Bison 说开始符号不派生任何句子

Bison says that start symbol does not derive any sentence

我正在编写基本的编译器,但很早就卡住了。当我尝试 运行 我的 bison 文件时它抛出错误(在下面)我不知道为什么会这样并且已经为此苦苦挣扎了一段时间。

错误:

compiler/parser.y: warning: 9 nonterminals useless in grammar [-Wother]
compiler/parser.y: warning: 32 rules useless in grammar [-Wother]
compiler/parser.y:34.1-7: fatal error: start symbol program does not derive any sentence
 program            :   DECLARE declaration IN commands END

弹性:

%option noyywrap
%{
    #include <stdio.h>
    #include "parser.tab.h"
%}

NUMBER          [0-9]+
PID                 [_a-z]+

WHITESPACE  [ \t\r]+

%x COMMENT
%%

<INITIAL>{
"["                     BEGIN(COMMENT);

\n                      yylineno++;
{WHITESPACE}

{NUMBER}            {
                                printf("Number: %s\n", yytext);
                                yylval.ival = (char*) strdup(yytext);
                                return NUM;
                            }

{PID}                   {
                                printf("PID: %s\n", yytext);
                                yylval.sval = (char*) strdup(yytext);
                                return PID;
                            }

":="                    return ASSIGN;

"+"                     return ADD;
"-"                     return SUB;
"*"                     return MUL;
"/"                     return DIV;
"%"                     return MOD;

"="                     return EQ;
"!="                    return NEQ;
"<"                     return LT;
">"                     return GT;
"<="                    return LE;
">="                    return GE;

")"                     return R_BRACKET;
"("                     return L_BRACKET;
";"                     return SEMICOLON;
":"                     return COLON;


"DECLARE"           return DECLARE;
"IN"                    return IN;
"END"                   return END;

"IF"                    return IF;
"ELSE"              return ELSE;
"ENDIF"             return ENDIF;

"WHILE"             return WHILE;
"DO"                    return DO;
"ENDWHILE"      return ENDWHILE;
"ENDDO"             return ENDDO;

"FOR"                   return FOR;
"FROM"              return FROM;
"TO"                    return TO;
"DOWNTO"            return DOWNTO;
"ENDFOR"            return ENDFOR;

"READ"              return READ;
"WRITE"             return WRITE;
}

<COMMENT>{
"]"                     BEGIN(INITIAL);
[^\n]+\n            yylineno++;
}

%%

野牛:

%{
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    extern int yylineno;

    int yylex(void);
    void yyerror(const char *);

    int error = 0;
%}

%union{
    char* sval;
    char* ival;
}

%token <sval> DECLARE /* Declarations block */
%token <sval> IN END /* Code block */
%token <sval> IF THEN ELSE ENDIF /* Conditional block */
%token <sval> WHILE DO ENDWHILE ENDDO /* While-do and Do-while loop block */
%token <sval> FOR FROM TO DOWNTO ENDFOR /* For loop block */
%token <sval> READ WRITE
%token <sval> ASSIGN
%token <sval> ADD SUB MUL DIV MOD /* Arithmetic operators */
%token <sval> EQ NEQ LT GT LE GE /* Boolean operators */
%token <sval> L_BRACKET R_BRACKET SEMICOLON COLON /* Symbols */
%token <ival> NUM
%token <sval> PID

%%

program         :   DECLARE declaration IN commands END
                        ;

declaration :   declaration PID SEMICOLON
                        |   declaration PID L_BRACKET NUM COLON NUM R_BRACKET SEMICOLON
                        ;

commands        :   commands command
                        |   command
                        ;

command         :   id ASSIGN expression SEMICOLON
                        |   IF condition THEN commands ELSE commands ENDIF
                        |   IF condition THEN commands ENDIF
                        |   WHILE condition DO commands ENDWHILE
                        |   DO commands WHILE condition ENDDO
                        |   FOR PID FROM value TO value DO commands ENDFOR
                        |   FOR PID FROM value DOWNTO value DO commands ENDFOR
                        |   READ id SEMICOLON
                        |   WRITE value SEMICOLON
                        ;

expression  :   value
                        |   value ADD value
                        |   value SUB value
                        |   value MUL value
                        |   value DIV value
                        |   value MOD value
                        ;

condition       :   value EQ value
                        |   value NEQ value
                        |   value LT value
                        |   value GT value
                        |   value LE value
                        |   value GE value
                        ;

value               :   NUM
                        |   id
                        ;

id                  :   PID
                        |   PID L_BRACKET PID R_BRACKET
                        |   PID L_BRACKET NUM R_BRACKET
                        ;

%%

void yyerror(const char *msg) {
    fprintf(stderr, "Compiling error: %s\n", msg);
}

如果您想知道,我 运行 来自另一个文件的 main 函数,但我认为这不是问题所在。

你的语法说有一个program,你必须有一个declaration:

program         :   DECLARE declaration ...

而获得声明的唯一途径就是这两条规则

declaration :   declaration ...
                    |   declaration ...

但这两者都要求您已经拥有 declaration。因为你一开始什么都没有,如果你已经有了一个,你只能得到一个 declaration,你永远不能有任何声明。

因此您永远无法解析 program

通常情况下,当野牛这么说时,它是在抱怨你给它提供的语法。该错误消息意味着使用该语法无法构建仅由终结符组成的有效句子。必须修补您的语法才能构建语法树 ,在叶子中只有终端符号 。如果你检查一下,你会发现实际上不可能构建一个在叶子中只有终端符号的解析树。试着自己观察。这个简单的语法会发生这种情况。

sentence: '*' sentence
    | '(' sentence ')' ;

你会看到你为 sentence 构建的所有解析树总是有一个 sentence 作为它的叶子之一,所以不可能用那种语言构建一个只有终结符号的有效句子.

你的具体问题的技术细节在其他答案中有讨论,这里不再赘述(Bison使用你在语法中写的第一条规则作为句法树的根,默认情况下,在你的情况是 declaration,而不是程序)

无论如何,如果您遇到该错误,可能这不是您遇到的唯一问题。如果您尝试 bison 与选项 --report--report-file(请参阅联机帮助页),您将获得有关使其失败的规则的更详细信息。

编辑

查看您的代码后,您将 declaration 扩展为 declaration 以及 您为 declaration 提供的所有替代方案中的更多内容永远不能生成只有终端符号的声明,因为当你扩展时,总是有一个 declaration 需要扩展。