我想为特定语言写一个小美化器。在美化器中,我们将能够缩进一行或多行(即在每行左侧添加空格);我们还将能够格式化整个代码(即,在适当的位置更改空格和换行符)。
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)) }