# Compiling Variables A variable is identified by an alphanumeric string. We can store this as a list of pairs, with the variable's identifier and its value. Variable Environment or VarEnv - `[(Identifier, Stack Address)]` A stack address is an integer value that specifies where in the stack that variable is contained. The bottom of the stack is reserved for variable values. The bottom of the stack is indexed `0`. Let's say our environment consists of 3 variables named x, y, z. It would look like: `[("z",2), ("y",1), ("x",0)]` | Variables | Stack (Values) | Index | | :-------: | :------------: | :---: | | x | 7 | 0 | | y | 2 | 1 | | z | 9 | 2 | To get the value of a variable from the stack, TAM uses the instruction `LOADL a` where `a` is a stack address. `LOADL` will get the value and copy the value to the top of the stack. `LOAD a` - copy address a to top of stack `STORE a` - pop top of stack to address a For example, if `LOADL 2` is called, it will affect the stack in the following way: | Variables | Stack (Values) | Index | | :-------: | :------------: | :---: | | x | 7 | 0 | | y | 2 | 1 | | z | 9 | 2 | | | … | | | | 9 | | ```haskell expCode :: VarEnv -> Expr -> [TAMInst] ``` Before, we just called the abstract syntax tree `AST`; however, with the extended grammar, we will now have multiple ASTs: one for programs, one for commands and one for expressions. The AST for expressions we call `Expr`. Remember in our compiler, the stack is represented and stored as a list, with the top of the stack being the head of the list. ## Declaration of Variables ```js let var x; //no value given means initialised to 0 var y := 5 //note no semicolon var z; in ... ``` For the code above, we need to generate a VarEnv. The compiler needs to generate a variable environment and TAM code. VarEnv: `[("z",2), ("y",1), ("x",0)]` TAM code stack: `[0,5,0]` However we also need to account for expressions such as: ```js let var x := 3; var y := 5; var z := x*y ``` ```haskell declarationCompiler :: [Declaration] -> (VarEnv, [TAMInstr]) VarEnv :: [(Identifier, Address)] ``` NOTE: this can be defined with functions given in the `FunParser` library. Or using a `state monad` ### State Monad $s_0 \rightarrow s_1 \rightarrow s_2 \rightarrow s_n$ for each change in state, there's a corresponding result generated. $$ a_0 \quad\space\space\space a_1 \quad\space\space\space a_n $$ - For each of these states, we need a variable environment and address - For each of the results, we need to generate TAM instructions. Example: $s_n$ could be your bank balance and $a_n$ could be the purchase history. - In our case: - States are VarEnv & next free address space for next variable - Outputs are TAM instructions We need to define a type that models a state transform, while at the same time producing a result. This is where a state monad comes in. ```haskell newtype ST st a = S (\st -> (a, st)) -- ST - state transformer -- st - type of states -- a - type of output/results -- S - constructor -- \st a function that takes a state and returns a value along with a new state -- this is a general type definition with state type st and result type a -- this is still just a type constructor, has to be applied to a type instance Functor (ST st) instance Applicative (ST st) instance Monad (ST st) --as we inherit the monad class, we can use do notation ``` ```haskell newtype ST st a = S (\st -> (a, st)) --type definition ST Int --type constructor ST Int String --type ``` ```haskell app :: ST st a -> st -> (a, st) app (S f) x = f x --applies the constructor to state x ``` ```haskell instance Functor (ST st) where --fmap :: (a->b) -> ST st a -> ST st b fmap g sta = S (\s -> let (x,s') = app sta s in (g x, s')) ``` ```haskell instance Applicative (ST st) where --pure :: a -> ST st a pure x = S (\s -> (x,s)) --(<*>) :: (ST st (a -> b)) -> ST st a -> ST st b stf <*> sta = S (\s -> let (f,s') = app stf s (x,s'') = app sta s') in (f x, s'')) ``` ```haskell instance Monad (ST st) where return = pure -- (>>=) :: (ST st a) -> (a -> ST st b) -> ST st b sta >>= f = S (\s -> let (x,s') = app sta s (y,s'') = app (f x) s' in (y,s'')) ```