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 be a grammar in which every nonterminal derives some terminal string, augmented with , let , and suppose that LRK-TABLES reports no conflict. Then for every input :
- if LR-PARSE returns a tree, it is a parse tree of with root ;
- if , LR-PARSE returns a tree;
- if LR-PARSE reports an error at position (with for the end of the input), then is a prefix of a sentence, and is not when ;
- LR-PARSE stops after steps.
Setup. As on the LL(k) parsing page, the computed sets are exact, , and for every string . For a string of grammar symbols, let be the state reached from by GOTO along , when it exists. Each stack entry is a symbol , a tree with root and a state. A shift pushes and a reduction pushes , so the state on top is always , where is the string of stack symbols. Every kernel item of a GOTO state comes from the item of the previous state, and every item with the dot at the start, other than , is added by closure. The item is only in , because is on no right side.
Lemma 1 (validity). If , there is a rightmost derivation with , and .
Proof. By induction on the order in which the construction adds items.
- The start item. For , take the empty derivation with .
- GOTO. If comes from , the derivation for the latter has , so .
- Closure. Suppose is added from with . Take the derivation of the latter. Since , for some . Rewriting to only touches symbols to the right of , so it is rightmost: , with .
Lemma 2 (completeness). Let be a parse tree with root , under the extra root . Let be an inner node of with production , where is any prefix of the right side. Let be the labels of the left siblings of the proper ancestors of and of itself, in order, and let be the part of the yield of to the right of . Then exists and contains .
Proof. We use induction on the depth of . For the root , take the start item. Let be a child of , with production , where is the child labeled after . By the induction hypothesis, , where and belong to . Here , and is the yield of the subtrees of followed by . So , and closure puts into . GOTO along moves the dot, and each GOTO exists because its item has the next symbol after the dot.
Lemma 3 (keys). If , then every is a key of .
Proof. We use induction on the least height of a forest of trees for whose yield has . There are three cases.
- . Then , and line L17 sets the reduction, or accept, at .
- starts with a terminal. Line L16 sets shift at all of .
- with . Let the tree of use with yield , and let . Closure puts into with . Then , and the children of the tree of form a forest for of smaller height.
Step 1: acceptance gives a parse tree. Each reduction by pops the trees of the symbols and pushes a node 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 . The accept action comes only from . A state with this item is for a state that contains , so . The state 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 . Line L11 checks , so the yield of that tree is . This proves part 1.
Step 2: sentences are accepted. Let and fix a parse tree of under the extra root . Claim: the parser processes the nodes of below 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 , with tokens shifted. Let .
- is an inner node. Say uses . All its children have been processed, so the stack symbols are in the notation of Lemma 2, and the part of the yield to the right of is . Lemma 2 gives . Since there is no conflict, ACTION at the lookahead is this reduction. The parser pops the children and pushes .
- is a leaf. Then , the child of a node with production , whose children before are processed. Lemma 2 gives in the top state, where is the yield to the right of . The input is , followed by a yield of , followed by . So , and the cell holds shift. GOTO on exists because of the same item.
- All nodes below are processed. The stack is over , and . Lemma 2 for with gives , so the parser accepts.
The tree is finite, so the parser accepts after one step for each node of and one more. This proves part 2.
Step 3: every key is a real continuation. Let the stack symbols be , with tokens shifted, and let be a key of . Then for some with .
If the key comes from a complete item, Lemma 1 gives with . If it comes from line L16, the item and Lemma 1 give with . Then for some . In both cases derives through the stack trees.
Step 4: the inspected tokens stay consistent. Let be the largest position read by a lookahead so far, that is, the largest over the steps done so far at positions . Claim: at each test of line L3, is a prefix of some key of the top state (the empty string when ).
Let the last step be taken at position with the lookahead , a key of the state on top then. Then is , or longer when .
- A reduction by . Its item traces back through GOTO to in the state below the popped entries. That item is added by closure from some with . The new state contains , so is a key of it by Lemma 3. The position is unchanged.
- A shift of . It comes from with for a string that starts with a yield of and continues with . The new state contains . Its key , which is a key by Lemma 3, has the rest of as a prefix.
Step 5: the valid prefix property. Suppose the parser reports an error at position , with stack symbols and tokens shifted. An error arises in one of three ways.
- No action (line L4). Here , and shares tokens with a key. By Step 3, starts a sentence. By Step 4, , so .
- Shift without GOTO (line L6), only for . Here and . The top state has a shift item . By Lemma 1 and Step 3, starts a sentence, so does too.
- Accept with input left (line L11). Here and , and by Step 1.
Now let , and suppose that a sentence starts with . Every step so far read only positions up to and shifted tokens before . So the parser makes the same moves on and reaches the same stack. On it accepts by Step 2, following the tree of . So at this stack, has the next action that Step 2 describes.
- No action. The lookahead on is a key that agrees with on tokens, against the choice of .
- Shift without GOTO. The next node of the tree of is a leaf, and GOTO on exists, a contradiction.
- Accept with input left. The parser on accepts here while has the token left, which Step 1 excludes.
This proves part 3.
Step 6: termination. Shifts happen at most times. Between two shifts, the moves depend only on the stack and the lookahead . By Step 3 there is a sentence with . It agrees with on every position read so far, so the parser makes the same moves on , 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 , which gives part 4. We cite that bound rather than reprove it.