In this part of the project you will write an interpreter which will translate programs that do not contain functions.
We need an environment for storing variables. I have provided you with a module Dictionary. A dictionary is a data structure that stores values associated with "keys". For our purpose, the key will be a variable name and the value will be the numeric value of that variable.
If you look at the Dictionary module you will see that the
Dictionary is actually a list of pairs, [(a,b)] , where a is the type of the
keys and b is the type of the values. We have functions:
empty :: Dictionary a b -- returns an empty Dictionary
lookup :: a ->
Dictionary a b -> Maybe b -- gives the value associated with key if it
exists
insert ::
(a,b) -> Dictionary a b -> Dictionary a b -- gives a new dictionary with
the pair inserted
You will need to add the line
import qualified Dictionary
to the Interpreter module.
We will define the following data types:
data Value = Val
Integer
type
Environment = Dictionary.T String Value
Our Environment is a dictionary where the keys are Strings
(variable names) and the values are our defined type Value. This may seem
a bit awkward. Why not just let the values be Integers? This is
because our environment will get more complex as we continue with the project.
We need a function which will give us the
value of an expression. So if the variable x contains the value 2, the
expression 2 * x + 1 will evaluate to 5.
You need to write the function
value :: Expr -> Environment -> Integer
Recall that an expression is of the data type
data
Expr = Num Integer | Var String | Add Expr Expr | Sub Expr Expr |
Mul Expr Expr | Div Expr Expr | Func String [Expr]
deriving Show
Your definition of value
will therefore use pattern matching of the first argument for each of the cases
(except omit Func for now). For example:
value (Num n) env = ...
value (Var v) env =
...
value (Add e1 e2)
= ...
...
You should
use the integer division operator `div` to perform the division. For
example 5 `div` 2 will return 2 (rather than 2.5).
If the
expression contains a variable which is not defined, you should produce an error
message. If the expression contains division by zero you should also
produce an error message.
We need a function which execute a list of statements.
You will need to write the function
exec :: [Statement] -> Environment -> [Integer] ->
([Integer], Environment)
The arguments to exec are a list of statements, the current environment, and a list of integers containing the numbers that are read by the read statements. The result is a pair containing the list of numbers produced by the write statements and the altered environment.
The function exec will be defined using pattern matching on the first argument for each type of statement. For example for an assignment statement,
exec (Assignment var expr : stmts) env input =
exec stmts env' input
where
v = (value expr env)
env' = changeVar var v env
This performs a recursive call to execute the
rest of the statements in the list. This recursive call uses the changed
environment, env' produced by the function changeVar which puts the new
value into the environment and is defined as follows:
changeVar ::
String ->
Integer ->
Environment ->
Environment
changeVar var val env
= Dictionary.insert (var,Val val)
env
For each kind of statement there will be a recursive call. The write statement will add a value to the returned list. You will not be implementing the return statement at this time.
The following code will parse an input list (separated by spaces) and run your program.
--
An input list represented by InputList is a series of input values entered
-- at
the keyboard by the user running a program
newtype InputList =
Input [Integer]
nums =
number # iter number >->
cons
input =
nums >->
buildInput
buildInput
nums = Input nums
instance Parse
InputList where
parse = input
-- The main program executes the interpreter and runs the program
run :: Program
-> InputList -> [Integer]Send me your modified zipped project in the dropbox in BlackBoard.