Yacc只阅读第一个语法规则

时间:2013-01-07 19:00:59

标签: grammar bison yacc

我有这个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);
}

输入时 int x; 一切正常,但输入的内容不是“INT” 让我们说FOR它会抛出一个错误: 意外的期待INT或$结束 所以它实际上只是从规则集中读取第一条规则。 此外,当应用野牛命令时,它会不断显示无用的非终端和终端警告。

这个yacc文件出了什么问题?

2 个答案:

答案 0 :(得分:2)

问题在于规则:

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

只允许声明;什么都不允许statements作为program的一部分。你的FOR不是声明,所以语法拒绝它。

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

  

你有很大的时间;你的语法有一个错误。你曾尝试为某些制作编写规则,但你永远不会让它被识别,所以没有必要添加它。

或者左右......

也许你需要:

program
    : definitions statements
    ;

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

答案 1 :(得分:0)

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

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

关于圆形符号的投诉意味着“定义”可以衍生出来。例如,'定义'可以产生'定义',但'定义'是可空的,因此'定义'只能产生自身,kinduva无限循环,很少有解析器生成器能够以任何合理的方式处理。换句话说,你已经将'定义'定义为可以为空的符号列表,那么你想要匹配多少个epsilons?无穷大怎么样? : - )

即使语法存在问题,这也是yacc / bison风格尝试生成某些解析器的缺点;如果你确切知道自己在做什么,那就很方便了,但其他方面却很困惑。

但是,关于如何处理语法循环的狭隘观点,它给你一个非常无用的(但是通过口香糖可编辑!)解析器。你怎么能让“定义”可以为空而不是“定义”? IOW:

definitions : | definitions definition ;
definition : declaration ;

尝试不在可空性之上叠加可空性。所以当你以后改为:

definition : declarations ;

不要让'声明'可以为空(这已经由'定义'处理为可空)。相反,将其更改为:

declarations : declaration | declarations declaration ;

这应该可以让你解决眼前的问题和一些新问题: - )