我想从以JSON格式给出的AST构建控制流图(CFG)。所以这个AST是在TouchDevelop中针对每个脚本自动创建的。而且由于TouchDevelop不是面向对象的编程,我还可以使用访问者模式吗?任何有用的指针都将不胜感激。
Update1:我的问题是我不明白从哪里开始。从互联网上,我应该使用访问者模式来浏览AST以访问每个节点并收集信息。从那里,我可以构建一个CFG,然后进行数据流分析。但有两个问题:
1)AFAIK,我需要面向对象的编程模型来使用访问者模式,(我可能错了)TouchDevelop不是。
2)我在互联网上找到的AST不是AST格式。它是JSON格式。我想我可以解析JSON以将其转换为所需的AST结构,但我不太确定。
示例脚本的源代码
meta version "v2.2,nothing";
meta name "DivideByZero";
//
meta platform "current";
action main() {
(5 / 0)→post_to_wall;
}
结果AST(JSON格式化)如下:
{
"type":"app",
"version":"v2.2,nothing",
"name":"DivideByZero",
"icon":null,
"color":null,
"comment":"",
"things":[
{
"type":"action",
"name":"main",
"isEvent":false,
"outParameters":[
],
"inParameters":[
],
"body":[
{
"type":"exprStmt",
"tokens":[
{
"type":"operator",
"data":"("
},
{
"type":"operator",
"data":"5"
},
{
"type":"operator",
"data":"/"
},
{
"type":"operator",
"data":"0"
},
{
"type":"operator",
"data":")"
},
{
"type":"propertyRef",
"data":"post to wall"
}
]
}
],
"isPrivate":false
}
]
}
答案 0 :(得分:7)
我还没有找到对TouchDevelop脚本语言的引用。我不知道你能用它做什么以及你做不了什么。
您不一定要使用访客模式。访问者模式是当抽象语法树由类层次结构中的节点实例描述时使用的方法。从AST到CFG的转换比这更普遍。抽象语法树是抽象数据类型,tree的特例。与任何其他抽象数据类型一样,它可以以多种方式表示。无论你怎么做,但你唯一需要做的就是迭代这棵树。您使用的迭代方法取决于您使用的语言。这应该回答你的问题2 /:JSON字符串可能是AST的表示。 AST是abstract data type,而JSON字符串是此抽象数据类型的实现。
在JSON中,您可以拥有值,数组或(键,值)关联集。我可以假设您的AST节点将是(键,值)关联的集合。我还假设这些节点中的每一个都有一个名为type
的密钥,它允许您识别它是什么类型的节点。
如果我是对的,这就回答了这个问题:为什么你不需要访客模式。访问者模式允许我们提取每个节点的类型。 (这就是所谓的“双重调度”)但是在这里,你不需要它,因为每个节点的类型都在type
字段中编码。
通常,从AST到CFG的转换是通过使用一组函数完成的:AST中每种类型节点的一个函数。这些函数中的每一个都需要编写与其作为参数的节点相关联的CFG部分。它将递归调用子节点的转换函数。 (对于OO-AST,这就是访问者模式会做的事情)
例如,您将拥有一个函数ConvertNode
。此函数将读取节点的type
字段,并使用该节点调用相应的转换函数。您的根节点的类型为app
。然后ConvertNode
函数将调度到ConvertApp
函数。 ConvertApp
会读取name
等字段,并会遍历things
数组并为每个节点调用ConvertNode
。然后,ConvertNode
将调用该调用到相应的函数。
调用这些转换函数的方式完全遵循AST结构。迭代树时如何创建CFG取决于输入语言。每个转换函数都可以返回CFG的构造节点或转换,以允许调用者重用它。或者调用者可以将节点或转换作为参数传递,以允许被调用函数从那里继续构造。您可以自由选择合适的方式来构建CFG并打破一般规则:可以通过巧妙的方式简化构造。