Bottom-up parsing and LR
The LR parser: the stack of states and symbols, the ACTION and GOTO tables, the parsing algorithm and its configurations, what LR(k) means and why it is the most general deterministic bottom-up method, error detection, and an overview of the four table constructions LR(0), SLR(1), LALR(1) and LR(1).
Why it exists
A shift-reduce parser must decide, at every moment, whether to shift or to reduce, and by which production. Looking through the stack for a handle would be slow and ambiguous. The LR parser solves it with a finite automaton: the stack stores, together with every grammar symbol, the state of an automaton that has already read the whole stack. The state and the next input token then determine the move, by a table look-up. LR parsing is fast (linear time), handles the largest class of grammars of any deterministic bottom-up method, detects errors at the earliest token, and can be generated automatically from the grammar.
Prerequisites
You need shift-reduce parsing, handles and viable prefixes (shift-reduce parsing). The tables are built from FIRST and FOLLOW or from lookahead sets on the next pages.
Precise definitions
LR(). Left-to-right scan of the input, Rightmost derivation in reverse, tokens of lookahead. The parser makes every decision from the stack contents and the next tokens. In GATE, is 0 or 1. A grammar is LR() if such a parser exists for it. LR(1) grammars generate exactly the deterministic context-free languages, so nothing is gained by using for the languages (some grammars become simpler).
The LR parser. An input buffer ending in $, a stack that alternates states and grammar symbols (the top is ), and a parsing table with two parts:
- ACTION[, ] for a state and a terminal (or
$) : one of- shift : push and the state ;
- reduce (written for production number ): pop entries ( symbols and their states), let be the new top state, push and GOTO[, ];
- accept;
- error (an empty cell).
- GOTO[, ] for a state and a nonterminal : the state to push after a reduction to .
Algorithm. Let be the state on top and the next token. Look up ACTION[, ] and do what it says; repeat until accept or error. The sequence of reductions is a rightmost derivation in reverse. The cost is linear in the input length: every token is shifted once and the number of reductions is bounded by the size of the tree.
Configuration. A pair (stack, remaining input). The stack contents plus the input is a right-sentential form.
Error detection. The parser reports an error as soon as it looks at an empty ACTION cell. LR parsers (like LL(1) parsers) have the viable-prefix property: they never shift a token that cannot extend a valid prefix of some sentence, so the error is detected at the earliest possible token (canonical LR(1); SLR and LALR may perform some extra reductions before noticing the error, but never shift the offending token).
The four table-building methods (details on the next two pages):
| Method | Item sets | Reduce on | Typical use |
|---|---|---|---|
| LR(0) | LR(0) items | every terminal | a teaching case; very few grammars |
| SLR(1) | LR(0) items | tokens in FOLLOW() | simple, small tables |
| LALR(1) | LR(0) states with LR(1) lookaheads merged | the merged lookahead of the item | Yacc and Bison |
| LR(1) / CLR(1) | LR(1) items | the lookahead of the item | most powerful, biggest tables |
All four use the same driver; only the way the table is filled differs. The size of the table (the number of states) is the number of LR(0) states for LR(0), SLR and LALR, and larger for canonical LR(1).
Why LR is more powerful than LL. An LL parser must pick a production after seeing only the first token that the production derives. An LR parser waits until the whole right side has been seen (and one more token). Left recursion is natural for LR (and keeps the stack shallow); it is fatal for LL.
How it works
The animation parses with the SLR(1) table of the expression grammar. The stack alternates states and symbols (the top is at the right). The cell consulted in the table is outlined at each step. For a reduce you also see in the explanation which GOTO entry gives the next state. Follow one reduce slowly: in the step "reduce " the parser pops two stack entries (the symbol and its state 3), looks at the state that is now on top (0), reads GOTO[0, ] = 2, and pushes and 2.
SLR(1) parse of id + id * id: start
Parser run by a script, not typedLR parsing with the SLR(1) table: the stack alternates states and symbols (top at the right).
- 1E → E + T
- 2E → T
- 3T → T * F
- 4T → F
- 5F → ( E )
- 6F → id
| state | + | * | ( | ) | id | $ | E | T | F |
|---|---|---|---|---|---|---|---|---|---|
| 0 | s4 | s5 | 1 | 2 | 3 | ||||
| 1 | s6 | acc | |||||||
| 2 | r2 | s7 | r2 | r2 | |||||
| 3 | r4 | r4 | r4 | r4 | |||||
| 4 | s4 | s5 | 8 | 2 | 3 | ||||
| 5 | r6 | r6 | r6 | r6 | |||||
| 6 | s4 | s5 | 9 | 3 | |||||
| 7 | s4 | s5 | 10 | ||||||
| 8 | s6 | s11 | |||||||
| 9 | r1 | s7 | r1 | r1 | |||||
| 10 | r3 | r3 | r3 | r3 | |||||
| 11 | r5 | r5 | r5 | r5 |
Step 0
The stack holds the start state 0. The parser looks at the state on top and the next input token, and the ACTION table says shift, reduce, accept or error; after a reduce the GOTO table gives the new state.
The next animation shows an error. After id + the state is 6 and the parser sees another +: the cell ACTION[6, +] is empty, because after a plus an operand must come. The error is reported at that token, without shifting it.
SLR(1) parse of id + + id (a syntax error): start
Parser run by a script, not typedLR parsing with the SLR(1) table: the stack alternates states and symbols (top at the right).
- 1E → E + T
- 2E → T
- 3T → T * F
- 4T → F
- 5F → ( E )
- 6F → id
| state | + | * | ( | ) | id | $ | E | T | F |
|---|---|---|---|---|---|---|---|---|---|
| 0 | s4 | s5 | 1 | 2 | 3 | ||||
| 1 | s6 | acc | |||||||
| 2 | r2 | s7 | r2 | r2 | |||||
| 3 | r4 | r4 | r4 | r4 | |||||
| 4 | s4 | s5 | 8 | 2 | 3 | ||||
| 5 | r6 | r6 | r6 | r6 | |||||
| 6 | s4 | s5 | 9 | 3 | |||||
| 7 | s4 | s5 | 10 | ||||||
| 8 | s6 | s11 | |||||||
| 9 | r1 | s7 | r1 | r1 | |||||
| 10 | r3 | r3 | r3 | r3 | |||||
| 11 | r5 | r5 | r5 | r5 |
Step 0
The stack holds the start state 0. The parser looks at the state on top and the next input token, and the ACTION table says shift, reduce, accept or error; after a reduce the GOTO table gives the new state.
Worked examples
EX 1Use the table: grammar S → C C, C → c C | d
EasyProductions: (1) , (2) , (3) . The canonical LR(1) table (the LALR(1) and SLR(1) tables are similar; see the later pages) has the states 0 to 9:
| state | c | d | $ | S | C |
|---|---|---|---|---|---|
| 0 | s3 | s4 | 1 | 2 | |
| 1 | acc | ||||
| 2 | s6 | s7 | 5 | ||
| 3 | s3 | s4 | 8 | ||
| 4 | r3 | r3 | |||
| 5 | r1 | ||||
| 6 | s6 | s7 | 9 | ||
| 7 | r3 | ||||
| 8 | r2 | r2 | |||
| 9 | r2 |
Parse d d. Stack 0, input d d $: ACTION[0, d] = s4, so push d 4. Now state 4, next d: r3 (): pop d 4, top is 0, GOTO[0, C] = 2, push C 2. State 2, next d: s7, push d 7. State 7, next $: r3: pop d 7, top is 2, GOTO[2, C] = 5, push C 5. State 5, next $: r1 (): pop C 5 C 2... (four entries), top is 0, GOTO[0, S] = 1, push S 1. State 1, $: accept. Moves: shift, reduce, shift, reduce, reduce, accept (checked against the program's own run: 0 d 4, 0 C 2, 0 C 2 d 7, 0 C 2 C 5, 0 S 1).
EX 2How many reduces and shifts?
EasyFor the parser makes 5 shifts and 8 reduces, then accepts: 13 moves and the accept, 15 lines in the animation counting the start. The stack is deepest after the last id is shifted: 0 E 1 + 6 T 9 * 7 id 5, which is 11 entries (6 states and 5 symbols); in terms of grammar symbols the stack holds at most 5 symbols (E + T * id). A question that asks for the maximum stack height must say whether states are counted.
EX 3Read an error from the table
MediumFor the expression table, ACTION[0, +] is empty: a sentence cannot start with a plus. ACTION[4, $] is empty: after ( the input cannot end. ACTION[8, id] is empty: after ( E an identifier cannot appear. In each case the parser stops in that state, before shifting the offending token. In contrast, a reduce entry may be present for tokens that are in FOLLOW of the left side but not valid here (SLR); then the parser first performs some reductions and notices the error a few moves later, still before shifting that token.
EX 4Count states
MediumThe grammar , has 7 states in the LR(0) automaton (and therefore in SLR(1) and LALR(1)), and 10 in the canonical LR(1) automaton. The expression grammar has 12 states for LR(0), SLR(1) and LALR(1) and 22 in canonical LR(1). (Both were computed and compared with a second implementation; the first matches the textbook example.) The difference is the price of the precise lookaheads.
EX 5Which statements are true of LR parsers?
GATE level(a) "An LR parser uses a stack of states." True: the stack is a stack of states (with symbols as documentation). (b) "LR parsing can handle left-recursive grammars." True. (c) "Every LR(1) grammar is unambiguous." True. (d) "LR(1) parsers need the grammar to have no ε-productions." False; ε-productions are handled by reducing with an empty handle. (e) "An LR(0) parser never looks at the input to decide a reduction." True for LR(0): reduce is the only action in a state with a complete item, regardless of the token (which is why LR(0) is so weak). (f) "The LALR(1) table has the same number of states as the SLR(1) table." True; they differ only in the reduce entries.
Cheat box
Cheat box
- LR(): Left-to-right, Rightmost derivation in reverse, lookahead. LR(1) = deterministic CFLs.
- Stack of states (and symbols). ACTION[state, terminal]: shift / reduce / accept / error. GOTO[state, nonterminal].
- Reduce by : pop symbols (and states), push and GOTO[top, ].
- Moves = tokens (shifts) + nonterminal nodes (reduces) + accept. Linear time.
- Errors found before shifting the bad token; canonical LR(1) detects it with no extra reductions.
- Methods: LR(0) ⊂ SLR(1) ⊂ LALR(1) ⊂ LR(1) in power; LR(0), SLR, LALR have the same states.
Traps and GATE patterns
Connections
Builds on
Unlocks
Across subjects
No cross-subject links yet.
Within this subject
Journeys that pass through here
The method is the table-driven form of shift-reduce parsing. The finite automaton and the first two table methods are in LR(0) and SLR(1); the lookahead-based methods are in CLR(1) and LALR(1); all are compared with LL(1) in the parser hierarchy. The semantic actions attached to reductions compute attributes in syntax-directed definitions.
PYQs
1 previous year question from your book. I re-solved each one myself (0 by running or simulating, 1 by reasoning only); the book's key is shown next to my answer. All PYQs
Which one of the following kinds of derivation is used by LR parsers?
- (a)Leftmost in reverse
- (b)Rightmost in reverse
- (c)Leftmost
- (d)Rightmost
Self-check
Question 1
The stack of an LR parser holds states and the next token reads ACTION[6, id] = s5. What is on the stack afterwards?
Show answerHide
: the token and the state 5 are pushed.
Question 2
An entry says reduce by with the stack . What is the stack after the pops, and what is looked up next?
Show answerHide
Pop entries: the stack is ; GOTO[6, ] = 9 gives .
Question 3
Which methods give the same number of states for one grammar?
Show answerHide
LR(0), SLR(1) and LALR(1). Canonical LR(1) has at least as many.
Question 4
Is every LL(1) grammar LR(1)?
Show answerHide
Yes. LR parsing is more general than LL parsing: every LL() grammar is LR() (an LR parser knows the whole right side before deciding, an LL parser only the first tokens).
Revision card
One-screen revision
- LR parser: stack of states + ACTION and GOTO tables; shift, reduce (pop , GOTO), accept, error.
- LR(k): left-to-right, rightmost derivation reversed, k lookahead; LR(1) = DCFLs.
- Methods differ in reduce entries: LR(0) all, SLR FOLLOW, LALR merged lookahead, LR(1) exact.
- LR(0)=SLR=LALR states; LR(1) more. Detects errors before shifting the bad token.
References
- ·Aho, Lam, Sethi, Ullman, Compilers: Principles, Techniques, and Tools (2nd edition), Chapter 4 Syntax Analysis (4.5 and 4.6 introduction to LR parsing: simple LR; the LR-parsing algorithm, structure of the LR parsing table)
- ·Cooper and Torczon, Engineering a Compiler, Chapter 3 Parsers (LR(1) parsing, the table-driven skeleton parser)
Verification
The parse animations are produced by a table-driven LR driver run by script, with the table of the expression grammar shown in the viewer; tests/cd-traces.test.ts re-simulates every move in TypeScript from the table printed in the trace. scripts/enum-checks/cd_lr.py checks that for every conflict-free table the driver accepts exactly the sentences of the grammar up to length 6 (eight grammars), and that the reductions form a rightmost derivation in reverse. The claim that LR(1) grammars generate exactly the deterministic context-free languages is a standard theorem quoted from textbooks, not machine-checked. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand or by a small script (token counts, FIRST and FOLLOW sets, LL(1) tables and moves, LR item sets, state counts and parses, operator-precedence values, attribute evaluation and printing schemes, activation-record counts and access links, parameter-passing results, three-address code, jumping and backpatched code, leaders and blocks, value numbering and DAGs, gen/kill and data flow sets, Sethi-Ullman labels and live ranges); long C programs were not re-read line by line (they are compiled and compared by npm run verify:c, and their printed outputs were checked against the prose); tables and animations are machine output and were read, not re-run; No other defect found. Status raised to self-checked; verified needs a textbook or human check.
last verified: never
My notes (saved in this browser)