Name Resolution

A step prior to type-checking.

Symbol Table

  • Symbol table = a hash table containing the info about the symbols.
  • For each declaration, create a symbol and enter into table.
  • For each expression node in the AST, look up the symbol table to ensure the type consistency.
  • Multiple hash tables (called “scopes”) in a stack are needed to keep track of the current scope.
  • Look for symbols in each scope in the stack.
/* symbol.h */
 
typedef enum {
    SYMBOL_LOCAL;
    SYMBOL_PARAM;
    SYMBOL_GLOBAL;
} kind;
 
struct symbol {
    symbol_t kind;
    struct type *type;
    char *name;
    int which; // local 0, local 1, param 0, param 1, etc...
}
 
struct symbol *symbol_create( ... );
 
void symbol_print(struct symbol * s);

Name Resolution

  • Walk the AST
    • For each decl, insert the symbol.
    • For every use, lookup the symbol.
void decl_resolve(struct decl *d) {
    struct symbol s = symbol_create(SYMBOL_GLOBAL, d->type);
    scope_bind(d->name, s);
    d->symbol = s;
 
    if(d->code) {
        scope_enter();
        param_list_resolve(d->type->params);
        stmt_resolve(d->code);
        scope_exit();
    }
 
    decl_resolve(d->next);
}
 
void expr_resolve(struct expr *e) {
    if(e->kind == EXPR_IDENT) {
        e->symbol = scope_lookup(e->name);
    } else {
        expr_resolve(e->left);
        expr_resolve(e->right);
    }
}