COEN 171
Principles of Programming Languages
Winter 2000
Page 34:
8.
Some languages distinguish between uppercase and
lowercase in identifiers. What are the pros and cons of this design decision?
Pro: having case sensitive
identifiers gives a much broader name space (more possible identifiers) and
avoids possible confusion for the programmer when two names that appear
different in the program are taken as the same by the compiler.
Con: case sensitivity
leads to small, hard to detect differences between identifiers, making the
program harder to read and potentially introducing errors.
I. Consider
the grammar given below
<pop> ::= [ <bop> , <pop> ] |
<bop>
<bop> ::= <boop>
| ( <pop>
)
<boop>
::= x | y | z
(a) What
are the nonterminal symbols?
<pop> <bop>
<boop>
(b) What
are the terminal symbols?
[ ]
, ( ) x y z
(c) What
is the start symbol?
<pop>
(d) Draw
a parse tree for the sentence (x).
(e) Draw
a parse tree for the sentence [(x),[y,x]].
Page 152 ff:
2c. Write EBNF and syntax graph descriptions for a C
switch statement.
<stmt> -> switch
( <int expr> ) {
case
<int const> : {
<stmt> ; }
{ case <int const> : { <stmt> ; }}
[ default : { <stmt> ; } ]
}
3a. Using the grammar in Example 3.2, show a parse tree
and a leftmost derivation for A := A * (B + (C * A))
<assign> --> <id>
:= <expr>
A
:= <expr>
A
:= <id> * <expr>
A
:= A * <expr>
A
:= A *
(<expr>)
A
:= A *
( <id> + <expr> )
A
:= A *
( B + <expr> )
A
:= A *
( B + ( <expr> ) )
A
:= A *
( B + ( <id> * <expr> ) )
A
:= A *
( B + ( C * <expr> ) )
A
:= A *
( B + ( C * <id> ) )
A
:= A *
( B + ( C * A ) )
5. Prove that the following grammar is ambiguous:
<S>
-> <A>
<A>
-> <A> + <A> | <id>
<id>
-> a | b | c
There
are two different parse trees for many expressions, for example, a + b + c
7. Describe, in English, the language defined by the
grammar:
<S>
-> <A> <B> <C>
<A>
-> a <A> | a
<B>
-> b <B> | b
<C>
-> c <C> | c
All sentences
consisting of one or more a’s followed by one or more b’s followed by one or
more c’s
10. Write a grammar for the language consisting of
strings that have n copies of the letter a followed by the same number
of copies of the letter b, where n > 0.
<S>
-> a <S> b | ab
13a. Compute the weakest precondition for the assignment
statement a := 2*(b – 1) –1 given the postcondition {a > 0).
Substitute
the right hand side of the assignment statement for a in the postcondition
2*(b-1) > 0
2b–2
> 0
2b > 2
b > 1
14a. Compute the weakest precondition for the following
sequence of assignment statements, for the postcondition given.
a := 2 *
b + 1;
b := a –
3
{b <
0}
Substitute the right hand side of the second assignment in the postcondition to get a postcondition for the first assignment, then substitute the right hand side of the first assignment in that postcondition to get the precondition.
a-3 <
0
a < 3
weakest precondition for first assignment
2*b+1
< 3
2b < 2
b < 1
16. What is the difference between an intrinsic
attribute and a nonintrinsic synthesized attribute?
An
intrinsic attribute is an inherent characteristic of a terminal symbol in the grammar
(e.g., an identifier in a program). So the value of the attribute is determined
solely from the terminal symbol. A nonintrinsic synthesized attribute is an
attribute of a non-terminal symbol in the grammar. It’s value depends on the
values of the attributes in the children of that non-terminal symbol’s nod in
the parse tree.