/* ------------------------------------------------------------------------- */ /* "symbols" : The symbols table; creating stock of reserved words */ /* */ /* Part of Inform 6.30 */ /* copyright (c) Graham Nelson 1993 - 2004 */ /* */ /* ------------------------------------------------------------------------- */ #include "header.h" /* ------------------------------------------------------------------------- */ /* This section of Inform is a service detached from the rest. */ /* Only two variables are accessible from the outside: */ /* ------------------------------------------------------------------------- */ int no_symbols; /* Total number of symbols defined */ int no_named_constants; /* Copied into story file */ /* ------------------------------------------------------------------------- */ /* Plus four arrays. Each symbol has its own index n (an int32) and */ /* */ /* svals[n] is its value (must be 32 bits wide, i.e. an int32, tho' */ /* it is used to hold an unsigned 16 bit Z-machine value) */ /* sflags[n] holds flags (see "header.h" for a list) */ /* stypes[n] is the "type", distinguishing between the data type of */ /* different kinds of constants/variables. */ /* (See the "typename()" below.) */ /* symbs[n] (needs to be cast to (char *) to be used) is the name */ /* of the symbol, in the same case form as when created. */ /* slines[n] is the source line on which the symbol value was first */ /* assigned */ /* */ /* Comparison is case insensitive. */ /* Note that local variable names are not entered into the symbols table, */ /* as their numbers and scope are too limited for this to be efficient. */ /* ------------------------------------------------------------------------- */ /* Caveat editor: some array types are set up to work even on machines */ /* where sizeof(int32 *) differs from, e.g., sizeof(char *): so do not */ /* alter the types unless you understand what is going on! */ /* ------------------------------------------------------------------------- */ int32 **symbs; int32 *svals; int *smarks; /* Glulx-only */ int32 *slines; int *sflags; #ifdef VAX char *stypes; /* In VAX C, insanely, "signed char" is illegal */ #else signed char *stypes; #endif /* ------------------------------------------------------------------------- */ /* Memory to hold the text of symbol names: note that this memory is */ /* allocated as needed in chunks of size SYMBOLS_CHUNK_SIZE. */ /* ------------------------------------------------------------------------- */ static uchar *symbols_free_space, /* Next byte free to hold new names */ *symbols_ceiling; /* Pointer to the end of the current allocation of memory for names */ static char** symbol_name_space_chunks; /* For chunks of memory used to hold the name strings of symbols */ static int no_symbol_name_space_chunks; /* ------------------------------------------------------------------------- */ /* The symbols table is "hash-coded" into a disjoint union of linked */ /* lists, so that for any symbol i, next_entry[i] is either -1 (meaning */ /* that it's the last in its list) or the next in the list. */ /* */ /* Each list contains, in alphabetical order, all the symbols which share */ /* the same "hash code" (a numerical function of the text of the symbol */ /* name, designed with the aim that roughly equal numbers of symbols are */ /* given each possible hash code). The hash codes are 0 to HASH_TAB_SIZE */ /* (which is a memory setting) minus 1: start_of_list[h] gives the first */ /* symbol with hash code h, or -1 if no symbol exists with hash code h. */ /* */ /* Note that the running time of the symbol search algorithm is about */ /* */ /* O ( n^2 / HASH_TAB_SIZE ) */ /* */ /* (where n is the number of symbols in the program) so that it is a good */ /* idea to choose HASH_TAB_SIZE as large as conveniently possible. */ /* ------------------------------------------------------------------------- */ static int *next_entry; static int32 *start_of_list; /* ------------------------------------------------------------------------- */ /* Initialisation. */ /* ------------------------------------------------------------------------- */ static void init_symbol_banks(void) { int i; for (i=0; i 0) break; last = this; this = next_entry[this]; } while (this != -1); if (no_symbols >= MAX_SYMBOLS) memoryerror("MAX_SYMBOLS", MAX_SYMBOLS); if (last == -1) { next_entry[no_symbols]=start_of_list[hashcode]; start_of_list[hashcode]=no_symbols; } else { next_entry[no_symbols]=this; next_entry[last]=no_symbols; } if (symbols_free_space+strlen(p)+1 >= symbols_ceiling) { symbols_free_space = my_malloc(SYMBOLS_CHUNK_SIZE, "symbol names chunk"); symbols_ceiling = symbols_free_space + SYMBOLS_CHUNK_SIZE; symbol_name_space_chunks[no_symbol_name_space_chunks++] = (char *) symbols_free_space; } strcpy((char *) symbols_free_space, p); symbs[no_symbols] = (int32 *) symbols_free_space; symbols_free_space += strlen((char *)symbols_free_space) + 1; svals[no_symbols] = 0x100; /* ###-wrong? Would this fix the unbound-symbol-causes-asm-error? */ sflags[no_symbols] = UNKNOWN_SFLAG; stypes[no_symbols] = CONSTANT_T; slines[no_symbols] = ErrorReport.line_number + 0x10000*ErrorReport.file_number; return(no_symbols++); } /* ------------------------------------------------------------------------- */ /* Printing diagnostics */ /* ------------------------------------------------------------------------- */ extern char *typename(int type) { switch(type) { /* These are the possible symbol types. Note that local variables do not reside in the symbol table (for scope and efficiency reasons) and actions have their own name-space (via routine names with "Sub" appended). */ case ROUTINE_T: return("Routine"); case LABEL_T: return("Label"); case GLOBAL_VARIABLE_T: return("Global variable"); case ARRAY_T: return("Array"); case CONSTANT_T: return("Defined constant"); case ATTRIBUTE_T: return("Attribute"); case PROPERTY_T: return("Property"); case INDIVIDUAL_PROPERTY_T: return("Individual property"); case OBJECT_T: return("Object"); case CLASS_T: return("Class"); case FAKE_ACTION_T: return("Fake action"); default: return("(Unknown type)"); } } static void describe_flags(int flags) { if (flags & UNKNOWN_SFLAG) printf("(?) "); if (flags & USED_SFLAG) printf("(used) "); if (flags & REPLACE_SFLAG) printf("(Replaced) "); if (flags & DEFCON_SFLAG) printf("(Defaulted) "); if (flags & STUB_SFLAG) printf("(Stubbed) "); if (flags & CHANGE_SFLAG) printf("(value will change) "); if (flags & IMPORT_SFLAG) printf("(Imported) "); if (flags & EXPORT_SFLAG) printf("(Exported) "); if (flags & SYSTEM_SFLAG) printf("(System) "); if (flags & INSF_SFLAG) printf("(created in sys file) "); if (flags & UERROR_SFLAG) printf("('Unknown' error issued) "); if (flags & ALIASED_SFLAG) printf("(aliased) "); if (flags & ACTION_SFLAG) printf("(Action name) "); if (flags & REDEFINABLE_SFLAG) printf("(Redefinable) "); } extern void describe_symbol(int k) { printf("%4d %-16s %2d:%04d %04x %s ", k, (char *) (symbs[k]), slines[k]/0x10000, slines[k]%0x10000, svals[k], typename(stypes[k])); describe_flags(sflags[k]); } extern void list_symbols(int level) { int k; for (k=0; k