Long Quiz3 ( 45mins) Name: Person Number: Generating parse tables Calculating First and Follow sets Problem 1. (20pts) Parser Technology First andagain Follow an fexample a) Look at our sets: grammar or well-­‐matched bracket sequences: S → epslon | TS Look again at our grammar for well-matched bracket sequences: T → (S) S → � | TS T → (S) Please write down First set of S and T, and Follow Set of S and T (considering LL(1) parser) By inspection, we can see that First(S) = { (, � } First(T ) = { ( } Follow (S) = { ), $ } because an S can begin with ( or be empty because a T must begin with ( because within a complete phrase, an S can be followed by ) or appear at the end Follow (T ) = { (, ), $ } because a T can be followed by ( or ) or appear at the end Later we’ll give a systematic method for computing these sets. Further convention: take First(a) = {a} for each terminal a. b) Say you have an xml document <?xml version='1.0' encoding='us-ascii'?> <slideshow title="Sample Slide Show" date="Date of publication" author="Yours Truly" > <slide type="all"> <title>Wake up to WonderWidgets!</title> </slide> <slide type="all"> <title>Overview</title> <item>Why <em>WonderWidgets</em> are great</item> <item/> <item>Who <em>buys</em> WonderWidgets</item> </slide> </slideshow> Please convert it to Context Free Grammar for parsing. 7 / 16 Xml -­‐> SlideShow SlideShow -­‐> SlideList SlideList -­‐> Slide SlideList Slide -­‐> Title | Title ItemList ItemList -­‐> Item ItemList | epslon Problem 2. (20pts) Analysis of Definition The Fibonacci function F(n) defined for natural numbers n is as follows. F (n) = 0 if n = 0 = 1 if n = 1 = F(n-­‐1) + F(n-­‐2) otherwise Define an SML-­‐function cntCalls that computes the number of calls to F generated for various input values. (E.g., cntCalls(0) = 1, cntCalls(3) = 5, etc.) What are the values of F(5) and cntCalls(5)? fun cntCall 0 = 1 | cntCall 1 = 2 | cntCall n = cntCall(n-­‐1) + cntCall(n-­‐2) ; Problem 3. (20pts) Understanding Function Definition fun f [] = [] | f (x::xs) = let val s = f xs in (map (fn y => y@[x]) s) end; a) What is the signature of f ? f = fn : 'a list -­‐> 'a list list b) Informally describe the list function computed by f. Give the value and type returned for f ["a"]? -­‐ f["a"]; val it = [] : string list list c) Now formalize what f does using the Induction Principle. There are 2 rules here: 1) x : x ' xs : xs' f : ! y@ys :[y', ys']. f (ys)@y x@xs :[x ', xs'] f (x@xs :[x ', xs']) : [a' list, x '] Where a’ is type variable mapping f(xs’) -­‐> a’ 2) x : x ' xs : Nil f : ! y : Nil. Nil x@xs : x ' f (x@Nil) : x ' Problem4. (20 pts) Writing Function Definition The following SML-­‐definition specifies two concrete datatypes etype and expr. datatype etype = Int | Real; datatype expr = I | J | A | B | Plus of (expr * expr) | Mul of (expr * expr); The type of I and J is Int. The type of A and B is Real. The type of a Plus-­‐ expression is Int, if the subexpressions have Int type; otherwise it is an error. (E.g., if both arguments are Real, it is an error!) The type of a Mul-­‐expression is always Real as long as the subexpressions are well-­‐typed; otherwise it is an error. (Note, a subexpression is well-­‐typed if its type either Int or Real.) Write an SML-­‐function typeInfer that infers the type of an expression whereever feasible (according to the specified notion of type inference) and throws an exception called Error otherwise. For example, -­‐ typeInfer I; val it = Int : etype -­‐ typeInfer (Mul (A,Plus(J,I))); val it = Real : etype -­‐ typeInfer (Mul (A,Plus(B,J))); Upcasting In Chapter 14 you saw how an object can be used as its own type or as an object of its base type. In addition, it can be manipulated fun typeInfer e = of the base type. Taking the address of an through an address object (either case ea opointer f or a reference) and treating it as the address of the I =base > Int type is called upcasting because of the way inheritance trees | Pare lus(e1, e2) => Rthe eal base class at the top. drawn with | Mul(e1, e2) => Real ; You also saw a problem arise, which is embodied in the following code: //: C15:Instrument2.cpp // Inheritance & upcasting Problem 5. (20pts) Please write down result of following program. #include <iostream> using namespace std; enum note { middleC, Csharp, Eflat }; // Etc. class Instrument { public: void play(note) const { cout << "Instrument::play" << endl; } }; // Wind objects are Instruments // because they have the same interface: class Wind : public Instrument { public: // Redefine interface function: void play(note) const { cout << "Wind::play" << endl; } }; void tune(Instrument& i) { // ... i.play(middleC); } int main() { Wind flute; tune(flute); // Upcasting } ///:~ Thinking in C++ 662 www.BruceEckel.com The function tune( ) accepts (by reference) an Instrument, but also Instrument::play without complaint anything derived from Instrument. In main( ), you can see this happening as a Wind object is passed to tune( ), with no cast necessary. This is acceptable; the interface in Instrumentmust exist in Wind, because Wind is publicly inherited from Instrument. Upcasting from Wind to Instrumentmay “narrow” that interface, but never less than the full interface to Instrument. The same arguments are true when dealing with pointers; the only difference is that the user must explicitly take the addresses of objects as they are passed into the function.