简体   繁体   中英

How to find shift/reduce conflict in a yacc file

When compiling my yacc file I'm given the shift/reduce conflict. I can't seem to resolve, so how can I find it? The error is pointing to the line 73 which is the line for the auxVartSpec production definition and specifically its second production auxVarSpec COMMA ID but I've already set de precedences for those tokens.

%

%token <value> SEMICOLON BLANKID PACKAGE RETURN AND ASSIGN STAR COMMA DIV EQ GE GT LBRACE LE LPAR LSQ LT MINUS MOD NE NOT OR PLUS RBRACE RPAR RSQ ELSE FOR IF VAR INT FLOAT32 BOOL STRING PRINT PARSEINT FUNC CMDARGS RESERVED ID INTLIT REALLIT STRLIT

%type <node> Program Declarations VarDeclaration VarSpec Type FuncDeclaration FuncHeader Parameters FuncBody VarsAndStatements Statement ParseArgs FuncInvocation Expr auxDeclarations auxVarSpec auxParameters auxStatement auxFuncInvocation opcType opcParameters opcExpr opcFuncInvocation 


%nonassoc   IFX
%nonassoc   ELSE

%left  COMMA
%right  ASSIGN
%left   OR
%left   AND
%left   EQ NEQ
%left   LT GT LEQ GEQ
%left   PLUS MINUS
%left   STAR DIV MOD
%right  NOT

%%

Program: PACKAGE ID SEMICOLON Declarations                  
       ;                                   

Declarations: auxDeclarations                       

auxDeclarations: %empty                             

           | auxDeclarations VarDeclaration SEMICOLON                
           | auxDeclarations FuncDeclaration SEMICOLON      
           ;

VarDeclaration: VAR VarSpec                     

          | ID auxVarSpec Type                  

        ;                                                               
VarSpec: ID auxVarSpec Type                                         
           ;
auxVarSpec: %empty                          
      | auxVarSpec COMMA ID                     
      ;

Type: INT                   

    | FLOAT32                   

    | BOOL                  

    | STRING                    

    ;

FuncDeclaration: FUNC FuncHeader FuncBody            
           ;
FuncHeader: ID LPAR opcParameters RPAR opcType            
       ;

opcType: %empty                 
    | Type                  
        ;

Parameters: ID Type auxParameters       

opcParameters: %empty               
         | Parameters           
         ;

auxParameters: %empty               

         | auxParameters COMMA ID Type  
         ;

FuncBody: LBRACE VarsAndStatements RBRACE             

VarsAndStatements: VarsAndStatements SEMICOLON            

         | VarsAndStatements VarDeclaration SEMICOLON 

         | VarsAndStatements Statement SEMICOLON      

         | %empty                         

         ;

Statement: ID ASSIGN Expr                   


     | LBRACE auxStatement RBRACE               

     | IF Expr LBRACE auxStatement RBRACE %prec IFX     

     | IF Expr LBRACE auxStatement RBRACE ELSE LBRACE auxStatement RBRACE       


         | FOR opcExpr LBRACE auxStatement RBRACE       


     | RETURN opcExpr                       

     | FuncInvocation                   

     | ParseArgs                        

     | PRINT LPAR Expr RPAR                 

     | PRINT LPAR STRLIT RPAR               

     ;

opcExpr: %empty                 
       | Expr                   
       ;

auxStatement: %empty                               
        | auxStatement Statement SEMICOLON                 
        ; 

ParseArgs: ID COMMA BLANKID ASSIGN PARSEINT LPAR CMDARGS LSQ Expr RSQ RPAR 


FuncInvocation: ID LPAR opcFuncInvocation RPAR  

auxFuncInvocation: %empty               
         | COMMA Expr           
         ;

opcFuncInvocation: %empty           
         | Expr auxFuncInvocation     
         ;

Expr: Expr OR Expr              

    | Expr AND Expr             


    | Expr LT  Expr             


    | Expr GT  Expr             


    | Expr EQ  Expr             


    | Expr NE  Expr             


    | Expr LE  Expr             


    | Expr GE  Expr             


    | Expr PLUS  Expr               

    | Expr MINUS  Expr              


    | Expr DIV  Expr                


    | Expr MOD  Expr                


    | NOT Expr                  


    | MINUS Expr                


    | PLUS Expr                 


    | INTLIT                    


    | REALLIT                   


    | ID                    

    | FuncInvocation                

    | LPAR Expr RPAR                
%%

The error message you were seeing indicates that there are 73 shift/reduce conflicts in your file, not that there is a shift/reduce conflict at line 73. (Shift/reduce conflicts correspond to parser states, not line numbers. You can see where the conflicts are by generating a report file with the -v command line option.)

Of these conflicts, 72 are the result of a simple typo. Your grammar uses the token names NE , GE and LE in productions for Expr , but your precedence declarations are for the tokens NEQ , GEQ and LEQ . This produces a warning about unused tokens. (Also unused are STAR and RESERVED . I suppose you accidentally left out the Expr rule for multiplication.)

The remaining conflict is in State 45, whose items are (from the report file):

State 45

    7 VarDeclaration: ID . auxVarSpec Type
   29 Statement: ID . ASSIGN Expr
   43 ParseArgs: ID . COMMA BLANKID ASSIGN PARSEINT LPAR CMDARGS LSQ Expr RSQ RPAR
   44 FuncInvocation: ID . LPAR opcFuncInvocation RPAR

(The numbers attached to each production are the production number, not the line number. The production numbers are found at the top of the report file, but since the production is also listed, they don't make that much difference here. The . in each production indicates the lookahead point. Productions with the lookahead point at the beginning aren't shown, unless you specify --report=itemset )

The conflict is with the lookahead COMMA :

COMMA     shift, and go to state 68
COMMA     [reduce using rule 9 (auxVarSpec)]

So in this state, a comma can either be shifted, to continue with production 43. Or it can trigger a reduction using rule 9 ( auxVarSpec: %empty ). That reduction is possible because there is an item with auxVarSpec as its next non-terminal, and auxVarSpec starts with a comma if it is not empty.

To be possibly clearer, the problem is that in a list VarsAndStatements , there could be a VarDeclaration (which is a declaration) but there can also be a ParseArgs (which is a statement). So ParseArgs and VarDeclaration are both possible, and both of them can start with ID COMMA , but one of them requires the reduction of an empty right-hand side between ID and COMMA .

That conflict cannot be resolved without an additional token of lookahead: if the comma is followed by another ID , then the parser is looking at a VarDeclaration , whereas if the comma is followed by a BLANKID (whatever that is), then it must be a ParseArgs .

Although the conflict cannot be resolved as written, it can be avoided with the usual technique of deferring the shift/reduce decision. In particular, it is necessary to distinguish between three cases:

ID Type                /* VarDeclaration */
ID COMMA ID ...        /* VarDeclaration */
ID COMMA BLANKID ...   /* ParseArgs */

One way to do that is to add an apparently redundant production:

VarDeclaration: VAR VarSpec
              | ID Type
              | ID COMMA ID auxVarSpec Type

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM