✅ SLR — Fixing LR(0) with FOLLOW Sets
Problem: LR(0) reduces on all terminals — even ones that make no grammatical sense.
Fix: Only reduce A → α when the next token is in FOLLOW(A). Fewer conflicts!
Remaining Problem: FOLLOW sets are global — they don't know the specific context where A was invoked.
Fixed by: CLR (next page) — tracks exact per-item lookaheads, not global FOLLOW sets.
Parser 5 of 5

SLR(1) Parsing

Simple LR uses the same DFA as LR(0) but a smarter reduce strategy — restrict reductions using FOLLOW sets. See exactly where it helps, where it still fails, and why CLR is needed.

Recall the LR(0) Conflict

A Grammar That Breaks LR(0)

Consider the classic assignment grammar used by the Dragon Book to demonstrate SLR vs CLR:

Original Grammar

S → L = R
S → R
L → *R
L → id
R → L
This models assignments: id = id, *id = id, id = *id, etc.
L = lvalue (left-hand side), R = rvalue (right-hand side).

Augmented Grammar

[0]S' → S
[1]S → L = R
[2]S → R
[3]L → *R
[4]L → id
[5]R → L

The Conflict State: I₂

After building the LR(0) DFA for this grammar, state I₂ contains items for both S → L•=R and R → L•. This creates an immediate conflict on the = token.

⚠️ State I₂ — The Conflict
Items in I₂
S → L•=R
R → L•    ← COMPLETE! Reduce R → L
SHIFT on '='
We want to shift = to continue matching S → L = R. This is correct for an assignment statement.
REDUCE R → L on '='
LR(0) also wants to reduce R → L on all terminals including =. But semantically, R → L shouldn't happen right before =!
LR(0) CONFLICT: On token = in state I₂, we have both Shift and Reduce R→L — LR(0) cannot decide.

FOLLOW Sets — SLR's Secret Weapon

The Three Rules of FOLLOW

FOLLOW(A) = the set of terminals that can appear immediately after A in any valid sentential form.

Rule 1
$ ∈ FOLLOW(start symbol) — End-of-input can always follow the start.
Rule 2
A → αBβ: Add FIRST(β) \ {ε} to FOLLOW(B). Whatever can start β can appear after B.
Rule 3
A → αB or A → αBβ where ε ∈ FIRST(β): Add FOLLOW(A) to FOLLOW(B). If β can be empty, A's followers can also follow B.

Computing FOLLOW for S → L=R | R, L → *R | id, R → L

SLR Applied to I₂ — Does It Help?

SLR Rule: Reduce A → α Only When Next Token ∈ FOLLOW(A)

SLR says: instead of reducing on ALL terminals, only reduce when the next token is in FOLLOW(A). Let's apply this to state I₂.

Analysis of State I₂
FOLLOW(R) computed in Section 2:
Since = ∈ FOLLOW(R), SLR says: reduce R → L on =!
Shift action on =:
Shift = (for S → L•=R)
State still wants to shift = to continue matching.
❌ SLR Still Has a Conflict Here!
On token =:
  • Shift (to continue S → L = R)
  • Reduce R → L (because = ∈ FOLLOW(R) = {=, $})
SLR still has a shift-reduce conflict on = in state I₂!
Why does this happen? FOLLOW(R) includes = because of the production S → L = R — after an R, we can see = in some context. But not this context! FOLLOW sets are global — they don't know we're specifically inside S → L•=R.
CLR/LALR solution: In CLR, the item [R → L•, $] has lookahead {$} — NOT {=, $}. So reduce R→L only on $, and shift = without conflict. See CLR →

The Critical Difference: Global vs Per-Item Lookaheads

SLR: FOLLOW(R) = {=, $}
Global FOLLOW — computed by looking at all places where R appears. Includes = because of S → L=R, even though that = appears before R, not after it in I₂'s context.
→ Reduce R→L on {=, $} → CONFLICT on =
CLR: Lookahead for [R→L•] = {$}
Per-item lookahead — computed precisely for this specific item in this specific state. The only way we reach I₂ via R → L• is as part of S → R, so $ is the only valid lookahead.
→ Reduce R→L on {$} only → NO conflict!

Where SLR Actually Helps: A Cleaner Grammar

Grammar: S → CC, C → cC | d

For our familiar S→CC grammar, let's compare what LR(0) vs SLR would do in a hypothetical conflict scenario. First, let's compute FOLLOW sets.

Grammar (augmented)

[0]S' → S
[1]S → CC
[2]C → cC
[3]C → d

FOLLOW Sets

LR(0) vs SLR: The Reduce Difference

LR(0) State 4 (C → d•)
LR(0) Reduce Rule
Reduce C → d
On: c, d, $ (ALL terminals)
LR(0) reduces on every terminal — even if it doesn't make sense.
SLR State 4 (C → d•)
SLR Reduce Rule
Reduce C → d
Only when next ∈ FOLLOW(C) = {c, d, $}
In this case, FOLLOW(C) = {c, d, $} = all terminals, so no difference here.
For S→CC grammar: LR(0) and SLR produce the same table — FOLLOW(C) = {c, d, $} happens to be all terminals. The SLR improvement shows more clearly for grammars where FOLLOW is a proper subset of all terminals.
Concrete Example Where SLR Helps
Suppose we have: E → E+T | T and T → id. In LR(0), state with T → id• would reduce on ALL terminals including +. But if FOLLOW(T) = {+, $}, then SLR reduces only on + and $ — avoiding spurious reductions on tokens like * that would signal a conflict in more complex grammars.

Full SLR Table: S → L=R | R Grammar

All States I₀ – I₉

The DFA for the S→L=R grammar has 10 states. State I₂ is the notorious conflict state.

SLR Parsing Table

Compared to LR(0), SLR restricts reduce entries to FOLLOW(A) only. The red cell shows the remaining conflict in I₂.

State
id * = $ S L R

Parsing Simulation: id$

Parsing a Simple Valid String

Let's parse the simplest valid string: id followed by end-of-input. This exercises the path S → R → L → id. We use the S→CC grammar (which IS SLR-parseable without conflict) for a clean demonstration.

Parsing ccdd$ with SLR: For the S→CC grammar, the SLR table is identical to the LR(0) table (FOLLOW(C) = all terminals). The power of SLR shines for grammars where restricting reduce lookaheads actually eliminates conflicts.
Stack (states) Remaining Input Action Notes
Current State

SLR vs LR(0) — Side by Side

Aspect LR(0) SLR(1)
Reduce on ALL terminals (no lookahead) FOLLOW(A) only (1-token lookahead)
DFA states Same as SLR Same as LR(0)
Table size Same as SLR Same as LR(0)
Conflicts More conflicts Fewer conflicts (not zero)
Grammar class LR(0) grammars (rare) SLR(1) grammars (larger class)
Lookahead source None Global FOLLOW sets
Lookahead accuracy N/A Imprecise (global context)
Implementation Simplest Simple (just add FOLLOW check)
Handles S → L=R ❌ Conflict ❌ Still conflict (FOLLOW too broad)

The Parser Hierarchy

LR(0)
Smallest class
⊂
SLR(1)
+ FOLLOW sets
⊂
LALR(1)
+ merged lookaheads
⊂
CLR(1)
Exact lookaheads
⊂
All Deterministic CFGs
Largest class
In practice: Most real programming languages are LALR(1). Tools like Yacc, Bison, and ANTLR generate LALR parsers. CLR is theoretically more powerful but produces larger tables.

Key Takeaways

Same DFA, Smarter Table
SLR uses exactly the same LR(0) item sets and DFA. The only difference is in the reduce entries of the table.
FOLLOW is a Global Approximation
FOLLOW(A) includes all tokens that could follow A anywhere in the grammar — not just in this specific state.
Residual Conflicts
When a terminal is in FOLLOW(A) AND appears as a shift in the same state, SLR still conflicts. CLR resolves this.
Good Enough for Many Grammars
Many simple grammars (especially expression grammars with unambiguous precedence) are SLR(1) — SLR is sufficient for them.