How to Prove That a Formal Grammar Is Correct
At a glance
- 1. State the target language
Define precisely which strings the grammar is supposed to generate.
- 2. Prove soundness
Show that every string generated by the grammar belongs to the target language.
- 3. Prove completeness
Show that every string in the target language can be generated by the grammar.
- 4. Check ambiguity separately
A grammar can generate the right language while still giving some strings multiple parse trees.
A formal grammar is correct when it generates exactly the strings that it is intended to describe. The standard proof is therefore an equality proof: if is the grammar and is the target language, establish
The most reliable way to prove this equality is to prove both inclusions separately. This method applies to context-free grammars and, with suitable changes, to regular and unrestricted grammars as well.
What “correct” means
Let be a grammar, where is the set of variables, is the terminal alphabet, is the set of productions, and is the start symbol. The language generated by is
Here, means that can be obtained from through zero or more production applications.
Suppose the intended language is . There are two obligations:
- Soundness: . The grammar does not generate invalid strings.
- Completeness: . The grammar generates every valid string.
Together, these imply .
Correctness does not necessarily mean that the grammar is unambiguous. A grammar may generate exactly the right language but provide two or more parse trees for one string.
Proving soundness
To prove soundness, start with an arbitrary string such that . You must show that satisfies the definition of the target language.
The proof usually follows one of these patterns:
- induction on the number of production applications;
- structural induction on the grammar’s recursive rules;
- an invariant that remains true for every sentential form.
The key is to examine every production that can contribute to a derivation. If each production preserves the desired property, then the final terminal string has that property too.
Proving completeness
To prove completeness, start with an arbitrary string . Use the description of to construct a derivation from .
For recursively defined languages, induction on the size of the string is often natural. The induction step should explain which production corresponds to the structure of the string. For example, if every nonempty string in the target language has the form , use a production that adds at the left and at the right.
Worked example: the language
Consider the grammar
The intended language is
This language contains
We will prove that the grammar is correct.
Soundness
We show that every string derived from has the form for some .
Use induction on the number of times the production is used.
Base case: If it is used zero times, then the derivation is
This is , so the claim holds.
Inductive step: Assume a derivation using copies of produces . A derivation using copies has the form
Thus every generated string contains the same number of symbols and symbols, with all symbols before all symbols. Therefore,
Completeness
Now take any string in the target language. It has the form for some .
If , then
If , apply exactly times and then apply :
Therefore every string in the target language is generated by the grammar:
The two inclusions establish
The grammar is correct for this language.
A useful proof template
For many grammar questions, the following structure is enough:
Claim. The grammar generates exactly the language .
Soundness. Let . Analyze a derivation , usually by induction. Show that has the required form, so .
Completeness. Let . Use the structure or defining recurrence of to construct a derivation . Hence .
Conclusion. Since both inclusions hold, .
Avoid saying only that the grammar “looks like” the language. A few successful derivations demonstrate possibility, not correctness. They do not show that every valid string is generated or that invalid strings are excluded.
Correctness versus ambiguity
A grammar can be correct but ambiguous. For example, the grammar
can generate arithmetic expressions, but an expression such as may have different parse trees corresponding to different groupings. Whether that is acceptable depends on the language specification.
If the grammar must be unambiguous, add a third proof obligation: show that every generated string has at most one parse tree, or at most one leftmost derivation. For arithmetic, this is usually handled by separating precedence levels, for example with distinct variables for expressions, terms, and factors.
Common mistakes
- Proving only soundness: Showing that generated strings are valid does not show that all valid strings can be generated.
- Proving only completeness: A grammar may generate every intended string and many unintended ones.
- Forgetting the empty string: If the target definition allows , the proof must account for .
- Using examples as a proof: Listing derivations for several strings cannot replace an induction or general construction.
- Confusing language equality with unambiguity: Exact language generation and unique parsing are different properties.
- Ignoring the start symbol: Derivations must begin with the specified start symbol, not an arbitrary variable.
For a programming-language grammar, the same distinction remains useful: first prove that the syntax accepts every intended valid construct and rejects strings outside the syntactic language; then analyze semantic rules, such as type checking, separately.
References
- Introduction to the Theory of Computation, Michael Sipser
- Formal Languages and Their Relation to Automata, Hopcroft, Motwani, and Ullman
Spotted an error? Send a correction. Read how we write and check articles in our editorial policy.