Compiler construction 如何在编译器中管理符号表

Compiler construction 如何在编译器中管理符号表,compiler-construction,symbol-table,Compiler Construction,Symbol Table,我想知道是只有一个符号表存储了关于源文件的所有信息,还是有多个符号表相互堆叠,并且仅在当前范围与表相关时才获取 比如说我有两种方法 int foo(int a){ int b; bar(b); ... } double bar (int a){ int b; ... } 这里,两个中的a、b的作用域不相同,因此,如果符号表被堆叠,则在执行foo时首先获取与foo相关联的符号表。但是,在执行bar时,bar的符号表堆叠在foo上,因此当前符号表包含bar的

我想知道是只有一个符号表存储了关于源文件的所有信息,还是有多个符号表相互堆叠,并且仅在当前范围与表相关时才获取

比如说我有两种方法

int foo(int a){
    int b;

    bar(b);
    ...
}

double bar (int a){
   int b;
   ...
}
这里,两个中的a、b的作用域不相同,因此,如果符号表被堆叠,则在执行foo时首先获取与foo相关联的符号表。但是,在执行bar时,bar的符号表堆叠在foo上,因此当前符号表包含bar的a和b的信息

如果符号表是集中的,则foo的信息和bar的信息都位于一个符号表中,但可能有一些条目指定foo中的a、b属于foo的范围,而bar中的a、b属于bar。没有其他符号表可供参考

以上是我对符号表的假设。请告诉我哪一个是真实案例,并尽可能详细地填写


谢谢

您需要根据语言定义的源代码中的每个范围实例,将标识符映射到类型/含义。有些人会把这种单一的映射称为“符号表”,但我认为这是对这个术语的滥用;我更喜欢用“符号空间”这个术语来表示这些单独的范围映射。对我来说,范围映射集就是符号表

符号空间/表的概念与编译器创建此类符号空间/表的方式和时间无关

对于经典的类Pascal语言,作用域的嵌套方式恰好与程序嵌套语法相匹配(“词法作用域”)。对于这类语言,可以以类似堆栈的方式创建符号空间,从上到下(从最低行号到最大行号)处理程序。当遇到每个新的范围边界时,会将一个新的符号空间推送到堆栈上。标识符查找通过搜索当前符号空间(堆栈顶部的符号空间)进行,如果未找到标识符,则搜索堆栈下的符号空间。退出作用域时,可以删除该符号空间(例如,弹出)。此方案仅在编译器单次处理程序时有效。有时,您希望保留所有符号空间,以允许在多个过程中对程序进行复杂处理;在这种情况下,, 可以根据遇到的情况创建符号空间,但不能删除它们

许多语言的作用域规则根本不适合符号空间堆栈。一个明显的例子是名称空间,它实际上只是可以从程序中广泛分离的部分访问的符号空间

我构建了相当多的语言处理工具,这些工具需要使用工具基础结构的符号表(有关该工具的详细信息,请参见bio)。大多数情况下,我不使用符号空间的堆栈样式,工具基础设施使创建(必要时删除)符号空间变得简单,并提供了一个符号空间和另一个符号空间之间的链接。其中一个链接是一个特殊的词法范围链接,使基础设施能够记录一个符号空间在词法上嵌入另一个符号空间。然后,标准查找方案搜索“当前”范围,如果没有找到匹配的符号,则遵循词法范围链接继续搜索

这个计划实际上更聪明一些;每个符号空间具有父符号空间链接的关联序列;当在当前范围内找不到符号时,标准词汇搜索(递归)访问父级。只有一个父链接,这与词法范围相同。通过多个父链接,它可以很好地处理多重继承。命名空间是通过使用一个“众所周知”的顶层符号空间来处理的,它包含顶级命名空间的符号等。您可以在C++中看到这样的答案:


在访问词法范围链接之前调用自定义操作(“程序附件”);这允许操作决定首先访问任意其他符号空间。特别是,这使得Java的符号空间搜索能够从文件系统中获取源/类文件,提取它们的符号,然后根据需要继续搜索。

我想这取决于所实现的语言。例如,在C中,函数调用不会导致像这样的嵌套作用域。所以在C中,有一个中心表?嗯,这将取决于编译器。该语言不要求特定的编译器实现。em,是否有任何小型开源编译器,我可以看看它的实现?谷歌“迷你c编译器”。