Bingo, Computer Graphics & Game Developer
在使用编译器前端Flex+Bison完成了大部分工作之后,尽管可以使用简易的printf来完成终端调试,但终究不够方便。
使用Bison完成AST生成之后需要对其构建的AST进行分析,此时常规思路的前序中序后序遍历对这样一个庞大的二叉树而言实现可视重建并不容易。因为你需要通过前中序来手工推导出一整棵树,但这并不是你做此任务的主要目的。
这里我安利一波贝尔实验室推出的黑科技Graphviz,在原有的遍历基础上基本上能够做到1分钟完成上手。
假定一抽象语法树节点类Node,之后所有AST都将被视为普通二叉树。
简单的类定义
class Node
{
public:
Node *leftChild;
Node *rightChild;
// 访问当前结点
virtual void value();
};
传统的中序遍历
void traversal(Node * root)
{
if(!root) return;
traversal(root->leftChild);
root->value();
traversal(root->rightChild);
}
Graphviz支持DOT语言的输入,个人认为只要依样画葫芦即可
使用DOT输出的中序遍历 只需要增加当前结点的label名及各子结点地址 无论是printf或是保存文件都可选 目的无非就是获取这一整段DOT输出代码
class Node
{
public:
Node *leftChild;
Node *rightChild;
// 访问当前结点
virtual void value();
string name;
};
// 以下代码将会使得遍历转换为DOT格式
void traversal(Node * root)
{
// 可选将渲染的结点形状更换为其他形式
printf("digraph G {\n");
printf("node[shape=rect]\n");
traversalAsDot(root);
printf("}");
}
void traversalAsDot(Node* root)
{
if(!root) return;
// 当前结点名
// root->name.c_str() 可以更换为任意能够获取当前结点名的函数 手工RTTI都可
printf("_%p[label=%s]\n", root, root->name.c_str());
// 传递父节点到子节点地址信息
if (l != NULL) printf("_%p -> _%p\n", root, root->leftChild);
if (r != NULL) printf("_%p -> _%p\n", root, root->rightChild);
traversalAsDot(l);
root->value();
traversalAsDot(r);
}
我在这里是对CSS进行解析生成AST,解析以下代码,获得AST,输出DOT使用Graphviz渲染
head.font-face.a .b:hover, #ahs{
background: #00FF00;
src: 222;
}
.body {
font-family: 'Raleway', Arial, sans-serif;
margin: 1, 2, 3, 4;
}
输出的DOT如下
digraph G {
node[shape=rect]
_0059C010[label=RuleList]
_0059C010 -> _0059BE48
_0059C010 -> _0059BFF8
_0059BE48[label=RuleList]
_0059BE48 -> _0059BE30
_0059BE30[label=Ruleset]
_0059BE30 -> _0059BD70
_0059BE30 -> _0059BE18
_0059BD70[label=SelectorList]
_0059BD70 -> _00597EC0
_0059BD70 -> _0059BD58
_00597EC0[label=SelectorList]
_00597EC0 -> _00597E78
_00597E78[label=Selector]
_00597E78 -> _00597E30
_00597E78 -> _00597C98
_00597E30[label=SimpleSelector]
_00597E30 -> _00597DF0
_00597DF0[label=SpecifierList]
_00597DF0 -> _00597DD8
_00597DF0 -> _00597D50
_00597DD8[label=SpecifierPseudo]
_00597D50[label=SpecifierList]
_00597D50 -> _00597D38
_00597D38[label=SpecifierClass]
_00597C98[label=Selector]
_00597C98 -> _00597C50
_00597C50[label=SimpleSelector]
_00597C50 -> _00597C10
_00597C10[label=SpecifierList]
_00597C10 -> _00597BF8
_00597C10 -> _00597B70
_00597BF8[label=SpecifierClass]
_00597B70[label=SpecifierList]
_00597B70 -> _00597B58
_00597B58[label=SpecifierClass]
_0059BD58[label=Selector]
_0059BD58 -> _0059BD40
_0059BD40[label=SimpleSelector]
_0059BD40 -> _0059BCA0
_0059BCA0[label=SpecifierList]
_0059BCA0 -> _00597F68
_00597F68[label=SpecifierElement]
_0059BE18[label=DeclarationList]
_0059BE18 -> _0059BDD0
_0059BE18 -> _0059BE00
_0059BDD0[label=DeclarationList]
_0059BDD0 -> _0059BDA0
_0059BDA0[label=Declaration]
_0059BDA0 -> _0059BD88
_0059BD88[label=Expression]
_0059BD88 -> _0059C5C8
_0059C5C8[label=TermHex]
_0059BE00[label=Declaration]
_0059BE00 -> _0059BDE8
_0059BDE8[label=Expression]
_0059BDE8 -> _0059C620
_0059C620[label=TermInteger]
_0059BFF8[label=Ruleset]
_0059BFF8 -> _0059BED8
_0059BFF8 -> _0059BFE0
_0059BED8[label=SelectorList]
_0059BED8 -> _0059BEC0
_0059BEC0[label=Selector]
_0059BEC0 -> _0059BEA8
_0059BEA8[label=Selector]
_0059BEA8 -> _0059BE90
_0059BE90[label=SimpleSelector]
_0059BE90 -> _0059BE78
_0059BE78[label=SpecifierList]
_0059BE78 -> _0059BE60
_0059BE60[label=SpecifierClass]
_0059BFE0[label=DeclarationList]
_0059BFE0 -> _0059BF50
_0059BFE0 -> _0059BFC8
_0059BF50[label=DeclarationList]
_0059BF50 -> _0059BF38
_0059BF38[label=Declaration]
_0059BF38 -> _0059BF20
_0059BF20[label=Expression]
_0059BF20 -> _0059BF08
_0059BF20 -> _0059C8E0
_0059BF08[label=Expression]
_0059BF08 -> _0059BEF0
_0059BF08 -> _0059C860
_0059BEF0[label=Expression]
_0059BEF0 -> _0059C7E0
_0059C7E0[label=TermString]
_0059C860[label=TermIndent]
_0059C8E0[label=TermIndent]
_0059BFC8[label=Declaration]
_0059BFC8 -> _0059BFB0
_0059BFB0[label=Expression]
_0059BFB0 -> _0059BF98
_0059BFB0 -> _0059CA80
_0059BF98[label=Expression]
_0059BF98 -> _0059BF80
_0059BF98 -> _0059CA20
_0059BF80[label=Expression]
_0059BF80 -> _0059BF68
_0059BF80 -> _0059C9C0
_0059BF68[label=Expression]
_0059BF68 -> _0059C980
_0059C980[label=TermInteger]
_0059C9C0[label=TermInteger]
_0059CA20[label=TermInteger]
_0059CA80[label=TermInteger]
}
渲染结果为