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

TermDefinition
Augmented grammarThe grammar plus a new start symbol S′S' and production S′→SS' \to S; the completed item S′→S⋅S'\to S\cdot accepts only with $\text{\textdollar} next, rather than creating an ordinary reduce action
LR(0) itemA production with a dot in its body, for example A→X⋅YZA \to X \cdot Y Z: what has been seen (left of the dot) and what is expected
Complete itemDot at the right end, A→α⋅A\to\alpha\cdot: an ordinary reduction is possible if A is not the augmented start; the completed augmented start accepts only on the endmarker
Kernel itemS′→⋅SS' \to \cdot S or any item whose dot is not at the left end
CLOSURE(II)II plus, for every item A→α⋅BβA \to \alpha \cdot B \beta in it, all items B→⋅γB \to \cdot \gamma, repeated until nothing new appears
GOTO(I,XI, X)CLOSURE of all items A→αX⋅βA \to \alpha X \cdot \beta such that A→α⋅XβA \to \alpha \cdot X \beta is in II
Canonical LR(0) collectionAll item sets reachable from CLOSURE({S′→⋅S}\{S' \to \cdot S\}) by GOTO; these are the states

An item A→α⋅βA \to \alpha \cdot \beta is valid for a viable prefix γ\gamma if some rightmost derivation has the form S′⇒∗δAw⇒δαβwS' \Rightarrow^{*} \delta A w \Rightarrow \delta\alpha\beta w with γ=δα\gamma = \delta\alpha. The state reached by reading γ\gamma in the LR(0) automaton is exactly the set of items valid for γ\gamma.

Algorithms

Pseudocode uses I for item sets, X for a grammar symbol, and numbers states in the order they are first created.

Text
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 C

Filling the table

For each state IiI_i:

  1. If A→α⋅aβA \to \alpha \cdot a \beta is in IiI_i with aa a terminal and GOTO(Ii,aI_i, a) =Ij= I_j: ACTION[i,ai, a] == shift jj.
  2. If A→α⋅A \to \alpha \cdot is in IiI_i with A≠S′A \ne S':
    • LR(0): ACTION[i,ai, a] == reduce A→αA \to \alpha for every terminal aa and $\text{\textdollar}.
    • SLR(1): ACTION[i,ai, a] == reduce A→αA \to \alpha for every a∈FOLLOW(A)a \in \text{FOLLOW}(A) only.
  3. If S′→S⋅S' \to S \cdot is in IiI_i: ACTION[i,$i, \text{\textdollar}] == accept.
  4. GOTO[i,Bi, B] =j= j for each nonterminal BB with GOTO(Ii,BI_i, B) =Ij= I_j.

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

Text
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 error

The 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)

Text
S -> C C
C -> c C | d

The augmented grammar adds S′→SS' \to S. The canonical LR(0) collection has 7 states:

StateItemsTransitions
I0I_0S′→⋅SS' \to \cdot S, S→⋅CCS \to \cdot C C, C→⋅cCC \to \cdot c C, C→⋅dC \to \cdot dSS: 1, CC: 2, cc: 3, dd: 4
I1I_1S′→S⋅S' \to S \cdotnone (accept on $\text{\textdollar})
I2I_2S→C⋅CS \to C \cdot C, C→⋅cCC \to \cdot c C, C→⋅dC \to \cdot dCC: 5, cc: 3, dd: 4
I3I_3C→c⋅CC \to c \cdot C, C→⋅cCC \to \cdot c C, C→⋅dC \to \cdot dCC: 6, cc: 3, dd: 4
I4I_4C→d⋅C \to d \cdotnone
I5I_5S→CC⋅S \to C C \cdotnone
I6I_6C→cC⋅C \to c C \cdotnone

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(CC) ={c,d,$}= \{c, d, \text{\textdollar}\} and FOLLOW(SS) ={$}= \{\text{\textdollar}\}, so I5I_5 reduces only on $\text{\textdollar}.

Statecd$SSCC
0s3s412
1acc
2s3s45
3s3s46
4r C→dC \to dr C→dC \to dr C→dC \to d
5r S→CCS \to C C
6r C→cCC \to c Cr C→cCC \to c Cr C→cCC \to c C

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 3×3=93 \times 3 = 9 reduce entries. The SLR table keeps all 3 for states 4 and 6 (FOLLOW(CC) 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)SymbolsInputAction
0c d d $s3
0 3cd d $s4
0 3 4c dd $r C→dC \to d: pop 1, GOTO[3, CC] =6= 6
0 3 6c Cd $r C→cCC \to c C: pop 2, GOTO[0, CC] =2= 2
0 2Cd $s4
0 2 4C d$r C→dC \to d: pop 1, GOTO[2, CC] =5= 5
0 2 5C C$r S→CCS \to C C: pop 2, GOTO[0, SS] =1= 1
0 1S$accept

3 shifts and 4 reductions. After a reduction the new state depends on the state uncovered by the pops: the same CC goes to state 6 above state 3, to 2 above state 0 and to 5 above state 2.

LR(0) automaton of the grammar S to C C, C to c C or d
Figure 1. The seven-state LR(0) automaton of S→CCS \to C C, C→cC∣dC \to c C \mid d, with the items of each state and its transitions; states 1, 4, 5 and 6 contain complete items and no other item.

A grammar that is SLR(1) but not LR(0)

The expression grammar E→E+T∣TE \to E + T \mid T, T→T∗F∣FT \to T * F \mid F, F→(E)∣idF \to ( E ) \mid \textbf{id} has 12 LR(0) states, I0I_0 to I11I_{11}. Two of them contain a complete item together with a shift:

  • I2={E→T⋅,  T→T⋅∗F}I_2 = \{E \to T \cdot,\; T \to T \cdot * F\}
  • I9={E→E+T⋅,  T→T⋅∗F}I_9 = \{E \to E + T \cdot,\; T \to T \cdot * F\}

In the LR(0) table both states reduce on every token, including *, where they also shift (to I7I_7): two shift-reduce conflicts, so the grammar is not LR(0). In the SLR table the reductions go only on FOLLOW(EE) ={+,),$}= \{+, ), \text{\textdollar}\}, 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)

Text
S -> L = R | R
L -> * R | id
R -> L

The LR(0) collection has 10 states. State I2={S→L⋅=R,  R→L⋅}I_2 = \{S \to L \cdot = R,\; R \to L \cdot\} shifts on = (to I6I_6). SLR reduces R→LR \to L on FOLLOW(RR), and FOLLOW(RR) contains = (from S→L=RS \to L = R and L→∗RL \to * R: RR can end an LL 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(RR) for every state, while in state 2 an = can never follow an RR that was just reduced from the LL at the start of a statement. The LALR and canonical LR methods of the next note track that context and have no conflict.

LR(0) and SLR conflicts in the expression grammar and in the L = R grammar
Figure 2. Left: state I2I_2 of the expression grammar, an LR(0) shift-reduce conflict on * that SLR removes because * is not in FOLLOW(E). Right: state I2I_2 of the L = R grammar, where = is in FOLLOW(R), so the SLR table keeps the shift-reduce conflict.

Quick classification

GrammarLR(0)SLR(1)Where the conflict is
S -> C C, C -> c C | dYesYesnone
Expression grammarNoYesI2I_2, I9I_9 on * (LR(0) only)
S -> a A c, A -> b A | bNoYesstate with A→b⋅AA \to b \cdot A and A→b⋅A \to b \cdot, on b (LR(0) only); FOLLOW(AA) ={c}= \{c\}
S -> a S b | epsNoYesstates with S→⋅S \to \cdot and a shift on a (LR(0) only); FOLLOW(SS) ={b,$}= \{b, \text{\textdollar}\}
S -> a S b | a bYesYesnone: the complete items S→aSb⋅S \to a S b \cdot and S→ab⋅S \to a b \cdot are each alone in their states
S -> L = R | R, L -> * R | id, R -> LNoNoI2I_2 on =
S -> A a A b | B b B a, A -> eps, B -> epsNoNoI0I_0: reduce-reduce on a and b
Dangling-else grammarNoNoshift-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 A→α⋅A \to \alpha \cdot conflicts with a shift on aa only if a∈FOLLOW(A)a \in \text{FOLLOW}(A), 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 XX has every kernel item with XX 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.
  • ε\varepsilon-productions and LR(0). A production A→εA \to \varepsilon puts the complete item A→⋅A \to \cdot into every state whose closure adds AA-items. If that state also shifts, LR(0) has a conflict. S -> a S b | eps fails LR(0) for this reason, while S -> 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 ∣β∣\lvert\beta\rvert 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 = R grammar 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(I0I_0, ()?" 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 $\text{\textdollar}); in SLR, only in its head's FOLLOW columns. The completed augmented-start item instead accepts only on $\text{\textdollar}.
  • Trace the state stack. Questions give a table and ask for the stack after kk moves; pop ∣β∣\lvert\beta\rvert states on each reduction and push GOTO of the uncovered state.
  • Containment. LR(0) ⊂\subset SLR(1) ⊂\subset LALR(1) ⊂\subset LR(1) as classes of grammars, all strict. LR(0) can fail with ε\varepsilon-productions or with lists such as A -> b A | b.

Summary

Sources

  1. 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).

Next steps