#include // Externally visible, for the generator extern tlhash_t *global_names; extern char **string_list; extern size_t n_string_list, stringc; // Implementation choices, only relevant internally static void find_globals ( void ); static void bind_names ( symbol_t *function, node_t *root ); static void print_symbols ( tlhash_t *table ); static void destroy_symtab ( void ); // Internal details of name resolution static size_t n_scopes = 1, scope_depth = 0; static tlhash_t **scopes = NULL; /* External interface */ void create_symbol_table ( void ) { find_globals(); size_t n_globals = tlhash_size ( global_names ); symbol_t *global_list[n_globals]; tlhash_values ( global_names, (void **)&global_list ); for ( size_t i=0; itype == SYM_FUNCTION ) bind_names ( global_list[i], global_list[i]->node ); } void print_symbol_table ( void ) { print_symbols ( global_names ); } void destroy_symbol_table ( void ) { destroy_symtab(); } /* Internal matters */ static void print_symbols ( tlhash_t *table ) { if ( table == NULL ) return; size_t n_entries = tlhash_size(table); symbol_t *entry_list[n_entries]; tlhash_values ( table, (void **)&entry_list ); for ( size_t e=0; etype ) { case SYM_FUNCTION: fprintf ( stderr, "function: %s\n", entry_list[e]->name ); if ( entry_list[e]->type == SYM_FUNCTION ) print_symbols ( entry_list[e]->locals ); break; case SYM_GLOBAL_VAR: fprintf ( stderr, "global var: %s\n", entry_list[e]->name ); break; case SYM_PARAMETER: fprintf ( stderr, "parameter: %s\n", entry_list[e]->name ); break; case SYM_LOCAL_VAR: fprintf ( stderr, "local var: %s\n", entry_list[e]->name ); break; default: /* This should never happen if all symbols have correct type */ fprintf ( stderr, "** Unknown symbol: %s\n", entry_list[e]->name ); break; } } } static void add_global ( symbol_t *symbol ) { tlhash_insert ( global_names, symbol->name, strlen(symbol->name), symbol ); } static void find_globals ( void ) { global_names = malloc ( sizeof(tlhash_t) ); tlhash_init ( global_names, 32 ); string_list = malloc ( n_string_list * sizeof(char * ) ); size_t n_functions = 0; node_t *global_list = root->children[0]; for ( uint64_t g=0; gn_children; g++ ) { node_t *global = global_list->children[g], *namelist; symbol_t *symbol; switch ( global->type ) { case FUNCTION: symbol = malloc ( sizeof(symbol_t) ); *symbol = (symbol_t) { .type = SYM_FUNCTION, .name = global->children[0]->data, .node = global->children[2], .seq = n_functions, .nparms = 0, .locals = malloc ( sizeof(tlhash_t) ) }; n_functions++; tlhash_init ( symbol->locals, 32 ); if ( global->children[1] != NULL ) { symbol->nparms = global->children[1]->n_children; for ( int p=0; pnparms; p++ ) { node_t *param = global->children[1]->children[p]; symbol_t *psym = malloc ( sizeof(symbol_t) ); *psym = (symbol_t) { .type = SYM_PARAMETER, .name = param->data, .node = NULL, .seq = p, .nparms = 0, .locals = NULL }; tlhash_insert ( symbol->locals, psym->name, strlen(psym->name), psym ); } } add_global ( symbol ); break; case DECLARATION: namelist = global->children[0]; for ( uint64_t d=0; dn_children; d++ ) { symbol = malloc ( sizeof(symbol_t) ); *symbol = (symbol_t) { .type = SYM_GLOBAL_VAR, .name = namelist->children[d]->data, .node = NULL, .seq = 0, .nparms = 0, .locals = NULL }; add_global(symbol); } break; } } } static void push_scope ( void ) { if ( scopes == NULL ) scopes = malloc ( n_scopes * sizeof(tlhash_t *) ); tlhash_t *new_scope = malloc ( sizeof(tlhash_t) ); tlhash_init ( new_scope, 32 ); scopes[scope_depth] = new_scope; scope_depth += 1; if ( scope_depth >= n_scopes ) { n_scopes *= 2; scopes = realloc ( scopes, n_scopes*sizeof(tlhash_t **) ); } } static void add_local ( symbol_t *local ) { tlhash_insert ( scopes[scope_depth-1],local->name,strlen(local->name),local ); } static symbol_t * lookup_local ( char *name ) { symbol_t *result = NULL; size_t depth = scope_depth; while ( result == NULL && depth > 0 ) { depth -= 1; tlhash_lookup ( scopes[depth], name, strlen(name), (void **)&result ); } return result; } static void pop_scope ( void ) { scope_depth -= 1; tlhash_finalize ( scopes[scope_depth] ); free ( scopes[scope_depth] ); scopes[scope_depth] = NULL; } static void add_string ( node_t *string ) { string_list[stringc] = string->data; string->data = malloc ( sizeof(size_t) ); *((size_t *)string->data) = stringc; stringc++; if ( stringc >= n_string_list ) { n_string_list *= 2; string_list = realloc ( string_list, n_string_list * sizeof(char *) ); } } static void bind_names ( symbol_t *function, node_t *root ) { if ( root == NULL ) return; else switch ( root->type ) { node_t *namelist; symbol_t *entry; case BLOCK: push_scope(); for ( size_t c=0; cn_children; c++ ) bind_names ( function, root->children[c] ); pop_scope(); break; case DECLARATION: namelist = root->children[0]; for ( uint64_t d=0; dn_children; d++ ) { node_t *varname = namelist->children[d]; size_t local_num = tlhash_size(function->locals) - function->nparms; symbol_t *symbol = malloc ( sizeof(symbol_t) ); *symbol = (symbol_t) { .type = SYM_LOCAL_VAR, .name = varname->data, .node = NULL, .seq = local_num, .nparms = 0, .locals = NULL }; tlhash_insert ( function->locals, &local_num, sizeof(size_t), symbol ); add_local ( symbol ); } break; case IDENTIFIER_DATA: entry = lookup_local ( root->data ); if ( entry == NULL ) tlhash_lookup ( function->locals, root->data, strlen(root->data), (void**)&entry ); if ( entry == NULL ) tlhash_lookup ( global_names,root->data,strlen(root->data),(void**)&entry ); if ( entry == NULL ) { fprintf ( stderr, "Identifier '%s' does not exist in scope\n", (char *)root->data ); exit ( EXIT_FAILURE ); } root->entry = entry; break; case STRING_DATA: add_string ( root ); break; default: for ( size_t c=0; cn_children; c++ ) bind_names ( function, root->children[c] ); break; } } void destroy_symtab ( void ) { for ( size_t i=0; ilocals != NULL ) { size_t n_locals = tlhash_size ( glob->locals ); symbol_t *locals[n_locals]; tlhash_values ( glob->locals, (void **)&locals ); for ( size_t l=0; llocals ); free ( glob->locals ); } free ( glob ); } tlhash_finalize ( global_names ); free ( global_names ); free ( scopes ); }