Context-Free Grammars
(Content adapted from Critchlow & Eck)
Both natural languages, such as English, and the artificial languages used for programming have a structure known as grammar or syntax. In order to form legal sentences or programs, the parts of the language must be fit together according to certain rules. For natural languages, the rules are somewhat informal (although high-school English teachers might have us believe differently). For programming languages, the rules are absolute, and programs that violate the rules will be rejected by a compiler.
In this chapter, we will study formal grammars and languages defined by them. The languages we look at will, for the most part, be "toy" languages, compared to natural languages or even to programming languages, but the ideas and techniques are basic to any study of language. In fact, many of the ideas arose almost simultaneously in the 1950s in the work of linguists who were studying natural language and programmers who were looking for ways to specify the syntax of programming languages.
The grammars in this chapter are generative grammars. A generative grammar is a set of rules that can be used to generate all the legal strings in a language. We will also consider the closely related idea of parsing. To parse a string means to determine how that string can be generated according to the rules.
This chapter is a continuation of the preceding chapter. Like a regular expression, a grammar is a way to specify a possibly infinite language with a finite amount of information. In fact, we will see that every regular language can be specified by a certain simple type of grammar. We will also see that some languages that can be specified by grammars are not regular.
In its most general form, a grammar is a set of rewriting rules. A rewriting rule specifies that a certain string of symbols can be substituted for all or part of another string. If and are strings, then is a rewriting rule that specifies that the string can be replaced by the string . The symbol "" is read "can be rewritten as." Rewriting rules are also called production rules or productions, and "" can also be read as "produces." For example, if we consider strings over the alphabet , then the production rule can be applied to the string to give the string . The substring in the string has been replaced with .
In a context-free grammar, every rewriting rule has the form , where is single symbol and is a string of zero or more symbols. (The grammar is "context-free" in the sense that can be substituted for wherever occurs in a string, regardless of the surrounding context in which occurs.) The symbols that occur on the left-hand sides of production rules in a context-free grammar are called non-terminal symbols. By convention, the non-terminal symbols are usually uppercase letters. The strings on the right-hand sides of the production rules can include non-terminal symbols as well as other symbols, which are called terminal symbols. By convention, the terminal symbols are usually lowercase letters. Here are some typical production rules that might occur in context-free grammars:
In the last rule in this list, represents the empty string, as usual. For example, this rule could be applied to the string to produce the string . The first occurrence of the symbol in has been replaced by the empty string—which is just another way of saying that the symbol has been dropped from the string.
In every context-free grammar, one of the non-terminal symbols is designated as the start symbol of the grammar. The start symbol is often, though not always, denoted by . When the grammar is used to generate strings in a language, the idea is to start with a string consisting of nothing but the start symbol. Then a sequence of production rules is applied. Each application of a production rule to the string transforms the string to a new string. If and when this process produces a string that consists purely of terminal symbols, the process ends. That string of terminal symbols is one of the strings in the language generated by the grammar. In fact, the language consists precisely of all strings of terminal symbols that can be produced in this way.
As a simple example, consider a grammar that has three production rules: , , and . In this example, is the only non-terminal symbol, and the terminal symbols are and . Starting from the string , we can apply any of the three rules of the grammar to produce either , , or . Since the string contains no non-terminals, we see that is one of the strings in the language generated by this grammar. The strings and are not in that language, since they contain the non-terminal symbol , but we can continue to apply production rules to these strings. From , for example, we can obtain , , or . From , we go on to obtain , , or . The strings and are in the language generated by the grammar. It's not hard to see that any string of 's and 's that ends with a can be generated by this grammar, and that these are the only strings that can be generated. That is, the language generated by this grammar is the regular language specified by the regular expression .
It's time to give some formal definitions of the concepts which we have been discussing.
A context-free grammar is a 4-tuple , where:
is a finite set of symbols. The elements of are the non-terminal symbols of the grammar.
is a finite set of symbols such that . The elements of are the terminal symbols of the grammar.
is a set of production rules. Each rule is of the form where is one of the symbols in and is a string in the language .
. is the start symbol of the grammar.
Even though this is the formal definition, grammars are often specified informally simply by listing the set of production rules. When this is done it is assumed, unless otherwise specified, that the non-terminal symbols are just the symbols that occur on the left-hand sides of production rules of the grammar. The terminal symbols are all the other symbols that occur on the right-hand sides of production rules. The start symbol is the symbol that occurs on the left-hand side of the first production rule in the list. Thus, the list of production rules
specifies a grammar where is , is , and is the start symbol. , of course, is a set containing the six production rules in the list.
Let be a context-free grammar. Suppose that and are strings in the language . The notation is used to express the fact that can be obtained from by applying one of the production rules in . To be more exact, we say that if and only if there is a production rule in the grammar and two strings and in the language such that and . The fact that is just a way of saying that occurs somewhere in . When the production rule is applied to substitute for in , the result is , which is . Note that either or or both can be the empty string.
If a string can be obtained from a string by applying a sequence of zero or more production rules, we write . In most cases, the "" in the notations and will be omitted, assuming that the grammar in question is understood. Note that is a relation on the set . The relation is the reflexive, transitive closure of that relation. (This explains the use of "", which is usually used to denote the transitive, but not necessarily reflexive, closure of a relation. In this case, is reflexive as well as transitive since is true for any string .) For example, using the grammar that is defined by the above list of production rules, we have
From this, it follows that . The relation is read "yields" or "produces" while can be read "yields in zero or more steps" or "produces in zero or more steps." The following theorem states some simple facts about the relations and :
Theorem: Let be the context-free grammar