Worked examples — Chomsky Normal Form (CNF) — conversion
Before we start, one reminder of the vocabulary every example uses. A terminal is an actual output letter (lowercase, like ). A variable (or non-terminal, uppercase like ) is a placeholder that gets rewritten. A production is a rewrite rule: "wherever you see , you may replace it with ." means the empty string — nothing at all. These come from Context-Free Grammars; we build every step from them.
The scenario matrix
| # | Cell (case class) | What makes it tricky | Hit by |
|---|---|---|---|
| C1 | Already clean, only TERM+BIN needed | no ε, no unit — most students over-work it | Ex 1 |
| C2 | Multiple nullable positions in one rule | must add every subset, not one rule | Ex 2 |
| C3 | Chained nullables (A nullable because B is) | fixed-point iteration, order matters | Ex 3 |
| C4 | Unit-rule chain 3 deep () | transitive closure of renames | Ex 4 |
| C5 | Start symbol on a right-hand side + ε in language | why START step exists; survives | Ex 5 |
| C6 | Long RHS of pure terminals () | TERM then BIN cascade, many helpers | Ex 6 |
| C7 | Useless / degenerate: rule that only self-loops | vanishes, empty language edge | Ex 7 |
| C8 | Real-world word problem | translate an English spec into a grammar, then CNF | Ex 8 |
| C9 | Exam twist: everything at once + count the rules | combine C2, C4, C6 and predict final size | Ex 9 |
Every worked example below is tagged with the cell it fills. Together they cover the whole table.
Ex 1 — the "already clean" trap · cell C1
Forecast: DEL and UNIT — do they do anything here? How many new variables does TERM create? Guess the final rule count before reading on.
- START. Add . Why this step? CNF permits the start symbol to go to ; keeping the start off every right-hand side means later steps can never tangle it. Here never appears on a right side anyway, but we follow the pipeline honestly.
- DEL. Nullable set: no rule has , so . Nothing to patch. Why this step? Without a nullable variable there is no illegal to remove — DEL is a no-op. Recognising this saves you from imaginary work.
- UNIT. Unit rules are (one variable to one variable). We have . Its only source of non-unit bodies is : those are . Replace: ; drop . Why this step? A rename produces no letter and no branching, so we substitute the actual bodies it eventually reaches.
- TERM. Terminal is mixed with a variable in . Add , rewrite . Standalone is already legal. Why this step? CNF forbids mixing a terminal and a variable in the same body.
- BIN. Longest body now is (length 2). Nothing to chop.
Final CNF:
Verify: Derive : . Every step used or . Language is , unchanged. Rule count = 5. ✓
Ex 2 — several nullables in one rule · cell C2
Forecast: Which of are nullable? The rule will spawn how many patched versions? (Careful — it is not three.)
- START. Add . Why this step? Standard hygiene for the start symbol — keep it off every right-hand side so ε handling never tangles.
- DEL — find nullables. so ; so ; has no -path so . Thus . Why this step? We must know which positions can disappear before patching.
- DEL — patch . Nullable positions are (the and the ). For every subset of those to drop:
- drop nothing:
- drop :
- drop :
- drop both: Also delete and (neither is ). Why this step? Each nullable symbol either stays or vanishes independently, so we cover all combinations. We never delete down to empty here because always remains.
- UNIT. and are the unit rules. Replace by 's bodies ; but is itself a unit — resolve it to 's non-unit body . So (and ) gain and lose . Why this step? Renames get flattened into the real bodies they eventually reach.
- TERM. Standalone are already legal. No mixed rule exists. Why this step? TERM only fires when a terminal shares a body with another symbol; here every terminal already sits alone.
- BIN. has length 3: add , rewrite . All others length . Why this step? Only length- bodies violate the binary shape; is the sole offender.
Final CNF:
Verify: The original language of is = the 4 strings . Our final grammar can produce exactly these four terminal strings and no others. Count of patched versions of the long rule = 4. ✓
Ex 3 — chained nullables (fixed point) · cell C3
Forecast: Is nullable even though never has an rule directly? Trace the fixed-point iteration.
The figure below is a round-by-round film of the nullable set growing. Read it left to right: each boxed panel is one iteration, the arrow means "carry what you learned into the next round," and the coloured text names which rule let a new variable join . It makes visible the one idea students miss — that enters only after is already inside, i.e. nullability spreads outward like a stain.

- DEL — fixed-point iteration. Follow the panels in the figure: we grow in rounds.
- Round 0 (leftmost panel): .
- Round 1 (blue panel): ⟹ add . .
- Round 2 (pink panel): and (the whole RHS is nullable) ⟹ add . .
- Round 3 (yellow panel): ; is nullable? No. So not added. stops growing. Final . Why this step? Nullability is transitive: a variable is nullable if it can reach through other nullable variables, not only by a direct . The iteration keeps adding until nothing new appears — that "stops changing" point (the last panel) is the fixed point.
- DEL — patch. In , position 1 () is nullable, position 2 () is not. Subsets of : keep → ; drop → . So . Delete . Why this step? can vanish, so must be able to skip it.
- UNIT. After DEL the unit rules are and (from the new ). now has no productions (its only rule was , deleted) — so contributes nothing and becomes useless; drop it. resolves to 's body : add . Why this step? A rename to a variable with an empty body dies; a rename to a real body is flattened.
- TERM / BIN. is two variables (legal), and are single terminals (legal). Nothing to do. Why this step? No terminal is mixed into a longer body and no body exceeds length 2, so both passes are no-ops.
Final CNF: Since has no productions, can never terminate and is itself pruned, leaving .
Verify: Original language: , so ; also with nonterminating gives nothing. Language . Final grammar gives . ✓
Ex 4 — a unit chain three deep · cell C4
Forecast: What is the set of unit pairs reachable from ? Which non-unit bodies does inherit?
- START. Add . Why this step? Keep the start symbol off every right-hand side so the later ε/unit passes never have to special-case it.
- DEL. No anywhere, . No-op. Why this step? With no nullable variable there is no illegal to remove.
- UNIT — build the transitive closure. A unit pair means using only single-variable renames. Chain: . So the pairs are plus and hence by transitivity. Why this step? A rename can hop through several variables; we must follow the chain all the way to the non-unit bodies at the end (here only 's bodies ).
- UNIT — substitute. The only non-unit bodies live at : . Every variable that reaches inherits them: Drop all unit rules. Why this step? Once a rename's endpoint is found, we replace the rename by the actual productive bodies so no empty-branching rule survives.
- TERM. is fine. No mixed terminal. Why this step? TERM only fires on a terminal sharing a body with another symbol; the lone is already legal.
- BIN. is length 2 — already binary. Why this step? Only length- bodies need chopping, and none exist here.
Final CNF:
Verify: Original language: generates any nonempty binary tree of 's = ; renames down to so same language. Final grammar: / gives exactly . Unit pairs from : , size 5. ✓
Ex 5 — start on RHS + ε in language · cell C5
Forecast: appears on its own right side and is in the language. Does the final grammar keep an -rule? On which symbol?
- START. Add . Now is the only start, and still occurs in . Why this step? This is exactly the case START exists for. If we deleted 's -rule while sits on a right-hand side, we would lose the ability to place at the top of the parse. The fresh absorbs the "may be empty" role.
- DEL. ⟹ . Then with both positions nullable ⟹ already in . And with nullable ⟹ . So .
- Patch : nullable positions ; subsets give . We keep and but must not create the empty RHS. So .
- Patch : drop-or-keep gives and . Because is the start and , we keep .
- Delete non-start . Why this step? CNF allows as the single legal empty rule; that is how " is in the language" is recorded.
- UNIT. Unit rules now: and . The self-loop is trivial — remove it (it adds nothing). 's non-unit bodies: . So inherits : . Drop unit rules. keeps . Why this step? A variable renaming itself is pure noise; a rename to a real body is flattened.
- TERM / BIN. is binary and variable-only; legal. is the permitted start ε-rule. Why this step? No terminal to isolate and no over-long body, so both passes are no-ops.
Final CNF:
Verify: Original language: generates only (every must eventually vanish, no terminal exists). So . Final grammar: gives ; needs to produce a terminal, but never emits a terminal, so it is a dead branch → . Matches. The one legal ε-rule lives on . ✓
Ex 6 — long run of pure terminals · cell C6
Forecast: How many terminal-helper variables ? How many BIN helpers? Total rules?
The figure below shows the whole TERM-then-BIN cascade at a glance. The top row displays the offending length-4 body after terminals are isolated; the three stacked boxes below are the binary rules BIN carves out, and the downward arrows trace how each fresh helper (, then ) swallows "the rest of the chain." Watching the arrows makes the count helpers obvious rather than memorised.

- START / DEL / UNIT. No start-on-RHS, no ε, no unit rules — all no-ops. Why this step? None of these three passes has anything to fire on: the grammar has one rule with no variables, no , and no rename.
- TERM. Every terminal in a body of length must be replaced by a variable. Add and rewrite: Why this step? CNF forbids a raw terminal inside a multi-symbol body; four terminals ⟹ four helpers (top row of the figure).
- BIN. Now has length 4. Chop left-to-right (the stacked boxes in the figure), each helper holding "the rest of the chain": Why this step? Every internal parse node must have exactly two children; a length- body needs helpers. Here ⟹ 2 helpers ().
Final CNF:
Verify: Terminal helpers = 4, BIN helpers = , plus the original -chain rule count. Language , unchanged: derive . ✓
Ex 7 — degenerate self-loop / empty language · cell C7
Forecast: What terminal strings can produce? What does CNF conversion leave you with?
- START. ; . Why this step? Keep the start symbol off every right-hand side, following the pipeline honestly even on a degenerate grammar.
- DEL. No ε ⟹ . Why this step? No nullable variable exists, so there is no illegal to remove.
- UNIT. is a rename; 's non-unit body is , so . stays. No self-unit ( is length 2, not a unit). Why this step? Flatten the rename into the actual body it reaches.
- TERM / BIN. already binary and variable-only. Why this step? No terminal to isolate and no body longer than 2, so both passes do nothing.
Final "CNF": .
But look closer: neither nor can ever reach a terminal — no production ever emits a letter. So the language is empty, . Why this matters: CNF conversion does not invent terminals. A grammar with no terminal-producing rule stays terminal-free, and its language is empty. A clean-up pass (removing non-generating variables) would delete both rules, leaving a grammar with no productions at all — the honest CNF for the empty language is simply an empty rule set. This is the degenerate edge case CNF still handles correctly: it never fabricates a string that the original grammar could not produce.
Verify: Every derivation from only ever produces longer strings of 's and never terminates in a terminal string. So . ✓
Ex 8 — real-world word problem · cell C8
Forecast: "One or more letters" means recursion. Will TERM produce three helpers or fewer? Predict.
- Grammar from the spec. ", then copies of , then ": = "one or more 's." wraps it in brackets. Why this step? repetition is exactly right-recursion ; the outer rule bolts on the brackets.
- START / DEL / UNIT. No start-on-RHS, no ε, no unit rules — no-ops. Why this step? never appears on a right side, no rule derives , and no rule is a bare variable-to-variable rename, so all three passes are empty.
- TERM. Terminals inside long bodies: . Add . Rewrite: Why this step? (length 1) stays raw; but the inside must become . So 3 helpers.
- BIN. has length 3: . Everything else length . Why this step? The length-3 body is the only one violating the binary shape; one helper fixes it.
Final CNF:
Verify: Sanity-check <xx> = : . Length-4 string, binary tree has nodes. Helper count = 3 (TERM) + 1 (BIN) = 4. ✓
Ex 9 — exam twist: everything at once, count the rules · cell C9
Forecast: is nullable; is a self-loop; mixes a terminal. Predict how many rules survive on the right of it all.
- START. . Why this step? Keep the start symbol off every right-hand side before the ε and unit passes run.
- DEL. ⟹ . No other ε. .
- : position 1 nullable ⟹ add . So .
- : position 2 () nullable ⟹ add . So (delete ).
- : no nullable. stays for now. Why this step? Only can vanish, so only -positions branch; the illegal is then removed.
- UNIT. Unit rules: , , (self-loop, drop it).
- 's non-unit bodies: — but only, with no base case, so is non-generating (like Ex 7). Prune .
- With pruned, and die. survives.
- ⟹ . Why this step? A variable with no path to a terminal string is useless; removing it kills every rule that depends on it, and renames to survivors are flattened.
- TERM. In , terminal is mixed: , . Standalone , , stay. Why this step? CNF forbids the terminal sharing the body with variable .
- BIN. All bodies length . Nothing to chop. Why this step? No surviving body exceeds length 2, so the binary shape already holds.
Final CNF: (Note is now unreachable from too, so a reachability clean-up leaves just . We list the full set to show the mechanics.)
Verify: Original language: with no base ⟹ generates nothing ⟹ dead; only works ⟹ . Final grammar reachable from : ⟹ . Matches. ✓
Recall Self-test
Nullable means a variable can derive what? ::: The empty string (possibly through other nullable variables). In DEL, a rule with nullable positions spawns how many patched versions (before removing the empty one)? ::: subsets, minus the all-dropped empty RHS when it occurs. Why does START exist? ::: So the start symbol never sits on a right-hand side, letting be the single legal ε-rule (see Ex 5). A length- body needs how many BIN helper variables? ::: . A variable that can never reach a terminal string is called? ::: Non-generating (useless) — prune it (see Ex 7, Ex 9).
See also: CYK Algorithm (why we wanted binary trees), Pumping Lemma for CFLs, Greibach Normal Form (a different normal form), Pushdown Automata, and the parent Chomsky Normal Form (CNF) — conversion.