Description
Lab goals
This lab will explore the interpreter that we wrote in lecture and
extend it a bit. This is based on “denotational semantics”. This is a
mechanism for defining the semantics of imperative programs in which
the meaning of a program is seen as a state transformation function.
You can read more about denotational semantics in the paper
[“The Denotational Semantics of Programming Languages”](https://github.umn.edu/umn-csci-2041-S18/public-class-repo/blob/master/Resources/Denotational_Semantics_Tennent.pdf) by
R. D. Tennent. This paper is also in the Resources directory in the
public class repository.
## Getting started.
Copy the file “interpreter.ml“ from either the
“Sample Programs/Sec_01_1:25pm“ or
“Sample Programs/Sec_10_3:35pm“ directory of
the public class repository into a
new directory named “Lab_12“. Name the copy of this file
“interpreter.ml“.
## Review
Open the file and familiarize your self with the data types and the
functions “eval“ and “exec“.
Run “exec program_while []“. And enter “10“. How many times does
“sum“ appear in the final state?
Create a let-binding in your file of the from
“`
let num_sum = …
“`
where “…“ is replaced by the number of times that “sum“ appears
in the final state.
## Add a conditional statement — if-then-else
Add a new constructor of the following form to “stmt“:
“`
| IfThenElse of expr * stmt * stmt
“`
Then write to clause for this new constructor in the “match“
expression in “exec“.
Next, add a modulus operator constructor to “expr“:
“`
| Mod of expr * expr
“`
Then write the clause for this new constructor in the “match“
expression in “eval“.
Hint: in OCaml, “mod“ is the infix operator for modulus. Try it out
in “utop“.
## Another program
Construct a new program of type “stmt“ named
“program_while_ifthenelse“. It should correspond to the following
comment already in “interpreter.ml“. Note how “program_seq“ and
“program_while“ both have similar comments for them. You need to
construct a let-binding for “program_while_ifthenelse“ that
corresponds to the program in the comment below:
“`
(* read x;
i = 0;
sum_evens = 0;
sum_odds = 0;
while (i < x) {
write i;
if i mod 2 = 0 then
sum_evens = sum_evens + i;
else
sum_odds = sum_odds + i;
i = i + 1
}
write sum_evens;
write sum_odds
*)
```
## Test your extended ``exec``
Run ``exec program_while_ifthenelse []`` and enter ``8`` when prompted to enter a
number.
It should print out the integers from 0 to 7 and the print 12 and then
16.
Run ``exec program_while_ifthenelse []`` and enter ``15`` when prompted. Then
create the following let-bindings in your file:
```
let val_sum_evens =
let val_sum_odds =
let num_sum_evens =
let num_sum_odds =
```
+ give ``val_sum_evens`` the value of ``sum_evens`` in the final state
+ give ``val_sum_odds`` the value of ``sum_odds`` in the final state
+ give ``num_sum_evens`` the number of times ``sum_evens`` appears in
the final state
+ give ``num_sum_odds`` the number of times ``sum_odds`` appears in
the final state
## Create a testable version of ``program_while_ifthenelse``
Define ``program_while_ifthenelse_test`` in your file to be the same as
``program_while_ifthenelse``, but replace
```
ReadNum "x"
```
with
```
Assign ("x", Val (Int 12))
```
The following should evaluate to ``Int 30``
```
lookup "sum_evens" (exec program_while_ifthenelse_test [])
```
## Add a skip statement
Add the following constructor to ``stmt``:
```
| Skip
```
This is a "skip" statement that does nothing. It is like ``pass`` in
Python or a "noop" in assembly language.
Complete the implementation of ``exec`` to handle this new
construct.
Also, re-implement the ``IfThen`` construct based on the
observation that executing "if ...cond... then ...stmt..." is the same
as executing "if ...cond... then ...stmt... else skip".
Next, define ``program_ifthen`` to correspond to to the following comment:
```
(* y = 0;
if x mod 2 = 0 then y = y + 2;
if x mod 3 = 0 then y = y + 3;
if x mod 4 = 0 then y = y + 4;
*)
```
Now try ``exec program_ifthen [ ("x",Int 4) ]``.
For example ``lookup "y" (exec program_ifthen [ ("x",Int 4) ])`` should
evaluate to ``Int 6``.
## Add a for loop
Next, add the following ``stmt`` constructor
```
| For of string * expr * expr * stmt
```
that represents a for-loop with a name of the integer counter (the ``string``)
and the lower and upper bounds (the two ``expr`` components) and the
body of the loop (the ``stmt``).
Complete the implementation of ``exec`` to handle this new
construct.
Define ``program_for`` to be
```
For ("i", Val (Int 1), Val (Int 5), WriteNum (Var "i"))
```
When run, this will print out the values 1, 2, 3, 4, and 5. You can
see the bounds are inclusive.
Add the following declaration to your file:
```
let program_sum_10 =
(* sum = 0
for i = 1 to 10
sum = sum + i
write sum
*)
Seq (Assign ("sum", Val (Int 0)),
Seq (For ("i", Val (Int 1), Val (Int 10),
Assign("sum", Add (Var "sum", Var "i"))),
WriteNum (Var "sum")
) )
```
Run it to check that ``55`` is displayed.
Consider this alternate version. It should print out ``55`` two
times. Why is that? Ensure that your implementation of the for-loop
gives this same behavior.
```
let program_sum_10_n =
(* n = 10
sum = 0
for i = 1 to n
sum = sum + i
n = sum
write sum
write n
*)
Seq (Assign ("n", Val (Int 10)),
Seq (Assign ("sum", Val (Int 0)),
Seq (For ("i", Val (Int 1), Var "n",
Seq (Assign("sum", Add (Var "sum", Var "i")),
Assign("n", Var "sum")
)
),
Seq(WriteNum (Var "sum"),
WriteNum (Var "n")
) ) ) )
```
## Repeat-until
If time allows, attempt this optional task. Add a repeat-until loop.
It consists of a ``stmt`` and ``expr``. It executes the loop body
first, then does the check. It keeps looping until the ``expr``
evaluates to true.
You might use this as the constructor in ``stmt``:
```
| Repeat of stmt * expr
```
## Push your work.
Now be sure to commit and push your work. Check the feedback file
that should be generated each time you push this work.