Formal Semantics

New! Extended deadline! Due Thursday, April 12, at 11:59PM.

This assignment focuses on formal semantics and its application to the construction of interpreters and compilers.

Denotational Semantics

Problems 1-3 involve modifying the denotational semantics given in the lecture notes. For each problem, give only those parts of the semantics that have changed.
  1. Modify the "Locations and Environments" semantics on page 19 of the printed version of the lecture notes so that variables are automatically initialized to zero at the time they are declared.
    [7 points]

  2. Modify the "Gotos and Labels" semantics on page 23 of the printed version of the lecture notes so that A (answers) are the same as V (integers), and the answer given by a program is the value of the variable [[Answer]] at the end of termination. Hint: it is sufficient to give a definition of the [[done]] function.
    [7 points]

  3. Again, start with the "Gotos and Labels" semantics, but modify the language to add a print statement. Add a grammar rule
    [[stm ::= PRINT exp]]
    Let A, the type of answers, be the same as V list (list of integer), and assume you are given the constructors [[nil]] and [[cons]] on lists. (Simply add [[nil : V list]] and [[cons : V * V list -> V list]] to the list of predefined functions.) Finally change the semantics so that a program like this one:
            A := -5;
            LOOP: ; 
            PRINT A+5;
            A := A+1 ;
            IF A GOTO LOOP
        
    yields the answer cons(0, cons(1, cons(2, cons(3, cons(4, nil))))). That is, the answer yielded by a program should be a list, in order, of everything printed.
    Hint: just fiddling with the "done" function is not enough. Think about the semantics of the [[PRINT]] statement.
    Warning: There is no variable called [[Answer]], so don't try to use one.
    [11 points]
Each of these problems can be solved with a one- or two-line change to the denotational definitions given in class. For those of you who may wish to use TeX for your answers, the LaTeX source for the lecture notes is available online.

Applying semantics

In the remaining problems, you will apply ideas from both operational and denotational semantics to a tiny Java-like system: ``nano-Java.'' The nano-Java language does not really justify its name: it is like Impcore, but without even function definitions. But the implementation of nano-Java does justify the name; it is based on the Java Virtual Machine.

Before you tackle the remaining problems, please

Problems 4-7 involve nano-Java.

  1. Write, using the notation of formal operational semantics, a definition of the nano-Java Virtual Machine. Be sure to say what the machine configuration is, and what are acceptable final states, as well as giving transition rules. To avoid repetition, give transition rules for only the following instructions:
    istore iload iconst iadd goto if_icmpeq label return
    To save bookkeeping, your semantics need not account for the behavior of print. If you want to describe the behavior of the iprint instruction, I'll take it for extra credit (PRINT). [17 points]

  2. Using the ideas of continuation semantics, write a definitional interpreter for the nano-Java source language. The code for nano-Java is part of the nano-Java compiler source code Your code should be closely based on the definitional interpreter using expression continuations in the readings.

    To get your interpreter started, you'll want to use the following types and values. <>= type V = int datatype A = ANSWER of V (* answer is the value returned by a program *) type Ide = string type L = int (* location *) type Env = Ide -> L (* location of a variable *) type S = L -> V (* state == values in locations *) val upd : S * L * V -> S = fn (sigma, n, v) => fn n' => if n = n' then v else sigma n' type C = S -> A (* continuation *) type K = V -> C (* expression continuation *) @ The unusual declaration of [[A]] makes [[A]] generative: you will have to apply [[ANSWER]] to a value to produce an answer. This little trick will enable the type checker to help you; it will keep you from confusing values and answers. @

    The following three types define the meaning of a statement, the meaning of an expression in a value context, and the meaning of an expression in a control-flow context. An expression in a control-flow context should be a Boolean condition, and it takes two continuations: one to go to if the condition is true, and one to go to if the condition is false. <>= type Stm = Env -> C -> C type Exp = Env -> K -> C type Condition = Env -> C -> C -> C @ Your interpreter should rely on five mutually recursive functions.
    [[P]]The meaning of a program: an answer [[A]]
    [[S]]The meaning of a statement: [[Stm]]
    [[Ss]]The meaning of a sequence of statements: [[Stm]]
    [[E]]The meaning of an expression in a value context: [[Exp]]
    [[B]]The meaning of an expression in a control-flow context: [[Condition]]
    @ Please check the types of your functions by including the following lines after their definitions: <>= val _ = P : prog -> A val _ = S : stmt -> Env -> C -> C val _ = Ss : stmt list -> Env -> C -> C val _ = E : exp -> Env -> K -> C val _ = B : exp -> Env -> C -> C -> C @ Notes:

    Final note: this problem involves much more thought than programming; you can write a good solution by adding less than 40 lines of code to what is already provided. The hard part is mastering continuations.
    [38 points]

  3. One of the advantages of continuation semantics is the ease with which we can work with different kinds of answers. In this problem, you will make a very minor change to your interpreter that will enable you to answer questions about what values a program prints. You will use the modified interpreter to answer one such question.

    Change type of answer ([[A]]) to be

    [[type A = {printed : V list, returned : V}]]
    Change your interpreter so that it no longer prints anything. Instead, your interpreter should produce an answer of the new type [[A]], which tells you what the nano-Java program would have printed had it been executed on the original interpreter. You will need to change your semantic equations (the definitions of your four functions) to work with the new [[A]] type.
    Hints:

    Now use your new interpreter, and the [[primes]] program that is part of the nano-Java compiler source code, to write

    [[val earlyPrime : int -> bool =]] ...
    which determines whether [[k]] is in the first 20 primes by running the program and looking to see if [[k]] is printed.

    Note that you can get full credit for [[earlyPrime]] and for correct semantic equations even if you do not get your whole interpreter working.
    [11 points]

  4. Add to nano-Java, and to your definitional interpreter, the short-circuit Boolean operators [[AND]] and [[OR]], as well as Boolean [[NOT]].
    Keep in mind the following algebraic laws:
    if p && q then s1 else s2  ===  if p then if q then s1 else s2 else s2      
    if p || q then s1 else s2  ===  if p then s1 else if q then s1 else s2
    
    You should be able to discover a similar law for [[NOT]], and by thinking about the laws, you should be able to discover very simple semantic equations for the new operators.
    Again, you can get full credit for handling the new constructs correctly even if your full interpreter does not work.
    [9 points]

Extra credit:

What to submit

For each problem above, submit
  1. the changed parts of the semantics, either on paper or as part of the PostScript file sem.ps.
  2. the changed parts of the semantics, either on paper or as part of the PostScript file sem.ps.
  3. the changed parts of the semantics, either on paper or as part of the PostScript file sem.ps.
  4. your operational semantics, either on paper or as part of the PostScript file sem.ps.
  5. an interpreter in ujint.sml. This file should be complete and self-contained, including the definition of nano-Java and whatever else you need for it to work.
  6. a self-contained interpreter in ujintp.sml
  7. a self-contained interpreter in ujintb.sml
Please also submit a README file telling us what you have completed and how much time you spent.

The submit script for this homework is ~cs152/bin/submit-sem.