Proofs: Left recursion elimination algorithm
These are the human proofs of Left recursion elimination algorithm, at full length.
PREPARE followed by PAULL keeps the language and removes all left recursion full
This proof shows: correctness.
Statement. Let be any grammar, and let be the result of PREPARE, then PAULL, then the new start when . Then , and no nonterminal of satisfies .
Throughout, is the set of terminal strings derived from in the grammar , and trees are complete parse trees.
Step 1 (PREPARE). Let be the grammar after line P4. We show that , that has no -production, that every nonterminal with a production derives a terminal string, and that no nonterminal satisfies in .
- Lines P1 and P3 drop only productions that use a symbol deriving no terminal string. No complete tree uses such a production, so is unchanged for every remaining .
- Line P2 is epsilon-production elimination, which gives for each and no -production.
- Without -productions a step never shortens a sentential form, so a derivation goes through strings of length 1 only, and uses only unit productions . Thus such cycles are exactly the cycles of the unit graph, with an edge for each unit production. Line P4 renames every nonterminal to the representative of its strongly connected component in this graph and drops the productions . Claim: for every , the new grammar derives from exactly when the old one derives from . From old to new, rename every node label of an old tree by and remove each node that now uses , putting its child in its place. From new to old, we show by induction on the size of a new tree with root that, for every with , there is an old tree with root and the same yield: the root of uses for some old production with ; in the old grammar by unit productions, because and lie in one component; apply and replace each child subtree by the old tree given by the induction hypothesis for the corresponding symbol of . After the renaming the unit graph is the condensation of the old one without loops, so it is acyclic, and has no derivation . Renaming creates no -production and no unproductive symbol.
Line P5 records before line P2 removes it, and adds it back at the end.
Step 2 (substitution keeps the language). Let have a production with , and let be with replaced by for every production of . Then for every . A step of is the two steps , of . Conversely, take a -tree and a node that uses . Its first child is labelled and is an inner node using some ; this production is not , because , and it is still in , because the productions of do not change. Replace the two nodes by one node using , whose children are the children of the node followed by the other children of the node. The yield does not change, and the number of nodes using drops by one, so induction on this number gives a -tree.
Lines L3 to L5 apply this step once for each replaced production, with and , , while stays fixed, so every set is unchanged.
Step 3 (the direct step keeps the language). Let have the productions , where no starts with , and let replace them by and , with new. Then for every nonterminal of . In a -tree, take a node that is not the first child of a node using some , and follow its first children down while they use productions , , ..., ; the last on this spine uses some . The spine has yield , where denotes the yields of the subtrees of these symbols. Replace it by the node and the chain , ..., , , which has the same yield. Doing this for the topmost such spine and then, by induction on size, inside the subtrees of and of the s gives a -tree. Conversely, occurs only at the right end of the new productions, so in a -tree every node lies on a chain that hangs from a node and ends with ; the inverse rewriting turns this chain back into a left spine.
By Steps 1 to 3, after the loop, so once is added.
Step 4 (three invariants). Call the original nonterminals and the the primed ones. We show that the following hold before round 1 and after every substitution and every direct step:
- (P) every production of an original nonterminal is nonempty and starts with a terminal or an original nonterminal;
- (U) if an original has a production with original and a string of primed symbols, then in by unit productions;
- (I) after round , every production of with starts with a terminal or with some , .
Before round 1 there are no primed symbols, so (P) is the absence of -productions in and (U) says that is a unit production of .
Substitution. The production becomes with . By (P) for , is nonempty and starts with a terminal or an original, so (P) holds. If with original and primed, then and with primed. (U) for gives , and (U) for gives , both by unit productions of ; so and (U) holds.
Direct step. The new productions of are , where was a production before the step. By (P), is nonempty and starts with a terminal or an original, so (P) holds. If with primed, then with primed, and (U) for gives . The productions of are not productions of an original, so (P) and (U) say nothing about them.
Invariant (I). Rounds before and after round do not change the productions of , . In round , after iteration of line L3, no production of starts with : iteration replaces each production that starts with by productions that start with , and by (I) for , starts with a terminal or with , . So after line L5 every production of starts with a terminal or with , . Lines L6 to L9 replace those that start with , and the new productions start with the first symbol of , which is a terminal or an with .
The direct step is well defined. At line L6 there is at least one : by Steps 2 and 3, is still , which is not empty; if every production of started with , the leftmost path of any tree with root would never end. Each is not a string of primed symbols, and in particular not empty: otherwise (U) applied to gives in , which Step 1 excludes.
Step 5 (nullable symbols). In every primed symbol is nullable, by , and no original symbol is nullable. Suppose some original is; take one, , with a tree of yield of least height. By (P), uses a production that starts with a terminal, which cannot vanish, or with an original , whose subtree has yield and smaller height. Both contradict the choice of .
Step 6 (no left recursion). Define the left-corner graph of : an edge whenever has a production with nullable. If , take a tree with root and yield and the path from the root to the leaf at the left end of the yield. Every sibling to the left of a node on this path has yield , so every edge of the path is an edge of the graph, and the path is a closed walk of length at least 1 through . So it suffices to show that the graph has no cycle.
- Edges from an original . By (I) the first symbol of each production of is a terminal or an with , and by Step 5 it is not nullable. So the only edges from go to originals with .
- Edges from a primed . Its productions are and with fixed in round ; they never change afterwards, since later rounds rewrite only productions of originals. At that time the primed symbols are with , so contains no . By Step 4, contains a terminal or an original; the left corners of are the symbols of up to the first of these. So the edges from go to some with and to at most one original or terminal, and never to .
- Edges from go to , and no edge enters , which occurs on no right side.
A cycle that contains an original stays among originals, because no edge leads from an original to a primed symbol, and then the indices strictly increase along it, which is impossible. A cycle of primed symbols only has strictly decreasing indices, which is also impossible. So the graph is acyclic and has no left-recursive nonterminal.
Termination. PREPARE does a bounded amount of work, line P2 creating at most versions of a production with nullable symbols. The main loop does rounds of at most substitutions, each over a finite set of productions. So the algorithm stops.