我们的DMS Software Reengineering Toolkit 正是这样做的(并为分析/转换代码提供了许多额外的支持)。它通过用附加属性装饰语言语法来做到这一点,产生所谓的属性语法。我们使用专门的 DSL 来编写这些规则,方便编写。
了解 DMS 直接根据语法生成树会很有帮助。
每个 DMS 语法规则都与所谓的"prettyprinting" rule 配对。每个漂亮打印规则都描述了如何“漂亮打印”由其相应语法规则识别的句法元素和子元素。漂亮打印过程本质上是水平或垂直制造或组合矩形文本框(带有可选的缩进),叶子产生包含叶子文字值(关键字、运算符、标识符、常量等)的单位高度框。
例如,可以编写以下 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 还捕获 cmets,将它们附加到 AST 节点,并在输出时重新生成它们。该实现有点奇特,因为大多数解析器不处理 cmets,但使用起来很容易,甚至是“免费的”; cmets 将自动插入到它们原始位置的漂亮打印结果中。
DMS 也可以在“保真”模式下打印。在这种形式中,它试图保留标记的形状(例如,数字基数、标识符字符大写、使用了哪个关键字拼写)和已解析标记的列偏移量(到行中)。这将导致重新生成原始文本(或非常接近以至于您认为它没有不同的内容)。
我在Compiling an AST back to source code 的 SO 回答中提供了有关漂亮打印机必须做什么的更多详细信息。 DMS 清晰地解决了所有这些主题。
DMS 已在大约 40 多种真实语言上使用此功能,包括完整的 IBM COBOL、PL/SQL、Java 1.8、C# 5.0、C(多种方言)和 C++14。
通过编写一组足够有趣的漂亮打印机规则,您可以构建东西like JavaDoc extended to include hyperlinked source code。