Algorithm Search⌘K

Proofs: LR parse table

These are the human proofs of LR parse table, at full length.

A conflict-free LR(0), SLR or LR(1) table makes LR-DRIVE a correct parser with the valid prefix property full

This proof shows: correctness.

Setting. Let GG be a grammar in which every nonterminal derives some terminal string (the implementation first drops the productions that use a nonterminal deriving none), augmented with S′→SS' \to S, where S′S' is new. For a string γ∈(V∪Σ)∗\gamma \in (V \cup \Sigma)^*, write δ(γ)\delta(\gamma) for the state reached from the start state q0q_0 by the automaton's transitions on the symbols of γ\gamma, if all these transitions exist. The automaton is the LR(0) automaton for the kinds LR(0) and SLR, and the canonical LR(1) automaton for LR(1). A viable prefix is a prefix γ\gamma of a right-sentential form δβy\delta \beta y with γ\gamma no longer than δβ\delta \beta, where S′⇒rm∗δAy⇒rmδβyS' \Rightarrow^*_{rm} \delta A y \Rightarrow_{rm} \delta \beta y. An LR(0) item A→μ⋅νA \to \mu \cdot \nu is valid for γ\gamma if S′⇒rm∗δAz⇒rmδμνzS' \Rightarrow^*_{rm} \delta A z \Rightarrow_{rm} \delta \mu \nu z with γ=δμ\gamma = \delta \mu and z∈Σ∗z \in \Sigma^*, and the LR(1) item [A→μ⋅ν,b][A \to \mu \cdot \nu, b] is valid if moreover bb is the first symbol of z$z \$.

We use Knuth's theorem on the LR item page: δ(γ)\delta(\gamma) is defined if and only if γ\gamma is a viable prefix, and then it is the set of items valid for γ\gamma (LR(0) items for the LR(0) automaton, LR(1) items for the LR(1) automaton).

Statement. Suppose FILL, run on the automaton with the lookahead sets of the chosen kind, records no conflict. Let w=a1⋯anw = a_1 \cdots a_n and an+1=$a_{n+1} = \$. Then:

  1. (Soundness.) If LR-DRIVE accepts ww, then the tree it returns is a parse tree of ww, so w∈L(G)w \in L(G).
  2. (Completeness.) If w∈L(G)w \in L(G), LR-DRIVE accepts ww and reports no error.
  3. (Valid prefix.) LR-DRIVE shifts aia_i only if a1⋯aia_1 \cdots a_i is a prefix of a sentence, and when it reports an error at aia_i, the string a1⋯aia_1 \cdots a_i (for i=n+1i = n + 1, the string ww itself) is not a prefix of any sentence.

Termination on inputs that are not sentences is not part of this statement; it is proved for LR(0) tables on the LR(0) parsing page and by Knuth (1965) for LR(k) in general.

Proof.

Step 1 (cells). Since there is no conflict, L7 assigns each cell at most one action, and by L1 to L5 the action xx is in cell (q,a)(q, a) exactly when some item of qq calls for it: shift to the successor of qq on aa when qq has an item with the dot before aa (then this transition exists), accept when a=$a = \$ and S′→S⋅∈qS' \to S \cdot \in q, and reduce A→βA \to \beta when qq has a complete item A→β⋅A \to \beta \cdot with aa in its lookahead set. The lookahead set is Σ∪{$}\Sigma \cup \{\$\} for LR(0), FOLLOW(A)\mathrm{FOLLOW}(A) for SLR, and {b}\{b\} for the LR(1) item [A→β⋅,b][A \to \beta \cdot, b].

Step 2 (dots and stack). For every item A→μ⋅νA \to \mu \cdot \nu of δ(γ)\delta(\gamma), μ\mu is a suffix of γ\gamma, say γ=κμ\gamma = \kappa \mu, and A→⋅μνA \to \cdot \mu \nu is in δ(κ)\delta(\kappa). By induction on ∣γ∣|\gamma|: the items of q0q_0 have the dot at the start; an item of δ(γX)\delta(\gamma X) either comes from closure, with the dot at the start, or is A→μ′X⋅νA \to \mu' X \cdot \nu from A→μ′⋅Xν∈δ(γ)A \to \mu' \cdot X \nu \in \delta(\gamma). Moreover, an item A→⋅βA \to \cdot \beta with A≠S′A \neq S' is in a state only through closure, so that state also has an item with the dot before AA and the transition on AA exists. The item S′→S⋅S' \to S \cdot is in δ(γ)\delta(\gamma) only for γ=S\gamma = S, since S′S' is on no right side and S′→⋅SS' \to \cdot S is only in q0q_0.

Let ψ\psi be the string of grammar symbols on the stack. We claim that LR-DRIVE keeps the invariant: the states on the stack are δ\delta of the prefixes of ψ\psi, from q0=δ(ε)q_0 = \delta(\varepsilon) to δ(ψ)\delta(\psi) on top; the trees on the stack have the roots ψ\psi in order; and the yields of the trees, concatenated, are the tokens shifted so far. A shift of aa (L12) pushes δ(ψa)\delta(\psi a) and the leaf aa. A reduction by A→βA \to \beta (L13) happens only when A→β⋅∈δ(ψ)A \to \beta \cdot \in \delta(\psi) (Step 1), so ψ=κβ\psi = \kappa \beta by Step 2; it pops ∣β∣|\beta| states and trees, exposes δ(κ)\delta(\kappa), which contains A→⋅βA \to \cdot \beta, so the GOTO entry for AA exists, and pushes δ(κA)\delta(\kappa A) and the node AA whose children are the popped trees, a correct node of a parse tree since A→β∈RA \to \beta \in R.

Step 3 (soundness). Accept (L14) happens only on $\$, which comes only after all of ww has been shifted (L11 rejects a $\$ token inside the input), and only when S′→S⋅∈δ(ψ)S' \to S \cdot \in \delta(\psi), that is, ψ=S\psi = S by Step 2. By the invariant, the stack then holds one tree with root SS and yield ww. This proves part 1.

Step 4 (completeness). Let w∈L(G)w \in L(G) and fix a rightmost derivation S′⇒rmS=ζm⇒rm⋯⇒rmζ0=wS' \Rightarrow_{rm} S = \zeta_m \Rightarrow_{rm} \cdots \Rightarrow_{rm} \zeta_0 = w. Read backwards, it defines the canonical run of a shift-reduce parser: in configuration (stack ψ\psi, unread input xx) with ψx=ζj\psi x = \zeta_j, let ζj=δβy\zeta_j = \delta \beta y where ζj+1=δAy⇒rmδβy\zeta_{j+1} = \delta A y \Rightarrow_{rm} \delta \beta y; if ψ=δβ\psi = \delta \beta, reduce by A→βA \to \beta, reaching the configuration (δA,y)(\delta A, y) with δAy=ζj+1\delta A y = \zeta_{j+1}; otherwise shift. The canonical run ends with stack SS and empty input, and then accepts.

We show that in every configuration of the canonical run, ψ\psi is a prefix of δβ\delta \beta and δβ=ψτ\delta \beta = \psi \tau with τ∈Σ∗\tau \in \Sigma^*. At the start ψ=ε\psi = \varepsilon, and the handle δβ\delta \beta of ζ0=w\zeta_0 = w is a terminal string. Shifts keep the property as long as τ≠ε\tau \neq \varepsilon. After a reduction, the stack is δA\delta A and AA is the rightmost nonterminal of ζj+1=δAy\zeta_{j+1} = \delta A y. The next handle comes from the step ζj+2=δ′By′⇒rmδ′θy′=ζj+1\zeta_{j+2} = \delta' B y' \Rightarrow_{rm} \delta' \theta y' = \zeta_{j+1}. If θ\theta contains a nonterminal, it contains the rightmost one, AA, so θ=θ′Aθ′′\theta = \theta' A \theta'' with θ′′∈Σ∗\theta'' \in \Sigma^* and δ′θ=δAθ′′\delta' \theta = \delta A \theta''. Otherwise θ\theta is terminal and lies to the right of AA, inside yy, so δ′θ=δAτ\delta' \theta = \delta A \tau with τ∈Σ∗\tau \in \Sigma^*. Both cases give the claim. So every stack ψ\psi of the canonical run is a viable prefix, and so is ψa\psi a whenever the canonical move is to shift aa.

Now we show by induction on the steps that LR-DRIVE makes the same moves as the canonical run. Both start in the same configuration, and by Step 2 the states of LR-DRIVE are determined by ψ\psi, so it is enough to show that the cell (δ(ψ),a)(\delta(\psi), a), with aa the next token, contains the canonical move: since the cell holds at most one action, it then holds exactly that move.

  • Shift aa. ψa\psi a is a viable prefix, so by Knuth's theorem δ(ψa)\delta(\psi a) is defined, so δ(ψ)\delta(\psi) has an item with the dot before aa and the cell holds a shift.
  • Reduce A→βA \to \beta, with ψ=δβ\psi = \delta \beta, S′⇒rm∗δAy⇒rmδβyS' \Rightarrow^*_{rm} \delta A y \Rightarrow_{rm} \delta \beta y and aa the first symbol of y$y \$. The LR(0) item A→β⋅A \to \beta \cdot and the LR(1) item [A→β⋅,a][A \to \beta \cdot, a] are valid for ψ\psi, so by Knuth's theorem they are in δ(ψ)\delta(\psi). For LR(0), every column gets the reduction. For SLR, S′$⇒∗δAy$S' \$ \Rightarrow^* \delta A y \$ shows a∈FOLLOW(A)a \in \mathrm{FOLLOW}(A). For LR(1), aa is the lookahead of the item. In all three cases the cell holds the reduction.
  • Accept. The stack is ψ=S\psi = S, the state δ(S)\delta(S) contains S′→S⋅S' \to S \cdot, and the next token is $\$, so the cell holds accept.

So LR-DRIVE follows the canonical run, never reports an error, and accepts. This proves part 2.

Step 5 (valid prefix). If LR-DRIVE shifts aia_i from stack ψ\psi, the state δ(ψai)\delta(\psi a_i) is defined, so ψai\psi a_i is a viable prefix by Knuth's theorem, a prefix of a right-sentential form ψaiη\psi a_i \eta. Every symbol of η\eta derives some terminal string vv, and by the invariant ψ⇒∗a1⋯ai−1\psi \Rightarrow^* a_1 \cdots a_{i-1}, so a1⋯aiv∈L(G)a_1 \cdots a_i v \in L(G).

Suppose LR-DRIVE reports an error at aia_i but a1⋯aia_1 \cdots a_i is a prefix of a sentence w′w' (for i=n+1i = n + 1, suppose w∈L(G)w \in L(G), which part 2 excludes). Each move of LR-DRIVE depends only on its stack and the next token, so its runs on ww and on w′w' coincide up to the first time it looks at token ii and moves on. By part 2 the run on w′w' never reports an error and shifts its ii-th token aia_i after finitely many moves, so the run on ww also shifts aia_i and does not report an error at it, a contradiction. This proves part 3. ■\blacksquare

Back to LR parse table