CS 132, W10, Midterm Exam, Answers
==================================
Q.1: Here is a sequence of transformations of the grammar.
A ::= A x B | C y
B ::= z A y
C ::= x A | epsilon
------> (inline B and C into A)
A ::= A x z A y | x A y | y
------> (left recursion elimination)
A ::= ( x A y | y ) ( x z A y )*
------> (implement * via the new nonterminal D)
Nullable First Follow x y z EOF
A ::= x A y D | y D No x y y EOF x A y D y D -- --
D ::= x z A y D | epsilon Yes x y EOF x Z A y D eps -- eps
In the final grammar, the two productions for A have
disjoint First sets ({x} and {y}).
For the first productions for D, we have that the First set is {x},
while the other is epsilon and so we should consider Follow(D) = {y, EOF}.
We see that {x} and {y, EOF} are disjoint.
In summary, the final grammar is LL(1).
Q.2: Yes, the grammar LL(1).
Nullable First Follow
A ::= C z | x B No x y z z EOF
B ::= x C No x z EOF
C ::= y A | epsilon Yes y z EOF
Follow(A) <= Follow(B) <= Follow(C) <= Follow(C)
so Follow(A) = Follow(B) = Follow(C)
The two productions for A have disjoint First sets ({y} and {x}).
For the first productions for C, we have that the First set is {y},
while the other is epsilon and so we should consider Follow(C) = {z, EOF}.
We see that {y} and {z, EOF} are disjoint.
In summary, the grammar is LL(1).
Q.3: void eat(Token t) {
if (next_token == t) { next_token = get_next_token(); }
else { throw new Exception(); }
}
void A() {
if (next_token == 'x') {
eat(x); A();
}
else { // next_token in {y,z}
B(); eat(y);
}
}
void B() {
if (next_token == 'z') {
eat(x); C();
}
else { // next_token in {x,y}
/* do nothing */
}
}
void C() {
eat(z); A(); eat(x);
}
void main() {
next_token = get_next_token();
A();
if (next_token != EOF) {
throw new Exception();
}
}