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,它 是 可变的并且可以很好地处理字符串。
非常接近使它工作,但在使用 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,它 是 可变的并且可以很好地处理字符串。