从多行代码创建AST时的一般做法是什么?例如,如果我正在编写一个翻译器将代码从一种语言翻译成另一种语言,我遇到了一组这样的语句:
x = 2
f = k->o
a = 1+2*3
我可以在这里为每个代码行成功创建AST。现在,在必须生成已翻译的代码时,如果代码长度为n行,我会更好地使用一个AST而不是n个AST吗?如果是这样,那个单一的AST是如何形成的?
答案 0 :(得分:1)
首先,您可能不应该再考虑“代码行”了。解析器的输入是令牌流。你做有词法分析器,不是吗? : - )
AST完全可以(和正常)完成许多语句。实际上,它通常会跨越整个编译单元,例如单个函数甚至整个模块(读取:源文件)。
例如,请考虑以下程序:
fun f(x, y) {
z = x + y;
if (z > 3) {
return z;
} else {
return g(x);
}
}
fun g(x) {
return x * 2;
}
编译器可能会构建一个类似于此的AST(请忽略具体细节并关注一般结构):
ModNode
FunNode[Name = "f"]
CompoundStmtNode
AssignStmtNode
VarNode[Name = "z"]
BinExprNode[Oper = "+"]
VarNode[Name = "x"]
VarNode[Name = "y"]
IfStmtNode
BinExprNode[Oper = ">"]
VarNode[Name = "z"]
ConstNode[Value = 3]
CompoundStmtNode
ReturnNode
VarNode[Name = "z"]
CompoundStmtNode
ReturnNode
CallNode[Name = "g"]
VarNode[Name = "x"]
FunNode[Name = "g"]
CompoundStmtNode
ReturnNode
BinExprNode[Oper = "*"]
VarNode[Name = "x"]
ConstNode[Value = 2]
为整个源文件构建AST的好处是可以轻松地对代码执行多次逻辑传递(例如,为了解析前向引用)。当然,缺点是AST可能会变得非常大。
答案 1 :(得分:-1)
我建议你有一个由较小的Asts制成的Ast。并使用递归遍历它们。对于树的设计,您可以选择任何一方。但我会使用右侧的每一行,左侧指向下一行代码。把它画出来。我假设你知道如何通过assignNode和exprNode解析并显示更大的图片
x = 2
f = k-> o
a = 1 + 2 * 3
所以你有这个。
[AssignNode]
left right
[AssignNode] [x=2]
left right
[AssignNode] [f=k->o]
left right
[Null] a = [ExprNode]
[1] + [2*3]
Traversal将从右向前开始直到我们达到null。一旦我们点击null返回到节点并向左移动。
因为这是一个由较小的组成的Ast。每次我们点击一个新的Node / Ast时,我们都会进行相同的遍历,然后再向左走。
给我们 go right get x = 2 然后点击null返回并向左转。 获取AssignNode go right get f = k-> o 然后点击null返回并向左转。 获取AssignNode go right get a = ExprNode 向右转并解析ExprNode返回 并完成assignNode返回 然后走了 左边是空的。