2

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

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

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

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

回答

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所说的,在符号表记录中创建一个字段听起来就像是最简单的方法。在为缺少的参数生成代码时,查找表中的默认值。

+0

再次感谢您。我记得你回答我的另一个问题。我想知道编译器如何处理由程序员设置的默认值,而不是“类”或“类型”的“默认”。谢谢。 – 2012-04-16 20:47:02

+0

@SimonGuo:更新。 – blackcompe 2012-04-16 21:09:22

3

无论您如何操作,您都必须将默认值与特定标识符相关联。

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

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

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