Why is a reduce-reduce conflict between two rules that share a right-hand side more serious than a shift-reduce conflict?
answer
- two rules, one stack content
- both items complete in the state
- nothing left to shift that would help
- the default makes one rule unreachable
- unify the nonterminals, classify later
basics
~20 sA reduce-reduce conflict means identical stack contents could become two different nonterminals. The conventional default picks whichever rule was declared first, so the other construct is never built in that context and a whole feature quietly disappears.
solid answer
~50 sIn a reduce-reduce conflict one state holds two **complete** items, say `A -> alpha .` and `B -> alpha .`, with a shared lookahead. The parser has consumed exactly the same symbols either way and must decide which nonterminal they become — there is nothing left to shift that could disambiguate. Generators conventionally break the tie by rule order, so the losing rule is simply unreachable in that state: every input that should have produced `B` produces `A` instead, and the parse continues until something much later fails. Compare a shift-reduce conflict, where the default usually still yields a sensible tree. The fix is rarely a bigger table: **merge the two rules into one nonterminal** and let a later pass classify the construct, or add context that separates the states. A larger construction only helps when the conflict was an artefact of state merging.
go deeper
Recall the difference between the two conflict reports: one is about closing versus extending a construct, the other is about which construct identical symbols even are.
Explain the two complete items with overlapping lookahead, and why the tie-break leaves one rule unreachable rather than merely mis-attached.
Diagnose it: reach the state with a minimal input, decide whether the distinction is syntactic at all, and move a purely semantic distinction out of the grammar into a later pass.
Treat it as a language-design signal: a rule set that encodes semantic categories as separate syntax will keep producing these, so the grammar's job boundary is the thing to settle.
## The shape of the conflict Take a data-definition language where a declaration can refer either to a type or to a value: - `decl -> type_ref semi` - `decl -> value_ref semi` - `type_ref -> name` - `value_ref -> name` After shifting one `name` with `semi` ahead, the state contains `type_ref -> name .` and `value_ref -> name .`, both complete, both legal on `semi`. The text `name ;` is genuinely both things as far as the rule set can tell — the distinction lives in what that name was declared as, which is knowledge no parser has at this point. ## Why it hurts more than the other conflict | | Shift-reduce | Reduce-reduce | |---|---|---| | What is in dispute | whether to close the construct now or extend it | which construct the same symbols are | | Conventional default | prefer shift | prefer the rule declared earlier | | Typical outcome | a valid tree, one of two attachments | one rule becomes unreachable in that state | | How it surfaces | a construct binds to the wrong parent | a whole form of declaration stops parsing | | Usual cause | two readings of a nesting | two names for the same shape | The shift-reduce default still builds *something* defensible. The reduce-reduce default silently deletes a production from the effective language. Users experience it as "this perfectly valid file is rejected", and the rejection often happens several tokens later, where the wrong nonterminal fails to fit the enclosing rule — so the error message points nowhere near the real cause. ## Where the conflict comes from 1. **Two names for one shape.** The rule set gives two nonterminals identical right-hand sides because they mean different things downstream. The grammar cannot see downstream. 2. **Over-specialised rules.** A rule set that encodes a semantic category as syntax — separate nonterminals for things that look alike — collides the moment both are reachable in one context. 3. **State merging.** A construction that merges states sharing an item core unions their lookahead sets; two reductions that were separated by precise lookaheads can overlap after the merge. This kind is not a defect in the rule set at all. ## Removing it 1. **Unify the nonterminals.** Parse a single `name_ref` and let a later pass decide whether it denotes a type or a value. This is almost always the right move: the ambiguity is semantic, so it belongs to a semantic pass, not to the parse. 2. **Add distinguishing context.** If the language can afford it, a keyword or a punctuation mark makes the two forms syntactically distinct and the states separate. 3. **Make the lookahead more precise.** If the conflict is an artefact of merging, a construction that keeps the states apart removes it without touching the rules — at a cost in table size. 4. **Never resolve it by reordering the rules.** Reordering changes which construct silently disappears; it does not make the parser able to tell them apart. ## Reading the report The report gives a state and the two rules it would reduce by. The diagnosis is quick: write the shortest input that reaches the state, and ask which of the two nonterminals the language intends there. If the honest answer is "it depends on a declaration elsewhere", the grammar can never decide it, and step 1 is the only real fix. - A conflict the rule set cannot decide is not a table problem. - A conflict a bigger table removes was never in the rule set. - Either way, the shipped parser has already been choosing — so find out what it chose before changing anything.
- Why is reordering the two rules not a fix?Because the conflict is that the parser cannot distinguish the two constructs in that state. Reordering only changes which one wins and therefore which one becomes unreachable. The set of files that parse correctly changes, but it is never all of them.
- If a later pass must decide anyway, why not let the parser guess and correct it afterwards?Because the wrong nonterminal changes the tree's shape, and the enclosing rules then fail or build something different. Correcting after the fact means re-parsing. Parsing a single neutral nonterminal and classifying it later keeps one tree and moves the decision to a pass that has the information.
- How would you tell a merge artefact from a genuine grammar defect?Regenerate with a construction that does not merge same-core states. If the conflict disappears, the lookaheads were only overlapping because they were unioned; if it survives, the rule set really does have two readings of the same symbols and the rules must change.
Two forms in a filing tray with identical text but different filing rules: a clerk who may only look at the sheet in front of them will always file both the same way, and the second form's drawer stays empty.
saying these in an interview costs you the question
- Suggests fixing it by reordering the two rules
- Says the parser tries both reductions and keeps the better tree
- Expects the failure at the conflicted state rather than much later
- Thinks a larger table construction removes every reduce-reduce conflict
- Treats it as equivalent in severity to a shift-reduce conflict
- Claims a later semantic pass can recover the discarded reading for free