4.6.10 · D3Theory of Computation

Worked examples — Pushdown automata (PDA) — configuration, acceptance by empty stack - final state

3,726 words17 min readBack to topic

This page is a complete tour of every situation a PDA problem can throw at you. Before we work anything, we lay out a matrix of case-classes. Then each worked example is tagged with the cell it fills, so by the end you have seen every corner — accept, reject, empty stack vs final state, degenerate empty input, "stack never empties" traps, nondeterministic guessing, and an exam twist.

If any symbol below feels unfamiliar, go back to the parent topic first — everything here reuses its 7-tuple , its configuration triple , and its yields relation .


The scenario matrix

Every PDA exercise lives in one of these cells. The examples that follow cover all ten.

# Case class What makes it tricky Filled by
C1 Accept by empty stack, matched input must pop too Ex 1
C2 Accept by final state, junk left on stack stack ignored Ex 2
C3 Reject — input runs out with symbols still on stack no accepting snapshot Ex 3
C4 Reject — stack empties too early / no move available dead configuration Ex 3
C5 Degenerate: empty input does count? Ex 4
C6 Nondeterminism essential: guess a midpoint one guess-path accepts Ex 5
C7 Two counters at once () push/pop in bulk Ex 6
C8 Conversion empty-stack final-state (marker ) avoid early emptying Ex 7
C9 Real-world word problem: balanced brackets practical parsing Ex 8
C10 Exam twist: same string, opposite verdict under the two modes modes really differ Ex 9

Ex 1 — C1 · accepted by empty stack

The rules again (top of stack written leftmost):

Steps (one -move per line, each labelled with the rule it uses):

  1. Why this step? rule 1: first hits , push on top.
  2. Why? rule 2: second pushes another (count ).
  3. Why? rule 2 again: third pushes another (count ).
  4. Why? rule 3: first pops one (count ).
  5. Why? rule 3: second pops one (count ).
  6. Why? rule 3: third pops the last (count ).
  7. Why? rule 4: input empty, only remains, pop it on -input. Stack empty = accept.

Ex 2 — C2 · Final-state accept with junk on the stack

Steps (one -move per line):

  1. Why? rule 1: first pushes an .
  2. Why? rule 2: second pushes another .
  3. Why? rule 3: first pops one .
  4. Why? rule 3: second pops the last .
  5. Why this step? rule : move to on -input without popping. Input exhausted and accept.

Ex 3 — C3 & C4 · Two ways to reject

Case C3 — (surplus on stack).

  1. Why? rule 1: first pushes an .
  2. Why? rule 2: second pushes another .
  3. Why? rule 3: the single pops one . Now input is empty but stack is , not .
  4. Could rule 4 fire? No — it needs on top, but is on top. No -move applies. Stuck with a non-empty stack ⇒ reject. (Cell C3.)

Case C4 — (pop past the marker).

  1. Why? rule 1: one pushes one .
  2. Why? rule 3: first pops the lone . Stack is now just .
  3. Second with on top: is there a rule ? No. The machine is in a dead configuration with input left. Reject. (Cell C4.)

Ex 4 — C5 · The degenerate empty input

On the Ex 1 machine (which we'll show actually targets ).

  1. Start: — input already empty. Why look here? The empty string means we never read a letter.
  2. Only -rule available is rule 4: , giving empty stack!
  3. So this exact machine accepts . Since , the Ex 1 machine really recognises (), not ().

A formally sound machine for (). The bug is that rule 4 can fire from the very start, before any was ever pushed. To forbid that, we use two states and so the marker-pop is reachable only after at least one full pop happened. The state itself records "have we popped an yet?":

  • — first : push (still in ).
  • — each further : push (still in ).
  • is not how works (it only reads the single top symbol), so we split the last pop by looking at what is underneath: use for a pop that still leaves an or below, and detect the final pop by the state we move into:
    • — nondeterministically, this may be the last one: branch to .
  • — pop the marker only in , i.e. only on a branch that has already popped at least one .
  • There is no rule , so on input the machine sits in with on top and no move is rejected.

Why this is sound. State means "no has been popped as the final one yet"; state means "the branch guessed the last is popped." The only marker-pop lives in , and is entered only by a -pop. Therefore a marker-pop can never happen unless at least one popped an — which forces . The correct branch (guess the last correctly) reaches and accepts; wrong guesses die harmlessly.

For (): the original Ex 1 machine is exactly right, since it accepts directly via rule 4.


Ex 5 — C6 · Nondeterminism is essential ()

Rules (one state , top of stack leftmost). Note maps to a set:

  • (P) Push phase: for and any top — put the read symbol on top.
  • (G) Midpoint guess: for — an -move that consumes no input and leaves the stack unchanged, but commits to "stop pushing, start matching." (This is the nondeterministic choice, offered alongside (P).)
  • (M) Match-pop phase: for — pop iff the input symbol equals the top.
  • (E) Finish: — pop the marker → empty stack.

The accepting branch on (one -move per line, each labelled with the rule and how the configuration changes):

  1. Why? rule (P): push the first symbol ; stack .
  2. Why? rule (P): push the second symbol ; stack . (This is the push; input shrank , stack grew.)
  3. Why this step? the midpoint-guess rule (G) fires: consumes no input and leaves the stack unchanged, so state, input and stack look identical to step 2's result. Its only effect is that we now commit to matching. (This is the -guess; nothing visible changes — that is exactly what a silent commit looks like.)
  4. Why? rule (M): input equals top → pop; input , stack .
  5. Why? rule (M): input equals top → pop; both halves now matched.
  6. Why? rule (E): pop empty stack, accept.

Why other branches don't spoil it. A branch that fires (G) too early (say after 1 symbol) will find the input top and get stuck — that branch just dies. Acceptance needs only one surviving branch, and the correct-midpoint branch survives.


Ex 6 — C7 · Two counters at once:

Rules:

  1. — first pushes two 's.
  2. — each further pushes two more 's (replace top by = net ).
  3. — each pops one .
  4. — pop marker when 's exhausted.

Run on (one -move per line):

  1. Why? rule 1: one deposits two 's (the debt of two 's).
  2. Why? rule 3: first pops one .
  3. Why? rule 3: second pops the last .
  4. Why? rule 4: pop accept.

Sanity on a bad string . After the two 's are popped by the first two 's we reach ; the third needs which is undefined → dead → reject (correct, since ).


Ex 7 — C8 · Conversion empty-stack final-state with marker

Construction of . New start state , new bottom guard , final state , :

  • (S) Set-up: — push 's bottom above the guard, hand control to 's state .
  • (1c) copy of rule 1: .
  • (2c) copy of rule 2: .
  • (3c) copy of rule 3: .
  • (4c) copy of rule 4 (pop the simulated bottom ): .
  • (A) Accept: — when is exposed, jump to the final state.

Run on (one -move per line, each labelled with the rule it fires):

  1. Why? rule (S): set up the simulated bottom above the guard , enter 's state .
  2. Why? rule (1c): first pushes an .
  3. Why? rule (2c): second pushes another .
  4. Why? rule (3c): first pops one .
  5. Why? rule (3c): second pops the last .
  6. Why this step? rule (4c) — the rule-4 copy — pops the simulated bottom on -input. Now only the guard remains: this is the moment "would have emptied its stack."
  7. Why? rule (A): exposed → jump to . Input empty and accept.

Why the marker matters (Mistake D defused). Without , if ever emptied its stack mid-input, would be stuck (no top symbol to read). guarantees there's always a symbol on top, so never dies from an empty stack; it only accepts by the deliberate jump. Note 's stack holds symbol () at every configuration above.


Ex 8 — C9 · Real-world: balanced brackets

Rules (map ( push, ) pop; let (, )):

  1. and — every ( pushes an .
  2. — every ) pops one (matches an open bracket).
  3. — clear marker when all matched → empty stack.

Run on (()) (one -move per line):

  1. Why? rule 1: first ( pushes an (depth ).
  2. Why? rule 1: second ( pushes an (depth ).
  3. Why? rule 2: first ) pops one (depth ).
  4. Why? rule 2: second ) pops the last (depth ).
  5. Why? rule 3: pop accept: balanced.

Run on ())( (one -move per line):

  1. Why? rule 1: first ( pushes an .
  2. Why? rule 2: first ) pops the ; stack back to .
  3. Next symbol ) needs undefined (a close bracket with nothing open) → dead → reject: unbalanced.

Ex 9 — C10 · Exam twist: same string, opposite verdicts

Trace on (one -move per line):

  1. Why? rule 1: the pushes an .
  2. Why? rule 2: the reads top , moves to , leaves the stack as (peek, no pop).

Now judge under each mode from the final snapshot .

  • Final state: condition is with . Here , input . Accept.
  • Empty stack: condition needs . Here , and no rule can pop them — dead. Reject.

So but . Same machine, same input, opposite results because the two acceptance conventions ask different questions. (Recall Mistake C from the parent: modes are equal in power across all machines — you can always convert — but on any fixed machine they can differ.)


Recall Self-test (reveal after guessing)

Ex 1 verdict on ::: Accept (empty stack, height returns to floor). Ex 2 stack contents when accepting by final state ::: (non-empty — stack ignored). Ex 3 reason is rejected ::: Input ends with still on top; rule 4 needs on top → stuck. Ex 4 is in ? ::: No — that needs ; . Ex 6 verdict on for ::: Reject (). Ex 9 punchline ::: Same machine can accept a string by final state yet reject it by empty stack.


Flashcards

Why does fail on the empty-stack PDA?
One remains on top when input ends; rule 4 needs on top, so no move → non-empty stack → reject.
In Ex 2 what is on the stack at the accepting moment?
— final-state mode ignores stack contents.
How many 's does one push in the machine?
Two (each owes two 's).
Why must the PDA be nondeterministic?
It must guess the unmarked midpoint; a DPDA can't detect it.
What does the fresh marker prevent during empty-stack→final-state conversion?
The simulated machine emptying its stack early and getting stuck; keeps a symbol on top always.
Can one fixed PDA accept a string by final state but reject it by empty stack?
Yes (Ex 9) — the two modes ask different questions though they define the same language class.