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
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With