Algorithm Search⌘K

Proofs: LR(k) parsing

These are the human proofs of LR(k) parsing, at full length.

The canonical LR(k) parser accepts exactly the sentences, returns their parse trees, and reports each error at the first bad token full

This proof shows: correctness.

Statement. Let GG be a grammar in which every nonterminal derives some terminal string, augmented with S′→SS' \to S, let k≥0k \ge 0, and suppose that LRK-TABLES reports no conflict. Then for every input w=a1⋯anw = a_1 \cdots a_n:

  1. if LR-PARSE returns a tree, it is a parse tree of ww with root SS;
  2. if w∈L(G)w \in L(G), LR-PARSE returns a tree;
  3. if LR-PARSE reports an error at position pp (with p=n+1p = n + 1 for the end of the input), then a1⋯ap−1a_1 \cdots a_{p-1} is a prefix of a sentence, and a1⋯apa_1 \cdots a_p is not when p≤np \le n;
  4. LR-PARSE stops after O(n+1)O(n + 1) steps.

Setup. As on the LL(k) parsing page, the computed FIRSTk\mathrm{FIRST}_k sets are exact, FIRSTk(αβ)=FIRSTk(α)⊕kFIRSTk(β)\mathrm{FIRST}_k(\alpha \beta) = \mathrm{FIRST}_k(\alpha) \oplus_k \mathrm{FIRST}_k(\beta), and L(α)≠∅L(\alpha) \ne \emptyset for every string α\alpha. For a string γ\gamma of grammar symbols, let st(γ)\mathrm{st}(\gamma) be the state reached from I0I_0 by GOTO along γ\gamma, when it exists. Each stack entry is a symbol XX, a tree with root XX and a state. A shift pushes GOTO[s,ai]\mathrm{GOTO}[s, a_i] and a reduction pushes GOTO[s′,A]\mathrm{GOTO}[s', A], so the state on top is always st(γ)\mathrm{st}(\gamma), where γ\gamma is the string of stack symbols. Every kernel item [A→β1X⋅β2,u][A \to \beta_1 X \cdot \beta_2, u] of a GOTO state comes from the item [A→β1⋅Xβ2,u][A \to \beta_1 \cdot X \beta_2, u] of the previous state, and every item with the dot at the start, other than [S′→⋅S,ε][S' \to \cdot S, \varepsilon], is added by closure. The item [S′→⋅S,ε][S' \to \cdot S, \varepsilon] is only in I0I_0, because S′S' is on no right side.

Lemma 1 (validity). If [A→β1⋅β2,u]∈st(γ)[A \to \beta_1 \cdot \beta_2, u] \in \mathrm{st}(\gamma), there is a rightmost derivation S′⇒rm∗αAy⇒rmαβ1β2yS' \Rightarrow_{rm}^* \alpha A y \Rightarrow_{rm} \alpha \beta_1 \beta_2 y with y∈Σ∗y \in \Sigma^*, αβ1=γ\alpha \beta_1 = \gamma and FIRSTk(y)=u\mathrm{FIRST}_k(y) = u.

Proof. By induction on the order in which the construction adds items.

  • The start item. For [S′→⋅S,ε]∈I0[S' \to \cdot S, \varepsilon] \in I_0, take the empty derivation with α=y=ε\alpha = y = \varepsilon.
  • GOTO. If [A→β1X⋅β2,u]∈st(γX)[A \to \beta_1 X \cdot \beta_2, u] \in \mathrm{st}(\gamma X) comes from [A→β1⋅Xβ2,u]∈st(γ)[A \to \beta_1 \cdot X \beta_2, u] \in \mathrm{st}(\gamma), the derivation for the latter has αβ1=γ\alpha \beta_1 = \gamma, so αβ1X=γX\alpha \beta_1 X = \gamma X.
  • Closure. Suppose [B→⋅δ,v][B \to \cdot \delta, v] is added from [A→β1⋅Bβ2,u]∈st(γ)[A \to \beta_1 \cdot B \beta_2, u] \in \mathrm{st}(\gamma) with v∈FIRSTk(β2)⊕k{u}v \in \mathrm{FIRST}_k(\beta_2) \oplus_k \{u\}. Take the derivation of the latter. Since u=FIRSTk(y)u = \mathrm{FIRST}_k(y), v=FIRSTk(zy)v = \mathrm{FIRST}_k(z y) for some z∈L(β2)z \in L(\beta_2). Rewriting β2\beta_2 to zz only touches symbols to the right of BB, so it is rightmost: S′⇒rm∗αAy⇒rmαβ1Bβ2y⇒rm∗γBzy⇒rmγδzyS' \Rightarrow_{rm}^* \alpha A y \Rightarrow_{rm} \alpha \beta_1 B \beta_2 y \Rightarrow_{rm}^* \gamma B z y \Rightarrow_{rm} \gamma \delta z y, with FIRSTk(zy)=v\mathrm{FIRST}_k(z y) = v. □\square

Lemma 2 (completeness). Let tt be a parse tree with root SS, under the extra root S′S'. Let xx be an inner node of tt with production A→β1β2A \to \beta_1 \beta_2, where β1\beta_1 is any prefix of the right side. Let α\alpha be the labels of the left siblings of the proper ancestors of xx and of xx itself, in order, and let yy be the part of the yield of tt to the right of xx. Then st(αβ1)\mathrm{st}(\alpha \beta_1) exists and contains [A→β1⋅β2,FIRSTk(y)][A \to \beta_1 \cdot \beta_2, \mathrm{FIRST}_k(y)].

Proof. We use induction on the depth of xx. For the root S′S', take the start item. Let xx be a child of x′x', with production B→δAηB \to \delta A \eta, where xx is the child labeled AA after δ\delta. By the induction hypothesis, [B→δ⋅Aη,FIRSTk(y′)]∈st(α′δ)[B \to \delta \cdot A \eta, \mathrm{FIRST}_k(y')] \in \mathrm{st}(\alpha' \delta), where α′\alpha' and y′y' belong to x′x'. Here α=α′δ\alpha = \alpha' \delta, and yy is the yield of the subtrees of η\eta followed by y′y'. So FIRSTk(y)∈FIRSTk(η)⊕k{FIRSTk(y′)}\mathrm{FIRST}_k(y) \in \mathrm{FIRST}_k(\eta) \oplus_k \{\mathrm{FIRST}_k(y')\}, and closure puts [A→⋅β1β2,FIRSTk(y)][A \to \cdot \beta_1 \beta_2, \mathrm{FIRST}_k(y)] into st(α)\mathrm{st}(\alpha). GOTO along β1\beta_1 moves the dot, and each GOTO exists because its item has the next symbol after the dot. □\square

Lemma 3 (keys). If [A→β1⋅β2,u]∈I[A \to \beta_1 \cdot \beta_2, u] \in I, then every v∈FIRSTk(β2)⊕k{u}v \in \mathrm{FIRST}_k(\beta_2) \oplus_k \{u\} is a key of ACTION[I]\mathrm{ACTION}[I].

Proof. We use induction on the least height hh of a forest of trees for β2\beta_2 whose yield zz has FIRSTk(zu)=v\mathrm{FIRST}_k(z u) = v. There are three cases.

  • β2=ε\beta_2 = \varepsilon. Then v=uv = u, and line L17 sets the reduction, or accept, at uu.
  • β2\beta_2 starts with a terminal. Line L16 sets shift at all of FIRSTk(β2)⊕k{u}\mathrm{FIRST}_k(\beta_2) \oplus_k \{u\}.
  • β2=Cβ2′\beta_2 = C \beta_2' with C∈VC \in V. Let the tree of CC use C→δC \to \delta with yield z1z_1, and let z=z1z2z = z_1 z_2. Closure puts [C→⋅δ,v′][C \to \cdot \delta, v'] into II with v′=FIRSTk(z2u)∈FIRSTk(β2′)⊕k{u}v' = \mathrm{FIRST}_k(z_2 u) \in \mathrm{FIRST}_k(\beta_2') \oplus_k \{u\}. Then v=FIRSTk(z1v′)v = \mathrm{FIRST}_k(z_1 v'), and the children of the tree of CC form a forest for δ\delta of smaller height. □\square

Step 1: acceptance gives a parse tree. Each reduction by A→βA \to \beta pops the trees of the symbols β\beta and pushes a node AA with these children. So every tree on the stack is a parse tree of its symbol, and the yields of the stack trees, from bottom to top, spell a1⋯ai−1a_1 \cdots a_{i-1}. The accept action comes only from [S′→S⋅,ε][S' \to S \cdot, \varepsilon]. A state with this item is GOTO(I,S)\mathrm{GOTO}(I, S) for a state II that contains [S′→⋅S,ε][S' \to \cdot S, \varepsilon], so I=I0I = I_0. The state I0I_0 is only at the bottom of the stack: every other state is a GOTO state, and its kernel items have the dot after a symbol. So at acceptance the stack holds exactly one tree, with root SS. Line L11 checks i=n+1i = n + 1, so the yield of that tree is ww. This proves part 1.

Step 2: sentences are accepted. Let w∈L(G)w \in L(G) and fix a parse tree tt of ww under the extra root S′S'. Claim: the parser processes the nodes of tt below S′S' in postorder. A leaf is shifted, and an inner node is reduced with its production. At each step the stack holds the roots of the maximal processed subtrees, from left to right. These are the left siblings of the ancestors of the next node in postorder, and the left siblings of that node itself.

Suppose the claim holds and the next node in postorder is xx, with i−1i - 1 tokens shifted. Let y=ai⋯any = a_i \cdots a_n.

  • xx is an inner node. Say xx uses A→βA \to \beta. All its children have been processed, so the stack symbols are αβ\alpha \beta in the notation of Lemma 2, and the part of the yield to the right of xx is yy. Lemma 2 gives [A→β⋅,FIRSTk(y)]∈st(αβ)[A \to \beta \cdot, \mathrm{FIRST}_k(y)] \in \mathrm{st}(\alpha \beta). Since there is no conflict, ACTION at the lookahead u=FIRSTk(y)u = \mathrm{FIRST}_k(y) is this reduction. The parser pops the ∣β∣|\beta| children and pushes xx.
  • xx is a leaf. Then x=aix = a_i, the child of a node x′x' with production A→β1aiβ2A \to \beta_1 a_i \beta_2, whose children before aia_i are processed. Lemma 2 gives [A→β1⋅aiβ2,FIRSTk(y′)][A \to \beta_1 \cdot a_i \beta_2, \mathrm{FIRST}_k(y')] in the top state, where y′y' is the yield to the right of x′x'. The input yy is aia_i, followed by a yield of β2\beta_2, followed by y′y'. So FIRSTk(y)∈FIRSTk(aiβ2)⊕k{FIRSTk(y′)}\mathrm{FIRST}_k(y) \in \mathrm{FIRST}_k(a_i \beta_2) \oplus_k \{\mathrm{FIRST}_k(y')\}, and the cell holds shift. GOTO on aia_i exists because of the same item.
  • All nodes below S′S' are processed. The stack is SS over I0I_0, and i=n+1i = n + 1. Lemma 2 for S′S' with β1=S\beta_1 = S gives [S′→S⋅,ε][S' \to S \cdot, \varepsilon], so the parser accepts.

The tree is finite, so the parser accepts after one step for each node of tt and one more. This proves part 2.

Step 3: every key is a real continuation. Let the stack symbols be γ\gamma, with i−1i - 1 tokens shifted, and let vv be a key of ACTION[st(γ)]\mathrm{ACTION}[\mathrm{st}(\gamma)]. Then a1⋯ai−1z∈L(G)a_1 \cdots a_{i-1} z \in L(G) for some zz with FIRSTk(z)=v\mathrm{FIRST}_k(z) = v.

If the key comes from a complete item, Lemma 1 gives S′⇒rm∗γyS' \Rightarrow_{rm}^* \gamma y with FIRSTk(y)=v\mathrm{FIRST}_k(y) = v. If it comes from line L16, the item [A→β1⋅aβ2,u][A \to \beta_1 \cdot a \beta_2, u] and Lemma 1 give S′⇒∗γaβ2y′S' \Rightarrow^* \gamma a \beta_2 y' with FIRSTk(y′)=u\mathrm{FIRST}_k(y') = u. Then v=FIRSTk(az2y′)v = \mathrm{FIRST}_k(a z_2 y') for some z2∈L(β2)z_2 \in L(\beta_2). In both cases γ\gamma derives a1⋯ai−1a_1 \cdots a_{i-1} through the stack trees.

Step 4: the inspected tokens stay consistent. Let hh be the largest position read by a lookahead so far, that is, the largest min⁡(i′+k−1,n)\min(i' + k - 1, n) over the steps done so far at positions i′i'. Claim: at each test of line L3, ai⋯aha_i \cdots a_h is a prefix of some key of the top state (the empty string when h<ih < i).

Let the last step be taken at position ii with the lookahead uu, a key of the state on top then. Then uu is ai⋯aha_i \cdots a_h, or longer when h<i+k−1h < i + k - 1.

  • A reduction by A→βA \to \beta. Its item [A→β⋅,u][A \to \beta \cdot, u] traces back through GOTO to [A→⋅β,u][A \to \cdot \beta, u] in the state s′s' below the popped entries. That item is added by closure from some [B→δ⋅Aη,u′]∈s′[B \to \delta \cdot A \eta, u'] \in s' with u∈FIRSTk(η)⊕k{u′}u \in \mathrm{FIRST}_k(\eta) \oplus_k \{u'\}. The new state GOTO(s′,A)\mathrm{GOTO}(s', A) contains [B→δA⋅η,u′][B \to \delta A \cdot \eta, u'], so uu is a key of it by Lemma 3. The position ii is unchanged.
  • A shift of aia_i. It comes from [A→β1⋅aiβ2,u0][A \to \beta_1 \cdot a_i \beta_2, u_0] with u=FIRSTk(aiz)u = \mathrm{FIRST}_k(a_i z) for a string zz that starts with a yield of β2\beta_2 and continues with u0u_0. The new state contains [A→β1ai⋅β2,u0][A \to \beta_1 a_i \cdot \beta_2, u_0]. Its key FIRSTk(z)\mathrm{FIRST}_k(z), which is a key by Lemma 3, has the rest of uu as a prefix.

Step 5: the valid prefix property. Suppose the parser reports an error at position pp, with stack symbols γ\gamma and i−1i - 1 tokens shifted. An error arises in one of three ways.

  • No action (line L4). Here p=i+dp = i + d, and uu shares dd tokens with a key. By Step 3, a1⋯ap−1a_1 \cdots a_{p-1} starts a sentence. By Step 4, d≥h−i+1d \ge h - i + 1, so p>hp > h.
  • Shift without GOTO (line L6), only for k=0k = 0. Here p=ip = i and h<ih < i. The top state has a shift item [A→β1⋅aβ2,u][A \to \beta_1 \cdot a \beta_2, u]. By Lemma 1 and Step 3, a1⋯ai−1aa_1 \cdots a_{i-1} a starts a sentence, so a1⋯ai−1a_1 \cdots a_{i-1} does too.
  • Accept with input left (line L11). Here p=ip = i and h<ih < i, and a1⋯ai−1∈L(G)a_1 \cdots a_{i-1} \in L(G) by Step 1.

Now let p≤np \le n, and suppose that a sentence ss starts with a1⋯apa_1 \cdots a_p. Every step so far read only positions up to h<ph < p and shifted tokens before i≤pi \le p. So the parser makes the same moves on ss and reaches the same stack. On ss it accepts by Step 2, following the tree of ss. So at this stack, ss has the next action that Step 2 describes.

  • No action. The lookahead on ss is a key that agrees with uu on d+1d + 1 tokens, against the choice of dd.
  • Shift without GOTO. The next node of the tree of ss is a leaf, and GOTO on si=ais_i = a_i exists, a contradiction.
  • Accept with input left. The parser on ss accepts here while ss has the token sis_i left, which Step 1 excludes.

This proves part 3.

Step 6: termination. Shifts happen at most nn times. Between two shifts, the moves depend only on the stack and the lookahead uu. By Step 3 there is a sentence s=a1⋯ai−1zs = a_1 \cdots a_{i-1} z with FIRSTk(z)=u\mathrm{FIRST}_k(z) = u. It agrees with ww on every position read so far, so the parser makes the same moves on ss, which stop by Step 2. Hence the parser stops on every input. Knuth (1965) shows moreover that for an LR(k) grammar the number of reductions is O(n+1)O(n + 1), which gives part 4. We cite that bound rather than reprove it. ■\blacksquare

Back to LR(k) parsing