#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)
,并且可能通过使每个节点负责打印其自己的括号来鼓励代码重复(尽管我敢肯定您可以对此进行设计)。
评论
我认为如果您要进行静态分析,例如检测常见的操作员优先级错误,例如a&3 ==1。当您要将AST重新转换为源代码以获取更具可读性的代码时,它也很有用。不过,最好不要引入括号AST节点,因为这样会使在不在乎它们的AST上运行的代码更加复杂。对我来说,在表达式AST节点上添加括号标志似乎是更好的选择,不需要关心它们的部分可以忽略它。还可以对其进行改装或删除,而无需重新构造所有内容。
@jix,但另一方面,您可以按照语言规则重新生成括号。这也将产生没有不必要或缺少括号的代码。您可能会影响可读性
是的,我的意思是关于可读性。
与反向工程有关,这更多是关于如何最好地对AST建模的问题。