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