在Yacc文件中制定规则时,如何表示epsilon?

时间:2019-04-15 22:28:07

标签: yacc lex

我正在尝试在lex / yacc中实现一个简单的C减解析器。我用一组非常简单的规则测试了我的代码,它起作用了。但是现在,当我尝试添加实际规则时,由于存在epsilon规则,所以到处都会出现此错误。 error: syntax error, unexpected identifier 我一直在寻找如何在yacc中表示epsilon的方法,而我所看到的每个地方都说我可以将规则留空。我什至尝试在规则中添加评论,因为我也看到了。但是,我想问题可能出在其他地方。 为什么这对我不起作用? 下面是我的.y文件,第一个错误是这样的(意外的标识符):

   arglist {};
        ^^^^^^^
void yyerror (char *s);
#include <stdio.h>
#include <stdlib.h>
int yylex();
extern int yytext[];
extern FILE *yyin;
%}
%start program
%token LTE GTE BEQUALS NOTEQUALS BEGCOMMENT ENDCOMMENT COMMENT GREATER LESS COMMA PLUS SUB MULT DIV EQUAL LP RP LB RB LC RC SEMICOLON INT FLOAT VOID IF WHILE RETURN ELSE ID NUM INVALID
%%
program : declarationlist { printf("\nACCEPT\n"); };

declarationlist : declaration declarationlistPrime {};

declaration : typespecifier ID DDD {};

DDD : vardeclarationPrime {};
    | LP params RP compoundstmt {};
vardeclaration : typespecifier ID vardeclarationPrime {};
typespecifier : INT {};
    | VOID {};
    | FLOAT {};
params : paramlist {};
    | VOID {};
paramlist : param paramlistPrime {};
param : INT ID paramPrime  {};
    | VOID ID paramPrime {};
    | FLOAT ID paramPrime {};
compoundstmt : LC localdeclarations statementlist RC {};
localdeclarations : localdeclarationsPrime {};
statementlist : statementlistPrime {};
statement : expressionstmt {};
    | LC localdeclarations statementlist RC {}; 
    | selectionstmt {};
    | iterationstmt {};
    | returnstmt {};
expressionstmt : expression SEMICOLON {};
    | SEMICOLON {};
selectionstmt : IF LP expression RP statement selectionstmtPrime {};

iterationstmt : WHILE LP expression RP statement {};

returnstmt : RETURN returnstmtPrime {};

expression : ID FFF {};
    | LP expression RP termPrime SSS {};
    | NUM termPrime SSS {};

FFF : LP args RP termPrime SSS {};
    | varPrime XXX {};

XXX : EQUAL expression arglistPrime {};
    | termPrime additiveexpressionPrime SSS {};

var : ID varPrime {};

SSS : additiveexpressionPrime arglistPrime {};
    | relop additiveexpression arglistPrime {};

relop : LTE {};
    | LESS {};
    | GREATER {};
    | GTE {};
    | BEQUALS {};
    | NOTEQUALS {};

additiveexpression : term additiveexpressionPrime {};

addop : ADD {};
    | SUB {};

term : factor termPrime {};

mulop : MULT {};
    | DIV {};

factor : LP expression RP {};
    | ID factorXYZ {};
    | NUM {};

factorXYZ : varPrime {};
    | LP args RP {};

args : /* epsilon */ | {};
    arglist {};

arglist : ID CS {};
    | LP expression RP termPrime FID {};
    | NUM termPrime FID {};

CS : varPrime EEE {};
    | LP args RP termPrime FID {};

EEE : EQUAL expression arglistPrime {};
    | termPrime FID {};

FID : relop additiveexpression arglistPrime {};
    | additiveexpressionPrime arglistPrime {};

vardeclarationPrime : SEMICOLON {};
    | LB NUM RB SEMICOLON {};

paramPrime : /* epsilon */ | {};
    LB RB {};

selectionstmtPrime : | 
    ELSE statement {};

returnstmtPrime : SEMICOLON {};
    | ID CCC {};
    | NUM termPrime BBB {};
    | LP expression RP termPrime BBB {};

AAA : EQUAL expression SEMICOLON {};
    | termPrime BBB {};

BBB : relop additiveexpression SEMICOLON {};
    | additiveexpressionPrime SEMICOLON {};

CCC : varPrime AAA {};
    | LP args RP termPrime BBB {};

varPrime :  | {};
    LB expression RB {};

declarationlistPrime : | {};
    declaration declarationlistPrime {};

paramlistPrime : | {};
    COMMA param paramlistPrime {};

localdeclarationsPrime : | {};
    vardeclaration localdeclarationsPrime {};

statementlistPrime : | {};
    statement statementlistPrime {};

additiveexpressionPrime : | {};
    addop term additiveexpressionPrime {};

termPrime : | {};
    mulop factor termPrime {};

arglistPrime : | {};
    COMMA expression arglistPrime {};


%%
int main(int argc, char *argv[])
{
   yyin = fopen(argv[1], "r");
   if (!yyin)
   {
      printf("no file\n");
      exit(0);
   }
   yyparse();
}
void yyerror(char *s)
{
   printf("\nREJECT\n");
//   printf("error from yyerror\n");
   exit(0);
}
int yywrap()
{
  // printf("in yywarp\n");
   exit(0);
}```

Please help, I have tried everything I can think of.

1 个答案:

答案 0 :(得分:1)

你有

args : /* epsilon */ | {};

其中有args的两个产品,它们都是空的,并且有一个明确的无操作动作。以分号结尾,即args规则的末尾。因此,野牛不期望有另一个右手侧。期望有一些不同的非终端规则。

我想你的意思是

args : /* epsilon */
     | arglist
     ;

请注意,无需显式添加一个空动作,将动作完全省略(如上所述)是完全一样的,并且可以说噪音较小。

使用野牛的更好样式是使用%empty标记而不是注释,因为野牛将确保使用%empty的规则确实为空:

args : %empty
     | arglist
     ;