当评估函数调用的参数列表时,代码生成器可以通过将列表与存储在符号表中的函数签名进行比较来判断缺少哪些参数。一旦您辨别出需要替换哪个参数,只需将默认值放入参数寄存器(或堆栈帧)即可。如果您正在处理一种 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 所提到的,在符号表记录中创建一个字段听起来是最简单的方法。为缺少的参数生成代码时,请在表中查找默认值。