Ambiguity Analysis of an Expression Grammar with +, *, Parentheses, and id
Consider the grammar:
To decide whether it is ambiguous, we must determine whether there exists at least one string of terminals (e.g., a token sequence like ) that has two distinct parse trees (equivalently, two distinct leftmost derivations / rightmost derivations). A grammar is ambiguous if some string has multiple parse trees; it is unambiguous if every string has exactly one parse tree.
Key keyword ambiguity} questions to answer here:
- Where can and appear in the derivations?
- Does the grammar enforce operator precedence ( binds tighter than )?
- Does the grammar enforce left associativity for both and ?
We’ll show that the grammar enforces:
- has higher precedence than , because expands into ’s and only adds .
- Both and are left-associative, because the recursion is of the form and (left recursion).
As a result, the parse structure for any expression is forced: “splits” the expression into a sequence of terms, and each “splits” further into a sequence of factors separated by , with parentheses handled by .
The grammar is therefore unambiguous.
type="tip" title="Pro Tip" content="To prove unambiguity, it’s often enough to argue uniqueness of the operator-level decomposition: show that every string has exactly one way to split into top-level terms and then into factors."
Operator decomposition idea (why the grammar structure is forced)
Observe the nonterminals’ roles:
- represents expressions built from connecting one or more ’s.
- represents terms built from connecting one or more ’s.
- represents the smallest units: either or .
So any derivation for a string of the form:
- will produce some sequence containing at the “top level”.
- will produce some sequence containing at the “next level”.
- will never introduce or by itself—those operators can appear only via expanding or .
This immediately yields precedence: a cannot “escape” to become a at the level, because only creates by using the production .
keyword precedence] and keyword associativity] here follow from the grammar’s stratification:
- happens inside
- happens inside
Unambiguity justification by forced grouping at each operator level
- 1Step 1
Let be a string derived from (e.g., , , etc.).
- 2Step 2
At the top level, the only way to introduce a token in a derivation from is via . Therefore any derived string that contains must have a unique decomposition into a left part and a right at the outermost that is not inside parentheses.
- 3Step 3
When occurs inside parentheses, it is generated only inside . This prevents from interfering with the outer -level decomposition because the parentheses create a boundary for the substring derived by that .
- 4Step 4
Once the outer split produces a left and a right , each substring can contain only through . Thus each substring has a forced decomposition into left and right parts around at the corresponding level.
- 5Step 5
Similarly, if a substring contains , it must correspond to repeated use of with units as the leaves. Parentheses again isolate occurrences uniquely.
- 6Step 6
Because the recursion is (not ) and (not ), the grouping of a chain like is forced to left association: . Likewise, groups as .
- 7Step 7
Since the outermost decomposition is unique (thanks to operator placement rules and parentheses boundaries), and each produced substring has a unique decomposition, and each leaf is either or , the entire parse tree for is unique. Hence the grammar is unambiguous.
type="warning" title="Common Pitfall" content="A grammar with left recursion can still be ambiguous in some cases (e.g., if both parse structures can introduce the same operators at the same syntactic level). Here, the separation into E (only +) and T (only *) is what prevents competing parse trees."
Worked micro-examples (showing uniqueness)
Example 1:
- The must be inside because only adds with .
- There is only one plausible hierarchy:
- left
- right
- for the left factor
- for the right factor
So the structure corresponds to:
Example 2:
Parentheses force the part to be parsed as an inside a single :
- the on the left is , and inside it the must be
So it becomes:
These examples illustrate precedence: without parentheses, groups tighter; with parentheses, the inside groups first.
How the grammar enforces structure from tokens to parse tree
Leaves
1) Token levelOnly or appear as ."
Build products
2) Factor levelconstructs sequences of connected by ."
Build sums
3) Term levelconstructs sequences of connected by . "
Recursive isolation
4) Parentheses boundarycreates a boundary so outer operators cannot regroup inside."
Knowledge Check
The grammar , , is best classified as: