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

时间:2008-09-18 13:30:46

标签: java parsing abstract-syntax-tree control-flow

我有一个源自ANTLR Parser Generator for Java的AST。我想要做的是以某种方式构建源代码的控制流图,其中每个语句或表达式是唯一的节点。我知道必须有一些这种识别的递归,我想知道你会建议什么是最好的选择,如果ANTLR有一个工具集我可以用于这项工作。 干杯, 克里斯


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

6 个答案:

答案 0 :(得分:10)

通常,CFG是在较低级别的表示(例如JVM字节码)上计算的。几年前有人对这些事做过a thesis。可能有一种有用的方式描述如何获得该表示。

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

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

  1. 如果当前语句是方法调用,请确定该方法调用的相应主体的入口节点的位置,并使当前语句的边指向该入口节点。如果语句是方法返回,则枚举可以调用它的位置并为其添加边缘。
  2. 对于每个非跳跃语句,在它与下一个语句之间形成优势。
  3. 这将为您提供某种的CFG。在步骤2中,该过程略显毛茸茸,因为调用的方法可以在库中声明,而不是在AST中的其他地方声明 - 如果是这样,要么不为表示该条目的特殊节点创建边缘或边缘图书馆方法。

    这有意义吗?

答案 1 :(得分:5)

制作一个真正考虑所有语言的完整控制流图 问题比看起来更难。你不仅需要确定什么 似乎是“基本块”,但您必须识别函数调用 (有点容易,但识别目标可能更难), 可以发生诸如类初始化程序之类的幕后操作。 并担心可能发生异常的点 如果发生异常,控制权将在何处发生。

如果仔细检查大多数语言,它们也会 清楚表达式中计算的评估顺序, 如果你在表达中有两个副作用,这就很重要; 控制流程应反映顺序(或非顺序, 如果没有定义)。

也许你只想要控制流的抽象 拥有基本块和条件。那是 显然有点容易。

在任何一种情况下(简单的CFG或完整的CFG),你需要走AST, 在每个点上都有可能的控制流目标 (例如,对于大多数情况,例如IF语句,有两个流程目标: THEN和ELSE条款)。在每个节点上,将该节点链接到 适当的控制流量目标,可能取代流量目标 (例如,当您遇到IF时)。

为Java(或C)的完整语言语义执行此操作是相当的 很多工作。您可能只想使用计算此功能的工具 现成的。 见http://www.semanticdesigns.com/Products/DMS/FlowAnalysis.html 从我们的工具中脱颖而出。

答案 2 :(得分:1)

根据一些评论,听起来OP真的想做code generation - 将AST转换为基于基本块和跳转点的低级指令序列。

代码生成是特定于语言的,并且已经在该主题中进行了大量工作。在进行代码生成之前,您需要了解目标语言 - 无论是汇编程序还是其他高级语言。一旦确定了这一点,您只需要遍历AST并生成一系列指令来实现AST中的代码。 (我说这很简单,但可能很难 - 很难概括,因为这里的注意事项非常适合特定语言。)

您为代码生成选择的表示将隐式或显式地包含控制流图。如果你的目标语言相当低级(接近汇编程序),那么控制流图应该相对容易提取。

(如果您想进一步澄清,请发表评论。)

答案 3 :(得分:-1)

你有没有试过ANTLR Studio?它没有生成孔AST图,但是为了审查,它已经非常有用了。

答案 4 :(得分:-1)

当我过去这样做时,我使用graphviz,特别是点工具来生成图形。我通过在编译时实际遍历控制流图来创建点输入文件。

图形布局是一个难题,而graphviz做得很好。它可以输出为ps,pdf和各种图像格式,布局通常非常直观。我强烈推荐它。

答案 5 :(得分:-1)

我认为我无法以您可能正在寻找的方式回答您的问题,因为我不知道在ANTLR中以任何方式生成带有或不带有AST的CFG。但是,简而言之,您将使用ANTLR生成的内容生成一个单独的Java程序来生成CFG。您将利用ANTLR生成的语法树作为输入,以在自己创建的单独Java程序中生成CFG。从本质上讲,这时您正在构建编译器。您的“编译器”和JVM之间的区别在于,您的输出是对程序如何分支其各种执行路径的可视化表示(CFG),而JVM / Java编译器生成了可在真实计算机(CPU)上执行的代码。 >

打个比方,如果有人坐下来写书(例如,用英语),句子中使用的各个单词就是计算机语言的令牌,句子的形成方式类似于上下文无关的语法表示有效的计算机代码,段落和整本小说以类似的方式讲述一个故事,即语义分析/编译器/ CFG可能会生成/表示逻辑上有效的程序,这些程序实际上在做有用的事情,或多或少没有逻辑错误。换句话说,一旦您克服了有效语法(正确的句子结构)的问题,任何人都可以在页面上写一堆句子,但是只有某些句子组合才能产生出确实可以起到作用的文本(讲述一个故事)。

您要问的是最后一部分-如何进行语法树转换和解释AST在逻辑上的实际作用。当然,您需要为每种语言构建一个“编译器”。拥有正确的语法并不能告诉您程序做什么-只是从语法角度来看程序是正确的。

林特软件,语法突出显示工具和IDE都是基于这样的想法构建的:试图使难题的最后一部分对人类来说变得更容易,更有效。