我已经实现了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
的出现。我甚至不能在lexer.mll
的OCaml结尾中引用这些标识符。
有没有办法实现这个目标?
答案 0 :(得分:4)
最后,我采用了以下风格,我从ocamllex
本身的来源偷走了(所以我猜它是标准做法)。从lexer.mll
let symbols =
[
...
(Symb.turnstile, TURNSTILE);
...
]
其中Symb
是将turnstile
定义为字符串的模块。然后,lexer.mll
的lexing部分故意过于笼统:
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
答案 1 :(得分:1)
虽然这两个令牌看起来都是符号字符串,但它们确实非常不同。我认为没有一种方便的类型可以共享它们以供ocamllex和Printf.printf使用。这可能是ocamllex不支持此类外部定义的原因。您可以通过宏工具获得所需的效果(文本包含)。