【问题标题】:Yacc reading only the first grammar ruleyacc 只读第一条语法规则
【发布时间】:2013-01-07 19:00:59
【问题描述】:

我有这个 yacc 文件

%error-verbose
%token  END
%token  ID
%token  INT
%token  IF
%token  ELSE
%token  WHILE
%token  FOR
%token  BREAK
%token  CONTINUE
%token  RETURN
%token  SEM
%token  LPAR
%token  RPAR
%token  PLUS
%token  MINUS
%token  MULT
%token  DIV
%token  MOD
%token  GT
%token  LT
%token  GTE /* >= */
%token  LTE /* <= */
%token  EQUAL   /* == */
%token  NEQUAL  /* != */
%token  AND
%token  OR
%token  EQ
%token  COM
%token PRINT 
%token READ
%token FLOAT
%token LABR
%token RABR
%token NUM
%token STR


/*
 *  precedentce tabLTE
 */

%right  EQ PE ME TE DE RE
%left   OR
%left   AND
%left   EQUAL NEQUAL
%left   LT GT GTE LTE
%left   PLUS MINUS
%left   MULT DIV MOD
%right  PP MM
%{
#include<stdio.h>
extern char *yyname;
extern char *yytext;
extern int yylineno;
void yyerror(char const *msg)
{
fprintf(stderr,"%s:%d:%s\n", yyname,yylineno,msg);

}
%}
%%
program
    : definitions
    ;
definitions
    : definition
    | definitions definition
    ;
definition:
    | declaration
    ;
declarations
    : /* null */
    | declarations declaration
    ;
declaration
    : INT declarator_list SEM
    ;

declarator_list
    : ID
    | declarator_list COM ID
    ;
statements
    : /* null */
    | statements statement
    ;
statement
    : expression SEM
    | SEM   /* null statement */
    | if_prefix statement
    | if_prefix statement ELSE statement
    | loop_prefix statement
    ;
if_prefix
    : IF LPAR expression RPAR
    ;
loop_prefix
    : WHILE LPAR expression RPAR
    ;
expression
    : binary
    | expression COM binary
    ;
binary
    : ID
    | LPAR expression RPAR
    | ID LPAR optional_argument_list RPAR
    | binary PLUS binary
    | binary MINUS binary
    | binary MULT binary
    | binary DIV binary
    | binary MOD binary
    | binary GT binary
    | binary LT binary
    | binary GTE binary
    | binary LTE binary
    | binary EQUAL binary
    | binary NEQUAL binary
    | binary AND binary
    | binary OR binary
    | ID EQ binary
    | ID PE binary
    | ID ME binary
    | ID TE binary
    | ID DE binary
    | ID RE binary
    ;
optional_argument_list
    : /* no actual arguments */
    | argument_list
    ;
argument_list
    : binary
    | argument_list COM binary
    ;

%%

#include <stdlib.h>
extern FILE *yyin;
int main(int argc, char **argv)
{
    int ok;
    if (argc != 2) {
        fprintf(stderr, "%s: Wrong arguments\n", argv[0]);
        return EXIT_FAILURE;
    }
    yyname = argv[1];
    if ((yyin = fopen(yyname, "r")) == NULL) {
        fprintf(stderr, "%s: %s: Invalid file\n", argv[0], argv[1]);
        return EXIT_FAILURE;
    }
    return (yyparse() ? EXIT_SUCCESS : EXIT_FAILURE);
}

当输入是 诠释 x; 一切正常,但是当输入不是“INT”时 可以说 FOR 它会引发错误: 意外 FOR 期待 INT 或 $end 所以它实际上只读取规则集中的第一条规则.. 此外,在执行 bison 命令时,它一直显示无用的非终端和终端警告。

这个 yacc 文件有什么问题?

【问题讨论】:

  • 您对 'le' 到 'LTE' 的全局编辑对 /* * precedentce tabLTE */ 的影响太大(超过 3 行)。 'Precedence' 也不包含 't'。

标签: grammar bison yacc


【解决方案1】:

麻烦的是规则:

program
    : definitions
    ;
definitions
    : definition
    | definitions definition
    ;
definition:
    | declaration
    ;
declarations
    : /* null */
    | declarations declaration
    ;
declaration
    : INT declarator_list SEM
    ;

只允许声明通过;没有任何东西允许statements 作为program 的一部分。您的 FOR 不是声明,因此语法会拒绝它。

“无用的非终端”警告试图告诉你:

你犯了大错;你的语法有错误。您曾尝试为某些生产编写规则,但您从未让它被识别,因此添加它没有意义。

或者差不多……

也许你需要:

program
    : definitions statements
    ;

或者也许您也需要允许函数作为定义,然后 FOR 语句将成为函数体的一部分。

【讨论】:

  • 感谢您的澄清,添加语句后无用终端/非终端的数量减少了,但它仍然期待 $end 而输入文件中有其他语句,如 if 语句,但它不是阅读这些陈述.. 它一直期待 $end
  • @doctorMizo:它需要一个 INT 或一个 $end,而不仅仅是一个 $end。那是因为你所有的声明都以 INT 开头,所以在看到一个声明之后,它需要另一个声明,或者文件的结尾——其他任何东西都是语法错误。
  • 看看那些没用的终端和非终端,找出为什么它还在抱怨它们没用。或消除无用的临时。 (你可以在你的 VCS 的当前版本上贴上标签——不要告诉我你没有使用一个;继续使用一个——然后删除无用的东西,知道你可以回到当前版本,如果/当你再次需要它们时。)令牌 FOR 会引起麻烦,因为没有规则引用它。
【解决方案2】:

向我的 LL oracle 询问您修改后的语法:

Out of 15 non-terminals, 14 are reachable, 1 are unreachable:
'declarations'
Circular symbols:
definitions
definitions

对圆形符号的抱怨意味着“定义”可以自己推导出来。例如,“定义”可以产生“定义定义”,但“定义”是可以为空的,所以“定义”只能产生自己,kinduva 无限循环很少有解析器生成器愿意以任何明智的方式处理。换一种方式来看,您已经将“定义”定义为可以为空的符号列表,那么您希望匹配多少个 epsilon?无穷大呢? :-)

这是 yacc/bison 风格的一个缺点,它试图生成 some 解析器,即使语法存在问题;如果您确切地知道自己在做什么,那将非常方便,但否则会很混乱。

但是,对于如何处理语法循环的狭窄点,这给了你一个非常无用的(但可以通过口香糖编译!)解析器。您如何允许“定义”为空但不允许“定义”?爱荷华州:

definitions : | definitions definition ;
definition : declaration ;

尽量不要在可空性之上叠加可空性。因此,当您稍后更改为:

definition : declarations ;

不要使“声明”可以为空(“定义”可以为空)。相反,将其更改为:

declarations : declaration | declarations declaration ;

这应该可以让您摆脱眼前的问题并解决一些新问题 :-)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多