Search code examples
bisonyaccparser-generator

Parser - Shift/reduce conflict


I have a problem with my parser that is driving me crazy and was wondering if you guys would be able to help me.

I have this set of rules:

exp:        exp OP exp
    |       exp OSQUAREPAR exp CSQUAREPAR
    |       exp DOT LENGTH
    |       exp DOT ID OPAR expList CPAR
    |       READERS DOT INTREADER DOT READINT OPAR CPAR
    |       DIGIT
    |       TRUE
    |       FALSE
    |       ID
    |       THIS
    |       NEW INT OSQUAREPAR exp CSQUAREPAR 
    |       NEW ID OPAR CPAR
    |       EXCL exp    
    |       OPAR exp CPAR   
    ;

And the following conflict:

rule 28 exp -> exp OP exp

rule 29 exp -> exp OSQUAREPAR exp CSQUAREPAR

rule 30 exp -> exp DOT LENGTH

rule 31 exp -> exp DOT ID OPAR expList CPAR

rule 32 exp -> READERS DOT INTREADER DOT READINT OPAR CPAR

rule 33 exp -> DIGIT

rule 34 exp -> TRUE

rule 35 exp -> FALSE

rule 36 exp -> ID

rule 37 exp -> THIS

rule 38 exp -> NEW INT OSQUAREPAR exp CSQUAREPAR

rule 39 exp -> NEW ID OPAR CPAR

rule 40 exp -> EXCL exp

rule 41 exp -> OPAR exp CPAR

state 94

exp  ->  EXCL exp .   (rule 37)
exp2  ->  exp . OP exp   (rule 39)
exp2  ->  exp . OSQUAREPAR exp CSQUAREPAR   (rule 40)
exp2  ->  exp . DOT LENGTH   (rule 41)
exp2  ->  exp . DOT ID OPAR expList CPAR   (rule 42)

OSQUAREPAR    shift, and go to state 97
DOT   shift, and go to state 98
OP    shift, and go to state 99

OSQUAREPAR    [reduce using rule 37 (exp)]
DOT   [reduce using rule 37 (exp)]
OP    [reduce using rule 37 (exp)]
$default  reduce using rule 37 (exp)

Any ideas of how to solve this problem? I already checked other similar questions and even tried adding a priority to EXCL like one of the answers indicates but can't solve this.

Thanks.


Solution

  • A possible approach example (conflict-free):

    %token DIGIT FALSE ID INT INTREADER LENGTH NEW READERS READINT THIS TRUE
    
    %left  '+' '-'
    %left  '*' '/'
    %left  UNARY
    
    %%
    
    exp:       unary
       |       exp '+' exp
       |       exp '-' exp
       |       exp '*' exp
       |       exp '/' exp
       ;
    
    expList:    exp
           |    expList ',' exp
           ;
    
    operand:    '(' exp ')'
           |    DIGIT
           |    TRUE
           |    FALSE
           |    ID
           |    THIS
           |    READERS '.' INTREADER '.' READINT '(' ')'
           |    NEW INT '[' exp ']' 
           |    NEW ID '(' ')'
           ;
    
    primary:    operand
           |    primary '[' exp ']'
           |    primary '.' LENGTH
           |    primary '.' ID '(' expList ')'
           ;
    
    unary:      primary
         |      '!' unary
         |      '+' unary
         |      '-' unary %prec UNARY
         ;