Writing a CFG
Context: FIT2014_MOC · turning a language description into a grammar · the assessable counterpart to Finding Regular Expressions, one tier up Problem it solves: given a language, write production rules that generate exactly it.
Quick Revision
- 🎯 Trigger: a language with nesting or matching or a running count ➔ find an inductive definition (“a string is either , or … built from smaller strings”) and transcribe each case into a rule.
- ⚡ Key Constraint: the recursion must be structural — every rule should shrink toward the base case , and the nonterminals should capture the invariant that defines membership.
📐 The recipe
- Find an inductive definition of the language: a base case plus ways to build bigger members from smaller ones.
- One rule per case. The base case becomes (or a terminal); each recursive case becomes a rule whose right side contains nonterminal(s) for the smaller pieces.
- Introduce a nonterminal per “type” of string when membership depends on a running property (imbalance, parity, phase).
- Check the extremes — does the grammar produce and the shortest non-empty members? Does it avoid non-members?
🧱 Worked example — PARENTHESES (the Dyck language)
Language ➔ all strings of correctly matched parentheses: (non-members: , ).
Inductive definition ➔ a string of parentheses is one of:
- the empty string ;
- where is a string of parentheses;
- where are strings of parentheses.
Grammar (transcribe the three cases):
- Where does the matching go? ➔ any non-empty balanced string starts with ; its partner is either at the very end (rule ) or before the end (rule ) — exactly the two recursive cases.
✍️ Practice
Practice 1: A grammar for HALF-AND-HALF .
Reference solution
- Key move: add one on the left and one on the right per step — the matched pair keeps the counts equal and correctly ordered. This is the language the pumping lemma proved non-regular, yet a two-rule CFG generates it.
Practice 2: A grammar for PALINDROME over .
Reference solution
- Key move: wrap the same letter on both ends each step; the odd-length middle needs the single-letter cases and , the even-length core needs .
Practice 3: A grammar for balanced strings over two bracket types, round and square .
Reference solution
- Key move: the Dyck idea generalises — one “wrap” rule per bracket pair, plus concatenation. A round open must be closed by a round close, so and stay separate.
⚠️ Common Mistakes
- 💡 Concatenation needs its own rule ➔ (or similar) is what lets members sit side by side; without it is underivable.
- 💡 Don’t over-generate ➔ a sloppy grammar like would produce ; the wrap rule is what enforces matching.
- 💡 Track the invariant with nonterminals ➔ for counting languages (EQUAL), one nonterminal per imbalance class; for phase languages, one per phase.
- 💡 Always allow the base case ➔ forgetting silently excludes the empty word (and can break recursion that bottoms out at ).
🧠 Active Recall
Derive the CFG for balanced parentheses from an inductive definition.
Answer
- Short answer: a balanced string is either empty (), or a smaller balanced string wrapped in a pair (), or two balanced strings concatenated (). Each clause of the definition becomes one production.
- Why: Matching partner is at or before the end ➔ every non-empty balanced string begins with whose partner is either final (giving ) or internal (giving ); the two recursive rules cover exactly these, and both shrink toward .
Why can a CFG generate when no regular expression can?
Answer
- Short answer: the rule adds a matched … pair around the recursive call, so the two counts are kept equal by construction for arbitrarily large .
- Why: Recursion = unbounded matched memory ➔ each expansion remembers one outstanding obligation through the grammar’s nesting, whereas a finite automaton has only finitely many states and cannot count without bound (the pumping-lemma obstruction).