Correctness of the DeRemer and Pennello lookahead computation full
This proof shows: correctness.
We prove that the algorithm on the LALR lookahead computation page returns, for every completed item A→ω⋅ of every LR(0) state q with A=S′, exactly the set of lookaheads that the item has in the canonical LR(1) states whose core is q.
Notation and assumptions. G=(V,Σ,P,S) is augmented with S′→S as production 0, and S′ occurs on no right side. G is reduced: every nonterminal is reachable from S and derives some terminal string. LR(0) states are identified with their kernels; p is the closure of p, and GOTO(p,β) is defined symbol by symbol. For a string γ and a set M of terminals, FIRST(γM) is FIRST(γ), together with M when γ⇒∗ε. T(q) is the set of terminals t with GOTO(q,t) defined. Items A→⋅ω with A=S′ are never kernel items, and GOTO never leads to state 0, whose only kernel item has the dot at position 0.
Part 1: merged lookaheads as a least solution
For a state p and an item i∈p, let M(p,i) be the set of b such that [i,b] belongs to some canonical LR(1) state whose core is p.
Lemma 1. M is the least family of sets, indexed by pairs (p,i) with i∈p, that satisfies
- (a) $∈M(0,S′→⋅S);
- (b) M(GOTO(p,Y),B→βY⋅γ)⊇M(p,B→β⋅Yγ);
- (c) M(p,C→⋅η)⊇FIRST(γM(p,B→β⋅Cγ)) for every item B→β⋅Cγ∈p and every production C→η.
Proof. Because G is reduced, every FIRST(γb) is nonempty, so the LR(1) closure adds a dotted production exactly when the LR(0) closure does, and the core of GOTO1(J,Y) is GOTO(core(J),Y). Hence M satisfies (a), since the start state contains [S′→⋅S, $]; (b), since GOTO1(J,Y) contains [B→βY⋅γ, b] whenever J contains [B→β⋅Yγ, b]; and (c), since every LR(1) state is closed. Conversely let M0 be the least solution. Every LR(1) state is built from the start item by GOTO and closure steps, and by induction on the number of steps each of its items [i,b], in a state with core p, has b∈M0(p,i): the start item by (a), a kernel item made by GOTO by (b), and an item added by closure by (c). So M⊆M0, and M0⊆M because M is a solution. □
In the least solution each set is exactly the union of what the rules put into it. Items with the dot at position 0 and A=S′ get lookaheads only from (c), and items with the dot later only from (b). Unrolling (b) along the symbols before the dot gives, for B=S′,
M(q,B→β⋅γ)=⋃{M(p,B→⋅βγ):GOTO(p,β)=q, B→⋅βγ∈p},(1) while M(0,S′→⋅S)=M(GOTO(0,S),S′→S⋅)={$}. For a nonterminal transition (p,A) define
Fol(p,A)=⋃{FIRST(γM(p,B→β⋅Aγ)):B→β⋅Aγ∈p}. By (c), M(p,A→⋅ω)=Fol(p,A) for every production A→ω with A=S′. An item A→⋅ω lies in p exactly when (p,A) is a nonterminal transition: it is added by closure from an item with the dot before A, and such an item makes GOTO(p,A) defined. So (1) gives
M(q,A→ω⋅)=⋃{Fol(p,A):(q,A→ω) lookback (p,A)}.(2) Part 2: the first terminals of a state
For a state q, let R(q) be the union of T(q′) over all states q′ reachable from q by moves on nullable nonterminals, q itself included.
Lemma 2. R(q)=⋃{FIRST(λ):K→κ⋅λ is a kernel item of q}.
Proof of ⊇. We show the stronger claim: for every state q′ and every item E→ζ⋅η∈q′, FIRST(η)⊆R(q′). Take t∈FIRST(η) and a derivation η⇒∗tz with the fewest steps; induct on that number. Let η=Y1η′. If Y1=t, then t∈T(q′)⊆R(q′). Otherwise Y1 is a nonterminal, and either t comes from Y1, so that Y1→η1 with η1⇒∗tz1 in fewer steps, and Y1→⋅η1∈q′ gives t∈R(q′) by induction; or Y1⇒+ε and η′⇒∗tz in fewer steps, and then the item E→ζY1⋅η′ lies in q′′ for q′′=GOTO(q′,Y1), a move on a nullable nonterminal, so t∈R(q′′)⊆R(q′) by induction.
Proof of ⊆. Let U(q) be the right side of the lemma. First, T(q)⊆U(q): an item E→ζ⋅tη∈q is a kernel item, so t∈U(q), or it was added by closure from a kernel item K→κ⋅Dλ through productions that each begin with the next nonterminal of the chain, so Dλ⇒∗tημλ and t∈FIRST(Dλ)⊆U(q). Second, if C is nullable and q1=GOTO(q,C), then U(q1)⊆U(q): a kernel item of q1 is B→βC⋅γ for some B→β⋅Cγ∈q. If that item is a kernel item of q, then FIRST(γ)⊆FIRST(Cγ) because C is nullable. If it was added by closure from a kernel item K→κ⋅Dλ, then Dλ⇒∗Bμλ⇒Cγμλ⇒∗γμλ, so FIRST(γ)⊆FIRST(γμλ)⊆FIRST(Dλ). By induction along the path, T(q′)⊆U(q′)⊆U(q) for every q′ reachable by nullable moves. □
Part 3: Read and Follow
For a relation R on X and sets F′(x), a family F solves (R,F′) if F(x)=F′(x)∪⋃xRyF(y) for all x. The family Reach(x)=⋃{F′(y):y reachable from x along R} solves it, and every solution contains it, by induction on the length of a path from x to y. So Reach is the least solution; Part 4 shows that DIGRAPH returns it. Thus line L4 returns the least solution Read of (reads,DR) and line L6 the least solution Follow of (includes,Read).
Lemma 3. Read(p,A)=R(GOTO(p,A)), together with $ when (p,A)=(0,S).
Proof. A reads path from (p,A) is (p,A),(r0,C1),(r1,C2),…,(rk−1,Ck) with r0=GOTO(p,A), rj=GOTO(rj−1,Cj) and every Cj nullable, and the terminals in DR along it are T(r0),T(r1),…,T(rk). Their union over all such paths is R(r0). The marker $ is in DR(x) only for x=(0,S), the only transition whose target contains S′→S⋅, and no reads path enters (0,S) from another node, since that would need a move into state 0. □
Lemma 4. Fol solves (includes,Read), and Fol=Follow.
Proof. Split the union defining Fol(p,A) into the parts FIRST(γ) and the parts M(p,B→β⋅Aγ) with γ nullable. The kernel items of GOTO(p,A) are the items B→βA⋅γ for B→β⋅Aγ∈p, so by Lemmas 2 and 3 the first parts give Read(p,A) without $. For B=S′ the item is S′→⋅S in state 0 and contributes $, which Read contains for (0,S). For B=S′ with γ nullable, (1) writes M(p,B→β⋅Aγ) as the union of Fol(p′,B) over the states p′ with GOTO(p′,β)=p and B→⋅βAγ∈p′, that is over the (p′,B) that (p,A) includes. Hence Fol(p,A)=Read(p,A)∪⋃(p,A) includes (p′,B)Fol(p′,B), and since Follow is the least solution, Follow⊆Fol.
For the other inclusion define M′ from Follow: M′(0,S′→⋅S)=M′(GOTO(0,S),S′→S⋅)={$}, and for B=S′ let M′(q,B→β⋅γ) be the union of Follow(p,B) over the states p with GOTO(p,β)=q and B→⋅βγ∈p. Then M′ satisfies (a) and (b) by its definition. For (c), let B→β⋅Cγ∈p and C→η; then M′(p,C→⋅η)=Follow(p,C). By Lemmas 2 and 3, FIRST(γ)⊆R(GOTO(p,C))⊆Read(p,C)⊆Follow(p,C). If γ is nullable and B=S′, then (p,C)=(0,S) and $∈Read(0,S); if B=S′, each Follow(p′,B) in M′(p,B→β⋅Cγ) comes from a pair that (p,C) includes, so it is contained in Follow(p,C). By Lemma 1, M⊆M′, and therefore
Fol(p,A)=⋃FIRST(γM(p,B→β⋅Aγ))⊆⋃FIRST(γM′(p,B→β⋅Aγ))⊆Follow(p,A), the last step by the same computation as in the first paragraph with M′ and Follow in place of M and Fol. □
Theorem 5. Line L7 sets LA(q,A→ω)=M(q,A→ω⋅) for every completed item with A=S′.
Proof. Line L7 takes, for each transition (p,A) and production A→ω, the state q=GOTO(p,ω), which is defined because A→⋅ω∈p, and adds Follow(p,A). So it computes the union of Follow over the lookback pairs, which by Lemma 4 and (2) is M(q,A→ω⋅). Every completed item gets a set, because by (1) it has at least one lookback pair. □
Part 4: DIGRAPH
Lemma 6. DIGRAPH(X,R,F′) returns F(x)=Reach(x) for every x.
Proof. The search is Tarjan's strongly connected components algorithm, with N(x) in the role of the low link and N=∞ marking finished nodes, so that line L11 does not lower N(x) through them. Tarjan's analysis gives three facts for it: when line L12 finds N(x)=d, the nodes popped are exactly the strongly connected component of x; every node of that component was first visited inside the call on x; and every component reachable from it by an edge leaving it was finished earlier.
Every set ever stored in F(u) is contained in Reach(u): it starts as F′(u) and grows only by F(v) for an edge uRv, and Reach(v)⊆Reach(u); the sets copied at line L12 go to nodes of one component, which all have the same Reach.
We show by induction on the order in which components finish that, when the component Q with root x finishes, F(x)⊇Reach(x). Each u∈Q is visited inside the call on x, and when the call on a node returns, line L11 adds its set to its caller's set, so F(x)⊇F(u)⊇F′(u) for the value of F(u) when its call returned. During that call, line L11 was run for every edge uRv, after the call on v if v was new; if v lies in a component other than Q, that component finished earlier and F(v)=Reach(v) by induction. So F(x) contains F′(u) for every u∈Q and Reach(v) for every edge from Q to another component, and these together make up Reach(x). With the previous paragraph, F(x)=Reach(x), and line L12 gives every member of Q this set, which is its own Reach. Later steps never change the set of a finished node. □
The implementation replaces the recursion by an explicit stack of frames (x,d,i), where i is the position of the next successor of x to look at. When a frame is removed, the update of line L11 for the edge from its caller is done at once, so the order of operations is the same as in the recursive version.
Conclusion. By Lemma 6, lines L4 and L6 compute the least solutions Read and Follow; by Theorem 5, line L7 gives each completed item exactly its lookaheads in the canonical LR(1) states with the same core, which are the LALR(1) lookaheads. ∎