Introduction
An LR parser is a shift-reduce parser that decides each action from a table indexed by a state on top of its stack and the next input token. The states are the states of a DFA that recognises viable prefixes, so the parser always knows which productions it might be in the middle of. LR parsers handle left recursion, detect errors at the earliest possible token, and cover every grammar that LL(1) covers.
This note builds the simplest version. LR(0) items and the LR(0) automaton give the states. An LR(0) table places ordinary reductions for complete non-augmented production items in every ACTION column; an SLR(1) ("simple LR") table places those reductions only on tokens in FOLLOW of the production's head. In both, the completed augmented-start item accepts only on the endmarker; it is not an ordinary reduction. The difference between the two, and the conflicts each can leave, is the set of table-construction and conflict-analysis skills this note teaches.
Prerequisites
- Bottom-Up Parsing and Shift-Reduce: handles, viable prefixes, shift-reduce and reduce-reduce conflicts.
- FIRST and FOLLOW sets (see the note FIRST and FOLLOW Sets): SLR reductions are placed on FOLLOW of the head.
Core concepts
| Term | Definition |
|---|---|
| Augmented grammar | The grammar plus a new start symbol and production ; the completed item accepts only with next, rather than creating an ordinary reduce action |
| LR(0) item | A production with a dot in its body, for example : what has been seen (left of the dot) and what is expected |
| Complete item | Dot at the right end, : an ordinary reduction is possible if A is not the augmented start; the completed augmented start accepts only on the endmarker |
| Kernel item | or any item whose dot is not at the left end |
| CLOSURE() | plus, for every item in it, all items , repeated until nothing new appears |
| GOTO() | CLOSURE of all items such that is in |
| Canonical LR(0) collection | All item sets reachable from CLOSURE() by GOTO; these are the states |
An item is valid for a viable prefix if some rightmost derivation has the form with . The state reached by reading in the LR(0) automaton is exactly the set of items valid for .
Algorithms
Pseudocode uses I for item sets, X for a grammar symbol, and numbers states in the order they are first created.
CLOSURE(I)
J <- I
repeat
for each item A -> alpha . B beta in J, B a nonterminal
for each production B -> gamma
add B -> . gamma to J
until no item is added
return J
GOTO(I, X)
return CLOSURE({ A -> alpha X . beta : A -> alpha . X beta in I })
LR0-COLLECTION(G')
C <- [ CLOSURE({ S' -> . S }) ]
for each state I in C, in order
for each symbol X appearing after a dot in I
J <- GOTO(I, X); if J not in C then append J to C
return CFilling the table
For each state :
- If is in with a terminal and GOTO() : ACTION[] shift .
- If is in with :
- LR(0): ACTION[] reduce for every terminal and .
- SLR(1): ACTION[] reduce for every only.
- If is in : ACTION[] accept.
- GOTO[] for each nonterminal with GOTO() .
All remaining entries are errors. A grammar is LR(0) or SLR(1) if the corresponding table has no entry with two actions.
The LR driver
LR-PARSE(ACTION, GOTO, input)
push state 0
a <- first token of input$
loop
s <- state on top of stack
if ACTION[s, a] = shift t then push t; a <- next token
else if ACTION[s, a] = reduce A -> beta
pop |beta| states; t <- top state; push GOTO[t, A]
else if ACTION[s, a] = accept then return success
else errorThe driver is the same for LR(0), SLR, LALR and canonical LR; only the table differs. Each token is shifted once and each reduction corresponds to one parse-tree node, so parsing is linear in the input length.
Worked examples
A grammar that is LR(0)
S -> C C
C -> c C | dThe augmented grammar adds . The canonical LR(0) collection has 7 states:
| State | Items | Transitions |
|---|---|---|
| , , , | : 1, : 2, : 3, : 4 | |
| none (accept on ) | ||
| , , | : 5, : 3, : 4 | |
| , , | : 6, : 3, : 4 | |
| none | ||
| none | ||
| none |
Every state with a complete item has no other item, so there is no conflict: the grammar is LR(0), and therefore also SLR(1). The SLR table differs from the LR(0) table only in where the reductions appear: FOLLOW() and FOLLOW() , so reduces only on .
| State | c | d | $ | ||
|---|---|---|---|---|---|
| 0 | s3 | s4 | 1 | 2 | |
| 1 | acc | ||||
| 2 | s3 | s4 | 5 | ||
| 3 | s3 | s4 | 6 | ||
| 4 | r | r | r | ||
| 5 | r | ||||
| 6 | r | r | r |
Counting reduce entries. States 4, 5 and 6 each hold one complete item. The LR(0) table reduces in all three ACTION columns of each, so it has reduce entries. The SLR table keeps all 3 for states 4 and 6 (FOLLOW() has three elements) but only 1 for state 5: 7 reduce entries.
Parsing c d d with the table. The stack holds states; the grammar symbols are shown only to help reading.
| Stack (states) | Symbols | Input | Action |
|---|---|---|---|
| 0 | c d d $ | s3 | |
| 0 3 | c | d d $ | s4 |
| 0 3 4 | c d | d $ | r : pop 1, GOTO[3, ] |
| 0 3 6 | c C | d $ | r : pop 2, GOTO[0, ] |
| 0 2 | C | d $ | s4 |
| 0 2 4 | C d | $ | r : pop 1, GOTO[2, ] |
| 0 2 5 | C C | $ | r : pop 2, GOTO[0, ] |
| 0 1 | S | $ | accept |
3 shifts and 4 reductions. After a reduction the new state depends on the state uncovered by the pops: the same goes to state 6 above state 3, to 2 above state 0 and to 5 above state 2.

A grammar that is SLR(1) but not LR(0)
The expression grammar , , has 12 LR(0) states, to . Two of them contain a complete item together with a shift:
In the LR(0) table both states reduce on every token, including *, where they also shift (to ): two shift-reduce conflicts, so the grammar is not LR(0). In the SLR table the reductions go only on FOLLOW() , which does not contain *. The conflicts disappear and the grammar is SLR(1). This is exactly the decision seen in the bottom-up trace: with T on the stack, reduce on +, shift on *.
A grammar that is not SLR(1)
S -> L = R | R
L -> * R | id
R -> LThe LR(0) collection has 10 states. State shifts on = (to ). SLR reduces on FOLLOW(), and FOLLOW() contains = (from and : can end an that is followed by =). So ACTION[2, =] holds both shift and reduce: a shift-reduce conflict. The grammar is unambiguous; SLR is simply too weak, because it uses FOLLOW() for every state, while in state 2 an = can never follow an that was just reduced from the at the start of a statement. The LALR and canonical LR methods of the next note track that context and have no conflict.

Quick classification
| Grammar | LR(0) | SLR(1) | Where the conflict is |
|---|---|---|---|
S -> C C, C -> c C | d | Yes | Yes | none |
| Expression grammar | No | Yes | , on * (LR(0) only) |
S -> a A c, A -> b A | b | No | Yes | state with and , on b (LR(0) only); FOLLOW() |
S -> a S b | eps | No | Yes | states with and a shift on a (LR(0) only); FOLLOW() |
S -> a S b | a b | Yes | Yes | none: the complete items and are each alone in their states |
S -> L = R | R, L -> * R | id, R -> L | No | No | on = |
S -> A a A b | B b B a, A -> eps, B -> eps | No | No | : reduce-reduce on a and b |
| Dangling-else grammar | No | No | shift-reduce on e |
Important properties and observations
- Conflict tests. An LR(0) state has a shift-reduce conflict if it has a complete non-augmented item (head other than the augmented start) and an item with a terminal after the dot; a reduce-reduce conflict if it has two complete reduction items. The augmented completed start item accepts only on the endmarker; it is not a reduce-on-all-terminals item. In SLR, a complete item conflicts with a shift on only if , and two complete items conflict only if their heads' FOLLOW sets intersect.
- SLR never has more conflicts than LR(0). Its reduce entries are a subset of LR(0)'s, on the same automaton. Every LR(0) grammar is SLR(1).
- Same states. LR(0) and SLR use the same automaton, so they have the same number of states; LALR also has that number (next note).
- Item sets and nonterminals. A state reached on a symbol has every kernel item with just before the dot; that is why the transitions on a symbol always go to states whose kernel items "just passed" that symbol.
- Error detection. An LR parser never shifts a token that cannot extend the viable prefix, so errors are found at the first wrong token. SLR (and LALR) may do a few extra reductions before reporting the error, but never an extra shift.
- Ambiguous grammars are never LR. A conflict will appear for any LR method. Parser generators still accept ambiguous expression grammars by resolving each conflict with declared precedence and associativity.
- -productions and LR(0). A production puts the complete item into every state whose closure adds -items. If that state also shifts, LR(0) has a conflict.
S -> a S b | epsfails LR(0) for this reason, whileS -> a S b | a b, for the same language without the empty string, is LR(0). - GOTO after a reduction is read from the state uncovered by popping states, not from the state that held the handle.
Common misconceptions.
- "LR(0) parsers use no lookahead at all." They look at the next token to choose the shift target; they do not use it to decide whether to reduce.
- "SLR needs a different automaton." It reuses the LR(0) automaton; only the reduce entries change.
- "A shift-reduce conflict in SLR means the grammar is ambiguous." The
L = Rgrammar is unambiguous and still conflicts.
GATE examination perspective
- Count states. Build the canonical LR(0) collection carefully; the count is the same for LR(0), SLR and LALR tables.
- Closure and goto questions. "Which items are in GOTO(,
()?" Take the kernel items that move the dot past(, then close. - Is the grammar LR(0) or SLR(1)? Find states with complete non-augmented reduction items; check what else they contain and, for SLR, FOLLOW of their heads. Handle the completed augmented-start accept action only on the endmarker.
- Count conflicts or reduce entries. In LR(0), a complete non-augmented production item reduces in every ACTION column (all terminals and ); in SLR, only in its head's FOLLOW columns. The completed augmented-start item instead accepts only on .
- Trace the state stack. Questions give a table and ask for the stack after moves; pop states on each reduction and push GOTO of the uncovered state.
- Containment. LR(0) SLR(1) LALR(1) LR(1) as classes of grammars, all strict. LR(0) can fail with -productions or with lists such as
A -> b A | b.
Summary
Sources
- A. V. Aho, M. S. Lam, R. Sethi, J. D. Ullman, Compilers, Principles, Techniques, and Tools, 2nd ed., Pearson Addison-Wesley, 2007: Section 4.6.1 (why LR parsers), Section 4.6.2 (items and the LR(0) automaton), Section 4.6.3 (the LR-parsing algorithm), Section 4.6.4 (constructing SLR-parsing tables), Section 4.6.5 (viable prefixes), Section 4.8 (using ambiguous grammars).