1

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

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_plexbuf 运行时使用的示例。但是,我想知道的是人们是否以及如何在解析之外(或之后)获取这些信息?例如,在解析之外(或之后),我们如何从某个位置获取令牌?

  (* 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)) }
4

1 回答 1

0

用标记保持标记位置在实际编程语言实现中非常常见。

按原样打印部分输入代码的最简单方法是将输入文本保存在某处,然后使用标记位置提取您想要的部分。从标记流中重建文本及其适当地插入空格的位置很难实现并且很容易出错,恐怕当你的词法分析器忽略非空格的东西(如注释)时,这是不可能的。

这种按原样打印输入代码的示例可以在 OCaml 编译器实现中找到。例如Location.highlight_dumb,尝试使用带有输入文本的词法分析器字段围绕错误打印代码lex_buffer,尽管有时这是不可能的,因为lex_buffer不会保留整个输入。

于 2016-06-05T02:06:28.733 回答