Question

Some programming language allow parameters have default value in function call or attributes in struct has default. Like python or javascript, when we omit some parameters in function call, the default value will be replaced in the function (same as struct can have default in attribute as well). So how does compiler actually handle this? particular in symbol table? I think adding one more additional attribute for pointer pointing to default value also I guess default value pushed on stack on run-time? Please let me know if I am correct. Thanks.

Update: Here default value I mean say in Python, following program parameter b has default value 0.

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

we will get result 0 and 1. So how is this handled by compiler in run-time or compile-time?

Was it helpful?

Solution

When the argument list of a function call is evaluated, the code generator can tell what arguments are missing by comparing the list to the function signature stored in the symbol table. Once you've discerned which argument needs to be replaced, it's just a matter of throwing the default value into the argument registers (or stack frame). If you're dealing with an OO language and the formal parameter is an object, you might push 0 (NULL) into the next word of the stack. If the parameter is a built-in primitive, you'll push whatever default value the language specifies.

Of course compilers can vary, but in a simplistic one, it's not absolutely necessary to associate a default value in the symbol table. First, lets be clear that a symbol table records all variable declarations. You must store information about those declarations (e.g. class, method, type, line, char, etc.), but surely there's no need to record a default value for each variable when there are only but a few types, and thus only a few possible default values.

Some languages (Java/C++) specify that a class with an uninitialized object attribute has a default value of NULL. In implementing something like that, when the code generator creates the class constructor, it'll be sure to generate code that places a 0 in the object memory mapped to that attribute (assume everything is pointer based). When you go to generate the constructor, and you're iterating over the class attribute list (an AST node), if there's no initialization expression for that attribute, call a method to do the default.

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)");
          }
     }
}

Update:

I am wondering how compiler handle the default value set by programmer instead of "default" for "class" or "type".

I'm assuming you're speaking of something similar to default args in C++ constructors. In that case, as Ira mentioned, making a field in the symbol table record sounds like the simplest way to go about it. When generating the code for the missing argument, look up the default value in the table.

OTHER TIPS

No matter how you do it, you have to associate the default value with the specific identifier.

Parameter lists and struct members form small namespaces, and compilers generally track them by building a symbol table for those namespaces and a larger symbol table that keeps track of how the namespaces are related.

Since the compiler already typically has symbol table entries in these small namespaces that associate other information with the symbol (e.g., any type information), this is a pretty natural place to record it.

There's a question of what exactly to record for the initial value. An easy thing to do is simply record a pointer to the AST representing the initial/default value. Along with that, one has to record the context (e.g., "environment") in which that expression should be evaluated. This context can often be left implicit as it usually identical to the context in which the struct/parameters were defined, and that information is stored in the larger symbol table that glues everything together.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top