4.6.11 · D2Theory of Computation

Visual walkthrough — Equivalence of CFGs and PDAs

1,996 words9 min readBack to topic

Step 1 — What a stack actually is (from zero)

WHAT. We draw a stack as a vertical column. The bottom plate went on first; the top plate is where all the action happens.

WHY this object and not a list or array? Because a stack answers exactly one question — "what is the single most recent unfinished thing I owe?" — and forgets everything below it until that top is cleared. That "one unfinished thing at a time, deepest last" behaviour is precisely how nested things (boxes in boxes, brackets in brackets) close.

PICTURE. The left column shows a push; the right column shows a pop. Watch the top move.

Recall Why "top only"?

Why can a stack read only its top plate? ::: Because that top plate is the innermost unfinished job; you cannot finish an outer job until the inner one closes — same as brackets.


Step 2 — A derivation is already a stack (the key sighting)

WHAT. We expand and draw the nesting as brackets.

WHY. This is the whole theorem in embryo. The reason a machine with one stack can imitate a grammar is that the grammar's own recursion is a bracket structure, and brackets are what a stack tracks. Nothing deeper is going on than this matching of shapes.

PICTURE. Each expansion opens a new bracket pair a[ ]b; the deepest bracket is the one we resolve first — exactly the top of a stack.

  • = terminals (real output characters).
  • = "empty string", the base case where the innermost produces nothing.
  • The brace nesting = the stack depth at that moment.

Step 3 — Turning the grammar into a one-state PDA

WHAT. Two move-types, straight from the grammar:

WHY one state? The grammar has no "control state" — every scrap of progress lives in the sentential form (the half-finished string). We store that whole sentential form on the stack, so the machine needs no memory in its state at all. One state suffices.

WHY does expansion read ? Applying a grammar rule produces no input character; it only rearranges what we still owe. Reading a real symbol happens only in the second move, when a promised terminal meets the actual input.

PICTURE. Top of stack decides which move is even legal: a variable on top → only expansion; a terminal on top → only matching.


Step 4 — Run it on (the film strip)

WHAT. We trace the PDA move-by-move on the string . Stack top is drawn at the left.

WHY show every row? Because acceptance is a path, and we must witness that the guesses (which rule to expand) can be made so the stack empties exactly as the input ends.

PICTURE. Each frame = the stack after one move; the arrow labels which move fired.

Step Move (why) Unread input Stack (top-left)
0 start
1 expand
2 match
3 expand
4 match
5 expand
6 match
7 match (empty) → accept

Step 5 is the guess: nondeterminism tries here, and this guess is the one that works.


Step 5 — The invariant that proves it (one picture)

WHAT. Read the read-part and the stack-part as one string; that concatenation is always something can derive so far.

WHY it clinches Direction 1. When input is exhausted and the stack is empty, both sides say "" — the whole input was genuinely derived. Conversely any derivation gives an accepting run. So .

PICTURE. A dotted seam splits "already read" (left, teal) from "still on stack" (right, orange); glue them and you get the sentential form (plum) above.


Step 6 — The reverse direction: reading a run as brackets

WHAT. We first normalise the PDA so every move either pushes exactly one symbol or pops exactly one. Then a balanced run looks like a bracket string, and each variable expands like a bracket.

WHY this definition? A push that waits and is later popped is literally a matching bracket pair. A grammar variable expanding to "open · middle · close" is the same shape. Matching the shapes gives the grammar for free.

PICTURE. Stack height plotted over time (a "mountain profile"). = one full mountain returning to the baseline.


Step 7 — The two rules, and why they are ALL the cases

WHAT. Term-by-term on the match rule :

  • = the input read when the machine pushes symbol , moving .
  • = the input read when the machine pops that same , moving .
  • = whatever happened above while it sat on the stack — a balanced sub-run from to .

WHY exactly two working shapes? Look at the first symbol pushed in a balanced run. There are only two fates for it:

  1. It is popped only at the very end → one outer bracket wraps everything → match rule.
  2. It is popped strictly before the end → the stack touches baseline mid-run at some state → the run splits into two balanced halves → split rule.

No third possibility exists, so the rules generate exactly .

PICTURE. Two mountain profiles side by side: left = one big arch (match), right = two arches meeting the baseline (split).

For our example PDA (state pushes per ; pops per into ; pops per staying in ), the match rule gives and — literally again. The two constructions are inverse in spirit.


The one-picture summary

WHAT. One figure that stacks all four viewpoints of the SAME string : the parse tree, the bracket nesting, the PDA stack film, and the balanced mountain profile. Read any column — they are the same object.

Compare with Leftmost Derivations and Parse Trees and Chomsky Normal Form (the normal form that makes the balanced-run argument clean). The one-stack limit is what keeps us inside Closure Properties of CFLs and short of Turing Machines — two stacks would jump the fence.

Recall Feynman: tell it to a friend in plain words

A grammar is a recipe for nesting boxes: to make a box you may put a smaller box inside and then close the lid, and the innermost box must be finished before any outer lid closes. A stack machine is a kid holding a pile of plates: every time the recipe opens a box the kid puts a plate down; every time a real letter is matched the kid takes the matching plate off. Because you must always deal with the top plate first — the innermost box first — the pile of plates and the nested boxes rise and fall in perfect step. Reading the run forward, the plate you set down first is the plate you lift last: one opening bracket, one closing bracket, with a smaller balanced run sitting on top of it. That single fact — "first plate down is last plate up" — is why one stack equals grammar recursion, and why two stacks would be too much and turn the kid into a full computer.

Recall Active recall — cover the answers
  • What single shape do a derivation and a stack share? ::: nesting / matched brackets.
  • In CFG→PDA, when is input read? ::: only on the match move (a terminal on top meets the input); expansion is an -move.
  • What does "balanced run" mean for ? ::: same start and end stack height, never dipping below the start.
  • Why exactly two rule schemas in PDA→CFG? ::: the first pushed symbol is popped either at the very end (match) or earlier (split); no third case.
  • Why does the equivalence fail with two stacks? ::: two stacks simulate a Turing machine, escaping the context-free class.