我正在为源代码逆向工程平台开发AST模型。我的问题是,我应该在AST中保留括号数据吗?因为我将所有内容都放在树中,所以我已经知道哪个操作将首先执行。

评论

我认为如果您要进行静态分析,例如检测常见的操作员优先级错误,例如a&3 ==1。

当您要将AST重新转换为源代码以获取更具可读性的代码时,它也很有用。不过,最好不要引入括号AST节点,因为这样会使在不在乎它们的AST上运行的代码更加复杂。对我来说,在表达式AST节点上添加括号标志似乎是更好的选择,不需要关心它们的部分可以忽略它。还可以对其进行改装或删除,而无需重新构造所有内容。

@jix,但另一方面,您可以按照语言规则重新生成括号。这也将产生没有不必要或缺少括号的代码。您可能会影响可读性

是的,我的意思是关于可读性。

与反向工程有关,这更多是关于如何最好地对AST建模的问题。

#1 楼

这是一个相当普遍的问题,正确的决定将取决于您希望进行哪种分析。当进行逆向工程时,我本着这样的理念:更好的信息。

语法分析

正如Igor所提到的,C编程语言将a & 3 == 1解析为a & (3 == 1),从而导致代码中的大量错误。该代码没有什么无效的,但是不太可能是开发人员想要的,可以找到语法模式并给出警告。几个编译器已经实现了此功能:在另一方面,Clang将圆括号存储在AST中作为名为warn_about_parentheses的节点。这样就可以将常见错误条件的检查与解析器分离(请参阅gcc/c-typeck.c中的ParenExpr)。该设计使得可以添加更多模块来分析代码的语法,而无需修改解析器。 Clang还使用空格信息来警告类似DiagnoseBitwisePrecedence(而不是SemaExpr.cpp)之类的内容,并使用代码起源信息来防止在宏引起过多括号时发出警告。尽管在任何非C派生的语言中都不太可能需要这种确切的功能,但是它表明,您在AST中拥有的信息越多,您可以使用它进行的操作就越多。

代码重新生成和调试

正如jix所提到的那样,丢弃有关括号的信息可能会损害AST生成的代码的可读性。如果不存储有关括号的信息,则代码生成器可能会将x =+ 1转换为x = +1,这既正确又令人困惑。

这也用于调试-AST对源代码的建模越紧密,您就越容易查看AST并了解其与输入代码的对应关系。

语义分析

如您的问题所述,将所有内容解析为树后,您不再需要有关括号的信息即可理解代码的语义。如果这只是您的意图,那么您的树将变得更小,更简单,并且没有括号。

反编译器从二进制代码重构AST,并在不了解括号的情况下对其进行广泛的分析和转换。该语言的运算符优先级用于确定反编译过程结束时括号的位置。

实现

如果希望在AST中保留括号,由于上述任何原因,我将使用Clang的方法并为带括号的表达式添加一个简单的节点。这可能不会在遍历树的任何代码中添加超过十行。应当注意,这不足以表示有效代码x & (y == z),并且可能通过使每个节点负责打印其自己的括号来鼓励代码重复(尽管我敢肯定您可以对此进行设计)。