Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shift reduce conflict

I'm having a problem understanding the shift/reduce confict for a grammar that I know has no ambiguity. The case is one of the if else type but it's not the 'dangling else' problem since I have mandatory END clauses delimiting code blocks.

Here is the grammar for gppg (Its a Bison like compiler compiler ... and that was not an echo):

%output=program.cs

%start program

%token FOR
%token END
%token THINGS
%token WHILE
%token SET
%token IF
%token ELSEIF
%token ELSE
%%

program : statements
        ;

statements : /*empty */
           | statements stmt
           ;

stmt : flow
     | THINGS
     ;

flow : '#' IF '(' ')' statements else
     ;

else : '#' END
     | '#' ELSE statements '#' END
     | elseifs
     ;

elseifs : elseifs '#' ELSEIF statements else
        | '#' ELSEIF statements else
        ;

Here is the conflict output:

// Parser Conflict Information for grammar file "program.y"

Shift/Reduce conflict on symbol "'#'", parser will shift
 Reduce 10: else -> elseifs
 Shift "'#'":   State-22 -> State-23
  Items for From-state State 22
    10 else: elseifs .
    -lookahead: '#', THINGS, EOF
    11 elseifs: elseifs . '#' ELSEIF statements else 
  Items for Next-state State 23
    11 elseifs: elseifs '#' . ELSEIF statements else 

// End conflict information for parser

I already switched arround everything, and I do know how to resolve it, but that solution involves giving up the left recursion on 'elseif' for a right recursion.

Ive been through all the scarse documentation I have found on the internet regarding this issue (I post some links at the end) and still have not found an elegant solution. I know about ANTLR and I don't want to consider it right now. Please limit your solution to Yacc/Bison parsers.

I would appreciate elegant solutions, I managed to do It by eleminating the /* empty */ rules and duplication everything that needed an empty list but in the larger grammar Im working on It just ends up like 'sparghetti grammar syndrome'.

Here are some links:

http://nitsan.org/~maratb/cs164/bison.html

http://compilers.iecc.com/comparch/article/98-01-079

GPPG, the parser I'm using

Bison manual

like image 430
Caerbanog Avatar asked Oct 12 '08 21:10

Caerbanog


People also ask

What are the 2 conflicts in shift reduce parser?

In shift-reduce parsing, there is two types of conflicts: one is shift-reduce conflict (SR conflict) and another is reduce – reduce conflict (RR) conflict.

What are shift-reduce conflicts?

Overview. The Shift-Reduce Conflict is the most common type of conflict found in grammars. It is caused when the grammar allows a rule to be reduced for particular token, but, at the same time, allowing another rule to be shifted for that same token.

How do you resolve shift-reduce conflict?

Rule 1. If there is a shift-reduce conflict in situations where no precedence rules have been created to resolve the conflict, the default action is to shift. The conflict is also reported in the yacc output so you can check that shifting is actually what you want.

What are shift-reduce and reduce-reduce conflict explain with suitable examples?

There are two kinds of conflicts that can occur in an SLR(1) parsing table. A shift-reduce conflict occurs in a state that requests both a shift action and a reduce action. A reduce-reduce conflict occurs in a state that requests two or more different reduce actions.


1 Answers

Your revised ELSEIF rule has no markers for a condition -- it should nominally have '(' and ')' added.

More seriously, you now have a rule for

elsebody : else
         | elseifs else
         ;

and

elseifs : /* Nothing */
        | elseifs ...something... 
        ;

The 'nothing' is not needed; it is implicitly taken care of by the 'elsebody' without the 'elseifs'.

I would be very inclined to use rules 'opt_elseifs', 'opt_else', and 'end':

flow : '#' IF '(' ')' statements opt_elseifs opt_else end
     ;

opt_elseifs : /* Nothing */
            | opt_elseifs '#' ELSIF '(' ')' statements 
            ;

opt_else : /* Nothing */
         | '#' ELSE statements
         ;

end : '#' END
    ;

I've not run this through a parser generator, but I find this relatively easy to understand.

like image 68
Jonathan Leffler Avatar answered Nov 06 '22 02:11

Jonathan Leffler