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