Внешние определения регулярных выражений ocamllex

Я реализовал обычную комбинацию lexer / parser / pretty-printer для чтения / печати типа в моем коде. Я обнаружил, что между лексером и красивым принтером есть избыточность, когда дело касается регулярных выражений в виде простых строк, обычно используемых для символов, знаков препинания или разделителей.

Например, теперь у меня есть

rule token = parse
  | "|-" { TURNSTILE }

в моем lexer.mll файле и такую ​​функцию, как:

let pp fmt (l,r) = 
  Format.fprintf fmt "@[%a |-@ %a@]" Form.pp l Form.pp r

для красивой печати. Если я решу изменить строку для TURNSTILE, мне придется отредактировать два места в коде, что я считаю не идеальным.

Очевидно, лексер OCaml поддерживает определенную возможность определять регулярные выражения и затем ссылаться на них в mll файле. Итак, lexer.mll можно было бы записать как

let symb_turnstile = "|-"

rule token = parse
  | symb_turnstile { TURNSTILE }

Но это не позволит мне получить внешний доступ к symb_turnstile, скажем, из моих функций красивой печати. Фактически, после запуска ocamllex в lexer.ml не встречается symb_turnstile. Я даже не могу ссылаться на эти идентификаторы в эпилоге OCaml lexer.mll.

Есть ли способ добиться этого?


person Nikos    schedule 03.08.2012    source источник


Ответы (2)


В конце концов, я выбрал следующий стиль, который я позаимствовал из источников самого ocamllex (так что я предполагаю, что это стандартная практика). Карта от строк к токенам (здесь список ассоциаций) определена в преамбуле lexer.mll

let symbols =
  [ 
    ...
    (Symb.turnstile, TURNSTILE); 
    ...
  ]

где Symb - модуль, определяющий turnstile как строку. Затем лексическая часть lexer.mll намеренно носит чрезмерно общий характер:

rule token = parse
  ...
  | punctuation
    {
      try 
        List.assoc (Lexing.lexeme lexbuf) symbols
      with Not_found -> lex_error lexbuf  
    }
  ...

где punctuation - регулярное выражение, соответствующее последовательности символов.

Теперь симпатичный принтер можно написать так.

let pp fmt (l,r) = 
  Format.fprintf fmt "@[%a %s@ %a@]" Form.pp Symb.turnstile l Form.pp r
person Nikos    schedule 05.08.2012

Хотя оба токена условно выглядят как строки, на самом деле они очень разные. Я не думаю, что есть удобный тип, в котором они могли бы использоваться ocamllex и Printf.printf. Возможно, это причина того, что ocamllex не поддерживает такие внешние определения. Вероятно, вы могли бы получить желаемый эффект с помощью макроса (текстовое включение).

person Jeffrey Scofield    schedule 03.08.2012