为具有多行的代码创建抽象语法树

时间:2016-06-20 18:44:49

标签: compiler-construction abstract-syntax-tree yacc

从多行代码创建AST时的一般做法是什么?例如,如果我正在编写一个翻译器将代码从一种语言翻译成另一种语言,我遇到了一组这样的语句:

x = 2
f = k->o
a = 1+2*3

我可以在这里为每个代码行成功创建AST。现在,在必须生成已翻译的代码时,如果代码长度为n行,我会更好地使用一个AST而不是n个AST吗?如果是这样,那个单一的AST是如何形成的?

2 个答案:

答案 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返回 然后走了 左边是空的。