Sandeep Menon
Sandeep Menon

Reputation: 27

yacc: 22 reduce/reduce conflicts

%%

%token IDENTIFIER NUMBER SIZEOF
%token PTR DOT
%token TYPEDEF INT FLOAT VOID STRUCT
%token IF ELSE WHILE RETURN FOR DO SWITCH CASE BREAK DEFAULT CONTINUE
%token PRINTF SCANF
%token STRING
%token PREPROC

%left GT LT LE GE NE EQ
%left AND OR

%right '='
%left '+' '-'
%left '*' '/'

%%
start:  Function
    |   Declaration
    ;

Function:   Type IDENTIFIER '(' ArgList ')' CompoundStmt
    |   Type IDENTIFIER '('')' CompoundStmt
    ;

ArgList:    ArgList ',' Arg
    |   Arg
    ;

Arg:    Type IDENTIFIER
    ;

Type:   INT
    |   FLOAT
    |   VOID
    ;

CompoundStmt:   '{' StmtList '}'
    |   '{''}'
    ;

StmtList:   StmtList Stmt
    | Stmt
    ;

Stmt:   WhileStmt
    |   Declaration
    |   ForStmt
    |   IfStmt
    |   PrintStmt
    |   ScanStmt
    |   ';'
    ;

WhileStmt:  WHILE '(' Expr ')' Stmt
    |   WHILE '(' Expr ')' CompoundStmt
    ;

ForStmt:    FOR '(' Expr ';' Expr ';' Expr ')' Stmt
    |   FOR '(' Expr ';' Expr ';' Expr ')' CompoundStmt
    ;

IfStmt: IF '(' Expr ')' Stmt
    |   IF '(' Expr ')' CompoundStmt
    ;

PrintStmt:  PRINTF '(' Expr ')' ';'
    ;

ScanStmt:   SCANF '(' Expr ')' ';'
    ;

Expr:   Expr LE Expr
    |   Expr GE Expr
    |   Expr GT Expr
    |   Expr LT Expr
    |   Expr NE Expr
    |   Expr EQ Expr
    |   Assignment
    |   ArrayUsage
    ;

ArrayUsage: IDENTIFIER '[' Assignment ']'
    ;

Declaration:    Type Assignment ';'
    |   Assignment ';'
    |   FunctionCall ';'
    |   ArrayUsage ';'
    |   Type ArrayUsage ';'
    |   StructStmt ';'
    ;

StructStmt: STRUCT IDENTIFIER '{' Type Assignment '}'
    ;

FunctionCall:   IDENTIFIER '('')'
    |   IDENTIFIER '(' Assignment ')'
    ;

Assignment: IDENTIFIER '=' Assignment
    |   IDENTIFIER '=' FunctionCall
    |   IDENTIFIER '=' ArrayUsage
    |   ArrayUsage '=' Assignment
    |   IDENTIFIER ',' Assignment
    |   NUMBER ',' Assignment
    |   IDENTIFIER '+' Assignment
    |   IDENTIFIER '-' Assignment
    |   IDENTIFIER '*' Assignment
    |   IDENTIFIER '/' Assignment
    |   NUMBER '+' Assignment
    |   NUMBER '-' Assignment
    |   NUMBER '*' Assignment
    |   NUMBER '/' Assignment
    |   '\'' Assignment '\''
    |   '(' Assignment ')'
    |   '-' Assignment
    |   '-' NUMBER
    |   '-' IDENTIFIER
    |   NUMBER
    |   IDENTIFIER
    ;

%%
include"lex.yy.c"

int main(int argc,char *argv[])
{
    FILE *file;
        file = fopen(argv[1], "r");
        if (!file)
        {
            fprintf(stderr, "Could not open %s\n", argv[1]);
            exit(1);
        }
        yyin = file;

    if(!yyparse())
        printf("\nParsing done");
    else
        printf("\nParsing failed");

    fclose(yyin);

        return 0;
    }

While running :

yacc scanner.y          // scanner.y being by yacc code

I get the following error :

yacc: 22 reduce/reduce conflicts.

A reduce/reduce conflict occurs if there are two or more rules that apply to the same sequence of input. This usually indicates a serious error in the grammar.

What is the error here?

Upvotes: 0

Views: 432

Answers (2)

Chris Dodd
Chris Dodd

Reputation: 126526

The problem comes from the ambiguity in the rules

Assignment: '-' Assignment
          |   '-' NUMBER
          |   '-' IDENTIFIER
          |   NUMBER
          |   IDENTIFIER

When you have the input - IDENTIFIER or (- NUMBER) you can either reduce it to Assignment in one step (the 2nd or 3rd rule above) or two steps (4th or 5th rule, followed by 1st rule). The easiest fix is to just delete 2nd and 3rd rules above, which will force it to always reduce two steps. You probably also want to give the '-' Assignment rule higher precedence by defining a fake UNARY token (with higher precedence than all binary operators), which the lexer never returns, but allowing you to say

Assignment: '-' Assignment %prec UNARY

to give that rule higher precedence.

Upvotes: 2

Alexander Egorov
Alexander Egorov

Reputation: 593

you can use bison with -v option and you'll get verbose output. I received

State 32 conflicts: 11 reduce/reduce
State 33 conflicts: 11 reduce/reduce

these states looks like this:

State 32

38 ArrayUsage: IDENTIFIER . '[' Assignment ']'
48 Assignment: IDENTIFIER . '=' Assignment
49           | IDENTIFIER . '=' FunctionCall
50           | IDENTIFIER . '=' ArrayUsage
52           | IDENTIFIER . ',' Assignment
54           | IDENTIFIER . '+' Assignment
55           | IDENTIFIER . '-' Assignment
56           | IDENTIFIER . '*' Assignment
57           | IDENTIFIER . '/' Assignment
66           | '-' IDENTIFIER .
68           | IDENTIFIER .

'='  shift, and go to state 18
'+'  shift, and go to state 19
'-'  shift, and go to state 20
'*'  shift, and go to state 21
'/'  shift, and go to state 22
','  shift, and go to state 24
'['  shift, and go to state 25

GT        reduce using rule 66 (Assignment)
GT        [reduce using rule 68 (Assignment)]
LT        reduce using rule 66 (Assignment)
LT        [reduce using rule 68 (Assignment)]
LE        reduce using rule 66 (Assignment)
LE        [reduce using rule 68 (Assignment)]
GE        reduce using rule 66 (Assignment)
GE        [reduce using rule 68 (Assignment)]
NE        reduce using rule 66 (Assignment)
NE        [reduce using rule 68 (Assignment)]
EQ        reduce using rule 66 (Assignment)
EQ        [reduce using rule 68 (Assignment)]
')'       reduce using rule 66 (Assignment)
')'       [reduce using rule 68 (Assignment)]
'}'       reduce using rule 66 (Assignment)
'}'       [reduce using rule 68 (Assignment)]
';'       reduce using rule 66 (Assignment)
';'       [reduce using rule 68 (Assignment)]
']'       reduce using rule 66 (Assignment)
']'       [reduce using rule 68 (Assignment)]
'\''      reduce using rule 66 (Assignment)
'\''      [reduce using rule 68 (Assignment)]
$default  reduce using rule 66 (Assignment)


State 33

53 Assignment: NUMBER . ',' Assignment
58           | NUMBER . '+' Assignment
59           | NUMBER . '-' Assignment
60           | NUMBER . '*' Assignment
61           | NUMBER . '/' Assignment
65           | '-' NUMBER .
67           | NUMBER .

'+'  shift, and go to state 26
'-'  shift, and go to state 27
'*'  shift, and go to state 28
'/'  shift, and go to state 29
','  shift, and go to state 30

GT        reduce using rule 65 (Assignment)
GT        [reduce using rule 67 (Assignment)]
LT        reduce using rule 65 (Assignment)
LT        [reduce using rule 67 (Assignment)]
LE        reduce using rule 65 (Assignment)
LE        [reduce using rule 67 (Assignment)]
GE        reduce using rule 65 (Assignment)
GE        [reduce using rule 67 (Assignment)]
NE        reduce using rule 65 (Assignment)
NE        [reduce using rule 67 (Assignment)]
EQ        reduce using rule 65 (Assignment)
EQ        [reduce using rule 67 (Assignment)]
')'       reduce using rule 65 (Assignment)
')'       [reduce using rule 67 (Assignment)]
'}'       reduce using rule 65 (Assignment)
'}'       [reduce using rule 67 (Assignment)]
';'       reduce using rule 65 (Assignment)
';'       [reduce using rule 67 (Assignment)]
']'       reduce using rule 65 (Assignment)
']'       [reduce using rule 67 (Assignment)]
'\''      reduce using rule 65 (Assignment)
'\''      [reduce using rule 67 (Assignment)]
$default  reduce using rule 65 (Assignment)

As you can see same tokens in both states can reduce using different rules.

The problem is in the Assignment rule:

Assignment: IDENTIFIER '=' Assignment
|   IDENTIFIER '=' FunctionCall
|   IDENTIFIER '=' ArrayUsage
|   ArrayUsage '=' Assignment
|   IDENTIFIER ',' Assignment
|   NUMBER ',' Assignment
|   IDENTIFIER '+' Assignment
|   IDENTIFIER '-' Assignment
|   IDENTIFIER '*' Assignment
|   IDENTIFIER '/' Assignment
|   NUMBER '+' Assignment
|   NUMBER '-' Assignment
|   NUMBER '*' Assignment
|   NUMBER '/' Assignment
|   '\'' Assignment '\''
|   '(' Assignment ')'
|   '-' Assignment
|   '-' NUMBER
|   '-' IDENTIFIER
|   NUMBER
|   IDENTIFIER
;

I gues you should use special unary minus token and rewrite rule like this:

Assignment: IDENTIFIER '=' Assignment
|   IDENTIFIER '=' FunctionCall
|   IDENTIFIER '=' ArrayUsage
|   ArrayUsage '=' Assignment
|   IDENTIFIER ',' Assignment
|   NUMBER ',' Assignment
|   IDENTIFIER '+' Assignment
|   IDENTIFIER '-' Assignment
|   IDENTIFIER '*' Assignment
|   IDENTIFIER '/' Assignment
|   NUMBER '+' Assignment
|   NUMBER '-' Assignment
|   NUMBER '*' Assignment
|   NUMBER '/' Assignment
|   '\'' Assignment '\''
|   '(' Assignment ')'
|   '-' Assignment
|   UMINUS NUMBER
|   UMINUS IDENTIFIER
|   NUMBER
|   IDENTIFIER
;

Define it something like this:

%token IDENTIFIER NUMBER SIZEOF UMINUS

and do it

%nonassoc UMINUS

Upvotes: 0

Related Questions