English 中文(简体)
抽象语法树的构造和遍历
原标题:Abstract syntax tree construction and traversal

我不清楚抽象语法树的结构。要在AST所代表的程序源中“向下(前进)”,是直接在最顶部的节点上,还是向下?例如,示例程序

a = 1
b = 2
c = 3
d = 4
e = 5

Result in an AST that looks like this: enter image description here

or this: enter image description here

在第一个节点中,在主节点上“向右”将推进程序,但在第二个节点中只需在每个节点上跟随下一个指针即可。

第二个似乎更正确,因为你不需要像特殊节点类型这样的东西,第一个节点可能有一个超长的指针数组。尽管如此,当您进入循环的如果分支和更复杂的事情时,我可以看到第二个比第一个变得更复杂。

最佳回答

第一种表示是更典型的表示,尽管第二种表示与将树构造为递归数据结构兼容,这可以在实现平台是功能性的而不是命令性的时使用。

考虑:

这是你的第一个例子,除了缩短了“主”节点(概念上的稻草人),更恰当地命名为“块”,以反映命令式编程语言中包含一系列语句的“块”的常见构造。不同类型的节点有不同类型的子节点,有时这些子节点包括顺序很重要的子节点的集合,就像“块”的情况一样。例如,数组初始化可能会产生同样的情况:

int[] arr = {1, 2}

考虑如何在语法树中表示这一点:

这里,数组文字类型节点还有多个相同类型的子节点,它们的顺序很重要。

问题回答

Where in the first one, going "right" on the main node will advance you through the program, but in the second one simply following the next pointer on each node will do the same.

It seems like the second one would be more correct since you don t need something like a special node type with a potentially extremely long array of pointers for the very first node

我几乎总是喜欢第一种方法,而且我认为当您不需要维护指向下一个节点的指针时,您会发现构建AST要容易得多。

我认为让所有对象从一个公共基类派生通常更容易,类似于这样:

abstract class Expr { }

class Block : Expr
{
    Expr[] Statements { get; set; }
    public Block(Expr[] statements) { ... }
}

class Assign : Expr
{
    Var Variable { get; set; }
    Expr Expression { get; set; }
    public Assign(Var variable, Expr expression) { ... }
}

class Var : Expr
{
    string Name { get; set; }
    public Variable(string name) { ... }
}

class Int : Expr
{
    int Value { get; set; }
    public Int(int value) { ... }
}

结果AST如下:

Expr program =
    new Block(new Expr[]
        {
            new Assign(new Var("a"), new Int(1)),
            new Assign(new Var("b"), new Int(2)),
            new Assign(new Var("c"), new Int(3)),
            new Assign(new Var("d"), new Int(4)),
            new Assign(new Var("e"), new Int(5)),
        });

这取决于语言。在C中,您必须使用第一种形式来捕捉块的概念,因为块具有可变范围:

{
    {
        int a = 1;
    }
    // a doesn t exist here
}

变量作用域将是您所称的“主节点”的一个属性。

我相信你的第一个版本更有意义,原因有几个。

首先,第一个更清楚地展示了程序的“嵌套性”,也被明确地实现为有根树(这是树的常见概念)。

第二个也是更重要的原因是,您的“主节点”实际上可能是一个“分支节点”(例如),它可以只是更大AST中的另一个节点。这样,可以从递归的意义上查看AST,其中每个AST都是一个节点,其他AST都是它的子节点。这使得第一个的设计更加简单,更加通用,并且非常均匀。

建议:在处理树数据结构时,无论是与编译器相关的AST还是其他类型,总是使用单个“根”节点,它都可以帮助您执行操作并拥有更多的控制权:

class ASTTreeNode {
  bool isRoot() {...}

  string display() { ... }  
  // ...
}

void main ()
{
  ASTTreeNode MyRoot = new ASTTreeNode();

  // ...

  // prints the root node, plus each subnode recursively
  MyRoot.Show();
}

干杯





相关问题
XML-RPC Standard and XML Data Type

I was looking at XML-RPC for a project. And correct me if I m wrong, but it seems like XML-RPC has no XML datatype. Are you supposed to pass as a string? or something else? Am I missing something? ...

Is it exists any "rss hosting" with API for creating feeds

I am creating a desktop app that will create some reports. I want to export these reports as RSS or ATOM feeds. I can easily create feeds with Rome lib for Java. But I have no idea how to spread them. ...

Improving Q-Learning

I am currently using Q-Learning to try to teach a bot how to move in a room filled with walls/obstacles. It must start in any place in the room and get to the goal state(this might be, to the tile ...

High-traffic, Highly-secure web API, what language? [closed]

If you were planning on building a high-traffic, very secure site what language would you use? For example, if you were planning on say building an authorize.net-scale site, that had to handle tons ...

Def, Void, Function?

Recently, I ve been learning different programming langages, and come across many different names to initalize a function construct. For instance, ruby and python use the def keyword, and php and ...