![]() Run p r = nubBy ((=) `on` fst) (exec p r)Īfter executing the statement we clean up any shadowed bindings, so that we can easily read off the contents of the final store. Running a program reduces to executing its top-level statement in the context of an initial store. Note that, in the case of assignments, we simply push a new binding for the updated variable to the store, effectively shadowing any previous bindings for that variable. exec :: Stmt -> Store -> StoreĮxec (While e s) r | eval e r /= 0 = exec (Seq ) rĮxec (Seq (s : ss)) r = exec (Seq ss) (exec s r) Hence, the function for executing a statement takes a store as an argument and produces a possibly updated store. While the evaluation of an expression cannot alter the contents of the store, executing a statement may in fact result in an update of the store. Note that if the store contains multiple bindings for a variable, lookup selects the bindings that comes first in the store. Nothing -> error ("unbound variable `" ++ x ++ "'")Įval (e1 :+: e2) r = eval e1 r + eval e2 rĮval (e1 :-: e2) r = eval e1 r - eval e2 rĮval (e1 :*: e2) r = eval e1 r * eval e2 rĮval (e1 :/: e2) r = eval e1 r `div` eval e2 r type Val = IntĮxpressions are evaluated by mapping constants to their value, looking up the values of variables in the store, and mapping arithmetic operations to their Haskell counterparts. These values are just integers and as a representation of our "memory" we just use lists of pairs consisting of a variable and a value. While running a program, we need to keep track of the values assigned to the different variables in the programs. Now, let us move to the actual interpreter. infix 1 :=įor example, a sequence of statements for "swapping" the values of the variables x and y can be represented by Seq. We have three forms of statements: variable assignments, while loops, and sequences. The statement language is rather minimal. infixl 6 :+:, :-:įor example, the expression that adds the constant 2 to the variable x is represented by V "x" :+: C 2. Expressions are constructed from integer constants, variable references, and arithmetic operations. Here, variables simply represented by strings: type Var = String The essence of an imperative language is that it has some form of mutable variables. Let us first import some modules that we will use in just a bit. The language that I use here is very simple and only consists of integer expressions and some basic statements. I assume that you have already tackled the issue of parsing the source text of the programs you want to write an interpreter for and that you have some types for capturing the abstract syntax of your language. The following may serve as a minitutorial. If you are new to writing this kind of processors, I would recommend to put off using monads for a while and first focus on getting a barebones implementation without any bells or whistles.
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |