Pushdown Automata
(Content adapted from Critchlow & Eck)
In the previous chapter, we saw that there is a neat correspondence between regular expressions and finite automata. That is, a language is generated by a regular expression if and only if that language is accepted by a finite automaton. Finite automata come in two types, deterministic and nondeterministic, but the two types of finite automata are equivalent in terms of their ability to recognize languages. So, the class of regular languages can be defined in two ways: either as the set of languages that can be generated by regular expressions or as the set of languages that can be recognized by finite automata (either deterministic or nondeterministic).
In this chapter, we have introduced the class of context-free languages, and we have considered how context-free grammars can be used to generate context-free languages. You might wonder whether there is any type of automaton that can be used to recognize context-free languages. In fact, there is: The abstract machines known as pushdown automata can be used to define context-free languages. That is, a language is context-free if and only if there is a pushdown automaton that accepts that language.
A pushdown automaton is essentially a finite automaton with an auxiliary data structure known as a stack. A stack consists of a finite list of symbols. Symbols can be added to and removed from the list, but only at one end of the list. The end of the list where items can be added and removed is called the top of the stack. The list is usually visualized as a vertical "stack" of symbols, with items being added and removed at the top. Adding a symbol at the top of the stack is referred to as pushing a symbol onto the stack, and removing a symbol is referred to as popping an item from the stack. During each step of its computation, a pushdown automaton is capable of doing several push and pop operations on its stack (this in addition to possibly reading a symbol from the input string that is being processed by the automaton).
Before giving a formal definition of pushdown automata, we will look at how they can be represented by transition diagrams. A diagram of a pushdown automaton is similar to a diagram for an NFA, except that each transition in the diagram can involve stack operations. We will use a label of the form / on a transition to mean that the automaton consumes from its input string, pops from the stack, and pushes onto the stack. can be either or a single symbol. and are strings, possibly empty. (When a string is popped from the stack, must be the top symbol on the stack, followed by , etc.; for to be pushed onto a stack, the symbols are pushed in the order , so that ends up on the top of the stack.) For example, consider the following transition diagram for a pushdown automaton:
This pushdown automaton has start state and one accepting state, . It can read strings over the alphabet . The transition from to , labeled with /1, means that if the machine is in state , then it can read an from its input string, pop nothing from the stack, push 1 onto the stack, and remain in state . Similarly, the transition from to means that if the machine is in state , it can read a from its input string, pop a 1 from the stack, and push nothing onto the stack. Finally, the transition from state to , labeled with /, means that the machine can transition from state to state without reading, pushing, or popping anything.
Note that the automation can follow transition / only if the next symbol in the input string is and if is on the top of the stack. When it makes the transition, it consumes the from input and pops the from the stack. Since in this case, the automaton pushes (that is, no symbols at all) onto the stack, the net change in the stack is simply to pop the 1.
We have to say what it means for this pushdown automaton to accept a string. For , we say that the pushdown automaton accepts if and only if it is possible for the machine to start in its start state, , read all of , and finish in the accepting state, , with an empty stack. Note in particular that it is not enough for the machine to finish in an accepting state—it must also empty the stack.1
It's not difficult to see that with this definition, the language accepted by our pushdown automaton is . In fact, given the string , the machine can process this string by following the transition from to times. This will consume all the 's and will push 1's onto the stack. The machine can then jump to state and follow the transition from to times. Each time it does so, it consumes one from the input and pops one 1 from the stack. At the end, the input has been completely consumed and the stack is empty. So, the string is accepted by the automaton. Conversely, this pushdown automaton only accepts strings of the form , since the only way that the automaton can finish in the accepting state, , is to follow the transition from to some number of times, reading 's as it does so, then jump at some point to , and then follow the transition from to some number of times, reading 's as it does so. This means that an accepted string must be of the form for some . However, in reading this string, the automaton pushes 1's onto the stack and pops 1's from the stack. For the stack to end up empty, must equal , which means that in fact the string is of the form , as claimed.
Here are two more examples. These pushdown automata use the capability to push or pop more than one symbol at a time:
The automaton on the left accepts the language . Each time it reads an , it pushes either one or two 1's onto the stack, so that after reading 's, the number of 1's on the stack is between and . If the machine then jumps to state , it must be able to read exactly enough 's to empty the stack, so any string accepted by this machine must be of the form with . Conversely, any such string can be accepted by the machine. Similarly, the automaton on the right above accepts the language . To accept , it must push 1'a onto the stack and then pop one or two 1's for each b; this can succeed only if the number of 's is between and .
Note that an NFA can be considered to be a pushdown automaton that does not make any use of its stack. This means that any language that can be accepted by an NFA (that is, any regular language) can be accepted by a pushdown automaton. Since the language is context-free but not regular, and since it is accepted by the above pushdown automaton, we see that pushdown automata are capable of recognizing context-free languages that are not regular, therefore pushdown automata are strictly more powerful than finite automata.
Formal Definition
Although it is not particularly illuminating, we can give a formal definition of pushdown automaton. The definition does at least make it clear that the set of symbols that can be used on the stack is not necessarily the same as the set of symbols that can be used as input.
A pushdown automaton is specified by six components where
- is a finite set of states.
- is an alphabet. is the input alphabet for .
- is an alphabet. is the stack alphabet for .
- is the start state of .
- is the set of final or accepting states in .
- is the set of transitions in . can be taken to be a finite subset of the set . An element of represents a transition from state to state in which reads from its input string, pops from the stack, and pushes onto the stack.
We can then define the language accepted by a pushdown automaton to be the set .
With this definition, the class of languages accepted by pushdown automata is the same as the class of languages generated by context-free grammars.
Theorem: Let be an alphabet, and let be a language over . Then is context-free if and only if there is a pushdown automaton whose input alphabet is such that .
We will not prove this theorem, but we do discuss how one direction can be proved. Suppose that is a context-free language over an alphabet . Let be a context-free grammar for . Then we can construct a pushdown automaton that accepts . In fact, we can take where , , , and contains transitions of the forms
- ;
- , for ; and
- , for each production in .
The transition lets move from the start state to the accepting state while reading no input and pushing onto the stack. This is the only possible first move by .
A transition of the form , for , allows to read from its input string, provided there is a on the top of the stack. Note that if is at the top of the stack, then this transition is the only transition that applies. Effectively, any terminal symbol that appears at the top of the stack must be matched by the same symbol in the input string, and the transition rule allows to consume the symbol from the input string and remove it from the stack at the same time.
A transition of the third form, , can be applied if and only if the non-terminal symbol is at the top of the stack. consumes no input when this rule is applied, but is replaced on the top of the stack by the string on the right-hand side of the production rule . Since the grammar can contain several production rules that have as their left-hand side, there can be several transition rules in that apply when is on the top of the stack. This is the only source of nondeterminism in ; note that is also the source of nondeterminism in .
The proof that follows from the fact that a computation of that accepts a string corresponds in a natural way to a left derivation of from 's start symbol, . Instead of giving a proof of this fact, we look at an example. Consider the following context-free grammar:
This grammar generates the language . The pushdown automaton constructed from this grammar by the procedure given above has the following set of transition rules:
Suppose that the automaton is run on the input . We can trace the sequence of transitions that are applied in a computation that accepts this input, and we can compare that computation to a left derivation of the string:
Transition | Input Consumed | Stack | Derivation | Production |
---|---|---|---|---|
Note that at all times during this computation, the concatenation of the input that has been consumed so far with the contents of the stack is equal to one of the strings in the left derivation. Application of a rule of the form has the effect of removing one terminal symbol from the "Stack" column to the "Input Consumed" column. Application of a rule of the form has the effect of applying the next step in the left derivation to the non-terminal symbol on the top of the stack. (In the "Stack" column, the pushdown automaton's stack is shown with its top on the left.) In the end, the entire input string has been consumed and the stack is empty, which means that the string has been accepted by the pushdown automaton. It should be easy to see that for any context free grammar , the same correspondence will always hold between left derivations and computations performed by the pushdown automaton constructed from .
The computation of a pushdown automaton can involve nondeterminism. That is, at some point in the computation, there might be more than one transition rule that apply. When this is not the case—that is, when there is no circumstance in which two different transition rules apply—then we say that the pushdown automaton is deterministic. Note that a deterministic pushdown automaton can have transition rules of the form (or even if that is the only transition from state ). Note also that is is possible for a deterministic pushdown automaton to get "stuck"; that is, it is possible that no rules apply in some circumstances even though the input has not been completely consumed or the stack is not empty. If a deterministic pushdown automaton gets stuck while reading a string , then is not accepted by the automaton.
The automaton given at the beginning of this section, which accepts the language , is not deterministic. However, it is easy to construct a deterministic pushdown automaton for this language:
However, consider the language . Here is a pushdown automaton that accepts this language:
In state , this machine copies the first part of its input string onto the stack. In state , it tries to match the remainder of the input against the contents of the stack. In order for this to work, it must "guess" where the middle of the string occurs by following the transition from state to state . In this case, it is by no means clear that it is possible to construct a deterministic pushdown automaton that accepts the same language.
At this point, it might be tempting to define a deterministic context-free language as one for which there exists a deterministic pushdown automaton which accepts that language. However, there is a technical problem with this definition: we need to make it possible for the pushdown automaton to detect the end of the input string. Consider the language , which consists of strings over the alphabet in which the number of 's is equal to the number of 's. This language is accepted by the following pushdown automaton:
In this automaton, a is first pushed onto the stack, and it remains on the bottom of the stack until the computation ends. During the process of reading an input string, if the machine is in state , then the number of 's that have been read is greater than or equal to the number of 's that have been read, and the stack contains (copies of) the excess 's that have been read. Similarly, if the machine is in state , then the number of 's that have been read is greater than or equal to the number of 's that have been read, and the stack contains (copies of) the excess 's that have been read. As the computation proceeds, if the stack contains nothing but a , then the number of 's that have been consumed by the machine is equal to the number of 's that have been consumed; in such cases, the machine can pop the from the stack—leaving the stack empty—and jump to state . If the entire string has been read at that time, then the string is accepted. This involves nondeterminism because the automaton has to "guess" when to jump to state ; it has no way of knowing whether it has actually reached the end of the string.
Although this pushdown automaton is not deterministic, we can modify it easily to get a deterministic pushdown automaton that accepts a closely related language. We just have to add a special end-of-string symbol to the language. We use the symbol for this purpose. The following deterministic automaton accepts the language :
In this modified automaton, it is only possible for the machine to reach the accepting state by reading the end-of-string symbol at a time when the number of 's that have been consumed is equal to the number of 's. Taking our cue from this example, we define what it means for a language to be deterministic context-free as follows:
Let be a language over an alphabet , and let be a symbol that is not in . We say that is a deterministic context-free language if there is a deterministic pushdown automaton that accepts the language (which is equal to ).
There are context-free languages that are not deterministic context-free. An example, given without proof, is the language of even-length palindromes over the alphabet : . This means that for pushdown automata, nondeterminism adds real power. This contrasts with the case of finite automata, where deterministic finite automata and nondeterministic finite automata are equivalent in power in the sense that they accept the same class of languages.
A deterministic context-free language can be parsed efficiently (in time, where is the length of the input). LL(1) parsing and LR(1) parsing can both be defined in terms of deterministic pushdown automata, although we have not pursued that approach here. It can be shown that every deterministic context-free language can be generated by an LR(1) grammar. However, the languages that have LL(1) grammars are a strict subset: an example of a language that has an LR(1) grammar but not an LL(1) grammar is .
Exercises
Identify the context-free language that is accepted by each of the following pushdown automata. Explain your answers.
a)
b)
c)
d)
Let be the language over the alphabet that consists of strings of parentheses that are balanced in the sense that every left parenthesis has a matching right parenthesis. Examples include , , , and the empty string. Find a deterministic pushdown automaton with a single state that accepts the language . Explain how your automaton works, and explain the circumstances in which it will fail to accept a given string of parentheses.
Suppose that is a language over an alphabet . Suppose that there is a deterministic pushdown automaton that accepts . Show that is deterministic context-free. That is, show how to construct a deterministic pushdown automaton that accepts the language . (Assume that the symbol is not in .)
Find a deterministic pushdown automaton that accepts the language .
Show that the language is deterministic context-free.
Show that the language is deterministic context-free.
Let be a pushdown automaton. Define to be the language it is possible for to start in state , read all of , and end in an accepting state. differs from in that for , we do not require that the stack be empty at the end of the computation.
- Show that there is a pushdown automaton such that .
- Show that a language is context-free if and only if there is a pushdown automaton such that .
- Identify the language for each of the automata in Exercise 1.
Let be a regular language over an alphabet , and let be a context-free language over the same alphabet. Let be a DFA that accepts , and let be a pushdown automaton that accepts . Show that the language is context-free by constructing a pushdown automaton that accepts . The pushdown automaton can be constructed as a "cross product" of and in which the set of states is . The construction is analogous to the proof that the intersection of two regular languages is regular, as outlined in an exercise in the section on regular languages.
- We could relax this restriction and require only that the machine finish in an accepting state after reading the string , without requiring that the stack be empty. In fact, using this definition of accepting would not change the class of languages that are accepted by pushdown automata.↩