Compiler construction 如何在多程编译器中正确重用符号表

Compiler construction 如何在多程编译器中正确重用符号表,compiler-construction,code-generation,compiler-optimization,symbol-table,Compiler Construction,Code Generation,Compiler Optimization,Symbol Table,我目前正在为块结构语言构建一个多过程编译器。我在语义分析阶段构建了一个范围堆栈。输入新范围时,创建一个新表,将其推送到堆栈并使其成为当前范围表,然后将此范围内的所有符号插入到当前表中。 离开作用域时,当前表记录在AST节点中,然后将其从作用域堆栈中弹出 这样,在代码生成阶段,它不必重新构建符号表。一旦它进入一个新的作用域,它可以简单地从AST节点获取表,然后将其推送到作用域堆栈。我认为这是大多数编译器教科书推荐的方式 在大多数情况下,这一切都很好,然而,有一个极端的情况我不知道如何正确处理。考虑

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

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

在大多数情况下,这一切都很好,然而,有一个极端的情况我不知道如何正确处理。考虑下面的代码示例:

int a = 1;
int b = 2;

void test()
{
    int a = b;
    int b = 3;
}
它有两个作用域:全局作用域和test()的作用域。 因此,要为test()生成代码,我们必须:

  • 将全局符号表推送到作用域堆栈
  • 从AST节点获取test()的符号表并将其推送到作用域堆栈
  • 现在,当处理“inta=b;”时,它会从作用域堆栈中找到局部可值b,这显然是不正确的,因为局部b尚未声明

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


    谢谢大家

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

    根据源语言的语义定义,这可能是一个没有实际意义的问题。例如,C#将
    test()
    (在本例中)定义为作用域,因此上面的代码将在
    b
    引用上产生错误,因为它尚未定义。也就是说,本地定义隐藏了全局定义,即使它还没有在代码序列中定义。感谢您提供关于C#如何处理此问题的提示。但我希望语义与C相似,所以我希望它能找到全局变量b,直到定义了局部变量b。有什么想法吗?为什么你觉得在解析时需要构造作用域树?您的语法是否需要名称解析来消除歧义?(与C/C++一样)。如果是这样,您可能希望重新考虑该语言设计决策。:-)