首页 > 解决方案 > 如何在多遍编译器中正确重用符号表

问题描述

我目前正在为一种块结构的语言语言构建一个多遍编译器。我在语义分析阶段建立了一个范围堆栈。当进入一个新的作用域时,创建一个新的表,将它压入堆栈并使其成为当前作用域表,然后这个作用域内的所有符号都插入到当前表中。离开作用域时,当前表记录在 AST 节点中,然后从作用域堆栈中弹出。

这样,在代码生成阶段,就不必重新构建符号表了。一旦它进入一个新的作用域,它可以简单地从 AST 节点获取表,然后将其推送到作用域堆栈。我认为这是大多数编译器教科书推荐的方式。

在大多数情况下,这工作得很好,但是,有一个我不知道如何正确处理的极端情况。考虑以下代码示例:

int a = 1;
int b = 2;

void test()
{
    int a = b;
    int b = 3;
}

它有两个作用域:全局作用域和 test() 的作用域。因此,要为 test() 生成代码,我们必须:

  1. 将全局符号表推送到作用域堆栈
  2. 从 AST 节点获取 test() 的符号表并将其推送到范围堆栈

现在,在处理“int a = b;”时,它会从作用域堆栈中找到局部变量 b,这显然是不正确的,因为尚未声明局部 b。

知道如何处理这个问题吗?离开作用域时是否必须销毁所有符号并在代码生成阶段重新构建符号表?

多谢你们!

标签: compiler-constructioncode-generationcompiler-optimizationsymbol-table

解决方案


该问题的一种解决方案是让标识符的 AST 节点包含指向创建时在符号表中找到的特定符号的链接。在假设程序文本从头到尾按顺序解析的情况下,一次一条语句,这将给出正确的符号。这也消除了在符号表中重复查找的需要。


推荐阅读