Ocaml stringmap 计算器 AST 解析不添加或查找

Ocaml stringmap calculator AST parse not adding or finding

非常接近使它工作,但在使用 OCaml 的 StringMap 时遇到问题。本质上,我正在制作一个计算器,它从 ocamllex 获取词法流......所以这里应该用逗号分隔我们的表达式,而等号意味着我们将为变量赋值。

我意识到在分配变量时我无法查找它们,因为我在行中得到(致命错误:异常Not_found)找不到我在 Var 案例中添加的键功能。我不知道将 StringMap.empty 放在哪里或如何使其在此函数中可见...我想知道为什么它找不到我在 equals 情况下添加的内容?

这是我的代码。

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)

地图是不可变的。该行

StringMap.add v e1 varMap; parser e1

因此正在计算更新的地图,然后立即丢弃它。 换句话说,地图 varMap 总是空的。

为避免丢弃环境贴图,您应该在函数 parser 中跟踪它,方法是将其添加为函数的参数——您可以将其重命名为 eval:

  let rec eval env = function
  | ...

Map是一个不可变的数据结构。任何更改映射的函数都将 return 一个新的修改实例,同时保持前一个不变。因此,这个表达式

StringMap.add v e1 varMap; parser e1

只会丢弃新地图,而 return 无论对 parser return 的递归调用如何。如果你想使用 Map 你必须保留新实例。您可以通过使 varMap 成为您更新的参考单元格来做到这一点:

let varMap = ref StringMap.empty

...

varMap := StringMap.add v1 !varMap

或者通过向 parser 添加函数参数并将其传递:

let rec parser varMap = function

...

parser (StringMap.add v e1 varMap) e1

另一种选择是使用 Hashtbl,它 可变的并且可以很好地处理字符串。