Is it correct to state:
" A shift reduce conflict occurs in an LR(1) parser if and only if there exist items:
A -> alpha .
A -> alpha . beta
such that Follow(A) is not disjoint from First(beta).
where A is a non-terminal, alpha and beta are possibly empty sequences of grammar symbols."
(Intuitively this is because there is no way to determine, based on the top of the stack and the lookahead, whether it is appropriate to shift or reduce)
Note: If you guys think this depends on any specifics of the definition of first/follow comment and I will provide.
No, that statement is not correct.
Suppose in some grammar:
That is not quite sufficient for the grammar to have a shift-reduce conflict, because it requires that the non-terminal A
be reachable in a context in which the lookahead includes FOLLOW(A) ∩ FIRST(β).
So only if we require the grammar to be reduced, or at least to not contain any unreachable or useless productions, is the above sufficient to generate a shift-reduce conflict.
However, the above conditions are not necessary because there is no requirement that the shift and the reduction apply to the same non-terminal, or even "related" non-terminals. Consider the following simple grammar:
prog → stmt
prog → prog stmt
stmt → expr
stmt → func
expr → ID
expr → '(' expr ')'
func → ID '(' ')' stmt
That grammar (which is not ambiguous, as it happens) has a shift-reduce conflict in the state containing ID . (
because ID
could be reduced to expr
and then stmt
, or (
could be shifted as part of func → ID '(' ')' stmt
.
Although it's a side-point, it's worth noting the the FOLLOW set is only used in the construction of SLR(k) grammars. The canonical LR(k) construction -- and even the LALR(k) construction -- will successfully generating parsers for grammars in which the use of the FOLLOW set instead of a full lookahead computation will indicate a (non-existent) shift-reduce conflict. The classic example, taken from the Dragon book (example 4.39 in my copy), edited with slightly more meaningful non-terminal names:
stmt → lvalue '=' rvalue
stmt → rvalue
lvalue → '*' rvalue
lvalue → ID
rvalue → lvalue
Here, FOLLOW(rvalue) is {=, $}, and as a result in the state {stmt → lvalue · '=' rvalue
, rvalue → lvalue ·
}, it appears that a reduction to rvalue
is possible, leading to a false shift-reduce conflict.