When you have a conflict, you will see an entry like this in your info file:
State 432 atype -> SIMPLEQUOTE '[' . comma_types0 ']' (rule 318) sysdcon -> '[' . ']' (rule 613) '_' shift, and enter state 60 'as' shift, and enter state 16 ... ']' shift, and enter state 381 (reduce using rule 328) ...
On large, complex grammars, determining what the conflict is can be a bit of an art, since the state with the conflict may not have enough information to determine why a conflict is occurring).
In some cases, the rules associated with the state with the conflict will immediately give you enough guidance to determine what the ambiguous syntax is. For example, in the miniature shift/reduce conflict described in Section 8.4, “Conflict Tips”, the conflict looks like this:
State 13 exp -> exp . '+' exp0 (rule 1) exp0 -> if exp then exp else exp . (rule 3) then reduce using rule 3 else reduce using rule 3 '+' shift, and enter state 7 (reduce using rule 3) %eof reduce using rule 3
Here, rule 3 makes it easy to imagine that we had been parsing a
statement like if 1 then 2 else 3 + 4
; the conflict
arises from whether or not we should shift (thus parsing as
if 1 then 2 else (3 + 4)
) or reduce (thus parsing
as (if 1 then 2 else 3) + 4
).
Sometimes, there's not as much helpful context in the error message; take this abridged example from GHC's parser:
State 49 type -> btype . (rule 281) type -> btype . '->' ctype (rule 284) '->' shift, and enter state 472 (reduce using rule 281)
A pair of rules like this doesn't always result in a shift/reduce
conflict: to reduce with rule 281 implies that, in some context when
parsing the non-terminal type
, it is possible for
an '->'
to occur immediately afterwards (indeed
these source rules are factored such that there is no rule of the form
... -> type '->' ...
).
The best way this author knows how to sleuth this out is to look for instances of the token and check if any of the preceeding non-terminals could terminate in a type:
texp -> exp '->' texp (500) exp -> infixexp '::' sigtype (414) sigtype -> ctype (260) ctype -> type (274)
As it turns out, this shift/reduce conflict results from
ambiguity for view patterns, as in
the code sample case v of { x :: T -> T ... }
.