This assignment focuses on formal semantics and its application to the construction of interpreters and compilers.
[[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 LOOPyields 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.
Before you tackle the remaining problems, please
Problems 4-7 involve nano-Java.
istore iload iconst iadd goto if_icmpeq label returnTo 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]
To get your interpreter started, you'll want to use the following
types and values.
<
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.
<
Because the Y combinator is not typeable in ML, you will not be able
to use it. Use the function [[fix]] from the lecture notes on the
lambda calculus. Also, you will need to beware of applicative-order
versus normal-order evaluation. Remember, in ML you can delay
something's evaluation by placing it under a lambda.
Eta-expansion is a good way to do this.
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.
Change type of answer ([[A]]) to be
Now
use your new interpreter, and the [[primes]] program
that is part of the nano-Java
compiler source code, to write
Note that you can get full credit for [[earlyPrime]] and for
correct semantic equations even if you do not get your whole
interpreter working.
@
Please check the types of your functions by including the following
lines after their definitions:
<[[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]]
This definition uses the [[E]] function; after you get your code
working, you should change over to the [[B]] function.
Your definitional interpreter should raise an exception if it is
given a program that is not meaningful.
[38 points]
[[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:
[[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.
[11 points]
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]
The submit script for this homework is ~cs152/bin/submit-sem.