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