/* ------------------------------------------------------------------------- */ /* "tables" : Constructs the story file (the output) up to the end */ /* of dynamic memory, gluing together all the required */ /* tables. */ /* */ /* Part of Inform 6.43 */ /* copyright (c) Graham Nelson 1993 - 2024 */ /* */ /* ------------------------------------------------------------------------- */ #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 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 /* Write a six-digit date, null-terminated. Fall back to "970000" if that fails. */ int len = strftime(buffer,7,"%y%m%d",localtime(&tt)); if (len != 6) sprintf(buffer,"970000"); #endif } } static char percentage_buffer[64]; static char *show_percentage(int32 x, int32 total) { if (memory_map_setting < 2) { percentage_buffer[0] = '\0'; } else if (x == 0) { sprintf(percentage_buffer, " ( --- )"); } else if (memory_map_setting < 3) { sprintf(percentage_buffer, " (%.1f %%)", (float)x * 100.0 / (float)total); } else { sprintf(percentage_buffer, " (%.1f %%, %d bytes)", (float)x * 100.0 / (float)total, x); } return percentage_buffer; } 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 7: return "Extended Alternate"; 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 + low_strings_top /* 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)*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. */ 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++]=commonprops[i].default_value/256; p[mark++]=commonprops[i].default_value%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_setting = 1; /* 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 higher into the "p" buffer.) */ /* -------------------------------------------------------------------- */ if (mark > rough_size) compiler_error("Paged size exceeds rough estimate."); 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) { 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 -------------------------- */ /* (no longer used) */ /* --------------------- 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 (excess > 0) { fatalerror_fmt( "The %s exceeds version-%d limit (%dK) by %d bytes", output_called, version_number, limit, excess); } /* --------------------------- 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) { fatalerror_fmt( "The code area limit has been exceeded by %d bytes", excess); } excess = strings_length + strings_offset - (scale_factor*((int32) 0x10000L)); if (excess > 0) { if (oddeven_packing_switch) fatalerror_fmt( "The strings area limit has been exceeded by %d bytes", excess); else fatalerror_fmt( "The code+strings area limit has been exceeded by %d bytes. \ Try running Inform again with -B on the command line.", excess); } } 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 ------------------- */ /* (no longer used) */ /* ---- Backpatch the Z-machine, now that all information is in ------- */ if (!skip_backpatching) { backpatch_zmachine_image_z(); if (!OMIT_SYMBOL_TABLE) { 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] *DICT_ENTRY_BYTE_LENGTH + 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 (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_setting) { int32 addr; { printf("Dynamic +---------------------+ 00000\n"); printf("memory | header | %s\n", show_percentage(0x40, Out_Size)); printf(" +---------------------+ 00040\n"); printf(" | abbreviations | %s\n", show_percentage(abbrevs_at-0x40, Out_Size)); printf(" + - - - - - - - - - - + %05lx\n", (long int) abbrevs_at); printf(" | abbreviations table | %s\n", show_percentage(headerext_at-abbrevs_at, Out_Size)); printf(" +---------------------+ %05lx\n", (long int) headerext_at); addr = (alphabet_modified ? charset_at : (zscii_defn_modified ? unicode_at : prop_defaults_at)); printf(" | header extension | %s\n", show_percentage(addr-headerext_at, Out_Size)); if (alphabet_modified) { printf(" + - - - - - - - - - - + %05lx\n", (long int) charset_at); addr = (zscii_defn_modified ? unicode_at : prop_defaults_at); printf(" | alphabets table | %s\n", show_percentage(addr-charset_at, Out_Size)); } if (zscii_defn_modified) { printf(" + - - - - - - - - - - + %05lx\n", (long int) unicode_at); printf(" | Unicode table | %s\n", show_percentage(prop_defaults_at-unicode_at, Out_Size)); } printf(" +---------------------+ %05lx\n", (long int) prop_defaults_at); printf(" | property defaults | %s\n", show_percentage(object_tree_at-prop_defaults_at, Out_Size)); printf(" + - - - - - - - - - - + %05lx\n", (long int) object_tree_at); printf(" | objects | %s\n", show_percentage(object_props_at-object_tree_at, Out_Size)); printf(" + - - - - - - - - - - + %05lx\n", (long int) object_props_at); printf(" | object short names, |\n"); printf(" | common prop values | %s\n", show_percentage(class_numbers_offset-object_props_at, Out_Size)); printf(" + - - - - - - - - - - + %05lx\n", (long int) class_numbers_offset); printf(" | class numbers table | %s\n", show_percentage(identifier_names_offset-class_numbers_offset, Out_Size)); printf(" + - - - - - - - - - - + %05lx\n", (long int) identifier_names_offset); printf(" | symbol names table | %s\n", show_percentage(individuals_offset-identifier_names_offset, Out_Size)); printf(" + - - - - - - - - - - + %05lx\n", (long int) individuals_offset); printf(" | indiv prop values | %s\n", show_percentage(globals_at-individuals_offset, Out_Size)); printf(" +---------------------+ %05lx\n", (long int) globals_at); printf(" | global variables | %s\n", show_percentage(480, Out_Size)); printf(" + - - - - - - - - - - + %05lx\n", ((long int) globals_at)+480L); printf(" | arrays | %s\n", show_percentage(grammar_table_at-(globals_at+480), Out_Size)); printf(" +=====================+ %05lx\n", (long int) grammar_table_at); printf("Readable| grammar table | %s\n", show_percentage(actions_at-grammar_table_at, Out_Size)); printf("memory + - - - - - - - - - - + %05lx\n", (long int) actions_at); printf(" | actions | %s\n", show_percentage(preactions_at-actions_at, Out_Size)); printf(" + - - - - - - - - - - + %05lx\n", (long int) preactions_at); printf(" | parsing routines | %s\n", show_percentage(adjectives_offset-preactions_at, Out_Size)); printf(" + - - - - - - - - - - + %05lx\n", (long int) adjectives_offset); printf(" | adjectives | %s\n", show_percentage(dictionary_at-adjectives_offset, Out_Size)); printf(" +---------------------+ %05lx\n", (long int) dictionary_at); addr = (static_array_area_size ? static_arrays_at : Write_Code_At); printf(" | dictionary | %s\n", show_percentage(addr-dictionary_at, Out_Size)); if (static_array_area_size) { printf(" +---------------------+ %05lx\n", (long int) static_arrays_at); printf(" | static arrays | %s\n", show_percentage(Write_Code_At-static_arrays_at, Out_Size)); } printf(" +=====================+ %05lx\n", (long int) Write_Code_At); printf("Above | Z-code | %s\n", show_percentage(Write_Strings_At-Write_Code_At, Out_Size)); printf("readable+---------------------+ %05lx\n", (long int) Write_Strings_At); addr = (Out_Size); printf("memory | strings | %s\n", show_percentage(addr-Write_Strings_At, Out_Size)); printf(" +---------------------+ %05lx\n", (long int) Out_Size); } } } static void construct_storyfile_g(void) { uchar *p; int32 i, j, k, l, mark, strings_length; int32 globals_at, dictionary_at, actions_at, preactions_at, abbrevs_at, prop_defaults_at, object_tree_at, object_props_at, grammar_table_at, arrays_at, static_arrays_at; int32 threespaces, code_length; int32 rough_size; ASSERT_GLULX(); individual_name_strings = my_calloc(sizeof(int32), no_individual_properties, "identifier name strings"); action_name_strings = my_calloc(sizeof(int32), no_actions + no_fake_actions, "action name strings"); attribute_name_strings = my_calloc(sizeof(int32), NUM_ATTR_BYTES*8, "attribute name strings"); array_name_strings = my_calloc(sizeof(int32), no_symbols, "array name strings"); write_the_identifier_names(); threespaces = compile_string(" ", STRCTX_GAME); compress_game_text(); /* We now know how large the buffer to hold our construction has to be */ rough_size = rough_size_of_paged_memory_g(); zmachine_paged_memory = my_malloc(rough_size, "output buffer"); /* Foolish code to make this routine compile on all ANSI compilers */ p = (uchar *) zmachine_paged_memory; /* In what follows, the "mark" will move upwards in memory: at various points its value will be recorded for milestones like "dictionary table start". It begins at 0x40, just after the header */ /* Ok, our policy here will be to set the *_at values all relative to RAM. That's so we can write into zmachine_paged_memory[mark] and actually hit what we're aiming at. All the *_offset values will be set to true Glulx machine addresses. */ /* To get our bearings, figure out where the strings and code are. */ /* We start with two words, which conventionally identify the memory layout. This is why the code starts eight bytes after the header. */ Write_Code_At = GLULX_HEADER_SIZE + GLULX_STATIC_ROM_SIZE; 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; } Write_Strings_At = Write_Code_At + code_length; strings_length = compression_table_size + compression_string_size; static_arrays_at = Write_Strings_At + strings_length; /* Now figure out where RAM starts. */ Write_RAM_At = static_arrays_at + static_array_area_size; /* The Write_RAM_At boundary must be a multiple of GPAGESIZE. */ while (Write_RAM_At % GPAGESIZE) Write_RAM_At++; /* Now work out all those RAM positions. */ mark = 0; /* ----------------- Variables and Dynamic Arrays --------------------- */ globals_at = mark; for (i=0; i> 24) & 0xFF; p[mark++] = (val >> 16) & 0xFF; p[mark++] = (val >> 8) & 0xFF; p[mark++] = (val) & 0xFF; } for (j=0; j rough_size) compiler_error("RAM size exceeds rough estimate."); Out_Size = Write_RAM_At + RAM_Size; /* --------------------------- Offsets -------------------------------- */ dictionary_offset = Write_RAM_At + dictionary_at; variables_offset = Write_RAM_At + globals_at; arrays_offset = Write_RAM_At + arrays_at; actions_offset = Write_RAM_At + actions_at; preactions_offset = Write_RAM_At + preactions_at; prop_defaults_offset = Write_RAM_At + prop_defaults_at; object_tree_offset = Write_RAM_At + object_tree_at; prop_values_offset = Write_RAM_At + object_props_at; static_memory_offset = Write_RAM_At + grammar_table_at; grammar_table_offset = Write_RAM_At + grammar_table_at; abbreviations_offset = Write_RAM_At + abbrevs_at; code_offset = Write_Code_At; strings_offset = Write_Strings_At; static_arrays_offset = static_arrays_at; /* --------------------------- The Header ----------------------------- */ /* ------ Backpatch the machine, now that all information is in ------- */ if (TRUE) { backpatch_zmachine_image_g(); mark = actions_at + 4; for (i=0; i0; 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 (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_setting) { int32 addr; { printf(" +---------------------+ 000000\n"); printf("Read- | header | %s\n", show_percentage(GLULX_HEADER_SIZE, Out_Size)); printf(" only +=====================+ %06lx\n", (long int) GLULX_HEADER_SIZE); printf("memory | memory layout id | %s\n", show_percentage(Write_Code_At-GLULX_HEADER_SIZE, Out_Size)); printf(" +---------------------+ %06lx\n", (long int) Write_Code_At); printf(" | code | %s\n", show_percentage(Write_Strings_At-Write_Code_At, Out_Size)); printf(" +---------------------+ %06lx\n", (long int) Write_Strings_At); printf(" | string decode table | %s\n", show_percentage(compression_table_size, Out_Size)); printf(" + - - - - - - - - - - + %06lx\n", (long int) Write_Strings_At + compression_table_size); addr = (static_array_area_size ? static_arrays_at : Write_RAM_At+globals_at); printf(" | strings | %s\n", show_percentage(addr-(Write_Strings_At + compression_table_size), Out_Size)); if (static_array_area_size) { printf(" +---------------------+ %06lx\n", (long int) (static_arrays_at)); printf(" | static arrays | %s\n", show_percentage(Write_RAM_At+globals_at-static_arrays_at, Out_Size)); } printf(" +=====================+ %06lx\n", (long int) (Write_RAM_At+globals_at)); printf("Dynamic | global variables | %s\n", show_percentage(arrays_at-globals_at, Out_Size)); printf("memory + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+arrays_at)); printf(" | arrays | %s\n", show_percentage(abbrevs_at-arrays_at, Out_Size)); printf(" +---------------------+ %06lx\n", (long int) (Write_RAM_At+abbrevs_at)); printf(" | printing variables | %s\n", show_percentage(object_tree_at-abbrevs_at, Out_Size)); printf(" +---------------------+ %06lx\n", (long int) (Write_RAM_At+object_tree_at)); printf(" | objects | %s\n", show_percentage(object_props_at-object_tree_at, Out_Size)); printf(" + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+object_props_at)); printf(" | property values | %s\n", show_percentage(prop_defaults_at-object_props_at, Out_Size)); printf(" + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+prop_defaults_at)); printf(" | property defaults | %s\n", show_percentage(class_numbers_offset-prop_defaults_at, Out_Size)); printf(" + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+class_numbers_offset)); printf(" | class numbers table | %s\n", show_percentage(identifier_names_offset-class_numbers_offset, Out_Size)); printf(" + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+identifier_names_offset)); printf(" | id names table | %s\n", show_percentage(grammar_table_at-identifier_names_offset, Out_Size)); printf(" +---------------------+ %06lx\n", (long int) (Write_RAM_At+grammar_table_at)); printf(" | grammar table | %s\n", show_percentage(actions_at-grammar_table_at, Out_Size)); printf(" + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+actions_at)); printf(" | actions | %s\n", show_percentage(dictionary_offset-(Write_RAM_At+actions_at), Out_Size)); printf(" +---------------------+ %06lx\n", (long int) dictionary_offset); printf(" | dictionary | %s\n", show_percentage(Out_Size-dictionary_offset, Out_Size)); if (MEMORY_MAP_EXTENSION == 0) { printf(" +---------------------+ %06lx\n", (long int) Out_Size); } else { printf(" +=====================+ %06lx\n", (long int) Out_Size); printf("Runtime | (empty) |\n"); /* no percentage */ printf(" extn +---------------------+ %06lx\n", (long int) Out_Size+MEMORY_MAP_EXTENSION); } } } } static void display_frequencies() { int i, j; printf("How frequently abbreviations were used, and roughly\n"); printf("how many bytes they saved: ('_' denotes spaces)\n"); for (i=0; i= 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 %8ld bytes of memory\n\ Out: Version %d \"%s\" %s %d.%c%c%c%c%c%c (%ld%sK long):\n", no_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 %6d objects\n\ %6d global vars (maximum 233) %6d variable/array space\n", no_classes, no_objects, no_globals, dynamic_array_area_size); printf( "%6d verbs %6d dictionary entries\n\ %6d grammar lines (version %d) %6d grammar tokens (unlimited)\n\ %6d actions %6d attributes (maximum %2d)\n\ %6d common props (maximum %2d) %6d individual props (unlimited)\n", no_Inform_verbs, dict_entries, no_grammar_lines, grammar_version_number, no_grammar_tokens, no_actions, no_attributes, ((version_number==3)?32:48), no_properties-3, ((version_number==3)?29:61), 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))); } } static void display_statistics_g() { int32 k_long, rate; char *k_str = ""; int32 limit = 1024*1024; int32 strings_length = compression_table_size + compression_string_size; char *output_called = "story file"; 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 %8ld bytes of memory\n\ Out: %s %s %d.%c%c%c%c%c%c (%ld%sK long):\n", no_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 %6d objects\n\ %6d global vars %6d variable/array space\n", no_classes, no_objects, no_globals, dynamic_array_area_size); printf( "%6d verbs %6d dictionary entries\n\ %6d grammar lines (version %d) %6d grammar tokens (unlimited)\n\ %6d actions %6d attributes (maximum %2d)\n\ %6d common props (maximum %3d) %6d individual props (unlimited)\n", no_Inform_verbs, dict_entries, no_grammar_lines, grammar_version_number, no_grammar_tokens, no_actions, no_attributes, NUM_ATTR_BYTES*8, no_properties-3, INDIV_PROP_START-3, 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))); } } extern void construct_storyfile(void) { if (!glulx_mode) construct_storyfile_z(); else construct_storyfile_g(); /* Display all the trace/stats info that came out of compilation. (Except for the memory map, which uses a bunch of local variables from construct_storyfile_z/g(), so it's easier to do that inside that function.) */ if (frequencies_setting) display_frequencies(); if (list_symbols_setting) list_symbols(list_symbols_setting); if (list_dict_setting) show_dictionary(list_dict_setting); if (list_verbs_setting) list_verb_table(); if (list_objects_setting) list_object_tree(); if (statistics_switch) { if (!glulx_mode) display_statistics_z(); else display_statistics_g(); } } /* ========================================================================= */ /* Data structure management routines */ /* ------------------------------------------------------------------------- */ extern void init_tables_vars(void) { release_number = 1; statusline_flag = SCORE_STYLE; zmachine_paged_memory = NULL; if (!glulx_mode) { code_offset = 0x800; actions_offset = 0x800; preactions_offset = 0x800; dictionary_offset = 0x800; adjectives_offset = 0x800; variables_offset = 0; strings_offset = 0xc00; individuals_offset=0x800; identifier_names_offset=0x800; class_numbers_offset = 0x800; arrays_offset = 0x0800; /* only used in Glulx, but might as well set */ static_arrays_offset = 0x0800; } else { code_offset = 0x12345; actions_offset = 0x12345; preactions_offset = 0x12345; dictionary_offset = 0x12345; adjectives_offset = 0x12345; variables_offset = 0x12345; arrays_offset = 0x12345; strings_offset = 0x12345; individuals_offset=0x12345; identifier_names_offset=0x12345; class_numbers_offset = 0x12345; static_arrays_offset = 0x12345; } } extern void tables_begin_pass(void) { } extern void tables_allocate_arrays(void) { } extern void tables_free_arrays(void) { /* Allocation for this array happens in construct_storyfile() above */ my_free(&zmachine_paged_memory,"output buffer"); } /* ========================================================================= */