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

问题描述 投票:0回答:2

非常接近让这个工作,但从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)
ocaml ocamlyacc
2个回答
3
投票

Map是一个不可变的数据结构。任何更改地图的函数都将返回一个新的修改过的实例,同时保留前一个不变的实例。所以,这个表达方式

StringMap.add v e1 varMap; parser e1

只会扔掉新地图,然后返回parser返回的递归调用。如果你想使用Map,你必须保持新的实例。您可以通过将varMap更新为您更新的ref单元格来执行此操作:

let varMap = ref StringMap.empty

...

varMap := StringMap.add v1 !varMap

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

let rec parser varMap = function

...

parser (StringMap.add v e1 varMap) e1

另一种选择是使用Hashtbl,它是可变的并且对字符串非常有效。


1
投票

地图是不可变的。这条线

StringMap.add v e1 varMap; parser e1

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

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

  let rec eval env = function
  | ...
© www.soinside.com 2019 - 2024. All rights reserved.