0

我有这个 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 它会引发错误:意外 FOR 期望 INT 或 $end 所以它实际上只读取规则集中的第一条规则。此外,它一直显示应用野牛命令时无用的非终端和终端警告。

这个 yacc 文件有什么问题?

4

2 回答 2

2

麻烦的是规则:

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

只允许通过声明;什么都不允许statements作为 a 的一部分program。您的 FOR 不是声明,因此语法拒绝它。

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

你犯了大错;你的语法有错误。你试图为一些生产编写规则,但你从来没有让它被识别,所以添加它没有意义。

或者差不多...

也许你需要:

program
    : definitions statements
    ;

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

于 2013-01-07T19:09:00.497 回答
0

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

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

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

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

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

definitions : | definitions definition ;
definition : declaration ;

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

definition : declarations ;

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

declarations : declaration | declarations declaration ;

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

于 2013-02-05T08:18:35.800 回答