Introduction
A context-free grammar written to describe a language is often unsuitable for a parser. An ambiguous grammar gives a parser two trees to choose from. A left-recursive grammar sends a top-down parser into an infinite loop. Two alternatives that begin with the same symbols force a top-down parser to guess. This note collects the three standard rewrites that fix these problems while keeping the language the same: eliminating ambiguity, eliminating left recursion, and left factoring.
Each rewrite preserves the set of strings but changes the shape of the parse trees. That matters later, because translations attached to the grammar (for example, evaluating left-associative subtraction) must then be adjusted to the new shape.
Prerequisites
- Context-Free Grammars, Derivations and Ambiguity: productions, leftmost and rightmost derivations, parse trees, and the definition of an ambiguous grammar.
Core concepts
Notation used in all Compiler Design notes. Upper-case letters and names such as E, T, stmt are nonterminals; lower-case letters, operator symbols and bold-face names such as id are terminals; Greek letters are strings of grammar symbols (possibly empty); is the empty string. The first production's head is the start symbol. A vertical bar separates alternatives.
| Term | Definition |
|---|---|
| Immediately left-recursive | Some production has the form |
| Left-recursive | for some : can derive a sentential form that starts with in one or more steps |
| Indirect left recursion | Left recursion through other nonterminals, for example , |
| Common prefix | Two alternatives with |
| Ambiguous grammar | Some string has two different parse trees (equivalently, two leftmost derivations) |
How it works
Eliminating ambiguity by precedence levels
The grammar is ambiguous: id + id * id has two parse trees, one grouping id * id first and one grouping id + id first. With only +, the string id + id + id + id has 5 parse trees, the Catalan number , one per way of bracketing three operators.
The fix introduces one nonterminal per precedence level, lowest precedence nearest the start symbol, and chooses left or right recursion per operator to fix associativity:
E -> E + T | T (+ lowest precedence, left-associative)
T -> T * F | F (* higher precedence, left-associative)
F -> ( E ) | idNow id + id * id has exactly one parse tree, with * below +.
Associativity rule. A left-recursive production makes op left-associative (the leftmost operator is deepest in the tree, so it is applied first). A right-recursive production makes it right-associative, as used for exponentiation P -> B ^ P | B. Associativity is read from where the recursive nonterminal sits relative to the operator, not from the parser that will be used.
Reading an unusual grammar. In
E -> T * E | T
T -> T - F | F
F -> num- is on the lower level , so it binds tighter than *; - is left-associative (left recursion in ) and * is right-associative (right recursion in ). The string 8 - 2 - 1 * 3 * 2 - 1 has exactly one parse tree. First split at the * signs into the -pieces 8 - 2 - 1, 3 and 2 - 1; each piece groups to the left, and the pieces combine from the right:
With the usual precedences the same string would evaluate to .
The dangling else
The grammar S -> i E t S | i E t S e S | a, E -> b (with i for if, t for then, e for else) is ambiguous: i b t i b t a e a has two trees, one attaching the else to the inner if and one to the outer. Languages choose "match each else with the closest unmatched then". An unambiguous grammar for that rule separates matched statements (every then has its else) from open ones:
S -> M | O
M -> i E t M e M | a
O -> i E t S | i E t M e O
E -> bIt generates the same strings, and i b t i b t a e a now has exactly one tree, with the else attached to the inner if. Parser generators usually keep the short ambiguous grammar and resolve the conflict in favour of shifting else, which gives the same grouping.
Eliminating immediate left recursion
A top-down parser expands the leftmost nonterminal. With it would expand to , then to , without ever consuming input. The cure rewrites the recursion to the right.
Group the -productions as
where no begins with . Every string derived from is some followed by any sequence of 's. Replace them by
with a new nonterminal . Applied to the expression grammar:
E -> T E'
E' -> + T E' | eps
T -> F T'
T' -> * F T' | eps
F -> ( E ) | idThe two explicitly parenthesised expression grammars, the precedence grammar and this left-recursion-free grammar, generate exactly the same strings (257 token strings of length at most 9 agree). This rewritten grammar is not left-recursive and is LL(1).
Precondition. If every were (a production ), the rewrite would be meaningless; such cycles are removed first. -productions elsewhere are allowed in the immediate case.
Example: several alternatives on each side. has , , , :
S -> c S' | d S'
S' -> a S' | b S' | epsBoth grammars generate .
Example: one is . In , the non-recursive alternatives are and . The alternative does not disappear; it becomes :
A -> b d A' | A'
A' -> c A' | a d A' | epsBoth generate . Dropping would lose every string that does not start with b d, for example c and ad.
Eliminating indirect left recursion
The general algorithm orders the nonterminals and makes every production satisfy .
ELIMINATE-LEFT-RECURSION(G)
order the nonterminals A1, A2, ..., An
for i <- 1 to n
for j <- 1 to i - 1
replace each production Ai -> Aj gamma by
Ai -> delta1 gamma | ... | deltak gamma,
where Aj -> delta1 | ... | deltak are the current Aj-productions
eliminate immediate left recursion among the Ai-productionsPrecondition: the grammar has no cycles () and no -productions; with -productions, hidden left recursion can survive the substitution. Time: the substitution step can multiply the number of productions, so the output may be exponentially larger than the input in the worst case.
Worked example. Order in
S -> A a | b
A -> S c | dhas no immediate left recursion. For , substitute the -productions into : . Now remove the immediate left recursion with , , :
S -> A a | b
A -> b c A' | d A'
A' -> a c A' | epsThe original grammar is left-recursive (); the result is not, and both generate the same strings (all strings up to length 10 agree).
Hidden left recursion. In S -> A S b | c, A -> a | eps no production starts with S, yet because is nullable. This grammar is left-recursive. Questions that ask "is the grammar left-recursive?" test exactly this.
Left factoring
When two alternatives share a non-empty prefix , a predictive parser cannot choose between them by looking at the next token. Left factoring delays the choice until the prefix has been read:
Take to be the longest prefix common to two or more alternatives, and repeat until no two alternatives of any nonterminal share a prefix.
Example 1 (dangling else). S -> i E t S | i E t S e S | a has common prefix i E t S:
S -> i E t S S' | a
S' -> e S | eps
E -> bThe language is unchanged, but the grammar is still ambiguous and still not LL(1): with e as the next token, may either take e S or derive (because e can follow ). Left factoring removes guessing caused by common prefixes; it cannot remove ambiguity.
Example 2 (repeated factoring). A -> a b c | a b d | a e. The longest prefix shared by two alternatives is a b, but a is shared by all three. Factoring a first and then b:
A -> a A'
A' -> b A'' | e
A'' -> c | dImportant properties and observations
- Language preserved, trees changed. All three rewrites keep the language. Removing left recursion turns left-leaning trees into right-leaning ones; an attribute rule that computed left-associative subtraction on the old grammar must be rewritten with inherited attributes on the new one (see the note Syntax-Directed Translation Schemes in this subject).
- Independent problems. Removing left recursion does not remove ambiguity, and left factoring does not remove left recursion. An ambiguous grammar is never LL(1) or LR(1), whatever else is done to it.
- Necessary, not sufficient. A grammar that is unambiguous, free of left recursion and left-factored may still fail to be LL(1). The test is the LL(1) condition on FIRST and FOLLOW sets.
- Bottom-up parsers do not need these rewrites. LR parsers handle left recursion well (left recursion even keeps the LR stack short); only ambiguity matters to them.
- Inherent ambiguity. Some context-free languages have no unambiguous grammar at all; no rewrite can help (see the Theory of Computation note on context-free grammars).
Common misconceptions.
- "Right recursion is a problem for top-down parsing." It is not; only left recursion is.
- "Left factoring makes a grammar unambiguous." It does not: the factored dangling-else grammar is still ambiguous.
- ", is a different language." It is the same language , written with right recursion.
- "Removing left recursion from gives only." itself must still derive , as in .
GATE examination perspective
- Apply the rewrite. Given , write , . Check each carefully: every non-left-recursive alternative gets appended.
- Is the grammar left-recursive? Look for indirect and hidden left recursion through nullable nonterminals, not only for .
- Which rewrite for which parser. Left-recursion removal and left factoring prepare a grammar for top-down (LL) parsing. They are not needed for LR parsing.
- Ambiguity questions. Count parse trees for a short string; with one binary operator and no precedence, operators give trees (5 for three operators). A grammar with two parse trees for one string is ambiguous, even if all other strings have one tree.
- Associativity and precedence from a grammar. Lower precedence nearer the start symbol; left recursion means left-associative, right recursion right-associative. Questions sometimes define unusual grammars where
+binds tighter than*; read the levels, not your habits. - Language equality. Options that change the language (dropping an alternative, forgetting in ) are the usual wrong answers.
- The alternative of a left-recursive nonterminal. This is a : becomes , (equivalently after renaming).
- Evaluate with the grammar's precedences. For an unusual grammar, split the string at the lowest-level operator first, then group each piece by its own associativity.
Summary
Sources
- A. V. Aho, M. S. Lam, R. Sethi, J. D. Ullman, Compilers, Principles, Techniques, and Tools, 2nd ed., Pearson Addison-Wesley, 2007: Section 2.2.5 (associativity of operators), Section 2.2.6 (precedence of operators), Section 4.3.2 (eliminating ambiguity, the dangling else), Section 4.3.3 (elimination of left recursion), Section 4.3.4 (left factoring).