Update to Inform v6.42
[inform.git] / src / tables.c
1 /* ------------------------------------------------------------------------- */
2 /*   "tables" :  Constructs the story file (the output) up to the end        */
3 /*               of dynamic memory, gluing together all the required         */
4 /*               tables.                                                     */
5 /*                                                                           */
6 /*   Part of Inform 6.42                                                     */
7 /*   copyright (c) Graham Nelson 1993 - 2024                                 */
8 /*                                                                           */
9 /* Inform is free software: you can redistribute it and/or modify            */
10 /* it under the terms of the GNU General Public License as published by      */
11 /* the Free Software Foundation, either version 3 of the License, or         */
12 /* (at your option) any later version.                                       */
13 /*                                                                           */
14 /* Inform is distributed in the hope that it will be useful,                 */
15 /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
16 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
17 /* GNU General Public License for more details.                              */
18 /*                                                                           */
19 /* You should have received a copy of the GNU General Public License         */
20 /* along with Inform. If not, see https://gnu.org/licenses/                  */
21 /*                                                                           */
22 /* ------------------------------------------------------------------------- */
23
24 #include "header.h"
25
26 uchar *zmachine_paged_memory;          /* Where we shall store the story file
27                                           constructed (contains all of paged
28                                           memory, i.e. all but code and the
29                                           static strings: allocated only when
30                                           we know how large it needs to be,
31                                           at the end of the compilation pass */
32
33 /* In Glulx, zmachine_paged_memory contains all of RAM -- i.e. all but
34    the header, the code, the static arrays, and the static strings. */
35
36 /* ------------------------------------------------------------------------- */
37 /*   Offsets of various areas in the Z-machine: these are set to nominal     */
38 /*   values before the compilation pass, and to their calculated final       */
39 /*   values only when construct_storyfile() happens.  These are then used to */
40 /*   backpatch the incorrect values now existing in the Z-machine which      */
41 /*   used these nominal values.                                              */
42 /*   Most of the nominal values are 0x800 because this is guaranteed to      */
43 /*   be assembled as a long constant if it's needed in code, since the       */
44 /*   largest possible value of scale_factor is 8 and 0x800/8 = 256.          */
45 /*                                                                           */
46 /*   In Glulx, I use 0x12345 instead of 0x800. This will always be a long    */
47 /*   (32-bit) constant, since there's no scale_factor.                       */
48 /* ------------------------------------------------------------------------- */
49
50 int32 code_offset,
51       actions_offset,
52       preactions_offset,
53       dictionary_offset,
54       adjectives_offset,
55       variables_offset,
56       strings_offset,
57       class_numbers_offset,
58       individuals_offset,
59       identifier_names_offset,
60       array_names_offset,
61       prop_defaults_offset,
62       prop_values_offset,
63       static_memory_offset,
64       attribute_names_offset,
65       action_names_offset,
66       fake_action_names_offset,
67       routine_names_offset,
68       constant_names_offset,
69       routines_array_offset,
70       constants_array_offset,
71       routine_flags_array_offset,
72       global_names_offset,
73       global_flags_array_offset,
74       array_flags_array_offset,
75       static_arrays_offset;
76 int32 arrays_offset,
77       object_tree_offset,
78       grammar_table_offset,
79       abbreviations_offset; /* Glulx */
80
81 int32 Out_Size, Write_Code_At, Write_Strings_At;
82 int32 RAM_Size, Write_RAM_At; /* Glulx */
83
84 /* ------------------------------------------------------------------------- */
85 /*   Story file header settings.   (Written to in "directs.c" and "asm.c".)  */
86 /* ------------------------------------------------------------------------- */
87
88 int release_number,                    /* Release number game is to have     */
89     statusline_flag;                   /* Either TIME_STYLE or SCORE_STYLE   */
90
91 int serial_code_given_in_program       /* If TRUE, a Serial directive has    */
92     = FALSE;                           /* specified this 6-digit serial code */
93 char serial_code_buffer[7];            /* (overriding the usual date-stamp)  */
94 int flags2_requirements[16];           /* An array of which bits in Flags 2 of
95                                           the header will need to be set:
96                                           e.g. if the save_undo / restore_undo
97                                           opcodes are ever assembled, we have
98                                           to set the "games want UNDO" bit.
99                                           Values are 0 or 1.                 */
100
101 /* ------------------------------------------------------------------------- */
102 /*   Construct story file (up to code area start).                           */
103 /*                                                                           */
104 /*   (To understand what follows, you really need to look at the run-time    */
105 /*   system's specification, the Z-Machine Standards document.)              */
106 /* ------------------------------------------------------------------------- */
107
108 extern void write_serial_number(char *buffer)
109 {
110     /*  Note that this function may require modification for "ANSI" compilers
111         which do not provide the standard time functions: what is needed is
112         the ability to work out today's date                                 */
113
114     time_t tt;  tt=time(0);
115     if (serial_code_given_in_program) {
116         strcpy(buffer, serial_code_buffer);
117     }
118     else {
119 #ifdef TIME_UNAVAILABLE
120         sprintf(buffer,"970000");
121 #else
122         /* Write a six-digit date, null-terminated. Fall back to "970000"
123            if that fails. */
124         int len = strftime(buffer,7,"%y%m%d",localtime(&tt));
125         if (len != 6)
126             sprintf(buffer,"970000");
127 #endif
128     }
129 }
130
131 static char percentage_buffer[64];
132
133 static char *show_percentage(int32 x, int32 total)
134 {
135     if (memory_map_setting < 2) {
136         percentage_buffer[0] = '\0';
137     }
138     else if (x == 0) {
139         sprintf(percentage_buffer, "  ( --- )");
140     }
141     else if (memory_map_setting < 3) {
142         sprintf(percentage_buffer, "  (%.1f %%)", (float)x * 100.0 / (float)total);
143     }
144     else {
145         sprintf(percentage_buffer, "  (%.1f %%, %d bytes)", (float)x * 100.0 / (float)total, x);
146     }
147     return percentage_buffer;
148 }
149
150 static char *version_name(int v)
151 {
152   if (!glulx_mode) {
153     switch(v)
154     {   case 3: return "Standard";
155         case 4: return "Plus";
156         case 5: return "Advanced";
157         case 6: return "Graphical";
158         case 7: return "Extended Alternate";
159         case 8: return "Extended";
160     }
161     return "experimental format";
162   }
163   else {
164     return "Glulx";
165   }
166 }
167
168 static int32 rough_size_of_paged_memory_z(void)
169 {
170     /*  This function calculates a modest over-estimate of the amount of
171         memory required to store the Z-machine's paged memory area
172         (that is, everything up to the start of the code area).              */
173
174     int32 total, i;
175
176     ASSERT_ZCODE();
177
178     total = 64                                                     /* header */
179             + 2 + low_strings_top
180                                                          /* low strings pool */
181             + 6*32;                                   /* abbreviations table */
182
183     total += 8;                                    /* header extension table */
184     if (ZCODE_HEADER_EXT_WORDS>3) total += (ZCODE_HEADER_EXT_WORDS-3)*2;
185
186     if (alphabet_modified) total += 78;               /* character set table */
187
188     if (zscii_defn_modified)                    /* Unicode translation table */
189         total += 2 + 2*zscii_high_water_mark;
190
191     total += 2*((version_number==3)?31:63)        /* property default values */
192             + no_objects*((version_number==3)?9:14)     /* object tree table */
193             + properties_table_size            /* property values of objects */
194             + (no_classes+1)*2
195                                                /* class object numbers table */
196             + no_symbols*2                       /* names of numerous things */
197             + individuals_length                 /* tables of prop variables */
198             + dynamic_array_area_size;               /* variables and arrays */
199
200     for (i=0; i<no_Inform_verbs; i++)
201         total += 2 + 1 +                        /* address of grammar table, */
202                                                   /* number of grammar lines */
203                  ((grammar_version_number == 1)?
204                   (8*Inform_verbs[i].lines):0);             /* grammar lines */
205
206     if (grammar_version_number != 1)
207         total += grammar_lines_top;            /* size of grammar lines area */
208
209     total +=  2 + 4*no_adjectives                        /* adjectives table */
210               + 2*no_actions                              /* action routines */
211               + 2*no_grammar_token_routines;     /* general parsing routines */
212
213     total += (dictionary_top)                            /* dictionary size */
214              + (0);                                           /* module map */
215
216     total += static_array_area_size;                       /* static arrays */
217
218     total += scale_factor*0x100            /* maximum null bytes before code */
219             + 1000;             /* fudge factor (in case the above is wrong) */
220
221     return(total);
222 }
223
224 static int32 rough_size_of_paged_memory_g(void)
225 {
226     /*  This function calculates a modest over-estimate of the amount of
227         memory required to store the machine's paged memory area
228         (that is, everything past the start of RAM). */
229
230     int32 total;
231
232     ASSERT_GLULX();
233
234     /* No header for us! */
235     total = 1000; /* bit of a fudge factor */
236
237     total += no_globals * 4; /* global variables */
238     total += dynamic_array_area_size; /* arrays */
239
240     total += no_objects * OBJECT_BYTE_LENGTH; /* object tables */
241     total += properties_table_size; /* property tables */
242     total += no_properties * 4; /* property defaults table */
243
244     total += 4 + no_classes * 4; /* class prototype object numbers */
245
246     total += 32; /* address/length of the identifier tables */
247     total += no_properties * 4;
248     total += (no_individual_properties-INDIV_PROP_START) * 4;
249     total += (NUM_ATTR_BYTES*8) * 4;
250     total += (no_actions + no_fake_actions) * 4;
251     total += 4 + no_arrays * 4;
252
253     total += 4 + no_Inform_verbs * 4; /* index of grammar tables */
254     total += grammar_lines_top; /* grammar tables */
255
256     total += 4 + no_actions * 4; /* actions functions table */
257
258     total += 4;
259     total += dictionary_top;
260
261     while (total % GPAGESIZE)
262       total++;
263
264     return(total);
265 }
266
267 static void construct_storyfile_z(void)
268 {   uchar *p;
269     int32 i, j, k, l, mark, objs, strings_length, code_length,
270           limit=0, excess=0, extend_offset=0, headerext_length=0;
271     int32 globals_at=0, dictionary_at=0, actions_at=0, preactions_at=0,
272           abbrevs_at=0, prop_defaults_at=0, object_tree_at=0, object_props_at=0,
273           grammar_table_at=0, charset_at=0, headerext_at=0,
274           terminating_chars_at=0, unicode_at=0, id_names_length=0,
275           static_arrays_at=0;
276     int32 rough_size;
277     int skip_backpatching = FALSE;
278     char *output_called = "story file";
279
280     ASSERT_ZCODE();
281
282     if (!OMIT_SYMBOL_TABLE) {
283         individual_name_strings =
284             my_calloc(sizeof(int32), no_individual_properties,
285                       "identifier name strings");
286         action_name_strings =
287             my_calloc(sizeof(int32), no_actions + no_fake_actions,
288                       "action name strings");
289         attribute_name_strings =
290             my_calloc(sizeof(int32), 48,
291                       "attribute name strings");
292         array_name_strings =
293             my_calloc(sizeof(int32),
294                       no_symbols,
295                       "array name strings");
296
297         write_the_identifier_names();
298     }
299
300     /*  We now know how large the buffer to hold our construction has to be  */
301
302     rough_size = rough_size_of_paged_memory_z();
303     zmachine_paged_memory = my_malloc(rough_size, "output buffer");
304
305     /*  Foolish code to make this routine compile on all ANSI compilers      */
306
307     p = (uchar *) zmachine_paged_memory;
308
309     /*  In what follows, the "mark" will move upwards in memory: at various
310         points its value will be recorded for milestones like
311         "dictionary table start".  It begins at 0x40, just after the header  */
312
313     for (mark=0; mark<0x40; mark++)
314         p[mark] = 0x0;
315
316     /*  ----------------- Low Strings and Abbreviations -------------------- */
317
318     p[mark]=0x80; p[mark+1]=0; mark+=2;        /* Start the low strings pool
319                                          with a useful default string, "   " */
320
321     for (i=0; i<low_strings_top; mark++, i++)  /* Low strings pool */
322         p[0x42+i]=low_strings[i];
323
324     abbrevs_at = mark;
325     
326     if (MAX_ABBREVS + MAX_DYNAMIC_STRINGS != 96)
327         fatalerror("MAX_ABBREVS + MAX_DYNAMIC_STRINGS is not 96");
328     
329     /* Initially all 96 entries are set to "   ". (We store half of 0x40,
330        the address of the "   " we wrote above.) */
331     for (i=0; i<3*32; i++)
332     {   p[mark++]=0; p[mark++]=0x20;
333     }
334     
335     /* Entries from 0 to MAX_DYNAMIC_STRINGS (default 32) are "variable 
336        strings". Write the abbreviations after these. */
337     k = abbrevs_at+2*MAX_DYNAMIC_STRINGS;
338     for (i=0; i<no_abbreviations; i++)
339     {   j=abbreviations[i].value;
340         p[k++]=j/256;
341         p[k++]=j%256;
342     }
343
344     /*  ------------------- Header extension table ------------------------- */
345
346     headerext_at = mark;
347     headerext_length = ZCODE_HEADER_EXT_WORDS;
348     if (zscii_defn_modified) {
349         /* Need at least 3 words for unicode table address */
350         if (headerext_length < 3)
351             headerext_length = 3;
352     }
353     if (ZCODE_HEADER_FLAGS_3) {
354         /* Need at least 4 words for the flags-3 field (ZSpec 1.1) */
355         if (headerext_length < 4)
356             headerext_length = 4;
357     }
358     p[mark++] = 0; p[mark++] = headerext_length;
359     for (i=0; i<headerext_length; i++)
360     {   p[mark++] = 0; p[mark++] = 0;
361     }
362
363     /*  -------------------- Z-character set table ------------------------- */
364
365     if (alphabet_modified)
366     {   charset_at = mark;
367         for (i=0;i<3;i++) for (j=0;j<26;j++)
368         {   if (alphabet[i][j] == '~') p[mark++] = '\"';
369             else p[mark++] = alphabet[i][j];
370         }
371     }
372
373     /*  ------------------ Unicode translation table ----------------------- */
374
375     unicode_at = 0;
376     if (zscii_defn_modified)
377     {   unicode_at = mark;
378         p[mark++] = zscii_high_water_mark;
379         for (i=0;i<zscii_high_water_mark;i++)
380         {   j = zscii_to_unicode(155 + i);
381             if (j < 0 || j > 0xFFFF) {
382                 error("Z-machine Unicode translation table cannot contain characters beyond $FFFF.");
383             }
384             p[mark++] = j/256; p[mark++] = j%256;
385         }
386     }
387
388     /*  -------------------- Objects and Properties ------------------------ */
389
390     /* The object table must be word-aligned. The Z-machine spec does not
391        require this, but the RA__Pr() veneer routine does.
392     */
393     while ((mark%2) != 0) p[mark++]=0;
394
395     prop_defaults_at = mark;
396
397     p[mark++]=0; p[mark++]=0;
398
399     for (i=2; i< ((version_number==3)?32:64); i++)
400     {   p[mark++]=commonprops[i].default_value/256;
401         p[mark++]=commonprops[i].default_value%256;
402     }
403
404     object_tree_at = mark;
405
406     mark += ((version_number==3)?9:14)*no_objects;
407
408     object_props_at = mark;
409
410     for (i=0; i<properties_table_size; i++)
411         p[mark+i]=properties_table[i];
412
413     for (i=0, objs=object_tree_at; i<no_objects; i++)
414     {
415         if (version_number == 3)
416         {   p[objs]=objectsz[i].atts[0];
417             p[objs+1]=objectsz[i].atts[1];
418             p[objs+2]=objectsz[i].atts[2];
419             p[objs+3]=objectsz[i].atts[3];
420             p[objs+4]=objectsz[i].parent;
421             p[objs+5]=objectsz[i].next;
422             p[objs+6]=objectsz[i].child;
423             p[objs+7]=mark/256;
424             p[objs+8]=mark%256;
425             objs+=9;
426         }
427         else
428         {   p[objs]=objectsz[i].atts[0];
429             p[objs+1]=objectsz[i].atts[1];
430             p[objs+2]=objectsz[i].atts[2];
431             p[objs+3]=objectsz[i].atts[3];
432             p[objs+4]=objectsz[i].atts[4];
433             p[objs+5]=objectsz[i].atts[5];
434             p[objs+6]=(objectsz[i].parent)/256;
435             p[objs+7]=(objectsz[i].parent)%256;
436             p[objs+8]=(objectsz[i].next)/256;
437             p[objs+9]=(objectsz[i].next)%256;
438             p[objs+10]=(objectsz[i].child)/256;
439             p[objs+11]=(objectsz[i].child)%256;
440             p[objs+12]=mark/256;
441             p[objs+13]=mark%256;
442             objs+=14;
443         }
444         mark+=objectsz[i].propsize;
445     }
446
447     /*  ----------- Table of Class Prototype Object Numbers ---------------- */
448
449     class_numbers_offset = mark;
450     for (i=0; i<no_classes; i++)
451     {   p[mark++] = class_info[i].object_number/256;
452         p[mark++] = class_info[i].object_number%256;
453     }
454     p[mark++] = 0;
455     p[mark++] = 0;
456
457     /*  ------------------- Table of Identifier Names ---------------------- */
458
459     identifier_names_offset = mark;
460
461     if (!OMIT_SYMBOL_TABLE)
462     {   p[mark++] = no_individual_properties/256;
463         p[mark++] = no_individual_properties%256;
464         for (i=1; i<no_individual_properties; i++)
465         {   p[mark++] = individual_name_strings[i]/256;
466             p[mark++] = individual_name_strings[i]%256;
467         }
468
469         attribute_names_offset = mark;
470         for (i=0; i<48; i++)
471         {   p[mark++] = attribute_name_strings[i]/256;
472             p[mark++] = attribute_name_strings[i]%256;
473         }
474
475         action_names_offset = mark;
476         fake_action_names_offset = mark + 2*no_actions;
477         for (i=0; i<no_actions + no_fake_actions; i++)
478         {   p[mark++] = action_name_strings[i]/256;
479             p[mark++] = action_name_strings[i]%256;
480         }
481
482         array_names_offset = mark;
483         global_names_offset = mark + 2*no_arrays;
484         routine_names_offset = global_names_offset + 2*no_globals;
485         constant_names_offset = routine_names_offset + 2*no_named_routines;
486         for (i=0; i<no_arrays + no_globals
487                     + no_named_routines + no_named_constants; i++)
488         {   if ((i == no_arrays) && (define_INFIX_switch == FALSE)) break;
489             p[mark++] = array_name_strings[i]/256;
490             p[mark++] = array_name_strings[i]%256;
491         }
492
493         id_names_length = (mark - identifier_names_offset)/2;
494     }
495     else {
496         attribute_names_offset = mark;
497         action_names_offset = mark;
498         fake_action_names_offset = mark;
499         array_names_offset = mark;
500         global_names_offset = mark;
501         routine_names_offset = mark;
502         constant_names_offset = mark;
503         id_names_length = 0;
504     }
505     
506     routine_flags_array_offset = mark;
507
508     if (define_INFIX_switch)
509     {   for (i=0, k=1, l=0; i<no_named_routines; i++)
510         {   if (symbols[named_routine_symbols[i]].flags & STAR_SFLAG) l=l+k;
511             k=k*2;
512             if (k==256) { p[mark++] = l; k=1; l=0; }
513         }
514         if (k!=1) p[mark++]=l;
515     }
516
517     /*  ---------------- Table of Indiv Property Values -------------------- */
518
519     individuals_offset = mark;
520     for (i=0; i<individuals_length; i++)
521         p[mark++] = individuals_table[i];
522
523     /*  ----------------- Variables and Dynamic Arrays --------------------- */
524
525     globals_at = mark;
526
527     for (i=0; i<dynamic_array_area_size; i++)
528         p[mark++] = dynamic_array_area[i];
529
530     for (i=0; i<240; i++)
531     {   j=global_initial_value[i];
532         p[globals_at+i*2]   = j/256; p[globals_at+i*2+1] = j%256;
533     }
534
535     /*  ------------------ Terminating Characters Table -------------------- */
536
537     if (version_number >= 5)
538     {   terminating_chars_at = mark;
539         for (i=0; i<no_termcs; i++) p[mark++] = terminating_characters[i];
540         p[mark++] = 0;
541     }
542
543     /*  ------------------------ Grammar Table ----------------------------- */
544
545     if (grammar_version_number > 2)
546     {   warning("This version of Inform is unable to produce the grammar \
547 table format requested (producing number 2 format instead)");
548         grammar_version_number = 2;
549     }
550
551     grammar_table_at = mark;
552
553     mark = mark + no_Inform_verbs*2;
554
555     for (i=0; i<no_Inform_verbs; i++)
556     {   p[grammar_table_at + i*2] = (mark/256);
557         p[grammar_table_at + i*2 + 1] = (mark%256);
558         if (!Inform_verbs[i].used) {
559             /* This verb was marked unused at locate_dead_grammar_lines()
560                time. Omit the grammar lines. */
561             p[mark++] = 0;
562             continue;
563         }
564         p[mark++] = Inform_verbs[i].lines;
565         for (j=0; j<Inform_verbs[i].lines; j++)
566         {   k = Inform_verbs[i].l[j];
567             if (grammar_version_number == 1)
568             {   int m, n;
569                 p[mark+7] = grammar_lines[k+1];
570                 for (m=1;m<=6;m++) p[mark + m] = 0;
571                 k = k + 2; m = 1; n = 0;
572                 while ((grammar_lines[k] != 15) && (m<=6))
573                 {   p[mark + m] = grammar_lines[k];
574                     if (grammar_lines[k] < 180) n++;
575                     m++; k = k + 3;
576                 }
577                 p[mark] = n;
578                 mark = mark + 8;
579             }
580             else
581             {   int tok;
582                 p[mark++] = grammar_lines[k++];
583                 p[mark++] = grammar_lines[k++];
584                 for (;;)
585                 {   tok = grammar_lines[k++];
586                     p[mark++] = tok;
587                     if (tok == 15) break;
588                     p[mark++] = grammar_lines[k++];
589                     p[mark++] = grammar_lines[k++];
590                 }
591             }
592         }
593     }
594
595     /*  ------------------- Actions and Preactions ------------------------- */
596     /*  (The term "preactions" is traditional: Inform uses the preactions    */
597     /*  table for a different purpose than Infocom used to.)                 */
598     /*  The values are written later, when the Z-code offset is known.       */
599     /*  -------------------------------------------------------------------- */
600
601     actions_at = mark;
602     mark += no_actions*2;
603
604     preactions_at = mark;
605     if (grammar_version_number == 1)
606         mark += no_grammar_token_routines*2;
607
608     /*  ----------------------- Adjectives Table --------------------------- */
609
610     if (grammar_version_number == 1)
611     {   p[mark]=0; p[mark+1]=no_adjectives; mark+=2; /* To assist "infodump" */
612         adjectives_offset = mark;
613         dictionary_offset = mark + 4*no_adjectives;
614
615         for (i=0; i<no_adjectives; i++)
616         {   j = final_dict_order[adjectives[no_adjectives-i-1]]
617                 *DICT_ENTRY_BYTE_LENGTH
618                 + dictionary_offset + 7;
619             p[mark++]=j/256; p[mark++]=j%256; p[mark++]=0;
620             p[mark++]=(256-no_adjectives+i);
621         }
622     }
623     else
624     {   p[mark]=0; p[mark+1]=0; mark+=2;
625         adjectives_offset = mark;
626         dictionary_offset = mark;
627     }
628
629     /*  ------------------------- Dictionary ------------------------------- */
630
631     dictionary_at=mark;
632
633     dictionary[0]=3; dictionary[1]='.';        /* Non-space characters which */
634                      dictionary[2]=',';                 /* force words apart */
635                      dictionary[3]='"';
636
637     dictionary[4]=DICT_ENTRY_BYTE_LENGTH;           /* Length of each entry */
638     dictionary[5]=(dict_entries/256);                   /* Number of entries */
639     dictionary[6]=(dict_entries%256);
640
641     for (i=0; i<7; i++) p[mark++] = dictionary[i];
642
643     for (i=0; i<dict_entries; i++)
644     {   k = 7 + i*DICT_ENTRY_BYTE_LENGTH;
645         j = mark + final_dict_order[i]*DICT_ENTRY_BYTE_LENGTH;
646         for (l = 0; l<DICT_ENTRY_BYTE_LENGTH; l++)
647             p[j++] = dictionary[k++];
648     }
649     mark += dict_entries * DICT_ENTRY_BYTE_LENGTH;
650
651     /*  ------------------------- Module Map ------------------------------- */
652
653     /* (no longer used) */
654
655     /*  ------------------------ Static Arrays ----------------------------- */
656
657     static_arrays_at = mark;
658     for (i=0; i<static_array_area_size; i++)
659         p[mark++] = static_array_area[i];
660     
661     /*  ----------------- A gap before the code area ----------------------- */
662     /*  (so that it will start at an exact packed address and so that all    */
663     /*  routine packed addresses are >= 256, hence long constants)           */
664     /*  -------------------------------------------------------------------- */
665
666     while ((mark%length_scale_factor) != 0) p[mark++]=0;
667     while (mark < (scale_factor*0x100)) p[mark++]=0;
668     if (oddeven_packing_switch)
669         while ((mark%(scale_factor*2)) != 0) p[mark++]=0;
670
671     if (mark > 0x0FFFE)
672     {   error("This program has overflowed the maximum readable-memory \
673 size of the Z-machine format. See the memory map below: the start \
674 of the area marked \"above readable memory\" must be brought down to $FFFE \
675 or less.");
676         memory_map_setting = 1;
677         /* Backpatching the grammar tables requires us to trust some of the */
678         /* addresses we've written into Z-machine memory, but they may have */
679         /* been truncated to 16 bits, so we can't do it.                    */
680         skip_backpatching = TRUE;
681     }
682
683     /*  -------------------------- Code Area ------------------------------- */
684     /*  (From this point on we don't write any higher into the "p" buffer.)  */
685     /*  -------------------------------------------------------------------- */
686
687     if (mark > rough_size)
688         compiler_error("Paged size exceeds rough estimate.");
689
690     Write_Code_At = mark;
691     if (!OMIT_UNUSED_ROUTINES) {
692         code_length = zmachine_pc;
693     }
694     else {
695         if (zmachine_pc != df_total_size_before_stripping)
696             compiler_error("Code size does not match (zmachine_pc and df_total_size).");
697         code_length = df_total_size_after_stripping;
698     }
699     mark += code_length;
700
701     /*  ------------------ Another synchronising gap ----------------------- */
702
703     if (oddeven_packing_switch)
704     {   
705         while ((mark%(scale_factor*2)) != scale_factor) mark++;
706     }
707     else
708         while ((mark%scale_factor) != 0) mark++;
709
710     /*  ------------------------- Strings Area ----------------------------- */
711
712     Write_Strings_At = mark;
713     strings_length = static_strings_extent;
714     mark += strings_length;
715
716     /*  --------------------- Module Linking Data -------------------------- */
717
718     /* (no longer used) */
719
720     /*  --------------------- Is the file too big? ------------------------- */
721
722     Out_Size = mark;
723
724     switch(version_number)
725     {   case 3: excess = Out_Size-((int32) 0x20000L); limit = 128; break;
726         case 4:
727         case 5: excess = Out_Size-((int32) 0x40000L); limit = 256; break;
728         case 6:
729         case 7:
730         case 8: excess = Out_Size-((int32) 0x80000L); limit = 512; break;
731     }
732
733     if (excess > 0)
734     {
735         fatalerror_fmt(
736             "The %s exceeds version-%d limit (%dK) by %d bytes",
737              output_called, version_number, limit, excess);
738     }
739
740     /*  --------------------------- Offsets -------------------------------- */
741
742     dictionary_offset = dictionary_at;
743     variables_offset = globals_at;
744     actions_offset = actions_at;
745     preactions_offset = preactions_at;
746     prop_defaults_offset = prop_defaults_at;
747     prop_values_offset = object_props_at;
748     static_memory_offset = grammar_table_at;
749     grammar_table_offset = grammar_table_at;
750     static_arrays_offset = static_arrays_at;
751
752     if (extend_memory_map)
753     {   extend_offset=256;
754         if (no_objects+9 > extend_offset) extend_offset=no_objects+9;
755         while ((extend_offset%length_scale_factor) != 0) extend_offset++;
756         /* Not sure why above line is necessary, but oddeven_packing
757          * will need extend_offset to be even */
758         code_offset = extend_offset*scale_factor;
759         if (oddeven_packing_switch)
760             strings_offset = code_offset + scale_factor;
761         else
762             strings_offset = code_offset + (Write_Strings_At-Write_Code_At);
763
764         /* With the extended memory model, need to specifically check that we
765          * haven't overflowed the packed address range for routines or strings.
766          * With the standard memory model, we only need the earlier total size
767          * check.
768          */
769         excess = code_length + code_offset - (scale_factor*((int32) 0x10000L));
770         if (excess > 0)
771         {
772             fatalerror_fmt(
773                 "The code area limit has been exceeded by %d bytes",
774                  excess);
775         }
776
777         excess = strings_length + strings_offset - (scale_factor*((int32) 0x10000L));
778         if (excess > 0)
779         {
780             if (oddeven_packing_switch)
781                 fatalerror_fmt(
782                     "The strings area limit has been exceeded by %d bytes",
783                      excess);
784             else
785                 fatalerror_fmt(
786                     "The code+strings area limit has been exceeded by %d bytes. \
787  Try running Inform again with -B on the command line.",
788                      excess);
789         }
790     }
791     else
792     {   code_offset = Write_Code_At;
793         strings_offset = Write_Strings_At;
794     }
795
796     /*  --------------------------- The Header ----------------------------- */
797
798     for (i=0; i<=0x3f; i++) p[i]=0;             /* Begin with 64 blank bytes */
799
800     p[0] = version_number;                                 /* Version number */
801     p[1] = statusline_flag*2;          /* Bit 1 of Flags 1: statusline style */
802     p[2] = (release_number/256);
803     p[3] = (release_number%256);                                  /* Release */
804     p[4] = (Write_Code_At/256);
805     p[5] = (Write_Code_At%256);                       /* End of paged memory */
806     if (version_number==6)
807     {   j=code_offset/scale_factor;            /* Packed address of "Main__" */
808         p[6]=(j/256); p[7]=(j%256);
809     }
810     else
811     {   j=Write_Code_At+1;                       /* Initial PC value (bytes) */
812         p[6]=(j/256); p[7]=(j%256);            /* (first opcode in "Main__") */
813     }
814     p[8] = (dictionary_at/256); p[9]=(dictionary_at%256);      /* Dictionary */
815     p[10]=prop_defaults_at/256; p[11]=prop_defaults_at%256;       /* Objects */
816     p[12]=(globals_at/256); p[13]=(globals_at%256);          /* Dynamic area */
817     p[14]=(grammar_table_at/256);
818     p[15]=(grammar_table_at%256);                                 /* Grammar */
819     for (i=0, j=0, k=1;i<16;i++, k=k*2)         /* Flags 2 as needed for any */
820         j+=k*flags2_requirements[i];            /* unusual opcodes assembled */
821     p[16]=j/256; p[17]=j%256;
822     write_serial_number((char *) (p+18)); /* Serial number: 6 chars of ASCII */
823     p[24]=abbrevs_at/256;
824     p[25]=abbrevs_at%256;                             /* Abbreviations table */
825     p[26]=0; p[27]=0;            /* Length of file to be filled in "files.c" */
826     p[28]=0; p[29]=0;                  /* Checksum to be filled in "files.c" */
827
828     if (extend_memory_map)
829     {   j=(Write_Code_At - extend_offset*scale_factor)/length_scale_factor;
830         p[40]=j/256; p[41]=j%256;                         /* Routines offset */
831         if (oddeven_packing_switch)
832             j=(Write_Strings_At - extend_offset*scale_factor)/length_scale_factor;
833         p[42]=j/256; p[43]=j%256;                        /* = Strings offset */
834     }
835
836     if (version_number >= 5)
837     {   p[46] = terminating_chars_at/256;    /* Terminating characters table */
838         p[47] = terminating_chars_at%256;
839     }
840
841     if (alphabet_modified)
842     {   j = charset_at;
843         p[52]=j/256; p[53]=j%256; }           /* Character set table address */
844
845     j = headerext_at;
846     p[54] = j/256; p[55] = j%256;          /* Header extension table address */
847
848     p[60] = '0' + ((RELEASE_NUMBER/100)%10);
849     p[61] = '.';
850     p[62] = '0' + ((RELEASE_NUMBER/10)%10);
851     p[63] = '0' + RELEASE_NUMBER%10;
852
853     /*  ------------------------ Header Extension -------------------------- */
854
855     /* The numbering in the spec is a little weird -- it's headerext_length
856        words *after* the initial length word. We follow the spec numbering
857        in this switch statement, so the count is 1-based. */
858     for (i=1; i<=headerext_length; i++) {
859         switch (i) {
860         case 3:
861             j = unicode_at;             /* Unicode translation table address */
862             break;
863         case 4:
864             j = ZCODE_HEADER_FLAGS_3;                        /* Flags 3 word */
865             break;
866         default:
867             j = 0;
868             break;
869         }
870         p[headerext_at+2*i+0] = j / 256;
871         p[headerext_at+2*i+1] = j % 256;
872     }
873
874     /*  ----------------- The Header: Extras for modules ------------------- */
875
876     /* (no longer used) */
877
878     /*  ---- Backpatch the Z-machine, now that all information is in ------- */
879
880     if (!skip_backpatching)
881     {   backpatch_zmachine_image_z();
882
883         if (!OMIT_SYMBOL_TABLE) {
884             for (i=1; i<id_names_length; i++)
885             {   int32 v = 256*p[identifier_names_offset + i*2]
886                     + p[identifier_names_offset + i*2 + 1];
887                 if (v!=0) v += strings_offset/scale_factor;
888                 p[identifier_names_offset + i*2] = v/256;
889                 p[identifier_names_offset + i*2 + 1] = v%256;
890             }
891         }
892
893         mark = actions_at;
894         for (i=0; i<no_actions; i++)
895         {   j=actions[i].byte_offset;
896             if (OMIT_UNUSED_ROUTINES)
897                 j = df_stripped_address_for_address(j);
898             j += code_offset/scale_factor;
899             p[mark++]=j/256; p[mark++]=j%256;
900         }
901
902         if (grammar_version_number == 1)
903         {   mark = preactions_at;
904             for (i=0; i<no_grammar_token_routines; i++)
905             {   j=grammar_token_routine[i];
906                 if (OMIT_UNUSED_ROUTINES)
907                     j = df_stripped_address_for_address(j);
908                 j += code_offset/scale_factor;
909                 p[mark++]=j/256; p[mark++]=j%256;
910             }
911         }
912         else
913         {   for (l = 0; l<no_Inform_verbs; l++)
914             {   k = grammar_table_at + 2*l;
915                 i = p[k]*256 + p[k+1];
916                 for (j = p[i++]; j>0; j--)
917                 {   int topbits; int32 value;
918                     i = i + 2;
919                     while (p[i] != 15)
920                     {   topbits = (p[i]/0x40) & 3;
921                         value = p[i+1]*256 + p[i+2];
922                         switch(topbits)
923                         {   case 1:
924                                 value = final_dict_order[value]
925                                         *DICT_ENTRY_BYTE_LENGTH
926                                         + dictionary_offset + 7;
927                                 break;
928                             case 2:
929                                 if (OMIT_UNUSED_ROUTINES)
930                                     value = df_stripped_address_for_address(value);
931                                 value += code_offset/scale_factor;
932                                 break;
933                         }
934                         p[i+1] = value/256; p[i+2] = value%256;
935                         i = i + 3;
936                     }
937                     i++;
938                 }
939             }
940         }
941     }
942
943     /*  ---- From here on, it's all reportage: construction is finished ---- */
944
945     if (debugfile_switch)
946     {   begin_writing_debug_sections();
947         write_debug_section("abbreviations", 64);
948         write_debug_section("abbreviations table", abbrevs_at);
949         write_debug_section("header extension", headerext_at);
950         if (alphabet_modified)
951         {   write_debug_section("alphabets table", charset_at);
952         }
953         if (zscii_defn_modified)
954         {   write_debug_section("Unicode table", unicode_at);
955         }
956         write_debug_section("property defaults", prop_defaults_at);
957         write_debug_section("object tree", object_tree_at);
958         write_debug_section("common properties", object_props_at);
959         write_debug_section("class numbers", class_numbers_offset);
960         write_debug_section("identifier names", identifier_names_offset);
961         write_debug_section("individual properties", individuals_offset);
962         write_debug_section("global variables", globals_at);
963         write_debug_section("array space", globals_at+480);
964         write_debug_section("grammar table", grammar_table_at);
965         write_debug_section("actions table", actions_at);
966         write_debug_section("parsing routines", preactions_at);
967         write_debug_section("adjectives table", adjectives_offset);
968         write_debug_section("dictionary", dictionary_at);
969         write_debug_section("code area", Write_Code_At);
970         write_debug_section("strings area", Write_Strings_At);
971         end_writing_debug_sections(Out_Size);
972     }
973
974     if (memory_map_setting)
975     {
976         int32 addr;
977         {
978 printf("Dynamic +---------------------+   00000\n");
979 printf("memory  |       header        |   %s\n",
980     show_percentage(0x40, Out_Size));
981 printf("        +---------------------+   00040\n");
982 printf("        |    abbreviations    |   %s\n",
983     show_percentage(abbrevs_at-0x40, Out_Size));
984 printf("        + - - - - - - - - - - +   %05lx\n", (long int) abbrevs_at);
985 printf("        | abbreviations table |   %s\n",
986     show_percentage(headerext_at-abbrevs_at, Out_Size));
987 printf("        +---------------------+   %05lx\n", (long int) headerext_at);
988 addr = (alphabet_modified ? charset_at : (zscii_defn_modified ? unicode_at : prop_defaults_at));
989 printf("        |  header extension   |   %s\n",
990     show_percentage(addr-headerext_at, Out_Size));
991             if (alphabet_modified)
992             {
993 printf("        + - - - - - - - - - - +   %05lx\n", (long int) charset_at);
994 addr = (zscii_defn_modified ? unicode_at : prop_defaults_at);
995 printf("        |   alphabets table   |   %s\n",
996     show_percentage(addr-charset_at, Out_Size));
997             }
998             if (zscii_defn_modified)
999             {
1000 printf("        + - - - - - - - - - - +   %05lx\n", (long int) unicode_at);
1001 printf("        |    Unicode table    |   %s\n",
1002     show_percentage(prop_defaults_at-unicode_at, Out_Size));
1003             }
1004 printf("        +---------------------+   %05lx\n",
1005                                           (long int) prop_defaults_at);
1006 printf("        |  property defaults  |   %s\n",
1007     show_percentage(object_tree_at-prop_defaults_at, Out_Size));
1008 printf("        + - - - - - - - - - - +   %05lx\n", (long int) object_tree_at);
1009 printf("        |       objects       |   %s\n",
1010     show_percentage(object_props_at-object_tree_at, Out_Size));
1011 printf("        + - - - - - - - - - - +   %05lx\n",
1012                                           (long int) object_props_at);
1013 printf("        | object short names, |\n");
1014 printf("        | common prop values  |   %s\n",
1015     show_percentage(class_numbers_offset-object_props_at, Out_Size));
1016 printf("        + - - - - - - - - - - +   %05lx\n",
1017                                           (long int) class_numbers_offset);
1018 printf("        | class numbers table |   %s\n",
1019     show_percentage(identifier_names_offset-class_numbers_offset, Out_Size));
1020 printf("        + - - - - - - - - - - +   %05lx\n",
1021                                           (long int) identifier_names_offset);
1022 printf("        | symbol names table  |   %s\n",
1023     show_percentage(individuals_offset-identifier_names_offset, Out_Size));
1024 printf("        + - - - - - - - - - - +   %05lx\n",
1025                                           (long int) individuals_offset);
1026 printf("        | indiv prop values   |   %s\n",
1027     show_percentage(globals_at-individuals_offset, Out_Size));
1028 printf("        +---------------------+   %05lx\n", (long int) globals_at);
1029 printf("        |  global variables   |   %s\n",
1030     show_percentage(480, Out_Size));
1031 printf("        + - - - - - - - - - - +   %05lx\n",
1032                                           ((long int) globals_at)+480L);
1033 printf("        |       arrays        |   %s\n",
1034     show_percentage(grammar_table_at-(globals_at+480), Out_Size));
1035 printf("        +=====================+   %05lx\n",
1036                                           (long int) grammar_table_at);
1037 printf("Readable|    grammar table    |   %s\n",
1038     show_percentage(actions_at-grammar_table_at, Out_Size));
1039 printf("memory  + - - - - - - - - - - +   %05lx\n", (long int) actions_at);
1040 printf("        |       actions       |   %s\n",
1041     show_percentage(preactions_at-actions_at, Out_Size));
1042 printf("        + - - - - - - - - - - +   %05lx\n", (long int) preactions_at);
1043 printf("        |   parsing routines  |   %s\n",
1044     show_percentage(adjectives_offset-preactions_at, Out_Size));
1045 printf("        + - - - - - - - - - - +   %05lx\n",
1046                                           (long int) adjectives_offset);
1047 printf("        |     adjectives      |   %s\n",
1048     show_percentage(dictionary_at-adjectives_offset, Out_Size));
1049 printf("        +---------------------+   %05lx\n", (long int) dictionary_at);
1050 addr = (static_array_area_size ? static_arrays_at : Write_Code_At);
1051 printf("        |     dictionary      |   %s\n",
1052     show_percentage(addr-dictionary_at, Out_Size));
1053 if (static_array_area_size)
1054 {
1055 printf("        +---------------------+   %05lx\n", (long int) static_arrays_at);
1056 printf("        |    static arrays    |   %s\n",
1057     show_percentage(Write_Code_At-static_arrays_at, Out_Size));
1058 }
1059 printf("        +=====================+   %05lx\n", (long int) Write_Code_At);
1060 printf("Above   |       Z-code        |   %s\n",
1061     show_percentage(Write_Strings_At-Write_Code_At, Out_Size));
1062 printf("readable+---------------------+   %05lx\n",
1063                                           (long int) Write_Strings_At);
1064 addr = (Out_Size);
1065 printf("memory  |       strings       |   %s\n",
1066     show_percentage(addr-Write_Strings_At, Out_Size));
1067 printf("        +---------------------+   %05lx\n", (long int) Out_Size);
1068         }
1069     }
1070 }
1071
1072 static void construct_storyfile_g(void)
1073 {   uchar *p;
1074     int32 i, j, k, l, mark, strings_length;
1075     int32 globals_at, dictionary_at, actions_at, preactions_at,
1076           abbrevs_at, prop_defaults_at, object_tree_at, object_props_at,
1077           grammar_table_at, arrays_at, static_arrays_at;
1078     int32 threespaces, code_length;
1079     int32 rough_size;
1080
1081     ASSERT_GLULX();
1082
1083     individual_name_strings =
1084         my_calloc(sizeof(int32), no_individual_properties,
1085             "identifier name strings");
1086     action_name_strings =
1087         my_calloc(sizeof(int32), no_actions + no_fake_actions,
1088             "action name strings");
1089     attribute_name_strings =
1090         my_calloc(sizeof(int32), NUM_ATTR_BYTES*8,
1091             "attribute name strings");
1092     array_name_strings =
1093         my_calloc(sizeof(int32), 
1094             no_symbols,
1095             "array name strings");
1096
1097     write_the_identifier_names();
1098     threespaces = compile_string("   ", STRCTX_GAME);
1099
1100     compress_game_text();
1101
1102     /*  We now know how large the buffer to hold our construction has to be  */
1103
1104     rough_size = rough_size_of_paged_memory_g();
1105     zmachine_paged_memory = my_malloc(rough_size, "output buffer");
1106
1107     /*  Foolish code to make this routine compile on all ANSI compilers      */
1108
1109     p = (uchar *) zmachine_paged_memory;
1110
1111     /*  In what follows, the "mark" will move upwards in memory: at various
1112         points its value will be recorded for milestones like
1113         "dictionary table start".  It begins at 0x40, just after the header  */
1114
1115     /* Ok, our policy here will be to set the *_at values all relative
1116        to RAM. That's so we can write into zmachine_paged_memory[mark] 
1117        and actually hit what we're aiming at.
1118        All the *_offset values will be set to true Glulx machine
1119        addresses. */
1120
1121     /* To get our bearings, figure out where the strings and code are. */
1122     /* We start with two words, which conventionally identify the 
1123        memory layout. This is why the code starts eight bytes after
1124        the header. */
1125     Write_Code_At = GLULX_HEADER_SIZE + GLULX_STATIC_ROM_SIZE;
1126     if (!OMIT_UNUSED_ROUTINES) {
1127         code_length = zmachine_pc;
1128     }
1129     else {
1130         if (zmachine_pc != df_total_size_before_stripping)
1131             compiler_error("Code size does not match (zmachine_pc and df_total_size).");
1132         code_length = df_total_size_after_stripping;
1133     }
1134     Write_Strings_At = Write_Code_At + code_length;
1135     strings_length = compression_table_size + compression_string_size;
1136
1137     static_arrays_at = Write_Strings_At + strings_length;
1138
1139     /* Now figure out where RAM starts. */
1140     Write_RAM_At = static_arrays_at + static_array_area_size;
1141     /* The Write_RAM_At boundary must be a multiple of GPAGESIZE. */
1142     while (Write_RAM_At % GPAGESIZE)
1143       Write_RAM_At++;
1144
1145     /* Now work out all those RAM positions. */
1146     mark = 0;
1147
1148     /*  ----------------- Variables and Dynamic Arrays --------------------- */
1149
1150     globals_at = mark;
1151     for (i=0; i<no_globals; i++) {
1152       j = global_initial_value[i];
1153       WriteInt32(p+mark, j);
1154       mark += 4;
1155     }
1156
1157     arrays_at = mark;
1158     for (i=0; i<dynamic_array_area_size; i++)
1159         p[mark++] = dynamic_array_area[i];
1160
1161     /* -------------------------- Dynamic Strings -------------------------- */
1162
1163     abbrevs_at = mark;
1164     WriteInt32(p+mark, no_dynamic_strings);
1165     mark += 4;
1166     for (i=0; i<no_dynamic_strings; i++) {
1167       j = Write_Strings_At + compressed_offsets[threespaces-1];
1168       WriteInt32(p+mark, j);
1169       mark += 4;
1170     }
1171
1172     /*  -------------------- Objects and Properties ------------------------ */
1173
1174     object_tree_at = mark;
1175
1176     object_props_at = mark + no_objects*OBJECT_BYTE_LENGTH;
1177
1178     for (i=0; i<no_objects; i++) {
1179       int32 objmark = mark;
1180       p[mark++] = 0x70; /* type byte -- object */
1181       for (j=0; j<NUM_ATTR_BYTES; j++) {
1182         p[mark++] = objectatts[i*NUM_ATTR_BYTES+j];
1183       }
1184       for (j=0; j<6; j++) {
1185         int32 val = 0;
1186         switch (j) {
1187         case 0: /* next object in the linked list. */
1188           if (i == no_objects-1)
1189             val = 0;
1190           else
1191             val = Write_RAM_At + objmark + OBJECT_BYTE_LENGTH;
1192           break;
1193         case 1: /* hardware name address */
1194           val = Write_Strings_At + compressed_offsets[objectsg[i].shortname-1];
1195           break;
1196         case 2: /* property table address */
1197           val = Write_RAM_At + object_props_at + objectsg[i].propaddr;
1198           break;
1199         case 3: /* parent */
1200           if (objectsg[i].parent == 0)
1201             val = 0;
1202           else
1203             val = Write_RAM_At + object_tree_at +
1204               (OBJECT_BYTE_LENGTH*(objectsg[i].parent-1));
1205           break;
1206         case 4: /* sibling */
1207           if (objectsg[i].next == 0)
1208             val = 0;
1209           else
1210             val = Write_RAM_At + object_tree_at +
1211               (OBJECT_BYTE_LENGTH*(objectsg[i].next-1));
1212           break;
1213         case 5: /* child */
1214           if (objectsg[i].child == 0)
1215             val = 0;
1216           else
1217             val = Write_RAM_At + object_tree_at +
1218               (OBJECT_BYTE_LENGTH*(objectsg[i].child-1));
1219           break;
1220         }
1221         p[mark++] = (val >> 24) & 0xFF;
1222         p[mark++] = (val >> 16) & 0xFF;
1223         p[mark++] = (val >> 8) & 0xFF;
1224         p[mark++] = (val) & 0xFF;
1225       }
1226
1227       for (j=0; j<GLULX_OBJECT_EXT_BYTES; j++) {
1228         p[mark++] = 0;
1229       }
1230     }
1231
1232     if (object_props_at != mark)
1233       error("*** Object table was impossible length ***");
1234
1235     for (i=0; i<properties_table_size; i++)
1236       p[mark+i]=properties_table[i];
1237
1238     for (i=0; i<no_objects; i++) { 
1239       int32 tableaddr = object_props_at + objectsg[i].propaddr;
1240       int32 tablelen = ReadInt32(p+tableaddr);
1241       tableaddr += 4;
1242       for (j=0; j<tablelen; j++) {
1243         k = ReadInt32(p+tableaddr+4);
1244         k += (Write_RAM_At + object_props_at);
1245         WriteInt32(p+tableaddr+4, k);
1246         tableaddr += 10;
1247       }
1248     }
1249
1250     mark += properties_table_size;
1251
1252     prop_defaults_at = mark;
1253     for (i=0; i<no_properties; i++) {
1254       k = commonprops[i].default_value;
1255       WriteInt32(p+mark, k);
1256       mark += 4;
1257     }
1258
1259     /*  ----------- Table of Class Prototype Object Numbers ---------------- */
1260     
1261     class_numbers_offset = mark;
1262     for (i=0; i<no_classes; i++) {
1263       j = Write_RAM_At + object_tree_at +
1264         (OBJECT_BYTE_LENGTH*(class_info[i].object_number-1));
1265       WriteInt32(p+mark, j);
1266       mark += 4;
1267     }
1268     WriteInt32(p+mark, 0);
1269     mark += 4;
1270
1271     /* -------------------- Table of Property Names ------------------------ */
1272
1273     /* We try to format this bit with some regularity...
1274        address of common properties
1275        number of common properties
1276        address of indiv properties
1277        number of indiv properties (counted from INDIV_PROP_START)
1278        address of attributes
1279        number of attributes (always NUM_ATTR_BYTES*8)
1280        address of actions
1281        number of actions
1282     */
1283
1284     if (!OMIT_SYMBOL_TABLE) {
1285       identifier_names_offset = mark;
1286       mark += 32; /* eight pairs of values, to be filled in. */
1287   
1288       WriteInt32(p+identifier_names_offset+0, Write_RAM_At + mark);
1289       WriteInt32(p+identifier_names_offset+4, no_properties);
1290       for (i=0; i<no_properties; i++) {
1291         j = individual_name_strings[i];
1292         if (j)
1293           j = Write_Strings_At + compressed_offsets[j-1];
1294         WriteInt32(p+mark, j);
1295         mark += 4;
1296       }
1297   
1298       WriteInt32(p+identifier_names_offset+8, Write_RAM_At + mark);
1299       WriteInt32(p+identifier_names_offset+12, 
1300         no_individual_properties-INDIV_PROP_START);
1301       for (i=INDIV_PROP_START; i<no_individual_properties; i++) {
1302         j = individual_name_strings[i];
1303         if (j)
1304           j = Write_Strings_At + compressed_offsets[j-1];
1305         WriteInt32(p+mark, j);
1306         mark += 4;
1307       }
1308   
1309       WriteInt32(p+identifier_names_offset+16, Write_RAM_At + mark);
1310       WriteInt32(p+identifier_names_offset+20, NUM_ATTR_BYTES*8);
1311       for (i=0; i<NUM_ATTR_BYTES*8; i++) {
1312         j = attribute_name_strings[i];
1313         if (j)
1314           j = Write_Strings_At + compressed_offsets[j-1];
1315         WriteInt32(p+mark, j);
1316         mark += 4;
1317       }
1318   
1319       WriteInt32(p+identifier_names_offset+24, Write_RAM_At + mark);
1320       WriteInt32(p+identifier_names_offset+28, no_actions + no_fake_actions);
1321       action_names_offset = mark;
1322       fake_action_names_offset = mark + 4*no_actions;
1323       for (i=0; i<no_actions + no_fake_actions; i++) {
1324         j = action_name_strings[i];
1325         if (j)
1326           j = Write_Strings_At + compressed_offsets[j-1];
1327         WriteInt32(p+mark, j);
1328         mark += 4;
1329       }
1330   
1331       array_names_offset = mark;
1332       WriteInt32(p+mark, no_arrays);
1333       mark += 4;
1334       for (i=0; i<no_arrays; i++) {
1335         j = array_name_strings[i];
1336         if (j)
1337           j = Write_Strings_At + compressed_offsets[j-1];
1338         WriteInt32(p+mark, j);
1339         mark += 4;
1340       }
1341     }
1342     else {
1343       identifier_names_offset = mark;
1344       action_names_offset = mark;
1345       fake_action_names_offset = mark;
1346       array_names_offset = mark;
1347     }
1348
1349     individuals_offset = mark;
1350
1351     /*  ------------------------ Grammar Table ----------------------------- */
1352
1353     if (grammar_version_number != 2)
1354     {   warning("This version of Inform is unable to produce the grammar \
1355 table format requested (producing number 2 format instead)");
1356         grammar_version_number = 2;
1357     }
1358
1359     grammar_table_at = mark;
1360
1361     WriteInt32(p+mark, no_Inform_verbs);
1362     mark += 4;
1363
1364     mark += no_Inform_verbs*4;
1365
1366     for (i=0; i<no_Inform_verbs; i++) {
1367       j = mark + Write_RAM_At;
1368       WriteInt32(p+(grammar_table_at+4+i*4), j);
1369       if (!Inform_verbs[i].used) {
1370           /* This verb was marked unused at locate_dead_grammar_lines()
1371              time. Omit the grammar lines. */
1372           p[mark++] = 0;
1373           continue;
1374       }
1375       p[mark++] = Inform_verbs[i].lines;
1376       for (j=0; j<Inform_verbs[i].lines; j++) {
1377         int tok;
1378         k = Inform_verbs[i].l[j];
1379         p[mark++] = grammar_lines[k++];
1380         p[mark++] = grammar_lines[k++];
1381         p[mark++] = grammar_lines[k++];
1382         for (;;) {
1383           tok = grammar_lines[k++];
1384           p[mark++] = tok;
1385           if (tok == 15) break;
1386           p[mark++] = grammar_lines[k++];
1387           p[mark++] = grammar_lines[k++];
1388           p[mark++] = grammar_lines[k++];
1389           p[mark++] = grammar_lines[k++];
1390         }
1391       }
1392     }
1393
1394     /*  ------------------- Actions and Preactions ------------------------- */
1395
1396     actions_at = mark;
1397     WriteInt32(p+mark, no_actions);
1398     mark += 4;
1399     mark += no_actions*4;
1400     /* Values to be written in later. */
1401
1402     if (DICT_CHAR_SIZE != 1) {
1403       /* If the dictionary is Unicode, we'd like it to be word-aligned. */
1404       while (mark % 4)
1405         p[mark++]=0;
1406     }
1407
1408     preactions_at = mark;
1409     adjectives_offset = mark;
1410     dictionary_offset = mark;
1411
1412     /*  ------------------------- Dictionary ------------------------------- */
1413
1414     dictionary_at = mark;
1415
1416     WriteInt32(dictionary+0, dict_entries);
1417     for (i=0; i<4; i++) 
1418       p[mark+i] = dictionary[i];
1419
1420     for (i=0; i<dict_entries; i++) {
1421       k = 4 + i*DICT_ENTRY_BYTE_LENGTH;
1422       j = mark + 4 + final_dict_order[i]*DICT_ENTRY_BYTE_LENGTH;
1423       for (l=0; l<DICT_ENTRY_BYTE_LENGTH; l++)
1424         p[j++] = dictionary[k++];
1425     }
1426     mark += 4 + dict_entries * DICT_ENTRY_BYTE_LENGTH;
1427
1428     /*  -------------------------- All Data -------------------------------- */
1429     
1430     /* The end-of-RAM boundary must be a multiple of GPAGESIZE. */
1431     while (mark % GPAGESIZE)
1432       p[mark++]=0;
1433
1434     RAM_Size = mark;
1435
1436     if (RAM_Size > rough_size)
1437         compiler_error("RAM size exceeds rough estimate.");
1438     
1439     Out_Size = Write_RAM_At + RAM_Size;
1440
1441     /*  --------------------------- Offsets -------------------------------- */
1442
1443     dictionary_offset = Write_RAM_At + dictionary_at;
1444     variables_offset = Write_RAM_At + globals_at;
1445     arrays_offset = Write_RAM_At + arrays_at;
1446     actions_offset = Write_RAM_At + actions_at;
1447     preactions_offset = Write_RAM_At + preactions_at;
1448     prop_defaults_offset = Write_RAM_At + prop_defaults_at;
1449     object_tree_offset = Write_RAM_At + object_tree_at;
1450     prop_values_offset = Write_RAM_At + object_props_at;
1451     static_memory_offset = Write_RAM_At + grammar_table_at;
1452     grammar_table_offset = Write_RAM_At + grammar_table_at;
1453     abbreviations_offset = Write_RAM_At + abbrevs_at;
1454
1455     code_offset = Write_Code_At;
1456     strings_offset = Write_Strings_At;
1457     static_arrays_offset = static_arrays_at;
1458
1459     /*  --------------------------- The Header ----------------------------- */
1460
1461     /*  ------ Backpatch the machine, now that all information is in ------- */
1462
1463     if (TRUE)
1464     {   backpatch_zmachine_image_g();
1465
1466         mark = actions_at + 4;
1467         for (i=0; i<no_actions; i++) {
1468           j = actions[i].byte_offset;
1469           if (OMIT_UNUSED_ROUTINES)
1470             j = df_stripped_address_for_address(j);
1471           j += code_offset;
1472           WriteInt32(p+mark, j);
1473           mark += 4;
1474         }
1475
1476         for (l = 0; l<no_Inform_verbs; l++) {
1477           k = grammar_table_at + 4 + 4*l; 
1478           i = ((p[k] << 24) | (p[k+1] << 16) | (p[k+2] << 8) | (p[k+3]));
1479           i -= Write_RAM_At;
1480           for (j = p[i++]; j>0; j--) {
1481             int topbits; 
1482             int32 value;
1483             i = i + 3;
1484             while (p[i] != 15) {
1485               topbits = (p[i]/0x40) & 3;
1486               value = ((p[i+1] << 24) | (p[i+2] << 16) 
1487                 | (p[i+3] << 8) | (p[i+4]));
1488               switch(topbits) {
1489               case 1:
1490                 value = dictionary_offset + 4
1491                   + final_dict_order[value]*DICT_ENTRY_BYTE_LENGTH;
1492                 break;
1493               case 2:
1494                 if (OMIT_UNUSED_ROUTINES)
1495                   value = df_stripped_address_for_address(value);
1496                 value += code_offset;
1497                 break;
1498               }
1499               WriteInt32(p+(i+1), value);
1500               i = i + 5;
1501             }
1502             i++;
1503           }
1504         }
1505
1506     }
1507
1508     /*  ---- From here on, it's all reportage: construction is finished ---- */
1509
1510     if (debugfile_switch)
1511     {   begin_writing_debug_sections();
1512         write_debug_section("memory layout id", GLULX_HEADER_SIZE);
1513         write_debug_section("code area", Write_Code_At);
1514         write_debug_section("string decoding table", Write_Strings_At);
1515         write_debug_section("strings area",
1516                             Write_Strings_At + compression_table_size);
1517         write_debug_section("static array space", static_arrays_at);
1518         if (static_arrays_at + static_array_area_size < Write_RAM_At)
1519         {   write_debug_section
1520                 ("zero padding", static_arrays_at + static_array_area_size);
1521         }
1522         if (globals_at)
1523         {   compiler_error("Failed assumption that globals are at start of "
1524                            "Glulx RAM");
1525         }
1526         write_debug_section("global variables", Write_RAM_At + globals_at);
1527         write_debug_section("array space", Write_RAM_At + arrays_at);
1528         write_debug_section("abbreviations table", Write_RAM_At + abbrevs_at);
1529         write_debug_section("object tree", Write_RAM_At + object_tree_at);
1530         write_debug_section("common properties",
1531                             Write_RAM_At + object_props_at);
1532         write_debug_section("property defaults",
1533                             Write_RAM_At + prop_defaults_at);
1534         write_debug_section("class numbers",
1535                             Write_RAM_At + class_numbers_offset);
1536         write_debug_section("identifier names",
1537                             Write_RAM_At + identifier_names_offset);
1538         write_debug_section("grammar table", Write_RAM_At + grammar_table_at);
1539         write_debug_section("actions table", Write_RAM_At + actions_at);
1540         write_debug_section("dictionary", Write_RAM_At + dictionary_at);
1541         if (MEMORY_MAP_EXTENSION)
1542         {   write_debug_section("zero padding", Out_Size);
1543         }
1544         end_writing_debug_sections(Out_Size + MEMORY_MAP_EXTENSION);
1545     }
1546
1547     if (memory_map_setting)
1548     {
1549         int32 addr;
1550         {
1551 printf("        +---------------------+   000000\n");
1552 printf("Read-   |       header        |   %s\n",
1553     show_percentage(GLULX_HEADER_SIZE, Out_Size));
1554 printf(" only   +=====================+   %06lx\n", (long int) GLULX_HEADER_SIZE);
1555 printf("memory  |  memory layout id   |   %s\n",
1556     show_percentage(Write_Code_At-GLULX_HEADER_SIZE, Out_Size));
1557 printf("        +---------------------+   %06lx\n", (long int) Write_Code_At);
1558 printf("        |        code         |   %s\n",
1559     show_percentage(Write_Strings_At-Write_Code_At, Out_Size));
1560 printf("        +---------------------+   %06lx\n",
1561   (long int) Write_Strings_At);
1562 printf("        | string decode table |   %s\n",
1563     show_percentage(compression_table_size, Out_Size));
1564 printf("        + - - - - - - - - - - +   %06lx\n",
1565   (long int) Write_Strings_At + compression_table_size);
1566 addr = (static_array_area_size ? static_arrays_at : Write_RAM_At+globals_at);
1567 printf("        |       strings       |   %s\n",
1568     show_percentage(addr-(Write_Strings_At + compression_table_size), Out_Size));
1569             if (static_array_area_size)
1570             {
1571 printf("        +---------------------+   %06lx\n", 
1572   (long int) (static_arrays_at));
1573 printf("        |    static arrays    |   %s\n",
1574     show_percentage(Write_RAM_At+globals_at-static_arrays_at, Out_Size));
1575             }
1576 printf("        +=====================+   %06lx\n", 
1577   (long int) (Write_RAM_At+globals_at));
1578 printf("Dynamic |  global variables   |   %s\n",
1579     show_percentage(arrays_at-globals_at, Out_Size));
1580 printf("memory  + - - - - - - - - - - +   %06lx\n",
1581   (long int) (Write_RAM_At+arrays_at));
1582 printf("        |       arrays        |   %s\n",
1583     show_percentage(abbrevs_at-arrays_at, Out_Size));
1584 printf("        +---------------------+   %06lx\n",
1585   (long int) (Write_RAM_At+abbrevs_at));
1586 printf("        | printing variables  |   %s\n",
1587     show_percentage(object_tree_at-abbrevs_at, Out_Size));
1588 printf("        +---------------------+   %06lx\n", 
1589   (long int) (Write_RAM_At+object_tree_at));
1590 printf("        |       objects       |   %s\n",
1591     show_percentage(object_props_at-object_tree_at, Out_Size));
1592 printf("        + - - - - - - - - - - +   %06lx\n",
1593   (long int) (Write_RAM_At+object_props_at));
1594 printf("        |   property values   |   %s\n",
1595     show_percentage(prop_defaults_at-object_props_at, Out_Size));
1596 printf("        + - - - - - - - - - - +   %06lx\n",
1597   (long int) (Write_RAM_At+prop_defaults_at));
1598 printf("        |  property defaults  |   %s\n",
1599     show_percentage(class_numbers_offset-prop_defaults_at, Out_Size));
1600 printf("        + - - - - - - - - - - +   %06lx\n",
1601   (long int) (Write_RAM_At+class_numbers_offset));
1602 printf("        | class numbers table |   %s\n",
1603     show_percentage(identifier_names_offset-class_numbers_offset, Out_Size));
1604 printf("        + - - - - - - - - - - +   %06lx\n",
1605   (long int) (Write_RAM_At+identifier_names_offset));
1606 printf("        |   id names table    |   %s\n",
1607     show_percentage(grammar_table_at-identifier_names_offset, Out_Size));
1608 printf("        +---------------------+   %06lx\n",
1609   (long int) (Write_RAM_At+grammar_table_at));
1610 printf("        |    grammar table    |   %s\n",
1611     show_percentage(actions_at-grammar_table_at, Out_Size));
1612 printf("        + - - - - - - - - - - +   %06lx\n", 
1613   (long int) (Write_RAM_At+actions_at));
1614 printf("        |       actions       |   %s\n",
1615     show_percentage(dictionary_offset-(Write_RAM_At+actions_at), Out_Size));
1616 printf("        +---------------------+   %06lx\n", 
1617   (long int) dictionary_offset);
1618 printf("        |     dictionary      |   %s\n",
1619     show_percentage(Out_Size-dictionary_offset, Out_Size));
1620             if (MEMORY_MAP_EXTENSION == 0)
1621             {
1622 printf("        +---------------------+   %06lx\n", (long int) Out_Size);
1623             }
1624             else
1625             {
1626 printf("        +=====================+   %06lx\n", (long int) Out_Size);
1627 printf("Runtime |       (empty)       |\n");   /* no percentage */
1628 printf("  extn  +---------------------+   %06lx\n", (long int) Out_Size+MEMORY_MAP_EXTENSION);
1629             }
1630
1631         }
1632
1633     }
1634 }
1635
1636 static void display_frequencies()
1637 {
1638     int i, j;
1639     
1640     printf("How frequently abbreviations were used, and roughly\n");
1641     printf("how many bytes they saved:  ('_' denotes spaces)\n");
1642     
1643     for (i=0; i<no_abbreviations; i++) {
1644         int32 saving;
1645         char *astr;
1646         if (!glulx_mode)
1647             saving = 2*((abbreviations[i].freq-1)*abbreviations[i].quality)/3;
1648         else
1649             saving = (abbreviations[i].freq-1)*abbreviations[i].quality;
1650
1651         astr = abbreviation_text(i);
1652         /* Print the abbreviation text, left-padded to ten spaces, with
1653            spaces replaced by underscores. */
1654         for (j=strlen(astr); j<10; j++) {
1655             putchar(' ');
1656         }
1657         for (j=0; astr[j]; j++) {
1658             putchar(astr[j] == ' ' ? '_' : astr[j]);
1659         }
1660         
1661         printf(" %5d/%5d   ", abbreviations[i].freq, saving);
1662         
1663         if ((i%3)==2) printf("\n");
1664     }
1665     if ((i%3)!=0) printf("\n");
1666     
1667     if (no_abbreviations==0) printf("None were declared.\n");
1668 }
1669
1670 static void display_statistics_z()
1671 {
1672     int32 k_long, rate;
1673     char *k_str = "";
1674     uchar *p = (uchar *) zmachine_paged_memory;
1675     char *output_called = "story file";
1676     int limit = 0;
1677
1678     /* Yeah, we're repeating this calculation from construct_storyfile_z() */
1679     switch(version_number)
1680     {   case 3: limit = 128; break;
1681         case 4:
1682         case 5: limit = 256; break;
1683         case 6:
1684         case 7:
1685         case 8: limit = 512; break;
1686     }
1687
1688     k_long=(Out_Size/1024);
1689     if ((Out_Size-1024*k_long) >= 512) { k_long++; k_str=""; }
1690     else if ((Out_Size-1024*k_long) > 0) { k_str=".5"; }
1691     if (total_bytes_trans == 0) rate = 0;
1692     else rate=total_bytes_trans*1000/total_chars_trans;
1693     
1694     {   printf("In:\
1695 %3d source code files            %6d syntactic lines\n\
1696 %6d textual lines              %8ld characters ",
1697                total_input_files, no_syntax_lines,
1698                total_source_line_count, (long int) total_chars_read);
1699         if (character_set_unicode) printf("(UTF-8)\n");
1700         else if (character_set_setting == 0) printf("(plain ASCII)\n");
1701         else
1702             {   printf("(ISO 8859-%d %s)\n", character_set_setting,
1703                        name_of_iso_set(character_set_setting));
1704             }
1705
1706         printf("Allocated:\n\
1707 %6d symbols                    %8ld bytes of memory\n\
1708 Out:   Version %d \"%s\" %s %d.%c%c%c%c%c%c (%ld%sK long):\n",
1709                no_symbols,
1710                (long int) malloced_bytes,
1711                version_number,
1712                version_name(version_number),
1713                output_called,
1714                release_number, p[18], p[19], p[20], p[21], p[22], p[23],
1715                (long int) k_long, k_str);
1716
1717         printf("\
1718 %6d classes                      %6d objects\n\
1719 %6d global vars (maximum 233)    %6d variable/array space\n",
1720                no_classes,
1721                no_objects,
1722                no_globals,
1723                dynamic_array_area_size);
1724
1725         printf(
1726                "%6d verbs                        %6d dictionary entries\n\
1727 %6d grammar lines (version %d)    %6d grammar tokens (unlimited)\n\
1728 %6d actions                      %6d attributes (maximum %2d)\n\
1729 %6d common props (maximum %2d)    %6d individual props (unlimited)\n",
1730                no_Inform_verbs,
1731                dict_entries,
1732                no_grammar_lines, grammar_version_number,
1733                no_grammar_tokens,
1734                no_actions,
1735                no_attributes, ((version_number==3)?32:48),
1736                no_properties-3, ((version_number==3)?29:61),
1737                no_individual_properties - 64);
1738
1739         if (track_unused_routines)
1740             {
1741                 uint32 diff = df_total_size_before_stripping - df_total_size_after_stripping;
1742                 printf(
1743                        "%6ld bytes of Z-code              %6ld unused bytes %s (%.1f%%)\n",
1744                        (long int) df_total_size_before_stripping, (long int) diff,
1745                        (OMIT_UNUSED_ROUTINES ? "stripped out" : "detected"),
1746                        100 * (float)diff / (float)df_total_size_before_stripping);
1747             }
1748
1749         printf(
1750                "%6ld characters used in text      %6ld bytes compressed (rate %d.%3ld)\n\
1751 %6d abbreviations (maximum %d)   %6d routines (unlimited)\n\
1752 %6ld instructions of Z-code       %6d sequence points\n\
1753 %6ld bytes readable memory used (maximum 65536)\n\
1754 %6ld bytes used in Z-machine      %6ld bytes free in Z-machine\n",
1755                (long int) total_chars_trans,
1756                (long int) total_bytes_trans,
1757                (total_chars_trans>total_bytes_trans)?0:1,
1758                (long int) rate,
1759                no_abbreviations, MAX_ABBREVS,
1760                no_routines,
1761                (long int) no_instructions, no_sequence_points,
1762                (long int) Write_Code_At,
1763                (long int) Out_Size,
1764                (long int)
1765                (((long int) (limit*1024L)) - ((long int) Out_Size)));
1766
1767     }
1768 }
1769
1770 static void display_statistics_g()
1771 {
1772     int32 k_long, rate;
1773     char *k_str = "";
1774     int32 limit = 1024*1024;
1775     int32 strings_length = compression_table_size + compression_string_size;
1776     char *output_called = "story file";
1777     
1778     k_long=(Out_Size/1024);
1779     if ((Out_Size-1024*k_long) >= 512) { k_long++; k_str=""; }
1780     else if ((Out_Size-1024*k_long) > 0) { k_str=".5"; }
1781     
1782     if (strings_length == 0) rate = 0;
1783     else rate=strings_length*1000/total_chars_trans;
1784
1785     {   printf("In:\
1786 %3d source code files            %6d syntactic lines\n\
1787 %6d textual lines              %8ld characters ",
1788                total_input_files, no_syntax_lines,
1789                total_source_line_count, (long int) total_chars_read);
1790         if (character_set_unicode) printf("(UTF-8)\n");
1791         else if (character_set_setting == 0) printf("(plain ASCII)\n");
1792         else
1793             {   printf("(ISO 8859-%d %s)\n", character_set_setting,
1794                        name_of_iso_set(character_set_setting));
1795             }
1796
1797         {char serialnum[8];
1798             write_serial_number(serialnum);
1799             printf("Allocated:\n\
1800 %6d symbols                    %8ld bytes of memory\n\
1801 Out:   %s %s %d.%c%c%c%c%c%c (%ld%sK long):\n",
1802                    no_symbols,
1803                    (long int) malloced_bytes,
1804                    version_name(version_number),
1805                    output_called,
1806                    release_number,
1807                    serialnum[0], serialnum[1], serialnum[2],
1808                    serialnum[3], serialnum[4], serialnum[5],
1809                    (long int) k_long, k_str);
1810         } 
1811
1812         printf("\
1813 %6d classes                      %6d objects\n\
1814 %6d global vars                  %6d variable/array space\n",
1815                no_classes,
1816                no_objects,
1817                no_globals,
1818                dynamic_array_area_size);
1819
1820         printf(
1821                "%6d verbs                        %6d dictionary entries\n\
1822 %6d grammar lines (version %d)    %6d grammar tokens (unlimited)\n\
1823 %6d actions                      %6d attributes (maximum %2d)\n\
1824 %6d common props (maximum %3d)   %6d individual props (unlimited)\n",
1825                no_Inform_verbs,
1826                dict_entries,
1827                no_grammar_lines, grammar_version_number,
1828                no_grammar_tokens,
1829                no_actions,
1830                no_attributes, NUM_ATTR_BYTES*8,
1831                no_properties-3, INDIV_PROP_START-3,
1832                no_individual_properties - INDIV_PROP_START);
1833
1834         if (track_unused_routines)
1835             {
1836                 uint32 diff = df_total_size_before_stripping - df_total_size_after_stripping;
1837                 printf(
1838                        "%6ld bytes of code                %6ld unused bytes %s (%.1f%%)\n",
1839                        (long int) df_total_size_before_stripping, (long int) diff,
1840                        (OMIT_UNUSED_ROUTINES ? "stripped out" : "detected"),
1841                        100 * (float)diff / (float)df_total_size_before_stripping);
1842             }
1843
1844         printf(
1845                "%6ld characters used in text      %6ld bytes compressed (rate %d.%3ld)\n\
1846 %6d abbreviations (maximum %d)   %6d routines (unlimited)\n\
1847 %6ld instructions of code         %6d sequence points\n\
1848 %6ld bytes writable memory used   %6ld bytes read-only memory used\n\
1849 %6ld bytes used in machine    %10ld bytes free in machine\n",
1850                (long int) total_chars_trans,
1851                (long int) strings_length,
1852                (total_chars_trans>strings_length)?0:1,
1853                (long int) rate,
1854                no_abbreviations, MAX_ABBREVS,
1855                no_routines,
1856                (long int) no_instructions, no_sequence_points,
1857                (long int) (Out_Size - Write_RAM_At),
1858                (long int) Write_RAM_At,
1859                (long int) Out_Size,
1860                (long int)
1861                (((long int) (limit*1024L)) - ((long int) Out_Size)));
1862
1863     }
1864 }
1865
1866
1867 extern void construct_storyfile(void)
1868 {
1869     if (!glulx_mode)
1870         construct_storyfile_z();
1871     else
1872         construct_storyfile_g();
1873
1874     /* Display all the trace/stats info that came out of compilation.
1875
1876        (Except for the memory map, which uses a bunch of local variables
1877        from construct_storyfile_z/g(), so it's easier to do that inside
1878        that function.)
1879     */
1880     
1881     if (frequencies_setting)
1882         display_frequencies();
1883
1884     if (list_symbols_setting)
1885         list_symbols(list_symbols_setting);
1886     
1887     if (list_dict_setting)
1888         show_dictionary(list_dict_setting);
1889     
1890     if (list_verbs_setting)
1891         list_verb_table();
1892
1893     if (list_objects_setting)
1894         list_object_tree();
1895     
1896     if (statistics_switch) {
1897         if (!glulx_mode)
1898             display_statistics_z();
1899         else
1900             display_statistics_g();
1901     }
1902 }
1903
1904 /* ========================================================================= */
1905 /*   Data structure management routines                                      */
1906 /* ------------------------------------------------------------------------- */
1907
1908 extern void init_tables_vars(void)
1909 {
1910     release_number = 1;
1911     statusline_flag = SCORE_STYLE;
1912
1913     zmachine_paged_memory = NULL;
1914
1915     if (!glulx_mode) {
1916       code_offset = 0x800;
1917       actions_offset = 0x800;
1918       preactions_offset = 0x800;
1919       dictionary_offset = 0x800;
1920       adjectives_offset = 0x800;
1921       variables_offset = 0;
1922       strings_offset = 0xc00;
1923       individuals_offset=0x800;
1924       identifier_names_offset=0x800;
1925       class_numbers_offset = 0x800;
1926       arrays_offset = 0x0800; /* only used in Glulx, but might as well set */
1927       static_arrays_offset = 0x0800;
1928     }
1929     else {
1930       code_offset = 0x12345;
1931       actions_offset = 0x12345;
1932       preactions_offset = 0x12345;
1933       dictionary_offset = 0x12345;
1934       adjectives_offset = 0x12345;
1935       variables_offset = 0x12345;
1936       arrays_offset = 0x12345;
1937       strings_offset = 0x12345;
1938       individuals_offset=0x12345;
1939       identifier_names_offset=0x12345;
1940       class_numbers_offset = 0x12345;
1941       static_arrays_offset = 0x12345;
1942     }
1943 }
1944
1945 extern void tables_begin_pass(void)
1946 {
1947 }
1948
1949 extern void tables_allocate_arrays(void)
1950 {
1951 }
1952
1953 extern void tables_free_arrays(void)
1954 {
1955     /*  Allocation for this array happens in construct_storyfile() above     */
1956
1957     my_free(&zmachine_paged_memory,"output buffer");
1958 }
1959
1960 /* ========================================================================= */