Is there a parser generator that also implements the inverse direction, i.e. unparsing domain objects (a.k.a. pretty-printing) from the same grammar specification? As far as I know, ANTLR does not support this.
5 回答
我已经用 Java 和 Kotlin 实现了一组可逆解析器组合器。解析器几乎是用 LL-1 风格编写的,它提供了解析和打印方法,而后者提供了漂亮的打印机。
你可以在这里找到项目:https ://github.com/searles/parsing 这是一个教程:https ://github.com/searles/parsing/blob/master/tutorial.md 这是一个解析器/漂亮的打印机对于数学表达式:https ://github.com/searles/parsing/blob/master/src/main/java/at/searles/demo/DemoInvert.kt
我们的DMS Software Reengineering Toolkit正是这样做的(并为分析/转换代码提供了许多额外的支持)。它通过用附加属性装饰语言语法来做到这一点,产生所谓的属性语法。我们使用特殊的 DSL 来编写这些规则,以方便编写。
了解 DMS 直接基于语法生成树会有所帮助。
每个 DMS 语法规则都与所谓的“漂亮打印”规则配对。每个漂亮打印规则都描述了如何“漂亮打印”由其相应语法规则识别的句法元素和子元素。漂亮打印过程本质上是水平或垂直制造或组合矩形文本框(带有可选的缩进),叶子生成包含叶子文字值(关键字、运算符、标识符、常量等)的单位高度框。
例如,可以编写以下 DMS 语法规则和匹配的漂亮打印规则:
statement = 'for' '(' assignment ';' assignment ';' conditional_expression ')'
'{' sequence_of_statements '}' ;
<<PrettyPrinter>>:
{ V(H('for','(',assignment[1],';','assignment[2],';',conditional_expression,')'),
H('{', I(sequence_of_statements)),
'}');
这将解析以下内容:
for ( i=x*2;
i--; i>-2*x ) { a[x]+=3;
b[x]=a[x]-1; }
(对语句和表达式使用额外的语法规则)和漂亮打印它(对那些额外的语法规则使用额外的漂亮打印规则)如下:
for (i=x*2;i--;i>-2*x)
{ a[x]+=3;
b[x]=a[x]-1;
}
DMS 还捕获评论,将它们附加到 AST 节点,并在输出时重新生成它们。该实现有点奇特,因为大多数解析器不处理注释,但使用起来很容易,甚至是“免费的”;评论将自动插入到它们原始位置的漂亮打印结果中。
DMS 还可以在“保真”模式下打印。在这种形式中,它试图保留标记的形状(例如,数字基数、标识符字符大写、使用了哪个关键字拼写)和已解析标记的列偏移量(到行中)。这将导致重新生成原始文本(或非常接近以至于您认为它没有不同的内容)。
我的 SO answer on Compiling an AST back to source code提供了有关漂亮打印机必须做什么的更多详细信息。DMS 清晰地解决了所有这些主题。
此功能已被 DMS 用于大约 40 多种真实语言,包括完整的 IBM COBOL、PL/SQL、Java 1.8、C# 5.0、C(许多方言)和 C++14。
通过编写一组足够有趣的漂亮打印机规则,您可以构建像 JavaDoc 这样的东西,扩展为包含超链接源代码。
有几个解析器生成器包含一个解解析器的实现。其中之一是用于上下文无关语法的Nearley解析器生成器。
也可以使用明确的子句语法来实现源代码的双向转换。在 SWI-Prolog 中,谓词可以将输入文本转换为解析树,反之亦然。phrase/2
一般情况下是不可能的。
是什么让印刷品漂亮?打印件很漂亮,如果空格、制表符或换行符位于这些位置,这会使打印件看起来很漂亮。
但是大多数语法忽略空格,因为在大多数语言中空格并不重要。有像 Python 这样的例外,但总的来说,使用空格作为语法是否是一个好主意的问题仍然存在争议。因此大多数语法不使用空格作为语法。
如果抽象语法树不包含空格,因为解析器已经把它们扔掉了,没有生成器可以使用它们来漂亮地打印 AST。