CS558 Homework #3
Due 5:00 PM, Monday, January 26, 2015

Homework must be submitted via D2L. All submitted files (5 for this assignment sol3A.e3, sol3B.hs, sol3C.hs, sol3C.e3, sol3D.pdf ) must be submitted in the appropriate D2L directory in the drop box HW2. It is your responsibility to submit the homework in the proper format with the proper names. For example.

-- Homework 3  Tom Smith   tom_smith@gmail.com

All programs mentioned can be downloaded from the this document

All the questions concern a simple language with imperative expressions, functions, global variables, and pairs, which we'll call E3. Its "concretized" abstract syntax is given by the following grammar:

prog := '(' { def } ')' exp
def := globaldef | fundef
globaldef := '(' 'global' var exp ')'
fundef := '(' 'fun' fname '(' { var } ')' exp ')'
exp := var
| int
| '(' ':=' var exp ')'
| '(' 'while' exp exp ')'
| '(' 'if' exp exp exp ')'
| '(' 'write' exp ')'
| '(' 'block' { exp } ')'
| '(' '@' fname { exp } ')'
| '(' '+' exp exp ')'
| '(' '-' exp exp ')'
| '(' '*' exp exp ')'
| '(' '/' exp exp ')'
| '(' '<=' exp exp ')'
| '(' 'pair' exp exp ')'
| '(' 'fst' exp ')'
| '(' 'snd' exp ')'
| '('  'ispair' exp ')'
fname := letter { letter | digit }
var := letter { letter | digit }

As before, comments may be included by enclosing them between comment braces '{-' and '-}' characters, and they may be nested.

The informal semantics of E3 programs is as follows. Values include integers and pairs, each of which has a left and a right component value. A program (d1 ... dn) e is evaluated by elaborating each definition d1 , . . . dn in that order and then evaluating the top-level expression e , whose value is the program result. A global definition (global x e ) is elaborated by evaluating its initializing expression e to a value v and extending the variable environment with a binding from x to v . A function definition is elaborated by recording the function name in an environment of available functions.

Functions and variables live in separate name spaces, so their names may overlap. The language uses a combination of static and dynamic scope rules. Function names are handled dynamically; the most recently elaborated definition with a matching name is used. Global variable names and the formal parameters of functions are statically scoped. A global variable's scope reaches from its definition to the end of the file in which it appears. The scope of a formal parameter is statically limited to the body of the function. If a second global variable has the same name as a previous global, the second hides the first. In a similar manner, if a formal parameter has the same name as a global, the parameter hides the global. It is a checked runtime error to use an undefined function or variable name.

The semantics of E3 expressions are similar to those of E2, with the following extensions:

An E3 interpreter in Haskell (only) has been provided ( hw3.hs ).

As usual, it reads a file containing an E3 program in the syntax described above, echoes the program (to confirm correct parsing), evaluates the program (possibly producing output from write expressions), and displays the evaluation result, and then enters a READ-EVAL-PRINT loop. Users may type in expressions and see what they evaluate to. To exit the loop type ":q", one may also flip the tracing mode by typing "trace".

What you should do.

  1. (A) Pairs and Lists: sol3A.e3

    Write the following list-manipulation functions in E3. Put both your function definitions and a test expression that exercises them in a single file sol3A.e3 and submit that file. Some useful list manipulation examples are in lists.e3 . You may find it easier (or just more fun!) to write your solutions in recursive functional style (like the append example) rather than in imperative style (like gen and length).

  2. (B) Local variables: sol3B.hs

    Modify the E3 interpreter to support local variables, by adding a new expression form:

    exp := ...
         | '(' 'local' '(' { var exp } ')' exp ')'
    
    where the parenthesized list specifies a set of local variable names and associated initializing expressions.

    The informal semantics of (local ( x1 e1 ... xn en ) e) is as follows: evaluate e1 ,. . . , en in that order, bind the resulting values to newly created local variables x1 , . . . , xn respectively, then evaluate e in the resulting environment, and yield the resulting value. (Do not worry about what happens if two of the variables have the same name.)

    The scope of the local variables is just the expression e . If a local variable has the same name as a parameter or global, it hides the parameter or global.

    For example, the program

    (
    (global a 10)
    )
    (local (a 1 b a)
    (block
    (local (a 100)
    (block
    (:= b (+ a b))
    (:= a 0)))
    (+ a b)))
    

    should evaluate to 111 .

    Most of the necessary parsing support is already present in hw3.hs . All you have to do is

    Put your solution in a file sol3B.hs. Hint: You don't need to introduce an additional environment component for local variables; just use the existing vars environment which currently holds parameters. You might want to study the interpE case for (At f args) (near line 213). The function application case has some similar components to the local case. Remember that local expressions can be nested. (25 points)

  3. (C) Mutable pairs: sol3C.hs and sol3C.e3
    1. Further modify the E3 interpreter you produced for the local variable problem, by adding two new expression forms to the E3 language:

      exp := ...
           | '(' 'setfst' exp exp ')'
           | '(' 'setsnd' exp exp ')'
      

      Most of the necessary parsing support is already present in hw3.hs . All you have to do is

      • Add the AST (add a cases to the data for Exp for setfst and setsnd).
      • Parsing replace the "error" calls in "setfst" and setsnd with your constructors (near line 394 and 397).
      • Printing add cases for "setfst" and "setsnd" in ppExp (near line 540). Model after the case for Pair (line 557) which also has two arguments.
      • evaluation code (add a cases to interpE) for setfst and setsnd (near line 297).

      The informal semantics of these expressions is as follows. To evaluate (setfst e1 e2) , first evaluate e1 to a value v1 , which must be a pair, then evaluate e2 to a value v2 , then update the left component of v1 with v2 , and yield the (updated) pair v1 as result. setsnd is similar, except that the right component of v1 is updated. For either expression, it is a checked runtime error if v1 is not a pair.

      Note that the value printing code can now go into an infinite loop for some programs that use setfst and setsnd; don't worry about this. Put your solution in a file sol3C.hs (25 points).

    2. Test your solution to part (b) by writing an E3 function nreverse that reverses a list in place , that is, without constructing any new pairs. Hint: You'll need setsnd but not setfst. Again, your can use either a functional recursive style or an imperative style. Submit a test program defining and using nreverse called sol3C.e3 (10 points).

  4. (D) Formal Operational Semantics: sol3D.pdf

    This problem can be written using paper and pencil, scanned and then submitted. You are are also allowed to use any other tools that will let you create a *.pdf document for submission. Consider the operational semantics rules presented in lecture.

    1. Write down a rule for the block expression form of E3. For simplicity, assume that each block has exactly two sub-expressions.

    2. Write down a rule for a new expression form (alias x1 x2 e ) , whose informal semantics is as follows: make the newly created local variable x1 an alias to the existing variable x2 , evaluate e in the resulting environment, and yield the resulting value. Note that alias is not the same as local : when two variables are aliased, they refer to the same location. (Note: A simple variable aliasing form like this is not very useful, but many real languages introduce aliasing less directly -- although this is often considered a bad feature, because it makes it easy to write confusing programs.)

    3. Write down the full derivation tree for the following judgment:
      <(local x 1 (block (alias y x (+ (:= x 3) (:= y 5))) x)),Ø,Ø> ¥ <5,Ø>
      

      Use symbolic names (e.g., l1 ; l2 ; ... ) for locations. When writing concrete environments and stores, use set notation, e.g. { x -> lx ; y -> ly } for the environment E where E ( x ) - lx and E( y ) - ly . Write Ø for the empty environment or store. (Hint: use a pencil and a broad sheet of paper. Your completed tree should have ten nodes.). Submit your answer as file sol3D.pdf (15 points) to D2L.