CS 224 Project - Part 2

In this part of the project you will write an interpreter which will translate programs that do not contain functions.

The Environment

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.

Evaluating Expressions

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. 

Executing Statements

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.

Running the Interpreter

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
       
main =
           
do putStr "Filename: "
            name <-
getLine
           
contents <- readFile name
           
putStr "Input: "
           
input <- getLine
            putStr (show
(run (fromString contents) (fromString input)))

        run :: Program-> InputList -> [Integer]
        run (Program funcs stmts) (Input input) =
           
fst
(exec stmts Dictionary.empty input)

Send me your modified zipped project in the dropbox in BlackBoard.