X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;ds=sidebyside;f=symbols.c;fp=symbols.c;h=0000000000000000000000000000000000000000;hb=81ffe9a7de1db0b3a318a053b38882d1b7ab304c;hp=326316651af503cb2237cdd5bf86f6e72f3e8160;hpb=d1090135a32de7b38b48c55d4e21f95da4c405bc;p=inform.git diff --git a/symbols.c b/symbols.c deleted file mode 100644 index 3263166..0000000 --- a/symbols.c +++ /dev/null @@ -1,1493 +0,0 @@ -/* ------------------------------------------------------------------------- */ -/* "symbols" : The symbols table; creating stock of reserved words */ -/* */ -/* Copyright (c) Graham Nelson 1993 - 2018 */ -/* */ -/* This file is part of Inform. */ -/* */ -/* Inform is free software: you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation, either version 3 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* Inform is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with Inform. If not, see https://gnu.org/licenses/ */ -/* */ -/* ------------------------------------------------------------------------- */ - -#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 six 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 */ -/* symbol_debug_backpatch_positions[n] */ -/* is a file position in the debug information file where */ -/* the symbol's value should be written after backpatching, */ -/* or else the null position if the value was known and */ -/* written beforehand */ -/* replacement_debug_backpatch_positions[n] */ -/* is a file position in the debug information file where */ -/* the symbol's name can be erased if it is replaced, or */ -/* else null if the name will never need to be replaced */ -/* */ -/* 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 */ - brief_location *slines; - int *sflags; -#ifdef VAX - char *stypes; /* In VAX C, insanely, "signed char" is illegal */ -#else - signed char *stypes; -#endif - maybe_file_position *symbol_debug_backpatch_positions; - maybe_file_position *replacement_debug_backpatch_positions; - -/* ------------------------------------------------------------------------- */ -/* Memory to hold the text of symbol names: note that this memory is */ -/* allocated as needed in chunks of size SYMBOLS_CHUNK_SIZE. */ -/* ------------------------------------------------------------------------- */ - -#define MAX_SYMBOL_CHUNKS (100) - -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; - -typedef struct value_pair_struct { - int original_symbol; - int renamed_symbol; -} value_pair_t; -static value_pair_t *symbol_replacements; -static int symbol_replacements_count; -static int symbol_replacements_size; /* calloced size */ - -/* ------------------------------------------------------------------------- */ -/* 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; - /* If we've passed MAX_SYMBOL_CHUNKS chunks, we print an error - message telling the user to increase SYMBOLS_CHUNK_SIZE. - That is the correct cure, even though the error comes out - worded inaccurately. */ - if (no_symbol_name_space_chunks >= MAX_SYMBOL_CHUNKS) - memoryerror("SYMBOLS_CHUNK_SIZE", SYMBOLS_CHUNK_SIZE); - symbol_name_space_chunks[no_symbol_name_space_chunks++] - = (char *) symbols_free_space; - if (symbols_free_space+strlen(p)+1 >= symbols_ceiling) - memoryerror("SYMBOLS_CHUNK_SIZE", SYMBOLS_CHUNK_SIZE); - } - - 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] = get_brief_location(&ErrorReport); - if (debugfile_switch) - { nullify_debug_file_position - (&symbol_debug_backpatch_positions[no_symbols]); - nullify_debug_file_position - (&replacement_debug_backpatch_positions[no_symbols]); - } - - if (track_unused_routines) - df_note_function_symbol(no_symbols); - return(no_symbols++); -} - -extern void end_symbol_scope(int k) -{ - /* Remove the given symbol from the hash table, making it - invisible to symbol_index. This is used by the Undef directive. - If the symbol is not found, this silently does nothing. - */ - - int j; - j = hash_code_from_string((char *) symbs[k]); - if (start_of_list[j] == k) - { start_of_list[j] = next_entry[k]; - return; - } - j = start_of_list[j]; - while (j != -1) - { - if (next_entry[j] == k) - { next_entry[j] = next_entry[k]; - return; - } - j = next_entry[j]; - } -} - -/* ------------------------------------------------------------------------- */ -/* 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]), - (int)(slines[k].file_index), - (int)(slines[k].line_number), - svals[k], typename(stypes[k])); - describe_flags(sflags[k]); -} - -extern void list_symbols(int level) -{ int k; - for (k=0; k"); - debug_file_printf - ("##%s", idname_string); - debug_file_printf("%d", svals[i]); - debug_file_printf(""); - } - - action_name_strings[svals[i]] - = compile_string(idname_string, FALSE, FALSE); - } - } - - for (i=0; i"); - debug_file_printf("%s", name); - write_debug_symbol_optional_backpatch(symbol); - debug_file_printf(""); - break; - case GLOBAL_VARIABLE_T: - debug_file_printf(""); - debug_file_printf("%s", name); - debug_file_printf("
"); - write_debug_global_backpatch(value); - debug_file_printf("
"); - debug_file_printf("
"); - break; - case OBJECT_T: - if (value) - { compiler_error("Non-nothing object predefined"); - } - debug_file_printf(""); - debug_file_printf("%s", name); - debug_file_printf("0"); - debug_file_printf(""); - break; - case ATTRIBUTE_T: - debug_file_printf(""); - debug_file_printf("%s", name); - debug_file_printf("%d", value); - debug_file_printf(""); - break; - case PROPERTY_T: - case INDIVIDUAL_PROPERTY_T: - debug_file_printf(""); - debug_file_printf("%s", name); - debug_file_printf("%d", value); - debug_file_printf(""); - break; - default: - compiler_error - ("Unable to emit debug information for predefined symbol"); - break; - } - } -} - -static void create_symbol(char *p, int32 value, int type) -{ int i = symbol_index(p, -1); - svals[i] = value; stypes[i] = type; slines[i] = blank_brief_location; - sflags[i] = USED_SFLAG + SYSTEM_SFLAG; - emit_debug_information_for_predefined_symbol(p, i, value, type); -} - -static void create_rsymbol(char *p, int value, int type) -{ int i = symbol_index(p, -1); - svals[i] = value; stypes[i] = type; slines[i] = blank_brief_location; - sflags[i] = USED_SFLAG + SYSTEM_SFLAG + REDEFINABLE_SFLAG; - emit_debug_information_for_predefined_symbol(p, i, value, type); -} - -static void stockup_symbols(void) -{ - if (!glulx_mode) - create_symbol("TARGET_ZCODE", 0, CONSTANT_T); - else - create_symbol("TARGET_GLULX", 0, CONSTANT_T); - - create_symbol("nothing", 0, OBJECT_T); - create_symbol("name", 1, PROPERTY_T); - - create_symbol("true", 1, CONSTANT_T); - create_symbol("false", 0, CONSTANT_T); - - /* Glulx defaults to GV2; Z-code to GV1 */ - if (!glulx_mode) - create_rsymbol("Grammar__Version", 1, CONSTANT_T); - else - create_rsymbol("Grammar__Version", 2, CONSTANT_T); - grammar_version_symbol = symbol_index("Grammar__Version", -1); - - if (module_switch) - create_rsymbol("MODULE_MODE",0, CONSTANT_T); - - if (runtime_error_checking_switch) - create_rsymbol("STRICT_MODE",0, CONSTANT_T); - - if (define_DEBUG_switch) - create_rsymbol("DEBUG", 0, CONSTANT_T); - - if (define_USE_MODULES_switch) - create_rsymbol("USE_MODULES",0, CONSTANT_T); - - if (define_INFIX_switch) - { create_rsymbol("INFIX", 0, CONSTANT_T); - create_symbol("infix__watching", 0, ATTRIBUTE_T); - } - - create_symbol("WORDSIZE", WORDSIZE, CONSTANT_T); - create_symbol("DICT_ENTRY_BYTES", DICT_ENTRY_BYTE_LENGTH, CONSTANT_T); - if (!glulx_mode) { - create_symbol("DICT_WORD_SIZE", ((version_number==3)?4:6), CONSTANT_T); - create_symbol("NUM_ATTR_BYTES", ((version_number==3)?4:6), CONSTANT_T); - } - else { - create_symbol("DICT_WORD_SIZE", DICT_WORD_SIZE, CONSTANT_T); - create_symbol("DICT_CHAR_SIZE", DICT_CHAR_SIZE, CONSTANT_T); - if (DICT_CHAR_SIZE != 1) - create_symbol("DICT_IS_UNICODE", 1, CONSTANT_T); - create_symbol("NUM_ATTR_BYTES", NUM_ATTR_BYTES, CONSTANT_T); - create_symbol("GOBJFIELD_CHAIN", GOBJFIELD_CHAIN(), CONSTANT_T); - create_symbol("GOBJFIELD_NAME", GOBJFIELD_NAME(), CONSTANT_T); - create_symbol("GOBJFIELD_PROPTAB", GOBJFIELD_PROPTAB(), CONSTANT_T); - create_symbol("GOBJFIELD_PARENT", GOBJFIELD_PARENT(), CONSTANT_T); - create_symbol("GOBJFIELD_SIBLING", GOBJFIELD_SIBLING(), CONSTANT_T); - create_symbol("GOBJFIELD_CHILD", GOBJFIELD_CHILD(), CONSTANT_T); - create_symbol("GOBJ_EXT_START", 1+NUM_ATTR_BYTES+6*WORDSIZE, CONSTANT_T); - create_symbol("GOBJ_TOTAL_LENGTH", 1+NUM_ATTR_BYTES+6*WORDSIZE+GLULX_OBJECT_EXT_BYTES, CONSTANT_T); - create_symbol("INDIV_PROP_START", INDIV_PROP_START, CONSTANT_T); - } - - if (!glulx_mode) { - create_symbol("temp_global", 255, GLOBAL_VARIABLE_T); - create_symbol("temp__global2", 254, GLOBAL_VARIABLE_T); - create_symbol("temp__global3", 253, GLOBAL_VARIABLE_T); - create_symbol("temp__global4", 252, GLOBAL_VARIABLE_T); - create_symbol("self", 251, GLOBAL_VARIABLE_T); - create_symbol("sender", 250, GLOBAL_VARIABLE_T); - create_symbol("sw__var", 249, GLOBAL_VARIABLE_T); - - create_symbol("sys__glob0", 16, GLOBAL_VARIABLE_T); - create_symbol("sys__glob1", 17, GLOBAL_VARIABLE_T); - create_symbol("sys__glob2", 18, GLOBAL_VARIABLE_T); - - create_symbol("create", 64, INDIVIDUAL_PROPERTY_T); - create_symbol("recreate", 65, INDIVIDUAL_PROPERTY_T); - create_symbol("destroy", 66, INDIVIDUAL_PROPERTY_T); - create_symbol("remaining", 67, INDIVIDUAL_PROPERTY_T); - create_symbol("copy", 68, INDIVIDUAL_PROPERTY_T); - create_symbol("call", 69, INDIVIDUAL_PROPERTY_T); - create_symbol("print", 70, INDIVIDUAL_PROPERTY_T); - create_symbol("print_to_array",71, INDIVIDUAL_PROPERTY_T); - } - else { - /* In Glulx, these system globals are entered in order, not down - from 255. */ - create_symbol("temp_global", MAX_LOCAL_VARIABLES+0, - GLOBAL_VARIABLE_T); - create_symbol("temp__global2", MAX_LOCAL_VARIABLES+1, - GLOBAL_VARIABLE_T); - create_symbol("temp__global3", MAX_LOCAL_VARIABLES+2, - GLOBAL_VARIABLE_T); - create_symbol("temp__global4", MAX_LOCAL_VARIABLES+3, - GLOBAL_VARIABLE_T); - create_symbol("self", MAX_LOCAL_VARIABLES+4, - GLOBAL_VARIABLE_T); - create_symbol("sender", MAX_LOCAL_VARIABLES+5, - GLOBAL_VARIABLE_T); - create_symbol("sw__var", MAX_LOCAL_VARIABLES+6, - GLOBAL_VARIABLE_T); - - /* These are almost certainly meaningless, and can be removed. */ - create_symbol("sys__glob0", MAX_LOCAL_VARIABLES+7, - GLOBAL_VARIABLE_T); - create_symbol("sys__glob1", MAX_LOCAL_VARIABLES+8, - GLOBAL_VARIABLE_T); - create_symbol("sys__glob2", MAX_LOCAL_VARIABLES+9, - GLOBAL_VARIABLE_T); - - /* value of statusline_flag to be written later */ - create_symbol("sys_statusline_flag", MAX_LOCAL_VARIABLES+10, - GLOBAL_VARIABLE_T); - - /* These are created in order, but not necessarily at a fixed - value. */ - create_symbol("create", INDIV_PROP_START+0, - INDIVIDUAL_PROPERTY_T); - create_symbol("recreate", INDIV_PROP_START+1, - INDIVIDUAL_PROPERTY_T); - create_symbol("destroy", INDIV_PROP_START+2, - INDIVIDUAL_PROPERTY_T); - create_symbol("remaining", INDIV_PROP_START+3, - INDIVIDUAL_PROPERTY_T); - create_symbol("copy", INDIV_PROP_START+4, - INDIVIDUAL_PROPERTY_T); - create_symbol("call", INDIV_PROP_START+5, - INDIVIDUAL_PROPERTY_T); - create_symbol("print", INDIV_PROP_START+6, - INDIVIDUAL_PROPERTY_T); - create_symbol("print_to_array",INDIV_PROP_START+7, - INDIVIDUAL_PROPERTY_T); - - /* Floating-point constants. Note that FLOAT_NINFINITY is not - -FLOAT_INFINITY, because float negation doesn't work that - way. Also note that FLOAT_NAN is just one of many possible - "not-a-number" values. */ - create_symbol("FLOAT_INFINITY", 0x7F800000, CONSTANT_T); - create_symbol("FLOAT_NINFINITY", 0xFF800000, CONSTANT_T); - create_symbol("FLOAT_NAN", 0x7FC00000, CONSTANT_T); - } -} - -/* ------------------------------------------------------------------------- */ -/* The symbol replacement table. This is needed only for the */ -/* "Replace X Y" directive. */ -/* ------------------------------------------------------------------------- */ - -extern void add_symbol_replacement_mapping(int original, int renamed) -{ - int ix; - - if (original == renamed) { - error_named("A routine cannot be 'Replace'd to itself:", (char *)symbs[original]); - return; - } - - if (symbol_replacements_count == symbol_replacements_size) { - int oldsize = symbol_replacements_size; - if (symbol_replacements_size == 0) - symbol_replacements_size = 4; - else - symbol_replacements_size *= 2; - my_recalloc(&symbol_replacements, sizeof(value_pair_t), oldsize, - symbol_replacements_size, "symbol replacement table"); - } - - /* If the original form is already in our table, report an error. - Same goes if the replaced form is already in the table as an - original. (Other collision cases have already been - detected.) */ - - for (ix=0; ix" -- their "obj.prop" name - never gets stored in permanent memory. */ - df_current_function_name = name; - df_current_function_addr = address; - - func = my_malloc(sizeof(df_function_t), "df function entry"); - memset(func, 0, sizeof(df_function_t)); - func->name = name; - func->address = address; - func->source_line = source_line; - func->sysfile = (address == DF_NOT_IN_FUNCTION || is_systemfile()); - /* An embedded function is stored in an object property, so we - consider it to be used a priori. */ - if (embedded_flag) - func->usage |= DF_USAGE_EMBEDDED; - - if (!df_functions_head) { - df_functions_head = func; - df_functions_tail = func; - } - else { - df_functions_tail->funcnext = func; - df_functions_tail = func; - } - - bucket = address % DF_FUNCTION_HASH_BUCKETS; - func->next = df_functions[bucket]; - df_functions[bucket] = func; - - df_current_function = func; -} - -/* When we're done compiling a function, call this. Any symbol referenced - from now on will be associated with the global namespace. -*/ -extern void df_note_function_end(uint32 endaddress) -{ - df_current_function->length = endaddress - df_current_function->address; - - df_current_function_name = NULL; - df_current_function_addr = DF_NOT_IN_FUNCTION; - df_current_function = df_functions_head; /* the global namespace */ -} - -/* Find the function record for a given address. (Addresses are offsets - in zcode_area.) -*/ -static df_function_t *df_function_for_address(uint32 address) -{ - int bucket = address % DF_FUNCTION_HASH_BUCKETS; - df_function_t *func; - for (func = df_functions[bucket]; func; func = func->next) { - if (func->address == address) - return func; - } - return NULL; -} - -/* Whenever a function is referenced, we call this to note who called it. -*/ -extern void df_note_function_symbol(int symbol) -{ - int bucket, symtype; - df_reference_t *ent; - - /* If the compiler pass is over, looking up symbols does not create - a global reference. */ - if (df_tables_closed) - return; - /* In certain cases during parsing, looking up symbols does not - create a global reference. (For example, when reading the name - of a function being defined.) */ - if (df_dont_note_global_symbols) - return; - - /* We are only interested in functions, or forward-declared symbols - that might turn out to be functions. */ - symtype = stypes[symbol]; - if (symtype != ROUTINE_T && symtype != CONSTANT_T) - return; - if (symtype == CONSTANT_T && !(sflags[symbol] & UNKNOWN_SFLAG)) - return; - - bucket = (df_current_function_addr ^ (uint32)symbol) % DF_SYMBOL_HASH_BUCKETS; - for (ent = df_symbol_map[bucket]; ent; ent = ent->next) { - if (ent->address == df_current_function_addr && ent->symbol == symbol) - return; - } - - /* Create a new reference entry in df_symbol_map. */ - ent = my_malloc(sizeof(df_reference_t), "df symbol map entry"); - ent->address = df_current_function_addr; - ent->symbol = symbol; - ent->next = df_symbol_map[bucket]; - df_symbol_map[bucket] = ent; - - /* Add the reference to the function's entry as well. */ - /* The current function is the most recently added, so it will be - at the top of its bucket. That makes this call fast. Unless - we're in global scope, in which case it might be slower. - (I suppose we could cache the df_function_t pointer of the - current function, to speed things up.) */ - if (!df_current_function || df_current_function_addr != df_current_function->address) - compiler_error("DF: df_current_function does not match current address."); - ent->refsnext = df_current_function->refs; - df_current_function->refs = ent; -} - -/* This does the hard work of figuring out what functions are truly dead. - It's called near the end of run_pass() in inform.c. -*/ -extern void locate_dead_functions(void) -{ - df_function_t *func, *tofunc; - df_reference_t *ent; - int ix; - - if (!track_unused_routines) - compiler_error("DF: locate_dead_functions called, but function references have not been mapped"); - - df_tables_closed = TRUE; - df_current_function = NULL; - - /* Note that Main__ was tagged as global implicitly during - compile_initial_routine(). Main was tagged during - issue_unused_warnings(). But for the sake of thoroughness, - we'll mark them specially. */ - - ix = symbol_index("Main__", -1); - if (stypes[ix] == ROUTINE_T) { - uint32 addr = svals[ix] * (glulx_mode ? 1 : scale_factor); - tofunc = df_function_for_address(addr); - if (tofunc) - tofunc->usage |= DF_USAGE_MAIN; - } - ix = symbol_index("Main", -1); - if (stypes[ix] == ROUTINE_T) { - uint32 addr = svals[ix] * (glulx_mode ? 1 : scale_factor); - tofunc = df_function_for_address(addr); - if (tofunc) - tofunc->usage |= DF_USAGE_MAIN; - } - - /* Go through all the functions referenced at the global level; - mark them as used. */ - - func = df_functions_head; - if (!func || func->address != DF_NOT_IN_FUNCTION) - compiler_error("DF: Global namespace entry is not at the head of the chain."); - - for (ent = func->refs; ent; ent=ent->refsnext) { - uint32 addr; - int symbol = ent->symbol; - if (stypes[symbol] != ROUTINE_T) - continue; - addr = svals[symbol] * (glulx_mode ? 1 : scale_factor); - tofunc = df_function_for_address(addr); - if (!tofunc) { - error_named("Internal error in stripping: global ROUTINE_T symbol is not found in df_function map:", (char *)symbs[symbol]); - continue; - } - /* A function may be marked here more than once. That's fine. */ - tofunc->usage |= DF_USAGE_GLOBAL; - } - - /* Perform a breadth-first search through functions, starting with - the ones that are known to be used at the top level. */ - { - df_function_t *todo, *todotail; - df_function_t *func; - todo = NULL; - todotail = NULL; - - for (func = df_functions_head; func; func = func->funcnext) { - if (func->address == DF_NOT_IN_FUNCTION) - continue; - if (func->usage == 0) - continue; - if (!todo) { - todo = func; - todotail = func; - } - else { - todotail->todonext = func; - todotail = func; - } - } - - /* todo is a linked list of functions which are known to be - used. If a function's usage field is nonzero, it must be - either be on the todo list or have come off already (in - which case processed will be set). */ - - while (todo) { - /* Pop the next function. */ - func = todo; - todo = todo->todonext; - if (!todo) - todotail = NULL; - - if (func->processed) - error_named("Internal error in stripping: function has been processed twice:", func->name); - - /* Go through the function's symbol references. Any - reference to a routine, push it into the todo list (if - it isn't there already). */ - - for (ent = func->refs; ent; ent=ent->refsnext) { - uint32 addr; - int symbol = ent->symbol; - if (stypes[symbol] != ROUTINE_T) - continue; - addr = svals[symbol] * (glulx_mode ? 1 : scale_factor); - tofunc = df_function_for_address(addr); - if (!tofunc) { - error_named("Internal error in stripping: function ROUTINE_T symbol is not found in df_function map:", (char *)symbs[symbol]); - continue; - } - if (tofunc->usage) - continue; - - /* Not yet known to be used. Add it to the todo list. */ - tofunc->usage |= DF_USAGE_FUNCTION; - if (!todo) { - todo = tofunc; - todotail = tofunc; - } - else { - todotail->todonext = tofunc; - todotail = tofunc; - } - } - - func->processed = TRUE; - } - } - - /* Go through all functions; figure out how much space is consumed, - with and without useless functions. */ - - { - df_function_t *func; - - df_total_size_before_stripping = 0; - df_total_size_after_stripping = 0; - - for (func = df_functions_head; func; func = func->funcnext) { - if (func->address == DF_NOT_IN_FUNCTION) - continue; - - if (func->address != df_total_size_before_stripping) - compiler_error("DF: Address gap in function list"); - - df_total_size_before_stripping += func->length; - if (func->usage) { - func->newaddress = df_total_size_after_stripping; - df_total_size_after_stripping += func->length; - } - - if (!glulx_mode && (df_total_size_after_stripping % scale_factor != 0)) - compiler_error("DF: New function address is not aligned"); - - if (WARN_UNUSED_ROUTINES && !func->usage) { - if (!func->sysfile || WARN_UNUSED_ROUTINES >= 2) - uncalled_routine_warning("Routine", func->name, func->source_line); - } - } - } - - /* df_measure_hash_table_usage(); */ -} - -/* Given an original function address, return where it winds up after - unused-function stripping. The function must not itself be unused. - - Both the input and output are offsets, and already scaled by - scale_factor. - - This is used by the backpatching system. -*/ -extern uint32 df_stripped_address_for_address(uint32 addr) -{ - df_function_t *func; - - if (!track_unused_routines) - compiler_error("DF: df_stripped_address_for_address called, but function references have not been mapped"); - - if (!glulx_mode) - func = df_function_for_address(addr*scale_factor); - else - func = df_function_for_address(addr); - - if (!func) { - compiler_error("DF: Unable to find function while backpatching"); - return 0; - } - if (!func->usage) - compiler_error("DF: Tried to backpatch a function address which should be stripped"); - - if (!glulx_mode) - return func->newaddress / scale_factor; - else - return func->newaddress; -} - -/* Given an address in the function area, return where it winds up after - unused-function stripping. The address can be a function or anywhere - within the function. If the address turns out to be in a stripped - function, returns 0 (and sets *stripped). - - The input and output are offsets, but *not* scaled. - - This is only used by the debug-file system. -*/ -uint32 df_stripped_offset_for_code_offset(uint32 offset, int *stripped) -{ - df_function_t *func; - int count; - - if (!track_unused_routines) - compiler_error("DF: df_stripped_offset_for_code_offset called, but function references have not been mapped"); - - if (!df_functions_sorted) { - /* To do this efficiently, we need a binary-searchable table. Fine, - we'll make one. Include both used and unused functions. */ - - for (func = df_functions_head, count = 0; func; func = func->funcnext) { - if (func->address == DF_NOT_IN_FUNCTION) - continue; - count++; - } - df_functions_sorted_count = count; - - df_functions_sorted = my_calloc(sizeof(df_function_t *), df_functions_sorted_count, "df function sorted table"); - - for (func = df_functions_head, count = 0; func; func = func->funcnext) { - if (func->address == DF_NOT_IN_FUNCTION) - continue; - df_functions_sorted[count] = func; - count++; - } - } - - /* Do a binary search. Maintain beg <= res < end, where res is the - function containing the desired address. */ - int beg = 0; - int end = df_functions_sorted_count; - - /* Set stripped flag until we decide on a non-stripped function. */ - *stripped = TRUE; - - while (1) { - if (beg >= end) { - error("DF: offset_for_code_offset: Could not locate address."); - return 0; - } - if (beg+1 == end) { - func = df_functions_sorted[beg]; - if (func->usage == 0) - return 0; - *stripped = FALSE; - return func->newaddress + (offset - func->address); - } - int new = (beg + end) / 2; - if (new <= beg || new >= end) - compiler_error("DF: binary search went off the rails"); - - func = df_functions_sorted[new]; - if (offset >= func->address) { - if (offset < func->address+func->length) { - /* We don't need to loop further; decide here. */ - if (func->usage == 0) - return 0; - *stripped = FALSE; - return func->newaddress + (offset - func->address); - } - beg = new; - } - else { - end = new; - } - } -} - -/* The output_file() routines in files.c have to run down the list of - functions, deciding who is in and who is out. But I don't want to - export the df_function_t list structure. Instead, I provide this - silly iterator pair. Set it up with df_prepare_function_iterate(); - then repeatedly call df_next_function_iterate(). -*/ - -extern void df_prepare_function_iterate(void) -{ - df_iterator = df_functions_head; - if (!df_iterator || df_iterator->address != DF_NOT_IN_FUNCTION) - compiler_error("DF: Global namespace entry is not at the head of the chain."); - if (!df_iterator->funcnext || df_iterator->funcnext->address != 0) - compiler_error("DF: First function entry is not second in the chain."); -} - -/* This returns the end of the next function, and whether the next function - is used (live). -*/ -extern uint32 df_next_function_iterate(int *funcused) -{ - if (df_iterator) - df_iterator = df_iterator->funcnext; - if (!df_iterator) { - *funcused = TRUE; - return df_total_size_before_stripping+1; - } - *funcused = (df_iterator->usage != 0); - return df_iterator->address + df_iterator->length; -} - -/* ========================================================================= */ -/* Data structure management routines */ -/* ------------------------------------------------------------------------- */ - -extern void init_symbols_vars(void) -{ - symbs = NULL; - svals = NULL; - smarks = NULL; - stypes = NULL; - sflags = NULL; - next_entry = NULL; - start_of_list = NULL; - - symbol_name_space_chunks = NULL; - no_symbol_name_space_chunks = 0; - symbols_free_space=NULL; - symbols_ceiling=symbols_free_space; - - no_symbols = 0; - - symbol_replacements = NULL; - symbol_replacements_count = 0; - symbol_replacements_size = 0; - - make_case_conversion_grid(); - - track_unused_routines = (WARN_UNUSED_ROUTINES || OMIT_UNUSED_ROUTINES); - df_tables_closed = FALSE; - df_symbol_map = NULL; - df_functions = NULL; - df_functions_head = NULL; - df_functions_tail = NULL; - df_current_function = NULL; - df_functions_sorted = NULL; - df_functions_sorted_count = 0; -} - -extern void symbols_begin_pass(void) -{ - df_total_size_before_stripping = 0; - df_total_size_after_stripping = 0; - df_dont_note_global_symbols = FALSE; - df_iterator = NULL; -} - -extern void symbols_allocate_arrays(void) -{ - symbs = my_calloc(sizeof(char *), MAX_SYMBOLS, "symbols"); - svals = my_calloc(sizeof(int32), MAX_SYMBOLS, "symbol values"); - if (glulx_mode) - smarks = my_calloc(sizeof(int), MAX_SYMBOLS, "symbol markers"); - slines = my_calloc(sizeof(brief_location), MAX_SYMBOLS, "symbol lines"); - stypes = my_calloc(sizeof(char), MAX_SYMBOLS, "symbol types"); - sflags = my_calloc(sizeof(int), MAX_SYMBOLS, "symbol flags"); - if (debugfile_switch) - { symbol_debug_backpatch_positions = - my_calloc(sizeof(maybe_file_position), MAX_SYMBOLS, - "symbol debug information backpatch positions"); - replacement_debug_backpatch_positions = - my_calloc(sizeof(maybe_file_position), MAX_SYMBOLS, - "replacement debug information backpatch positions"); - } - next_entry = my_calloc(sizeof(int), MAX_SYMBOLS, - "symbol linked-list forward links"); - start_of_list = my_calloc(sizeof(int32), HASH_TAB_SIZE, - "hash code list beginnings"); - - symbol_name_space_chunks - = my_calloc(sizeof(char *), MAX_SYMBOL_CHUNKS, "symbol names chunk addresses"); - - if (track_unused_routines) { - df_tables_closed = FALSE; - - df_symbol_map = my_calloc(sizeof(df_reference_t *), DF_SYMBOL_HASH_BUCKETS, "df symbol-map hash table"); - memset(df_symbol_map, 0, sizeof(df_reference_t *) * DF_SYMBOL_HASH_BUCKETS); - - df_functions = my_calloc(sizeof(df_function_t *), DF_FUNCTION_HASH_BUCKETS, "df function hash table"); - memset(df_functions, 0, sizeof(df_function_t *) * DF_FUNCTION_HASH_BUCKETS); - df_functions_head = NULL; - df_functions_tail = NULL; - - df_functions_sorted = NULL; - df_functions_sorted_count = 0; - - df_note_function_start("", DF_NOT_IN_FUNCTION, FALSE, blank_brief_location); - df_note_function_end(DF_NOT_IN_FUNCTION); - /* Now df_current_function is df_functions_head. */ - } - - init_symbol_banks(); - stockup_symbols(); - - /* Allocated as needed */ - symbol_replacements = NULL; - - /* Allocated during story file construction, not now */ - individual_name_strings = NULL; - attribute_name_strings = NULL; - action_name_strings = NULL; - array_name_strings = NULL; -} - -extern void symbols_free_arrays(void) -{ int i; - - for (i=0; inext; - my_free(&ent, "df symbol map entry"); - ent = next; - } - } - my_free(&df_symbol_map, "df symbol-map hash table"); - } - if (df_functions_sorted) { - my_free(&df_functions, "df function sorted table"); - } - if (df_functions) { - for (i=0; inext; - my_free(&func, "df function entry"); - func = next; - } - } - my_free(&df_functions, "df function hash table"); - } - df_functions_head = NULL; - df_functions_tail = NULL; - - if (individual_name_strings != NULL) - my_free(&individual_name_strings, "property name strings"); - if (action_name_strings != NULL) - my_free(&action_name_strings, "action name strings"); - if (attribute_name_strings != NULL) - my_free(&attribute_name_strings, "attribute name strings"); - if (array_name_strings != NULL) - my_free(&array_name_strings, "array name strings"); -} - -/* ========================================================================= */