致命错误:没有得出任何句子

时间:2014-05-23 11:10:19

标签: bison

当我在以下文件上运行parser.y时,我收到以下错误:

myanalyzer.y: warning: 14 nonterminals useless in grammar
myanalyzer.y: warning: 36 rules useless in grammar
myanalyzer.y:7.8-18: fatal error: start symbol main_struct does not derive any sentence

我无法理解代码有什么问题:

    %{
    #include <stdio.h>
    #include <string.h>
    extern int line_num;
    extern char *yytext;
%}
%start main_struct

%left PLUS

%token PUBLIC   1
...         
%token CONSTANT_CHAR    45

%%
main_struct:variables_declaration
        class_declaration
        functions_declaration
        ;  

constant:   INT
        |BOOLEAN
        |CHAR
        |STRING
        |FLOAT
        |DOUBLE 
        ;

locality:   PUBLIC
        | PRIVATE
        ;

identifier1:    IDENTIFIER
        | identifier1 COMMA IDENTIFIER
        ;

class_body: /*empty*/
        |  locality variables_declaration locality functions_declaration identifier1
        |  locality variables_declaration identifier1
        |  locality functions_declaration identifier1
        |  identifier1
        ;


variables_declaration:  /*empty*/ 
            |  variables_declaration constant identifier1 SEMICOLON
                |  variables_declaration constant identifier1 COMMA
                ;

class_declaration:  /*empty*/ 
            | class_declaration CLASS identifier1 BEGIN class_body END
            ;

functions_declaration:  functions_declaration constant identifier1 LEFT_PARENTHESIS vars_in_func RIGHT_PARENTHESIS BEGIN function_body END
            | functions_declaration VOID identifier1 LEFT_PARENTHESIS vars_in_func RIGHT_PARENTHESIS BEGIN function_body END
            ;

vars_in_func:       /*empty*/ 
            | constant identifier1
            | vars_in_func COMMA constant identifier1
            ;

function_body:      /*empty*/ 
            | variables_declaration identifier1
            | identifier1
            ; 
%%

int main ()
{     
  if ( yyparse() == 0 && error==0){
     printf("Accepted\n");
   }
  else{
     printf("Rejected\n");
   }
}

我现在第一次和Bison一起工作,所以代码可能不太好但是我想编译它以便我可以开始测试。但是我该如何解决这个错误?

注意:我可以这样做:

main_struct:variables_declaration
            | class_declaration
            | functions_declaration
            ;

但这是错误的,因为我希望我的程序能够拥有所有3个声明。

1 个答案:

答案 0 :(得分:7)

functions_declaration没有非递归制作,不像variables_declarationclass_declaration都有空制作。如果没有非递归生成,则无法从非终端派生句子,因为派生永远不会终止。

由于句子不能与functions_declaration匹配,main_struct也无法匹配,这反过来会使所有非终结者无效。

写入重复非终端有两种常见模式,分别对应于正则表达式运算符*(0或更多)和+(1或更多):

optional_repeating_element: /* EMPTY */
                          | optional_repeating_element element
                          ;

repeating_element         : element
                          | repeating_element element
                          ;

请注意,这些仅在基本情况下有所不同。在这两种情况下,您都需要单独为单个element定义生产。所以在你的情况下,你可以使用:

functions_declaration: function
                     | functions_declaration function
                     ;

function: constant identifier1 LEFT_PARENTHESIS vars_in_func RIGHT_PARENTHESIS
          BEGIN function_body END
        | VOID identifier1 LEFT_PARENTHESIS vars_in_func RIGHT_PARENTHESIS
          BEGIN function_body END
        ;

三个注释:

1)不要手动为您的代币编号。野牛会为你做,结果更加可维护。此外,对于单个字符的终端,使用单引号字符通常更具可读性;这些终端不需要声明,你可以使用一个简单的默认flex规则来处理所有这些终端(. {return *(unsigned char*)yytext;}。)因此,无论是写还是读都都可以更简单。

2)你对vars_in_func的定义会接受你可能不想接受的一些句子。你拥有的是:

vars_in_func:       /*empty*/ 
            | constant identifier1
            | vars_in_func COMMA constant identifier1
            ;

由于vars_in_func可以为空(第一次制作),第三次制作允许vars_in_funcCOMMA开头,因此以下内容有效:

(, int foo)

要正确执行此操作,您需要将空参数列表案例与递归分开。

3)你使用identifier1(这是一个令人困惑的标识符列表名称)会给你带来麻烦。您允许函数声明声明一个名称列表,但这与声明名称列表的变量声明中的有限前瞻无法区分。考虑两句话:

int variable1, variable2, variable3;

int function1, function2, function3() BEGIN END

当解析器找到第一个,时,它无法知道后面是整数变量列表,还是具有相同参数和主体的函数列表。我猜你并不是真的打算让第二种情况成为可能,这意味着你不应该在identifier1(或functions_declaration)中使用class_declaration。即使在您的参数列表非终端(vars_in_func)中,您也有一些奇怪的东西,尽管可以解析; vars_in_func是逗号分隔的类型列表,后跟逗号分隔的名称列表,因此以下内容是合法的:

void function(int a, b, int c, d)

也许你打算这样做,但我不相信。