Skip to main content

3.1 Context-Free Grammars in Compilers, Derivations & Parse Trees

📚Module 01Context-Free Grammars, Derivations & Parse Trees⏱️5 min read
🎯High-Yield For:Semester Exams • GATE CSE • Technical Interviews

💡 Core Intuition: The 3-Second Mental Model​

🍳 The Everyday Analogy: The Sentence Scaffolding vs Finished Meaning​

Imagine a high school English teacher analyzing Shakespearean prose:

  1. The Raw Words (Tokens): A linear sequence of words written on paper: ["The", "dog", "bit", "the", "mailman"].
  2. The Sentence Diagramming Tree (Concrete Parse Tree): The student draws an elaborate grammatical tree breaking the sentence down into Subject Phrase, Determiner, Noun, Verb Phrase, Transitive Verb, Object Phrase. Every comma, auxiliary word, and article has its own branch.
  3. The Semantic Core Meaning (Abstract Syntax Tree): The essential factual action extracted: Bite(Subject: Dog, Object: Mailman). The auxiliary grammar scaffolding has served its purpose and is set aside.

💻 Bridging to Computer Science: Linear Tokens to Hierarchical Derivation Trees​

When the lexical analyzer delivers a flat stream of tokens:

[ID, "pos"], [ASSIGN, "="], [ID, "init"], [PLUS, "+"], [ID, "rate"], [STAR, "*"], [NUM, 60]

The CPU cannot execute this directly because a flat array does not convey precedence, associative grouping, or nested control flow. Syntax analysis solves this by applying a Context-Free Grammar (CFG) to construct a hierarchical derivation tree that explicitly determines operator precedence, nesting, and execution order.


🏗️ Architectural Foundations: Tokens to Abstract Syntax Trees​

The syntax analysis phase converts flat lexical streams into minimal semantic trees through four sequential stages:

Architecture Flow

The Syntax Analysis Transformation Pipeline

From a flat token stream to a clean, minimal semantic Abstract Syntax Tree

🔢Stage 1

Token Stream

Linear sequence of terminal tokens emitted by the lexical scanner via getNextToken().

→
CFG Rules
📜Stage 2

Derivation Sequence

Ordered substitution steps replacing non-terminals (Leftmost or Rightmost Derivation).

→
Generates
🌳Stage 3

Concrete Parse Tree

Full syntax tree with every grammatical rule, non-terminal, parenthesis, and delimiter.

→
Prunes Noise
⚡Stage 4

Abstract Syntax Tree

Compact semantic execution tree passed downstream to Type Checking and ICG.

⚖️ Concrete Parse Tree vs Abstract Syntax Tree (AST)​

Concrete Parse Tree vs Abstract Syntax Tree (AST)

Contrasting grammatical verification scaffolding against semantic execution trees

Grammatical Scaffolding

Parse Tree (Concrete Syntax Tree)

🌳
Dominant Architecture / DomainSyntax Verification Phase
  • •Represents the exact grammatical derivation sequence used by the grammar.
  • •Contains every non-terminal, terminal, delimiter, and parenthesis.
  • •Bloated with intermediate chain productions (E -> T -> F -> id).
  • •Disposed of after syntax analysis to conserve compiler memory.
"Shows how the grammar derived the string down to every single punctuation mark."
Semantic Core

Abstract Syntax Tree (AST)

⚡
Dominant Architecture / DomainIntermediate Code & Optimization Phases
  • •Retains only essential semantic operators and operands.
  • •Operators form internal nodes; operands form leaf nodes.
  • •Discards syntactic clutter like parentheses, semicolons, and commas.
  • •Passed downstream to Semantic Analysis, Type Checking, and ICG.
"Retains only what is needed to compute the answer, eliminating syntax noise."

📐 Formal Mathematical Foundations of Context-Free Grammars​

📜 Formal CFG 4-Tuple​

A Context-Free Grammar GG is formally defined as a 4-tuple:

G=(V,Σ,P,S)G = (V, \Sigma, P, S)

Where:

  • VV is a finite set of Non-Terminal symbols (syntactic variables representing language constructs).
  • Σ\Sigma is a finite set of Terminal symbols (the tokens delivered by the scanner, where Σ∩V=∅\Sigma \cap V = \emptyset).
  • PP is a finite set of Production rules of the form: A→αwhere A∈V and α∈(V∪Σ)∗A \to \alpha \quad \text{where } A \in V \text{ and } \alpha \in (V \cup \Sigma)^*
  • S∈VS \in V is the designated Start symbol.

🔄 The Derivation Relations (⇒ and ⇒*)​

  • Derivation: The formal process of deriving a target string from the start symbol by repeatedly applying production rules.
  • If A→γA \to \gamma is a production in PP, and α,β∈(V∪Σ)∗\alpha, \beta \in (V \cup \Sigma)^*, we say that αAβ\alpha A \beta directly derives αγβ\alpha \gamma \beta:
αAβ⇒αγβ\alpha A \beta \Rightarrow \alpha \gamma \beta

The reflexive and transitive closure of ⇒\Rightarrow is denoted as ⇒∗\Rightarrow^*, representing zero or more derivation steps:

α0⇒α1⇒α2⋯⇒αn  ⟺  α0⇒∗αn\alpha_0 \Rightarrow \alpha_1 \Rightarrow \alpha_2 \dots \Rightarrow \alpha_n \iff \alpha_0 \Rightarrow^* \alpha_n

The language generated by grammar GG is the set of all terminal strings derived from start symbol SS:

L(G)={w∈Σ∗∣S⇒∗w}\mathcal{L}(G) = \{ w \in \Sigma^* \mid S \Rightarrow^* w \}

📄 Sentential Forms​

  • Sentential Form: Any string α∈(V∪Σ)∗\alpha \in (V \cup \Sigma)^* that appears at any intermediate step in a derivation from start symbol SS (S⇒∗αS \Rightarrow^* \alpha).
  • Left-Sentential Form: An intermediate sentential form appearing in a Leftmost Derivation.
  • Right-Sentential Form: An intermediate sentential form appearing in a Rightmost Derivation.
  • Sentence: A sentential form containing exclusively terminal symbols (w∈Σ∗w \in \Sigma^*).

🧭 Leftmost vs Rightmost Derivations & Sentential Forms​

At any step in a derivation containing multiple non-terminals, the compiler must decide which non-terminal to expand next:

⬅️ Leftmost Derivation (LMD) & LMDT​

  • Definition: The derivation process where at every step, the leftmost non-terminal is expanded first.
  • LMDT (Leftmost Derivation Tree): The graphical representation of an LMD.
  • Top-down parsers (e.g. LL(1) predictive parsers) construct derivations in Leftmost order.

➡️ Rightmost Derivation (RMD) & RMDT​

  • Definition: The derivation process where at every step, the rightmost non-terminal is expanded first.
  • Canonical Derivation: Rightmost derivation is also formally known as the canonical derivation.
  • RMDT (Rightmost Derivation Tree): The graphical representation of an RMD.
  • Bottom-up parsers (e.g. LR(0), SLR(1), LALR(1), CLR(1)) construct the reverse of a Rightmost Derivation (bottom-up reductions).

🌳 The Parse Tree & Yield Equivalence Theorem​

A Parse Tree (or Derivation Tree) is the graphical visualization of a derivation:

  • The root node is labeled with the grammar start symbol SS.
  • Each interior node is labeled with a non-terminal A∈VA \in V.
  • If an interior node AA has children X1,X2,…,XkX_1, X_2, \dots, X_k, then A→X1X2…XkA \to X_1 X_2 \dots X_k must be a valid production in PP.
  • The leaf nodes are labeled with terminals, non-terminals, or ϵ\epsilon.
  • Yield of the Tree: The string formed by concatenating all leaf nodes from left to right.

🌟 Fundamental Equivalence Theorem​

For any context-free grammar GG and any terminal string w∈L(G)w \in \mathcal{L}(G):

  1. Every distinct parse tree corresponds to exactly one unique Leftmost Derivation.
  2. Every distinct parse tree corresponds to exactly one unique Rightmost Derivation.
  3. Therefore: Number of Parse Trees=Number of LMDs=Number of RMDs\text{Number of Parse Trees} = \text{Number of LMDs} = \text{Number of RMDs}

If a string ww can be derived by two or more distinct parse trees (or equivalently, two or more distinct LMDs/RMDs), the grammar is Ambiguous.


🔄 Recursive Productions & Grammar Taxonomies​

A production is recursive if the non-terminal on the LHS also appears on the RHS:

ClassificationFormal StructureConcrete ExampleCompiler Significance
Left RecursiveA→Aα∣βA \to A\alpha \mid \betaE→E+T∣TE \to E + T \mid TCauses Top-Down (LL) parsers to loop infinitely; easily parsed by Bottom-Up (LR) parsers.
Right RecursiveA→αA∣βA \to \alpha A \mid \betaS→aS∣bS \to aS \mid bIdeal for Top-Down (LL) parsers; requires deep stack recursion in Bottom-Up parsers.
General RecursiveA→αAβA \to \alpha A \betaS→aSb∣abS \to aSb \mid abRecursion is neither strictly left nor right; enforces matched balanced delimiters.
Non-RecursiveNo production contains A⇒+…A…A \Rightarrow^+ \dots A \dotsS→aB,B→bS \to aB, B \to bGenerates only a finite number of strings.

Fundamental Theorem: If a Context-Free Grammar generates an infinite number of strings, it must contain at least one recursive production (or a cycle of mutually recursive productions).


🏭 Real-World Production Context: How Industry Builds This​

Production compilers like Clang/LLVM and Rustc build Abstract Syntax Trees directly during parsing rather than constructing physical parse trees:

In Clang, every AST node inherits from clang::Stmt or clang::Decl:

// Expression representation for a + b * c:
BinaryOperator '+'
|-- DeclRefExpr 'a'
`-- BinaryOperator '*'
|-- DeclRefExpr 'b'
`-- DeclRefExpr 'c'
  • Punctuation, parentheses, and intermediate non-terminals (E -> T -> F) are eliminated completely.
  • Memory consumption is reduced by over 85% compared to a raw parse tree, improving CPU L1/L2 cache locality during downstream semantic analysis.

📐 Numerical Applications & Worked Examples​

Example 1: Arithmetic Derivation and Precedence Trace​

Consider the standard unambiguous arithmetic expression grammar:

E→E+T∣TT→T×F∣FF→(E)∣id\begin{aligned} E &\to E + T \mid T \\ T &\to T \times F \mid F \\ F &\to ( E ) \mid \text{id} \end{aligned}

For the input string w=id+id×idw = \text{id} + \text{id} \times \text{id}:

  1. Construct the step-by-step Leftmost Derivation (LMD).
  2. Construct the step-by-step Rightmost Derivation (RMD).
  3. Verify that both derivations produce the exact same Parse Tree.
  4. Explain how this grammar enforces operator precedence (×\times over ++).

Mathematical Formulation & Step-by-Step Solution:

Step 1: Leftmost Derivation (LMD) At each step, expand the leftmost non-terminal:

E⇒lmE+T(using E→E+T)⇒lmT+T(using E→T)⇒lmF+T(using T→F)⇒lmid+T(using F→id)⇒lmid+T×F(using T→T×F)⇒lmid+F×F(using T→F)⇒lmid+id×F(using F→id)⇒lmid+id×id(using F→id)\begin{aligned} E &\Rightarrow_{\text{lm}} E + T && (\text{using } E \to E + T) \\ &\Rightarrow_{\text{lm}} T + T && (\text{using } E \to T) \\ &\Rightarrow_{\text{lm}} F + T && (\text{using } T \to F) \\ &\Rightarrow_{\text{lm}} \text{id} + T && (\text{using } F \to \text{id}) \\ &\Rightarrow_{\text{lm}} \text{id} + T \times F && (\text{using } T \to T \times F) \\ &\Rightarrow_{\text{lm}} \text{id} + F \times F && (\text{using } T \to F) \\ &\Rightarrow_{\text{lm}} \text{id} + \text{id} \times F && (\text{using } F \to \text{id}) \\ &\Rightarrow_{\text{lm}} \text{id} + \text{id} \times \text{id} && (\text{using } F \to \text{id}) \end{aligned}

Total steps = 8.

Step 2: Rightmost Derivation (RMD) At each step, expand the rightmost non-terminal:

E⇒rmE+T(using E→E+T)⇒rmE+T×F(using T→T×F)⇒rmE+T×id(using F→id)⇒rmE+F×id(using T→F)⇒rmE+id×id(using F→id)⇒rmT+id×id(using E→T)⇒rmF+id×id(using T→F)⇒rmid+id×id(using F→id)\begin{aligned} E &\Rightarrow_{\text{rm}} E + T && (\text{using } E \to E + T) \\ &\Rightarrow_{\text{rm}} E + T \times F && (\text{using } T \to T \times F) \\ &\Rightarrow_{\text{rm}} E + T \times \text{id} && (\text{using } F \to \text{id}) \\ &\Rightarrow_{\text{rm}} E + F \times \text{id} && (\text{using } T \to F) \\ &\Rightarrow_{\text{rm}} E + \text{id} \times \text{id} && (\text{using } F \to \text{id}) \\ &\Rightarrow_{\text{rm}} T + \text{id} \times \text{id} && (\text{using } E \to T) \\ &\Rightarrow_{\text{rm}} F + \text{id} \times \text{id} && (\text{using } T \to F) \\ &\Rightarrow_{\text{rm}} \text{id} + \text{id} \times \text{id} && (\text{using } F \to \text{id}) \end{aligned}

Total steps = 8.

Parse Tree Structural Levels: id + id × id

Hierarchical level-order decomposition proving operator precedence (multiplication binds deeper than addition)

Level 0 (Root)

Start Symbol: E

🌳

Root of the parse tree expanding via E → E + T.

Left Child: EOperator: +Right Child: T
↓Top-level addition operator (+)
Level 1 (Subtree)

Left Term: T | Right Subtree: T × F

🌿

Left E reduces to T; Right T expands via T → T × F enforcing higher precedence.

Left Term T → FRight Operator: ×Right Factor F
↓Deeper subtree forces multiplication (*) to evaluate first
Level 2 (Factors)

Factor Reductions: F → id

🍃

All factors reduce directly to identifier terminal tokens.

id (first)id (second)id (third)
↓Terminal frontier evaluation
Level 3 (Yield)

Sentence Yield: id + id × id

📜

Left-to-right concatenation of all leaf nodes matches target input string exactly.

Token 1: idToken 2: +Token 3: idToken 4: ×Token 5: id

Step 4: Precedence Enforcement Mechanics Notice that the multiplication node T×FT \times F is located deeper in the tree than the addition node E+TE + T. In any bottom-up post-order evaluation, the deeper subtree (T×FT \times F) must be reduced and computed first. Its result is subsequently added to EE. Therefore, placing an operator deeper in the grammar hierarchy automatically enforces higher operator precedence.


Example 2: Derivation Steps in Chomsky Normal Form (CNF)​

Let GG be a Context-Free Grammar where every production rule is in Chomsky Normal Form:

  • A→BCA \to B C (binary non-terminal branch)
  • A→aA \to a (terminal leaf)

If a terminal string ww has length n=∣w∣n = |w|, determine:

  1. The exact number of derivation steps required to derive ww.
  2. The exact total number of nodes (internal + leaf nodes) in the parse tree of ww.

Step-by-Step Analytical Solution:

Step 1: Derivation Steps

  • We start with 11 non-terminal (SS).
  • Each application of A→BCA \to B C consumes 1 non-terminal and produces 2 non-terminals, increasing the total count of non-terminals by +1+1.
  • To obtain a string with nn non-terminals from 11 non-terminal requires exactly: n−1 applications of A→BCn - 1 \text{ applications of } A \to B C
  • Each of the nn non-terminals must then be converted into a terminal character via A→aA \to a, which requires: n applications of A→an \text{ applications of } A \to a
  • Total derivation steps:
Total Steps=(n−1)+n=2n−1\text{Total Steps} = (n - 1) + n = 2n - 1

Step 2: Parse Tree Nodes

  • Leaf nodes: Exactly nn leaves (one for each terminal in ww).
  • Internal nodes: In a strictly binary tree with nn leaves, there are exactly n−1n - 1 internal nodes.
  • Total nodes:
Total Nodes=Internal+Leaves=(n−1)+n=2n−1\text{Total Nodes} = \text{Internal} + \text{Leaves} = (n - 1) + n = 2n - 1

🎯 Exam & Interview Pitfall Check​

Core Conceptual Questions

Question 1: "Does a string having multiple different derivations mean the grammar is ambiguous?"
Key Focus Points:

  • No: In any non-trivial unambiguous grammar, every string with more than one non-terminal has at least two distinct derivations: a Leftmost Derivation (LMD) and a Rightmost Derivation (RMD).
  • True Ambiguity Criterion: Ambiguity requires that a string has two or more distinct Leftmost Derivations, two or more distinct Rightmost Derivations, or two or more distinct Parse Trees.

Question 2: "What is the formal relationship between the Yield of a parse tree and the derived string?"
Key Focus Points:

  • Yield Definition: The yield of a parse tree is the string formed by reading its leaf nodes strictly from left to right.
  • Invariant: For any valid parse tree derived from start symbol SS, its yield must be an exact terminal sentence in the language L(G)\mathcal{L}(G).
Common Interview Traps: Architectural Trade-Offs

Trap 1: Is a sentence the same thing as a sentential form?
Answer: No. A sentential form is any intermediate string α∈(V∪Σ)∗\alpha \in (V \cup \Sigma)^* derived from SS (S⇒∗αS \Rightarrow^* \alpha), which may contain non-terminals. A sentence is a sentential form that contains strictly terminal symbols (w∈Σ∗w \in \Sigma^*). All sentences are sentential forms, but not all sentential forms are sentences.

Trap 2: Can Top-Down parsers construct Rightmost Derivations?
Answer: No. Top-down parsers (LL) construct derivations from the root down to the leaves in Leftmost order (LMD). Bottom-up parsers (LR) construct the reverse of a Rightmost Derivation (RMD) from leaves up to root.


💬

Discussion & Doubts