3c53096c05956f084497ed8d8d020459a1ff91eb
[inform.git] / src / asm.c
1 /* ------------------------------------------------------------------------- */
2 /*   "asm" : The Inform assembler                                            */
3 /*                                                                           */
4 /*   Part of Inform 6.40                                                     */
5 /*   copyright (c) Graham Nelson 1993 - 2022                                 */
6 /*                                                                           */
7 /* Inform is free software: you can redistribute it and/or modify            */
8 /* it under the terms of the GNU General Public License as published by      */
9 /* the Free Software Foundation, either version 3 of the License, or         */
10 /* (at your option) any later version.                                       */
11 /*                                                                           */
12 /* Inform is distributed in the hope that it will be useful,                 */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
15 /* GNU General Public License for more details.                              */
16 /*                                                                           */
17 /* You should have received a copy of the GNU General Public License         */
18 /* along with Inform. If not, see https://gnu.org/licenses/                  */
19 /*                                                                           */
20 /* ------------------------------------------------------------------------- */
21
22 #include "header.h"
23
24 static uchar *zcode_holding_area;  /* Area holding code yet to be transferred
25                                       to either zcode_area or temp file no 1 */
26 static memory_list zcode_holding_area_memlist;
27 static uchar *zcode_markers;       /* Bytes holding marker values for this
28                                       code                                   */
29 static memory_list zcode_markers_memlist;
30 static int zcode_ha_size;          /* Number of bytes in holding area        */
31
32 uchar *zcode_area;                 /* Array to hold assembled code           */
33
34 memory_list zcode_area_memlist;    /* Manages zcode_area                     */
35
36 int32 zmachine_pc;                 /* PC position of assembly (byte offset
37                                       from start of Z-code area)             */
38
39 int32 no_instructions;             /* Number of instructions assembled       */
40 int execution_never_reaches_here;  /* nonzero if the current PC value in the
41                                       code area cannot be reached: e.g. if
42                                       the previous instruction was a "quit"
43                                       opcode and no label is set to here
44                                       (see EXECSTATE flags for more) */
45 int next_label,                    /* Used to count the labels created all
46                                       over Inform in current routine, from 0 */
47     next_sequence_point;           /* Likewise, for sequence points          */
48 int no_sequence_points;            /* Total over all routines; kept for
49                                       statistics purposes only               */
50
51 static int label_moved_error_already_given;
52                                    /* When one label has moved, all subsequent
53                                       ones probably have too, and this flag
54                                       suppresses the runaway chain of error
55                                       messages which would otherwise result  */
56
57 int  sequence_point_follows;       /* Will the next instruction assembled    */
58                                    /* be at a sequence point in the routine? */
59
60 int uses_unicode_features;         /* Makes use of Glulx Unicode (3.0)
61                                       features?                              */
62 int uses_memheap_features;         /* Makes use of Glulx mem/heap (3.1)
63                                       features?                              */
64 int uses_acceleration_features;    /* Makes use of Glulx acceleration (3.1.1)
65                                       features?                              */
66 int uses_float_features;           /* Makes use of Glulx floating-point (3.1.2)
67                                       features?                              */
68 int uses_extundo_features;         /* Makes use of Glulx extended undo (3.1.3)
69                                       features?                              */
70
71 debug_location statement_debug_location;
72                                    /* Location of current statement          */
73
74
75 variableinfo *variables;           /* The allocated size is 
76                                       (MAX_LOCAL_VARIABLES + no_globals).
77                                       Local variables first, then globals.   */
78 memory_list variables_memlist;
79
80 assembly_instruction AI;           /* A structure used to hold the full
81                                       specification of a single Z-code
82                                       instruction: effectively this is the
83                                       input to the routine
84                                       assemble_instruction()                 */
85
86 static char opcode_syntax_string[128];  /*  Text buffer holding the correct
87                                       syntax for an opcode: used to produce
88                                       helpful assembler error messages       */
89
90 static int routine_symbol;         /* The symbol index of the routine currently
91                                       being compiled */
92 static memory_list current_routine_name; /* The name of the routine currently
93                                       being compiled. (This may be longer
94                                       than MAX_IDENTIFIER_LENGTH, e.g. for
95                                       an "obj.prop" property routine.)       */
96 static int routine_locals;         /* The number of local variables used by
97                                       the routine currently being compiled   */
98
99 static int32 routine_start_pc;
100
101 int32 *named_routine_symbols;      /* Allocated up to no_named_routines      */
102 static memory_list named_routine_symbols_memlist;
103
104 static void transfer_routine_z(void);
105 static void transfer_routine_g(void);
106
107 /* ------------------------------------------------------------------------- */
108 /*   Label data                                                              */
109 /* ------------------------------------------------------------------------- */
110
111 static labelinfo *labels; /* Label offsets  (i.e. zmachine_pc values).
112                              These are allocated sequentially, but accessed
113                              as a double-linked list from first_label
114                              to last_label (in PC order). */
115 static memory_list labels_memlist;
116 static int first_label, last_label;
117
118 static int *labeluse;     /* Flags indicating whether a given label has been
119                              used as a branch target yet. */
120 static memory_list labeluse_memlist;
121 static int labeluse_size; /* Entries up to here are initialized */
122
123 static sequencepointinfo *sequence_points; /* Allocated to next_sequence_point.
124                                               Only used when debugfile_switch
125                                               is set.                        */
126 static memory_list sequence_points_memlist;
127
128 /* ------------------------------------------------------------------------- */
129 /*   Label management                                                        */
130 /* ------------------------------------------------------------------------- */
131
132 /* The stripping of unreachable code requires a bit of explanation.
133
134    As we compile a function, we update the execution_never_reaches_here
135    flag to reflect whether the current line is reachable. If the flag
136    is set (EXECSTATE_UNREACHABLE), we skip generating opcodes,
137    compiling strings, and so on. (See assemblez_instruction(),
138    assembleg_instruction(), and compile_string() for these checks.)
139
140    If we're *between* functions, the execution_never_reaches_here flag
141    is always clear (EXECSTATE_REACHABLE), so global strings are
142    compiled correctly.
143
144    In general, every time we compile a JUMP or RETURN opcode, the flag
145    gets set. Every time we compile a label, the flag gets cleared.
146    This makes sense if you consider a common "while" loop:
147
148      while (true) {
149        ...
150        if (flag) break;
151        ...
152      }
153      ...
154
155    This is compiled as:
156
157      .TopLabel;
158      ...
159      @jnz flag ?ExitLabel;
160      ...
161      @jump TopLabel;
162      .ExitLabel;
163      ...
164    
165    Code after an unconditional JUMP is obviously unreachable. But the
166    next thing that happens is the .ExitLabel, which is the target of a
167    branch, so the next line is reachable again.
168
169    However, if the unreachable flag is set when we *begin* a statement
170    (or braced block of statements), we can get tougher. We set the
171    EXECSTATE_ENTIRE flag for the entire duration of the statement or
172    block. This flag cannot be cleared by compiling labels. An example
173    of this:
174
175      if (DOSTUFF) {
176        while (true) {
177          if (flag) break;
178        }
179      }
180
181    If the DOSTUFF constant is false, the entire "while" loop is definitely
182    unreachable. So we should skip .TopLabel, .ExitLabel, and everything
183    in between. To ensure this, we set EXECSTATE_ENTIRE upon entering the
184    "if {...}" braced block, and reset it upon leaving.
185
186    (See parse_code_block() and parse_statement() for the (slightly fugly)
187    bit-fidding that accomplishes this.)
188
189    As an added optimization, some labels are known to be "forward"; they
190    are only reached by forward jumps. (.ExitLabel above is an example.)
191    If we reach a forward label and nothing has in fact jumped there,
192    the label is dead and we can skip it. (And thus also skip clearing
193    the unreachable flag!)
194
195    To understand *that*, consider a "while true" loop with no "break":
196
197      while (true) {
198        ...
199        if (flag) return;
200        ...
201      }
202
203    This never branches to .ExitLabel. So when we reach .ExitLabel,
204    we can say for sure that *nothing* branches there. So we skip
205    compiling that label. The unreachable flag is left set (because we
206    just finished the jump to .TopLabel). Thus, any code following the
207    entire loop is known to be unreachable, and we can righteously
208    complain about it.
209
210    (In contrast, .TopLabel cannot be skipped because it might be the
211    target of a *backwards* branch later on. In fact there might be
212    several -- any "continue" in the loop will jump to .TopLabel.)
213 */
214
215 /* Set the position of the given label. The offset will be the current
216    zmachine_pc, or -1 if the label is definitely unused.
217
218    This adds the label to a linked list (via first_label, last_label).
219
220    The linked list must be in increasing PC order. We know this will
221    be true because we call this as we run through the function, so
222    zmachine_pc always increases.
223 */
224 static void set_label_offset(int label, int32 offset)
225 {
226     ensure_memory_list_available(&labels_memlist, label+1);
227
228     labels[label].offset = offset;
229     labels[label].symbol = -1;
230     if (offset < 0) {
231         /* Mark this label as invalid and don't put it in the linked list. */
232         labels[label].prev = -1;
233         labels[label].next = -1;
234         return;
235     }
236     
237     if (last_label == -1)
238     {   labels[label].prev = -1;
239         first_label = label;
240     }
241     else
242     {   labels[label].prev = last_label;
243         labels[last_label].next = label;
244     }
245     last_label = label;
246     labels[label].next = -1;
247 }
248
249 /* Set a flag indicating that the given label has been jumped to. */
250 static void mark_label_used(int label)
251 {
252     if (label < 0)
253         return;
254
255     /* Entries from 0 to labeluse_size have meaningful values.
256        If we have to increase labeluse_size, initialize the new
257        entries to FALSE. */
258     ensure_memory_list_available(&labeluse_memlist, label+1);
259     for (; labeluse_size < label+1; labeluse_size++) {
260         labeluse[labeluse_size] = FALSE;
261     }
262     labeluse[label] = TRUE;
263 }
264
265 /* ------------------------------------------------------------------------- */
266 /*   Useful tool for building operands                                       */
267 /* ------------------------------------------------------------------------- */
268
269 extern void set_constant_ot(assembly_operand *AO)
270 {
271   if (!glulx_mode) {
272     if (AO->value >= 0 && AO->value <= 255)
273       AO->type = SHORT_CONSTANT_OT;
274     else
275       AO->type = LONG_CONSTANT_OT;
276   }
277   else {
278     if (AO->value == 0)
279       AO->type = ZEROCONSTANT_OT;
280     else if (AO->value >= -0x80 && AO->value < 0x80)
281       AO->type = BYTECONSTANT_OT;
282     else if (AO->value >= -0x8000 && AO->value < 0x8000) 
283       AO->type = HALFCONSTANT_OT;
284     else
285       AO->type = CONSTANT_OT;
286   }
287 }
288
289 extern int is_constant_ot(int otval)
290 {
291   if (!glulx_mode) {
292     return ((otval == LONG_CONSTANT_OT) 
293       || (otval == SHORT_CONSTANT_OT));
294   }
295   else {
296     return ((otval == CONSTANT_OT)
297       || (otval == HALFCONSTANT_OT)
298       || (otval == BYTECONSTANT_OT)
299       || (otval == ZEROCONSTANT_OT));
300   }
301 }
302
303 extern int is_variable_ot(int otval)
304 {
305   if (!glulx_mode) {
306     return (otval == VARIABLE_OT);
307   }
308   else {
309     return ((otval == LOCALVAR_OT)
310       || (otval == GLOBALVAR_OT));
311   }
312 }
313
314 /* ------------------------------------------------------------------------- */
315 /*   Used in printing assembly traces                                        */
316 /* ------------------------------------------------------------------------- */
317
318 extern char *variable_name(int32 i)
319 {
320     if (i==0) return("sp");
321     if (i<MAX_LOCAL_VARIABLES) return local_variable_names[i-1].text;
322
323     if (!glulx_mode) {
324       if (i==255) return("TEMP1");
325       if (i==254) return("TEMP2");
326       if (i==253) return("TEMP3");
327       if (i==252) return("TEMP4");
328       if (i==251) return("self");
329       if (i==250) return("sender");
330       if (i==249) return("sw__var");
331       if (i >= 256 && i < 286)
332       {   if (i - 256 < NUMBER_SYSTEM_FUNCTIONS) return system_functions.keywords[i - 256];
333           return "<unnamed system function>";
334       }
335     }
336     else {
337       switch (i - MAX_LOCAL_VARIABLES) {
338       case 0: return "temp_global";
339       case 1: return "temp__global2";
340       case 2: return "temp__global3";
341       case 3: return "temp__global4";
342       case 4: return "self";
343       case 5: return "sender";
344       case 6: return "sw__var";
345       case 7: return "sys__glob0";
346       case 8: return "sys__glob1";
347       case 9: return "sys__glob2";
348       case 10: return "sys_statusline_flag";
349       }
350     }
351
352     return (symbols[variables[i].token].name);
353 }
354
355 /* Print symbolic information about the AO, if there is any. */
356 static void print_operand_annotation(const assembly_operand *o)
357 {
358     int any = FALSE;
359     if (o->marker) {
360         printf((!any) ? " (" : ": ");
361         any = TRUE;
362         printf("%s", describe_mv(o->marker));
363         switch (o->marker) {
364         case VROUTINE_MV:
365             printf(": %s", veneer_routine_name(o->value));
366             break;
367         case INCON_MV:
368             printf(": %s", name_of_system_constant(o->value));
369             break;
370         case DWORD_MV:
371             printf(": '");
372             print_dict_word(o->value);
373             printf("'");
374             break;
375         }
376     }
377     if (o->symindex >= 0 && o->symindex < no_symbols) {
378         printf((!any) ? " (" : ": ");
379         any = TRUE;
380         printf("%s", symbols[o->symindex].name);
381     }
382     if (any) printf(")");       
383 }
384
385 static void print_operand_z(const assembly_operand *o, int annotate)
386 {   switch(o->type)
387     {   case EXPRESSION_OT: printf("expr_"); break;
388         case LONG_CONSTANT_OT: printf("long_"); break;
389         case SHORT_CONSTANT_OT: printf("short_"); break;
390         case VARIABLE_OT:
391              if (o->value==0) { printf("sp"); return; }
392              printf("%s", variable_name(o->value)); return;
393         case OMITTED_OT: printf("<no value>"); return;
394     }
395     printf("%d", o->value);
396     if (annotate)
397         print_operand_annotation(o);
398 }
399
400 static void print_operand_g(const assembly_operand *o, int annotate)
401 {
402   switch (o->type) {
403   case EXPRESSION_OT: printf("expr_"); break;
404   case CONSTANT_OT: printf("long_"); break;
405   case HALFCONSTANT_OT: printf("short_"); break;
406   case BYTECONSTANT_OT: printf("byte_"); break;
407   case ZEROCONSTANT_OT: printf("zero_"); return;
408   case DEREFERENCE_OT: printf("*"); break;
409   case GLOBALVAR_OT: 
410     printf("global_%d (%s)", o->value, variable_name(o->value)); 
411     return;
412   case LOCALVAR_OT: 
413     if (o->value == 0)
414       printf("stackptr"); 
415     else
416       printf("local_%d (%s)", o->value-1, variable_name(o->value)); 
417     return;
418   case SYSFUN_OT:
419     if (o->value >= 0 && o->value < NUMBER_SYSTEM_FUNCTIONS)
420       printf("%s", system_functions.keywords[o->value]);
421     else
422       printf("<unnamed system function>");
423     return;
424   case OMITTED_OT: printf("<no value>"); return;
425   default: printf("???_"); break; 
426   }
427   printf("%d", o->value);
428   if (annotate)
429     print_operand_annotation(o);
430 }
431
432 extern void print_operand(const assembly_operand *o, int annotate)
433 {
434   if (!glulx_mode)
435     print_operand_z(o, annotate);
436   else
437     print_operand_g(o, annotate);
438 }
439
440 /* ------------------------------------------------------------------------- */
441 /*   Writing bytes to the code area                                          */
442 /* ------------------------------------------------------------------------- */
443
444 static void byteout(int32 i, int mv)
445 {
446     ensure_memory_list_available(&zcode_markers_memlist, zcode_ha_size+1);
447     ensure_memory_list_available(&zcode_holding_area_memlist, zcode_ha_size+1);
448     zcode_markers[zcode_ha_size] = (uchar) mv;
449     zcode_holding_area[zcode_ha_size++] = (uchar) i;
450     zmachine_pc++;
451 }
452
453 /* ------------------------------------------------------------------------- */
454 /*   A database of the 115 canonical Infocom opcodes in Versions 3 to 6      */
455 /*   And of the however-many-there-are Glulx opcodes                         */
456 /* ------------------------------------------------------------------------- */
457
458 typedef struct opcodez
459 {   uchar *name;      /* Lower case standard name */
460     int version1;     /* Valid from this version number... */
461     int version2;     /* ...until this one (or forever if this is 0) */
462     int extension;    /* In later versions, see this line in extension table:
463                          if -1, the opcode is illegal in later versions */
464     int code;         /* Opcode number within its operand-number block */
465     int flags;        /* Flags (see below) */
466     int op_rules;     /* Any unusual operand rule applying (see below) */
467     int flags2_set;   /* If not zero, set this bit in Flags 2 in the header
468                          of any game using the opcode */
469     int no;           /* Number of operands (see below) */
470 } opcodez;
471
472 typedef struct opcodeg
473 {   uchar *name;      /* Lower case standard name */
474     int32 code;       /* Opcode number */
475     int flags;        /* Flags (see below) */
476     int op_rules;     /* Any unusual operand rule applying (see below) */
477     int no;           /* Number of operands */
478 } opcodeg;
479
480     /* Flags which can be set */
481
482 #define St      1     /* Store */
483 #define Br      2     /* Branch */
484 #define Rf      4     /* "Return flag": execution never continues after this
485                          opcode (e.g., is a return or unconditional jump) */
486 #define St2 8     /* Store2 (second-to-last operand is store (Glulx)) */
487
488     /* Codes for any unusual operand assembly rules */
489
490     /* Z-code: */
491
492 #define VARIAB   1    /* First operand expected to be a variable name and
493                          assembled to a short constant: the variable number */
494 #define TEXT     2    /* One text operand, to be Z-encoded into the program */
495 #define LABEL    3    /* One operand, a label, given as long constant offset */
496 #define CALL     4    /* First operand is name of a routine, to be assembled
497                          as long constant (the routine's packed address):
498                          as if the name were prefixed by #r$ */
499
500     /* Glulx: (bit flags for Glulx VM features) */
501
502 #define GOP_Unicode      1   /* uses_unicode_features */
503 #define GOP_MemHeap      2   /* uses_memheap_features */
504 #define GOP_Acceleration 4   /* uses_acceleration_features */
505 #define GOP_Float        8   /* uses_float_features */
506 #define GOP_ExtUndo     16   /* uses_extundo_features */
507
508     /* Codes for the number of operands */
509
510 #define TWO      1    /* 2 (with certain types of operand, compiled as VAR) */
511 #define VAR      2    /* 0 to 4 */
512 #define VAR_LONG 3    /* 0 to 8 */
513 #define ONE      4    /* 1 */
514 #define ZERO     5    /* 0 */
515 #define EXT      6    /* Extended opcode set VAR: 0 to 4 */
516 #define EXT_LONG 7    /* Extended: 0 to 8 (not used by the canonical opcodes) */
517
518 static opcodez opcodes_table_z[] =
519 {
520     /* Opcodes introduced in Version 3 */
521
522 /* 0 */ { (uchar *) "je",              3, 0, -1, 0x01,     Br,      0, 0, TWO },
523 /* 1 */ { (uchar *) "jl",              3, 0, -1, 0x02,     Br,      0, 0, TWO },
524 /* 2 */ { (uchar *) "jg",              3, 0, -1, 0x03,     Br,      0, 0, TWO },
525 /* 3 */ { (uchar *) "dec_chk",         3, 0, -1, 0x04,     Br, VARIAB, 0, TWO },
526 /* 4 */ { (uchar *) "inc_chk",         3, 0, -1, 0x05,     Br, VARIAB, 0, TWO },
527 /* 5 */ { (uchar *) "jin",             3, 0, -1, 0x06,     Br,      0, 0, TWO },
528 /* 6 */ { (uchar *) "test",            3, 0, -1, 0x07,     Br,      0, 0, TWO },
529 /* 7 */ { (uchar *) "or",              3, 0, -1, 0x08,     St,      0, 0, TWO },
530 /* 8 */ { (uchar *) "and",             3, 0, -1, 0x09,     St,      0, 0, TWO },
531 /* 9 */ { (uchar *) "test_attr",       3, 0, -1, 0x0A,     Br,      0, 0, TWO },
532 /* 10 */ {(uchar *) "set_attr",        3, 0, -1, 0x0B,      0,      0, 0, TWO },
533 /* 11 */ {(uchar *) "clear_attr",      3, 0, -1, 0x0C,      0,      0, 0, TWO },
534 /* 12 */ {(uchar *) "store",           3, 0, -1, 0x0D,      0, VARIAB, 0, TWO },
535 /* 13 */ {(uchar *) "insert_obj",      3, 0, -1, 0x0E,      0,      0, 0, TWO },
536 /* 14 */ {(uchar *) "loadw",           3, 0, -1, 0x0F,     St,      0, 0, TWO },
537 /* 15 */ {(uchar *) "loadb",           3, 0, -1, 0x10,     St,      0, 0, TWO },
538 /* 16 */ {(uchar *) "get_prop",        3, 0, -1, 0x11,     St,      0, 0, TWO },
539 /* 17 */ {(uchar *) "get_prop_addr",   3, 0, -1, 0x12,     St,      0, 0, TWO },
540 /* 18 */ {(uchar *) "get_next_prop",   3, 0, -1, 0x13,     St,      0, 0, TWO },
541 /* 19 */ {(uchar *) "add",             3, 0, -1, 0x14,     St,      0, 0, TWO },
542 /* 20 */ {(uchar *) "sub",             3, 0, -1, 0x15,     St,      0, 0, TWO },
543 /* 21 */ {(uchar *) "mul",             3, 0, -1, 0x16,     St,      0, 0, TWO },
544 /* 22 */ {(uchar *) "div",             3, 0, -1, 0x17,     St,      0, 0, TWO },
545 /* 23 */ {(uchar *) "mod",             3, 0, -1, 0x18,     St,      0, 0, TWO },
546 /* 24 */ {(uchar *) "call",            3, 0, -1, 0x20,     St,   CALL, 0, VAR },
547 /* 25 */ {(uchar *) "storew",          3, 0, -1, 0x21,      0,      0, 0, VAR },
548 /* 26 */ {(uchar *) "storeb",          3, 0, -1, 0x22,      0,      0, 0, VAR },
549 /* 27 */ {(uchar *) "put_prop",        3, 0, -1, 0x23,      0,      0, 0, VAR },
550             /* This is the version of "read" called "sread" internally: */
551 /* 28 */ {(uchar *) "read",            3, 0, -1, 0x24,      0,      0, 0, VAR },
552 /* 29 */ {(uchar *) "print_char",      3, 0, -1, 0x25,      0,      0, 0, VAR },
553 /* 30 */ {(uchar *) "print_num",       3, 0, -1, 0x26,      0,      0, 0, VAR },
554 /* 31 */ {(uchar *) "random",          3, 0, -1, 0x27,     St,      0, 0, VAR },
555 /* 32 */ {(uchar *) "push",            3, 0, -1, 0x28,      0,      0, 0, VAR },
556 /* 33 */ {(uchar *) "pull",            3, 5,  6, 0x29,      0, VARIAB, 0, VAR },
557 /* 34 */ {(uchar *) "split_window",    3, 0, -1, 0x2A,      0,      0, 0, VAR },
558 /* 35 */ {(uchar *) "set_window",      3, 0, -1, 0x2B,      0,      0, 0, VAR },
559 /* 36 */ {(uchar *) "output_stream",   3, 0, -1, 0x33,      0,      0, 0, VAR },
560 /* 37 */ {(uchar *) "input_stream",    3, 0, -1, 0x34,      0,      0, 0, VAR },
561 /* 38 */ {(uchar *) "sound_effect",    3, 0, -1, 0x35,      0,      0, 7, VAR },
562 /* 39 */ {(uchar *) "jz",              3, 0, -1, 0x00,     Br,      0, 0, ONE },
563 /* 40 */ {(uchar *) "get_sibling",     3, 0, -1, 0x01,  St+Br,      0, 0, ONE },
564 /* 41 */ {(uchar *) "get_child",       3, 0, -1, 0x02,  St+Br,      0, 0, ONE },
565 /* 42 */ {(uchar *) "get_parent",      3, 0, -1, 0x03,     St,      0, 0, ONE },
566 /* 43 */ {(uchar *) "get_prop_len",    3, 0, -1, 0x04,     St,      0, 0, ONE },
567 /* 44 */ {(uchar *) "inc",             3, 0, -1, 0x05,      0, VARIAB, 0, ONE },
568 /* 45 */ {(uchar *) "dec",             3, 0, -1, 0x06,      0, VARIAB, 0, ONE },
569 /* 46 */ {(uchar *) "print_addr",      3, 0, -1, 0x07,      0,      0, 0, ONE },
570 /* 47 */ {(uchar *) "remove_obj",      3, 0, -1, 0x09,      0,      0, 0, ONE },
571 /* 48 */ {(uchar *) "print_obj",       3, 0, -1, 0x0A,      0,      0, 0, ONE },
572 /* 49 */ {(uchar *) "ret",             3, 0, -1, 0x0B,     Rf,      0, 0, ONE },
573 /* 50 */ {(uchar *) "jump",            3, 0, -1, 0x0C,     Rf,  LABEL, 0, ONE },
574 /* 51 */ {(uchar *) "print_paddr",     3, 0, -1, 0x0D,      0,      0, 0, ONE },
575 /* 52 */ {(uchar *) "load",            3, 0, -1, 0x0E,     St, VARIAB, 0, ONE },
576 /* 53 */ {(uchar *) "not",             3, 3,  0, 0x0F,     St,      0, 0, ONE },
577 /* 54 */ {(uchar *) "rtrue",           3, 0, -1, 0x00,     Rf,      0, 0,ZERO },
578 /* 55 */ {(uchar *) "rfalse",          3, 0, -1, 0x01,     Rf,      0, 0,ZERO },
579 /* 56 */ {(uchar *) "print",           3, 0, -1, 0x02,      0,   TEXT, 0,ZERO },
580 /* 57 */ {(uchar *) "print_ret",       3, 0, -1, 0x03,     Rf,   TEXT, 0,ZERO },
581 /* 58 */ {(uchar *) "nop",             3, 0, -1, 0x04,      0,      0, 0,ZERO },
582 /* 59 */ {(uchar *) "save",            3, 3,  1, 0x05,     Br,      0, 0,ZERO },
583 /* 60 */ {(uchar *) "restore",         3, 3,  2, 0x06,     Br,      0, 0,ZERO },
584 /* 61 */ {(uchar *) "restart",         3, 0, -1, 0x07,      0,      0, 0,ZERO },
585 /* 62 */ {(uchar *) "ret_popped",      3, 0, -1, 0x08,     Rf,      0, 0,ZERO },
586 /* 63 */ {(uchar *) "pop",             3, 4, -1, 0x09,      0,      0, 0,ZERO },
587 /* 64 */ {(uchar *) "quit",            3, 0, -1, 0x0A,     Rf,      0, 0,ZERO },
588 /* 65 */ {(uchar *) "new_line",        3, 0, -1, 0x0B,      0,      0, 0,ZERO },
589 /* 66 */ {(uchar *) "show_status",     3, 3, -1, 0x0C,      0,      0, 0,ZERO },
590 /* 67 */ {(uchar *) "verify",          3, 0, -1, 0x0D,     Br,      0, 0,ZERO },
591
592     /* Opcodes introduced in Version 4 */
593
594 /* 68 */ {(uchar *) "call_2s",         4, 0, -1, 0x19,     St,   CALL, 0, TWO },
595 /* 69 */ {(uchar *) "call_vs",         4, 0, -1, 0x20,     St,   CALL, 0, VAR },
596             /* This is the version of "read" called "aread" internally: */
597 /* 70 */ {(uchar *) "read",            4, 0, -1, 0x24,     St,      0, 0, VAR },
598 /* 71 */ {(uchar *) "call_vs2",        4, 0, -1, 0x2C,     St,   CALL, 0,
599                                                                      VAR_LONG },
600 /* 72 */ {(uchar *) "erase_window",    4, 0, -1, 0x2D,      0,      0, 0, VAR },
601 /* 73 */ {(uchar *) "erase_line",      4, 0, -1, 0x2E,      0,      0, 0, VAR },
602 /* 74 */ {(uchar *) "set_cursor",      4, 0, -1, 0x2F,      0,      0, 0, VAR },
603 /* 75 */ {(uchar *) "get_cursor",      4, 0, -1, 0x30,      0,      0, 0, VAR },
604 /* 76 */ {(uchar *) "set_text_style",  4, 0, -1, 0x31,      0,      0, 0, VAR },
605 /* 77 */ {(uchar *) "buffer_mode",     4, 0, -1, 0x32,      0,      0, 0, VAR },
606 /* 78 */ {(uchar *) "read_char",       4, 0, -1, 0x36,     St,      0, 0, VAR },
607 /* 79 */ {(uchar *) "scan_table",      4, 0, -1, 0x37,  St+Br,      0, 0, VAR },
608 /* 80 */ {(uchar *) "call_1s",         4, 0, -1, 0x08,     St,   CALL, 0, ONE },
609
610     /* Opcodes introduced in Version 5 */
611
612 /* 81 */ {(uchar *) "call_2n",         5, 0, -1, 0x1a,      0,   CALL, 0, TWO },
613 /* 82 */ {(uchar *) "set_colour",      5, 0, -1, 0x1b,      0,      0, 6, TWO },
614 /* 83 */ {(uchar *) "throw",           5, 0, -1, 0x1c,      0,      0, 0, TWO },
615 /* 84 */ {(uchar *) "call_vn",         5, 0, -1, 0x39,      0,   CALL, 0, VAR },
616 /* 85 */ {(uchar *) "call_vn2",        5, 0, -1, 0x3a,      0,   CALL, 0,
617                                                                      VAR_LONG },
618 /* 86 */ {(uchar *) "tokenise",        5, 0, -1, 0x3b,      0,      0, 0, VAR },
619 /* 87 */ {(uchar *) "encode_text",     5, 0, -1, 0x3c,      0,      0, 0, VAR },
620 /* 88 */ {(uchar *) "copy_table",      5, 0, -1, 0x3d,      0,      0, 0, VAR },
621 /* 89 */ {(uchar *) "print_table",     5, 0, -1, 0x3e,      0,      0, 0, VAR },
622 /* 90 */ {(uchar *) "check_arg_count", 5, 0, -1, 0x3f,     Br,      0, 0, VAR },
623 /* 91 */ {(uchar *) "call_1n",         5, 0, -1, 0x0F,      0,   CALL, 0, ONE },
624 /* 92 */ {(uchar *) "catch",           5, 0, -1, 0x09,     St,      0, 0, ZERO },
625 /* 93 */ {(uchar *) "piracy",          5, 0, -1, 0x0F,     Br,      0, 0, ZERO },
626 /* 94 */ {(uchar *) "log_shift",       5, 0, -1, 0x02,     St,      0, 0, EXT },
627 /* 95 */ {(uchar *) "art_shift",       5, 0, -1, 0x03,     St,      0, 0, EXT },
628 /* 96 */ {(uchar *) "set_font",        5, 0, -1, 0x04,     St,      0, 0, EXT },
629 /* 97 */ {(uchar *) "save_undo",       5, 0, -1, 0x09,     St,      0, 4, EXT },
630 /* 98 */ {(uchar *) "restore_undo",    5, 0, -1, 0x0A,     St,      0, 4, EXT },
631
632     /* Opcodes introduced in Version 6 */
633
634 /* 99 */  { (uchar *) "draw_picture",  6, 6, -1, 0x05,      0,      0, 3, EXT },
635 /* 100 */ { (uchar *) "picture_data",  6, 6, -1, 0x06,     Br,      0, 3, EXT },
636 /* 101 */ { (uchar *) "erase_picture", 6, 6, -1, 0x07,      0,      0, 3, EXT },
637 /* 102 */ { (uchar *) "set_margins",   6, 6, -1, 0x08,      0,      0, 0, EXT },
638 /* 103 */ { (uchar *) "move_window",   6, 6, -1, 0x10,      0,      0, 0, EXT },
639 /* 104 */ { (uchar *) "window_size",   6, 6, -1, 0x11,      0,      0, 0, EXT },
640 /* 105 */ { (uchar *) "window_style",  6, 6, -1, 0x12,      0,      0, 0, EXT },
641 /* 106 */ { (uchar *) "get_wind_prop", 6, 6, -1, 0x13,     St,      0, 0, EXT },
642 /* 107 */ { (uchar *) "scroll_window", 6, 6, -1, 0x14,      0,      0, 0, EXT },
643 /* 108 */ { (uchar *) "pop_stack",     6, 6, -1, 0x15,      0,      0, 0, EXT },
644 /* 109 */ { (uchar *) "read_mouse",    6, 6, -1, 0x16,      0,      0, 5, EXT },
645 /* 110 */ { (uchar *) "mouse_window",  6, 6, -1, 0x17,      0,      0, 5, EXT },
646 /* 111 */ { (uchar *) "push_stack",    6, 6, -1, 0x18,     Br,      0, 0, EXT },
647 /* 112 */ { (uchar *) "put_wind_prop", 6, 6, -1, 0x19,      0,      0, 0, EXT },
648 /* 113 */ { (uchar *) "print_form",    6, 6, -1, 0x1a,      0,      0, 0, EXT },
649 /* 114 */ { (uchar *) "make_menu",     6, 6, -1, 0x1b,     Br,      0, 8, EXT },
650 /* 115 */ { (uchar *) "picture_table", 6, 6, -1, 0x1c,      0,      0, 3, EXT },
651
652     /* Opcodes introduced in Z-Machine Specification Standard 1.0 */
653
654 /* 116 */ { (uchar *) "print_unicode", 5, 0, -1, 0x0b,      0,      0, 0, EXT },
655 /* 117 */ { (uchar *) "check_unicode", 5, 0, -1, 0x0c,     St,      0, 0, EXT }
656 };
657
658     /* Subsequent forms for opcodes whose meaning changes with version */
659
660 static opcodez extension_table_z[] =
661 {
662 /* 0 */ { (uchar *) "not",             4, 4,  3, 0x0F,     St,      0, 0, ONE },
663 /* 1 */ { (uchar *) "save",            4, 4,  4, 0x05,     St,      0, 0,ZERO },
664 /* 2 */ { (uchar *) "restore",         4, 4,  5, 0x06,     St,      0, 0,ZERO },
665 /* 3 */ { (uchar *) "not",             5, 0, -1, 0x38,     St,      0, 0, VAR },
666 /* 4 */ { (uchar *) "save",            5, 0, -1, 0x00,     St,      0, 0, EXT },
667 /* 5 */ { (uchar *) "restore",         5, 0, -1, 0x01,     St,      0, 0, EXT },
668 /* 6 */ { (uchar *) "pull",            6, 6, -1, 0x29,     St,      0, 0, VAR }
669 };
670
671 static opcodez invalid_opcode_z =
672         { (uchar *) "invalid",         0, 0, -1, 0xff,      0,      0, 0, ZERO};
673
674 static opcodez custom_opcode_z;
675
676 /* Note that this table assumes that all opcodes have at most two 
677    branch-label or store operands, and that if they exist, they are the
678    last operands. Glulx does not actually guarantee this. But it is
679    true for all opcodes in the current Glulx spec, so we will assume
680    it for now.
681
682    Also note that Inform can only compile branches to constant offsets,
683    even though the Glulx machine can handle stack or memory-loaded
684    operands in a branch instruction.
685 */
686
687 static opcodeg opcodes_table_g[] = {
688   { (uchar *) "nop",        0x00,  0, 0, 0 },
689   { (uchar *) "add",        0x10, St, 0, 3 },
690   { (uchar *) "sub",        0x11, St, 0, 3 },
691   { (uchar *) "mul",        0x12, St, 0, 3 },
692   { (uchar *) "div",        0x13, St, 0, 3 },
693   { (uchar *) "mod",        0x14, St, 0, 3 },
694   { (uchar *) "neg",        0x15, St, 0, 2 },
695   { (uchar *) "bitand",     0x18, St, 0, 3 },
696   { (uchar *) "bitor",      0x19, St, 0, 3 },
697   { (uchar *) "bitxor",     0x1A, St, 0, 3 },
698   { (uchar *) "bitnot",     0x1B, St, 0, 2 },
699   { (uchar *) "shiftl",     0x1C, St, 0, 3 },
700   { (uchar *) "sshiftr",    0x1D, St, 0, 3 },
701   { (uchar *) "ushiftr",    0x1E, St, 0, 3 },
702   { (uchar *) "jump",       0x20, Br|Rf, 0, 1 },
703   { (uchar *) "jz",     0x22, Br, 0, 2 },
704   { (uchar *) "jnz",        0x23, Br, 0, 2 },
705   { (uchar *) "jeq",        0x24, Br, 0, 3 },
706   { (uchar *) "jne",        0x25, Br, 0, 3 },
707   { (uchar *) "jlt",        0x26, Br, 0, 3 },
708   { (uchar *) "jge",        0x27, Br, 0, 3 },
709   { (uchar *) "jgt",        0x28, Br, 0, 3 },
710   { (uchar *) "jle",        0x29, Br, 0, 3 },
711   { (uchar *) "jltu",       0x2A, Br, 0, 3 },
712   { (uchar *) "jgeu",       0x2B, Br, 0, 3 },
713   { (uchar *) "jgtu",       0x2C, Br, 0, 3 },
714   { (uchar *) "jleu",       0x2D, Br, 0, 3 },
715   { (uchar *) "call",       0x30, St, 0, 3 },
716   { (uchar *) "return",     0x31, Rf, 0, 1 },
717   { (uchar *) "catch",      0x32, Br|St, 0, 2 },
718   { (uchar *) "throw",      0x33, Rf, 0, 2 },
719   { (uchar *) "tailcall",   0x34, Rf, 0, 2 },
720   { (uchar *) "copy",       0x40, St, 0, 2 },
721   { (uchar *) "copys",      0x41, St, 0, 2 },
722   { (uchar *) "copyb",      0x42, St, 0, 2 },
723   { (uchar *) "sexs",       0x44, St, 0, 2 },
724   { (uchar *) "sexb",       0x45, St, 0, 2 },
725   { (uchar *) "aload",      0x48, St, 0, 3 },
726   { (uchar *) "aloads",     0x49, St, 0, 3 },
727   { (uchar *) "aloadb",     0x4A, St, 0, 3 },
728   { (uchar *) "aloadbit",   0x4B, St, 0, 3 },
729   { (uchar *) "astore",     0x4C,  0, 0, 3 },
730   { (uchar *) "astores",    0x4D,  0, 0, 3 },
731   { (uchar *) "astoreb",    0x4E,  0, 0, 3 },
732   { (uchar *) "astorebit",  0x4F,  0, 0, 3 },
733   { (uchar *) "stkcount",   0x50, St, 0, 1 },
734   { (uchar *) "stkpeek",    0x51, St, 0, 2 },
735   { (uchar *) "stkswap",    0x52,  0, 0, 0 },
736   { (uchar *) "stkroll",    0x53,  0, 0, 2 },
737   { (uchar *) "stkcopy",    0x54,  0, 0, 1 },
738   { (uchar *) "streamchar", 0x70,  0, 0, 1 },
739   { (uchar *) "streamnum",  0x71,  0, 0, 1 },
740   { (uchar *) "streamstr",  0x72,  0, 0, 1 },
741   { (uchar *) "gestalt",    0x0100, St, 0, 3 },
742   { (uchar *) "debugtrap",  0x0101, 0, 0, 1 },
743   { (uchar *) "getmemsize",     0x0102, St, 0, 1 },
744   { (uchar *) "setmemsize",     0x0103, St, 0, 2 },
745   { (uchar *) "jumpabs",    0x0104, Rf, 0, 1 },
746   { (uchar *) "random",     0x0110, St, 0, 2 },
747   { (uchar *) "setrandom",  0x0111,  0, 0, 1 },
748   { (uchar *) "quit",       0x0120, Rf, 0, 0 },
749   { (uchar *) "verify",     0x0121, St, 0, 1 },
750   { (uchar *) "restart",    0x0122,  0, 0, 0 },
751   { (uchar *) "save",       0x0123, St, 0, 2 },
752   { (uchar *) "restore",    0x0124, St, 0, 2 },
753   { (uchar *) "saveundo",   0x0125, St, 0, 1 },
754   { (uchar *) "restoreundo",    0x0126, St, 0, 1 },
755   { (uchar *) "protect",    0x0127,  0, 0, 2 },
756   { (uchar *) "glk",        0x0130, St, 0, 3 },
757   { (uchar *) "getstringtbl",   0x0140, St, 0, 1 },
758   { (uchar *) "setstringtbl",   0x0141, 0, 0, 1 },
759   { (uchar *) "getiosys",   0x0148, St|St2, 0, 2 },
760   { (uchar *) "setiosys",   0x0149, 0, 0, 2 },
761   { (uchar *) "linearsearch",   0x0150, St, 0, 8 },
762   { (uchar *) "binarysearch",   0x0151, St, 0, 8 },
763   { (uchar *) "linkedsearch",   0x0152, St, 0, 7 },
764   { (uchar *) "callf",      0x0160, St, 0, 2 },
765   { (uchar *) "callfi",     0x0161, St, 0, 3 },
766   { (uchar *) "callfii",    0x0162, St, 0, 4 },
767   { (uchar *) "callfiii",   0x0163, St, 0, 5 },
768   { (uchar *) "streamunichar", 0x73,  0, GOP_Unicode, 1 },
769   { (uchar *) "mzero",      0x170,  0, GOP_MemHeap, 2 },
770   { (uchar *) "mcopy",      0x171,  0, GOP_MemHeap, 3 },
771   { (uchar *) "malloc",     0x178,  St, GOP_MemHeap, 2 },
772   { (uchar *) "mfree",      0x179,  0, GOP_MemHeap, 1 },
773   { (uchar *) "accelfunc",  0x180,  0, GOP_Acceleration, 2 },
774   { (uchar *) "accelparam", 0x181,  0, GOP_Acceleration, 2 },
775   { (uchar *) "numtof",     0x190,  St, GOP_Float, 2 },
776   { (uchar *) "ftonumz",    0x191,  St, GOP_Float, 2 },
777   { (uchar *) "ftonumn",    0x192,  St, GOP_Float, 2 },
778   { (uchar *) "ceil",       0x198,  St, GOP_Float, 2 },
779   { (uchar *) "floor",      0x199,  St, GOP_Float, 2 },
780   { (uchar *) "fadd",       0x1A0,  St, GOP_Float, 3 },
781   { (uchar *) "fsub",       0x1A1,  St, GOP_Float, 3 },
782   { (uchar *) "fmul",       0x1A2,  St, GOP_Float, 3 },
783   { (uchar *) "fdiv",       0x1A3,  St, GOP_Float, 3 },
784   { (uchar *) "fmod",       0x1A4,  St|St2, GOP_Float, 4 },
785   { (uchar *) "sqrt",       0x1A8,  St, GOP_Float, 2 },
786   { (uchar *) "exp",        0x1A9,  St, GOP_Float, 2 },
787   { (uchar *) "log",        0x1AA,  St, GOP_Float, 2 },
788   { (uchar *) "pow",        0x1AB,  St, GOP_Float, 3 },
789   { (uchar *) "sin",        0x1B0,  St, GOP_Float, 2 },
790   { (uchar *) "cos",        0x1B1,  St, GOP_Float, 2 },
791   { (uchar *) "tan",        0x1B2,  St, GOP_Float, 2 },
792   { (uchar *) "asin",       0x1B3,  St, GOP_Float, 2 },
793   { (uchar *) "acos",       0x1B4,  St, GOP_Float, 2 },
794   { (uchar *) "atan",       0x1B5,  St, GOP_Float, 2 },
795   { (uchar *) "atan2",      0x1B6,  St, GOP_Float, 3 },
796   { (uchar *) "jfeq",       0x1C0,  Br, GOP_Float, 4 },
797   { (uchar *) "jfne",       0x1C1,  Br, GOP_Float, 4 },
798   { (uchar *) "jflt",       0x1C2,  Br, GOP_Float, 3 },
799   { (uchar *) "jfle",       0x1C3,  Br, GOP_Float, 3 },
800   { (uchar *) "jfgt",       0x1C4,  Br, GOP_Float, 3 },
801   { (uchar *) "jfge",       0x1C5,  Br, GOP_Float, 3 },
802   { (uchar *) "jisnan",     0x1C8,  Br, GOP_Float, 2 },
803   { (uchar *) "jisinf",     0x1C9,  Br, GOP_Float, 2 },
804   { (uchar *) "hasundo",    0x128,  St, GOP_ExtUndo, 1 },
805   { (uchar *) "discardundo",0x129,   0, GOP_ExtUndo, 0 },
806 };
807
808 /* The opmacros table is used for fake opcodes. The opcode numbers are
809    ignored; this table is only used for argument parsing. */
810 static opcodeg opmacros_table_g[] = {
811   { (uchar *) "pull", 0, St, 0, 1 },
812   { (uchar *) "push", 0,  0, 0, 1 },
813 };
814
815 static opcodeg custom_opcode_g;
816
817 static opcodez internal_number_to_opcode_z(int32 i)
818 {   opcodez x;
819     ASSERT_ZCODE();
820     if (i == -1) return custom_opcode_z;
821     x = opcodes_table_z[i];
822     if (instruction_set_number < x.version1) return invalid_opcode_z;
823     if (x.version2 == 0) return x;
824     if (instruction_set_number <= x.version2) return x;
825     i = x.extension;
826     if (i < 0) return invalid_opcode_z;
827     x = extension_table_z[i];
828     if (instruction_set_number < x.version1) return invalid_opcode_z;
829     if (x.version2 == 0) return x;
830     if (instruction_set_number <= x.version2) return x;
831     return extension_table_z[x.extension];
832 }
833
834 static void make_opcode_syntax_z(opcodez opco)
835 {   char *p = "", *q = opcode_syntax_string;
836     sprintf(q, "%s", opco.name);
837     switch(opco.no)
838     {   case ONE: p=" <operand>"; break;
839         case TWO: p=" <operand1> <operand2>"; break;
840         case EXT:
841         case VAR: p=" <0 to 4 operands>"; break;
842         case VAR_LONG: p=" <0 to 8 operands>"; break;
843     }
844     switch(opco.op_rules)
845     {   case TEXT: sprintf(q+strlen(q), " <text>"); return;
846         case LABEL: sprintf(q+strlen(q), " <label>"); return;
847         case VARIAB:
848             sprintf(q+strlen(q), " <variable>");
849         case CALL:
850             if (opco.op_rules==CALL) sprintf(q+strlen(q), " <routine>");
851             switch(opco.no)
852             {   case ONE: p=""; break;
853                 case TWO: p=" <operand>"; break;
854                 case EXT:
855                 case VAR: p=" <1 to 4 operands>"; break;
856                 case VAR_LONG: p=" <1 to 8 operands>"; break;
857             }
858             break;
859     }
860     sprintf(q+strlen(q), "%s", p);
861     if ((opco.flags & St) != 0) sprintf(q+strlen(q), " -> <result-variable>");
862     if ((opco.flags & Br) != 0) sprintf(q+strlen(q), " ?[~]<label>");
863 }
864
865 static opcodeg internal_number_to_opcode_g(int32 i)
866 {   
867     opcodeg x;
868     if (i == -1) return custom_opcode_g;
869     x = opcodes_table_g[i];
870     return x;
871 }
872
873 static opcodeg internal_number_to_opmacro_g(int32 i)
874 {
875     return opmacros_table_g[i];
876 }
877
878 static void make_opcode_syntax_g(opcodeg opco)
879 {
880     int ix;
881     char *cx;
882     char *q = opcode_syntax_string;
883
884     sprintf(q, "%s", opco.name);
885     sprintf(q+strlen(q), " <%d operand%s", opco.no,
886         ((opco.no==1) ? "" : "s"));
887     if (opco.no) {
888         cx = q+strlen(q);
889         strcpy(cx, ": ");
890         cx += strlen(cx);
891         for (ix=0; ix<opco.no; ix++) {
892             if (ix) {
893                 *cx = ' ';
894                 cx++;
895             }
896             if (ix == opco.no-1) {
897                 if (opco.flags & Br) {
898                     strcpy(cx, "Lb");
899                 }
900                 else if (opco.flags & St) {
901                     strcpy(cx, "S");
902                 }
903                 else {
904                     strcpy(cx, "L");
905                 }
906             }
907             else if (ix == opco.no-2 && (opco.flags & Br) && (opco.flags & St)) {
908                 strcpy(cx, "S");
909             }
910             else if (ix == opco.no-2 && (opco.flags & St2)) {
911                 strcpy(cx, "S");
912             }
913             else {
914                 strcpy(cx, "L");
915             }
916             cx += strlen(cx);
917             sprintf(cx, "%d", ix+1);
918             cx += strlen(cx);
919         }
920     }
921     sprintf(q+strlen(q), ">");
922 }
923
924
925 /* ========================================================================= */
926 /*   The assembler itself does four things:                                  */
927 /*                                                                           */
928 /*       assembles instructions                                              */
929 /*       sets label N to the current code position                           */
930 /*       assembles routine headers                                           */
931 /*       assembles routine ends                                              */
932 /* ------------------------------------------------------------------------- */
933
934 /* This is for Z-code only. */
935 static void write_operand(assembly_operand op)
936 {   int32 j;
937     if (module_switch && (op.marker != 0))
938     {   if ((op.marker != VARIABLE_MV) && (op.type == SHORT_CONSTANT_OT))
939             op.type = LONG_CONSTANT_OT;
940     }
941     j=op.value;
942     switch(op.type)
943     {   case LONG_CONSTANT_OT:
944             byteout(j/256, op.marker); byteout(j%256, 0); return;
945         case SHORT_CONSTANT_OT:
946             if (op.marker == 0)
947             byteout(j, 0);
948             else byteout(j, 0x80 + op.marker); return;
949         case VARIABLE_OT:
950             byteout(j, (module_switch)?(0x80 + op.marker):0); return;
951         case CONSTANT_OT:
952         case HALFCONSTANT_OT:
953         case BYTECONSTANT_OT:
954         case ZEROCONSTANT_OT:
955         case SYSFUN_OT:
956         case DEREFERENCE_OT:
957         case LOCALVAR_OT:
958         case GLOBALVAR_OT:
959             compiler_error("Glulx OT in Z-code assembly operand.");
960             return;
961     }
962 }
963
964 extern void assemblez_instruction(const assembly_instruction *AI)
965 {
966     int32 operands_pc;
967     int32 start_pc;
968     int32 offset, j, topbits=0, types_byte1, types_byte2;
969     int operand_rules, min=0, max=0, no_operands_given, at_seq_point = FALSE;
970     assembly_operand o1, o2;
971     opcodez opco;
972
973     ASSERT_ZCODE();
974
975     if (execution_never_reaches_here) {
976         if (!(execution_never_reaches_here & EXECSTATE_NOWARN)) {
977             warning("This statement can never be reached");
978             /* only show the warning once */
979             execution_never_reaches_here |= EXECSTATE_NOWARN;
980         }
981         return;
982     }
983
984     offset = zmachine_pc;
985
986     no_instructions++;
987
988     if (veneer_mode) sequence_point_follows = FALSE;
989     if (sequence_point_follows)
990     {   sequence_point_follows = FALSE; at_seq_point = TRUE;
991         if (debugfile_switch)
992         {
993             ensure_memory_list_available(&sequence_points_memlist, next_sequence_point+1);
994             sequence_points[next_sequence_point].label = next_label;
995             sequence_points[next_sequence_point].location =
996                 statement_debug_location;
997             set_label_offset(next_label++, zmachine_pc);
998         }
999         next_sequence_point++;
1000     }
1001
1002     opco = internal_number_to_opcode_z(AI->internal_number);
1003     if (opco.version1==0)
1004     {   error_named("Opcode unavailable in this Z-machine version",
1005             opcode_names.keywords[AI->internal_number]);
1006         return;
1007     }
1008
1009     operand_rules = opco.op_rules;
1010     execution_never_reaches_here = ((opco.flags & Rf) ? EXECSTATE_UNREACHABLE : EXECSTATE_REACHABLE);
1011
1012     if (opco.flags2_set != 0) flags2_requirements[opco.flags2_set] = 1;
1013
1014     no_operands_given = AI->operand_count;
1015
1016     if ((opco.no == TWO) && ((no_operands_given==3)||(no_operands_given==4)))
1017         opco.no = VAR;
1018
1019     /* 1. Write the opcode byte(s) */
1020
1021     start_pc = zcode_ha_size;
1022
1023     switch(opco.no)
1024     {   case VAR_LONG: topbits=0xc0; min=0; max=8; break;
1025         case VAR:      topbits=0xc0; min=0; max=4; break;
1026         case ZERO:     topbits=0xb0; min=0; max=0; break;
1027         case ONE:      topbits=0x80; min=1; max=1; break;
1028         case TWO:      topbits=0x00; min=2; max=2; break;
1029         case EXT:      topbits=0x00; min=0; max=4;
1030                        byteout(0xbe, 0); opco.no=VAR; break;
1031         case EXT_LONG: topbits=0x00; min=0; max=8;
1032                        byteout(0xbe, 0); opco.no=VAR_LONG; break;
1033     }
1034     byteout(opco.code + topbits, 0);
1035
1036     operands_pc = zcode_ha_size;
1037
1038     /* 2. Dispose of the special rules LABEL and TEXT */
1039
1040     if (operand_rules==LABEL)
1041     {   j = (AI->operand[0]).value;
1042         mark_label_used(j);
1043         byteout(j/256, LABEL_MV); byteout(j%256, 0);
1044         goto Instruction_Done;
1045     }
1046
1047     if (operand_rules==TEXT)
1048     {   int32 i;
1049         j = translate_text(-1, AI->text, STRCTX_GAMEOPC);
1050         if (j < 0) {
1051             error("text translation failed");
1052             j = 0;
1053         }
1054         ensure_memory_list_available(&zcode_markers_memlist, zcode_ha_size+j);
1055         ensure_memory_list_available(&zcode_holding_area_memlist, zcode_ha_size+j);
1056         for (i=0; i<j; i++) {
1057             zcode_holding_area[zcode_ha_size] = translated_text[i];
1058             zcode_markers[zcode_ha_size] = 0;
1059             zcode_ha_size++;
1060         }
1061         zmachine_pc += j;
1062         goto Instruction_Done;
1063     }
1064
1065     /* 3. Sort out the operands */
1066
1067     if ((no_operands_given < min) || (no_operands_given > max))
1068         goto OpcodeSyntaxError;
1069
1070     switch(opco.no)
1071     {   case VAR:
1072         case VAR_LONG:
1073             byteout(0, 0);
1074             if (opco.no == VAR_LONG) byteout(0, 0);
1075             types_byte1=0xff; types_byte2=0xff;
1076             for (j=0; j<no_operands_given; j++)
1077             {   int multi=0, mask=0;
1078                 switch(j)
1079                 {   case 0: case 4: multi=0x40; mask=0xc0; break;
1080                     case 1: case 5: multi=0x10; mask=0x30; break;
1081                     case 2: case 6: multi=0x04; mask=0x0c; break;
1082                     case 3: case 7: multi=0x01; mask=0x03; break;
1083                 }
1084                 o1 = AI->operand[j];
1085                 write_operand(o1);
1086                 if (j<4)
1087                     types_byte1 = (types_byte1 & (~mask)) + o1.type*multi;
1088                 else
1089                     types_byte2 = (types_byte2 & (~mask)) + o1.type*multi;
1090             }
1091             zcode_holding_area[operands_pc]=types_byte1;
1092             if (opco.no == VAR_LONG) zcode_holding_area[operands_pc+1]=types_byte2;
1093             break;
1094
1095         case ONE:
1096             o1 = AI->operand[0];
1097             zcode_holding_area[start_pc] += o1.type*0x10;
1098             write_operand(o1);
1099             break;
1100
1101         case TWO:
1102             o1 = AI->operand[0];
1103             o2 = AI->operand[1];
1104
1105             /* Transfer to VAR form if either operand is a long constant */
1106
1107             if ((o1.type==LONG_CONSTANT_OT)||(o2.type==LONG_CONSTANT_OT))
1108             {   zcode_holding_area[start_pc] += 0xc0;
1109                 byteout(o1.type*0x40 + o2.type*0x10 + 0x0f, 0);
1110             }
1111             else
1112             {   if (o1.type==VARIABLE_OT) zcode_holding_area[start_pc] += 0x40;
1113                 if (o2.type==VARIABLE_OT) zcode_holding_area[start_pc] += 0x20;
1114             }
1115             write_operand(o1);
1116             write_operand(o2);
1117             break;
1118     }
1119
1120     /* 4. Assemble a Store destination, if needed */
1121
1122     if ((AI->store_variable_number) != -1)
1123     {   if (AI->store_variable_number >= MAX_LOCAL_VARIABLES+MAX_ZCODE_GLOBAL_VARS) {
1124             goto OpcodeSyntaxError;
1125         }
1126         o1.type = VARIABLE_OT;
1127         o1.value = AI->store_variable_number;
1128         variables[o1.value].usage = TRUE;
1129         o1.marker = 0;
1130
1131         /*  Note that variable numbers 249 to 255 (i.e. globals 233 to 239)
1132             are used as scratch workspace, so need no mapping between
1133             modules and story files: nor do local variables 0 to 15  */
1134
1135         if ((o1.value >= MAX_LOCAL_VARIABLES) && (o1.value < 249))
1136             o1.marker = VARIABLE_MV;
1137         write_operand(o1);
1138     }
1139
1140     /* 5. Assemble a branch, if needed */
1141
1142     if (AI->branch_label_number != -1)
1143     {   int32 addr, long_form;
1144         int branch_on_true = (AI->branch_flag)?1:0;
1145         mark_label_used(AI->branch_label_number);
1146         switch (AI->branch_label_number)
1147         {   case -2: addr = 2; branch_on_true = 0; long_form = 0; break;
1148                                                  /* branch nowhere, carry on */
1149             case -3: addr = 0; long_form = 0; break;  /* rfalse on condition */
1150             case -4: addr = 1; long_form = 0; break;  /* rtrue on condition */
1151             default:
1152                 long_form = 1; addr = AI->branch_label_number;
1153                 break;
1154         }
1155         if (addr > 0x7fff) fatalerror("Too many branch points in routine.");
1156         if (long_form==1)
1157         {   byteout(branch_on_true*0x80 + addr/256, BRANCH_MV);
1158             byteout(addr%256, 0);
1159         }
1160         else
1161             byteout(branch_on_true*0x80+ 0x40 + (addr&0x3f), 0);
1162     }
1163
1164     Instruction_Done:
1165
1166     if (asm_trace_level > 0)
1167     {   int i;
1168         printf("%5d  +%05lx %3s %-12s ", ErrorReport.line_number,
1169             ((long int) offset),
1170             (at_seq_point)?"<*>":"   ", opco.name);
1171
1172         if ((AI->internal_number == print_zc)
1173             || (AI->internal_number == print_ret_zc))
1174         {   printf("\"");
1175             for (i=0;(AI->text)[i]!=0 && i<35; i++) printf("%c",(AI->text)[i]);
1176             if (i == 35) printf("...");
1177             printf("\"");
1178         }
1179
1180         for (i=0; i<AI->operand_count; i++)
1181         {   if ((i==0) && (opco.op_rules == VARIAB))
1182             {   if ((AI->operand[0]).type == VARIABLE_OT)
1183                 {   printf("["); print_operand_z(&AI->operand[i], TRUE); }
1184                 else
1185                     printf("%s", variable_name((AI->operand[0]).value));
1186             }
1187             else
1188             if ((i==0) && (opco.op_rules == LABEL))
1189             {   printf("L%d", AI->operand[0].value);
1190             }
1191             else print_operand_z(&AI->operand[i], TRUE);
1192             printf(" ");
1193         }
1194         if (AI->store_variable_number != -1)
1195         {   assembly_operand AO;
1196             printf("-> ");
1197             AO.type = VARIABLE_OT; AO.value = AI->store_variable_number;
1198             print_operand_z(&AO, TRUE); printf(" ");
1199         }
1200
1201         switch(AI->branch_label_number)
1202         {   case -4: printf("rtrue if %s", (AI->branch_flag)?"TRUE":"FALSE");
1203                 break;
1204             case -3: printf("rfalse if %s", (AI->branch_flag)?"TRUE":"FALSE");
1205                 break;
1206             case -2: printf("(no branch)"); break;
1207             case -1: break;
1208             default:
1209                 printf("to L%d if %s", AI->branch_label_number,
1210                    (AI->branch_flag)?"TRUE":"FALSE"); break;
1211         }
1212
1213         if (asm_trace_level>=2)
1214         {   for (j=0;start_pc<zcode_ha_size;
1215                  j++, start_pc++)
1216             {   if (j%16==0) printf("\n                               ");
1217                 printf("%02x ", zcode_holding_area[start_pc]);
1218             }
1219         }
1220         printf("\n");
1221     }
1222
1223     if (module_switch) flush_link_data();
1224
1225     return;
1226
1227     OpcodeSyntaxError:
1228
1229     make_opcode_syntax_z(opco);
1230     error_named("Assembly mistake: syntax is", opcode_syntax_string);
1231 }
1232
1233 static void assembleg_macro(const assembly_instruction *AI)
1234 {
1235     /* validate macro syntax first */
1236     int ix, no_operands_given;
1237     opcodeg opco;
1238     
1239     opco = internal_number_to_opmacro_g(AI->internal_number);
1240     no_operands_given = AI->operand_count;
1241     
1242     if (no_operands_given != opco.no)
1243         goto OpcodeSyntaxError;
1244     
1245     for (ix = 0; ix < no_operands_given; ix++) {
1246         int type = AI->operand[ix].type;
1247         if ((opco.flags & St) 
1248           && ((!(opco.flags & Br) && (ix == no_operands_given-1))
1249           || ((opco.flags & Br) && (ix == no_operands_given-2)))) {
1250             if (is_constant_ot(type)) {
1251                 error("*** assembly macro tried to store to a constant ***");
1252                 goto OpcodeSyntaxError; 
1253             }
1254         }
1255         if ((opco.flags & St2) 
1256             && (ix == no_operands_given-2)) {
1257             if (is_constant_ot(type)) {
1258               error("*** assembly macro tried to store to a constant ***");
1259               goto OpcodeSyntaxError; 
1260             }
1261         }
1262     }
1263     
1264     /* expand the macro */
1265     switch (AI->internal_number) {
1266         case pull_gm:
1267             assembleg_store(AI->operand[0], stack_pointer);
1268             break;
1269         
1270         case push_gm:
1271             assembleg_store(stack_pointer, AI->operand[0]);
1272             break;
1273         
1274         default:
1275             compiler_error("Invalid Glulx assembly macro");
1276             break;
1277     }
1278     
1279     return;
1280     
1281     OpcodeSyntaxError:
1282     
1283     make_opcode_syntax_g(opco);
1284     error_named("Assembly mistake: syntax is", opcode_syntax_string);
1285 }
1286
1287 extern void assembleg_instruction(const assembly_instruction *AI)
1288 {
1289     int32 opmodes_pc;
1290     int32 start_pc;
1291     int32 offset, j;
1292     int no_operands_given, at_seq_point = FALSE;
1293     int ix, k;
1294     opcodeg opco;
1295
1296     ASSERT_GLULX();
1297
1298     if (execution_never_reaches_here) {
1299         if (!(execution_never_reaches_here & EXECSTATE_NOWARN)) {
1300             warning("This statement can never be reached");
1301             /* only show the warning once */
1302             execution_never_reaches_here |= EXECSTATE_NOWARN;
1303         }
1304         return;
1305     }
1306
1307     offset = zmachine_pc;
1308
1309     no_instructions++;
1310
1311     if (veneer_mode) sequence_point_follows = FALSE;
1312     if (sequence_point_follows)
1313     {   sequence_point_follows = FALSE; at_seq_point = TRUE;
1314         if (debugfile_switch)
1315         {
1316             ensure_memory_list_available(&sequence_points_memlist, next_sequence_point+1);
1317             sequence_points[next_sequence_point].label = next_label;
1318             sequence_points[next_sequence_point].location =
1319                 statement_debug_location;
1320             set_label_offset(next_label++, zmachine_pc);
1321         }
1322         next_sequence_point++;
1323     }
1324
1325     opco = internal_number_to_opcode_g(AI->internal_number);
1326
1327     execution_never_reaches_here = ((opco.flags & Rf) ? EXECSTATE_UNREACHABLE : EXECSTATE_REACHABLE);
1328
1329     if (opco.op_rules & GOP_Unicode) {
1330         uses_unicode_features = TRUE;
1331     }
1332     if (opco.op_rules & GOP_MemHeap) {
1333         uses_memheap_features = TRUE;
1334     }
1335     if (opco.op_rules & GOP_Acceleration) {
1336         uses_acceleration_features = TRUE;
1337     }
1338     if (opco.op_rules & GOP_Float) {
1339         uses_float_features = TRUE;
1340     }
1341     if (opco.op_rules & GOP_ExtUndo) {
1342         uses_extundo_features = TRUE;
1343     }
1344
1345     no_operands_given = AI->operand_count;
1346
1347     /* 1. Write the opcode byte(s) */
1348
1349     start_pc = zcode_ha_size; 
1350
1351     if (opco.code < 0x80) {
1352       byteout(opco.code, 0);
1353     }
1354     else if (opco.code < 0x4000) {
1355       byteout(((opco.code >> 8) & 0xFF) | 0x80, 0);
1356       byteout((opco.code & 0xFF), 0);
1357     }
1358     else {
1359       byteout(((opco.code >> 24) & 0xFF) | 0xC0, 0);
1360       byteout(((opco.code >> 16) & 0xFF), 0);
1361       byteout(((opco.code >> 8) & 0xFF), 0);
1362       byteout(((opco.code) & 0xFF), 0);
1363     }
1364
1365     /* ... and the operand addressing modes. There's one byte for
1366        every two operands (rounded up). We write zeroes for now; 
1367        when the operands are written, we'll go back and fix them. */
1368
1369     opmodes_pc = zcode_ha_size;
1370
1371     for (ix=0; ix<opco.no; ix+=2) {
1372       byteout(0, 0);
1373     }
1374
1375     /* 2. Dispose of the special rules */
1376     /* There aren't any in Glulx. */
1377
1378     /* 3. Sort out the operands */
1379
1380     if (no_operands_given != opco.no) {
1381       goto OpcodeSyntaxError;
1382     }
1383
1384     for (ix=0; ix<no_operands_given; ix++) {
1385         int marker = AI->operand[ix].marker;
1386         int type = AI->operand[ix].type;
1387         k = AI->operand[ix].value;
1388
1389         if ((opco.flags & Br) && (ix == no_operands_given-1)) {
1390             if (!(marker >= BRANCH_MV && marker < BRANCHMAX_MV)) {
1391                 compiler_error("Assembling branch without BRANCH_MV marker");
1392                 goto OpcodeSyntaxError; 
1393             }
1394             mark_label_used(k);
1395             if (k == -2) {
1396                 k = 2; /* branch no-op */
1397                 type = BYTECONSTANT_OT;
1398                 marker = 0;
1399             }
1400             else if (k == -3) {
1401                 k = 0; /* branch return 0 */
1402                 type = ZEROCONSTANT_OT;
1403                 marker = 0;
1404             }
1405             else if (k == -4) {
1406                 k = 1; /* branch return 1 */
1407                 type = BYTECONSTANT_OT;
1408                 marker = 0;
1409             }
1410             else {
1411                 /* branch to label k */
1412                 j = (zcode_ha_size - opmodes_pc);
1413                 j = 2*j - ix;
1414                 marker = BRANCH_MV + j;
1415                 if (!(marker >= BRANCH_MV && marker < BRANCHMAX_MV)) {
1416                     error("*** branch marker too far from opmode byte ***");
1417                     goto OpcodeSyntaxError; 
1418                 }
1419             }
1420         }
1421     if ((opco.flags & St) 
1422       && ((!(opco.flags & Br) && (ix == no_operands_given-1))
1423       || ((opco.flags & Br) && (ix == no_operands_given-2)))) {
1424         if (type == BYTECONSTANT_OT || type == HALFCONSTANT_OT
1425             || type == CONSTANT_OT) {
1426             error("*** instruction tried to store to a constant ***");
1427             goto OpcodeSyntaxError; 
1428         }
1429     }
1430     if ((opco.flags & St2) 
1431         && (ix == no_operands_given-2)) {
1432         if (type == BYTECONSTANT_OT || type == HALFCONSTANT_OT
1433           || type == CONSTANT_OT) {
1434           error("*** instruction tried to store to a constant ***");
1435           goto OpcodeSyntaxError; 
1436         }
1437     }
1438
1439       if (marker && (type == HALFCONSTANT_OT 
1440         || type == BYTECONSTANT_OT
1441         || type == ZEROCONSTANT_OT)) {
1442         compiler_error("Assembling marker in less than 32-bit constant.");
1443         /* Actually we should store marker|0x80 for a byte constant,
1444            but let's hold off on that. */
1445         }
1446
1447       switch (type) {
1448       case LONG_CONSTANT_OT:
1449       case SHORT_CONSTANT_OT:
1450       case VARIABLE_OT:
1451         j = 0;
1452         compiler_error("Z-code OT in Glulx assembly operand.");
1453         break;
1454       case CONSTANT_OT:
1455         j = 3;
1456         byteout((k >> 24) & 0xFF, marker);
1457         byteout((k >> 16) & 0xFF, 0);
1458         byteout((k >> 8) & 0xFF, 0);
1459         byteout((k & 0xFF), 0);
1460         break;
1461       case HALFCONSTANT_OT:
1462         j = 2;
1463         byteout((k >> 8) & 0xFF, marker);
1464         byteout((k & 0xFF), 0);
1465         break;
1466       case BYTECONSTANT_OT:
1467         j = 1;
1468         byteout((k & 0xFF), marker);
1469         break;
1470       case ZEROCONSTANT_OT:
1471         j = 0;
1472         break;
1473       case DEREFERENCE_OT:
1474         j = 7;
1475         byteout((k >> 24) & 0xFF, marker);
1476         byteout((k >> 16) & 0xFF, 0);
1477         byteout((k >> 8) & 0xFF, 0);
1478         byteout((k & 0xFF), 0);
1479         break;
1480       case GLOBALVAR_OT:
1481         /* Global variable -- a constant address. */
1482         k -= MAX_LOCAL_VARIABLES;
1483         if (/* DISABLES CODE */ (0)) {
1484             /* We could write the value as a marker and patch it later... */
1485             j = 7;
1486             byteout(((k) >> 24) & 0xFF, VARIABLE_MV);
1487             byteout(((k) >> 16) & 0xFF, 0);
1488             byteout(((k) >> 8) & 0xFF, 0);
1489             byteout(((k) & 0xFF), 0);
1490         }
1491         else {
1492             /* ...but it's more efficient to write it as a RAM operand,
1493                   which can be 1, 2, or 4 bytes. Remember that global variables
1494                   are the very first thing in RAM. */
1495             k = k * 4; /* each variable is four bytes */
1496             if (k <= 255) {
1497                 j = 13;
1498                 byteout(((k) & 0xFF), 0);
1499             }
1500             else if (k <= 65535) {
1501                 j = 14;
1502                 byteout(((k) >> 8) & 0xFF, 0);
1503                 byteout(((k) & 0xFF), 0);
1504             }
1505             else {
1506                 j = 15;
1507                 byteout(((k) >> 24) & 0xFF, 0);
1508                 byteout(((k) >> 16) & 0xFF, 0);
1509                 byteout(((k) >> 8) & 0xFF, 0);
1510                 byteout(((k) & 0xFF), 0);       
1511             }
1512         }
1513         break;
1514       case LOCALVAR_OT:
1515         if (k == 0) {
1516             /* Stack-pointer magic variable */
1517             j = 8; 
1518         }
1519         else {
1520             /* Local variable -- a byte or short offset from the
1521                frame pointer. It's an unsigned offset, so we can
1522                fit up to long 63 (offset 4*63) in a byte. */
1523             if ((k-1) < 64) {
1524                 j = 9;
1525                 byteout((k-1)*4, 0);
1526             }
1527             else {
1528                 j = 10;
1529                 byteout((((k-1)*4) >> 8) & 0xFF, 0);
1530                 byteout(((k-1)*4) & 0xFF, 0);
1531             }
1532         }
1533         break;
1534       default:
1535         j = 0;
1536         break;
1537       }
1538
1539       if (ix & 1)
1540           j = (j << 4);
1541       zcode_holding_area[opmodes_pc+ix/2] |= j;
1542     }
1543
1544     /* Print assembly trace. */
1545     if (asm_trace_level > 0) {
1546       int i;
1547       printf("%5d  +%05lx %3s %-12s ", ErrorReport.line_number,
1548         ((long int) offset),
1549         (at_seq_point)?"<*>":"   ", opco.name);
1550       for (i=0; i<AI->operand_count; i++) {
1551           if ((opco.flags & Br) && (i == opco.no-1)) {
1552             if (AI->operand[i].value == -4)
1553                 printf("to rtrue");
1554             else if (AI->operand[i].value == -3)
1555                 printf("to rfalse");
1556             else
1557                 printf("to L%d", AI->operand[i].value);
1558             }
1559           else {
1560             print_operand_g(&AI->operand[i], TRUE);
1561           }
1562           printf(" ");
1563       }
1564
1565       if (asm_trace_level>=2) {
1566         for (j=0;
1567             start_pc<zcode_ha_size;
1568             j++, start_pc++) {
1569             if (j%16==0) printf("\n                               ");
1570             if (/* DISABLES CODE */ (0)) {
1571                 printf("%02x ", zcode_holding_area[start_pc]);
1572             }
1573             else {
1574                 printf("%02x", zcode_holding_area[start_pc]);
1575                 if (zcode_markers[start_pc])
1576                     printf("{%02x}", zcode_markers[start_pc]);
1577                 printf(" ");
1578             }
1579         }
1580       }
1581       printf("\n");
1582     }
1583
1584     if (module_switch) flush_link_data();
1585
1586     return;
1587
1588     OpcodeSyntaxError:
1589
1590     make_opcode_syntax_g(opco);
1591     error_named("Assembly mistake: syntax is", opcode_syntax_string);
1592 }
1593
1594 /* Set up this label at zmachine_pc.
1595    This resets the execution_never_reaches_here flag, since every label
1596    is assumed to be reachable. 
1597    However, if STRIP_UNREACHABLE_LABELS and EXECSTATE_ENTIRE are both set,
1598    that's not true. The entire statement is being skipped, so we can safely
1599    skip all labels within it.
1600    (If STRIP_UNREACHABLE_LABELS is not set, the ENTIRE flag is ignored.)
1601 */
1602 extern void assemble_label_no(int n)
1603 {
1604     if ((execution_never_reaches_here & EXECSTATE_ENTIRE) && STRIP_UNREACHABLE_LABELS) {
1605         /* We're not going to compile this label at all. Set a negative
1606            offset, which will trip an error if this label is jumped to. */
1607         set_label_offset(n, -1);
1608         return;
1609     }
1610
1611     if (asm_trace_level > 0)
1612         printf("%5d  +%05lx    .L%d\n", ErrorReport.line_number,
1613             ((long int) zmachine_pc), n);
1614     set_label_offset(n, zmachine_pc);
1615     execution_never_reaches_here = EXECSTATE_REACHABLE;
1616 }
1617
1618 /* This is the same as assemble_label_no, except we only set up the label
1619    if there has been a forward branch to it.
1620    Returns whether the label is created.
1621    Only use this for labels which never have backwards branches!
1622 */
1623 extern int assemble_forward_label_no(int n)
1624 {
1625     if (n >= 0 && n < labeluse_size && labeluse[n]) {
1626         assemble_label_no(n);
1627         return TRUE;
1628     }
1629     else {
1630         /* There were no forward branches to this label and we promise
1631            there will be no backwards branches to it. Set a negative
1632            offset, which will trip an error if we break our promise. */
1633         set_label_offset(n, -1);
1634         return FALSE;
1635     }
1636 }
1637
1638 extern void define_symbol_label(int symbol)
1639 {
1640     int label = symbols[symbol].value;
1641     /* We may be creating a new label (label = next_label) or filling in
1642        the value of an old one. So we call ensure. */
1643     ensure_memory_list_available(&labels_memlist, label+1);
1644     labels[label].symbol = symbol;
1645 }
1646
1647 extern int32 assemble_routine_header(int no_locals,
1648     int routine_asterisked, char *name, int embedded_flag, int the_symbol)
1649 {   int i, rv;
1650     int stackargs = FALSE;
1651     int name_length;
1652
1653     execution_never_reaches_here = EXECSTATE_REACHABLE;
1654
1655     routine_locals = no_locals;
1656     
1657     ensure_memory_list_available(&variables_memlist, MAX_LOCAL_VARIABLES);
1658     for (i=0; i<MAX_LOCAL_VARIABLES; i++) variables[i].usage = FALSE;
1659
1660     if (no_locals >= 1
1661       && strcmpcis(local_variable_names[0].text, "_vararg_count")==0) {
1662       stackargs = TRUE;
1663     }
1664
1665     if (veneer_mode) routine_starts_line = blank_brief_location;
1666     else routine_starts_line = get_brief_location(&ErrorReport);
1667
1668     if (asm_trace_level > 0)
1669     {   printf("\n%5d  +%05lx  [ %s ", ErrorReport.line_number,
1670             ((long int) zmachine_pc), name);
1671         for (i=1; i<=no_locals; i++) printf("%s ", variable_name(i));
1672         printf("\n\n");
1673     }
1674
1675     routine_start_pc = zmachine_pc;
1676
1677     if (track_unused_routines) {
1678         /* The name of an embedded function is in a temporary buffer,
1679            so we shouldn't keep a reference to it. (It is sad that we
1680            have to know this here.) */
1681         char *funcname = name;
1682         if (embedded_flag)
1683             funcname = "<embedded>";
1684
1685         df_note_function_start(funcname, zmachine_pc, embedded_flag,
1686                                routine_starts_line);
1687     }
1688
1689     routine_symbol = the_symbol;
1690     name_length = strlen(name) + 1;
1691     ensure_memory_list_available(&current_routine_name, name_length);
1692     strncpy(current_routine_name.data, name, name_length);
1693
1694     /*  Update the routine counter                                           */
1695
1696     no_routines++;
1697
1698     /*  Actually assemble the routine header into the code area; note        */
1699     /*  Inform doesn't support the setting of local variables to default     */
1700     /*  values other than 0 in V3 and V4.  (In V5+ the Z-Machine doesn't     */
1701     /*  provide the possibility in any case.)                                */
1702
1703     if (!glulx_mode) {
1704
1705       if (stackargs) 
1706         warning("Z-code does not support stack-argument function definitions.");
1707
1708       byteout(no_locals, 0);
1709
1710       /*  Not the packed address, but the scaled offset from code area start:  */
1711
1712       rv = zmachine_pc/scale_factor;
1713
1714       if (instruction_set_number<5)
1715           for (i=0; i<no_locals; i++) { byteout(0,0); byteout(0,0); }
1716
1717       next_label = 0; next_sequence_point = 0; last_label = -1;
1718       labeluse_size = 0;
1719
1720       /*  Compile code to print out text like "a=3, b=4, c=5" when the       */
1721       /*  function is called, if it's required.                              */
1722
1723       if ((routine_asterisked) || (define_INFIX_switch))
1724       {   char fnt[256]; assembly_operand PV, RFA, CON, STP, SLF; int ln, ln2;
1725
1726           ln = next_label++;
1727           ln2 = next_label++;
1728
1729           if (define_INFIX_switch)
1730           {
1731                 if (embedded_flag)
1732             {   SLF.value = 251; SLF.type = VARIABLE_OT; SLF.marker = 0;
1733                   CON.value = 0; CON.type = SHORT_CONSTANT_OT; CON.marker = 0;
1734                 assemblez_2_branch(test_attr_zc, SLF, CON, ln2, FALSE);
1735             }
1736             else
1737             {   i = no_named_routines++;
1738                 ensure_memory_list_available(&named_routine_symbols_memlist, no_named_routines);
1739                 named_routine_symbols[i] = the_symbol;
1740                 CON.value = i/8; CON.type = LONG_CONSTANT_OT; CON.marker = 0;
1741                 RFA.value = routine_flags_array_SC;
1742                 RFA.type = LONG_CONSTANT_OT; RFA.marker = INCON_MV;
1743                 STP.value = 0; STP.type = VARIABLE_OT; STP.marker = 0;
1744                 assemblez_2_to(loadb_zc, RFA, CON, STP);
1745                 CON.value = (1 << (i%8)); CON.type = SHORT_CONSTANT_OT;
1746                 assemblez_2_to(and_zc, STP, CON, STP);
1747                 assemblez_1_branch(jz_zc, STP, ln2, TRUE);
1748             }
1749         }
1750         sprintf(fnt, "[ %s(", name);
1751         AI.text = fnt; assemblez_0(print_zc);
1752         for (i=1; (i<=7)&&(i<=no_locals); i++)
1753         {   if (version_number >= 5)
1754             {   PV.type = SHORT_CONSTANT_OT;
1755                 PV.value = i; PV.marker = 0;
1756                 assemblez_1_branch(check_arg_count_zc, PV, ln, FALSE);
1757             }
1758             sprintf(fnt, "%s%s = ", (i==1)?"":", ", variable_name(i));
1759             AI.text = fnt; assemblez_0(print_zc);
1760             PV.type = VARIABLE_OT; PV.value = i; PV.marker = 0;
1761             assemblez_1(print_num_zc, PV);
1762         }
1763         assemble_label_no(ln);
1764         sprintf(fnt, ") ]^"); AI.text = fnt;
1765         assemblez_0(print_zc);
1766         AI.text = NULL;
1767         assemble_label_no(ln2);
1768       }
1769
1770     }
1771     else {
1772       rv = zmachine_pc;
1773
1774       if (stackargs)
1775         byteout(0xC0, 0); /* Glulx type byte for function */
1776       else
1777         byteout(0xC1, 0); /* Glulx type byte for function */
1778
1779       /* Now the locals format list. This is simple; we only use
1780         four-byte locals. That's a single pair, unless we have more
1781         than 255 locals, or none at all. */
1782       i = no_locals;
1783       while (i) {
1784         int j = i;
1785         if (j > 255)
1786           j = 255;
1787         byteout(4, 0); 
1788         byteout(j, 0);
1789         i -= j;
1790       }
1791       /* Terminate the list with a (0, 0) pair. */
1792       byteout(0, 0);
1793       byteout(0, 0);
1794
1795       if (stackargs) {
1796         /* The top stack value is the number of function arguments. Let's
1797            move that into the first local, which is _vararg_count. */
1798         /* @copy sp _vararg_count; */
1799         byteout(0x40, 0); byteout(0x98, 0); byteout(0x00, 0);
1800       }
1801
1802       next_label = 0; next_sequence_point = 0; last_label = -1; 
1803       labeluse_size = 0;
1804
1805       if ((routine_asterisked) || (define_INFIX_switch)) {
1806         int ix;
1807         char fnt[256];
1808         assembly_operand AO, AO2;
1809         if (define_INFIX_switch) {
1810           /* This isn't supported */
1811           if (embedded_flag) {
1812           }
1813           else {
1814             i = no_named_routines++;
1815             ensure_memory_list_available(&named_routine_symbols_memlist, no_named_routines);
1816             named_routine_symbols[i] = the_symbol;
1817           }
1818         }
1819         sprintf(fnt, "[ %s(", name);
1820         AO.marker = STRING_MV;
1821         AO.type   = CONSTANT_OT;
1822         AO.value  = compile_string(fnt, STRCTX_INFIX);
1823         assembleg_1(streamstr_gc, AO);
1824
1825         if (!stackargs) {
1826           for (ix=1; ix<=no_locals; ix++) {
1827             sprintf(fnt, "%s%s = ", (ix==1)?"":", ", variable_name(ix));
1828             AO.marker = STRING_MV;
1829             AO.type   = CONSTANT_OT;
1830             AO.value  = compile_string(fnt, STRCTX_INFIX);
1831             assembleg_1(streamstr_gc, AO);
1832             AO.marker = 0;
1833             AO.type = LOCALVAR_OT;
1834             AO.value = ix;
1835             assembleg_1(streamnum_gc, AO);
1836           }
1837         }
1838         else {
1839           int lntop, lnbottom;
1840           sprintf(fnt, "%s = ", variable_name(1));
1841           AO.marker = STRING_MV;
1842           AO.type   = CONSTANT_OT;
1843           AO.value  = compile_string(fnt, STRCTX_INFIX);
1844           assembleg_1(streamstr_gc, AO);
1845           AO.marker = 0;
1846           AO.type = LOCALVAR_OT;
1847           AO.value = 1;
1848           assembleg_1(streamnum_gc, AO);
1849           AO2.type = BYTECONSTANT_OT;
1850           AO2.marker = 0;
1851           AO2.value = ':';
1852           assembleg_1(streamchar_gc, AO2);
1853           AO2.type = BYTECONSTANT_OT;
1854           AO2.marker = 0;
1855           AO2.value = ' ';
1856           /* for (temp_var4=0 : temp_var4<_vararg_count : temp_var4++) {
1857                @streamchar ' ';
1858                @stkpeek temp_var4 sp;
1859                @stream_num sp;
1860              }
1861           */
1862           assembleg_store(temp_var4, zero_operand);
1863           lntop = next_label++;
1864           lnbottom = next_label++;
1865           assemble_label_no(lntop);
1866           assembleg_2_branch(jge_gc, temp_var4, AO, lnbottom); /* AO is _vararg_count */
1867           assembleg_1(streamchar_gc, AO2); /* AO2 is space */
1868           assembleg_2(stkpeek_gc, temp_var4, stack_pointer);
1869           assembleg_1(streamnum_gc, stack_pointer);
1870           assembleg_3(add_gc, temp_var4, one_operand, temp_var4);
1871           assembleg_0_branch(jump_gc, lntop);
1872           assemble_label_no(lnbottom);
1873         }
1874
1875         AO.marker = STRING_MV;
1876         AO.type   = CONSTANT_OT;
1877         AO.value  = compile_string(") ]^", STRCTX_INFIX);
1878         assembleg_1(streamstr_gc, AO);
1879       }
1880     }
1881
1882     return rv;
1883 }
1884
1885 void assemble_routine_end(int embedded_flag, debug_locations locations)
1886 {   int32 i;
1887
1888     /* No marker is made in the Z-machine's code area to indicate the        */
1889     /* end of a routine.  Instead, we simply assemble a return opcode if     */
1890     /* need be (it won't be if the last instruction was, say, a "quit").     */
1891     /* The return value is true (1) for normal routines, false (0) for       */
1892     /* embedded routines (e.g. the library uses this for "before"            */
1893     /* properties).                                                          */
1894
1895     if (!execution_never_reaches_here)
1896     {   
1897       if (!glulx_mode) {
1898         if (embedded_flag) assemblez_0(rfalse_zc);
1899                       else assemblez_0(rtrue_zc);
1900       }
1901       else {
1902         assembly_operand AO;
1903         if (embedded_flag) 
1904             AO = zero_operand;
1905         else 
1906             AO = one_operand;
1907         assembleg_1(return_gc, AO);
1908       }
1909     }
1910
1911     /* Dump the contents of the current routine into longer-term Z-code
1912        storage                                                               */
1913
1914     if (!glulx_mode)
1915       transfer_routine_z();
1916     else
1917       transfer_routine_g();
1918
1919     if (track_unused_routines)
1920         df_note_function_end(zmachine_pc);
1921
1922     /* Tell the debugging file about the routine just ended.                 */
1923
1924     if (debugfile_switch)
1925     {
1926         char *routine_name = current_routine_name.data;
1927         debug_file_printf("<routine>");
1928         if (embedded_flag)
1929         {   debug_file_printf
1930                 ("<identifier artificial=\"true\">%s</identifier>",
1931                  routine_name);
1932         }
1933         else if (symbols[routine_symbol].flags & REPLACE_SFLAG)
1934         {   /* The symbol type will be set to ROUTINE_T once the replaced
1935                version has been given; if it is already set, we must be dealing
1936                with a replacement, and we can use the routine name as-is.
1937                Otherwise we look for a rename.  And if that doesn't work, we
1938                fall back to an artificial identifier. */
1939             if (symbols[routine_symbol].type == ROUTINE_T)
1940             {   /* Optional because there may be further replacements. */
1941                 write_debug_optional_identifier(routine_symbol);
1942             }
1943             else if (find_symbol_replacement(&routine_symbol))
1944             {   debug_file_printf
1945                     ("<identifier>%s</identifier>", symbols[routine_symbol].name);
1946             }
1947             else
1948             {   debug_file_printf
1949                     ("<identifier artificial=\"true\">%s (replaced)"
1950                          "</identifier>",
1951                      routine_name);
1952             }
1953         } else
1954         {   debug_file_printf("<identifier>%s</identifier>", routine_name);
1955         }
1956         debug_file_printf("<value>");
1957         if (glulx_mode)
1958         {   write_debug_code_backpatch(routine_start_pc);
1959         } else
1960         {   write_debug_packed_code_backpatch(routine_start_pc);
1961         }
1962         debug_file_printf("</value>");
1963         debug_file_printf("<address>");
1964         write_debug_code_backpatch(routine_start_pc);
1965         debug_file_printf("</address>");
1966         debug_file_printf
1967             ("<byte-count>%d</byte-count>", zmachine_pc - routine_start_pc);
1968         write_debug_locations(locations);
1969         for (i = 1; i <= routine_locals; ++i)
1970         {   debug_file_printf("<local-variable>");
1971             debug_file_printf("<identifier>%s</identifier>", variable_name(i));
1972             if (glulx_mode)
1973             {   debug_file_printf
1974                     ("<frame-offset>%d</frame-offset>", 4 * (i - 1));
1975             }
1976             else
1977             {   debug_file_printf("<index>%d</index>", i);
1978             }
1979             debug_file_printf("</local-variable>");
1980         }
1981         for (i = 0; i < next_sequence_point; ++i)
1982         {   debug_file_printf("<sequence-point>");
1983             debug_file_printf("<address>");
1984             write_debug_code_backpatch
1985                 (labels[sequence_points[i].label].offset);
1986             debug_file_printf("</address>");
1987             write_debug_location(sequence_points[i].location);
1988             debug_file_printf("</sequence-point>");
1989         }
1990         debug_file_printf("</routine>");
1991     }
1992
1993     /* Issue warnings about any local variables not used in the routine. */
1994
1995     for (i=1; i<=routine_locals; i++)
1996         if (!(variables[i].usage))
1997             dbnu_warning("Local variable", variable_name(i),
1998                 routine_starts_line);
1999
2000     for (i=0; i<next_label; i++)
2001     {   int j = labels[i].symbol;
2002         if (j != -1)
2003         {   if (symbols[j].flags & CHANGE_SFLAG)
2004                 error_named_at("Routine contains no such label as",
2005                     symbols[j].name, symbols[j].line);
2006             else
2007                 if ((symbols[j].flags & USED_SFLAG) == 0)
2008                     dbnu_warning("Label", symbols[j].name, symbols[j].line);
2009             symbols[j].type = CONSTANT_T;
2010             symbols[j].flags = UNKNOWN_SFLAG;
2011         }
2012     }
2013     no_sequence_points += next_sequence_point;
2014     next_label = 0; next_sequence_point = 0;
2015     labeluse_size = 0;
2016     execution_never_reaches_here = EXECSTATE_REACHABLE;
2017 }
2018
2019 /* ------------------------------------------------------------------------- */
2020 /*   Called when the holding area contains an entire routine of code:        */
2021 /*   backpatches the labels, issues module markers, then dumps the routine   */
2022 /*   into longer-term storage.                                               */
2023 /*                                                                           */
2024 /*   Note that in the code received, all branches have long form, and their  */
2025 /*   contents are not an offset but the label numbers they branch to.        */
2026 /*   Similarly, LABEL operands (those of "jump" instructions) are label      */
2027 /*   numbers.  So this routine must change the label numbers to offsets,     */
2028 /*   slimming the code down as it does so to take advantage of short-form    */
2029 /*   branch operands where possible.                                         */
2030 /*                                                                           */
2031 /*   zcode_ha_size is the number of bytes added since the last transfer      */
2032 /*   call. So we transfer starting at (zmachine_pc - zcode_ha_size). But we  */
2033 /*   might transfer fewer bytes than that.                                   */
2034 /* ------------------------------------------------------------------------- */
2035
2036 static void transfer_routine_z(void)
2037 {   int32 i, j, pc, new_pc, label, long_form, offset_of_next, addr,
2038           branch_on_true, rstart_pc;
2039     int32 adjusted_pc;
2040
2041     adjusted_pc = zmachine_pc - zcode_ha_size; rstart_pc = adjusted_pc;
2042
2043     if (asm_trace_level >= 3)
2044     {   printf("Backpatching routine at %05lx: initial size %d, %d labels\n",
2045              (long int) adjusted_pc, zcode_ha_size, next_label);
2046     }
2047
2048     /*  (1) Scan through for branches and make short/long decisions in each
2049             case.  Mark omitted bytes (2nd bytes in branches converted to
2050             short form) with DELETED_MV.
2051             We also look for jumps that can be entirely eliminated (because
2052             they are jumping to the very next instruction). The opcode and
2053             both label bytes get DELETED_MV. */
2054
2055     for (i=0, pc=adjusted_pc; i<zcode_ha_size; i++, pc++)
2056     {   if (zcode_markers[i] == BRANCH_MV)
2057         {   if (asm_trace_level >= 4)
2058                 printf("Branch detected at offset %04x\n", pc);
2059             j = (256*zcode_holding_area[i] + zcode_holding_area[i+1]) & 0x7fff;
2060             if (asm_trace_level >= 4)
2061                 printf("...To label %d, which is %d from here\n",
2062                     j, labels[j].offset-pc);
2063             if ((labels[j].offset >= pc+2) && (labels[j].offset < pc+64))
2064             {   if (asm_trace_level >= 4) printf("...Using short form\n");
2065                 zcode_markers[i+1] = DELETED_MV;
2066             }
2067         }
2068         else if (zcode_markers[i] == LABEL_MV)
2069         {
2070             if (asm_trace_level >= 4)
2071                 printf("Jump detected at offset %04x\n", pc);
2072             j = (256*zcode_holding_area[i] + zcode_holding_area[i+1]) & 0x7fff;
2073             if (asm_trace_level >= 4)
2074                 printf("...To label %d, which is %d from here\n",
2075                     j, labels[j].offset-pc);
2076             if (labels[j].offset-pc == 2 && i >= 1 && zcode_holding_area[i-1] == opcodes_table_z[jump_zc].code+128) {
2077                 if (asm_trace_level >= 4) printf("...Deleting jump\n");
2078                 zcode_markers[i-1] = DELETED_MV;
2079                 zcode_markers[i] = DELETED_MV;
2080                 zcode_markers[i+1] = DELETED_MV;
2081             }
2082         }
2083     }
2084
2085     /*  (2) Calculate the new positions of the labels.  Note that since the
2086             long/short decision was taken on the basis of the old labels,
2087             and since the new labels are slightly closer together because
2088             of branch bytes deleted, there may be a few further branch
2089             optimisations which are possible but which have been missed
2090             (if two labels move inside the "short" range as a result of
2091             a previous optimisation).  However, this is acceptably uncommon. */
2092
2093     if (next_label > 0)
2094     {   if (asm_trace_level >= 4)
2095         {   printf("Opening label: %d\n", first_label);
2096             for (i=0;i<next_label;i++)
2097                 printf("Label %d offset %04x next -> %d previous -> %d\n",
2098                     i, labels[i].offset, labels[i].next, labels[i].prev);
2099         }
2100
2101         /* label will advance through the linked list as pc increases. */
2102         for (i=0, pc=adjusted_pc, new_pc=adjusted_pc, label = first_label;
2103             i<zcode_ha_size; i++, pc++)
2104         {   while ((label != -1) && (labels[label].offset == pc))
2105             {   if (asm_trace_level >= 4)
2106                     printf("Position of L%d corrected from %04x to %04x\n",
2107                         label, labels[label].offset, new_pc);
2108                 labels[label].offset = new_pc;
2109                 label = labels[label].next;
2110             }
2111            if (zcode_markers[i] != DELETED_MV) new_pc++;
2112         }
2113     }
2114
2115     /*  (3) As we are transferring, replace the label numbers in branch
2116             operands with offsets to those labels.  Also issue markers, now
2117             that we know where they occur in the final Z-code area.          */
2118
2119     ensure_memory_list_available(&zcode_area_memlist, adjusted_pc+zcode_ha_size);
2120     
2121     for (i=0, new_pc=adjusted_pc; i<zcode_ha_size; i++)
2122     {   switch(zcode_markers[i])
2123         { case BRANCH_MV:
2124             long_form = 1; if (zcode_markers[i+1] == DELETED_MV) long_form = 0;
2125
2126             j = (256*zcode_holding_area[i] + zcode_holding_area[i+1]) & 0x7fff;
2127             branch_on_true = ((zcode_holding_area[i]) & 0x80);
2128             offset_of_next = new_pc + long_form + 1;
2129
2130             if (labels[j].offset < 0) {
2131                 error("Attempt to jump to an unreachable label");
2132                 addr = 0;
2133             }
2134             else {
2135                 addr = labels[j].offset - offset_of_next + 2;
2136             }
2137             if (addr<-0x2000 || addr>0x1fff) 
2138                 fatalerror("Branch out of range: divide the routine up?");
2139             if (addr<0) addr+=(int32) 0x10000L;
2140
2141             addr=addr&0x3fff;
2142             if (long_form==1)
2143             {   zcode_holding_area[i] = branch_on_true + addr/256;
2144                 zcode_holding_area[i+1] = addr%256;
2145             }
2146             else
2147             {   if (addr >= 64)
2148                 {   compiler_error("Label out of range for branch");
2149                     printf("Addr is %04x\n", addr);
2150                 }
2151                 zcode_holding_area[i] = branch_on_true + 0x40 + (addr&0x3f);
2152             }
2153             zcode_area[adjusted_pc++] = zcode_holding_area[i]; new_pc++;
2154             break;
2155
2156           case LABEL_MV:
2157             j = 256*zcode_holding_area[i] + zcode_holding_area[i+1];
2158             if (labels[j].offset < 0) {
2159                 error("Attempt to jump to an unreachable label");
2160                 addr = 0;
2161             }
2162             else {
2163                 addr = labels[j].offset - new_pc;
2164             }
2165             if (addr<-0x8000 || addr>0x7fff) 
2166                 fatalerror("Jump out of range: divide the routine up?");
2167             if (addr<0) addr += (int32) 0x10000L;
2168             zcode_holding_area[i] = addr/256;
2169             zcode_holding_area[i+1] = addr%256;
2170             zcode_area[adjusted_pc++] = zcode_holding_area[i]; new_pc++;
2171             break;
2172
2173           case DELETED_MV:
2174             break;
2175
2176           default:
2177             switch(zcode_markers[i] & 0x7f)
2178             {   case NULL_MV: break;
2179                 case VARIABLE_MV:
2180                 case OBJECT_MV:
2181                 case ACTION_MV:
2182                 case IDENT_MV:
2183                     if (!module_switch) break;
2184                 default:
2185                     if ((zcode_markers[i] & 0x7f) > LARGEST_BPATCH_MV)
2186                     {   compiler_error("Illegal code backpatch value");
2187                         printf("Illegal value of %02x at PC = %04x\n",
2188                             zcode_markers[i] & 0x7f, new_pc);
2189                         break;
2190                     }
2191
2192                     if (bpatch_trace_setting >= 2)
2193                         printf("BP added: MV %d PC %04x\n", zcode_markers[i], new_pc);
2194
2195                     ensure_memory_list_available(&zcode_backpatch_table_memlist, zcode_backpatch_size+3);
2196                     zcode_backpatch_table[zcode_backpatch_size++] = zcode_markers[i] + 32*(new_pc/65536);
2197                     zcode_backpatch_table[zcode_backpatch_size++] = (new_pc/256)%256;
2198                     zcode_backpatch_table[zcode_backpatch_size++] = new_pc%256;
2199                     break;
2200             }
2201             zcode_area[adjusted_pc++] = zcode_holding_area[i]; new_pc++;
2202             break;
2203         }
2204     }
2205
2206     /* Consistency check */
2207     if (new_pc - rstart_pc > zcode_ha_size || adjusted_pc != new_pc)
2208     {
2209         fatalerror("Optimisation increased routine length or failed to match; should not happen");
2210     }
2211
2212     if (asm_trace_level >= 3)
2213     {   printf("After branch optimisation, routine length is %d bytes\n",
2214              new_pc - rstart_pc);
2215     }
2216
2217     /*  Insert null bytes if necessary to ensure the next routine address is */
2218     /*  expressible as a packed address                                      */
2219
2220     ensure_memory_list_available(&zcode_area_memlist, adjusted_pc+2*scale_factor);
2221
2222     if (oddeven_packing_switch)
2223         while ((adjusted_pc%(scale_factor*2))!=0) zcode_area[adjusted_pc++] = 0;
2224     else
2225         while ((adjusted_pc%scale_factor)!=0) zcode_area[adjusted_pc++] = 0;
2226
2227     zmachine_pc = adjusted_pc;
2228     zcode_ha_size = 0;
2229 }
2230
2231 static void transfer_routine_g(void)
2232 {   int32 i, j, pc, new_pc, label, form_len, offset_of_next, addr,
2233           rstart_pc;
2234     int32 adjusted_pc;
2235
2236     adjusted_pc = zmachine_pc - zcode_ha_size; rstart_pc = adjusted_pc;
2237
2238     if (asm_trace_level >= 3)
2239     {   printf("Backpatching routine at %05lx: initial size %d, %d labels\n",
2240              (long int) adjusted_pc, zcode_ha_size, next_label);
2241     }
2242
2243     /*  (1) Scan through for branches and make short/long decisions in each
2244             case.  Mark omitted bytes (bytes 2-4 in branches converted to
2245             short form) with DELETED_MV.
2246             We also look for branches that can be entirely eliminated (because
2247             they are jumping to the very next instruction). The opcode and
2248             all label bytes get DELETED_MV. */
2249
2250     for (i=0, pc=adjusted_pc; i<zcode_ha_size; i++, pc++) {
2251       if (zcode_markers[i] >= BRANCH_MV && zcode_markers[i] < BRANCHMAX_MV) {
2252         int opmodeoffset = (zcode_markers[i] - BRANCH_MV);
2253         int32 opmodebyte;
2254         if (asm_trace_level >= 4)
2255             printf("Branch detected at offset %04x\n", pc);
2256         j = ((zcode_holding_area[i] << 24) 
2257             | (zcode_holding_area[i+1] << 16)
2258             | (zcode_holding_area[i+2] << 8)
2259             | (zcode_holding_area[i+3]));
2260         offset_of_next = pc + 4;
2261         addr = (labels[j].offset - offset_of_next) + 2;
2262         opmodebyte = i - ((opmodeoffset+1)/2);
2263         if (asm_trace_level >= 4)
2264             printf("...To label %d, which is (%d-2) = %d from here\n",
2265                 j, addr, labels[j].offset - offset_of_next);
2266         if (addr == 2 && i >= 2 && opmodeoffset == 2 && zcode_holding_area[opmodebyte-1] == opcodes_table_g[jump_gc].code) {
2267             if (asm_trace_level >= 4) printf("...Deleting branch\n");
2268             zcode_markers[i-2] = DELETED_MV;
2269             zcode_markers[i-1] = DELETED_MV;
2270             zcode_markers[i] = DELETED_MV;
2271             zcode_markers[i+1] = DELETED_MV;
2272             zcode_markers[i+2] = DELETED_MV;
2273             zcode_markers[i+3] = DELETED_MV;
2274         }
2275         else if (addr >= -0x80 && addr < 0x80) {
2276             if (asm_trace_level >= 4) printf("...Byte form\n");
2277             zcode_markers[i+1] = DELETED_MV;
2278             zcode_markers[i+2] = DELETED_MV;
2279             zcode_markers[i+3] = DELETED_MV;
2280             if ((opmodeoffset & 1) == 0)
2281                 zcode_holding_area[opmodebyte] = 
2282                     (zcode_holding_area[opmodebyte] & 0xF0) | 0x01;
2283             else
2284                 zcode_holding_area[opmodebyte] = 
2285                     (zcode_holding_area[opmodebyte] & 0x0F) | 0x10;
2286         }
2287         else if (addr >= -0x8000 && addr < 0x8000) {
2288             if (asm_trace_level >= 4) printf("...Short form\n");
2289             zcode_markers[i+2] = DELETED_MV;
2290             zcode_markers[i+3] = DELETED_MV;
2291             if ((opmodeoffset & 1) == 0)
2292                 zcode_holding_area[opmodebyte] = 
2293                     (zcode_holding_area[opmodebyte] & 0xF0) | 0x02;
2294             else
2295                 zcode_holding_area[opmodebyte] = 
2296                     (zcode_holding_area[opmodebyte] & 0x0F) | 0x20;
2297         }
2298       }
2299     }
2300
2301     /*  (2) Calculate the new positions of the labels.  Note that since the
2302             long/short decision was taken on the basis of the old labels,
2303             and since the new labels are slightly closer together because
2304             of branch bytes deleted, there may be a few further branch
2305             optimisations which are possible but which have been missed
2306             (if two labels move inside the "short" range as a result of
2307             a previous optimisation).  However, this is acceptably uncommon. */
2308     if (next_label > 0) {
2309       if (asm_trace_level >= 4) {
2310         printf("Opening label: %d\n", first_label);
2311         for (i=0;i<next_label;i++)
2312             printf("Label %d offset %04x next -> %d previous -> %d\n",
2313                 i, labels[i].offset, labels[i].next, labels[i].prev);
2314       }
2315
2316       /* label will advance through the linked list as pc increases. */
2317       for (i=0, pc=adjusted_pc, new_pc=adjusted_pc, label = first_label;
2318         i<zcode_ha_size; 
2319         i++, pc++) {
2320         while ((label != -1) && (labels[label].offset == pc)) {
2321             if (asm_trace_level >= 4)
2322                 printf("Position of L%d corrected from %04x to %04x\n",
2323                 label, labels[label].offset, new_pc);
2324             labels[label].offset = new_pc;
2325             label = labels[label].next;
2326         }
2327         if (zcode_markers[i] != DELETED_MV) new_pc++;
2328       }
2329     }
2330
2331     /*  (3) As we are transferring, replace the label numbers in branch
2332             operands with offsets to those labels.  Also issue markers, now
2333             that we know where they occur in the final Z-code area.          */
2334
2335     ensure_memory_list_available(&zcode_area_memlist, adjusted_pc+zcode_ha_size);
2336     
2337     for (i=0, new_pc=adjusted_pc; i<zcode_ha_size; i++) {
2338
2339       if (zcode_markers[i] >= BRANCH_MV && zcode_markers[i] < BRANCHMAX_MV) {
2340         form_len = 4;
2341         if (zcode_markers[i+1] == DELETED_MV) {
2342             form_len = 1;
2343         }
2344         else {
2345             if (zcode_markers[i+2] == DELETED_MV)
2346                 form_len = 2;
2347         }
2348         j = ((zcode_holding_area[i] << 24) 
2349             | (zcode_holding_area[i+1] << 16)
2350             | (zcode_holding_area[i+2] << 8)
2351             | (zcode_holding_area[i+3]));
2352
2353         /* At the moment, we can safely assume that the branch operand
2354            is the end of the opcode, so the next opcode starts right
2355            after it. */
2356         offset_of_next = new_pc + form_len;
2357
2358         if (labels[j].offset < 0) {
2359             error("Attempt to jump to an unreachable label");
2360             addr = 0;
2361         }
2362         else {
2363             addr = (labels[j].offset - offset_of_next) + 2;
2364         }
2365         if (asm_trace_level >= 4) {
2366             printf("Branch at offset %04x: %04x (%s)\n",
2367                 new_pc, addr, ((form_len == 1) ? "byte" :
2368                 ((form_len == 2) ? "short" : "long")));
2369         }
2370         if (form_len == 1) {
2371             if (addr < -0x80 || addr >= 0x80) {
2372                 error("*** Label out of range for byte branch ***");
2373             }
2374             zcode_holding_area[i] = (addr) & 0xFF;
2375         }
2376         else if (form_len == 2) {
2377             if (addr < -0x8000 || addr >= 0x8000) {
2378                 error("*** Label out of range for short branch ***");
2379             }
2380             zcode_holding_area[i] = (addr >> 8) & 0xFF;
2381             zcode_holding_area[i+1] = (addr) & 0xFF;
2382         }
2383         else {
2384             zcode_holding_area[i] = (addr >> 24) & 0xFF;
2385             zcode_holding_area[i+1] = (addr >> 16) & 0xFF;
2386             zcode_holding_area[i+2] = (addr >> 8) & 0xFF;
2387             zcode_holding_area[i+3] = (addr) & 0xFF;
2388         }
2389         zcode_area[adjusted_pc++] = zcode_holding_area[i]; new_pc++;
2390       }
2391       else if (zcode_markers[i] == LABEL_MV) {
2392           error("*** No LABEL opcodes in Glulx ***");
2393       }
2394       else if (zcode_markers[i] == DELETED_MV) {
2395         /* skip it */
2396       }
2397       else {
2398         switch(zcode_markers[i] & 0x7f) {
2399         case NULL_MV: 
2400             break;
2401         case ACTION_MV:
2402         case IDENT_MV:
2403             if (!module_switch) break;
2404         case OBJECT_MV:
2405         case VARIABLE_MV:
2406         default:
2407             if ((zcode_markers[i] & 0x7f) > LARGEST_BPATCH_MV) {
2408                 error("*** Illegal code backpatch value ***");
2409                 printf("Illegal value of %02x at PC = %04x\n",
2410                 zcode_markers[i] & 0x7f, new_pc);
2411                 break;
2412             }
2413           /* The backpatch table format for Glulx:
2414              First, the marker byte (0..LARGEST_BPATCH_MV).
2415              Then a byte indicating the data size to be patched (1, 2, 4).
2416              Then the four-byte address (new_pc).
2417           */
2418           if (bpatch_trace_setting >= 2)
2419               printf("BP added: MV %d size %d PC %04x\n", zcode_markers[i], 4, new_pc);
2420           ensure_memory_list_available(&zcode_backpatch_table_memlist, zcode_backpatch_size+6);
2421           zcode_backpatch_table[zcode_backpatch_size++] = zcode_markers[i];
2422           zcode_backpatch_table[zcode_backpatch_size++] = 4;
2423           zcode_backpatch_table[zcode_backpatch_size++] = ((new_pc >> 24) & 0xFF);
2424           zcode_backpatch_table[zcode_backpatch_size++] = ((new_pc >> 16) & 0xFF);
2425           zcode_backpatch_table[zcode_backpatch_size++] = ((new_pc >> 8) & 0xFF);
2426           zcode_backpatch_table[zcode_backpatch_size++] = (new_pc & 0xFF);
2427           break;
2428         }
2429         zcode_area[adjusted_pc++] = zcode_holding_area[i]; new_pc++;
2430       }
2431     }
2432
2433     /* Consistency check */
2434     if (new_pc - rstart_pc > zcode_ha_size || adjusted_pc != new_pc)
2435     {
2436         fatalerror("Optimisation increased routine length or failed to match; should not happen");
2437     }
2438
2439     if (asm_trace_level >= 3)
2440     {   printf("After branch optimisation, routine length is %d bytes\n",
2441              new_pc - rstart_pc);
2442     }
2443
2444     zmachine_pc = adjusted_pc;
2445     zcode_ha_size = 0;
2446 }
2447
2448
2449 /* ========================================================================= */
2450 /*   Front ends for the instruction assembler: convenient shorthand forms    */
2451 /*   used in various code generation routines all over Inform.               */
2452 /* ------------------------------------------------------------------------- */
2453
2454 void assemble_jump(int n)
2455 {
2456     if (!glulx_mode)
2457         assemblez_jump(n);
2458     else
2459         assembleg_jump(n);
2460 }
2461
2462 void assemblez_0(int internal_number)
2463 {   AI.internal_number = internal_number;
2464     AI.operand_count = 0;
2465     AI.store_variable_number = -1;
2466     AI.branch_label_number = -1;
2467     assemblez_instruction(&AI);
2468 }
2469
2470 void assemblez_0_to(int internal_number, assembly_operand o)
2471 {   AI.internal_number = internal_number;
2472     AI.operand_count = 0;
2473     AI.store_variable_number = o.value;
2474     AI.branch_label_number = -1;
2475     assemblez_instruction(&AI);
2476 }
2477
2478 void assemblez_0_branch(int internal_number, int label, int flag)
2479 {   AI.internal_number = internal_number;
2480     AI.operand_count = 0;
2481     AI.store_variable_number = -1;
2482     AI.branch_label_number = label;
2483     AI.branch_flag = flag;
2484     assemblez_instruction(&AI);
2485 }
2486
2487 void assemblez_1(int internal_number, assembly_operand o1)
2488 {   AI.internal_number = internal_number;
2489     AI.operand_count = 1;
2490     AI.operand[0] = o1;
2491     AI.store_variable_number = -1;
2492     AI.branch_label_number = -1;
2493     assemblez_instruction(&AI);
2494 }
2495
2496 void assemblez_1_to(int internal_number,
2497     assembly_operand o1, assembly_operand st)
2498 {   AI.internal_number = internal_number;
2499     AI.operand_count = 1;
2500     AI.operand[0] = o1;
2501     AI.store_variable_number = st.value;
2502     AI.branch_label_number = -1;
2503     assemblez_instruction(&AI);
2504 }
2505
2506 void assemblez_1_branch(int internal_number,
2507     assembly_operand o1, int label, int flag)
2508 {
2509     /* Some clever optimizations first. A constant is always or never equal
2510        to zero. */
2511     if (o1.marker == 0 && is_constant_ot(o1.type)) {
2512         if (internal_number == jz_zc) {
2513             if ((flag && o1.value == 0) || (!flag && o1.value != 0)) {
2514                 assemblez_jump(label);
2515                 return;
2516             }
2517             else {
2518                 /* assemble nothing at all! */
2519                 return;
2520             }
2521         }
2522     }
2523     AI.internal_number = internal_number;
2524     AI.operand_count = 1;
2525     AI.operand[0] = o1;
2526     AI.branch_label_number = label;
2527     AI.store_variable_number = -1;
2528     AI.branch_flag = flag;
2529     assemblez_instruction(&AI);
2530 }
2531
2532 void assemblez_2(int internal_number,
2533     assembly_operand o1, assembly_operand o2)
2534 {   AI.internal_number = internal_number;
2535     AI.operand_count = 2;
2536     AI.operand[0] = o1;
2537     AI.operand[1] = o2;
2538     AI.store_variable_number = -1;
2539     AI.branch_label_number = -1;
2540     assemblez_instruction(&AI);
2541 }
2542
2543 void assemblez_3(int internal_number,
2544     assembly_operand o1, assembly_operand o2, assembly_operand o3)
2545 {   AI.internal_number = internal_number;
2546     AI.operand_count = 3;
2547     AI.operand[0] = o1;
2548     AI.operand[1] = o2;
2549     AI.operand[2] = o3;
2550     AI.store_variable_number = -1;
2551     AI.branch_label_number = -1;
2552     assemblez_instruction(&AI);
2553 }
2554
2555 void assemblez_3_to(int internal_number,
2556     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2557     assembly_operand st)
2558 {   AI.internal_number = internal_number;
2559     AI.operand_count = 3;
2560     AI.operand[0] = o1;
2561     AI.operand[1] = o2;
2562     AI.operand[2] = o3;
2563     AI.store_variable_number = st.value;
2564     AI.branch_label_number = -1;
2565     assemblez_instruction(&AI);
2566 }
2567
2568 void assemblez_3_branch(int internal_number,
2569     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2570     int label, int flag)
2571 {   AI.internal_number = internal_number;
2572     AI.operand_count = 3;
2573     AI.operand[0] = o1;
2574     AI.operand[1] = o2;
2575     AI.operand[2] = o3;
2576     AI.store_variable_number = -1;
2577     AI.branch_label_number = label;
2578     AI.branch_flag = flag;
2579     assemblez_instruction(&AI);
2580 }
2581
2582 void assemblez_4(int internal_number,
2583     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2584     assembly_operand o4)
2585 {   AI.internal_number = internal_number;
2586     AI.operand_count = 4;
2587     AI.operand[0] = o1;
2588     AI.operand[1] = o2;
2589     AI.operand[2] = o3;
2590     AI.operand[3] = o4;
2591     AI.store_variable_number = -1;
2592     AI.branch_label_number = -1;
2593     assemblez_instruction(&AI);
2594 }
2595
2596 void assemblez_5(int internal_number,
2597     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2598     assembly_operand o4, assembly_operand o5)
2599 {   AI.internal_number = internal_number;
2600     AI.operand_count = 5;
2601     AI.operand[0] = o1;
2602     AI.operand[1] = o2;
2603     AI.operand[2] = o3;
2604     AI.operand[3] = o4;
2605     AI.operand[4] = o5;
2606     AI.store_variable_number = -1;
2607     AI.branch_label_number = -1;
2608     assemblez_instruction(&AI);
2609 }
2610
2611 void assemblez_6(int internal_number,
2612     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2613     assembly_operand o4, assembly_operand o5, assembly_operand o6)
2614 {   AI.internal_number = internal_number;
2615     AI.operand_count = 6;
2616     AI.operand[0] = o1;
2617     AI.operand[1] = o2;
2618     AI.operand[2] = o3;
2619     AI.operand[3] = o4;
2620     AI.operand[4] = o5;
2621     AI.operand[5] = o6;
2622     AI.store_variable_number = -1;
2623     AI.branch_label_number = -1;
2624     assemblez_instruction(&AI);
2625 }
2626
2627 void assemblez_4_branch(int internal_number,
2628     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2629     assembly_operand o4, int label, int flag)
2630 {   AI.internal_number = internal_number;
2631     AI.operand_count = 4;
2632     AI.operand[0] = o1;
2633     AI.operand[1] = o2;
2634     AI.operand[2] = o3;
2635     AI.operand[3] = o4;
2636     AI.store_variable_number = -1;
2637     AI.branch_label_number = label;
2638     AI.branch_flag = flag;
2639     assemblez_instruction(&AI);
2640 }
2641
2642 void assemblez_4_to(int internal_number,
2643     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2644     assembly_operand o4, assembly_operand st)
2645 {   AI.internal_number = internal_number;
2646     AI.operand_count = 4;
2647     AI.operand[0] = o1;
2648     AI.operand[1] = o2;
2649     AI.operand[2] = o3;
2650     AI.operand[3] = o4;
2651     AI.store_variable_number = st.value;
2652     AI.branch_label_number = -1;
2653     assemblez_instruction(&AI);
2654 }
2655
2656 void assemblez_5_to(int internal_number,
2657     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2658     assembly_operand o4, assembly_operand o5, assembly_operand st)
2659 {   AI.internal_number = internal_number;
2660     AI.operand_count = 5;
2661     AI.operand[0] = o1;
2662     AI.operand[1] = o2;
2663     AI.operand[2] = o3;
2664     AI.operand[3] = o4;
2665     AI.operand[4] = o5;
2666     AI.store_variable_number = st.value;
2667     AI.branch_label_number = -1;
2668     assemblez_instruction(&AI);
2669 }
2670
2671 void assemblez_2_to(int internal_number,
2672     assembly_operand o1, assembly_operand o2, assembly_operand st)
2673 {   AI.internal_number = internal_number;
2674     AI.operand_count = 2;
2675     AI.operand[0] = o1;
2676     AI.operand[1] = o2;
2677     AI.store_variable_number = st.value;
2678     AI.branch_label_number = -1;
2679     assemblez_instruction(&AI);
2680 }
2681
2682 void assemblez_2_branch(int internal_number,
2683     assembly_operand o1, assembly_operand o2, int label, int flag)
2684 {   AI.internal_number = internal_number;
2685     AI.operand_count = 2;
2686     AI.operand[0] = o1;
2687     AI.operand[1] = o2;
2688     AI.branch_label_number = label;
2689     AI.store_variable_number = -1;
2690     AI.branch_flag = flag;
2691     assemblez_instruction(&AI);
2692 }
2693
2694 void assemblez_objcode(int internal_number,
2695     assembly_operand o1, assembly_operand st, int label, int flag)
2696 {   AI.internal_number = internal_number;
2697     AI.operand_count = 1;
2698     AI.operand[0] = o1;
2699     AI.branch_label_number = label;
2700     AI.store_variable_number = st.value;
2701     AI.branch_flag = flag;
2702     assemblez_instruction(&AI);
2703 }
2704
2705 extern void assemblez_inc(assembly_operand o1)
2706 {   int m = 0;
2707     if ((o1.value >= MAX_LOCAL_VARIABLES) 
2708         && (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
2709             m = VARIABLE_MV;
2710     AI.internal_number = inc_zc;
2711     AI.operand_count = 1;
2712     AI.operand[0].value = o1.value;
2713     AI.operand[0].type = SHORT_CONSTANT_OT;
2714     AI.operand[0].marker = m;
2715     AI.store_variable_number = -1;
2716     AI.branch_label_number = -1;
2717     assemblez_instruction(&AI);
2718 }
2719
2720 extern void assemblez_dec(assembly_operand o1)
2721 {   int m = 0;
2722     if ((o1.value >= MAX_LOCAL_VARIABLES) 
2723         && (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
2724             m = VARIABLE_MV;
2725     AI.internal_number = dec_zc;
2726     AI.operand_count = 1;
2727     AI.operand[0].value = o1.value;
2728     AI.operand[0].type = SHORT_CONSTANT_OT;
2729     AI.operand[0].marker = m;
2730     AI.store_variable_number = -1;
2731     AI.branch_label_number = -1;
2732     assemblez_instruction(&AI);
2733 }
2734
2735 extern void assemblez_store(assembly_operand o1, assembly_operand o2)
2736 {   int m = 0;
2737     if ((o1.value >= MAX_LOCAL_VARIABLES)
2738         && (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
2739             m = VARIABLE_MV;
2740
2741     if ((o2.type == VARIABLE_OT) && (o2.value == 0))
2742     {
2743         /*  Assemble "pull VAR" rather than "store VAR sp",
2744             saving 1 byte  */
2745
2746         AI.internal_number = pull_zc;
2747         if (instruction_set_number == 6)
2748         {   AI.operand_count = 0;
2749             AI.store_variable_number = o1.value;
2750         }
2751         else
2752         {   AI.operand_count = 1;
2753             AI.operand[0].value = o1.value;
2754             AI.operand[0].type = SHORT_CONSTANT_OT;
2755             AI.operand[0].marker = m;
2756             AI.store_variable_number = -1;
2757         }
2758         AI.branch_label_number = -1;
2759         assemblez_instruction(&AI);
2760         return;
2761     }
2762
2763     if ((o1.type == VARIABLE_OT) && (o1.value == 0))
2764     {   /*  Assemble "push VAR" rather than "store sp VAR",
2765             saving 1 byte  */
2766
2767         AI.internal_number = push_zc;
2768         AI.operand_count = 1;
2769         AI.operand[0] = o2;
2770         AI.store_variable_number = -1;
2771         AI.branch_label_number = -1;
2772         assemblez_instruction(&AI);
2773         return;
2774     }
2775     AI.internal_number = store_zc;
2776     AI.operand_count = 2;
2777     AI.operand[0].value = o1.value;
2778     AI.operand[0].type = SHORT_CONSTANT_OT;
2779     AI.operand[0].marker = m;
2780     AI.operand[1] = o2;
2781     AI.store_variable_number = -1;
2782     AI.branch_label_number = -1;
2783     assemblez_instruction(&AI);
2784 }
2785
2786 void assemblez_jump(int n)
2787 {   assembly_operand AO;
2788     if (n==-4) assemblez_0(rtrue_zc);
2789     else if (n==-3) assemblez_0(rfalse_zc);
2790     else
2791     {   AO.type = LONG_CONSTANT_OT; AO.value = n; AO.marker = 0;
2792         assemblez_1(jump_zc, AO);
2793     }
2794 }
2795
2796 void assembleg_0(int internal_number)
2797 {   AI.internal_number = internal_number;
2798     AI.operand_count = 0;
2799     assembleg_instruction(&AI);
2800 }
2801
2802 void assembleg_1(int internal_number, assembly_operand o1)
2803 {   AI.internal_number = internal_number;
2804     AI.operand_count = 1;
2805     AI.operand[0] = o1;
2806     assembleg_instruction(&AI);
2807 }
2808
2809 void assembleg_2(int internal_number, assembly_operand o1,
2810   assembly_operand o2)
2811 {   AI.internal_number = internal_number;
2812     AI.operand_count = 2;
2813     AI.operand[0] = o1;
2814     AI.operand[1] = o2;
2815     assembleg_instruction(&AI);
2816 }
2817
2818 void assembleg_3(int internal_number, assembly_operand o1,
2819   assembly_operand o2, assembly_operand o3)
2820 {   AI.internal_number = internal_number;
2821     AI.operand_count = 3;
2822     AI.operand[0] = o1;
2823     AI.operand[1] = o2;
2824     AI.operand[2] = o3;
2825     assembleg_instruction(&AI);
2826 }
2827
2828 void assembleg_4(int internal_number, assembly_operand o1,
2829   assembly_operand o2, assembly_operand o3,
2830   assembly_operand o4)
2831 {   AI.internal_number = internal_number;
2832     AI.operand_count = 4;
2833     AI.operand[0] = o1;
2834     AI.operand[1] = o2;
2835     AI.operand[2] = o3;
2836     AI.operand[3] = o4;
2837     assembleg_instruction(&AI);
2838 }
2839
2840 void assembleg_5(int internal_number, assembly_operand o1,
2841   assembly_operand o2, assembly_operand o3,
2842   assembly_operand o4, assembly_operand o5)
2843 {   AI.internal_number = internal_number;
2844     AI.operand_count = 5;
2845     AI.operand[0] = o1;
2846     AI.operand[1] = o2;
2847     AI.operand[2] = o3;
2848     AI.operand[3] = o4;
2849     AI.operand[4] = o5;
2850     assembleg_instruction(&AI);
2851 }
2852
2853 void assembleg_0_branch(int internal_number,
2854     int label)
2855 {
2856     AI.internal_number = internal_number;
2857     AI.operand_count = 1;
2858     AI.operand[0].type = CONSTANT_OT;
2859     AI.operand[0].value = label;
2860     AI.operand[0].marker = BRANCH_MV;
2861     assembleg_instruction(&AI);
2862 }
2863
2864 void assembleg_1_branch(int internal_number,
2865     assembly_operand o1, int label)
2866 {
2867     /* Some clever optimizations first. A constant is always or never equal
2868        to zero. */
2869     if (o1.marker == 0 && is_constant_ot(o1.type)) {
2870         if ((internal_number == jz_gc && o1.value == 0)
2871           || (internal_number == jnz_gc && o1.value != 0)) {
2872             assembleg_0_branch(jump_gc, label);
2873             return;
2874         }
2875         if ((internal_number == jz_gc && o1.value != 0)
2876           || (internal_number == jnz_gc && o1.value == 0)) {
2877             /* assemble nothing at all! */
2878             return;
2879         }
2880     }
2881     AI.internal_number = internal_number;
2882     AI.operand_count = 2;
2883     AI.operand[0] = o1;
2884     AI.operand[1].type = CONSTANT_OT;
2885     AI.operand[1].value = label;
2886     AI.operand[1].marker = BRANCH_MV;
2887     assembleg_instruction(&AI);
2888 }
2889
2890 void assembleg_2_branch(int internal_number,
2891     assembly_operand o1, assembly_operand o2, int label)
2892 {
2893     AI.internal_number = internal_number;
2894     AI.operand_count = 3;
2895     AI.operand[0] = o1;
2896     AI.operand[1] = o2;
2897     AI.operand[2].type = CONSTANT_OT;
2898     AI.operand[2].value = label;
2899     AI.operand[2].marker = BRANCH_MV;
2900     assembleg_instruction(&AI);
2901 }
2902
2903 void assembleg_call_1(assembly_operand oaddr, assembly_operand o1, 
2904   assembly_operand odest)
2905 {
2906   assembleg_3(callfi_gc, oaddr, o1, odest);
2907 }
2908
2909 void assembleg_call_2(assembly_operand oaddr, assembly_operand o1, 
2910   assembly_operand o2, assembly_operand odest)
2911 {
2912   assembleg_4(callfii_gc, oaddr, o1, o2, odest);
2913 }
2914
2915 void assembleg_call_3(assembly_operand oaddr, assembly_operand o1, 
2916   assembly_operand o2, assembly_operand o3, assembly_operand odest)
2917 {
2918   assembleg_5(callfiii_gc, oaddr, o1, o2, o3, odest);
2919 }
2920
2921 void assembleg_inc(assembly_operand o1)
2922 {
2923   AI.internal_number = add_gc;
2924   AI.operand_count = 3;
2925   AI.operand[0] = o1;
2926   AI.operand[1] = one_operand;
2927   AI.operand[2] = o1;
2928   assembleg_instruction(&AI);
2929 }
2930
2931 void assembleg_dec(assembly_operand o1)
2932 {
2933   AI.internal_number = sub_gc;
2934   AI.operand_count = 3;
2935   AI.operand[0] = o1;
2936   AI.operand[1] = one_operand;
2937   AI.operand[2] = o1;
2938   assembleg_instruction(&AI);
2939 }
2940
2941 void assembleg_store(assembly_operand o1, assembly_operand o2)
2942 {
2943     /* Note the order is reversed: "o1 = o2;" */
2944     assembleg_2(copy_gc, o2, o1);
2945 }
2946
2947 void assembleg_jump(int n)
2948 {
2949   if (n==-4) {
2950       assembleg_1(return_gc, one_operand);
2951   }
2952   else if (n==-3) {
2953       assembleg_1(return_gc, zero_operand); 
2954   }
2955   else {
2956       assembleg_0_branch(jump_gc, n);
2957   }
2958 }
2959
2960 /* ========================================================================= */
2961 /*   Parsing and then calling the assembler for @ (assembly language)        */
2962 /*   statements                                                              */
2963 /* ------------------------------------------------------------------------- */
2964
2965 static assembly_operand parse_operand_z(void)
2966 {   assembly_operand AO;
2967
2968     AO = parse_expression(ASSEMBLY_CONTEXT);
2969     if (AO.type == EXPRESSION_OT)
2970     {   ebf_error("variable or constant", "expression");
2971         AO.type = SHORT_CONSTANT_OT;
2972     }
2973     return(AO);
2974 }
2975
2976 static void parse_assembly_z(void)
2977 {   int n, min, max, indirect_addressed, error_flag = FALSE;
2978     opcodez O;
2979
2980     AI.operand_count = 0;
2981     AI.store_variable_number = -1;
2982     AI.branch_label_number = -1;
2983     AI.text = NULL;
2984
2985     opcode_names.enabled = TRUE;
2986     get_next_token();
2987     opcode_names.enabled = FALSE;
2988
2989     if (token_type == DQ_TT)
2990     {   int i;
2991         AI.internal_number = -1;
2992
2993         custom_opcode_z.name = (uchar *) token_text;
2994         custom_opcode_z.version1 = instruction_set_number;
2995         custom_opcode_z.version2 = instruction_set_number;
2996         custom_opcode_z.extension = -1;
2997         custom_opcode_z.flags = 0;
2998         custom_opcode_z.op_rules = 0;
2999         custom_opcode_z.flags2_set = 0;
3000         custom_opcode_z.no = ZERO;
3001
3002         for (i=0; token_text[i]!=0; i++)
3003         {   if (token_text[i] == ':')
3004             {   token_text[i++] = 0;
3005                 break;
3006             }
3007         }
3008         if (token_text[i] == 0)
3009             error("Opcode specification should have form \"VAR:102\"");
3010
3011         n = -1;
3012         if (strcmp(token_text, "0OP")==0)      n=ZERO;
3013         if (strcmp(token_text, "1OP")==0)      n=ONE;
3014         if (strcmp(token_text, "2OP")==0)      n=TWO;
3015         if (strcmp(token_text, "VAR")==0)      n=VAR;
3016         if (strcmp(token_text, "EXT")==0)      n=EXT;
3017         if (strcmp(token_text, "VAR_LONG")==0) n=VAR_LONG;
3018         if (strcmp(token_text, "EXT_LONG")==0) n=EXT_LONG;
3019
3020         if (i>0) token_text[i-1] = ':';
3021
3022         if (n==-1)
3023         {   ebf_error("Expected 0OP, 1OP, 2OP, VAR, EXT, VAR_LONG or EXT_LONG",
3024                 token_text);
3025             n = EXT;
3026         }
3027         custom_opcode_z.no = n;
3028
3029         custom_opcode_z.code = atoi(token_text+i);
3030         while (isdigit(token_text[i])) i++;
3031
3032         {   max = 0; min = 0;
3033             switch(n)
3034             {   case ZERO: case ONE: max = 16; break;
3035                 case VAR: case VAR_LONG: min = 32; max = 64; break;
3036                 case EXT: case EXT_LONG: max = 256; break;
3037                 case TWO: max = 32; break;
3038             }
3039             if ((custom_opcode_z.code < min) || (custom_opcode_z.code >= max))
3040             {   char range[32];
3041                 sprintf(range, "%d to %d", min, max-1);
3042             error_named("For this operand type, opcode number must be in range",
3043                     range);
3044                 custom_opcode_z.code = min;
3045             }
3046         }
3047
3048         while (token_text[i++] != 0)
3049         {   switch(token_text[i-1])
3050             {   case 'B': custom_opcode_z.flags |= Br; break;
3051                 case 'S': custom_opcode_z.flags |= St; break;
3052                 case 'T': custom_opcode_z.op_rules = TEXT; break;
3053                 case 'I': custom_opcode_z.op_rules = VARIAB; break;
3054                 case 'F': custom_opcode_z.flags2_set = atoi(token_text+i);
3055                           while (isdigit(token_text[i])) i++; break;
3056                 default:
3057                     error("Unknown flag: options are B (branch), S (store), \
3058 T (text), I (indirect addressing), F** (set this Flags 2 bit)");
3059                     break;
3060             }
3061         }
3062         O = custom_opcode_z;
3063     }
3064     else
3065     {   if (token_type != OPCODE_NAME_TT)
3066         {   ebf_error("an opcode name", token_text);
3067             panic_mode_error_recovery();
3068             return;
3069         }
3070         AI.internal_number = token_value;
3071         O = internal_number_to_opcode_z(AI.internal_number);
3072     }
3073
3074     indirect_addressed = (O.op_rules == VARIAB);
3075
3076     if (O.op_rules == TEXT)
3077     {   get_next_token();
3078         if (token_type != DQ_TT)
3079             ebf_error("literal text in double-quotes", token_text);
3080         AI.text = token_text;
3081         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
3082         get_next_token();
3083         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
3084         {   assemblez_instruction(&AI);
3085             AI.text = NULL;
3086             return;
3087         }
3088         ebf_error("semicolon ';' after print string", token_text);
3089         AI.text = NULL;
3090         put_token_back();
3091         return;
3092     }
3093
3094     return_sp_as_variable = TRUE;
3095     do
3096     {   get_next_token();
3097
3098         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
3099
3100         if ((token_type == SEP_TT) && (token_value == ARROW_SEP))
3101         {   if (AI.store_variable_number != -1)
3102                 error("Only one '->' store destination can be given");
3103             get_next_token();
3104             if ((token_type != SYMBOL_TT)
3105                 && (token_type != LOCAL_VARIABLE_TT))
3106                 ebf_error("variable name or 'sp'", token_text);
3107             n = 255;
3108             if (token_type == LOCAL_VARIABLE_TT) n = token_value;
3109             else
3110             {   if (strcmp(token_text, "sp") == 0) n = 0;
3111                 else
3112                 {   if (symbols[token_value].type != GLOBAL_VARIABLE_T)
3113                         error_named(
3114                             "Store '->' destination not 'sp' or a variable:",
3115                             token_text);
3116                     else n = symbols[token_value].value;
3117                 }
3118             }
3119             AI.store_variable_number = n;
3120             continue;
3121         }
3122
3123         if ((token_type == SEP_TT) &&
3124             ((token_value == BRANCH_SEP) || (token_value == NBRANCH_SEP)))
3125         {   if (AI.branch_label_number != -1)
3126                 error("Only one '?' branch destination can be given");
3127
3128             AI.branch_flag = (token_value == BRANCH_SEP);
3129
3130             opcode_names.enabled = TRUE;
3131             get_next_token();
3132             opcode_names.enabled = FALSE;
3133
3134             n = -2;
3135             if ((token_type == OPCODE_NAME_TT)
3136                 && (token_value == rfalse_zc)) n = -3;
3137             else
3138             if ((token_type == OPCODE_NAME_TT)
3139                 && (token_value == rtrue_zc)) n = -4;
3140             else
3141             {   if (token_type == SYMBOL_TT)
3142                 {   put_token_back();
3143                     n = parse_label();
3144                 }
3145                 else
3146                     ebf_error("label name after '?' or '?~'", token_text);
3147             }
3148             AI.branch_label_number = n;
3149             continue;
3150         }
3151
3152         if (AI.operand_count == 8)
3153         {   error("No assembly instruction may have more than 8 operands");
3154             panic_mode_error_recovery(); break;
3155         }
3156
3157         if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
3158         {   if (!indirect_addressed)
3159                 error("This opcode does not use indirect addressing");
3160             if (AI.operand_count > 0)
3161             error("Indirect addressing can only be used on the first operand");
3162             AI.operand[AI.operand_count++] = parse_operand_z();
3163             get_next_token();
3164             if (!((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP)))
3165             {   ebf_error("']'", token_text);
3166                 put_token_back();
3167             }
3168         }
3169         else
3170         {   put_token_back();
3171             AI.operand[AI.operand_count++] = parse_operand_z();
3172             if ((indirect_addressed) && (AI.operand_count == 1)
3173                 && (AI.operand[AI.operand_count-1].type == VARIABLE_OT))
3174             {   AI.operand[AI.operand_count-1].type = SHORT_CONSTANT_OT;
3175                 AI.operand[AI.operand_count-1].marker = VARIABLE_MV;
3176             }
3177         }
3178
3179     } while (TRUE);
3180
3181     return_sp_as_variable = FALSE;
3182
3183
3184     if (O.version1 == 0)
3185     {   error_named("Opcode unavailable in this Z-machine version:",
3186             opcode_names.keywords[AI.internal_number]);
3187         return;
3188     }
3189
3190     if (((O.flags) & Br) != 0)
3191     {   if (AI.branch_label_number == -1)
3192         {   error_flag = TRUE;
3193             AI.branch_label_number = -2;
3194         }
3195     }
3196     else
3197     {   if (AI.branch_label_number != -1)
3198         {   error_flag = TRUE;
3199             AI.branch_label_number = -1;
3200         }
3201     }
3202     if (((O.flags) & St) != 0)
3203     {   if (AI.store_variable_number == -1)
3204         {   if (AI.operand_count == 0)
3205             {   error_flag = TRUE;
3206                 AI.store_variable_number = 255;
3207             }
3208             else
3209             {   AI.store_variable_number
3210                     = AI.operand[--AI.operand_count].value;
3211                 if (AI.operand[AI.operand_count].type != VARIABLE_OT)
3212             error("Store destination (the last operand) is not a variable");
3213             }
3214         }
3215     }
3216     else
3217     {   if (AI.store_variable_number != -1)
3218         {   error_flag = TRUE;
3219             AI.store_variable_number = -1;
3220         }
3221     }
3222
3223     min = 0; max = 0;
3224     switch(O.no)
3225     {   case TWO:      min = 2; max = 2;
3226                        /* Exception for the V6 set_colour, which can take
3227                           a third argument, thus forcing it into VAR form: */
3228                        if ((version_number == 6) && (O.code == 0x1b)) max = 3;
3229                        /* Also an exception for je, which can take from 1
3230                           argument (useless) to 4 arguments */
3231                        if (O.code == 0x01) { min = 1; max = 4; }
3232                        break;
3233         case VAR:      min = 0; max = 4; break;
3234         case VAR_LONG: min = 0; max = 8; break;
3235         case ONE:      min = 1; max = 1; break;
3236         case ZERO:     min = 0; max = 0; break;
3237         case EXT:      min = 0; max = 4; break;
3238         case EXT_LONG: min = 0; max = 8; break;
3239     }
3240
3241     if ((AI.operand_count >= min) && (AI.operand_count <= max))
3242         assemblez_instruction(&AI);
3243     else error_flag = TRUE;
3244
3245     if (error_flag)
3246     {   make_opcode_syntax_z(O);
3247         error_named("Assembly mistake: syntax is",
3248             opcode_syntax_string);
3249     }
3250 }
3251
3252 static assembly_operand parse_operand_g(void)
3253 {   assembly_operand AO;
3254
3255     AO = parse_expression(ASSEMBLY_CONTEXT);
3256     if (AO.type == EXPRESSION_OT)
3257     {   ebf_error("variable or constant", "expression");
3258         AO.type = CONSTANT_OT;
3259     }
3260     return(AO);
3261 }
3262
3263 static void parse_assembly_g(void)
3264 {
3265   opcodeg O;
3266   assembly_operand AO;
3267   int error_flag = FALSE, is_macro = FALSE;
3268
3269   AI.operand_count = 0;
3270   AI.text = NULL;
3271
3272   opcode_names.enabled = TRUE;
3273   opcode_macros.enabled = TRUE;
3274   get_next_token();
3275   opcode_names.enabled = FALSE;
3276   opcode_macros.enabled = FALSE;
3277
3278   if (token_type == DQ_TT) {
3279     char *cx;
3280     int badflags;
3281
3282     AI.internal_number = -1;
3283
3284     /* The format is @"FlagsCount:Code". Flags (which are optional)
3285        can include "S" for store, "SS" for two stores, "B" for branch
3286        format, "R" if execution never continues after the opcode. The
3287        Count is the number of arguments (currently limited to 0-9),
3288        and the Code is a decimal integer representing the opcode
3289        number.
3290
3291        So: @"S3:123" for a three-argument opcode (load, load, store)
3292        whose opcode number is (decimal) 123. Or: @"2:234" for a
3293        two-argument opcode (load, load) whose number is 234. */
3294
3295     custom_opcode_g.name = (uchar *) token_text;
3296     custom_opcode_g.flags = 0;
3297     custom_opcode_g.op_rules = 0;
3298     custom_opcode_g.no = 0;
3299
3300     badflags = FALSE;
3301
3302     for (cx = token_text; *cx && *cx != ':'; cx++) {
3303       if (badflags)
3304       continue;
3305
3306       switch (*cx) {
3307       case 'S':
3308       if (custom_opcode_g.flags & St)
3309         custom_opcode_g.flags |= St2;
3310       else
3311         custom_opcode_g.flags |= St;
3312       break;
3313       case 'B':
3314       custom_opcode_g.flags |= Br;
3315       break;
3316       case 'R':
3317       custom_opcode_g.flags |= Rf;
3318       break;
3319       default:
3320       if (isdigit(*cx)) {
3321         custom_opcode_g.no = (*cx) - '0';
3322         break;
3323       }
3324       badflags = TRUE;
3325       error("Unknown custom opcode flag: options are B (branch), \
3326 S (store), SS (two stores), R (execution never continues)");
3327       break;
3328       }
3329     }
3330
3331     if (*cx != ':') {
3332       error("Custom opcode must have colon");
3333     }
3334     else {
3335       cx++;
3336       if (!(*cx))
3337       error("Custom opcode must have colon followed by opcode number");
3338       else
3339       custom_opcode_g.code = atoi(cx);
3340     }
3341
3342     O = custom_opcode_g;
3343   }
3344   else {
3345     if (token_type != OPCODE_NAME_TT && token_type != OPCODE_MACRO_TT) {
3346       ebf_error("an opcode name", token_text);
3347       panic_mode_error_recovery();
3348       return;
3349     }
3350     AI.internal_number = token_value;
3351     if (token_type == OPCODE_MACRO_TT) {
3352       O = internal_number_to_opmacro_g(AI.internal_number);
3353       is_macro = TRUE;
3354     }
3355     else
3356       O = internal_number_to_opcode_g(AI.internal_number);
3357   }
3358   
3359   return_sp_as_variable = TRUE;
3360
3361   while (1) {
3362     get_next_token();
3363     
3364     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) 
3365       break;
3366
3367     if (AI.operand_count == 8) {
3368       error("No assembly instruction may have more than 8 operands");
3369       panic_mode_error_recovery(); 
3370       break;
3371     }
3372
3373     if ((O.flags & Br) && (AI.operand_count == O.no-1)) {
3374       if (!((token_type == SEP_TT) && (token_value == BRANCH_SEP))) {
3375         error_flag = TRUE;
3376         error("Branch opcode must have '?' label");
3377         put_token_back();
3378       }
3379       AO.type = CONSTANT_OT;
3380       AO.value = parse_label();
3381       AO.marker = BRANCH_MV;
3382     }
3383     else {
3384       put_token_back();
3385       AO = parse_operand_g();
3386     }
3387
3388     AI.operand[AI.operand_count] = AO;
3389     AI.operand_count++;
3390   }
3391
3392   return_sp_as_variable = FALSE;
3393
3394   if (O.no != AI.operand_count) {
3395     error_flag = TRUE;
3396   }
3397
3398   if (!error_flag) {
3399     if (is_macro)
3400       assembleg_macro(&AI);
3401     else
3402       assembleg_instruction(&AI);
3403   }
3404
3405   if (error_flag) {
3406     make_opcode_syntax_g(O);
3407     error_named("Assembly mistake: syntax is",
3408       opcode_syntax_string);
3409   }
3410 }
3411
3412 extern void parse_assembly(void)
3413 {
3414   if (!glulx_mode)
3415     parse_assembly_z();
3416   else
3417     parse_assembly_g();
3418 }
3419
3420 /* ========================================================================= */
3421 /*   Data structure management routines                                      */
3422 /* ------------------------------------------------------------------------- */
3423
3424 extern void init_asm_vars(void)
3425 {   int i;
3426
3427     for (i=0;i<16;i++) flags2_requirements[i]=0;
3428
3429     uses_unicode_features = FALSE;
3430     uses_memheap_features = FALSE;
3431     uses_acceleration_features = FALSE;
3432     uses_float_features = FALSE;
3433     uses_extundo_features = FALSE;
3434
3435     labels = NULL;
3436     sequence_points = NULL;
3437     sequence_point_follows = TRUE;
3438     label_moved_error_already_given = FALSE;
3439
3440     zcode_area = NULL;
3441 }
3442
3443 extern void asm_begin_pass(void)
3444 {   no_instructions = 0;
3445     zmachine_pc = 0;
3446     no_sequence_points = 0;
3447     next_label = 0;
3448     labeluse_size = 0;
3449     next_sequence_point = 0;
3450     zcode_ha_size = 0;
3451     execution_never_reaches_here = EXECSTATE_REACHABLE;
3452 }
3453
3454 extern void asm_allocate_arrays(void)
3455 {
3456     initialise_memory_list(&variables_memlist,
3457         sizeof(variableinfo), 200, (void**)&variables,
3458         "variables");
3459
3460     initialise_memory_list(&labels_memlist,
3461         sizeof(labelinfo), 1000, (void**)&labels,
3462         "labels");
3463     initialise_memory_list(&labeluse_memlist,
3464         sizeof(int), 1000, (void**)&labeluse,
3465         "labeluse");
3466     initialise_memory_list(&sequence_points_memlist,
3467         sizeof(sequencepointinfo), 1000, (void**)&sequence_points,
3468         "sequence points");
3469
3470     initialise_memory_list(&zcode_holding_area_memlist,
3471         sizeof(uchar), 2000, (void**)&zcode_holding_area,
3472         "compiled routine code area");
3473     initialise_memory_list(&zcode_markers_memlist,
3474         sizeof(uchar), 2000, (void**)&zcode_markers,
3475         "compiled routine markers area");
3476
3477     initialise_memory_list(&named_routine_symbols_memlist,
3478         sizeof(int32), 1000, (void**)&named_routine_symbols,
3479         "named routine symbols");
3480
3481     initialise_memory_list(&zcode_area_memlist,
3482         sizeof(uchar), 8192, (void**)&zcode_area,
3483         "code area");
3484
3485     initialise_memory_list(&current_routine_name,
3486         sizeof(char), 3*MAX_IDENTIFIER_LENGTH, NULL,
3487         "routine name currently being defined");
3488 }
3489
3490 extern void asm_free_arrays(void)
3491 {
3492     deallocate_memory_list(&variables_memlist);
3493
3494     deallocate_memory_list(&labels_memlist);
3495     deallocate_memory_list(&sequence_points_memlist);
3496
3497     deallocate_memory_list(&zcode_holding_area_memlist);
3498     deallocate_memory_list(&zcode_markers_memlist);
3499
3500     deallocate_memory_list(&named_routine_symbols_memlist);
3501     deallocate_memory_list(&zcode_area_memlist);
3502     deallocate_memory_list(&current_routine_name);
3503 }
3504
3505 /* ========================================================================= */