从抽象语法树中获取控制流图

我有一个从 JAVA 的 ANTLR 解析器生成器派生的 AST。我想做的是以某种方式构建源代码的控制流图,其中每个语句或表达式都是唯一的节点。我知道这种识别一定有一些递归性,我想知道你会建议什么作为最佳选择,如果ANTLR有一个工具集,我可以用于这项工作。干杯,克里斯


编辑 - 我主要关心的是从AST获取控制流图(CFG)。通过这种方式,我可以获得源的树表示形式。为了澄清,源代码和实现语言都是Java。


答案 1

通常CFG是在较低级别的表示形式(例如JVM字节码)上计算的。几年前,有人就这些事情做了一篇论文。那里可能有一种有用的方法来描述如何获得该表示。

由于您的源语言和目标语言是相同的,因此没有代码生成步骤 - 您已经完成了!但是,现在您可以步行AST。在AST的每个节点,你必须问自己:这是否是“跳跃”指令?方法调用和 if 语句是跳转指令的示例。循环构造也是如此(例如 and )。加法和乘法等指令是非跳转的。forwhile

首先与每个 java 语句关联 CFG 中的一个节点,以及一个入口和出口节点。作为第一个近似值,走树并:

  1. 如果当前语句是方法调用,则为该方法调用的相应主体确定入口节点的位置,并创建一个从当前语句指向该入口节点的边缘。如果该语句是方法返回,则枚举可能调用它的位置,并向这些位置添加一个边。
  2. 对于每个非跳转语句,在它和下一个语句之间留出一条边。

这将为您提供某种CFG。该过程在步骤 2 中略显毛茸茸的,因为调用的方法可能在库中声明,而不是在 AST 中的其他位置声明 - 如果是这样,要么不创建边缘,要么使边缘成为表示该库方法条目的特殊节点。

这有意义吗?


答案 2

生成真正考虑到所有语言问题的完整控制流图比看起来更难。您不仅必须识别看似“基本块”的内容,还必须识别函数调用(有点容易,但识别目标可能更难),其中可能会发生诸如类初始值设定项之类的幕后操作。并担心可能发生异常的点以及如果确实发生异常,控制将转到何处。

如果您仔细检查大多数语言,它们也会清楚地了解表达式中计算的计算顺序,如果您在表达式中有两个副作用,这很重要;控制流应反映顺序(如果未定义,则反映非顺序)。

也许你只想要一个具有基本块和条件的控制流的抽象。这显然容易一些。

在任何一种情况下(简单的 CFG 或完整的 CFG),您都需要遍历 AST,在每个点上都有对可能控制流目标的引用(例如,对于大多数情况,例如 IF 语句,有两个流目标:THEN 和 ELSE 子句)。在每个节点上,将该节点链接到相应的控制流目标,可能替换流目标(例如,当您遇到 IF 时)。

要为Java(或C)的完整语言语义做到这一点,需要做很多工作。您可能只想使用一个工具来计算此现成数据。请参阅 http://www.semanticdesigns.com/Products/DMS/FlowAnalysis.html,了解我们的工具的真正外观。


推荐