Ocaml stringmap калькулятор синтаксический анализ AST не добавление или поиск - PullRequest
0 голосов
/ 10 марта 2019

Очень близко к тому, чтобы заставить это работать, но возникли проблемы с StringMap от OCaml. По сути, я делаю калькулятор, который получает из ocamllex лексический поток ... поэтому здесь запятые должны разделять наши выражения, а знаки равенства означают, что мы будем присваивать значение переменной.

Я понял, что при назначении переменных я не могу их искать, потому что получаю (Fatal error: исключение Not_found) строки, где не могу найти ключ, который я добавил в случае Var функции. Я не знаю, куда поместить StringMap.empty или как сделать его видимым в этой функции ... Мне было интересно, почему он не может найти то, что я добавляю в случае равенства?

Вот мой код.

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)

Ответы [ 2 ]

3 голосов
/ 10 марта 2019

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 голос
/ 10 марта 2019

Карты неизменны. Линия

StringMap.add v e1 varMap; parser e1
Таким образом,

вычисляет обновленную карту, а затем немедленно отбрасывает . Другими словами, карта varMap всегда пуста.

Чтобы не отбрасывать карту окружения, вы должны отслеживать ее в самой функции parser, добавляя ее в качестве аргумента функции - которую вы можете переименовать в eval:

  let rec eval env = function
  | ...
...