compiler-construction - 如何在多遍编译器中正确重用符号表
问题描述
我目前正在为一种块结构的语言语言构建一个多遍编译器。我在语义分析阶段建立了一个范围堆栈。当进入一个新的作用域时,创建一个新的表,将它压入堆栈并使其成为当前作用域表,然后这个作用域内的所有符号都插入到当前表中。离开作用域时,当前表记录在 AST 节点中,然后从作用域堆栈中弹出。
这样,在代码生成阶段,就不必重新构建符号表了。一旦它进入一个新的作用域,它可以简单地从 AST 节点获取表,然后将其推送到作用域堆栈。我认为这是大多数编译器教科书推荐的方式。
在大多数情况下,这工作得很好,但是,有一个我不知道如何正确处理的极端情况。考虑以下代码示例:
int a = 1;
int b = 2;
void test()
{
int a = b;
int b = 3;
}
它有两个作用域:全局作用域和 test() 的作用域。因此,要为 test() 生成代码,我们必须:
- 将全局符号表推送到作用域堆栈
- 从 AST 节点获取 test() 的符号表并将其推送到范围堆栈
现在,在处理“int a = b;”时,它会从作用域堆栈中找到局部变量 b,这显然是不正确的,因为尚未声明局部 b。
知道如何处理这个问题吗?离开作用域时是否必须销毁所有符号并在代码生成阶段重新构建符号表?
多谢你们!
解决方案
该问题的一种解决方案是让标识符的 AST 节点包含指向创建时在符号表中找到的特定符号的链接。在假设程序文本从头到尾按顺序解析的情况下,一次一条语句,这将给出正确的符号。这也消除了在符号表中重复查找的需要。
推荐阅读
- c# - SQL 网络接口,错误:26:错误定位服务器
- c++ - 将数字打印成单词
- hyperledger-fabric - 当标识符为 userId 时,如何通过电子邮件 ID 从注册表中获取参与者
- integration-testing - 测试之间的相同实例
- websphere-liberty - Websphere Liberty 配置文件部署错误
- firebase - 我的 Firebase 云功能可以利用吗?
- node.js - 我如何为反应和节点应用程序设置 VS Code 调试器
- entity-framework-core - 多对多关系返回对象 null 但正确的 id
- gimp - GIMP中的高斯模糊脚本
- angular - 在 Angular 7 中解析 HTTP 响应?