首页 > 解决方案 > 编译器如何区分同名项目

问题描述

在以下示例中:

int main(void) {
    int a=7;
    {
        int a=8;
    }
}

生成的程序集将是这样的(来自 Compiler Explorer),没有优化:

main:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $7, -4(%rbp)   // outer scope: int a=7
        movl    $8, -8(%rbp)   // inner scope: int a=8 
        movl    $0, %eax
        popq    %rbp
        ret

如果有重复命名的变量,编译器如何知道变量在哪里?也就是说,当在内部范围内时,内存地址在%rbp-8,而在外部范围内时,地址在%rbp-4

标签: cassemblyscopecompiler-construction

解决方案


有很多方法可以实现本地范围规则。这是一个简单的例子:

  • 编译器可以保留一个嵌套范围列表,每个范围都有自己的符号定义列表。
  • 这个列表最初有一个全局范围的元素,
  • 在解析函数定义时,它会在函数参数名称的作用域列表前面添加一个新的作用域元素,并将每个参数名称与该作用域元素的标识符列表中的相应信息一起添加。
  • 对于每个新块,它会在范围列表前面添加一个新的范围元素。for (在它的第一个子句中也为定义引入了一个新的范围。
  • 离开作用域时(在块的末尾),它会从作用域列表中弹出作用域元素。
  • 在解析声明或定义时,如果对应的符号已经在当前作用域的列表中,则为局部重定义,这是禁止的(extern前向声明除外)。否则,该符号将添加到范围列表中。
  • 当它在表达式中遇到一个符号时,它会在当前作用域的符号列表中查找它,并在作用域列表中的每个后续作用域中查找它,直到找到它。如果找不到符号,则它是未定义的,根据最新的 C 标准,这是一个错误。否则,符号信息将用于进一步的解析和代码生成。

对类型和对象名称执行上述步骤,为 和标签维护单独的struct符号union列表enum

在所有这些发生之前,在程序翻译的一个单独阶段中执行预处理。


推荐阅读