我是否必须手动解决Yacc中的移位/减少问题?

时间:2019-04-16 02:34:26

标签: bison yacc lex

我很难消除语法中的两个移位/减少问题。我在任何地方都找不到解决方案。我看到Yacc显然会更喜欢这种转换,但是如果是这样,那为什么不进行编译呢?我知道一个问题是悬而未决的if-else,但是另一个我不知道。我希望Yacc可以为我自己处理。错误消息显示2 shift reduce conflicts

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  ID NUM 
%nonassoc IFX

%nonassoc ELSE
%%
program : declaration_list { printf("\nACCEPT\n"); };

declaration_list : declaration_list declaration     
                 | declaration          
                 ;

declaration  : var_declaration 
         | fun_declaration
             ;

var_declaration : type_specifier ID SEMICOLON   
                | type_specifier ID LB NUM RB SEMICOLON 
                ;

type_specifier : INT      
               | VOID   
           ;

fun_declaration : type_specifier ID LP params RP compound_stmt  ;

params : param_list | VOID ;

param_list : param_list COMMA param 
           | param                  
             ;

param : type_specifier ID           
      | type_specifier ID LB RB   
      ;


compound_stmt : LC local_declarations statement_list RC  
              ;

local_declarations : local_declarations var_declaration 
                   | /* empty */ ;

statement_list : statement_list statement
               | /* empty */ ;

statement : expression_stmt
          | compound_stmt
          | selection_stmt
          | iteration_stmt
          | return_stmt ;

expression_stmt : expression SEMICOLON
                | SEMICOLON 
        ;

selection_stmt : ifsubroutine  statement        
               | ifsubroutine  statement ELSE     
               ;

ifsubroutine : IF  LP expression RP  
        ;

iteration_stmt : whilesubroutine LP expression RP statement          
                ;
whilesubroutine : WHILE   ;

return_stmt : RETURN SEMICOLON              

            | RETURN expression SEMICOLON  
            ;

expression : var EQUAL expression     
           | simple_expression      
           ;

var : ID                    
    | ID LB expression RB 
    ;

simple_expression : additive_expression relop additive_expression  
                  | additive_expression                            
                  ;

relop : LTE | LESS | GREATER | GTE | EQUAL| NOTEQUALS ;

additive_expression : additive_expression addop term    
                    | term                              
                    ;

addop : PLUS 
      | SUB 
      ;

term : term mulop factor    
     | factor               
     ;

mulop : MULT 
      | DIV 
      ;

factor : LP expression RP 
       | var                
       | call               
       | NUM                
       ;

call : ID LP args RP  
     ;

args : arg_list | /* empty */ ;

arg_list : arg_list COMMA expression 
         | expression              
         ;

%%
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);
}```

1 个答案:

答案 0 :(得分:2)

您的yywrap()实现调用exit()。这意味着扫描程序一看到文件结束,应用程序就会终止。因此解析器将无法完成其工作。

通常,应在(f)lex文件中使用%option noyywrap,以避免需要提供yywrap。或使用-lfl中的默认实现。但是,如果您坚持要实现它,它应该返回1表示没有更多内容可供阅读。

此外,extern int yytext[];是不必要的,因为在解析器中的任何地方都没有引用yytext。而且您不应该在解析器中引用yytext;这种用法几乎总是一个错误。但是,如果您确实使用过yytext,则声明将是错误的:它是char(不是int)的指针(不是数组)。您的C编译器可能不会标记该错误。