2

一些编程语言允许参数在函数调用中具有默认值或结构中的属性具有默认值。像 python 或 javascript 一样,当我们在函数调用中省略一些参数时,函数中的默认值将被替换(就像 struct 也可以在属性中具有默认值一样)。那么编译器实际上是如何处理这个问题的呢?特别是在符号表中?我想为指向默认值的指针添加一个额外的属性我猜默认值在运行时推送到堆栈上?请让我知道我是否正确。谢谢。

更新: 这里的默认值我的意思是在 Python 中说,以下程序参数b具有默认值0

def foo(a, b=0):
    return a+b
print foo(1)
print foo(1, 1)

我们会得到结果01。那么编译器在运行时或编译时是如何处理的呢?

4

2 回答 2

3

不管你怎么做,你都必须把默认值和具体的标识符关联起来。

参数列表和结构成员形成小的命名空间,编译器通常通过为这些命名空间构建符号表和跟踪命名空间如何相关的更大符号表来跟踪它们。

由于编译器通常已经在这些将其他信息与符号(例如,任何类型信息)相关联的小名称空间中具有符号表条目,因此这是一个非常自然的记录它的地方。

有一个问题是要为初始值记录什么。一件简单的事情就是简单地记录一个指向 AST 的指针,该指针表示初始/默认值。除此之外,还必须记录应该在其中评估该表达式的上下文(例如,“环境”)。该上下文通常可以隐含,因为它通常与定义结构/参数的上下文相同,并且该信息存储在将所有内容粘合在一起的更大的符号表中。

于 2012-04-16T05:44:37.393 回答
1

当评估函数调用的参数列表时,代码生成器可以通过将列表与存储在符号表中的函数签名进行比较来判断缺少哪些参数。一旦您辨别出需要替换哪个参数,只需将默认值放入参数寄存器(或堆栈帧)即可。如果您正在处理一种 OO 语言并且形式参数是一个对象,您可能会将 0 (NULL) 压入堆栈的下一个单词。如果参数是内置原语,您将推送语言指定的任何默认值。

当然编译器可能会有所不同,但在一个简单的编译器中,在符号表中关联一个默认值并不是绝对必要的。首先,让我们明确一点,符号表记录了所有的变量声明。您必须存储有关这些声明的信息(例如类、方法、类型、行、字符等),但是当只有少数类型时,当然没有必要为每个变量记录默认值,因此只有少数可能的默认值。

某些语言 (Java/C++) 指定具有未初始化对象属性的类的默认值为 NULL。在实现类似的东西时,当代码生成器创建类构造函数时,它一定会生成将 0 放置在映射到该属性的对象内存中的代码(假设一切都是基于指针的)。当您去生成构造函数,并且您正在迭代类属性列表(一个 AST 节点)时,如果该属性没有初始化表达式,则调用一个方法来执行默认值。

private void genConstructor(int classId) {

     //allocate new object

     codeGen.write("li $a0, "+classId); 
     codeGen.write("jal Runtime.newObject");

     //call parent constructor

     codeGen.write("move $a0, $v0"); 
     codeGen.write("jal ParentInit");

     //initialize the attributes this class has declared

     for(Attributes a: getAttributes(classId)) {

        //provide default value
        if(a.getInitExpr() == null)
            doDefault(a.getType(), a.getNum());
        else
            doInit(a.getInitExpr(), a.getNum());
     }
}

// An 'Int' default value is 1, everything else is 0 (Objects included)
// $t0 has the object address
// attributes start at the 5th word of each object 
private void doDefault(String type, int attrNum) {
     switch(type) {
          case "Int": {
                codeGen.write("sw $one, "+(5+attrNum)+"($t0)");
          }
          default: {
                codeGen.write("sw $zero, "+(5+attrNum)+"($t0)");
          }
     }
}

更新:

我想知道编译器如何处理程序员设置的默认值,而不是“类”或“类型”的“默认”。

我假设您说的是类似于 C++ 构造函数中的默认参数的东西。在这种情况下,正如 Ira 所提到的,在符号表记录中创建一个字段听起来是最简单的方法。为缺少的参数生成代码时,请在表中查找默认值。

于 2012-04-16T18:44:23.190 回答