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

时间:2014-01-05 14:23:08

标签: 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 a和b的信息。

如果符号表是集中的,foo的info和bar的信息都驻留在一个符号表中,但是可能有条目指定a,b在foo中属于foo的范围,a,b在bar中属于bar。没有其他符号表可以引用

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

由于

1 个答案:

答案 0 :(得分:4)

您需要将源标识符中的标识符映射到类型/含义,每个范围实例,如语言所定义。有些人会把这样一个单一的映射称为“符号表”,但我认为这是对该术语的滥用;对于这样的单个范围映射,我更喜欢术语“符号空间”。对我来说,映射的 set 是符号表。

符号空间/表的概念与编译器创建这样的符号空格/表的方式和时间无关。

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

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

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

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

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