# Name Resolution A step prior to [[type-checking]]. ## Symbol Table - Symbol table = a [[hash-table|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|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. ```c /* 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|AST]] - For each decl, insert the symbol. - For every use, lookup the symbol. ```c 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); } } ```