RU beehive logo ITEC dept promo banner
ITEC 380
2015fall
ibarland

homelecturesrecipeexamshwsD2Lbreeze (snow day; distance)

hw07
Interpreting Q
project

The full Q1,Q2 (both racket and Java for Q1, plus any add'l tests) due Nov.30 (Mon) 14:00. It is strongly recommended to complete this before Thanksgiving break, so you can either not worry about it, or (if you really want to put in some hours over the break) get a head-start on hw08.
However, these test cases are due Nov.20 (Fri) 14:00.

Over the course of several homeworks, we'll implement a “tower” of languages (Q0, Q1, …, Q6) each language incorporating more features than the previous. Q0 is provided for you.


  1. (15pts) Implement Q1 in both racket, and Java. Q1 is just like Q0, but with two additional types of expressions:

    Expr ::=  | IfZeroExpr
    IfZeroExpr ::= if Expr is zero then Expr else Expr @
    
    BinOp ::=  | mod
    
    Update parse, toString (a.k.a. expr->string), and eval appropriately, for both the racket and Java implementations. Be sure to write test cases first.

    The only method which cares what these new expressions mean (their semantics) is eval:

    Complete two versions of Q1: both racket, and java. (For Q2 and beyond, you can choose which implementation to continue.)

  2. (25pts) Implement Q2 in either racket or Java (your choice). Q2 adds identifiers to Q1:

    Expr ::=  | Id | LetExpr
    
    LetExpr ::= say Id be Expr in Expr matey    // Subject to votes in class, for exact syntax.2
    
    where Id can be any series of letters and digits which isn't interpretable as a number3. (Assume for now that any nested let expressions use different Ids. We'll handle shadowing in Q3, later.)

    Update your three methods parse, toString (a.k.a. expr->string), eval.

    In order to write eval, we need to define the semantics of say Id be E0 in E1 matey:

    Observe that when evaluating a (legal) Q2 program, eval will never actually encounter an Id -- that Id will have been substituted out before we ever recur down to it.

    In order to make a substitution in an Expr parse-tree, write a helper function that does only substituting (and does not do any evaluating in any way). This task would be similar to taking an Ancestor-tree, and replacing every blue-eyed Child with a brown-eyed one. (The only difference is that an AncTree had only two cond-branches, while Expr has around seven, though the code for most of those are very similar.)

    For example: say x be 5 in (x add 3) matey(5 add 3)86. Be sure to write test cases for your substitution function before you write its code; include several trivial and easy tests, along with a couple of more complicated nestings and one deeply nested expression.

    You can choose implement Q2 in either in Racket, or in Java.


    Repeating the steps above in more words: For Q2, you will:


1 Because we don't need to check for bad inputs, it's fine to have your interpreter crash if y=0. If you prefer to "control" crash — creating a meaningful error message and calling error or throw yourself — you are also welcome to do that.      

2 In class, we will choose one of the following or (most likely) a variant, as a class:

ML-like: let x = 2+3 in x*9 end;
lisp-like: (let {[x (+ 2 3)]} (* x 9))
lisp-like, simplified: (let x (+ 2 3) (* x 9))
C#-like: using (var x = 2+3) { return x*9; }
javascript-like: var x = 2+3; return x*9;
Java-like: { int x = 2+3; return x*9; }
Haskell-like: * x 9 \n where x = + 2 3 \n
Another option for the assignment-character is “:=” (Ada,Pascal), or “” (indicating which way the data flows), or even something like “ExprId { }” (which might make CS1 students happier — the processing happens left-to-right, just like we read the statement). Or, if we want to include emoji keywords, good candidates are the entries on this page which have the left-most column “native” filled in.

Note that you can (and should) test and write a “substitute” function w/o worrying about the exact syntax of a LetExpr. Substituting one thing in a tree for another is its own independent task, de-coupled from eval'ing a local-binding statement.

     

3 Note that our different implementations are now varying by more than just precision of arithmetic: in a Java implementation, NaN is a Num, and in a racket implementation it's an Id. We won't use any test cases involving such subtle differences. However, note how our choices in designing a new language are being influenced by the language we're trying to easily implement it in! This stems from the fact that a primary design constraint on P is that implementing an intepreter for P doesn't get bogged down in minutae when using either Java or Racket.      

5 For example: what if a Q2 programmer uses a variable named “mod” or “say” or “fun” [which we might make into a keyword in the future]? While it's not advisable for somebody to do this, and perhaps our parse should disallow this, our eval shouldn't give wacky results in this situation.      

4 All our real code should work on the parse tree itself. String-substitution (like C pre-processor macros) can't be generalized to handle shadowed variables (scope) for Q3, and is in general fraught with error5. A local-variable construct which requires globally-unique names isn't very impressive!      

6 The notation “say x be 5 in (x add 3) matey5 add 38” is shorthand for

  eval(parse("say x be 5 in (x add 3) matey"))
= eval(parse("(5 add 3)"))
= eval(parse("8"))
Observe how we definitely don't write “"say x be 5 in (x add 3) matey" = "(5 add 3)" = 8” since the two strings are not .equals(·) to each other, and strings are never ints. More specifically: we distinguish between “” (“code evaluates to”) and “=” (“equals”, just as “=” has meant since kindergarten).      

homelecturesrecipeexamshwsD2Lbreeze (snow day; distance)


©2015, Ian Barland, Radford University
Last modified 2015.Dec.05 (Sat)
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Rendered by Racket.