如何以图形方式可视化抽象语法树?

How to visualize an Abstract Syntax Tree graphically?

我用 C++ 编写了一个简单的编译器,想可视化它生成的抽象语法树。目前,我将 AST 转储到类似于以下内容的超长字符串中:

Program(decls=[ConstDecl(type=BasicTypeKind::Int, value=Num(n=1, loc=Location(1, 21)), name=positive, loc=Location(1, 10)), ConstDecl(type=BasicTypeKind::Int, value=Num(n=-1, loc=Location(2, 21)), name=negative, loc=Location(2, 10)), ConstDecl(type=BasicTypeKind::Int, value=Num(n=100, loc=Location(3, 26)), name=max_heap_size, loc=Location(3, 10)), ConstDecl(type=BasicTypeKind::Character, value=Char(c=99, loc=Location(4, 23)), name=...

如您所见,此转储在可视化方面不是很人性化。人们不能自然地将 tree 的概念与这么长的字符串联系起来。我尝试了漂亮打印 AST 的方法并找到了 astpretty,这是 Python。它在调试方面有很多目标,但如果我想要 AST 的插图怎么办?图形格式肯定更适合。

实际上,我有关于我期待的输出的图片。 Graphviz 在这个领域做得很好,C++ 文档工具 Doxygen 生成的各种图表在概念上非常接近我的目的。

将这些放在一起,我想要一种方法将内存中的 AST 作为 C++ 对象转换为体面的图形输出(静态的也可以)。有什么好的起点吗?

编辑: 如评论所述,以 Graphviz 识别的格式转储我的 AST 是一个很好的起点。我会尝试这样做,直到出现新的更具体的问题。谢谢大家。

我找到了一个既快速又可接受的解决方案。 LLVM-8 包含一个选项,可通过从中生成点格式文件来可视化控制流图 (CFG)。基本上这适用于更通用的图形结构,只要您专门化 llvm::GraphTraitsllvm::DOTGraphTraits 模板(稍作变通)并且 llvm::WriteGraph() 将为您工作。这是没有太多微调的结果:

给定类似 C 的片段:

const int IntConstant = 1;
int Array[2];

void main() {
  Printf("hello");
}

这种语言是 C 语言的简化版,并且不区分大小写。 Printf()Write 语句表示为图像中的节点。 ConstDecl 表示 常量声明 VarDecl表示变量声明FuncDef表示函数定义。其他事情非常简单。

在解释魔术之前,我想向您指出这些文档,这些文档确实有助于如何使用所涉及的 llvm APT。

现在有了这个知识库,你只需要把它们放在一起。事实上,请按照以下步骤操作:

  1. 思考如何遍历 AST 中的每个节点并专门化 nodes_iterator 实现。
  2. 考虑如何遍历给定节点的所有子节点并专门化 ChildIteratorType 实现。
  3. 考虑如何从您的节点中提取有用的信息并专门化您的 DOTGraphTraitsgetNodeLabel()getNodeDescription()
  4. 注意我的:GraphTraitsNodeRef类型必须是一个指针!事先知道这一点可以为您节省一天的时间。这适用于最新版本。也许将来他们会取消限制。

我目前的实现只包括节点的 class 名称作为其标签和不言自明的字符串作为其描述,没有任何微调。如果您想要更多效果,即颜色、形状等,您可以在 DOTGraphTraits.

中进行