程序范围的数据结构?

时间:2016-09-29 18:03:52

标签: data-structures tree compiler-construction

我正在尝试通过一个程序的AST解析一个编写语言,具体我试图模拟范围,所以你输入一个函数,例如你推一个新的范围,当功能完成访问者访问,弹出范围。一个重要的方面是,当我们推送一个新范围时,会设置一个指针currentScope,指向我们当前正在查看的范围。当我们弹出范围时,此currentScope将设置为“外部”:

class Scope:
    outer : Scope
    inner : Scope

这将在多次传递中发生,但第一次传递它很重要,它构造了范围的一般树。 我问的问题是,我怎么能按照它创建的顺序遍历这棵树? 例如:

{ // global scope
    { // a
        { // aa

        }
        { // ab
        }
    }
    { // b
    }
}

当我再次传递完全相同的节点集时,理论上它们会给我相同的范围树,但我想保留我们收集的所有数据并将每个范围存储在每个传递中。换句话说,当第二次或第三次传递发生在AST上时,当我们访问a,currentScope = a时,当我们访问aa时,则currentScope = aa。这可能吗?我真的对这个想法感到困惑,整个递归方面真的搞得一团糟,我似乎无法弄清楚如何做到这一点。

这是我尝试过的:

class Scope
    outer : Scope
    inner : Scope
    siblings : []Scope

    Scope(outer):
        this.outer = outer

push_idx = 0

push_scope()
    // set global scope
    if current is null
        global = new Scope(null)
        current = global
        return

    if current.inner is not null:
        // first pass over the AST
        if current_pass == 0:
            new_scope = new Scope(current)
            current.siblings.push(new_scope)
            current = new_scope
            return
        current = current.siblings[push_idx++]
    else:
        new_scope = new Scope(current)
        current.inner = new_scope
        current = current.inner

pop_scope()
    push_idx = 0
    current = current.outer

虽然订单似乎不正确,但我相当确定这是错误的做法。

3 个答案:

答案 0 :(得分:3)

通常用于跟踪编译器内部范围的数据结构是 spaghetti堆栈,本质上是一个链表数据结构,其中每个作用域都是一个存储指向其父作用域的指针的节点。每当您输入范围时,您都会创建一个新节点,将其指向封闭范围,然后将该节点存储在与该范围关联的AST中的某个位置。当你走AST时,你的AST walker存储一个指向当前范围节点的指针。输入范围时,将创建一个新的范围节点,如上所述。离开作用域时,将指针更改为指向当前作用域的父级。这最终构建了一个大的倒置树结构,其中每个范围都可以跟踪其范围链到根范围 - 意大利面条堆栈。

答案 1 :(得分:0)

"适用范围"实际上是该程序的一个区域,该区域中的所有标识符都具有恒定的含义。

如果您的语言具有纯嵌套词法范围,您可以使用树(" spaghetti"堆栈,如果您愿意)对范围进行建模,其中每个叶子包含从该范围中引入的符号到他们对应的类型信息。这是编译器类中经典教授的内容。

但是通常使用更复杂的范围规则(命名空间,使用构造,......),您可能需要一个图形,其叶子是各个范围,图形弧表示范围之间的关系。是的,其中一个关系通常是" lexical parent"。其他可能包括"继承自"等。你也可能发现叶映射中的名称可能是一个类型,它实际上可能是图中任意其他(叶)范围的访问路径

(我构建了通用程序分析工具基础架构[参见bio]。我们定义了一个图形式符号表API,以支持我们遇到的所有不同的作用域规则。一个有趣的弧类是"继承优先级N"对于任意整数N;这使我们可以轻松地模拟C ++提供的有序多重继承。

答案 2 :(得分:0)

也许你应该考虑Segment tree

  • 每个段都显示一个范围(范围的开头|范围的结尾)。
  • 树结构将根据代码层次结构。
  • 树的叶子将是每个范围内的关键字。
祝你好运!