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