0% found this document useful (0 votes)
18 views

2015 Grammar 4 CS

Uploaded by

j.oswaldochan
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

2015 Grammar 4 CS

Uploaded by

j.oswaldochan
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 19

A Practical Tutorial on Context Free Grammars

Robert B. Heckendorn
University of Idaho

November 28, 2015

Contents
1 Some Definitions 2

2 Some Common Idioms and Hierarchical Development 4


2.1 A grammar for a language that allows a list of X’s . . . . . . . . . . . . . . . . . . . . . . . 4
2.2 A Language that is a List of X’s or Y’s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3 A Language that is a List of X’s Terminated with a Semicolon . . . . . . . . . . . . . . . . 4
2.4 Hierarchical Complexification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.5 A Language Where There are not Terminal Semicolons but Separating Commas . . . . . . 5
2.6 A language where each X is followed by a terminating semicolon: . . . . . . . . . . . . . . . 5
2.7 An arg list of X’s, Y’s and Z’s: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.8 A Simple Type Declaration: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.9 Augment the Type Grammar with the Keyword Static . . . . . . . . . . . . . . . . . . . . . 6
2.10 A Tree Structure as Nested Parentheses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

3 Associativity and Precedence 6


3.1 A Grammar for an Arithmetic Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.2 Grouping with Parentheses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.3 Unary operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.4 An Example Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

4 How can Things go Wrong 9


4.1 Inescapable Productions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.2 Ambiguity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.2.1 Ambiguity by Ill-specified Associativity . . . . . . . . . . . . . . . . . . . . . . . . . 11
4.2.2 Ambiguity by Infinite Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.2.3 Ambiguity by Multiple Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

1
5 The Dangling Else 14

6 The Power of Context Free and incomplete grammars 15

7 Tips for Grammar Writing 16

8 Extended BNF 17

2
A grammar is used to specify the syntax of a language. It answers the question: What sentences are
in the language and what are not? A sentence is a finite sequence of symbols from the alphabet of the
language. The grammar we discuss here is for a context free languages. The grammar is a context
free grammar or CFG.
The goal of this document is to help students understand grammars as they are used in Computer
Science through the use of many examples and to provide a reference of common things they might want
to do with a grammar.

1 Some Definitions
A grammar defines what are legal statements in a language.
A grammar has:

• Alphabet is a finite set of symbols that appear in the language

• Nontermals symbols that can be replaced by collections of symbols found in a production (see
below)

• Terminal symbols from the alphabet

• Productions replacement rules for nonterminals

• Start symbol the initial symbol from which all sentences in the language can be derived. Note: it
is usually the left hand side of the first production when a start symbol is not specifically given.

Backus-Naur Form (BNF) is a notation for expressing a CFG. The notation:

• Nonterminals are denoted by surrounding symbol with <>. e.g. <turtle>

• Alternation is denoted by | e.g. bad <cats> | good <dogs>. Strictly speaking before we intro-
duced BNF, if you wanted:

<animal> ::= bad <cats> | good <dogs>

you could say the same thing without alternation:

<animal> ::= bad <cats>


<animal> ::= good <dogs>

• Replacement is denoted by ::=. These are the productions. The left hand side (lhs) of a the
production is the nonterminal symbol to the left of the ::=. The right hand side (rhs) of a the
production is the sequence of terminal and nonterminal symbols to the right of the ::=.

e.g. <dogs> ::= corgi | other

• Blanks are ignored or must be in some escaping scheme like quotes “ ”

• Terminals are unadorned symbols

3
If and only if a sentence is composed of an ordered list of elements from the alphabet and it can be
derived from the start symbol by application of production rules then it is in the language defined by
the grammar. Specifically a context free grammar (CFG) is defined by a set of productions in which
the left hand side of the production is a single nonterminal which may be replace by the right hand side
anywhere where the left hand side occurs, regardless of the context in which the left hand side symbol
occurs. Hence “context free”.
Here is an example of a context free grammar using BNF for simple English sentences:

<sentence> ::= <subject> <predicate>


<subject> ::= <article> <noun>
<predicate> ::= <verb> <direct-object>
<direct-object> ::= <article> <noun>
<article> ::= THE | A
<noun> ::= MAN | DOG
<verb> ::= BITES | PETS

Is the sentence “THE DOG BITES A MAN” in the language? That is does

<sentence> -> THE DOG BITES A MAN?

MAN BITES DOG is not in the grammar.


Parse tree is a tree based notation for describing the way a sentence could be built from a grammar.
There might be more than one parse tree for a given sentence in a language (see ambiguity). For the
sentence THE DOG BITES A MAN we have the parse tree:

Derivation is the ordered list of steps used in construction of a specific parse tree for a sentence from
a grammar.
Left Most Derivation is a derivation in which the left most nonterminal is always replaced first.
Parse is to show how a sentence could be built from a grammar.
Metasymbols are symbols outside the language to prevent circularity in talking about the grammar.

4
2 Some Common Idioms and Hierarchical Development
Many of the linguistic structures in a computer language come from a small set of basic idioms. Here
are some basic forms for some common things you might want in your language. Assume start symbol:
<sentence>.

2.1 A grammar for a language that allows a list of X’s

<sentence> ::= X | X <sentence>

This is also a grammar for that language:

<sentence> ::= X | <sentence> X

This is an example that there can be multiple correct grammars for the same language.

2.2 A Language that is a List of X’s or Y’s

<sentence> ::= X | Y | X <sentence> | Y <sentence>

Here is a more hierarchical way to do the same thing:

<sentence> ::= <sub> | <sub> <sentence>


<sub> ::= X | Y

Note that the first part handles this “listing” of the subparts which can either be an X or Y. It is often
clarifying to do grammars hierarchically.
Here are some grammars for two similar, but different languages:

<sentence> ::= X | Y | X <sentence>

is a grammar for one or more X’s followed by an X or Y.

<sentence> ::= X | Y | <sentence> X

is a grammar for an X or a Y followed by one or more X’s. If there was no Y we could not tell which way
the string was built from the final string and so the languages would be identical i.e. a list of 1 or more
Xs.

2.3 A Language that is a List of X’s Terminated with a Semicolon

<sentence> ::= <listx> ";"


<listx> ::= X | X <listx>

Note the hierarchical approach.

5
2.4 Hierarchical Complexification

Let’s now combine the previous and make a list of sublists of Xs that end in semicolons. Note that the
we describe a list of <list> and then describe how the sublists end in semicolons and then how to make
a list. Very top to bottom and hierarchical. This will help you develop clean grammars and look for bugs
such as unwanted recursion.

<sentence> ::= <list> | <sentence> <list>


<list> ::= <listx> ";"
<listx> ::= X | X <listx>

2.5 A Language Where There are not Terminal Semicolons but Separating Commas

<listx> ::= X | X "," <listx>

2.6 A language where each X is followed by a terminating semicolon:

Sometimes you need to ask yourself is this a separating delimiter or a terminating delimiter?

<listx> ::= X ";" | X ";" <listx>

Compare again with the separating case in which each X is separated from the next:

<listx> ::= X | X "," <listx>

This is a terminating delimiter case. Hierarchically it looks like:

<sentence> ::= <sub> | <sentence> <sub>


<sub> ::= X ","

2.7 An arg list of X’s, Y’s and Z’s:

<arglist> ::= "(" ")" | "(" <varlist> ")"


<varlist> ::= <var> | <varlist> "," <var>
<var> ::= X | Y | Z

2.8 A Simple Type Declaration:

This has a very hierarchical feel:

<tdecl> ::= <type> <varlist> ";"


<varlist> ::= <var> | <varlist> "," <var>
<var> ::= X | Y | Z
<type> ::= int | bool | string

6
2.9 Augment the Type Grammar with the Keyword Static

<tdecl> ::= <type> <varlist> ";"


<varlist> ::= <var> | <varlist> "," <var>
<var> ::= X | Y | Z
<type> ::= static <basictype> | <basictype>
<basictype> ::= int | bool | string

Notice how I slipped the static as an option before the type allowing either static followed by the basic
type or just the basic type. Hierarchy, hierarchy, hierarchy.

2.10 A Tree Structure as Nested Parentheses

For instance consider this popular nested way to represent a tree: (ant) or (cat, bat) or ((cat), (bat))
or ((cat, bat, dog), ant). Note the hierarchical handling of each feature. Note also that when <tree>
points up from <thing> to the top of the grammar creating the nesting effect. It is important to see that
matching <tree> requires that parentheses be removed for each time through the loop to the top. This
prevents infinite recursion because you will run out of parentheses if you remove a pair each time through.
You can think of it as leaving evidence of the recursion in the form of the parentheses. Note how you can
immediately tell that every sentence in the languages begins and ends with a parenthesis.

<tree> ::= "(" <list> ")" // deal with parentheses


<list> ::= <thing> | <list> "," <thing> // do the list of things
<thing> ::= <tree> | <name> // things are more trees or names
<name> ::= ant | bat | cow | dog

3 Associativity and Precedence


Getting the parse tree to represent proper grouping when grouping delimiters like parentheses are missing
requires that we understand associativity and precedence. Modern C++ has a precedence hierarchy that
is over dozen levels deep. Here is where hierarchical design again shines prominently.

3.1 A Grammar for an Arithmetic Expression

This involves the five operators +, −, ∗, /, b (where b is exponentiation). Operator Associativity


determines the order of execution of homogeneous operators. The first four are evaluated left to right.
That is their associativity is left to right or left associative. Exponentiation in mathematics is done
right to left, that is, it is right associative. You can see in the grammar below by where the recursion
occurs in the statement. For <exp> the recursion of <exp> occurs to the left of the operator, while for
<mulpart> the recursion is on the right.
Operator precedence is rule for determining the order of execution of heterogeneous operators in an
expression. precedence is handled by grouping operators of same precedence in the same production. You
can see that + and - have the same precedence as does * and /. The operators with highest precedence
occur farther down in the grammar, that is, an expression is a sum of products which is product of
exponentiation.

7
3.2 Grouping with Parentheses

Finally, products of sums can be denoted by putting the sum in parentheses as in:

666*(42+496)*(x+y+z)

To get this affect the parenthesized expression is put in the same place that any variable could be put. In
order to return to the top of the grammar (see Tips section below) the parentheses act as a counter for
the number of times you return to the ”top” of the grammar.

<exp> ::= <exp> + <addpart> | <exp> - <addpart> | <addpart>


<addpart> ::= <addpart> * <mulpart> | <addpart> / <mulpart> | <mulpart>
<mulpart> ::= <group> ^ <mulpart> | <group>
<group> ::= <var> | ( <exp> )
<var> ::= X | Y | Z

Let’s look at a parsing of the expression Z - (X + Y)*X with this simplified version of the above
grammar:

<exp> ::= <exp> + <addpart> | <exp> - <addpart> | <addpart>


<addpart> ::= <addpart> * <mulpart> | <mulpart>
<mulpart> ::= <var> | ( <exp> )
<var> ::= X | Y | Z

8
Since this is a context free grammar the above grammar can be simplified by carefully replacing all
occurrences in the grammar of <var> with the right hand side of the production: <var> ::= X | Y | Z.
This gives us the simplified grammar:

<exp> ::= <exp> + <addpart> | <exp> - <addpart> | <addpart>


<addpart> ::= <addpart> * <mulpart> | <mulpart>
<mulpart> ::= X | Y | Z | ( <exp> )

3.3 Unary operators

Unary operators generally bind very tightly so they go close to the variables and grouping operators. Here
we have added unary minus:

<exp> ::= <exp> + <addpart> | <exp> - <addpart> | <addpart>


<addpart> ::= <addpart> * <mulpart> | <addpart> / <mulpart> | <mulpart>

9
<mulpart> ::= <unary> ^ <mulpart> | <unary>
<unary> ::= - <unary> | <group>
<group> ::= <var> | ( <exp> )
<var> ::= X | Y | Z

Notice that we allow things like −X, −−−X, and −(X). If we had done: <unary> ::= - <group>
| <group> instead we would not be allowed to recursively apply a unary operator. This would prevent
− − X from being in the language. In some circumstances this might be what you want. Implement
carefully.

3.4 An Example Problem

Let’s put it all together by solving a problem from an exam for a Computer Science Compilers Course:

Write an unambiguous grammar for the Zev language. In the Zev language a variable is one of
the letters Z, E, or V . The lowest precedence binary operator is + and it is evaluated left to
right. Then there are two binary operators # and % which have equal precedence but higher
precedence than +. They are also evaluated left to right and so are left associative. This
is also the binary @ operator which is of higher precedence and is right associative. The *
operator is a unary operator and applied on the left. Either brackets or parens can be used
for grouping. For example: [Z@[E#E]], [[Z]], *[[Z]%[E]%[V]], V#**V#*V, and E are in the
language.

The answer grammar is:

<zev> ::= <zev> + <pound> | <pound> // <zev> appears on left of +


<pound> ::= <pound> # <at> | <pound> % <at> | <at> // <pound> appears on left of #
<at> ::= <unary> @ <at> | <unary> // <at> appears on right of @
<unary> ::= * <unary> | <var> // * is applied to <unary> not <var>
<var> ::= Z | E | V | ( <zev> ) | [ <zev> ] // parens in same production with vars

4 How can Things go Wrong


The most common problems with grammars are:

• Using symbols in productions which are not in your alphabet. Don’t do this.
• Inescapable productions. We will talk about this briefly.
• Ambiguous grammars. This we will discuss in great detail.

4.1 Inescapable Productions

Consider these two simple grammars:

<exp> ::= <exp> + <pound> | <exp> - <pound> | <mul>


<mul> ::= <mul> * <var> | <mul> / <var> | <var>
<var> ::= X | Y | X

10
and

<exp> ::= <exp> + <pound> | <exp> - <pound>


<mul> ::= <mul> * <var> | <mul> / <var>
<var> ::= X | Y | X

The second grammar might look reasonable, but wait... given a <exp> how would you ever get rid of
<exp> since every right hand side contains an <exp>?! This means that you could never generate a sentence
that was devoid of the nonterminal <exp>! The second grammar is invalid because all of the right hand
side options contain the left hand side and so the production is inescapable.

4.2 Ambiguity

The processing of sentences in a language to get their meaning usually uses the parse trees. The parse
tree is a way to understand the structure of what was said in the sentence. If for a given grammar G
there exists a sentence in the language for which there is more than one parse tree then G is said to be
ambiguous. You only need one example sentence to make G ambiguous! Note that the language is not
ambiguous, the grammar is. Also note that it is OK for there to be more than one derivation for a sentence
using an unambiguous grammar. Derivation doesn’t make the grammar ambiguous, parse trees do.

<sentence> ::= X | <sentence> X | X <sentence>

This grammar is ambiguous because there exists a sentence that has more than one parse tree. For
example, XX has two parse trees:

and

Here is another way to get ambiguity for that language:

<sentence> ::= X | <sentence> <sentence>

Try the sentence XXX on above grammar. Can you can find two parse trees? The fix is just to do:

11
<sentence> ::= X | <sentence> X

Here is another very similar ambiguous grammar:

<binary-string> ::= 0 | 1 | <binary-string> <binary-string>

Here is a fix:

<binary-string> ::= 0 <binary-string> | 1 <binary-string> | 0 | 1

Ambiguity effects meaning:

<sentence> ::= <expression>

<expression> ::= <expression> + <expression> |


<expression> * <expression> |
<identifier>
<identifier> ::= X | Y | Z

These are in the language:

X
X + Y
X + Y * Z

While the first two expressions are fine, X + Y * Z has a multiple parse trees. We want the multiply to
be done first when we do a depth first traversal of the parse tree to extract the structure. How do we do
this? We need to control operator precedence. Here we have added to the ambiguous grammar above to
make multiply done before addition (BUT IT IS STILL AMBIGUOUS)

<sentence> ::= <expression>


<expression> ::= <term> | <expression> + <expression>
<term> ::= <identifier> | <term> * <term>
<identifier> ::= X | Y | Z

4.2.1 Ambiguity by Ill-specified Associativity

Operator Associativity determines the order of execution of homogeneous operators. Essentially is it left
to right or right to left. Here we have modified the grammar to be left to to right for both + and *.

<sentence> ::= <expression>


<expression> ::= <term> | <expression> + <term>
<term> ::= <identifier> | <term> * <identifier>
<identifier> ::= X | Y | Z

Suppose we want to have both + and - be of equal precedence? We can do that here:

12
<sentence> ::= <expression>
<expression> ::= <term> | <expression> + <term> | <expression> - <term>
<term> ::= <identifier> | <term> * <identifier>
<identifier> ::= X | Y | Z

Note: we cannot have two operators of the same precedence in which one is left to right associative
and the other is right to left associative. For example:

<sentence> ::= <expression>


<expression> ::= <term> | <expression> + <term> | <term> - <expression>
<identifier> ::= X | Y | Z

If we did then the grammar would be ambiguous. To see this assume for a moment that + is left to right
as normal but - is right to left. How do we parse: X+Y-Z? Is it evaluated as if it is (X+Y)-Z or is it
evaluated as X+(Y-Z)? Our grammar doesn’t tell us.
Interestingly, the Dangling Else Problem is essentially ambiguity through ill-defined associativity.
Finally, the grammar of the Perl language provides an interesting insight into associativity problems.
In Perl, the language allows for two kinds of if statements. The first is if ( test ) { statement } and the
second is statement if (test) . The grammar or Perl seems to inexplicably require braces in the first
case. But suppose the grammar for Perl had been designed so braces are not required in the first case.
What would happen? A little thought shows that the grammar without the braces is ambiguous. Let’s
walk through it. Assume the new grammar allows:

<stmt> ::= if ( <test> ) <stmt> | <stmt> if ( <test> )

Then how would an intermediate statement of the form:

if ( <test> ) <stmt> if ( <test> )

be parsed? Would it be the same as:

{ if ( <test> ) <stmt> } if ( <test> )

or would it be equivalent to :

if ( <test> ) { <stmt> if ( <test> ) }

4.2.2 Ambiguity by Infinite Loop

Why just adding stuff can be a bad idea: (infinite loop). We added a reference ”up the grammar” to an
earlier nonterminal. The result in a loop of <expression> → <term> → <expression> → <term> → ...
that can go on any number of times. Therefore there is more than one parse tree since you can pick to go
through the loop say 12 times or 317 times giving two different trees.

<sentence> ::= <expression>


<expression> ::= <term> | <expression> + <term>
<term> ::= <identifier> | <term> * <identifier> | <expression>
<identifier> ::= X | Y | Z

13
The fix is to mark each time through the loop by forcing something to be ”removed” from the sentence
each time. In this case we have parentheses:

<sentence> ::= <expression>


<expression> ::= <term> | <expression> + <term>
<term> ::= <identifier> | <term> * <identifier> | ( <expression> )
<identifier> ::= X | Y | Z

Now if you go through the loop 12 times you are nested 12 deep in parens but if you go through it 317
times then you are nested 317 deep.

4.2.3 Ambiguity by Multiple Paths

A grammar is ambiguous if you have two or more paths through the grammar to a symbol. For example
starting with <aardvark>:

<aardvark> :: = <cat> | <dog>


<cat> ::= <zebra>
<dog> ::= <zebra>

then you get at least two parse trees for <zebra> derived from <aardvark>. So this grammar is ambiguous.
Note that

<aardvark> :: = ( <cat> ) | <dog>


<cat> ::= <zebra>
<dog> ::= <zebra>

is NOT ambiguous since <zebra> must go through <dog> or it will pickup a set of parentheses ”marking”
that it went via <cat>.
In this next grammar just adding on stuff to a working grammar has created two ways to get from
expression to X making the grammar ambiguous.

<expression> ::= <term> | <expression> + <term> | <identifier>


<term> ::= <identifier> | <term> * <identifier>
<identifier> ::= X | Y | Z | <expression>

The first parse tree is:

<expression> -> <term> -> <identifier> -> X

The second is:

<expression> -> <identifier> -> X

In summary, there are three ways to get ambiguity.

• associativity:

14
<sentence> ::= X | <sentence> <sentence>

• infinite loop:

<expression> ::= <term> | <expression> + <term>


<term> ::= <identifier> | <term> * <identifier>
<identifier> ::= X | Y | Z | <expression>

• alternate routes:

<expression> ::= <term> | <expression> + <term> | <identifier>


<term> ::= <identifier> | <term> * <identifier>
<identifier> ::= X | Y | Z | <expression>

5 The Dangling Else


Here is the grammar for the dangling else problem. In this problem we want to make sure that we
always associate an else with last if. This prevents the ambiguity of not knowing which if an else
associates with. Let’s work through this. First note the ambiguity with the statement:

if ( exp ) if ( exp ) stmt else stmt

if you have the grammar:

stmt : IF ’(’ exp ’)’ stmt ELSE stmt


| IF ’(’ exp ’)’ stmt

Let’s now solve this my creating separate nonterminals for if-statements with a paired else and without.
Let a ”matched if” be one in which an else is matched with the the most recent unmatched if. Let an
”unmatched if” be an if with no matching else. This gives us 6 possible cases for an if-statement whose
then-part or else-part may also be an if-statement. They are:

IF ’(’ <exp> ’)’ <matched> // 1


IF ’(’ <exp> ’)’ <unmatched> // 2
IF ’(’ <exp> ’)’ <matched> ELSE <matched> // 3
IF ’(’ <exp> ’)’ <matched> ELSE <unmatched> // 4
IF ’(’ <exp> ’)’ <unmatched> ELSE <matched> // 5
IF ’(’ <exp> ’)’ <unmatched> ELSE <unmatched> // 6

To have our rule of ”the most recent unmatched if matches the else” we must discard rules 5 and 6. This
gives us a grammar like:

<stmts> ::= <stmts> <stmt> | <stmt>

<stmt> ::= <matched> | <unmatched>

<matched> ::= IF ’(’ <exp> ’)’ <matched> ELSE <matched>

15
| <other-stmts>

<unmatched> ::= IF ’(’ <exp> ’)’ <matched>


| IF ’(’ <exp> ’)’ <unmatched>
| IF ’(’ <exp> ’)’ <matched> ELSE <unmatched>

Here is a common mistake with the famous dangling else grammar:

<stmts> ::= <stmts> <stmt> | <stmt>

<stmt> ::= <matched> | <unmatched> | <other-stmts>

<matched> ::= IF ’(’ <exp> ’)’ <matched> ELSE <matched>


| <other-stmts>

<unmatched> ::= IF ’(’ <exp> ’)’ <matched>


| IF ’(’ <exp> ’)’ <unmatched>
| IF ’(’ <exp> ’)’ <matched> ELSE <unmatched>

In this case there is more than one way to get to <other-stmts>


Here is another common mistake with the dangling else grammar:

<stmts> ::= <stmts> <stmt> | <stmt>

<stmt> ::= <matched> | <unmatched> | <other-stmts>

<matched> ::= IF ’(’ <exp> ’)’ <matched> ELSE <matched>

<unmatched> ::= IF ’(’ <exp> ’)’ <matched>


| IF ’(’ <exp> ’)’ <unmatched>
| IF ’(’ <exp> ’)’ <matched> ELSE <unmatched>

Not only is this grammar incomplete it has a trap in it. Suppose you get to <matched> or <unmatched>
then you can never escape those two states.

6 The Power of Context Free and incomplete grammars


Another problem with grammars is they do not describe all the sentences of language you had in mind.
Let’s look at that along with the idea that a CFG is context free.
In a context free language you can make any substitution for a left-hand-side nonterminal suggested
by any production without regard to the context in which the nonterminal occurs. For example

<dogs> ::= corgi | other

means that anywhere a dog nonterminal occurs you can replace it with a corgi or an other. Let’s use this
mathematical property of grammars to see if there is a difference between two languages specified by these
two grammars.
What is the difference between La and Lb ?

16
L_a:
<sentence> ::= <exp>
<exp> ::= <term> | <exp> + <term>
<term> ::= <id> | <term> * <id>
<id> ::= X | Y | Z | ( <exp> )

L_b:
<sentence> ::= <exp>
<exp> ::= <term> | <exp> + <term>
<term> ::= <id> | <term> * <id> | ( <exp> )
<id> ::= X | Y | Z

Note that by using the rule of context-freeness we can transform the grammar of La to:

<sentence> ::= <exp>


<exp> ::= <term> | <exp> + <term>
<term> ::= <id> | <term> * <id> | (<exp>) | <term> * (<exp>)
<id> ::= X | Y | Z

so this adds <term> * (<exp>) that wasn’t in Lb . What is an example of this:

X*(Y)

Therefore X*(Y) is in La but not in Lb !!!


Here is another common mistake with the dangling else grammar:

<stmts> ::= <stmts> <stmt> | <stmt>

<stmt> ::= <matched> | <unmatched> | <other-stmts>

<matched> ::= IF ’(’ <exp> ’)’ <matched> ELSE <matched>

<unmatched> ::= IF ’(’ <exp> ’)’ <matched>


| IF ’(’ <exp> ’)’ <unmatched>
| IF ’(’ <exp> ’)’ <matched> ELSE <unmatched>

Not only is this grammar incomplete it has a trap in it. This is another case of an inescapable grammer.
Suppose you get to <matched> or <unmatched> then you can never escape those two states.

7 Tips for Grammar Writing


• There must be one of the alternations in a production that is not recursive. For example:

<list>::= <list> dogs | "(" <list> ")" | if <list> then dogs | my <list>

can never get rid of the ¡list¿ nonterminal since any replacement has a ¡list¿ in it. A fix would be
change the language:

17
<list>::= <list> dogs | "(" <list> ")" | if <list> then dogs | <other>

or

<list>::= <list> dogs | "(" <list> ")" | if <list> then dogs | cats

• Try to build your grammar from top to bottom. Each production only referring to nonterminals
farther down the page. If you do refer to a production up the page then make sure you tag the return
up the tree with some terminal as in the parenthesize expression example above.

• Build hierarchically. Each production can be used to handle a specific case. For example: Here is a
number:

<num> ::= <digit> <num> | <digit>


<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

Here we add a production for the signed number:

<signed> ::= + <num> | - <num> | <num> <--- added


<num> ::= <digit> <num> | <digit>
<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

Here we add a production for putting a nonzero digit at the beginning. How was 0 handled?

<signed> ::= + <num> | - <nznum> | <nznum>


<nznum> ::= <nzdigit> <num> | <digit> <--- added
<num> ::= <digit> <num> | <digit>
<digit> ::= 0 | <nzdigit>
<nzdigit> ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

8 Extended BNF
Extended BNF tries to make lists and optional arguments easy. Extended BNF uses metachars [], , (),
*, +

• optional elements (0 or 1 times) are denoted []

• grouping of alternatives are denoted ()

• sequences {}* means zero or more times (the star is called a Kleene Star)

• sequences {}+ means one or more times

Note: sometimes {} means {}*. EBNF often says nothing about precedence or associativity and this
is often defined with text about the operators. Here are a bunch of examples:

• {X} is zero or more X’s

18
• if <exp> then <stmt> [else <stmt> ] is a use of the optional designator.

• {<stmt>}+ is a list of one or more statements

• XX is another way to do 1 or more

• X { , X } is a comma separated list of X’s

• <num> { (+|-) <num> } This allows just a single number or an expression consisting of numbers
that are added and subtracted.

• { X ; } is the case of a list of semicolon terminated X’s

19

You might also like