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.