/* ------------------------------------------------------------------------- */ /* "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.30 */ /* copyright (c) Graham Nelson 1993 - 2004 */ /* */ /* ------------------------------------------------------------------------- */ #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, 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; 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 */ serial_code_given_in_program; /* If TRUE, a Serial directive has */ char serial_code_buffer[7]; /* specified this 6-digit serial code */ /* (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 (header_ext_setting>3) total += (header_ext_setting-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; i3) headerext_length = header_ext_setting; p[mark++] = 0; p[mark++] = headerext_length; 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 > 0x10000) { 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 $10000 \ or less."); memory_map_switch = TRUE; } /* -------------------------- Code Area ------------------------------- */ /* (From this point on we don't write any more into the "p" buffer.) */ /* -------------------------------------------------------------------- */ Write_Code_At = mark; mark += zmachine_pc; /* ------------------ 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; 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 = zmachine_pc + 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 -------------------------- */ i = headerext_at + 2; p[i++] = 0; p[i++] = 0; /* Mouse x-coordinate slot */ p[i++] = 0; p[i++] = 0; /* Mouse y-coordinate slot */ j = unicode_at; p[i++] = j/256; p[i++] = j%256; /* Unicode translation table address */ /* ----------------- 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) { 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: 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 %6ld characters ", input_file, no_syntax_lines, total_source_line_count, (long int) total_chars_read); 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) %6ld 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 %2d) %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); 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) { write_debug_byte(MAP_DBR); write_debug_string("abbreviations table"); write_debug_address(abbrevs_at); write_debug_string("header extension"); write_debug_address(headerext_at); if (alphabet_modified) { write_debug_string("alphabets table"); write_debug_address(charset_at); } if (zscii_defn_modified) { write_debug_string("Unicode table"); write_debug_address(unicode_at); } write_debug_string("property defaults"); write_debug_address(prop_defaults_at); write_debug_string("object tree"); write_debug_address(object_tree_at); write_debug_string("common properties"); write_debug_address(object_props_at); write_debug_string("class numbers"); write_debug_address(class_numbers_offset); write_debug_string("individual properties"); write_debug_address(individuals_offset); write_debug_string("global variables"); write_debug_address(globals_at); write_debug_string("array space"); write_debug_address(globals_at+480); write_debug_string("grammar table"); write_debug_address(grammar_table_at); write_debug_string("actions table"); write_debug_address(actions_at); write_debug_string("parsing routines"); write_debug_address(preactions_at); write_debug_string("adjectives table"); write_debug_address(adjectives_offset); write_debug_string("dictionary"); write_debug_address(dictionary_at); write_debug_string("code area"); write_debug_address(Write_Code_At); write_debug_string("strings area"); write_debug_address(Write_Strings_At); write_debug_byte(0); } 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"); } 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", zmachine_pc,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; } } if (object_props_at != mark) error("*** Object table was impossible length ***"); 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]*(7+DICT_WORD_SIZE); break; case 2: 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 (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 %6ld characters ", input_file, no_syntax_lines, total_source_line_count, (long int) total_chars_read); 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) %6ld 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, serialnum[0], serialnum[1], serialnum[2], serialnum[3], serialnum[4], serialnum[5], (long int) k_long, k_str); } printf("\ %6d classes (maximum %2d) %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); 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 readable memory used (maximum 65536)\n\ %6ld bytes used in machine %6ld bytes free in 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 (debugfile_switch) { write_debug_byte(MAP_DBR); write_debug_string("abbreviations table"); write_debug_address(abbrevs_at); write_debug_string("header extension"); write_debug_address(headerext_at); if (alphabet_modified) { write_debug_string("alphabets table"); write_debug_address(charset_at); } if (zscii_defn_modified) { write_debug_string("Unicode table"); write_debug_address(unicode_at); } write_debug_string("property defaults"); write_debug_address(prop_defaults_at); write_debug_string("object tree"); write_debug_address(object_tree_at); write_debug_string("common properties"); write_debug_address(object_props_at); write_debug_string("class numbers"); write_debug_address(class_numbers_offset); write_debug_string("individual properties"); write_debug_address(individuals_offset); write_debug_string("global variables"); write_debug_address(globals_at); write_debug_string("array space"); write_debug_address(globals_at+480); /* ###fix in Glulx */ write_debug_string("grammar table"); write_debug_address(grammar_table_at); write_debug_string("actions table"); write_debug_address(actions_at); write_debug_string("parsing routines"); write_debug_address(preactions_at); write_debug_string("adjectives table"); write_debug_address(adjectives_offset); write_debug_string("dictionary"); write_debug_address(dictionary_at); write_debug_string("code area"); write_debug_address(Write_Code_At); write_debug_string("strings area"); write_debug_address(Write_Strings_At); write_debug_byte(0); } 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"); 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("Readable| grammar table |\n"); printf("memory + - - - - - - - - - - + %06lx\n", (long int) (Write_RAM_At+actions_at)); printf(" | actions |\n"); printf(" + - - - - - - - - - - + %06lx\n", (long int) preactions_at); printf(" | parsing routines |\n"); printf(" + - - - - - - - - - - + %06lx\n", (long int) adjectives_offset); printf(" | adjectives |\n"); printf(" +---------------------+ %06lx\n", (long int) dictionary_offset); printf(" | dictionary |\n"); printf(" +---------------------+ %06lx\n", (long int) Out_Size); } } if (percentages_switch) { printf("Approximate percentage breakdown of %s:\n", output_called); percentage("Code", zmachine_pc,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