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(); } }