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.

Key takeaways
  • 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.
The core insight

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 G=(V,Σ,R,S)G = (V, \Sigma, R, S) of variables, terminals, rules, and a start symbol, generating strings via leftmost or arbitrary derivations from SS. In general, a rule's right-hand side (its body) can be any string over V∪ΣV \cup \Sigma, 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 nn was built." A grammar is in Chomsky Normal Form if every rule has one of these three shapes:

A→BC(B,C∈V∖{S})A \to BC \qquad (B, C \in V \setminus \{S\})
A→a(a∈Σ)A \to a \qquad (a \in \Sigma)
S→εS \to \varepsilon

with the extra constraint that if S→εS \to \varepsilon is present, SS 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 A→εA \to \varepsilon for non-start AA, no productions like A→BA \to B (a "unit" or "chain" rule), and no productions like A→aBcA \to aBc or A→BCDA \to BCD with three or more symbols. The central theorem is an equivalence result: for every context-free language LL, there is a CNF grammar G′G' with L(G′)=LL(G') = L. 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 ε\varepsilon 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 S0S_0 with rule S0→SS_0 \to S, where SS 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 S0→εS_0 \to \varepsilon without corrupting other derivations.

Phase 1 — Eliminate ε-productions (nullable variables). A variable AA is nullable if A⇒∗εA \Rightarrow^* \varepsilon. Compute the full set of nullable variables by fixed-point iteration, then remove every ε\varepsilon-rule (except possibly S0→εS_0 \to \varepsilon) 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 S0S_0).

Phase 2 — Eliminate unit productions. A unit rule has the form A→BA \to B for variables A,BA, B. Compute, for each variable AA, the set of variables reachable via a chain of unit rules. Remove all unit rules, and for each AA that can reach BB via units, add every non-unit rule of BB directly as a rule for AA.

Phase 3 — Break long and mixed bodies. Any rule with a terminal mixed into a body of length ≥2\ge 2, e.g. A→aBA \to aB, gets the terminal replaced by a fresh variable: A→UaBA \to U_a B, Ua→aU_a \to a. Any rule with three or more symbols, e.g. A→X1X2⋯XkA \to X_1 X_2 \cdots X_k, is broken into a chain of fresh variables: A→X1Y1A \to X_1 Y_1, Y1→X2Y2Y_1 \to X_2 Y_2, …, Yk−2→Xk−1XkY_{k-2} \to X_{k-1} X_k. ``` 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. A→BCA \to BC with CC nullable becomes A→BA \to B), so unit-elimination must come after. Eliminating unit productions can create bodies mixing terminals and variables of length ≥2\ge 2 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.

Figure
The four-phase pipeline transforming an arbitrary CFG into CNF
Phase 0 New start S₀ S₀ → S Phase 1 Remove ε-rules expand nullable subsets Phase 2 Remove unit rules A → B chains inlined Phase 3 Binarize bodies len ≥ 3 → chain of pairs Before: A → aBcD (mixed, length 4) A → a B c D ⇓ binarize ⇓ A → Uₐ Y1 Y1 → B Y2 Y2 → U_c D Uₐ → a U_c → c Every surviving rule now has body length exactly 2 (variables) or 1 (terminal).

Complexity & correctness

Correctness. We must show L(G′)=L(G)L(G') = L(G) (with the empty string handled by the S0→εS_0 \to \varepsilon 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: S0⇒S⇒∗wS_0 \Rightarrow S \Rightarrow^* w iff S⇒∗wS \Rightarrow^* w, and since S0S_0 is fresh, it introduces no new derivations elsewhere. Phase 1 (ε-removal). Fix a derivation A⇒∗wA \Rightarrow^* w using the old rules. Whenever a nullable variable in some production body is used to derive ε\varepsilon, 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 ε\varepsilon, 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 ε\varepsilon-derivation for each deleted position (using the original ε-productions), reproducing a valid old derivation of the same string. Thus L(G1)=L(G)∖{ε}L(G_1) = L(G) \setminus \{\varepsilon\} if ε∉L(G)\varepsilon \notin L(G)-handling, or with S0→εS_0 \to \varepsilon retained precisely to keep ε\varepsilon in the language when S⇒∗εS \Rightarrow^* \varepsilon originally. Phase 2 (unit-removal). If A⇒∗B⇒∗A \Rightarrow^* B \Rightarrow^* (via a chain of unit rules) ⇒\Rightarrow body ⇒∗w\Rightarrow^* w, then since unit-reachability is computed as the transitive closure of the unit-rule relation, AA directly gets a copy of BB's non-unit rule producing that same body, and hence the same derivation of ww collapses to one fewer step but produces the identical string. Conversely, every added rule A→bodyA \to \text{body} exists only because some genuine unit chain A→⋯→BA \to \cdots \to B existed and B→bodyB \to \text{body} 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 UaU_a with Ua→aU_a \to a and chaining fresh YiY_i variables is a pure notational refactor: the derivation A⇒X1X2⋯Xk⇒∗wA \Rightarrow X_1 X_2 \cdots X_k \Rightarrow^* w corresponds exactly to A⇒X1Y1⇒X1X2Y2⇒⋯⇒X1⋯Xk⇒∗wA \Rightarrow X_1 Y_1 \Rightarrow X_1 X_2 Y_2 \Rightarrow \cdots \Rightarrow X_1 \cdots X_k \Rightarrow^* w, a longer but string-preserving derivation, and this correspondence is clearly reversible (contract the chain of YiY_i'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 L(G′)=L(G)L(G') = L(G), 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 ∣V∣|V|), so each terminates in at most ∣V∣|V| rounds. Binarization processes each rule once, producing finitely many fresh variables. The whole algorithm halts.

Size and time complexity. Let n=∣R∣n = |R| (number of original rules) and let mm be the maximum body length. Phase 1's nullable-subset expansion is the potential blowup point: a rule with kk symbols, all nullable, generates up to 2k−12^k - 1 new rule variants (all subsets except deleting everything, unless the head is S0S_0). 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 O(n⋅2m)O(n \cdot 2^m) and hence polynomial in nn for fixed mm; in the worst case with unbounded body length, this step is exponential in mm. Phase 2 adds at most O(∣V∣2)O(|V|^2) 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-kk body with O(k)O(k) new rules and O(k)O(k) 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 O(n2)O(n^2) 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.

S→ASA∣aB,A→B∣S,B→b∣εS \to ASA \mid aB, \qquad A \to B \mid S, \qquad B \to b \mid \varepsilon

with start symbol SS.

StepActionResulting rules
Phase 0Add S0→SS_0 \to SS0→SS_0 \to S; plus all original rules
Nullable setB→εB \to \varepsilon, so BB nullable. A→BA \to B makes AA nullable. SS: no rule becomes fully nullable (ASAASA needs SS nullable too — check: is SS nullable? S→ASAS \to ASA needs A,SA,S both nullable — circular, SS not proven nullable this round; S→aBS \to aB has terminal, never nullable). Fixed point: {A,B}\{A, B\}
Phase 1: rewrite S→ASAS \to ASADelete nullable occurrences of AA (appears twice) in all subsets except deleting both and leaving nothing already covered since SS remains: subsets of positions {1,3}\{1,3\} (the two AA's)S→ASA∣SA∣AS∣SS \to ASA \mid SA \mid AS \mid S
Phase 1: rewrite S→aBS \to aBBB nullable, delete it optionallyS→aB∣aS \to aB \mid a
Phase 1: rewrite A→BA \to BBB nullable but deleting it leaves empty body; AA is not S0S_0, so drop this empty option — but wait, A→BA \to B with BB deleted gives A→εA \to \varepsilon, only kept if head is S0S_0. Since head is A≠S0A \ne S_0, this option is discarded (it will be handled by making AA itself nullable, tracked separately)A→BA \to B retained as unit rule for now
Phase 1: rewrite A→SA \to SNo nullable symbols to deleteA→SA \to S
Phase 1: drop B→εB \to \varepsilon—(removed)
Phase 1: keep B→bB \to bNo nullable symbolsB→bB \to b
Since S⇒∗εS \Rightarrow^* \varepsilon? Check: S→SS \to S (from the subset rewrite) is a self-loop, not helpful; is there any way S⇒∗εS \Rightarrow^* \varepsilon? S→aS \to a, S→aBS\to aB — both produce nonempty. S→ASA/SA/AS/SS \to ASA/SA/AS/S all still require some terminal eventually since B→bB\to b is the only way to terminate and A→B→bA \to B \to b or A→SA \to S. Actually trace: could SS derive ε\varepsilon if AA derives ε\varepsilon and the whole thing collapses? We already excluded the all-deleted case for S→ASAS \to ASA (that would need deleting the middle SS too, but SS was never proven nullable, so that full-deletion case was never a valid subset to begin with — only AA positions were nullable, not SS). So SS is not nullable; no S0→εS_0 \to \varepsilon needed.

After Phase 1, the rule set (before duplicate-removal cleanup) is:

S0→S,S→ASA∣SA∣AS∣S∣aB∣a,A→B∣S,B→bS_0 \to S,\quad S \to ASA \mid SA \mid AS \mid S \mid aB \mid a, \quad A \to B \mid S,\quad B \to b

Phase 2 (remove unit rules). Unit rules present: S0→SS_0 \to S, S→SS \to S (a self-loop unit rule — trivially removable, contributes nothing new), A→BA \to B, A→SA \to S. Unit-reachability: S0→SS_0 \to S; A→BA \to B and A→SA \to S, and since SS reaches nothing further via units (its only unit-target is itself), AA's reachable set is {B,S}\{B, S\}, and SS's (and hence S0S_0's) reachable set is just itself (the self-loop S→SS \to S adds nothing). Inline non-unit rules of reachable targets:

  • S0S_0 reaches SS: copy SS's non-unit rules (ASA,SA,AS,aB,aASA, SA, AS, aB, a) to S0S_0.
  • AA reaches BB: copy B→bB \to b to AA.
  • AA reaches SS: copy SS's non-unit rules to AA.

Result after Phase 2:

S0→ASA∣SA∣AS∣aB∣aS_0 \to ASA \mid SA \mid AS \mid aB \mid a
S→ASA∣SA∣AS∣aB∣aS \to ASA \mid SA \mid AS \mid aB \mid a
A→b∣ASA∣SA∣AS∣aB∣aA \to b \mid ASA \mid SA \mid AS \mid aB \mid a
B→bB \to b

Phase 3 (binarize). Rules of length 1 (S0→aS_0 \to a, A→aA \to a, A→bA \to b, B→bB \to b) are already CNF; keep them. Rules of length 2 with a terminal (S0→aBS_0 \to aB, S→aBS \to aB, A→aBA \to aB) need the terminal replaced: introduce Ua→aU_a \to a, giving S0→UaBS_0 \to U_a B, S→UaBS \to U_a B, A→UaBA \to U_a B. Rules of length 2 with two variables (S0→SAS_0 \to SA, S0→ASS_0 \to AS, S→SAS \to SA, S→ASS \to AS, A→SAA \to SA, A→ASA \to AS) are already CNF. Rules of length 3 (S0→ASAS_0 \to ASA, S→ASAS \to ASA, A→ASAA \to ASA) need one binarization step each: introduce fresh Y→SAY \to SA shared across all three (since the suffix SASA recurs), giving S0→AYS_0 \to AY, S→AYS \to AY, A→AYA \to AY, with Y→SAY \to SA.

Final CNF grammar:

S0→AY∣SA∣AS∣UaB∣aS_0 \to AY \mid SA \mid AS \mid U_aB \mid a
S→AY∣SA∣AS∣UaB∣aS \to AY \mid SA \mid AS \mid U_aB \mid a
A→AY∣SA∣AS∣UaB∣a∣bA \to AY \mid SA \mid AS \mid U_aB \mid a \mid b
B→b,Y→SA,Ua→aB \to b, \qquad Y \to SA, \qquad U_a \to a

Every rule is now `X → YZ` or `X → terminal`, exactly as required. Spot-check: the original string abab should still be derivable. Original grammar: S→aB→a bS \to aB \to a\,b ✓. New grammar: S0→UaB→a bS_0 \to U_aB \to a\,b ✓ — same string, confirming the transformation preserved at least this instance of the language.

Common pitfalls & traps

PitfallWhy it happensFix
Running unit-removal before ε-removalε-removal can create new unit rules (e.g. A→BCA \to BC with CC nullable becomes A→BA \to B), which get missed if unit-removal already ranAlways eliminate ε before units
Deleting all symbols of a nullable body and keeping the resulting empty ruleSilently reintroduces A→εA \to \varepsilon for a non-start variable, breaking CNFDiscard the all-nullable-deleted subset unless the head is S0S_0
Forgetting the fresh-start-symbol stepIf the original start symbol appears on some right-hand side, later allowing S→εS \to \varepsilon can make that symbol vanish in contexts where it shouldn'tAlways add S0→SS_0 \to S first, and never let S0S_0 appear on a right-hand side
Missing indirect unit chains (A→BA \to B, B→CB \to C, so AA should also inherit CC's rules)Only removing direct unit rules without computing the transitive closureCompute 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 bodySkipping 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 uniqueDifferent valid orderings of subset choices or fresh-variable naming give different but equivalent CNF grammarsCNF grammars are not unique; only the generated language is guaranteed to match

Pioneers & history

Origins · 1 minNoam Chomsky and how this was discovered
NC
Noam Chomsky
1928–present · Linguist and cognitive scientist whose formalization of generative grammars founded the mathematical study of language and directly gave rise to the Chomsky hierarchy of formal languages

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
History
1956
— Chomsky's "Three Models for the Description of Language" introduces the hierarchy of grammar types.
1959
— Chomsky formalizes context-free grammars and normal-form transformations in "On Certain Formal Properties of Grammars."
1960
s — Cocke, Younger, and Kasami independently develop the CYK parsing algorithm, which requires CNF input.
1970
s — CNF becomes a standard textbook tool for proving closure properties and the pumping lemma for context-free languages.
Present — CNF-style binarization remains foundational in statistical and neural parsers built on CFG or CFG-like backbones.

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 GG, the four-phase conversion algorithm produces a CNF grammar G′G' with L(G′)=L(G)L(G') = L(G). 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 ε∈L(G)\varepsilon \in L(G), the CNF grammar retains a single special rule S0→εS_0 \to \varepsilon 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 O(∣V∣2)O(|V|^2) rules, and binarization adds O(k)O(k) rules per original rule of length kk. The one genuine danger zone is ε-elimination, which in the worst case can create up to 2k−12^k - 1 new rule variants from a single rule with kk 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 S0S_0 may have the rule S0→εS_0 \to \varepsilon, and this is permitted specifically because Phase 0 guarantees S0S_0 never appears in any other rule's body. This isolation means the ε\varepsilon-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 A→aαA \to a\alpha for a terminal aa 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.

Before this

Where this leads