Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ocaml 在漂亮的打印机中忠实地处理白色间距_Ocaml_Frontend_Lex_Pretty Print_Ocamllex - Fatal编程技术网

Ocaml 在漂亮的打印机中忠实地处理白色间距

Ocaml 在漂亮的打印机中忠实地处理白色间距,ocaml,frontend,lex,pretty-print,ocamllex,Ocaml,Frontend,Lex,Pretty Print,Ocamllex,我正在为一种语言编写前端(通过ocamlex和ocamlyacc) 因此前端可以从程序中构建一个抽象语法树(AST)。然后我们经常编写一个漂亮的打印机,它使用AST打印程序。如果以后我们只想编译或分析AST,大多数时候,我们不需要打印的程序在白间距方面与原始程序完全相同。然而,这一次,我想写一个漂亮的打印机,在白间距方面打印出与原始打印机完全相同的程序 因此,我的问题是,在尽量不修改太多AST类型的同时,处理白间距的最佳实践是什么。我真的不想在AST中为每种类型添加大量(空白) 例如,这就是我目

我正在为一种语言编写前端(通过
ocamlex
ocamlyacc

因此前端可以从程序中构建一个
抽象语法树(AST)
。然后我们经常编写一个漂亮的打印机,它使用AST打印程序。如果以后我们只想编译或分析AST,大多数时候,我们不需要打印的程序在白间距方面与原始程序完全相同。然而,这一次,我想写一个漂亮的打印机,在白间距方面打印出与原始打印机完全相同的程序

因此,我的问题是,在尽量不修改太多AST类型的同时,处理白间距的最佳实践是什么。我真的不想在AST中为每种类型添加大量(空白)

例如,这就是我目前在
lexer.mll
中处理(即跳过)白色间距的方式:

rule token = parse
  ...
  | [' ' '\t']       { token lexbuf }     (* skip blanks *)
  | eof              { EOF }

是否有人知道如何更改此项以及前端的其他部分,以便在以后打印时正确考虑白间距?

保留每个令牌的源文件位置信息是很常见的。例如,此信息允许出现更准确的错误

最常用的方法是保留每个标记的起始行号和结束行号以及列位置,总共四个数字。如果很容易根据令牌的值和开始位置计算令牌的结束位置,那么可以将其减少为两个数字,但代价是额外的代码复杂性

野牛有一些特点,简化了记位置对象的簿记工作;ocamlyacc可能包含类似的功能,但我在文档中没有看到任何内容。在任何情况下,维护与每个输入令牌关联的位置对象都是很简单的

有了这些信息,就可以很容易地在两个相邻的标记之间重新创建空白,只要分隔标记的是空白。评论是另一个问题


这是一个判断调用,它是否比在每个标记经过词法分析时仅将前面的空格(甚至注释)附加到每个标记更简单。

您可以使用匹配语句,根据您处理的标记打印不同数量的空格。如果标记是:id、num、define语句、assign(=),我通常会在之前打印1个空格

如果标记是一个算术表达式,我会在它前面和后面各打印一个空格

如果您处理的是if或while语句,我会将主体缩进四个空格

我认为最好的办法是编写一个漂亮的打印函数,例如:

let rec pretty_print pos ast =
   match ast with
    |Some_token -> String.make pos ' '; (* adds 'pos' number of spaces; pos will start off as zero. *)
                   print_string "Some_token";
    |Other_token...

总之,我将通过在递归函数中分别匹配每个标记来处理空格,并打印出适当数量的空格。

如果您的pretty打印机没有以任何方式更改空格,那么它究竟做了什么来证明“pretty”一词的正确性呢?:)换言之,你为什么不把整个输入文本都倒出来呢?我明白了。。。这是因为对于程序的某些部分,我不想改变空格。例如,对于函数调用
f(arg0,arg1,arg2,arg3)
,我希望保持原样,而不是将其更改为漂亮的
f(arg0,arg1,arg2,arg3)
。OCaml确实具有获取令牌位置的类型。请您详细说明如何维护与每个令牌关联的位置,好吗?我是否必须在AST中存储每个元素的位置或空格数,以便在pretty printer中使用该信息?@softtimur:我将保留位置信息作为令牌的一部分。但可能还有其他选择。扩充令牌很简单,您所说的“将位置信息作为令牌的一部分”是什么意思?类型是什么样子的?可能是这样的:当我环顾ocaml解决方案时,我注意到ocamlp5似乎将位置信息保存在一个数组中,该数组由令牌号索引。这可能不太具侵入性,但当然这取决于您是否能够计算出每个令牌的数量。值得一提的是,漂亮的打印机与编译器的结构不同;在漂亮的打印机中,构建完整的解析树比抽象出纯粹的语法标记更为常见。还有,评论。和这个问题一样,空白。我想这不会完全重新创建原始程序的格式,但会创建一个完全缩进的程序