Algorithm Search⌘K

Proofs: SLR(1) parsing

These are the human proofs of SLR(1) parsing, at full length.

An SLR(1) parser without conflicts parses exactly the sentences, detects errors at the first bad token, and stops in linear time full

This proof shows: correctness, termination.

We use the notation of the context-free grammar page and the pseudocode BUILD-SLR and SLR-PARSE of the page. Line B1 removes the useless productions; this changes neither L(G)L(G) nor the parse trees of sentences, since no parse tree of a sentence uses a useless production. So we assume that GG is reduced: every nonterminal is reachable from SS and derives a terminal string. GG is augmented with S′→SS' \to S, the end marker is $\$, and FOLLOW is computed for the augmented grammar. We assume that the table has no conflict. The input is w=a1⋯anw = a_1 \cdots a_n and an+1=$a_{n+1} = \$.

An item [A→α⋅β][A \to \alpha \cdot \beta] is valid for a string γ\gamma of grammar symbols if there is a rightmost derivation S′⇒rm∗φAz⇒rmφαβzS' \Rightarrow^*_{rm} \varphi A z \Rightarrow_{rm} \varphi \alpha \beta z with γ=φα\gamma = \varphi \alpha and zz a terminal string. γ\gamma is a viable prefix if some item is valid for it. Write δ(γ)\delta(\gamma) for the state reached from state 0 by the GOTO transitions over the symbols of γ\gamma, if it exists.

Lemma 1: the states are the sets of valid items

Claim. For every γ\gamma, δ(γ)\delta(\gamma) exists if and only if γ\gamma is viable, and then δ(γ)\delta(\gamma) is the set of items valid for γ\gamma.

Items in the state are valid. By induction on the construction. [S′→⋅S][S' \to \cdot S] is valid for ε\varepsilon (the derivation with no step, φ=z=ε\varphi = z = \varepsilon). GOTO keeps validity: if [A→α⋅Xβ][A \to \alpha \cdot X \beta] is valid for γ\gamma, the same derivation shows that [A→αX⋅β][A \to \alpha X \cdot \beta] is valid for γX\gamma X. CLOSURE keeps validity: if [A→α⋅Bβ][A \to \alpha \cdot B \beta] is valid for γ\gamma, by S′⇒rm∗φAz⇒φαBβzS' \Rightarrow^*_{rm} \varphi A z \Rightarrow \varphi \alpha B \beta z, then β\beta derives a terminal string yy because GG is reduced, and φαBβz⇒rm∗φαByz⇒φαη yz\varphi \alpha B \beta z \Rightarrow^*_{rm} \varphi \alpha B y z \Rightarrow \varphi \alpha \eta\, y z is a rightmost derivation for every production B→ηB \to \eta. So [B→⋅η][B \to \cdot \eta] is valid for γ=φα\gamma = \varphi \alpha.

Valid items are in the state. Let [A→α⋅β][A \to \alpha \cdot \beta] be valid for γ\gamma, by a derivation of mm steps. We show by induction on mm that [A→⋅αβ]∈δ(φ)[A \to \cdot \alpha \beta] \in \delta(\varphi), where γ=φα\gamma = \varphi \alpha; then GOTO over the symbols of α\alpha gives [A→α⋅β]∈δ(γ)[A \to \alpha \cdot \beta] \in \delta(\gamma). If m=0m = 0, then A=S′A = S', φ=ε\varphi = \varepsilon, and [S′→⋅S][S' \to \cdot S] is in state 0. Otherwise, look at the step of the derivation that created this occurrence of AA, by a production B→α′Aβ′B \to \alpha' A \beta': S′⇒rm∗φ′Bz′⇒φ′α′Aβ′z′S' \Rightarrow^*_{rm} \varphi' B z' \Rightarrow \varphi' \alpha' A \beta' z'. After this step the derivation rewrites only symbols to the right of AA, until AA itself is rewritten, because it is rightmost. So φ=φ′α′\varphi = \varphi' \alpha' and β′\beta' derives a terminal prefix of zz. Then [B→α′⋅Aβ′][B \to \alpha' \cdot A \beta'] is valid for φ\varphi by a shorter derivation, so by induction it is in δ(φ)\delta(\varphi), and CLOSURE adds [A→⋅αβ][A \to \cdot \alpha \beta].

Finally, a state built by GOTO from a nonempty kernel is nonempty, and every item in it is valid, so γ\gamma is viable when δ(γ)\delta(\gamma) exists; conversely, if some item is valid for γ\gamma, it lies in δ(γ)\delta(\gamma), which therefore exists. □\square

Lemma 2: the stack invariant, and soundness

A configuration is a stack of trees with roots γ=X1⋯Xm\gamma = X_1 \cdots X_m, a stack of states, and the position ii of the next token. Invariant: the states are δ(ε),δ(X1),…,δ(X1⋯Xm)\delta(\varepsilon), \delta(X_1), \ldots, \delta(X_1 \cdots X_m); the leaves of the trees, left to right, are a1⋯ai−1a_1 \cdots a_{i-1}; and each tree is a parse tree with its root.

It holds after line L1. A shift of aa pushes GOTO[δ(γ),a]=δ(γa)\text{GOTO}[\delta(\gamma), a] = \delta(\gamma a) and the leaf aa. A reduction by A→βA \to \beta is made in a state that contains [A→β⋅][A \to \beta \cdot], so by Lemma 1 the item is valid for γ\gamma, which therefore ends with β\beta, say γ=αβ\gamma = \alpha \beta. The same derivation shows that [A→⋅β][A \to \cdot \beta] is valid for α\alpha, so δ(α)\delta(\alpha), the state uncovered by line L8, has a GOTO on AA, and line L9 pushes δ(αA)\delta(\alpha A) and a node AA over the trees of β\beta. So the invariant holds, and line L9 never finds GOTO undefined.

Soundness. The accept action is only in a state containing [S′→S⋅][S' \to S \cdot], which by Lemma 1 is valid only for γ=S\gamma = S, and only on $\$, that is, at i=n+1i = n + 1. So an accepted result is a single parse tree with root SS and leaves ww. Reading the reductions backwards gives a rightmost derivation of ww, by Claim 1 of the shift-reduce parsing proof, which holds for every sequence of legal moves.

Lemma 3: every move toward acceptance is in the table

A configuration is good if some sequence of legal shift-reduce moves (shift the next token, or reduce a right side that forms the top of the stack) leads from it to the stack SS at position n+1n + 1. By Claim 1 of the shift-reduce proof applied to such a continuation, its reductions read backwards give a rightmost derivation S⇒rm∗γ ai⋯anS \Rightarrow^*_{rm} \gamma\, a_i \cdots a_n.

Claim. Let a configuration with the invariant of Lemma 2 be good, and fix an accepting continuation. Its next move is an action in ACTION[δ(γ),ai]\text{ACTION}[\delta(\gamma), a_i].

Proof. Reduce by A→βA \to \beta. Then γ=αβ\gamma = \alpha \beta, and the continuation after the move gives S⇒rm∗αA ai⋯anS \Rightarrow^*_{rm} \alpha A\, a_i \cdots a_n. With S′⇒SS' \Rightarrow S in front and the step αA ai⋯an⇒αβ ai⋯an\alpha A\, a_i \cdots a_n \Rightarrow \alpha \beta\, a_i \cdots a_n, the item [A→β⋅][A \to \beta \cdot] is valid for γ\gamma, so it is in δ(γ)\delta(\gamma) by Lemma 1. The same derivation shows ai∈FOLLOW(A)a_i \in \text{FOLLOW}(A) (or $∈FOLLOW(A)\$ \in \text{FOLLOW}(A) when i=n+1i = n + 1). So line B5 put "reduce A→βA \to \beta" into the entry.

Shift aia_i. The leaf aia_i ends inside the final tree, so some later reduction of the continuation pops it; take the first one, by A′→β1aiβ2A' \to \beta_1 a_i \beta_2. Until then nothing below aia_i is popped, so at that moment the stack is γ ai β2\gamma\, a_i\, \beta_2 with γ=ρβ1\gamma = \rho \beta_1, and as in the first case the continuation gives S′⇒rm∗ρA′z⇒ρβ1aiβ2zS' \Rightarrow^*_{rm} \rho A' z \Rightarrow \rho \beta_1 a_i \beta_2 z with zz terminal. So [A′→β1⋅aiβ2][A' \to \beta_1 \cdot a_i \beta_2] is valid for γ\gamma, it is in δ(γ)\delta(\gamma), and line B4 put the shift into the entry.

Accept. Then γ=S\gamma = S and i=n+1i = n + 1; [S′→S⋅][S' \to S \cdot] is in δ(S)\delta(S) and line B6 put the accept action on $\$. □\square

Corollary. Since the table has no conflict, from a good configuration the parser makes the next move of every accepting continuation, and the new configuration is good again. So all accepting continuations from a good configuration are the same sequence, and the parser follows it to acceptance in finitely many moves. In particular the grammar is unambiguous: two parse trees of ww would give two different reverse rightmost derivations, that is, two different accepting continuations from the start.

Theorem 4: the parser accepts exactly L(G)L(G)

If w∈L(G)w \in L(G), the start configuration is good (any rightmost derivation of ww, read backwards, is an accepting continuation), so by the corollary the parser accepts, with the parse tree of ww. If w∉L(G)w \notin L(G), it never accepts, by soundness. □\square

Lemma 5: errors are found at the first bad token

Claim. The parser shifts aia_i (for i≤ni \le n) only if a1⋯aia_1 \cdots a_i is a prefix of a sentence, and it accepts only if a1⋯ana_1 \cdots a_n is a sentence. Conversely, if a1⋯aia_1 \cdots a_i is a prefix of a sentence, the parser shifts aia_i, or accepts when i=n+1i = n + 1 and w∈L(G)w \in L(G).

Proof. A shift of aia_i happens in a state δ(γ)\delta(\gamma) with an item [B→μ⋅aiν][B \to \mu \cdot a_i \nu], which by Lemma 1 is valid for γ\gamma: S′⇒rm∗ρBz⇒ρμaiνzS' \Rightarrow^*_{rm} \rho B z \Rightarrow \rho \mu a_i \nu z with ρμ=γ\rho \mu = \gamma. The trees on the stack show γ⇒∗a1⋯ai−1\gamma \Rightarrow^* a_1 \cdots a_{i-1}, and ν\nu derives a terminal string because GG is reduced, so a1⋯aia_1 \cdots a_i followed by that string and zz is a sentence. For the converse, let w′∈L(G)w' \in L(G) start with a1⋯aia_1 \cdots a_i. Each move depends only on the stack and the token being examined, and until aia_i is shifted the parser examines only a1,…,aia_1, \ldots, a_i. So the runs on ww and w′w' agree until aia_i is shifted, and on w′w' that happens, by Theorem 4. □\square

So if w∉L(G)w \notin L(G) and the parser stops, it reports the error at the least ii such that a1⋯aia_1 \cdots a_i is not a prefix of a sentence, where i=n+1i = n + 1 means that ww itself is a proper prefix of a sentence. It remains to show that it stops.

Lemma 6: no cycle of empty symbols in the automaton

Claim. There are no states p0,p1,…,pk=p0p_0, p_1, \ldots, p_k = p_0, k≥1k \ge 1, and nullable symbols Y1,…,YkY_1, \ldots, Y_k with GOTO[pj−1,Yj]=pj\text{GOTO}[p_{j-1}, Y_j] = p_j.

Proof. Suppose there are. Every state is reached by some string, so p0=δ(γ)p_0 = \delta(\gamma) for a viable γ\gamma, and δ(γ(Y1⋯Yk)m)=p0\delta(\gamma (Y_1 \cdots Y_k)^m) = p_0 for every m≥0m \ge 0. By Lemma 1 these strings are viable, so for each mm there is a valid item [B→μ⋅ν][B \to \mu \cdot \nu] with S′⇒rm∗ρBz⇒ρμνzS' \Rightarrow^*_{rm} \rho B z \Rightarrow \rho \mu \nu z, ρμ=γ(Y1⋯Yk)m\rho \mu = \gamma (Y_1 \cdots Y_k)^m; since GG is reduced, νz\nu z derives a terminal string xmx_m, and the YY's derive ε\varepsilon, so

S′⇒rm∗γ (Y1⋯Yk)m xm⇒rm∗γ xm.S' \Rightarrow^*_{rm} \gamma\, (Y_1 \cdots Y_k)^m\, x_m \Rightarrow^*_{rm} \gamma\, x_m .

Put trees for the symbols of γ\gamma, with some terminal yield uu, on the stack with the states δ\delta of its prefixes, and the input xmx_m. Read backwards, the derivation above is an accepting continuation from this configuration, which first builds the mkmk empty trees Y1,…,Yk,Y1,…Y_1, \ldots, Y_k, Y_1, \ldots one after the other, without shifting. By the corollary of Lemma 3, the parser follows it. But before its first shift, the parser's moves from stack γ\gamma depend only on the first token bb of xm$x_m \$. Some bb is the first token for infinitely many mm, and for all of them the parser makes the same sequence of moves before its first shift. That sequence is finite (it is part of an accepting run for one of them) and yet contains a stack of height ∣γ∣+mk|\gamma| + mk for infinitely many mm. This is impossible. □\square

Theorem 7: the parser stops after O(n)O(n) moves

Between two shifts there are finitely many reductions. Suppose that from some configuration the parser reduces forever. No new leaf is shifted, so every tree created from then on, on top of the stack, has the empty yield, and every stack is viable by Lemma 2 and Lemma 1.

Case 1: some stack of states occurs twice. The states determine the symbols (each state other than 0 is entered by one symbol), so the two configurations have the same roots X1⋯XmX_1 \cdots X_m, and the second forest is obtained from the first by at least one reduction, so it has more nodes and the same leaves. Since X1⋯XmX_1 \cdots X_m is viable and GG is reduced, there is a rightmost derivation S′⇒∗X1⋯Xm xS' \Rightarrow^* X_1 \cdots X_m\, x with xx terminal; hanging the first forest or the second forest under its tree gives two different parse trees of the same sentence. This contradicts the unambiguity in the corollary of Lemma 3.

Case 2: no stack of states repeats. Let LL be the lowest stack level that is popped infinitely often, if there is one. Then after some time the levels below LL never change, and each time level LL is popped, the next push gives a stack of states of height LL that consists of the fixed lower part and one state: finitely many stacks, occurring infinitely often, which is Case 1. So every level is eventually never popped. The heights are then unbounded (otherwise some stack would repeat), so there are infinitely many entries that are never popped, above the height h0h_0 at the start; their trees have empty yields. Two of them, at levels h0<j1<j2h_0 < j_1 < j_2, carry the same state, and the entries between them are consecutive, with states linked by GOTO over their nullable root symbols. This is a cycle as in Lemma 6, a contradiction.

So between two shifts the parser makes finitely many reductions, there are at most nn shifts, and the parser stops. By Theorem 4 and Lemma 5 it then accepts exactly the sentences, with their parse tree, and reports any other input at the first token that no sentence allows there.

The number of moves is linear. Every move creates a node, a leaf for a shift and an inner node for a reduction, and no node is ever destroyed, so the number of moves is at most the number of nodes in the forest on the stack when the parser stops, plus one. Let that forest have the roots γ\gamma and the leaves a1⋯ai−1a_1 \cdots a_{i-1}, with i≤n+1i \le n + 1. Since γ\gamma is viable, as in Case 1 the forest is part of a parse tree TT of a sentence, and GG is unambiguous. Then in TT no node has a proper descendant with the same label and the same span of leaves, since replacing the upper node's subtree by the lower one gives another parse tree of the same sentence. Let rr be the longest right side and NN the number of states. In the forest:

  • the nodes with a nonempty span have at most 2(i−1)2(i - 1) different spans, since the spans of a tree are nested or disjoint, and at most ∣V∣+1|V| + 1 nodes have each span, because nodes with the same nonempty span lie on one path and have different labels;
  • each maximal subtree with an empty yield has no repeated label on a path, so it has at most c=1+r+⋯+r∣V∣c = 1 + r + \cdots + r^{|V|} nodes;
  • such a subtree is either a child of a node with a nonempty span, at most rr per node, or a root of the forest. The roots with an empty yield come in runs of consecutive stack entries, one run after each root with a nonempty yield and one at the bottom; a run has at most NN entries, since two entries with the same state in a run would give a cycle as in Lemma 6.

So the forest has at most 2(i−1)(∣V∣+1)(1+rc)+iNc2(i - 1)(|V| + 1)(1 + r c) + i N c nodes, which is O(i)O(i) for a fixed grammar, and the parser makes O(n)O(n) moves. □\square

Back to SLR(1) parsing