Copyright (C) 2015, H. Conrad Cunningham

Acknowledgements: MS student Eli Allen assisted in preparation of these notes. These lecture notes are for use with Chapter 7 of the textbook: Peter Linz. Introduction to Formal Languages and Automata, Fifth Edition, Jones and Bartlett Learning, 2012. The terminology and notation used in these notes are similar to those used in the Linz textbook. This document uses several figures from the Linz textbook.

Advisory: The HTML version of this document requires use of a browser that supports the display of MathML. A good choice as of December 2015 seems to be a recent version of Firefox from Mozilla.

Introduction

Finite automata cannot recognize all context-free languages.

To recognize language {anbn:n0}\{ a^{n}b^{n} : n \geq 0 \}, an automaton must do more than just verify that all aa's precede all bb's; it must count an unbounded number of symbols. This cannot be done with the finite memory of a dfa.

To recognize language {wwR:wΣ*}\{ ww^{R}: w \in \Sigma^{*} \}, an automaton must do more than just count; it must remember a sequence of symbols and compare it to another sequence in reverse order.

Thus, to recognize context-free languages, an automaton needs unbounded memory. The second example above suggests using a stack as the "memory".

Hence, the class of machines we examine in this chapter are called pushdown automata.

In this chapter, we examine the connection between context-free languages and pushdown automata.

Unlike the situation with finite automata, deterministic and nondeterministic pushdown automata differ in the languages they accept.

7.1 Nondeterministic Pushdown Automata

7.1.1 Schematic Drawing

Linz Figure 7.1 illustrates a pushdown automaton.

On each move, the control unit reads a symbol from the input file. Based on the input symbol and symbol on the top of the stack, the control unit changes the content of the stack and enters a new state.

Linz Fig. 7.1: Pushdown Automaton

Linz Fig. 7.1: Pushdown Automaton

7.1.2 Definition of a Pushdown Automaton

Linz Definition 7.1 (Nondeterministic Pushdown Accepter): A nondeterministic pushdown accepter (npda) is defined by the tuple

M=(Q,Σ,Γ,δ,q0,z,F)M = (Q, \Sigma, \Gamma, \delta, q_{0}, z, F),

where

QQ is a finite set of internal states of the control unit,
Σ\Sigma is the input alphabet,
Γ\Gamma is a finite set of symbols called the stack alphabet,
δ:Q×(Σ{λ})×Γ\delta: Q \times (\Sigma \cup \{\lambda\}) \times \Gamma \rightarrow finite subsets of Q×Γ*Q \times \Gamma^{*} is the transition function,
q0Qq_{0} \in Q is the initial state of the control unit,
zΓz \in \Gamma is the stack start symbol,
FQF \subseteq Q is the set of final states.

Note that the input and stack alphabets may differ and that start stack symbol zz must be an element of Γ.\Gamma.

Consider the transition function δ:Q×(Σ{λ})×Γ\delta: Q \times (\Sigma \cup \{\lambda\}) \times \Gamma \rightarrow finite subsets of Q×Γ*Q \times \Gamma^{*}.

The machine is nondeterministic, but there are only a finite number of possible results for each step.

7.1.3 Linz Example 7.1

Suppose the set of transition rules of an npda contains

δ(q1,a,b)={(q2,cd),(q3,λ)}\delta(q_{1}, a, b) = \{(q_{2}, cd), (q_{3}, \lambda)\}.

A possible change in the state of the automaton from q1q_{1} to q2q_{2} is shown in following diagram.

This transition function can be drawn as a transition graph as shown below. The triple marking the edges represent the input symbol, the symbol at the top of the stack, and the string pushed back on the stack. Here we use "/" to separate the elements of the triple on the edges; the book uses commas for this purpose.

7.1.4 Linz Example 7.2

Consider an npda (Q,Σ,Γ,δ,q0,z,F)(Q,\Sigma,\Gamma,\delta,q_{0},z,F) where

Q={q0,q1,q2,q3}Q = \{q_{0}, q_{1}, q_{2}, q_{3}\}
Σ={a,b}\Sigma = \{a, b\}
Γ={0,1}\Gamma = \{0, 1\}
z=0z = 0
F={q3}F = \{q_{3}\}

with the initial state q0q_{0} and the transition function defined as follows:

  1. δ(q0,a,0)={(q1,10),(q3,λ)}\delta(q_{0}, a, 0) = \{(q_{1}, 10), (q_{3},\lambda)\}
  2. δ(q0,λ,0)={(q3,λ)}\delta(q_{0}, \lambda, 0) = \{(q_{3}, \lambda)\}
  3. δ(q1,a,1)={(q1,11)}\delta(q_{1}, a, 1) = \{(q_{1}, 11)\}
  4. δ(q1,b,1)={(q2,λ)}\delta(q_{1}, b, 1) = \{(q_{2}, \lambda)\}
  5. δ(q2,b,1)={(q2,λ)}\delta(q_{2}, b, 1) = \{(q_{2}, \lambda)\}
  6. δ(q2,λ,0)={(q3,λ)}\delta(q_{2}, \lambda, 0) = \{(q_{3}, \lambda)\}.

There are no transitions defined for final state q3q_{3} or in the cases

(q0,b,0)(q_{0}, b, 0), (q2,a,1)(q_{2}, a, 1), (q0,a,1)(q_{0}, a, 1), (q0,b,1)(q_{0}, b, 1), (q1,a,0)(q_{1}, a, 0), and (q1,b,0)(q_{1}, b, 0).

These are dead configurations of the npda. In these cases, δ\delta maps the arguments to the empty set.

The machine executes as follows.

  1. The first transition rule is nondeterministic, with two choices for input symbol aa and stack top 0.0.
    1. The machine can push 11 on the stack and transition to state q1q_{1}. (This is the only choice that will allow the machine to accept additional input.)
    2. The machine can pop the start symbol 00 and transition to final state q3q_{3}. (This is the only choice that will allow the machine to accept a single aa.)
  2. For stack top zz, the machine can also transition from the initial state q0q_{0} to final state q3q_{3} without consuming any input. (This is only choice that will allow the machine to accept an empty string.) Note that rule 2 overlaps with rule 1, giving additional nondeterminism.
  3. While the machine reads aa's, it pushes a 11 on the stack and stays in state q1q_{1}.
  4. When the machine reads a bb (with stack top 11), it pops the 11 from the stack and transitions to state q2q_{2}.
  5. While the machine reads bb's (with stack top 11), it pops the 11 from the stack and stays in state q2q_{2}.
  6. When the machine encounters the stack top 00, it pops the stack and transitions to final state q3q_{3}.

Acceptance or rejection?

The machine accepts:

Other strings will always end in dead configurations. For example:

Thus, it is not difficult to see that L={anbn:n0}{a}L = \{a^{n}b^{n}: n \geq 0\} \cup \{a\}.

Linz Figure 7.2 shows a transition graph for this npda. The triples marking the edges represent the input symbol, the symbol at the top of the stack, and the string pushed back on the stack.

Linz Fig. 7.2: Transition Graph for Example 7.2

Linz Fig. 7.2: Transition Graph for Example 7.2

7.1.5 Instantaneous Descriptions of Pushdown Automata

Transition graphs are useful for describing pushdown automata, but they are not useful in formal reasoning about them. For that, we use a concise notation for describing configurations of pushdown automata with tuples.

The triple (q,w,u)(q, w, u) where

qq is the control unit state
ww is the unread input string
uu is the stack as string, beginning with the top symbol

is called an instantaneous description of a pushdown automaton.

We introduce the symbol \vdash to denote a move from one instantaneous description to another such that

(q1,aw,bx)(q2,w,yx)(q_{1}, aw, bx) \vdash (q_{2}, w, yx)

is possible if and only if

(q2,y)δ(q1,a,b)(q_{2},y) \in \delta(q_{1}, a, b).

We also introduce the notation *\vdash^{*} to denote an arbitrary number of steps of the machine.

7.1.6 Language Accepted by an NPDA

Linz Definition 7.2 (Language Accepted by a Pushdown Automaton): Let M=(Q,Σ,Γ,δ,q0,z,F)M = (Q, \Sigma, \Gamma, \delta, q_{0}, z, F) be a nondeterministic pushdown automaton. The language accepted by MM is the set

L(M)={wΣ*:(q0,w,z)M*(p,λ,u),pF,uΓ*}L(M) = \{w \in \Sigma^{*}: (q_{0}, w, z) \vdash^{*}_{M} (p, \lambda, u), p \in F, u \in \Gamma^{*}\}.

In words, the language accepted by MM is the set of all strings that can put MM into a final state at the end of the string. The stack content uu is irrelevant to this definition of acceptance.

7.1.7 Linz Example 7.4

Construct an npda for the language

L={w{a,b}*:na(w)=nb(w)}L = \{w \in \{a, b\}^{*}: n_{a}(w) = n_{b}(w)\}.

We must count aa's and bb's, but their relative order is not important.

The basic idea is:

But, what if nb>nan_{b} > n_{a} at some point?

We must allow a "negative" count. So we modify the above solution as follows:

So the solution is an npda.

M=({q0,qf},{a,b},{0,1,z},δ,q0,z,{qf})M = (\{q_{0}, q_{f}\}, \{a, b\}, \{0, 1, z\}, \delta, q_{0}, z, \{q_{f}\}), with δ\delta given as

  1. δ(q0,λ,z)={(qf,z)}\delta(q_{0}, \lambda, z) = \{(q_{f}, z)\}
  2. δ(q0,a,z)={(q0,0z)}\delta(q_{0}, a, z) = \{(q_{0}, 0z)\}
  3. δ(q0,b,z)={(q0,1z)}\delta(q_{0}, b, z) = \{(q_{0}, 1z)\}
  4. δ(q0,a,0)={(q0,00)}\delta(q_{0}, a, 0) = \{(q_{0}, 00)\}
  5. δ(q0,b,0)={(q0,λ)}\delta(q_{0}, b, 0) = \{(q_{0}, \lambda)\}
  6. δ(q0,a,1)={(q0,λ)}\delta(q_{0}, a, 1) = \{(q_{0}, \lambda)\}
  7. δ(q0,b,1)={(q0,11)}\delta(q_{0}, b, 1) = \{(q_{0}, 11)\}.

Linz Figure 7.3 shows a transition graph for this npda.

Linz Fig. 7.3: Transition Graph for Example 7.4

Linz Fig. 7.3: Transition Graph for Example 7.4

In processing the string baabbaab, the npda makes the following moves (as indicated by transition rule number):

(q0,baab,z)(q_{0}, baab, z)
(3) \vdash (q0,aab,1z)(q_{0}, aab, 1z)
(6) \vdash (q0,ab,z)(q_{0}, ab, z)
(2) \vdash (q0,b,0z)(q_{0}, b, 0z)
(5) \vdash (q0,λ,z)(q_{0}, \lambda, z)
(1) \vdash (qf,λ,z)(q_{f}, \lambda, z)

Hence, the string is accepted.

7.1.8 Linz Example 7.5

Construct an npda for accepting the language L={wwR:w{a,b}+}L = \{ww^{R}: w \in \{a, b\}^{+}\},

The basic idea is:

Problem: How do we find the middle?

Solution: Use nondeterminism!

For L={wwR:w{a,b}+}L = \{ww^{R}: w \in \{a, b\}^{+}\}, a solution to the problem is given by M=(Q,Σ,Γ,δ,q0,z,F)M = (Q,\Sigma,\Gamma,\delta,q_{0},z,F), where:

Q={q0,q1,q2}Q = \{q_{0}, q_{1}, q_{2}\}
Σ={a,b}\Sigma = \{a, b\}
Γ={a,b,z}\Gamma = \{a, b, z\} -- which is Σ\Sigma plus the staack start symbol F={q2}F = \{q_{2}\}

The transition function can be visualized as having several parts.

  1. δ(q1,λ,z)=\delta(q_{1}, \lambda, z) = {(q2,z)}\{(q_{2}, z)\}

Remember that, to be accepted, a final state must be reached with no unprocessed input remaining.

The sequence of moves accepting abbaabba is as follows, where the number in parenthesis gives the transition rule applied:

(q0,abba,z)(q_{0}, abba, z)
(5) \vdash (q0,bba,az)(q_{0}, bba, az)
(2) \vdash (q0,ba,baz)(q_{0}, ba, baz)
(8) \vdash (q1,ba,baz)(q_{1}, ba, baz)
(10) \vdash (q1,a,az)(q_{1}, a, az)
(9) \vdash (q1,λ,z)(q_{1}, \lambda, z)
(11) \vdash (q2,z)(q_{2}, z)

7.2 Pushdown Automata and Context-Free Languages

7.2.1 Pushdown Automata for CFGs

Underlying idea: Given a context-free language, construct an npda that simulates a leftmost derivation for any string in the language.

We assume the context-free language is represented as grammar in Greibach Normal Form, as defined in Linz Chapter 6. We did not cover that chapter, but the definition and key theorem are shown below.

Greibach Normal Form restricts the positions at which terminals and variables can appear in a grammar's productions.

Linz Definition 6.5 (Greibach Normal Form): A context-free grammar is said to be in Greibach Normal Form if all productions have the form

AaxA \rightarrow ax,

where aTa \in T and xV*x \in V^{*}.

The structure of a grammar in Greibach Normal Form is similar to that of an s-grammar except that, unlike s-grammars, the grammar does not restrict pairs (A,a)(A,a) to single occurrences within the set of productions.

Linz Theorem 6.7 (Existence of Greibach Normal Form Grammars): For every context-free grammar GG with λL(G)\lambda \notin L(G), there exists an equivalent grammar G^\hat{G} in Greibach normal form.

Underlying idea, continued: Consider a sentential form, for example,

x1x2x3x4x5x6x_{1} x_{2} x_{3} x_{4} x_{5} x_{6}

where x1x2x3x_{1} x_{2} x_{3} are the terminals read from the input and x4x5x6x_{4} x_{5} x_{6} are the variables on the stack.

Consider a production AaxA \rightarrow ax.

If variable AA is on top of stack and terminal aa is the next input symbol, then remove AA from the stack and push back xx.

An npda transition function δ\delta for AaxA \rightarrow ax must be defined to have the move

(q,aw,Ay)(q,w,xy)(q, aw, Ay) \vdash (q, w, xy)

for some state qq, input string suffix ww, and stack yy. This, we define δ\delta such that

δ(q,a,A)={(q,x)}\delta(q, a, A) = \{(q, x)\}.

7.2.2 Linz Example 7.6

Construct a pda to accept the language generated by grammar with productions

SaSbb|aS \rightarrow aSbb \ |\ a.

First, we transform this grammar into Greibach Normal Form:

SaSA|aS \rightarrow aSA\ |\ a
AbBA \rightarrow bB
BbB \rightarrow b

We define the pda to have three states -- an initial state q0q_{0}, a final state q2q_{2}, and an intermediate state q1q_{1}.

We define the initial transition rule to push the start symbol SS on the stack:

δ(q0,λ,z)={(q1,Sz)}\delta(q_{0}, \lambda, z) = \{(q_{1}, Sz)\}

We simulate the production SaSAS \rightarrow aSA with a transition that reads aa from the input and replaces SS on the top of the stack by SASA.

Similarly, we simulate the production SaS \rightarrow a with a transition that reads aa while simply removing SS from the top of the stack. We represent these two productions in the pda as the nondeterministic transition rule:

δ(q1,a,S)={(q1,SA),(q1,λ)}\delta(q_{1}, a, S) = \{(q_{1}, SA), (q_{1}, \lambda)\}

Doing the same for the other productions, we get transition rules:

δ(q1,b,A)={(q1,B)}\delta(q_{1}, b, A) = \{(q_{1}, B)\}
δ(q1,b,B)={(q1,λ)}\delta(q_{1}, b, B) = \{(q_{1}, \lambda)\}

When the stack start symbol appears at the top of the stack, the derivation is complete. We define a transition rule to move the pda into its final state:

δ(q1,λ,z)={(q2,λ)}\delta(q_{1}, \lambda, z) = \{(q_{2}, \lambda)\}

7.2.3 Constructing an NPDA for a CFG

Linz Theorem 7.1 (Existence of NPDA for Context-Free Language): For any context-free language LL, there exists an npda MM such that L=L(M)L = L(M).

Proof: The proof partly follows from the following construction (algorithm).

Algorithm to construct an npda for a context-free grammar

7.2.4 Linz Example 7.7

Consider the grammar:

SaAS \rightarrow aA
AaABC|bB|aA \rightarrow aABC\ |\ bB\ |\ a
BbB \rightarrow b
CcC \rightarrow c

This grammar is already in Greibach Normal Form. So we can apply the algorithm above directly.

In addition to the transition rules for the startup and shutdown, i.e.,

  1. δ(q0,λ,z)\delta(q_{0}, \lambda, z) == {(q1,Sz)}\{(q_{1}, Sz)\}
  2. δ(q1,λ,z)\delta(q_{1}, \lambda, z) == {(qf,z)}\{(q_{f}, z)\}

the npda has the following transition rules for the productions:

  1. δ(q1,a,S)\delta(q_{1}, a, S) == {(q1,A)}\{(q_{1}, A)\}
  2. δ(q1,a,A)\delta(q_{1}, a, A) == {(q1,ABC),(q1,λ)}\{(q_{1}, ABC), (q_{1}, \lambda)\}
  3. δ(q1,b,A)\delta(q_{1}, b, A) == {(q1,B)}\{(q_{1}, B)\}
  4. δ(q1,b,B)\delta(q_{1}, b, B) == {(q1,λ)}\{(q_{1}, \lambda)\}
  5. δ(q1,c,C)\delta(q_{1}, c, C) == {(q1,λ)}\{(q_{1}, \lambda)\}

The sequence of moves made by MM in processing is aaabcaaabc is

(q0,aaabc,z)(q_{0}, aaabc, z)
(1) \vdash (q1,aaabc,Sz)(q_{1}, aaabc, Sz)
(3) \vdash (q1,aabc,Az)(q_{1}, aabc, Az)
(4a) \vdash (q1,abc,ABCz)(q_{1}, abc, ABCz)
(4b) \vdash (q1,bc,BCz)(q_{1}, bc, BCz)
(6) \vdash (q1,c,Cz)(q_{1}, c, Cz)
(7) \vdash (q1,λ,z)(q_{1}, \lambda, z)
(2) \vdash (qf,λ,z)(q_{f}, \lambda, z)

This corresponds to the derivation

SaAaaABCaaaBCaaabCaaabc.S \Rightarrow aA \Rightarrow aaABC \Rightarrow aaaBC \Rightarrow aaabC \Rightarrow aaabc.

The previous construction assumed Greibach Normal Form. This is not necessary, but the needed construction technique is more complex, as sketched below.

ABxA \rightarrow Bx

(q1,Bx)δ(q1,λ,A)(q_{1}, Bx) \in \delta(q_{1}, \lambda, A)

AabCxA \rightarrow abCx

e.g.,
(q2,λ)δ(q1,a,a)(q_{2}, \lambda) \in \delta(q_{1}, a, a)
(q3,λ)δ(q2,b,b)(q_{3}, \lambda) \in \delta(q_{2}, b, b)
(q1,Cx)δ(q3,λ,A)(q_{1}, Cx) \in \delta(q_{3}, \lambda, A)

etc.

7.2.5 Constructing a CFG for an NPDA

Linz Theorem 7.2 (Existence of a Context-Free Language for an NPDA): If L=L(M)L = L(M) for some npda MM, then LL is a context-free language.

Basic idea: To construct a context-free grammar from an npda, reverse the previous construction.

That is, construct a grammar to simulate npda moves:

This leads to a relatively complicated construction. This is described in the Linz textbook in more detail, but we will not cover it in this course.

7.3 Deterministic Pushdown Automata and Deterministic Context-Free Languages

7.3.1 Deterministic Pushdown Automata

A deterministic pushdown accepter (dpda) is a pushdown automaton that never has a choice in its move.

Linz Definition 7.3 (Deterministic Pushdown Automaton): A pushdown automaton M=(Q,Σ,Γ,δ,q0,z,F)M = (Q, \Sigma, \Gamma, \delta, q_{0}, z, F) is deterministic if it is an automaton as defined in Linz Definition 7.1, subject to the restrictions that, for every qQ,aΣ{λ}q \in Q, a \in \Sigma \cup \{\lambda\}, and bΓb \in \Gamma,

  1. δ(q,a,b)\delta(q, a, b) contains at most one element,

  2. if δ(q,λ,b)\delta(q, \lambda, b) is not empty, then δ(q,c,b)\delta(q, c, b) must be empty for every cΣc \in \Sigma.

Restriction 1 requires that for, any given input symbol and any stack top, at most one move can be made.

Restriction 2 requires that, when a λ\lambda-move is possible for some configuration, no input-consuming alternative is available.

Consider the difference between this dpda definition and the dfa definition:

Linz Definition 7.4 (Deterministic Context-Free Language): A language LL is a deterministic context-free language if and only if there exists a dpda MM such that L=L(M)L = L(M).

7.3.2 Linz Example 7.10

The language L={anbn:n0}L = \{a^{n}b^{n}: n \geq 0\} is a deterministic context-free language.

The pda M=({q0,q1,q2},{a,b},{0,1},δ,q0,0,{q0})M = (\{q_{0}, q_{1}, q_{2}\}, \{a,b\}, \{0,1\}, \delta, q_{0}, 0, \{q_{0}\}) with transition rules

δ(q0,a,0)={(q1,10)}\delta(q_{0}, a, 0) = \{(q_{1}, 10)\}
δ(q1,a,1)={(q1,11)}\delta(q_{1}, a, 1) = \{(q_{1}, 11)\}
δ(q1,b,1)={(q2,λ)}\delta(q_{1}, b, 1) = \{(q_{2}, \lambda)\}
δ(q2,b,1)={(q2,λ)}\delta(q_{2}, b, 1) = \{(q_{2}, \lambda)\}
δ(q2,λ,0)={(q0,λ)}\delta(q_{2}, \lambda, 0) = \{(q_{0}, \lambda)\}

accepts the given language. This grammar satisfies the conditions of Linz Definition 7.4. Therefore, it is deterministic.

7.3.3 Linz Example 7.5 Revisited

Consider language

L={wwR:w{a,b}+}L = \{ww^{R}: w \in \{a, b\}^{+}\}

and machine

M=(Q,Σ,Γ,δ,q0,z,F)M = (Q, \Sigma, \Gamma, \delta, q_{0}, z, F)

where:

Q={q0,q1,q2}Q = \{q_{0}, q_{1}, q_{2}\}
Σ={a,b}\Sigma = \{a, b\}
Γ={a,b,z}\Gamma = \{a, b, z\}
F={q2}F = \{q_{2}\}

The transition function can be visualized as having several parts:

δ(q0,a,a)={(q0,aa)}\delta(q_{0}, a, a) = \{(q_{0}, aa)\} \leftarrow Restriction 2 violation
δ(q0,b,a)={(q0,ba)}\delta(q_{0}, b, a) = \{(q_{0}, ba)\}
δ(q0,a,b)={(q0,ab)}\delta(q_{0}, a, b) = \{(q_{0}, ab)\}
δ(q0,b,b)={(q0,bb)}\delta(q_{0}, b, b) = \{(q_{0}, bb)\}
δ(q0,a,z)={(q0,az)}\delta(q_{0}, a, z) = \{(q_{0}, az)\}
δ(q0,b,z)={(q0,bz)}\delta(q_{0}, b, z) = \{(q_{0}, bz)\}

δ(q0,λ,a)={(q1,a)}\delta(q_{0}, \lambda, a) = \{(q_{1}, a)\} \leftarrow Restriction 2 violation
δ(q0,λ,b)={(q1,b)}\delta(q_{0}, \lambda, b) = \{(q_{1}, b)\}

δ(q1,a,a)={(q1,λ)}\delta(q_{1}, a, a) = \{(q_{1}, \lambda)\}
δ(q1,b,b)={(q1,λ)}\delta(q_{1}, b, b) = \{(q_{1}, \lambda)\}

δ(q1,λ,z)={(q2,z)}\delta(q_{1}, \lambda, z) = \{(q_{2}, z)\}

This machines violates Restriciton 2 of Linz Definition 7.3 (Deterministic Pushdown Automaton) as indicated above. Thus, it is not deterministic.

Moreover, LL is itself not deterministic (which is not proven here).

7.4 Grammars for Deterministic Context-Free Grammars

Deterministic context-free languages are important because they can be parsed efficiently.

An LL-grammar is a generalization of the concept of s-grammar. This family of grammars generates the deterministic context-free languages.

Compilers for practical programming languages may use top-down parsers based on LL-grammars to parse the languages efficiently.