如何以图形方式可视化抽象语法树?
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::GraphTraits
和 llvm::DOTGraphTraits
模板(稍作变通)并且 llvm::WriteGraph()
将为您工作。这是没有太多微调的结果:
给定类似 C 的片段:
const int IntConstant = 1;
int Array[2];
void main() {
Printf("hello");
}
这种语言是 C 语言的简化版,并且不区分大小写。 Printf()
由 Write
语句表示为图像中的节点。 ConstDecl
表示 常量声明 。 VarDecl
表示变量声明,FuncDef
表示函数定义。其他事情非常简单。
在解释魔术之前,我想向您指出这些文档,这些文档确实有助于如何使用所涉及的 llvm APT。
- GraphTraits 了解您的代码应具有的签名。
- WriteGraph 了解
WriteGraph
您的代码需要什么。
- CFGPrinter 了解如何使您的
GraphTraits
专业化
- DOTGraphTraits 了解如何通过为节点提供标签和描述来使您的插图有意义。
- iterator_facade_base 了解如何轻松编写工作迭代器。
现在有了这个知识库,你只需要把它们放在一起。事实上,请按照以下步骤操作:
- 思考如何遍历 AST 中的每个节点并专门化
nodes_iterator
实现。
- 考虑如何遍历给定节点的所有子节点并专门化
ChildIteratorType
实现。
- 考虑如何从您的节点中提取有用的信息并专门化您的
DOTGraphTraits
的 getNodeLabel()
和 getNodeDescription()
。
- 注意我的:
GraphTraits
的NodeRef
类型必须是一个指针!事先知道这一点可以为您节省一天的时间。这适用于最新版本。也许将来他们会取消限制。
我目前的实现只包括节点的 class 名称作为其标签和不言自明的字符串作为其描述,没有任何微调。如果您想要更多效果,即颜色、形状等,您可以在 DOTGraphTraits
.
中进行
我用 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::GraphTraits
和 llvm::DOTGraphTraits
模板(稍作变通)并且 llvm::WriteGraph()
将为您工作。这是没有太多微调的结果:
给定类似 C 的片段:
const int IntConstant = 1;
int Array[2];
void main() {
Printf("hello");
}
这种语言是 C 语言的简化版,并且不区分大小写。 Printf()
由 Write
语句表示为图像中的节点。 ConstDecl
表示 常量声明 。 VarDecl
表示变量声明,FuncDef
表示函数定义。其他事情非常简单。
在解释魔术之前,我想向您指出这些文档,这些文档确实有助于如何使用所涉及的 llvm APT。
- GraphTraits 了解您的代码应具有的签名。
- WriteGraph 了解
WriteGraph
您的代码需要什么。 - CFGPrinter 了解如何使您的
GraphTraits
专业化
- DOTGraphTraits 了解如何通过为节点提供标签和描述来使您的插图有意义。
- iterator_facade_base 了解如何轻松编写工作迭代器。
现在有了这个知识库,你只需要把它们放在一起。事实上,请按照以下步骤操作:
- 思考如何遍历 AST 中的每个节点并专门化
nodes_iterator
实现。 - 考虑如何遍历给定节点的所有子节点并专门化
ChildIteratorType
实现。 - 考虑如何从您的节点中提取有用的信息并专门化您的
DOTGraphTraits
的getNodeLabel()
和getNodeDescription()
。 - 注意我的:
GraphTraits
的NodeRef
类型必须是一个指针!事先知道这一点可以为您节省一天的时间。这适用于最新版本。也许将来他们会取消限制。
我目前的实现只包括节点的 class 名称作为其标签和不言自明的字符串作为其描述,没有任何微调。如果您想要更多效果,即颜色、形状等,您可以在 DOTGraphTraits
.