/* ------------------------------------------------------------------------- */ /* "tables" : Constructs the story file or module (the output) up to the */ /* end of dynamic memory, gluing together all the required */ /* tables. */ /* */ /* Part of Inform 6.34 */ /* copyright (c) Graham Nelson 1993 - 2020 */ /* */ /* ------------------------------------------------------------------------- */ #include "header.h" uchar *zmachine_paged_memory; /* Where we shall store the story file constructed (contains all of paged memory, i.e. all but code and the static strings: allocated only when we know how large it needs to be, at the end of the compilation pass */ /* In Glulx, zmachine_paged_memory contains all of RAM -- i.e. all but the header, the code, the static arrays, and the static strings. */ /* ------------------------------------------------------------------------- */ /* Offsets of various areas in the Z-machine: these are set to nominal */ /* values before the compilation pass, and to their calculated final */ /* values only when construct_storyfile() happens. These are then used to */ /* backpatch the incorrect values now existing in the Z-machine which */ /* used these nominal values. */ /* Most of the nominal values are 0x800 because this is guaranteed to */ /* be assembled as a long constant if it's needed in code, since the */ /* largest possible value of scale_factor is 8 and 0x800/8 = 256. */ /* */ /* In Glulx, I use 0x12345 instead of 0x800. This will always be a long */ /* (32-bit) constant, since there's no scale_factor. */ /* ------------------------------------------------------------------------- */ int32 code_offset, actions_offset, preactions_offset, dictionary_offset, adjectives_offset, variables_offset, strings_offset, class_numbers_offset, individuals_offset, identifier_names_offset, array_names_offset, prop_defaults_offset, prop_values_offset, static_memory_offset, attribute_names_offset, action_names_offset, fake_action_names_offset, routine_names_offset, constant_names_offset, routines_array_offset, constants_array_offset, routine_flags_array_offset, global_names_offset, global_flags_array_offset, array_flags_array_offset, static_arrays_offset; int32 arrays_offset, object_tree_offset, grammar_table_offset, abbreviations_offset; /* Glulx */ int32 Out_Size, Write_Code_At, Write_Strings_At; int32 RAM_Size, Write_RAM_At; /* Glulx */ /* ------------------------------------------------------------------------- */ /* Story file header settings. (Written to in "directs.c" and "asm.c".) */ /* ------------------------------------------------------------------------- */ int release_number, /* Release number game is to have */ statusline_flag; /* Either TIME_STYLE or SCORE_STYLE */ int serial_code_given_in_program /* If TRUE, a Serial directive has */ = FALSE; /* specified this 6-digit serial code */ char serial_code_buffer[7]; /* (overriding the usual date-stamp) */ int flags2_requirements[16]; /* An array of which bits in Flags 2 of the header will need to be set: e.g. if the save_undo / restore_undo opcodes are ever assembled, we have to set the "games want UNDO" bit. Values are 0 or 1. */ /* ------------------------------------------------------------------------- */ /* Construct story/module file (up to code area start). */ /* */ /* (To understand what follows, you really need to look at the run-time */ /* system's specification, the Z-Machine Standards document.) */ /* ------------------------------------------------------------------------- */ extern void write_serial_number(char *buffer) { /* Note that this function may require modification for "ANSI" compilers which do not provide the standard time functions: what is needed is the ability to work out today's date */ time_t tt; tt=time(0); if (serial_code_given_in_program) strcpy(buffer, serial_code_buffer); else #ifdef TIME_UNAVAILABLE sprintf(buffer,"970000"); #else strftime(buffer,10,"%y%m%d",localtime(&tt)); #endif } static void percentage(char *name, int32 x, int32 total) { printf(" %-20s %2d.%d%%\n",name,x*100/total,(x*1000/total)%10); } static char *version_name(int v) { if (!glulx_mode) { switch(v) { case 3: return "Standard"; case 4: return "Plus"; case 5: return "Advanced"; case 6: return "Graphical"; case 8: return "Extended"; } return "experimental format"; } else { return "Glulx"; } } static int32 rough_size_of_paged_memory_z(void) { /* This function calculates a modest over-estimate of the amount of memory required to store the Z-machine's paged memory area (that is, everything up to the start of the code area). */ int32 total, i; ASSERT_ZCODE(); total = 64 /* header */ + 2 + subtract_pointers(low_strings_top, low_strings) /* low strings pool */ + 6*32; /* abbreviations table */ total += 8; /* header extension table */ if (ZCODE_HEADER_EXT_WORDS>3) total += (ZCODE_HEADER_EXT_WORDS-3)*2; if (alphabet_modified) total += 78; /* character set table */ if (zscii_defn_modified) /* Unicode translation table */ total += 2 + 2*zscii_high_water_mark; total += 2*((version_number==3)?31:63) /* property default values */ + no_objects*((version_number==3)?9:14) /* object tree table */ + properties_table_size /* property values of objects */ + (no_classes+1)*(module_switch?4:2) /* class object numbers table */ + no_symbols*2 /* names of numerous things */ + individuals_length /* tables of prop variables */ + dynamic_array_area_size; /* variables and arrays */ for (i=0; i 0xFFFF) { error("Z-machine Unicode translation table cannot contain characters beyond $FFFF."); } p[mark++] = j/256; p[mark++] = j%256; } } /* -------------------- Objects and Properties ------------------------ */ /* The object table must be word-aligned. The Z-machine spec does not require this, but the RA__Pr() veneer routine does. See http://inform7.com/mantis/view.php?id=1712. */ while ((mark%2) != 0) p[mark++]=0; prop_defaults_at = mark; p[mark++]=0; p[mark++]=0; for (i=2; i< ((version_number==3)?32:64); i++) { p[mark++]=prop_default_value[i]/256; p[mark++]=prop_default_value[i]%256; } object_tree_at = mark; mark += ((version_number==3)?9:14)*no_objects; object_props_at = mark; for (i=0; i= 5) { terminating_chars_at = mark; for (i=0; i 2) { warning("This version of Inform is unable to produce the grammar \ table format requested (producing number 2 format instead)"); grammar_version_number = 2; } grammar_table_at = mark; mark = mark + no_Inform_verbs*2; for (i=0; i= 256, hence long constants) */ /* -------------------------------------------------------------------- */ while ((mark%length_scale_factor) != 0) p[mark++]=0; while (mark < (scale_factor*0x100)) p[mark++]=0; if (oddeven_packing_switch) while ((mark%(scale_factor*2)) != 0) p[mark++]=0; if (mark > 0x0FFFE) { error("This program has overflowed the maximum readable-memory \ size of the Z-machine format. See the memory map below: the start \ of the area marked \"above readable memory\" must be brought down to $FFFE \ or less."); memory_map_switch = TRUE; /* Backpatching the grammar tables requires us to trust some of the */ /* addresses we've written into Z-machine memory, but they may have */ /* been truncated to 16 bits, so we can't do it. */ skip_backpatching = TRUE; } /* -------------------------- Code Area ------------------------------- */ /* (From this point on we don't write any more into the "p" buffer.) */ /* -------------------------------------------------------------------- */ Write_Code_At = mark; if (!OMIT_UNUSED_ROUTINES) { code_length = zmachine_pc; } else { if (zmachine_pc != df_total_size_before_stripping) compiler_error("Code size does not match (zmachine_pc and df_total_size)."); code_length = df_total_size_after_stripping; } mark += code_length; /* ------------------ Another synchronising gap ----------------------- */ if (oddeven_packing_switch) { if (module_switch) while ((mark%(scale_factor*2)) != 0) mark++; else while ((mark%(scale_factor*2)) != scale_factor) mark++; } else while ((mark%scale_factor) != 0) mark++; /* ------------------------- Strings Area ----------------------------- */ Write_Strings_At = mark; strings_length = static_strings_extent; mark += strings_length; /* --------------------- Module Linking Data -------------------------- */ if (module_switch) { link_table_at = mark; mark += link_data_size; mark += zcode_backpatch_size; mark += zmachine_backpatch_size; } /* --------------------- Is the file too big? ------------------------- */ Out_Size = mark; switch(version_number) { case 3: excess = Out_Size-((int32) 0x20000L); limit = 128; break; case 4: case 5: excess = Out_Size-((int32) 0x40000L); limit = 256; break; case 6: case 7: case 8: excess = Out_Size-((int32) 0x80000L); limit = 512; break; } if (module_switch) { excess = Out_Size-((int32) 0x10000L); limit=64; } if (excess > 0) { char memory_full_error[80]; sprintf(memory_full_error, "The %s exceeds version-%d limit (%dK) by %d bytes", output_called, version_number, limit, excess); fatalerror(memory_full_error); } /* --------------------------- Offsets -------------------------------- */ dictionary_offset = dictionary_at; variables_offset = globals_at; actions_offset = actions_at; preactions_offset = preactions_at; prop_defaults_offset = prop_defaults_at; prop_values_offset = object_props_at; static_memory_offset = grammar_table_at; grammar_table_offset = grammar_table_at; static_arrays_offset = static_arrays_at; if (extend_memory_map) { extend_offset=256; if (no_objects+9 > extend_offset) extend_offset=no_objects+9; while ((extend_offset%length_scale_factor) != 0) extend_offset++; /* Not sure why above line is necessary, but oddeven_packing * will need extend_offset to be even */ code_offset = extend_offset*scale_factor; if (oddeven_packing_switch) strings_offset = code_offset + scale_factor; else strings_offset = code_offset + (Write_Strings_At-Write_Code_At); /* With the extended memory model, need to specifically check that we * haven't overflowed the packed address range for routines or strings. * With the standard memory model, we only need the earlier total size * check. */ excess = code_length + code_offset - (scale_factor*((int32) 0x10000L)); if (excess > 0) { char code_full_error[80]; sprintf(code_full_error, "The code area limit has been exceeded by %d bytes", excess); fatalerror(code_full_error); } excess = strings_length + strings_offset - (scale_factor*((int32) 0x10000L)); if (excess > 0) { char strings_full_error[140]; if (oddeven_packing_switch) sprintf(strings_full_error, "The strings area limit has been exceeded by %d bytes", excess); else sprintf(strings_full_error, "The code+strings area limit has been exceeded by %d bytes. \ Try running Inform again with -B on the command line.", excess); fatalerror(strings_full_error); } } else { code_offset = Write_Code_At; strings_offset = Write_Strings_At; } /* --------------------------- The Header ----------------------------- */ for (i=0; i<=0x3f; i++) p[i]=0; /* Begin with 64 blank bytes */ p[0] = version_number; /* Version number */ p[1] = statusline_flag*2; /* Bit 1 of Flags 1: statusline style */ p[2] = (release_number/256); p[3] = (release_number%256); /* Release */ p[4] = (Write_Code_At/256); p[5] = (Write_Code_At%256); /* End of paged memory */ if (version_number==6) { j=code_offset/scale_factor; /* Packed address of "Main__" */ p[6]=(j/256); p[7]=(j%256); } else { j=Write_Code_At+1; /* Initial PC value (bytes) */ p[6]=(j/256); p[7]=(j%256); /* (first opcode in "Main__") */ } p[8] = (dictionary_at/256); p[9]=(dictionary_at%256); /* Dictionary */ p[10]=prop_defaults_at/256; p[11]=prop_defaults_at%256; /* Objects */ p[12]=(globals_at/256); p[13]=(globals_at%256); /* Dynamic area */ p[14]=(grammar_table_at/256); p[15]=(grammar_table_at%256); /* Grammar */ for (i=0, j=0, k=1;i<16;i++, k=k*2) /* Flags 2 as needed for any */ j+=k*flags2_requirements[i]; /* unusual opcodes assembled */ p[16]=j/256; p[17]=j%256; write_serial_number((char *) (p+18)); /* Serial number: 6 chars of ASCII */ p[24]=abbrevs_at/256; p[25]=abbrevs_at%256; /* Abbreviations table */ p[26]=0; p[27]=0; /* Length of file to be filled in "files.c" */ p[28]=0; p[29]=0; /* Checksum to be filled in "files.c" */ if (extend_memory_map) { j=(Write_Code_At - extend_offset*scale_factor)/length_scale_factor; p[40]=j/256; p[41]=j%256; /* Routines offset */ if (oddeven_packing_switch) j=(Write_Strings_At - extend_offset*scale_factor)/length_scale_factor; p[42]=j/256; p[43]=j%256; /* = Strings offset */ } if (version_number >= 5) { p[46] = terminating_chars_at/256; /* Terminating characters table */ p[47] = terminating_chars_at%256; } if (alphabet_modified) { j = charset_at; p[52]=j/256; p[53]=j%256; } /* Character set table address */ j = headerext_at; p[54] = j/256; p[55] = j%256; /* Header extension table address */ p[60] = '0' + ((RELEASE_NUMBER/100)%10); p[61] = '.'; p[62] = '0' + ((RELEASE_NUMBER/10)%10); p[63] = '0' + RELEASE_NUMBER%10; /* ------------------------ Header Extension -------------------------- */ /* The numbering in the spec is a little weird -- it's headerext_length words *after* the initial length word. We follow the spec numbering in this switch statement, so the count is 1-based. */ for (i=1; i<=headerext_length; i++) { switch (i) { case 3: j = unicode_at; /* Unicode translation table address */ break; case 4: j = ZCODE_HEADER_FLAGS_3; /* Flags 3 word */ break; default: j = 0; break; } p[headerext_at+2*i+0] = j / 256; p[headerext_at+2*i+1] = j % 256; } /* ----------------- The Header: Extras for modules ------------------- */ if (module_switch) { p[0]=p[0]+64; p[1]=MODULE_VERSION_NUMBER; p[6]=map_of_module/256; p[7]=map_of_module%256; mark = map_of_module; /* Module map format: */ p[mark++]=object_tree_at/256; /* 0: Object tree addr */ p[mark++]=object_tree_at%256; p[mark++]=object_props_at/256; /* 2: Prop values addr */ p[mark++]=object_props_at%256; p[mark++]=(Write_Strings_At/scale_factor)/256; /* 4: Static strs */ p[mark++]=(Write_Strings_At/scale_factor)%256; p[mark++]=class_numbers_offset/256; /* 6: Class nos addr */ p[mark++]=class_numbers_offset%256; p[mark++]=individuals_offset/256; /* 8: Indiv prop values */ p[mark++]=individuals_offset%256; p[mark++]=individuals_length/256; /* 10: Length of table */ p[mark++]=individuals_length%256; p[mark++]=no_symbols/256; /* 12: No of symbols */ p[mark++]=no_symbols%256; p[mark++]=no_individual_properties/256; /* 14: Max property no */ p[mark++]=no_individual_properties%256; p[mark++]=no_objects/256; /* 16: No of objects */ p[mark++]=no_objects%256; i = link_table_at; p[mark++]=i/256; /* 18: Import/exports */ p[mark++]=i%256; p[mark++]=link_data_size/256; /* 20: Size of */ p[mark++]=link_data_size%256; i += link_data_size; p[mark++]=i/256; /* 22: Code backpatch */ p[mark++]=i%256; p[mark++]=zcode_backpatch_size/256; /* 24: Size of */ p[mark++]=zcode_backpatch_size%256; i += zcode_backpatch_size; p[mark++]=i/256; /* 26: Image backpatch */ p[mark++]=i%256; p[mark++]=zmachine_backpatch_size/256; /* 28: Size of */ p[mark++]=zmachine_backpatch_size%256; /* Further space in this table is reserved for future use */ } /* ---- Backpatch the Z-machine, now that all information is in ------- */ if (!module_switch && !skip_backpatching) { backpatch_zmachine_image_z(); for (i=1; i0; j--) { int topbits; int32 value; i = i + 2; while (p[i] != 15) { topbits = (p[i]/0x40) & 3; value = p[i+1]*256 + p[i+2]; switch(topbits) { case 1: value = final_dict_order[value] *((version_number==3)?7:9) + dictionary_offset + 7; break; case 2: if (OMIT_UNUSED_ROUTINES) value = df_stripped_address_for_address(value); value += code_offset/scale_factor; break; } p[i+1] = value/256; p[i+2] = value%256; i = i + 3; } i++; } } } } /* ---- From here on, it's all reportage: construction is finished ---- */ if (statistics_switch) { int32 k_long, rate; char *k_str=""; k_long=(Out_Size/1024); if ((Out_Size-1024*k_long) >= 512) { k_long++; k_str=""; } else if ((Out_Size-1024*k_long) > 0) { k_str=".5"; } if (total_bytes_trans == 0) rate = 0; else rate=total_bytes_trans*1000/total_chars_trans; { printf("In:\ %3d source code files %6d syntactic lines\n\ %6d textual lines %8ld characters ", total_input_files, no_syntax_lines, total_source_line_count, (long int) total_chars_read); if (character_set_unicode) printf("(UTF-8)\n"); else if (character_set_setting == 0) printf("(plain ASCII)\n"); else { printf("(ISO 8859-%d %s)\n", character_set_setting, name_of_iso_set(character_set_setting)); } printf("Allocated:\n\ %6d symbols (maximum %4d) %8ld bytes of memory\n\ Out: Version %d \"%s\" %s %d.%c%c%c%c%c%c (%ld%sK long):\n", no_symbols, MAX_SYMBOLS, (long int) malloced_bytes, version_number, version_name(version_number), output_called, release_number, p[18], p[19], p[20], p[21], p[22], p[23], (long int) k_long, k_str); printf("\ %6d classes (maximum %3d) %6d objects (maximum %3d)\n\ %6d global vars (maximum 233) %6d variable/array space (maximum %d)\n", no_classes, MAX_CLASSES, no_objects, ((version_number==3)?255:(MAX_OBJECTS-1)), no_globals, dynamic_array_area_size, MAX_STATIC_DATA); printf( "%6d verbs (maximum %3d) %6d dictionary entries (maximum %d)\n\ %6d grammar lines (version %d) %6d grammar tokens (unlimited)\n\ %6d actions (maximum %3d) %6d attributes (maximum %2d)\n\ %6d common props (maximum %2d) %6d individual props (unlimited)\n", no_Inform_verbs, MAX_VERBS, dict_entries, MAX_DICT_ENTRIES, no_grammar_lines, grammar_version_number, no_grammar_tokens, no_actions, MAX_ACTIONS, no_attributes, ((version_number==3)?32:48), no_properties-2, ((version_number==3)?30:62), no_individual_properties - 64); if (track_unused_routines) { uint32 diff = df_total_size_before_stripping - df_total_size_after_stripping; printf( "%6ld bytes of Z-code %6ld unused bytes %s (%.1f%%)\n", (long int) df_total_size_before_stripping, (long int) diff, (OMIT_UNUSED_ROUTINES ? "stripped out" : "detected"), 100 * (float)diff / (float)df_total_size_before_stripping); } printf( "%6ld characters used in text %6ld bytes compressed (rate %d.%3ld)\n\ %6d abbreviations (maximum %d) %6d routines (unlimited)\n\ %6ld instructions of Z-code %6d sequence points\n\ %6ld bytes readable memory used (maximum 65536)\n\ %6ld bytes used in Z-machine %6ld bytes free in Z-machine\n", (long int) total_chars_trans, (long int) total_bytes_trans, (total_chars_trans>total_bytes_trans)?0:1, (long int) rate, no_abbreviations, MAX_ABBREVS, no_routines, (long int) no_instructions, no_sequence_points, (long int) Write_Code_At, (long int) Out_Size, (long int) (((long int) (limit*1024L)) - ((long int) Out_Size))); } } if (offsets_switch) { { printf( "\nOffsets in %s:\n\ %05lx Synonyms %05lx Defaults %05lx Objects %05lx Properties\n\ %05lx Variables %05lx Parse table %05lx Actions %05lx Preactions\n\ %05lx Adjectives %05lx Dictionary %05lx Code %05lx Strings\n", output_called, (long int) abbrevs_at, (long int) prop_defaults_at, (long int) object_tree_at, (long int) object_props_at, (long int) globals_at, (long int) grammar_table_at, (long int) actions_at, (long int) preactions_at, (long int) adjectives_offset, (long int) dictionary_at, (long int) Write_Code_At, (long int) Write_Strings_At); if (module_switch) printf("%05lx Linking data\n",(long int) link_table_at); } } if (debugfile_switch) { begin_writing_debug_sections(); write_debug_section("abbreviations", 64); write_debug_section("abbreviations table", abbrevs_at); write_debug_section("header extension", headerext_at); if (alphabet_modified) { write_debug_section("alphabets table", charset_at); } if (zscii_defn_modified) { write_debug_section("Unicode table", unicode_at); } write_debug_section("property defaults", prop_defaults_at); write_debug_section("object tree", object_tree_at); write_debug_section("common properties", object_props_at); write_debug_section("class numbers", class_numbers_offset); write_debug_section("identifier names", identifier_names_offset); write_debug_section("individual properties", individuals_offset); write_debug_section("global variables", globals_at); write_debug_section("array space", globals_at+480); write_debug_section("grammar table", grammar_table_at); write_debug_section("actions table", actions_at); write_debug_section("parsing routines", preactions_at); write_debug_section("adjectives table", adjectives_offset); write_debug_section("dictionary", dictionary_at); write_debug_section("code area", Write_Code_At); write_debug_section("strings area", Write_Strings_At); end_writing_debug_sections(Out_Size); } if (memory_map_switch) { { printf("Dynamic +---------------------+ 00000\n"); printf("memory | header |\n"); printf(" +---------------------+ 00040\n"); printf(" | abbreviations |\n"); printf(" + - - - - - - - - - - + %05lx\n", (long int) abbrevs_at); printf(" | abbreviations table |\n"); printf(" +---------------------+ %05lx\n", (long int) headerext_at); printf(" | header extension |\n"); if (alphabet_modified) { printf(" + - - - - - - - - - - + %05lx\n", (long int) charset_at); printf(" | alphabets table |\n"); } if (zscii_defn_modified) { printf(" + - - - - - - - - - - + %05lx\n", (long int) unicode_at); printf(" | Unicode table |\n"); } printf(" +---------------------+ %05lx\n", (long int) prop_defaults_at); printf(" | property defaults |\n"); printf(" + - - - - - - - - - - + %05lx\n", (long int) object_tree_at); printf(" | objects |\n"); printf(" + - - - - - - - - - - + %05lx\n", (long int) object_props_at); printf(" | object short names, |\n"); printf(" | common prop values |\n"); printf(" + - - - - - - - - - - + %05lx\n", (long int) class_numbers_offset); printf(" | class numbers table |\n"); printf(" + - - - - - - - - - - + %05lx\n", (long int) identifier_names_offset); printf(" | symbol names table |\n"); printf(" + - - - - - - - - - - + %05lx\n", (long int) individuals_offset); printf(" | indiv prop values |\n"); printf(" +---------------------+ %05lx\n", (long int) globals_at); printf(" | global variables |\n"); printf(" + - - - - - - - - - - + %05lx\n", ((long int) globals_at)+480L); printf(" | arrays |\n"); printf(" +=====================+ %05lx\n", (long int) grammar_table_at); printf("Readable| grammar table |\n"); printf("memory + - - - - - - - - - - + %05lx\n", (long int) actions_at); printf(" | actions |\n"); printf(" + - - - - - - - - - - + %05lx\n", (long int) preactions_at); printf(" | parsing routines |\n"); printf(" + - - - - - - - - - - + %05lx\n", (long int) adjectives_offset); printf(" | adjectives |\n"); printf(" +---------------------+ %05lx\n", (long int) dictionary_at); printf(" | dictionary |\n"); if (module_switch) { printf(" + - - - - - - - - - - + %05lx\n", (long int) map_of_module); printf(" | map of module addrs |\n"); } if (static_array_area_size) { printf(" +---------------------+ %05lx\n", (long int) static_arrays_at); printf(" | static arrays |\n"); } printf(" +=====================+ %05lx\n", (long int) Write_Code_At); printf("Above | Z-code |\n"); printf("readable+---------------------+ %05lx\n", (long int) Write_Strings_At); printf("memory | strings |\n"); if (module_switch) { printf(" +=====================+ %05lx\n", (long int) link_table_at); printf(" | module linking data |\n"); } printf(" +---------------------+ %05lx\n", (long int) Out_Size); } } if (percentages_switch) { printf("Approximate percentage breakdown of %s:\n", output_called); percentage("Z-code", code_length,Out_Size); if (module_switch) percentage("Linking data", link_data_size,Out_Size); percentage("Static strings", strings_length,Out_Size); percentage("Dictionary", Write_Code_At-dictionary_at,Out_Size); percentage("Objects", globals_at-prop_defaults_at,Out_Size); percentage("Globals", grammar_table_at-globals_at,Out_Size); percentage("Parsing tables", dictionary_at-grammar_table_at,Out_Size); percentage("Header and synonyms", prop_defaults_at,Out_Size); percentage("Total of save area", grammar_table_at,Out_Size); percentage("Total of text", total_bytes_trans,Out_Size); } if (frequencies_switch) { { printf("How frequently abbreviations were used, and roughly\n"); printf("how many bytes they saved: ('_' denotes spaces)\n"); for (i=0; i> 24) & 0xFF; p[mark++] = (val >> 16) & 0xFF; p[mark++] = (val >> 8) & 0xFF; p[mark++] = (val) & 0xFF; } for (j=0; j0; j--) { int topbits; int32 value; i = i + 3; while (p[i] != 15) { topbits = (p[i]/0x40) & 3; value = ((p[i+1] << 24) | (p[i+2] << 16) | (p[i+3] << 8) | (p[i+4])); switch(topbits) { case 1: value = dictionary_offset + 4 + final_dict_order[value]*DICT_ENTRY_BYTE_LENGTH; break; case 2: if (OMIT_UNUSED_ROUTINES) value = df_stripped_address_for_address(value); value += code_offset; break; } WriteInt32(p+(i+1), value); i = i + 5; } i++; } } } /* ---- From here on, it's all reportage: construction is finished ---- */ if (statistics_switch) { int32 k_long, rate; char *k_str=""; k_long=(Out_Size/1024); if ((Out_Size-1024*k_long) >= 512) { k_long++; k_str=""; } else if ((Out_Size-1024*k_long) > 0) { k_str=".5"; } if (strings_length == 0) rate = 0; else rate=strings_length*1000/total_chars_trans; { printf("In:\ %3d source code files %6d syntactic lines\n\ %6d textual lines %8ld characters ", total_input_files, no_syntax_lines, total_source_line_count, (long int) total_chars_read); if (character_set_unicode) printf("(UTF-8)\n"); else if (character_set_setting == 0) printf("(plain ASCII)\n"); else { printf("(ISO 8859-%d %s)\n", character_set_setting, name_of_iso_set(character_set_setting)); } {char serialnum[8]; write_serial_number(serialnum); printf("Allocated:\n\ %6d symbols (maximum %4d) %8ld bytes of memory\n\ Out: %s %s %d.%c%c%c%c%c%c (%ld%sK long):\n", no_symbols, MAX_SYMBOLS, (long int) malloced_bytes, version_name(version_number), output_called, release_number, serialnum[0], serialnum[1], serialnum[2], serialnum[3], serialnum[4], serialnum[5], (long int) k_long, k_str); } printf("\ %6d classes (maximum %3d) %6d objects (maximum %3d)\n\ %6d global vars (maximum %3d) %6d variable/array space (maximum %d)\n", no_classes, MAX_CLASSES, no_objects, MAX_OBJECTS, no_globals, MAX_GLOBAL_VARIABLES, dynamic_array_area_size, MAX_STATIC_DATA); printf( "%6d verbs (maximum %3d) %6d dictionary entries (maximum %d)\n\ %6d grammar lines (version %d) %6d grammar tokens (unlimited)\n\ %6d actions (maximum %3d) %6d attributes (maximum %2d)\n\ %6d common props (maximum %3d) %6d individual props (unlimited)\n", no_Inform_verbs, MAX_VERBS, dict_entries, MAX_DICT_ENTRIES, no_grammar_lines, grammar_version_number, no_grammar_tokens, no_actions, MAX_ACTIONS, no_attributes, NUM_ATTR_BYTES*8, no_properties, INDIV_PROP_START, no_individual_properties - INDIV_PROP_START); if (track_unused_routines) { uint32 diff = df_total_size_before_stripping - df_total_size_after_stripping; printf( "%6ld bytes of code %6ld unused bytes %s (%.1f%%)\n", (long int) df_total_size_before_stripping, (long int) diff, (OMIT_UNUSED_ROUTINES ? "stripped out" : "detected"), 100 * (float)diff / (float)df_total_size_before_stripping); } printf( "%6ld characters used in text %6ld bytes compressed (rate %d.%3ld)\n\ %6d abbreviations (maximum %d) %6d routines (unlimited)\n\ %6ld instructions of code %6d sequence points\n\ %6ld bytes writable memory used %6ld bytes read-only memory used\n\ %6ld bytes used in machine %10ld bytes free in machine\n", (long int) total_chars_trans, (long int) strings_length, (total_chars_trans>strings_length)?0:1, (long int) rate, no_abbreviations, MAX_ABBREVS, no_routines, (long int) no_instructions, no_sequence_points, (long int) (Out_Size - Write_RAM_At), (long int) Write_RAM_At, (long int) Out_Size, (long int) (((long int) (limit*1024L)) - ((long int) Out_Size))); } } if (offsets_switch) { { printf( "\nOffsets in %s:\n\ %05lx Synonyms %05lx Defaults %05lx Objects %05lx Properties\n\ %05lx Variables %05lx Parse table %05lx Actions %05lx Preactions\n\ %05lx Adjectives %05lx Dictionary %05lx Code %05lx Strings\n", output_called, (long int) abbrevs_at, (long int) prop_defaults_at, (long int) object_tree_at, (long int) object_props_at, (long int) globals_at, (long int) grammar_table_at, (long int) actions_at, (long int) preactions_at, (long int) adjectives_offset, (long int) dictionary_at, (long int) Write_Code_At, (long int) Write_Strings_At); } } if (debugfile_switch) { begin_writing_debug_sections(); write_debug_section("memory layout id", GLULX_HEADER_SIZE); write_debug_section("code area", Write_Code_At); write_debug_section("string decoding table", Write_Strings_At); write_debug_section("strings area", Write_Strings_At + compression_table_size); write_debug_section("static array space", static_arrays_at); if (static_arrays_at + static_array_area_size < Write_RAM_At) { write_debug_section ("zero padding", static_arrays_at + static_array_area_size); } if (globals_at) { compiler_error("Failed assumption that globals are at start of " "Glulx RAM"); } write_debug_section("global variables", Write_RAM_At + globals_at); write_debug_section("array space", Write_RAM_At + arrays_at); write_debug_section("abbreviations table", Write_RAM_At + abbrevs_at); write_debug_section("object tree", Write_RAM_At + object_tree_at); write_debug_section("common properties", Write_RAM_At + object_props_at); write_debug_section("property defaults", Write_RAM_At + prop_defaults_at); write_debug_section("class numbers", Write_RAM_At + class_numbers_offset); write_debug_section("identifier names", Write_RAM_At + identifier_names_offset); write_debug_section("grammar table", Write_RAM_At + grammar_table_at); write_debug_section("actions table", Write_RAM_At + actions_at); write_debug_section("dictionary", Write_RAM_At + dictionary_at); if (MEMORY_MAP_EXTENSION) { write_debug_section("zero padding", Out_Size); } end_writing_debug_sections(Out_Size + MEMORY_MAP_EXTENSION); } if (memory_map_switch) { { printf(" +---------------------+ 000000\n"); printf("Read- | header |\n"); printf(" only +=====================+ %06lx\n", (long int) GLULX_HEADER_SIZE); printf("memory | memory layout id |\n"); printf(" +---------------------+ %06lx\n", (long int) Write_Code_At); printf(" | code |\n"); printf(" +---------------------+ %06lx\n", (long int) Write_Strings_At); printf(" | string decode table |\n"); printf(" + - - - - - - - - - - + %06lx\n", (long int) Write_Strings_At + compression_table_size); printf(" | strings |\n"); if (static_array_area_size) { printf(" +---------------------+ %06lx\n", (long int) (static_arrays_at)); printf(" | static arrays |\n"); } printf(" +=====================+ %06lx\n", (long int) (Write_RAM_At+globals_at)); printf("Dynamic | global variables |\n"); printf("memory + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+arrays_at)); printf(" | arrays |\n"); printf(" +---------------------+ %06lx\n", (long int) (Write_RAM_At+abbrevs_at)); printf(" | printing variables |\n"); if (alphabet_modified) { printf(" + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+charset_at)); printf(" | alphabets table |\n"); } if (zscii_defn_modified) { printf(" + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+unicode_at)); printf(" | Unicode table |\n"); } printf(" +---------------------+ %06lx\n", (long int) (Write_RAM_At+object_tree_at)); printf(" | objects |\n"); printf(" + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+object_props_at)); printf(" | property values |\n"); printf(" + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+prop_defaults_at)); printf(" | property defaults |\n"); printf(" + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+class_numbers_offset)); printf(" | class numbers table |\n"); printf(" + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+identifier_names_offset)); printf(" | id names table |\n"); printf(" +---------------------+ %06lx\n", (long int) (Write_RAM_At+grammar_table_at)); printf(" | grammar table |\n"); printf(" + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+actions_at)); printf(" | actions |\n"); printf(" +---------------------+ %06lx\n", (long int) dictionary_offset); printf(" | dictionary |\n"); if (MEMORY_MAP_EXTENSION == 0) { printf(" +---------------------+ %06lx\n", (long int) Out_Size); } else { printf(" +=====================+ %06lx\n", (long int) Out_Size); printf("Runtime | (empty) |\n"); printf(" extn +---------------------+ %06lx\n", (long int) Out_Size+MEMORY_MAP_EXTENSION); } } } if (percentages_switch) { printf("Approximate percentage breakdown of %s:\n", output_called); percentage("Code", code_length,Out_Size); if (module_switch) percentage("Linking data", link_data_size,Out_Size); percentage("Static strings", strings_length,Out_Size); percentage("Dictionary", Write_Code_At-dictionary_at,Out_Size); percentage("Objects", globals_at-prop_defaults_at,Out_Size); percentage("Globals", grammar_table_at-globals_at,Out_Size); percentage("Parsing tables", dictionary_at-grammar_table_at,Out_Size); percentage("Header and synonyms", prop_defaults_at,Out_Size); percentage("Total of save area", grammar_table_at,Out_Size); percentage("Total of text", strings_length,Out_Size); } if (frequencies_switch) { { printf("How frequently abbreviations were used, and roughly\n"); printf("how many bytes they saved: ('_' denotes spaces)\n"); for (i=0; i