编译器构造:处理对无序符号的引用
Compiler construction: Handle references to unordered symbols
我有dragonbook,但它似乎无法处理这个主题。。。
在大多数现代语言中,即使某些变量在代码中的出现是无序的,也可以使用它们。
示例
class Foo {
void bar() {
plonk = 42;
}
int plonk;
}
变量plonk
在函数之后声明并不重要。
问题
是否有任何最佳实践/有用的模式来实现这一点?我脑海中浮现出两种方法:
解析时,为看不见的符号添加伪符号。当解析声明时,这些伪符号将被它们的真实符号所取代。解析后,我们可以检查是否还有假人,如果有,则输出一个错误。
解析时不要做任何符号的事情,只创建AST。解析步骤后通过AST并根据节点添加符号。例如,类节点添加子节点的符号,然后对其进行处理。例如,语句块遍历子语句块,并在处理子语句块之前立即添加符号。
我期待方法1。对于"导入其他编译单元"这样的东西来说更容易,也更有用。
编辑:
我在方法1中看到的一个问题是,需要对有序符号进行某种处理。例如,在函数中,在使用本地符号之前不可能使用它。
如果可以,只需在解析过程中构建AST和符号表。然后通过AST将符号与符号表条目关联起来。这基本上是你的第二个策略。
在一般情况下,策略#1的问题是,在看到所有声明之前,您不一定知道同一名称的两个实例绑定到同一符号。例如,考虑一种类似javascript的语言,其中符号的绑定域是一个功能块(IMHO是一个错误,但品味各不相同),但符号在使用前不需要声明。在这种情况下,我们将只考虑命名函数的符号。
伪代码(事实证明是合法的javascript):
function outer() {
return foo();
function inner() {
return foo();
function foo() {
return "inner's foo";
}
}
function foo() {
return "outer's foo";
}
}
foo
的两个用法指的是不同的符号,这是在你达到foo
的最后一个定义之前你无法知道的。
策略#2的问题在于,在不了解所使用的符号的情况下,构建AST并不总是可能的。例如,在C中,如果不知道x
是一个类型名还是一个可以解引用到函数中的东西,就无法真正解析像(x)(y)
这样的表达式。(同样是个错误,IMHO,但我是谁?)。在C++中,您还需要知道给定的符号是否是模板。通常,这被描述为符号的"种类",而不是"类型"。在C++中,解析(x)(y)
不需要知道x
的"类型"是什么;你只需要知道它是否有。因此,C++允许在声明之前使用某些符号,但如果声明是typedef
,则不允许。
抛开病理病例和宏处理器不谈,通常可以在解析过程中定义作用域,并将每个声明附加到一个作用域。通常情况下,作用域以一种相当简单的方式嵌套,因此一旦构建了作用域树,就可以查找给定当前作用域节点的任何符号,只需在树上走一走,直到找到符号。
在某些语言(如python)中,声明是可选的和隐式的;在这种情况下,如果找不到符号,可以在第二次传递中将新定义附加到当前作用域。
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- 将无符号char*转换为std::istream*C++
- 如何在C++中将一个无符号的 int 转换为两个无符号的短裤?
- vscode g++链路故障:体系结构x86_64的未定义符号
- 从矢量<无符号字符>转换为字符* 包括垃圾数据
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- Visual studio代码重构似乎不起作用(例如,重命名符号-f2)
- 使用gcc从静态链接的文件中查找可选符号
- 递归无序映射
- C++中无符号字符溢出
- 使用无符号字符数组有效存储内存
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- VC++本机单元测试,找不到调试符号
- 为什么我必须在C++中添加一个赋值符号来声明一个数组
- c++找不到具有相同哈希的无序集合元素
- 正在将无序映射设置为无序映射的值
- 以三个无符号字符为关键字的无序映射
- 声明一个无符号int和一个数组的无序映射(将具有不同的大小)
- 编译器构造:处理对无序符号的引用