If you process the following grammar snippet with lox
, it will fail with the
error: grammar has conflicts
:
expr = expr '+' expr
| expr '*' expr
| NUMBER
Running lox
with the -report
flag provides the missing details:
I5:
expr = expr .PLUS expr, EOF
expr = expr .PLUS expr, PLUS
expr = expr .PLUS expr, MUL
expr = expr PLUS expr., EOF
expr = expr PLUS expr., PLUS
expr = expr PLUS expr., MUL
expr = expr .MUL expr, EOF
expr = expr .MUL expr, PLUS
expr = expr .MUL expr, MUL
on EOF reduce expr
on MUL reduce expr <== CONFLICT
on MUL shift I3 <== CONFLICT
on PLUS shift I4 <== CONFLICT
on PLUS reduce expr <== CONFLICT
The excerpt above represents a single state in the parser state machine. In this
state, the parser has just parsed a expr PLUS expr
(e.g. 2 + 2
). Say the
next token is a MUL
, what should it do? It could reduce expr PLUS expr
into
expr
or it could shift MUL
. The grammar does not make it clear which
action to take, so it is ambiguous.
One way to resolve this is by refactoring the grammar:
expr = expr '+' term
| term
term = term '*' factor
| factor
factor = number
number = NUMBER
| '-' NUMBER
Some conflicts can only be resolved by refactoring but a large class of conflicts can be resolved using precedence qualifiers:
expr = expr '+' expr @left(1)
| expr '*' expr @left(2)
| NUMBER
The @left
qualifiers in the grammar tells lox
that if it encounters a
conflict between expr '+' expr
and expr '*' expr
, then the latter should
take precendence over the former.