我想为特定语言写一个小美化器。在美化器中,我们将能够缩进一行或多行(即,在每行的左侧添加空格);我们还可以格式化整个代码(即,在适当的位置改变空格和换行符)。
鉴于某项计划,我的前端ocamllex
和ocamlyacc
可以构建Abstract Syntax Tree (AST)
:
(* in main.ml *)
let f = open_in file in
let buf = Lexing.from_channel f in
let ast = Parser.main Lexer.token buf in
analyse ast
...
我更喜欢使用AST来分析,编译和打印(不完全相同)程序。但是,似乎我们需要直接使用令牌来编写一个好的美化器。但我不知道如何在前端之外操纵令牌。
例如,在解析时记录令牌及其位置是否常见,以便我们仍然可以在前端之外使用它们?例如,我们可以逐个浏览此记录中的标记,并打印完全相同的程序(包括精确的空格)?
有没有人有任何代码段?
编辑1:
以下是在Lexing.lexeme_start_p
运行时上使用lexbuf
的一些示例。但是,我想知道的是,人们是否以及如何在外部(或之后)解析这些信息?例如,外部(或之后)解析,我们如何从某个位置获取令牌?
(* in main.ml *)
let ast = try Parser.main Lexer.token buf with
| Lexer.Lexing_error e ->
let pos = Lexing.lexeme_start_p buf in
let l = pos.pos_lnum in
let c = pos.pos_cnum - pos.pos_bol + 1 in
pffo "File \"%s\", line %d, characters %d-%d:\n" file l (c-1) c
pffo "Unexpected exception, parser top : lexical analysis > %s@." e;
exit 1
...
(* in lexer.mll *)
rule token = parse
...
| "'" '\\' (_ as c)
{ let msg = Printf.sprintf "illegal escape sequence \\%c" c in
let p = Lexing.lexeme_start_p lexbuf in
raise (Lexical_error (msg, p.Lexing.pos_fname, p.Lexing.pos_lnum,
p.Lexing.pos_cnum - p.Lexing.pos_bol + 1)) }
答案 0 :(得分:0)
在实际编程语言实现中,使用令牌保持令牌位置非常常见。
按原样打印输入代码的一部分的最简单方法是将输入文本保留在某处并使用令牌位置提取所需的部分。从令牌流中重建文本及其适当插入空格的位置很难实现,而且非常容易出错,当你的词法分析器忽略非白色空间之类的评论时,这是不可能的。
可以在OCaml编译器实现中找到这样的打印输入代码的示例。例如,on
尝试使用带有输入文本的词法分析器Location.highlight_dumb
字段来打印错误代码,但有时不可能,因为lex_buffer
不能保持整个输入。