如何在多通道编译器中正确重用符号 table
How to properly reuse symbol table in a multi-pass compiler
我目前正在为块结构语言语言构建多通道编译器。我在语义分析阶段构建了一个范围堆栈。当进入一个新的作用域时,创建一个新的table,将其压入堆栈并使其成为当前作用域table,然后将此作用域内的所有符号插入当前table。
离开作用域时,将当前table记录在AST节点中,然后从作用域栈中弹出。
这样,在代码生成阶段,就不必重新构建符号 table。一旦它进入一个新的作用域,它可以简单地从 AST 节点获取 table 然后将其推入作用域堆栈。我认为这是大多数编译器教科书推荐的方式。
在大多数情况下,这工作得很好,但是,有一个极端情况我不知道如何正确处理。考虑以下代码示例:
int a = 1;
int b = 2;
void test()
{
int a = b;
int b = 3;
}
它有两个作用域:全局作用域和 test() 的作用域。
因此,要为 test() 生成代码,我们必须:
- 将全局符号table推入作用域堆栈
- 从 AST 节点获取 test() 的符号 table 并将其推送到作用域堆栈
现在,在处理“int a = b;”时,它会从作用域堆栈中找到局部变量 b,这显然是不正确的,因为局部 b 尚未声明。
知道如何处理这个问题吗?
我是否必须在离开范围时销毁所有符号并在代码生成阶段重新构建符号 table?
谢谢大家!
这个问题的一个解决方案是让标识符的 AST 节点包含一个 link 到在其创建时在符号 table 中找到的特定符号。假设程序文本是从头到尾按顺序解析的,一次一条语句,这将给出正确的符号。这也消除了在符号 table.
中重复查找的需要
我目前正在为块结构语言语言构建多通道编译器。我在语义分析阶段构建了一个范围堆栈。当进入一个新的作用域时,创建一个新的table,将其压入堆栈并使其成为当前作用域table,然后将此作用域内的所有符号插入当前table。 离开作用域时,将当前table记录在AST节点中,然后从作用域栈中弹出。
这样,在代码生成阶段,就不必重新构建符号 table。一旦它进入一个新的作用域,它可以简单地从 AST 节点获取 table 然后将其推入作用域堆栈。我认为这是大多数编译器教科书推荐的方式。
在大多数情况下,这工作得很好,但是,有一个极端情况我不知道如何正确处理。考虑以下代码示例:
int a = 1;
int b = 2;
void test()
{
int a = b;
int b = 3;
}
它有两个作用域:全局作用域和 test() 的作用域。 因此,要为 test() 生成代码,我们必须:
- 将全局符号table推入作用域堆栈
- 从 AST 节点获取 test() 的符号 table 并将其推送到作用域堆栈
现在,在处理“int a = b;”时,它会从作用域堆栈中找到局部变量 b,这显然是不正确的,因为局部 b 尚未声明。
知道如何处理这个问题吗? 我是否必须在离开范围时销毁所有符号并在代码生成阶段重新构建符号 table?
谢谢大家!
这个问题的一个解决方案是让标识符的 AST 节点包含一个 link 到在其创建时在符号 table 中找到的特定符号。假设程序文本是从头到尾按顺序解析的,一次一条语句,这将给出正确的符号。这也消除了在符号 table.
中重复查找的需要