Very close to getting this to work but having trouble with StringMap from OCaml. Essentially I'm making a calculator which takes in from ocamllex the lexical stream ... so here commas are supposed to separate out our expressions while equal signs means that we will be assigning a value to a variable.
I realized that when assigning variables I'm not able to look them up because I get (Fatal error: exception Not_found) on the lines for not finding the key's I added in the Var case of the function. I don't know where to put the StringMap.empty or how to make it visible in this function... I was wondering why it can't find what I'm adding in the equals case?
Here's my code.
open Ast
module StringMap = Map.Make(String)
let varMap = StringMap.empty
let rec parser = function
Lit(x) -> x
| Binop(e1, op, e2) -> (
let v1 = parser e1 and v2 = parser e2 in
match op with
Add -> v1 + v2
| Sub -> v1 - v2
| Mul -> v1 * v2
| Div -> v1 / v2
)
| Var(v) -> StringMap.find v varMap
| Statements(e1, e2) -> ignore(parser e1); parser e2
| Equals(v, e1) -> StringMap.add v e1 varMap; parser e1
let _ =
let LexingBuffer = Lexing.from_channel stdin in
let expression = Parser.expression Scanner.token LexingBuffer in
let result = parser expression in
print_endline (string_of_int result)
Map
is an immutable data structure. Any function that changes the map will return a new modified instance, while leaving the previous one unaltered. Therefore, this expression
StringMap.add v e1 varMap; parser e1
will just throw the new map away, and return whatever the recursive call to parser
returns instead. If you want to use Map
you have to keep the new instance around. You can do so either by making varMap
a ref cell that you update:
let varMap = ref StringMap.empty
...
varMap := StringMap.add v1 !varMap
or by adding a function argument to parser
and pass it along:
let rec parser varMap = function
...
parser (StringMap.add v e1 varMap) e1
Another option is to use a Hashtbl instead, which is mutable and works very well with strings.