Внешние определения регулярных выражений 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
нет случаев symb_turnstile
в lexer.ml
, Я даже не могу сослаться на эти идентификаторы в эпилоге OCaml lexer.mll
,
Есть ли способ достичь этого?
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
Хотя оба токена выглядят как строки в нотации, на самом деле они очень разные. Я не думаю, что есть удобный тип, под которым они могут быть совместно использованы для ocamllex и Printf.printf. Возможно, это причина того, что ocamllex не поддерживает такие внешние определения. Вы можете получить эффект, который хотите, с помощью макро-функции (текстовое включение).