Derivations and Parse Trees
Consider a compiler reading the expression `2 + 3 4`. It must decide whether multiplication happens before addition. The grammar alone lists rules. It does not say how to apply them, or what shape the final answer takes. Derivations answer the "how," step by step. Parse trees answer the "what shape." They show the hierarchical structure hidden inside a flat string of symbols. Together they turn an abstract <a class="wiki-link" href="/wiki/cs-theory-context-free-grammars" data-track="wiki_article.body.wiki_link">context-free grammar</a> into a concrete recipe. That recipe generates, recognizes, and structurally interprets strings. This distinction matters enormously in real systems. A compiler's parser does not merely check that source code is syntactically valid. It builds a parse tree, or a lighter abstract syntax tree derived from it. Downstream stages walk this tree to generate machine code, perform type checking, or optimize expressions. Two different derivations of the same string can correspond to the same tree. They then differ only in the order rules were applied. Or they can correspond to genuinely different trees. This exposes a structural ambiguity the language designer must resolve. Understanding when derivations coincide and when they diverge is key. It is the conceptual bridge to ambiguity, one of the central concerns in language and grammar design. The big picture is this: a context-free grammar generates a language. It does so by permitting sequences of substitutions. These start from a special start symbol. Nonterminals are then repeatedly replaced using production rules, until only terminal symbols remain. Any such sequence is a <strong>derivation</strong>. A <strong>parse tree</strong> is a picture of one particular kind of derivation. It is an order-independent snapshot of which substitutions were made and how they nest. It is stripped of the arbitrary bookkeeping of when* each one happened. This article makes the mechanics precise. It covers what a derivation step is. It explains how leftmost and rightmost derivations canonically order the substitution choices. It shows how to build the parse tree that corresponds to a derivation. It explains why every parse tree corresponds to infinitely many equivalent derivations. Yet every leftmost (or rightmost) derivation corresponds to exactly one tree. This correspondence is the load-bearing fact used later to define and detect ambiguity. It also sets up the motivation for normal forms like Chomsky Normal Form. These make parse trees easier to analyze algorithmically.
- A derivation is a sequence of substitution steps transforming the start symbol into a string, using the grammar's rules one at a time.
- A leftmost derivation always expands the leftmost remaining nonterminal; a rightmost derivation always expands the rightmost one.
- A parse tree is a rooted, ordered tree whose internal nodes are nonterminals (labeled by rule left-hand sides) and whose leaves, read left to right, spell the derived string.
- Every parse tree corresponds to exactly one leftmost derivation and exactly one rightmost derivation, even though many interleaved derivations can share the same tree.
- If a string has two different parse trees under the same grammar, the grammar is ambiguous for that string — the key idea that motivates the next stage of study.
- Building parse trees mechanically (top-down or bottom-up) is the algorithmic core of parsing in compilers and other language-processing tools.
A derivation records the order of rule applications; a parse tree records only their nesting — and leftmost derivations are the canonical bridge that recovers one from the other uniquely.
The idea
A context-free grammar consists of nonterminals , terminals , production rules , and a start symbol . A derivation step rewrites a single occurrence of a nonterminal appearing in some string (where are strings of terminals and nonterminals) into , provided is a rule in . We write
to denote one derivation step. A derivation is a chain of such steps,
written compactly as , showing that the string is generated by . Crucially, at each intermediate string there is usually more than one nonterminal present, and the grammar's rules say nothing about which one must be expanded next — that choice is a bookkeeping decision made by whoever performs the derivation, not a property of the grammar itself. This ambiguity of order (not to be confused with ambiguity of the grammar) motivates fixing a canonical strategy. In a leftmost derivation, every step expands the leftmost nonterminal symbol still present in the current string. In a rightmost derivation, every step expands the rightmost nonterminal. These are conventions for producing a unique, deterministic sequence of steps that generates a given string, out of all the equivalent unordered derivations that differ only in which nonterminal was chosen first. Top-down parsers (like recursive descent) naturally construct leftmost derivations; bottom-up parsers (like LR parsers) naturally construct the reverse of rightmost derivations. A parse tree (also called a derivation tree) for a grammar is a rooted, ordered tree satisfying three conditions: the root is labeled ; every internal node is labeled by some nonterminal , and its children, read left to right, spell exactly the right-hand side of some rule (with a single child labeled if the rule is ); and every leaf is labeled by a terminal symbol or . The yield of the tree — its leaves read left to right — is the string generated. The tree captures only the hierarchical grouping of substitutions, discarding the temporal order in which they were performed. This is exactly why many different derivations, differing only in the interleaving of independent expansions, collapse onto the same single tree.
How it works
Building a parse tree from a grammar and a target string is the essence of parsing. Two dual algorithmic strategies correspond to leftmost and rightmost derivations respectively.
Top-down construction (leftmost derivation). Start with a single root node labeled . Repeatedly find the leftmost nonterminal leaf in the tree built so far, choose a rule for it, and attach children spelling that rule's right-hand side. Continue until every leaf is a terminal (or ) and the yield matches the target string.
Bottom-up construction (reverse rightmost derivation). Start with the target string as a forest of terminal leaves. Repeatedly find a substring matching some rule's right-hand side, replace it with a new internal node labeled by that rule's left-hand side, and continue until only the root remains. Read the sequence of reductions backward to recover the rightmost derivation. Below is pseudocode for generating a leftmost derivation and simultaneously constructing its parse tree, given a grammar and (via nondeterministic choice, as in a search procedure) a target string. This models what a nondeterministic top-down parser conceptually does; deterministic parsers add lookahead and restrictions to make the rule choice computable without backtracking. ``` function LEFTMOST-DERIVE(G, target):
# G = (V, Sigma, R, S). Returns a parse tree with yield == target,
# or FAIL if no leftmost derivation of target exists. root = new TreeNode(label = S, children = []) frontier = [root] # ordered list of tree leaves, left to right derivation = [] # sequence of (nonterminal, rule) pairs function YIELD(frontier): return concatenate(node.label for node in frontier if node.isTerminalOrEpsilon) function EXPAND(frontier, target):
# find leftmost nonterminal leaf i = index of first node in frontier where node.isNonterminal if i does not exist: return (YIELD(frontier) == target) ? SUCCESS : FAIL A = frontier[i].label for each rule (A -> X1 X2 ... Xk) in R: # nondeterministic choice newChildren = [TreeNode(Xj) for Xj in X1..Xk] # or single epsilon-node if k==0 attach newChildren as children of frontier[i] newFrontier = frontier[0:i] + newChildren + frontier[i+1:] partialYield = concatenate terminal labels in newFrontier up to next nonterminal if partialYield is not a prefix of target so far: undo attachment continue # prune: this choice cannot lead to target derivation.append((A, rule)) result = EXPAND(newFrontier, target) if result == SUCCESS: return SUCCESS derivation.pop() undo attachment # backtrack return FAIL if EXPAND(frontier, target) == SUCCESS: return (root, derivation) else: return FAIL ``` The rightmost analogue is identical except that `EXPAND` always selects the last nonterminal leaf in `frontier` rather than the first, and the resulting derivation, read in the order rules are applied, is the rightmost derivation of `target`. The figure below shows the parse tree for the arithmetic string `2+3*4` under a grammar with rules , alongside the two canonical derivations it corresponds to.
For this tree, the leftmost derivation always expands the leftmost `E`:
and the rightmost derivation always expands the rightmost `E`:
Both derivations produce the exact same tree shown above — they differ only in which order the two `E` children of the root were expanded, not in the final nesting structure.
Complexity & correctness
Time and space for tree construction. For a fixed grammar with rules, each of bounded right-hand-side length, generating a leftmost derivation top-down with unbounded backtracking (as in the pseudocode above) is exponential in the worst case: at each of the expansion steps for a target string of length , up to rule choices must be tried, giving a search tree of size in the naive case. This is why real parsers restrict attention to grammar subclasses (LL(1), LR(1), etc.) or use dynamic-programming parsers like CYK, which run in time and space for arbitrary context-free grammars by building parse trees bottom-up over all substrings, avoiding redundant recomputation. The CYK approach itself relies on rules being in Chomsky Normal Form, a normal form specifically designed to make this dynamic program clean — foreshadowing why that normal form exists at all. Independent of parsing strategy, once a specific derivation (leftmost or rightmost) of length steps is given, constructing its parse tree takes time and space: each step attaches amortized new nodes (bounded by the maximum rule length), and the total number of nodes in the tree is linear in the number of derivation steps plus the string length.
Correctness argument — the leftmost/tree bijection. The central fact to justify is: > For any context-free grammar and string , there is a bijection between parse trees for and leftmost derivations of (and, separately, a bijection between parse trees for and rightmost derivations of ). Tree → leftmost derivation. Given a parse tree , produce a leftmost derivation by induction on tree size. If is a single terminal leaf, the derivation is empty (or the trivial one-step case ). Otherwise let the root be with rule and subtrees rooted at . Emit the step , then recursively emit the leftmost derivation of 's yield (this expands all nonterminals inside before touching , since 's internal nonterminals are, by construction, always the leftmost pending nonterminal until is fully expanded), then of 's yield, and so on. This produces one well-defined derivation and it is easily checked to always expand the current leftmost nonterminal, by induction on the recursive structure. Leftmost derivation → tree. Conversely, given a leftmost derivation, build the tree exactly as the top-down pseudocode does: each step (with leftmost) attaches 's symbols as children of the tree node currently representing that occurrence of . Because the derivation always targets the unique leftmost pending nonterminal, there is never an ambiguity about which tree node receives the new children — the construction is forced at every step, giving a well-defined tree. These two maps are mutually inverse. Running tree → derivation → tree recovers the original tree exactly, because the induction above visits subtrees in the same left-to-right order that the reconstruction consumes derivation steps; running derivation → tree → derivation recovers the original derivation exactly, because at every point the "leftmost pending nonterminal" in the partially built tree is uniquely determined by the tree's shape so far, matching the induction's recursive order. Formally this is proved by induction on the number of derivation steps, showing the invariant: after steps of a leftmost derivation, the frontier of the corresponding partially-built tree, read left to right, equals the current sentential form . This invariant holds trivially at (frontier is just the root ), and is preserved at each step because expanding the leftmost nonterminal leaf in the tree corresponds exactly to rewriting the leftmost nonterminal occurrence in the string. The same argument, mirrored, gives the rightmost bijection.
Why unordered derivations do not give a bijection. A general (non-canonical) derivation need not expand nonterminals in any consistent left-to-right or right-to-left order — two independent nonterminals and present simultaneously in a sentential form can each be expanded first, giving two different derivations that nevertheless produce the identical tree (they only reorder when independent subtrees are grown, not how they nest). This is precisely why leftmost and rightmost derivations are singled out as canonical: they are the two derivation orders that break all remaining freedom by fixing a deterministic scan direction, collapsing the many equivalent unordered derivations of a tree down to exactly one representative each.
The honest tradeoff. Parse trees are the "right" object to reason about structure (operator precedence, scope nesting, semantic meaning), but they are more expensive to store and manipulate than a bare derivation string or a compressed abstract syntax tree. Compilers typically build a full parse tree (or an equivalent internal structure) only implicitly, collapsing it immediately into a leaner abstract syntax tree that omits redundant unit-production nodes, trading some traceability back to the exact grammar rules used for a smaller memory footprint and faster downstream traversal.
Worked example
Take the classic (deliberately ambiguity-prone) grammar for simple arithmetic:
and derive the string `id + id × id`, tracing a leftmost derivation, its rightmost counterpart, and the resulting tree — using the derivation choice that groups `+` at the top (i.e., reading the string as `id + (id × id)`).
| Step | Leftmost derivation (expand leftmost ) | Rightmost derivation (expand rightmost ) |
|---|---|---|
| 0 | ||
| 1 | ||
| 2 | ||
| 3 | ||
| 4 | ||
| 5 |
Both sequences are 5 steps long and use exactly the same multiset of rules — one application of , one of , and three of — but applied in reverse relative order, since leftmost sweeps outer-to-inner-left while rightmost sweeps outer-to-inner-right. Both correspond to the single tree: ``` E / | \ E + E | /|\ id E × E | | id id ``` Now check the bijection claim concretely. Reading the tree top-down, left to right, the induction described above emits: root rule first (step 1 above); then recurse into the left child, which is a leaf `id`, contributing nothing further to the derivation steps beyond having already appeared; then recurse into the right child , whose rule is (step 2's target, but note it appears as step 3 in the table because the leftmost `id` at position 1 must first be finalized) — this exactly reconstructs the leftmost derivation column. Running the same tree through the rightmost-recovery procedure (recursing right-to-left, applying the mirrored invariant) reconstructs the rightmost derivation column. Since both procedures are deterministic functions of the tree alone, this single tree provably yields exactly one leftmost and exactly one rightmost derivation — no other ordering of these same three rule applications is either leftmost or rightmost, even though several such orderings exist and all describe the same tree. Contrast this with genuine ambiguity: the same string `id + id × id` also has a second, different parse tree grouping as `(id + id) × id`: ``` E / | \ E × E / | \ | E + E id | | id id ``` This tree has a different shape (root rule is , not ), hence a genuinely different leftmost derivation: . Because two structurally distinct trees both yield the same final string under this grammar, the grammar is ambiguous for this input — the precise phenomenon that the concept of Ambiguity in Context-Free Grammars formalizes and studies.
Common pitfalls & traps
| Pitfall | Why it happens | Fix |
|---|---|---|
| Confusing "different derivation" with "different tree" | Two derivations can interleave independent expansions in different orders yet build the identical tree | Always compare parse trees, not raw derivation step sequences, when checking whether a string is genuinely ambiguous |
| Forgetting the -production case in a tree | A rule still needs a child node (labeled ) or the yield computation silently miscounts | Represent explicitly as a leaf, or define yield to skip it consistently everywhere |
| Assuming leftmost and rightmost derivations of a string are always different | For strings with only one nonterminal expanded at a time (no two pending nonterminals simultaneously), leftmost and rightmost derivations can coincide step-for-step | Check the sentential forms directly rather than assuming asymmetry |
| Treating parse trees and abstract syntax trees as the same object | Parse trees include every grammar rule application, including unit productions like ; ASTs collapse these away | Be explicit about which structure a given diagram or algorithm is building |
| Using unrestricted backtracking search to "parse" and calling it efficient | The naive top-down search shown for leftmost derivations is exponential in the worst case for ambiguous or highly branching grammars | Use CYK (, needs Chomsky Normal Form) or a restricted deterministic grammar class (LL/LR) for polynomial parsing |
Pioneers & history
The formal machinery of derivations and parse trees emerged from the mid-20th-century convergence of linguistics and computer science, as researchers sought precise mathematical models for how sentences — in natural language and later in programming languages — could be systematically generated and structurally analyzed.
Origins · 1 minNoam Chomsky and how this was discovered
Where this matters
Every modern compiler and interpreter — for C, Python, JavaScript, SQL, or any structured configuration language — relies on parsing a token stream into a parse tree (or a closely related abstract syntax tree) before any semantic analysis or code generation can proceed. Parser generators such as Yacc, Bison, ANTLR, and the Earley- or LR-based engines inside modern language toolchains all implement, at their core, the leftmost- or rightmost-derivation logic described here, differing mainly in how much lookahead and backtracking they permit before committing to a rule choice. Beyond programming languages, XML and JSON schema validators, natural language parsers used in computational linguistics, and even query optimizers for SQL that need to understand the structure of a query all build and manipulate parse-tree-like structures derived from an underlying context-free (or context-free-adjacent) grammar. The leftmost/rightmost canonical-derivation framework is also the conceptual foundation for understanding why certain grammars admit efficient, deterministic parsing (LL and LR grammars) while others require exponential search or restriction to normal forms — a distinction that directly determines which grammar classes are practical for building real-world language tools.
Ask the tutor: Can you show why an ambiguous grammar can sometimes be rewritten into an equivalent unambiguous grammar, and when that's impossible?
What exactly is a "derivation step" versus a full "derivation"?
A derivation step is a single application of one production rule: replacing one occurrence of a nonterminal in a string with the right-hand side of a matching rule, written . A full derivation is a finite chain of such steps starting from the grammar's start symbol and ending at a string made entirely of terminals, written . The step is the atomic unit of rewriting; the derivation is the complete generative history showing how was produced. A grammar generates a language precisely by allowing all strings reachable via some derivation from , so derivations are the formal witness that a string belongs to the language.
Why do we bother defining leftmost and rightmost derivations specifically, rather than just any derivation order?
Any valid rewriting order proves a string is generated by the grammar, but unordered derivations are not unique — many different orderings can produce the same parse tree, making it impossible to compare derivations directly to test ambiguity. Fixing a canonical scan direction (always leftmost, or always rightmost) removes this redundancy: it is a theorem that each parse tree corresponds to exactly one leftmost derivation and exactly one rightmost derivation. This turns "does this string have two different trees" into the cleanly checkable question "does this string have two different leftmost derivations," which is the operational definition of ambiguity used throughout formal language theory.
Can a string have a leftmost derivation but no corresponding rightmost derivation, or vice versa?
No — if a string is generated by a grammar at all, meaning some parse tree exists with yield , then that same tree yields both a leftmost derivation and a rightmost derivation of , by the two symmetric constructions described in the correctness argument. The two derivations may look very different as sequences of sentential forms, since they process the tree's subtrees in opposite left-to-right order, but they always exist together, in pairs, one per tree. Their number is therefore identical — the count of leftmost derivations for always equals the count of rightmost derivations for , equal to the number of distinct parse trees.
How do parse trees relate to abstract syntax trees used in real compilers?
An abstract syntax tree (AST) is a simplified version of a parse tree that omits grammar bookkeeping irrelevant to meaning, such as nodes for punctuation tokens, parenthesization rules, or unit productions like that add a layer without adding information. A parse tree faithfully mirrors every grammar rule applied, including these redundant layers, which makes it directly connected to the grammar's derivation but bulkier to store and traverse. Compilers typically construct (at least conceptually) a parse tree during parsing, then immediately simplify it into an AST for semantic analysis, type checking, and code generation, trading strict rule-by-rule fidelity for a leaner, more semantically direct structure.
Does every context-free grammar admit a leftmost derivation for every string in its language?
Yes. If , some derivation exists by definition of language membership, and hence at least one parse tree with yield exists. The tree-to-leftmost-derivation construction described in the correctness argument applies to any valid parse tree, deterministically producing a leftmost derivation from it. So the existence of a leftmost derivation is guaranteed whenever the string is in the language; what is not guaranteed is uniqueness — an ambiguous grammar may admit multiple distinct leftmost derivations (one per distinct tree) for the same string.
What is the practical cost of actually building a parse tree during parsing?
Given a fixed derivation of length (number of rule applications), constructing the corresponding parse tree takes time and space, since each step adds a bounded number of new nodes. The expensive part is not tree construction itself but finding a valid derivation in the first place: naive backtracking search can be exponential, while general dynamic-programming parsers like CYK guarantee time and space for any context-free grammar (after conversion to Chomsky Normal Form), and restricted deterministic grammars (LL(1), LR(1)) achieve linear parsing time by design, at the cost of restricting which context-free languages they can express without grammar transformation.
How does this connect to detecting ambiguity in a context-free grammar?
A grammar is defined as ambiguous for a string exactly when has two or more distinct parse trees, which by the bijection is equivalent to having two or more distinct leftmost derivations (or, equivalently, two or more distinct rightmost derivations). This gives a concrete, checkable criterion: to prove ambiguity, exhibit two different leftmost derivations of the same string and show they build different-shaped trees, as done in the worked example with `id + id × id`. This is precisely the tool used to formally establish Ambiguity in Context-Free Grammars, one immediate and important consequence of the derivation/tree correspondence developed here.