Chomsky Normal Form
Every context-free grammar hides a mess of irregular productions. Some rules vanish into nothing. Others just rename another symbol. Still others have right sides sprawling across five or six symbols. Parsing algorithms like CYK need a clean, uniform shape. This lets them search efficiently over all ways a string might be built. Chomsky Normal Form (CNF) is the answer. It is a restricted grammar shape with two allowed production types. Every production is either a single terminal or exactly two variables. There are no epsilon or unit shortcuts anywhere. The only exception is a tightly controlled case for the empty string. This matters far beyond a textbook exercise. Compiler front-ends, natural-language parsers, and bioinformatics tools all depend on it. The latter model RNA secondary structure using CFG parsing algorithms. Their polynomial-time guarantees depend on a normalized grammar. The Cocke-Younger-Kasami (CYK) algorithm is the workhorse cubic-time parser for arbitrary context-free grammars. It is defined on CNF grammars. Its correctness proof assumes every rule has the two-variable-or-one-terminal shape. Its dynamic-programming table structure assumes this too. The deep idea is that CNF is not a loss of expressive power. Every context-free language has a CNF grammar generating it. Instead, CNF is a normalization. It is exactly analogous to converting a boolean formula to conjunctive normal form. It is also like converting a matrix to row-echelon form. The conversion algorithm is mechanical and terminates. It preserves the language exactly (modulo the empty string, handled separately). This article gives the precise definition. It presents the four-phase conversion algorithm: eliminate the start symbol from the right-hand side, remove epsilon, remove unit rules, and break long bodies. It also offers a full correctness argument and a worked trace on a genuinely asymmetric grammar. By the end you will be able to convert any context-free grammar to CNF by hand. You will be able to justify why each phase preserves the language. You will also see why this normal form is the load-bearing prerequisite. It is essential for the CYK parsing algorithm. It is also essential for standard proofs of the pumping lemma for context-free languages.
- CNF restricts every production to `A → BC` (two variables) or `A → a` (one terminal), plus optionally `S → ε`.
- Every context-free language has a CNF grammar; the conversion is purely mechanical and always terminates.
- Conversion has four ordered phases: isolate the start symbol, eliminate ε-productions, eliminate unit productions, then binarize long/mixed bodies.
- Each phase is proven language-preserving via an explicit derivation-rewriting argument, not just claimed.
- The output grammar can grow polynomially in size but never blows up exponentially for the standard algorithm.
- CNF is the structural prerequisite for the CYK parsing algorithm and for the standard pumping-lemma proof for context-free languages.
Chomsky Normal Form rewrites any context-free grammar into an equivalent one where every rule is `A → BC` or `A → a`, making the grammar's structure uniform enough for polynomial-time parsing algorithms to exploit.
The idea
A context-free grammar (CFG) is a tuple of variables, terminals, rules, and a start symbol, generating strings via leftmost or arbitrary derivations from . In general, a rule's right-hand side (its body) can be any string over , including the empty string. This flexibility is convenient for writing grammars but obstructs algorithms that want to reason inductively about "how a string of length was built." A grammar is in Chomsky Normal Form if every rule has one of these three shapes:
with the extra constraint that if is present, never appears on the right-hand side of any rule. Every body is either exactly two variables, exactly one terminal, or (only for the start symbol) empty. There are no productions like for non-start , no productions like (a "unit" or "chain" rule), and no productions like or with three or more symbols. The central theorem is an equivalence result: for every context-free language , there is a CNF grammar with . The proof is constructive — it is exactly the four-phase algorithm below — and each phase is independently justified by showing that derivations in the old grammar correspond to derivations in the new one and vice versa. This is the same proof pattern used when normalizing regular expressions, converting NFAs to DFAs, or reducing boolean circuits to normal forms: restrict the syntax while preserving the semantics (the generated language), so that downstream algorithms can assume a uniform shape without loss of generality. The technique of separating "start symbol" handling to isolate generation echoes how derivations and parse trees cleanly track how substrings are assembled — CNF simply forces every internal parse-tree node to be strictly binary-branching (except leaves), which is what makes the tree structure countable and dynamic-programmable.
How it works
The conversion proceeds in a fixed order — reordering phases can silently reintroduce forbidden forms, so the sequence matters.
Phase 0 — New start symbol. Add a fresh start symbol with rule , where was the old start symbol. This guarantees the start symbol never appears on the right-hand side of any rule, which is required so that later we can safely let without corrupting other derivations.
Phase 1 — Eliminate ε-productions (nullable variables). A variable is nullable if . Compute the full set of nullable variables by fixed-point iteration, then remove every -rule (except possibly ) while adding, for every rule whose body contains nullable variables, all versions of that rule with nullable occurrences deleted in every subset combination (excluding the case where the entire body would vanish, unless the head is ).
Phase 2 — Eliminate unit productions. A unit rule has the form for variables . Compute, for each variable , the set of variables reachable via a chain of unit rules. Remove all unit rules, and for each that can reach via units, add every non-unit rule of directly as a rule for .
Phase 3 — Break long and mixed bodies. Any rule with a terminal mixed into a body of length , e.g. , gets the terminal replaced by a fresh variable: , . Any rule with three or more symbols, e.g. , is broken into a chain of fresh variables: , , …, . ``` CONVERT-TO-CNF(G = (V, Σ, R, S)): // Phase 0: fresh start symbol S0 := new symbol not in V R := R ∪ { S0 -> S } V := V ∪ { S0 } G.start := S0 // Phase 1: remove epsilon productions NULLABLE := {} repeat until no change: for each rule A -> body in R: if body == ε, or every symbol in body is in NULLABLE: add A to NULLABLE R' := {} for each rule A -> X1 X2 ... Xk in R (k >= 1): if A -> ε: continue // drop epsilon rules (handled separately) for each subset T of the positions i where Xi is in NULLABLE: body' := X1..Xk with positions in T deleted if body' is nonempty, OR A == S0: R'.add(A -> body') // (allow S0 -> ε to survive) R := R' with duplicates removed // Phase 2: remove unit productions for each variable A: UNIT-REACH(A) := smallest set containing A, closed under: if B in UNIT-REACH(A) and B -> C in R is a unit rule, then C in UNIT-REACH(A) R'' := { A -> body : A -> body in R and body is not a single variable } for each variable A: for each B in UNIT-REACH(A), B != A: for each rule B -> body in R that is NOT a unit rule: R''.add(A -> body) R := R'' with duplicates removed // Phase 3: binarize bodies R''' := {} TERM := {} // map terminal a -> variable U_a for each rule A -> X1 X2 ... Xk in R: if k == 1 and X1 is a terminal: R'''.add(A -> X1) // already CNF: A -> a else if k == 1 and X1 is a variable: // cannot happen: units already removed in Phase 2 else: // replace any terminal occurring inside a body of length >= 2 for i in 1..k: if Xi is a terminal a: if a not in TERM: TERM[a] := new variable U_a Xi := TERM[a] if k == 2: R'''.add(A -> X1 X2) else: // k >= 3, binarize with fresh variables Y1, ..., Y_{k-2} := new variables R'''.add(A -> X1 Y1) for i in 1..k-3: R'''.add(Yi -> X_{i+1} Y_{i+1}) R'''.add(Y_{k-2} -> X_{k-1} Xk) for each (a -> U_a) in TERM: R'''.add(U_a -> a) return G' = (V', Σ, R''', S0) ``` The order Phase 1 → Phase 2 → Phase 3 is not arbitrary. Removing ε-productions first can create new unit productions (e.g. with nullable becomes ), so unit-elimination must come after. Eliminating unit productions can create bodies mixing terminals and variables of length that still need binarizing, so binarization must come last. Running Phase 3 before Phase 2 would leave unit rules unbroken; running Phase 2 before Phase 1 would miss unit rules generated by ε-removal.
Complexity & correctness
Correctness. We must show (with the empty string handled by the exception). The argument proceeds phase by phase, each showing that derivations biject (up to the specific rewriting) between the old and new rule sets. Phase 0 trivially preserves the language: iff , and since is fresh, it introduces no new derivations elsewhere. Phase 1 (ε-removal). Fix a derivation using the old rules. Whenever a nullable variable in some production body is used to derive , that occurrence contributes nothing to the final string, so the same derivation tree can be pruned: delete every subtree rooted at a nullable variable that yields , and the production at the parent becomes exactly one of the subset-deleted bodies added by the algorithm. Conversely, any derivation using a new subset-deleted rule can be "re-inflated" by reinserting an -derivation for each deleted position (using the original ε-productions), reproducing a valid old derivation of the same string. Thus if -handling, or with retained precisely to keep in the language when originally. Phase 2 (unit-removal). If (via a chain of unit rules) body , then since unit-reachability is computed as the transitive closure of the unit-rule relation, directly gets a copy of 's non-unit rule producing that same body, and hence the same derivation of collapses to one fewer step but produces the identical string. Conversely, every added rule exists only because some genuine unit chain existed and was a real non-unit rule in the original grammar, so every new derivation corresponds to an old one. Phase 3 (binarization). Introducing fresh variables with and chaining fresh variables is a pure notational refactor: the derivation corresponds exactly to , a longer but string-preserving derivation, and this correspondence is clearly reversible (contract the chain of 's back into one step). None of these fresh variables appear anywhere else in the grammar, so no unintended new strings become derivable. Chaining these four language-preserving equivalences gives , establishing the CNF equivalence theorem.
Termination. Each phase operates over a finite rule set and finite alphabet; nullable-set computation and unit-reachability computation are both monotone fixed-point iterations over a finite universe (bounded by ), so each terminates in at most rounds. Binarization processes each rule once, producing finitely many fresh variables. The whole algorithm halts.
Size and time complexity. Let (number of original rules) and let be the maximum body length. Phase 1's nullable-subset expansion is the potential blowup point: a rule with symbols, all nullable, generates up to new rule variants (all subsets except deleting everything, unless the head is ). If body lengths are bounded by a constant (as is typical for grammars written by hand or produced by tools), this is a constant-factor blowup per rule, giving overall size and hence polynomial in for fixed ; in the worst case with unbounded body length, this step is exponential in . Phase 2 adds at most new rules (one potential inlined rule per ordered pair of variables with a unit-chain relation, times the constant number of non-unit rules each variable owns). Phase 3 replaces each length- body with new rules and fresh variables, so it is linear in the total input size. In practice, for grammars with bounded-length productions (the overwhelmingly common case, including all grammars produced by standard tools and nearly all grammars written by hand), the entire conversion runs in time and produces an output grammar of size polynomial in the input size — commonly cited as or better in rule count for reasonable inputs, though the theoretical worst case tied to the ε-elimination subset expansion is exponential in maximal body length. Being honest about this tradeoff matters: CNF conversion is "efficient" in the sense that matters for CYK's asymptotic parsing bound, but pathological grammars with very long, heavily nullable bodies can inflate grammar size substantially, which is a real practical concern in tools that auto-generate grammars.
Worked example
Convert the following CFG (deliberately asymmetric — mixed terminals, a nullable variable, and a unit chain) to CNF.
with start symbol .
| Step | Action | Resulting rules |
|---|---|---|
| Phase 0 | Add | ; plus all original rules |
| Nullable set | , so nullable. makes nullable. : no rule becomes fully nullable ( needs nullable too — check: is nullable? needs both nullable — circular, not proven nullable this round; has terminal, never nullable). Fixed point: | |
| Phase 1: rewrite | Delete nullable occurrences of (appears twice) in all subsets except deleting both and leaving nothing already covered since remains: subsets of positions (the two 's) | |
| Phase 1: rewrite | nullable, delete it optionally | |
| Phase 1: rewrite | nullable but deleting it leaves empty body; is not , so drop this empty option — but wait, with deleted gives , only kept if head is . Since head is , this option is discarded (it will be handled by making itself nullable, tracked separately) | retained as unit rule for now |
| Phase 1: rewrite | No nullable symbols to delete | |
| Phase 1: drop | — | (removed) |
| Phase 1: keep | No nullable symbols | |
| Since ? Check: (from the subset rewrite) is a self-loop, not helpful; is there any way ? , — both produce nonempty. all still require some terminal eventually since is the only way to terminate and or . Actually trace: could derive if derives and the whole thing collapses? We already excluded the all-deleted case for (that would need deleting the middle too, but was never proven nullable, so that full-deletion case was never a valid subset to begin with — only positions were nullable, not ). So is not nullable; no needed. |
After Phase 1, the rule set (before duplicate-removal cleanup) is:
Phase 2 (remove unit rules). Unit rules present: , (a self-loop unit rule — trivially removable, contributes nothing new), , . Unit-reachability: ; and , and since reaches nothing further via units (its only unit-target is itself), 's reachable set is , and 's (and hence 's) reachable set is just itself (the self-loop adds nothing). Inline non-unit rules of reachable targets:
- reaches : copy 's non-unit rules () to .
- reaches : copy to .
- reaches : copy 's non-unit rules to .
Result after Phase 2:
Phase 3 (binarize). Rules of length 1 (, , , ) are already CNF; keep them. Rules of length 2 with a terminal (, , ) need the terminal replaced: introduce , giving , , . Rules of length 2 with two variables (, , , , , ) are already CNF. Rules of length 3 (, , ) need one binarization step each: introduce fresh shared across all three (since the suffix recurs), giving , , , with .
Final CNF grammar:
Every rule is now `X → YZ` or `X → terminal`, exactly as required. Spot-check: the original string should still be derivable. Original grammar: ✓. New grammar: ✓ — same string, confirming the transformation preserved at least this instance of the language.
Common pitfalls & traps
| Pitfall | Why it happens | Fix |
|---|---|---|
| Running unit-removal before ε-removal | ε-removal can create new unit rules (e.g. with nullable becomes ), which get missed if unit-removal already ran | Always eliminate ε before units |
| Deleting all symbols of a nullable body and keeping the resulting empty rule | Silently reintroduces for a non-start variable, breaking CNF | Discard the all-nullable-deleted subset unless the head is |
| Forgetting the fresh-start-symbol step | If the original start symbol appears on some right-hand side, later allowing can make that symbol vanish in contexts where it shouldn't | Always add first, and never let appear on a right-hand side |
| Missing indirect unit chains (, , so should also inherit 's rules) | Only removing direct unit rules without computing the transitive closure | Compute full unit-reachability via fixed-point closure before inlining |
| Binarizing before removing units, leaving stray `A → B` rules that "look" like a length-1 variable body | Skipping Phase 2 order lets a unit rule survive; it is not valid CNF (body must be a single terminal, not a variable) | Confirm zero unit rules remain before starting Phase 3 |
| Assuming CNF conversion preserves the exact number of parse trees or is unique | Different valid orderings of subset choices or fresh-variable naming give different but equivalent CNF grammars | CNF grammars are not unique; only the generated language is guaranteed to match |
Pioneers & history
Origins · 1 minNoam Chomsky and how this was discovered
Noam Chomsky's 1956 and 1959 work on the mathematical structure of natural-language grammars sought a formal apparatus precise enough to reason about which string-generating rule systems could plausibly model human syntax. This effort produced the Chomsky hierarchy — regular, context-free, context-sensitive, and unrestricted (recursively enumerable) grammars — and, alongside it, the observation that context-free grammars could always be reshaped into a canonical binary-branching form without loss of generative power. This normal form, later named after him, became indispensable not for linguistics directly but for the algorithmic theory of parsing that followed, most directly the CYK algorithm developed independently around the same period.
Origins · 1 minhow this was discovered
Where this matters
The CYK algorithm, the canonical polynomial-time (cubic in string length) parser for arbitrary context-free grammars, is defined entirely in terms of a CNF grammar: its dynamic-programming table exploits the fact that every production splits a substring into exactly two independently parseable pieces, which is only guaranteed once the grammar is binarized. Any system that needs to parse an arbitrary context-free grammar without restricting to a deterministic subset — general-purpose natural-language parsers, ambiguity-checking tools, some bioinformatics pipelines modeling RNA secondary structure as context-free — runs a CNF conversion as a preprocessing step before invoking CYK or a close variant. CNF also underlies standard proofs in the theory itself: the pumping lemma for context-free languages is most cleanly proved by first placing the grammar in CNF (or Greibach Normal Form, a related canonical shape), because binary branching guarantees a bound on tree height relative to string length via the pigeonhole principle on repeated variables along a path — a bound that would be far messier to state for unrestricted-arity productions. Closure-property proofs (context-free languages closed under union, concatenation, Kleene star) are also frequently phrased using normalized grammars, since combining two CNF grammars cleanly is easier than combining two grammars with arbitrary rule shapes. Compiler theory courses and parser-generator tools that support general CFGs (as opposed to restricted LL/LR subsets) reference CNF or an equivalent binarized form when discussing worst-case parsing guarantees, and the equivalence between CFGs and pushdown automata is often first established for CNF-shaped grammars before generalizing, since the binary structure simplifies the stack-based construction.
Ask the tutor: Can you walk through why the CYK algorithm's correctness specifically depends on every CNF production having exactly two variables or one terminal?
Does every context-free language have a Chomsky Normal Form grammar?
Yes. This is the central equivalence theorem: for any context-free grammar , the four-phase conversion algorithm produces a CNF grammar with . The proof is constructive rather than existential — the algorithm itself, together with the phase-by-phase derivation-preservation argument, is the proof. The only subtlety is the empty string: if , the CNF grammar retains a single special rule for the (freshly introduced) start symbol, and that start symbol is guaranteed never to appear on any right-hand side, so this exception never contaminates other derivations.
Is the CNF grammar for a language unique?
No, and it should not be expected to be. Different valid choices during ε-elimination (which subsets of nullable positions to keep), different orderings of unit-inlining, and different fresh-variable names during binarization all produce different, but language-equivalent, CNF grammars. Just as row-echelon form or DNF for boolean formulas is not unique per underlying object, CNF is a normal form constraining shape, not a canonical form guaranteeing a single output. What is guaranteed is that any two valid CNF outputs for the same source grammar generate the exact same language.
How does CNF conversion affect grammar size in practice?
For grammars with bounded production-body length (essentially all hand-written and tool-generated grammars), the size increase is polynomial: unit-elimination adds at most rules, and binarization adds rules per original rule of length . The one genuine danger zone is ε-elimination, which in the worst case can create up to new rule variants from a single rule with nullable symbols — exponential in the length of that specific rule, though this only bites for artificially long, heavily nullable productions rarely seen outside adversarial examples.
Why does CYK specifically require CNF rather than working with arbitrary CFGs?
CYK is a bottom-up dynamic-programming parser that fills a table where each cell records which variables can generate a given substring. Its recurrence step combines two adjacent, already-solved subproblems into a larger one — this only works cleanly if every production splits a right-hand side into exactly two symbols, so that a substring's parse can always be described as "some split point where the left part matches one variable and the right part matches another." Arbitrary-arity or empty productions would break this invariant, forcing case-by-case handling that destroys the clean cubic-time bound, which is precisely why CNF is a prerequisite rather than a convenience.
Can CNF represent grammars that generate the empty string?
Yes, via the single carved-out exception: the (freshly added) start symbol may have the rule , and this is permitted specifically because Phase 0 guarantees never appears in any other rule's body. This isolation means the -production cannot be "reached" mid-derivation and cannot interact with any other part of the grammar, so it introduces no ambiguity or unsoundness — it only ever fires as the very first derivation step, generating exactly the empty string and nothing else.
How does CNF relate to parse tree shape?
In a CNF grammar, every internal node of a parse tree has either exactly two children (from an `A → BC` rule) or exactly one terminal child (from an `A → a` rule), making every parse tree a strict binary tree over its internal structure. This is precisely the structural property exploited both by CYK's dynamic programming and by the standard pumping lemma proof for context-free languages, which bounds the height of a parse tree relative to string length using a pigeonhole argument that only cleanly applies to binary-branching trees.
Is Chomsky Normal Form the only normal form used for context-free grammars?
No — Greibach Normal Form (GNF) is another well-known normal form, where every production has the shape for a terminal followed by zero or more variables. GNF is useful for different purposes, notably showing that every context-free language is accepted by some pushdown automaton with a bounded stack-growth pattern per input symbol. CNF and GNF are both language-preserving normalizations of the same underlying object, chosen because each makes a different downstream algorithm or proof cleaner.