a14493984a1203a2332f2038b7cb425953b7782a
[inform.git] / asm.c
1 /* ------------------------------------------------------------------------- */
2 /*   "asm" : The Inform assembler                                            */
3 /*                                                                           */
4 /* Copyright (c) Graham Nelson 1993 - 2016                                   */
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 = -1;
1427     else routine_starts_line = ErrorReport.line_number
1428              + FILE_LINE_SCALE_FACTOR*ErrorReport.file_number;
1429
1430     if (asm_trace_level > 0)
1431     {   printf("\n%5d  +%05lx  [ %s ", ErrorReport.line_number,
1432             ((long int) zmachine_pc), name);
1433         for (i=1; i<=no_locals; i++) printf("%s ", variable_name(i));
1434         printf("\n\n");
1435     }
1436
1437     routine_start_pc = zmachine_pc;
1438
1439     if (track_unused_routines) {
1440         /* The name of an embedded function is in a temporary buffer,
1441            so we shouldn't keep a reference to it. (It is sad that we
1442            have to know this here.) */
1443         char *funcname = name;
1444         if (embedded_flag)
1445             funcname = "<embedded>";
1446
1447         df_note_function_start(funcname, zmachine_pc, embedded_flag,
1448                                routine_starts_line);
1449     }
1450
1451     routine_symbol = the_symbol;
1452     name_length = strlen(name) + 1;
1453     routine_name =
1454       my_malloc(name_length * sizeof(char), "temporary copy of routine name");
1455     strncpy(routine_name, name, name_length);
1456
1457     /*  Update the routine counter                                           */
1458
1459     no_routines++;
1460
1461     /*  Actually assemble the routine header into the code area; note        */
1462     /*  Inform doesn't support the setting of local variables to default     */
1463     /*  values other than 0 in V3 and V4.  (In V5+ the Z-Machine doesn't     */
1464     /*  provide the possibility in any case.)                                */
1465
1466     if (!glulx_mode) {
1467
1468       if (stackargs) 
1469         warning("Z-code does not support stack-argument function definitions.");
1470
1471       byteout(no_locals, 0);
1472
1473       /*  Not the packed address, but the scaled offset from code area start:  */
1474
1475       rv = zmachine_pc/scale_factor;
1476
1477       if (instruction_set_number<5)
1478           for (i=0; i<no_locals; i++) { byteout(0,0); byteout(0,0); }
1479
1480       next_label = 0; next_sequence_point = 0; last_label = -1;
1481
1482       /*  Compile code to print out text like "a=3, b=4, c=5" when the       */
1483       /*  function is called, if it's required.                              */
1484
1485       if ((routine_asterisked) || (define_INFIX_switch))
1486       {   char fnt[256]; assembly_operand PV, RFA, CON, STP, SLF; int ln, ln2;
1487
1488           ln = next_label++;
1489           ln2 = next_label++;
1490
1491           if (define_INFIX_switch)
1492           {
1493                 if (embedded_flag)
1494             {   SLF.value = 251; SLF.type = VARIABLE_OT; SLF.marker = 0;
1495                   CON.value = 0; CON.type = SHORT_CONSTANT_OT; CON.marker = 0;
1496                 assemblez_2_branch(test_attr_zc, SLF, CON, ln2, FALSE);
1497             }
1498             else
1499             {   i = no_named_routines++;
1500                   named_routine_symbols[i] = the_symbol;
1501                 CON.value = i/8; CON.type = LONG_CONSTANT_OT; CON.marker = 0;
1502                 RFA.value = routine_flags_array_SC;
1503                 RFA.type = LONG_CONSTANT_OT; RFA.marker = INCON_MV;
1504                 STP.value = 0; STP.type = VARIABLE_OT; STP.marker = 0;
1505                 assemblez_2_to(loadb_zc, RFA, CON, STP);
1506                 CON.value = (1 << (i%8)); CON.type = SHORT_CONSTANT_OT;
1507                 assemblez_2_to(and_zc, STP, CON, STP);
1508                 assemblez_1_branch(jz_zc, STP, ln2, TRUE);
1509             }
1510         }
1511         sprintf(fnt, "[ %s(", name);
1512         AI.text = fnt; assemblez_0(print_zc);
1513         for (i=1; (i<=7)&&(i<=no_locals); i++)
1514         {   if (version_number >= 5)
1515             {   PV.type = SHORT_CONSTANT_OT;
1516                 PV.value = i; PV.marker = 0;
1517                 assemblez_1_branch(check_arg_count_zc, PV, ln, FALSE);
1518             }
1519             sprintf(fnt, "%s%s = ", (i==1)?"":", ", variable_name(i));
1520             AI.text = fnt; assemblez_0(print_zc);
1521             PV.type = VARIABLE_OT; PV.value = i; PV.marker = 0;
1522             assemblez_1(print_num_zc, PV);
1523         }
1524         assemble_label_no(ln);
1525         sprintf(fnt, ") ]^"); AI.text = fnt;
1526         assemblez_0(print_zc);
1527         assemble_label_no(ln2);
1528       }
1529
1530     }
1531     else {
1532       rv = zmachine_pc;
1533
1534       if (stackargs)
1535         byteout(0xC0, 0); /* Glulx type byte for function */
1536       else
1537         byteout(0xC1, 0); /* Glulx type byte for function */
1538
1539       /* Now the locals format list. This is simple; we only use
1540         four-byte locals. That's a single pair, unless we have more
1541         than 255 locals, or none at all. */
1542       i = no_locals;
1543       while (i) {
1544         int j = i;
1545         if (j > 255)
1546           j = 255;
1547         byteout(4, 0); 
1548         byteout(j, 0);
1549         i -= j;
1550       }
1551       /* Terminate the list with a (0, 0) pair. */
1552       byteout(0, 0);
1553       byteout(0, 0);
1554
1555       if (stackargs) {
1556         /* The top stack value is the number of function arguments. Let's
1557            move that into the first local, which is _vararg_count. */
1558         /* @copy sp _vararg_count; */
1559         byteout(0x40, 0); byteout(0x98, 0); byteout(0x00, 0);
1560       }
1561
1562       next_label = 0; next_sequence_point = 0; last_label = -1; 
1563
1564       if ((routine_asterisked) || (define_INFIX_switch)) {
1565         int ix;
1566         char fnt[256];
1567         assembly_operand AO, AO2;
1568         if (define_INFIX_switch) {
1569           /* This isn't supported */
1570           if (embedded_flag) {
1571           }
1572           else {
1573             i = no_named_routines++;
1574             named_routine_symbols[i] = the_symbol;
1575           }
1576         }
1577         sprintf(fnt, "[ %s(", name);
1578         AO.marker = STRING_MV;
1579         AO.type   = CONSTANT_OT;
1580         AO.value  = compile_string(fnt, FALSE, FALSE);
1581         assembleg_1(streamstr_gc, AO);
1582
1583         if (!stackargs) {
1584           for (ix=1; ix<=no_locals; ix++) {
1585             sprintf(fnt, "%s%s = ", (ix==1)?"":", ", variable_name(ix));
1586             AO.marker = STRING_MV;
1587             AO.type   = CONSTANT_OT;
1588             AO.value  = compile_string(fnt, FALSE, FALSE);
1589             assembleg_1(streamstr_gc, AO);
1590             AO.marker = 0;
1591             AO.type = LOCALVAR_OT;
1592             AO.value = ix;
1593             assembleg_1(streamnum_gc, AO);
1594           }
1595         }
1596         else {
1597           int lntop, lnbottom;
1598           sprintf(fnt, "%s = ", variable_name(1));
1599           AO.marker = STRING_MV;
1600           AO.type   = CONSTANT_OT;
1601           AO.value  = compile_string(fnt, FALSE, FALSE);
1602           assembleg_1(streamstr_gc, AO);
1603           AO.marker = 0;
1604           AO.type = LOCALVAR_OT;
1605           AO.value = 1;
1606           assembleg_1(streamnum_gc, AO);
1607           AO2.type = BYTECONSTANT_OT;
1608           AO2.marker = 0;
1609           AO2.value = ':';
1610           assembleg_1(streamchar_gc, AO2);
1611           AO2.type = BYTECONSTANT_OT;
1612           AO2.marker = 0;
1613           AO2.value = ' ';
1614           /* for (temp_var4=0 : temp_var4<_vararg_count : temp_var4++) {
1615                @streamchar ' ';
1616                @stkpeek temp_var4 sp;
1617                @stream_num sp;
1618              }
1619           */
1620           assembleg_store(temp_var4, zero_operand);
1621           lntop = next_label++;
1622           lnbottom = next_label++;
1623           assemble_label_no(lntop);
1624           assembleg_2_branch(jge_gc, temp_var4, AO, lnbottom); /* AO is _vararg_count */
1625           assembleg_1(streamchar_gc, AO2); /* AO2 is space */
1626           assembleg_2(stkpeek_gc, temp_var4, stack_pointer);
1627           assembleg_1(streamnum_gc, stack_pointer);
1628           assembleg_3(add_gc, temp_var4, one_operand, temp_var4);
1629           assembleg_0_branch(jump_gc, lntop);
1630           assemble_label_no(lnbottom);
1631         }
1632
1633         AO.marker = STRING_MV;
1634         AO.type   = CONSTANT_OT;
1635         AO.value  = compile_string(") ]^", FALSE, FALSE);
1636         assembleg_1(streamstr_gc, AO);
1637       }
1638     }
1639
1640     return rv;
1641 }
1642
1643 void assemble_routine_end(int embedded_flag, debug_locations locations)
1644 {   int32 i;
1645
1646     /* No marker is made in the Z-machine's code area to indicate the        */
1647     /* end of a routine.  Instead, we simply assemble a return opcode if     */
1648     /* need be (it won't be if the last instruction was, say, a "quit").     */
1649     /* The return value is true (1) for normal routines, false (0) for       */
1650     /* embedded routines (e.g. the library uses this for "before"            */
1651     /* properties).                                                          */
1652
1653     if (!execution_never_reaches_here)
1654     {   
1655       if (!glulx_mode) {
1656         if (embedded_flag) assemblez_0(rfalse_zc);
1657                       else assemblez_0(rtrue_zc);
1658       }
1659       else {
1660         assembly_operand AO;
1661         if (embedded_flag) 
1662             AO = zero_operand;
1663         else 
1664             AO = one_operand;
1665         assembleg_1(return_gc, AO);
1666       }
1667     }
1668
1669     /* Dump the contents of the current routine into longer-term Z-code
1670        storage                                                               */
1671
1672     if (!glulx_mode)
1673       transfer_routine_z();
1674     else
1675       transfer_routine_g();
1676
1677     if (track_unused_routines)
1678         df_note_function_end(zmachine_pc);
1679
1680     /* Tell the debugging file about the routine just ended.                 */
1681
1682     if (debugfile_switch)
1683     {
1684         debug_file_printf("<routine>");
1685         if (embedded_flag)
1686         {   debug_file_printf
1687                 ("<identifier artificial=\"true\">%s</identifier>",
1688                  routine_name);
1689         }
1690         else if (sflags[routine_symbol] & REPLACE_SFLAG)
1691         {   /* The symbol type will be set to ROUTINE_T once the replaced
1692                version has been given; if it is already set, we must be dealing
1693                with a replacement, and we can use the routine name as-is.
1694                Otherwise we look for a rename.  And if that doesn't work, we
1695                fall back to an artificial identifier. */
1696             if (stypes[routine_symbol] == ROUTINE_T)
1697             {   /* Optional because there may be further replacements. */
1698                 write_debug_optional_identifier(routine_symbol);
1699             }
1700             else if (find_symbol_replacement(&routine_symbol))
1701             {   debug_file_printf
1702                     ("<identifier>%s</identifier>", symbs[routine_symbol]);
1703             }
1704             else
1705             {   debug_file_printf
1706                     ("<identifier artificial=\"true\">%s (replaced)"
1707                          "</identifier>",
1708                      routine_name);
1709             }
1710         } else
1711         {   debug_file_printf("<identifier>%s</identifier>", routine_name);
1712         }
1713         debug_file_printf("<value>");
1714         if (glulx_mode)
1715         {   write_debug_code_backpatch(routine_start_pc);
1716         } else
1717         {   write_debug_packed_code_backpatch(routine_start_pc);
1718         }
1719         debug_file_printf("</value>");
1720         debug_file_printf("<address>");
1721         write_debug_code_backpatch(routine_start_pc);
1722         debug_file_printf("</address>");
1723         debug_file_printf
1724             ("<byte-count>%d</byte-count>", zmachine_pc - routine_start_pc);
1725         write_debug_locations(locations);
1726         for (i = 1; i <= routine_locals; ++i)
1727         {   debug_file_printf("<local-variable>");
1728             debug_file_printf("<identifier>%s</identifier>", variable_name(i));
1729             if (glulx_mode)
1730             {   debug_file_printf
1731                     ("<frame-offset>%d</frame-offset>", 4 * (i - 1));
1732             }
1733             else
1734             {   debug_file_printf("<index>%d</index>", i);
1735             }
1736             debug_file_printf("</local-variable>");
1737         }
1738         for (i = 0; i < next_sequence_point; ++i)
1739         {   debug_file_printf("<sequence-point>");
1740             debug_file_printf("<address>");
1741             write_debug_code_backpatch
1742                 (label_offsets[sequence_point_labels[i]]);
1743             debug_file_printf("</address>");
1744             write_debug_location(sequence_point_locations[i]);
1745             debug_file_printf("</sequence-point>");
1746         }
1747         debug_file_printf("</routine>");
1748     }
1749
1750     my_free(&routine_name, "temporary copy of routine name");
1751
1752     /* Issue warnings about any local variables not used in the routine. */
1753
1754     for (i=1; i<=routine_locals; i++)
1755         if (!(variable_usage[i]))
1756             dbnu_warning("Local variable", variable_name(i),
1757                 routine_starts_line);
1758
1759     for (i=0; i<next_label; i++)
1760     {   int j = label_symbols[i];
1761         if (j != -1)
1762         {   if (sflags[j] & CHANGE_SFLAG)
1763                 error_named_at("Routine contains no such label as",
1764                     (char *) symbs[j], slines[j]);
1765             else
1766                 if ((sflags[j] & USED_SFLAG) == 0)
1767                     dbnu_warning("Label", (char *) symbs[j], slines[j]);
1768             stypes[j] = CONSTANT_T;
1769             sflags[j] = UNKNOWN_SFLAG;
1770         }
1771     }
1772     no_sequence_points += next_sequence_point;
1773     next_label = 0; next_sequence_point = 0;
1774 }
1775
1776 /* ------------------------------------------------------------------------- */
1777 /*   Called when the holding area contains an entire routine of code:        */
1778 /*   backpatches the labels, issues module markers, then dumps the routine   */
1779 /*   into longer-term storage.                                               */
1780 /*   Note that in the code received, all branches have long form, and their  */
1781 /*   contents are not an offset but the label numbers they branch to.        */
1782 /*   Similarly, LABEL operands (those of "jump" instructions) are label      */
1783 /*   numbers.  So this routine must change the label numbers to offsets,     */
1784 /*   slimming the code down as it does so to take advantage of short-form    */
1785 /*   branch operands where possible.                                         */
1786 /* ------------------------------------------------------------------------- */
1787
1788 static int32 adjusted_pc;
1789
1790 static void transfer_to_temp_file(uchar *c)
1791 {   fputc(*c,Temp2_fp);
1792     adjusted_pc++;
1793 }
1794
1795 static void transfer_to_zcode_area(uchar *c)
1796 {   write_byte_to_memory_block(&zcode_area, adjusted_pc++, *c);
1797 }
1798
1799 static void transfer_routine_z(void)
1800 {   int32 i, j, pc, new_pc, label, long_form, offset_of_next, addr,
1801           branch_on_true, rstart_pc;
1802     void (* transfer_byte)(uchar *);
1803
1804     adjusted_pc = zmachine_pc - zcode_ha_size; rstart_pc = adjusted_pc;
1805
1806     if (asm_trace_level >= 3)
1807     {   printf("Backpatching routine at %05lx: initial size %d, %d labels\n",
1808              (long int) adjusted_pc, zcode_ha_size, next_label);
1809     }
1810
1811     transfer_byte =
1812         (temporary_files_switch)?transfer_to_temp_file:transfer_to_zcode_area;
1813
1814     /*  (1) Scan through for branches and make short/long decisions in each
1815             case.  Mark omitted bytes (2nd bytes in branches converted to
1816             short form) with DELETED_MV.                                     */
1817
1818     for (i=0, pc=adjusted_pc; i<zcode_ha_size; i++, pc++)
1819     {   if (zcode_markers[i] == BRANCH_MV)
1820         {   if (asm_trace_level >= 4)
1821                 printf("Branch detected at offset %04x\n", pc);
1822             j = (256*zcode_holding_area[i] + zcode_holding_area[i+1]) & 0x7fff;
1823             if (asm_trace_level >= 4)
1824                 printf("To label %d, which is %d from here\n",
1825                     j, label_offsets[j]-pc);
1826             if ((label_offsets[j] >= pc+2) && (label_offsets[j] < pc+64))
1827             {   if (asm_trace_level >= 4) printf("Short form\n");
1828                 zcode_markers[i+1] = DELETED_MV;
1829             }
1830         }
1831     }
1832
1833     /*  (2) Calculate the new positions of the labels.  Note that since the
1834             long/short decision was taken on the basis of the old labels,
1835             and since the new labels are slightly closer together because
1836             of branch bytes deleted, there may be a few further branch
1837             optimisations which are possible but which have been missed
1838             (if two labels move inside the "short" range as a result of
1839             a previous optimisation).  However, this is acceptably uncommon. */
1840
1841     if (next_label > 0)
1842     {   if (asm_trace_level >= 4)
1843         {   printf("Opening label: %d\n", first_label);
1844             for (i=0;i<next_label;i++)
1845                 printf("Label %d offset %04x next -> %d previous -> %d\n",
1846                     i, label_offsets[i], label_next[i], label_prev[i]);
1847         }
1848
1849         for (i=0, pc=adjusted_pc, new_pc=adjusted_pc, label = first_label;
1850             i<zcode_ha_size; i++, pc++)
1851         {   while ((label != -1) && (label_offsets[label] == pc))
1852             {   if (asm_trace_level >= 4)
1853                     printf("Position of L%d corrected from %04x to %04x\n",
1854                         label, label_offsets[label], new_pc);
1855                 label_offsets[label] = new_pc;
1856                 label = label_next[label];
1857             }
1858            if (zcode_markers[i] != DELETED_MV) new_pc++;
1859         }
1860     }
1861
1862     /*  (3) As we are transferring, replace the label numbers in branch
1863             operands with offsets to those labels.  Also issue markers, now
1864             that we know where they occur in the final Z-code area.          */
1865
1866     for (i=0, new_pc=adjusted_pc; i<zcode_ha_size; i++)
1867     {   switch(zcode_markers[i])
1868         { case BRANCH_MV:
1869             long_form = 1; if (zcode_markers[i+1] == DELETED_MV) long_form = 0;
1870
1871             j = (256*zcode_holding_area[i] + zcode_holding_area[i+1]) & 0x7fff;
1872             branch_on_true = ((zcode_holding_area[i]) & 0x80);
1873             offset_of_next = new_pc + long_form + 1;
1874
1875             addr = label_offsets[j] - offset_of_next + 2;
1876             if (addr<-0x2000 || addr>0x1fff) 
1877                 fatalerror("Branch out of range: divide the routine up?");
1878             if (addr<0) addr+=(int32) 0x10000L;
1879
1880             addr=addr&0x3fff;
1881             if (long_form==1)
1882             {   zcode_holding_area[i] = branch_on_true + addr/256;
1883                 zcode_holding_area[i+1] = addr%256;
1884             }
1885             else
1886             {   if (addr >= 64)
1887                 {   compiler_error("Label out of range for branch");
1888                     printf("Addr is %04x\n", addr);
1889                 }
1890                 zcode_holding_area[i] = branch_on_true + 0x40 + (addr&0x3f);
1891             }
1892             transfer_byte(zcode_holding_area + i); new_pc++;
1893             break;
1894
1895           case LABEL_MV:
1896             j = 256*zcode_holding_area[i] + zcode_holding_area[i+1];
1897             addr = label_offsets[j] - new_pc;
1898             if (addr<-0x8000 || addr>0x7fff) 
1899                 fatalerror("Jump out of range: divide the routine up?");
1900             if (addr<0) addr += (int32) 0x10000L;
1901             zcode_holding_area[i] = addr/256;
1902             zcode_holding_area[i+1] = addr%256;
1903             transfer_byte(zcode_holding_area + i); new_pc++;
1904             break;
1905
1906           case DELETED_MV:
1907             break;
1908
1909           default:
1910             switch(zcode_markers[i] & 0x7f)
1911             {   case NULL_MV: break;
1912                 case VARIABLE_MV:
1913                 case OBJECT_MV:
1914                 case ACTION_MV:
1915                 case IDENT_MV:
1916                     if (!module_switch) break;
1917                 default:
1918                     if ((zcode_markers[i] & 0x7f) > LARGEST_BPATCH_MV)
1919                     {   compiler_error("Illegal code backpatch value");
1920                         printf("Illegal value of %02x at PC = %04x\n",
1921                             zcode_markers[i] & 0x7f, new_pc);
1922                         break;
1923                     }
1924
1925                     write_byte_to_memory_block(&zcode_backpatch_table,
1926                         zcode_backpatch_size++,
1927                         zcode_markers[i] + 32*(new_pc/65536));
1928                     write_byte_to_memory_block(&zcode_backpatch_table,
1929                         zcode_backpatch_size++, (new_pc/256)%256);
1930                     write_byte_to_memory_block(&zcode_backpatch_table,
1931                         zcode_backpatch_size++, new_pc%256);
1932                     break;
1933             }
1934             transfer_byte(zcode_holding_area + i); new_pc++;
1935             break;
1936         }
1937     }
1938
1939     if (asm_trace_level >= 3)
1940     {   printf("After branch optimisation, routine length is %d bytes\n",
1941              new_pc - rstart_pc);
1942     }
1943
1944     /*  Insert null bytes if necessary to ensure the next routine address is */
1945     /*  expressible as a packed address                                      */
1946
1947     {   uchar zero[1];
1948         zero[0] = 0;
1949         if (oddeven_packing_switch)
1950             while ((adjusted_pc%(scale_factor*2))!=0) transfer_byte(zero);
1951         else
1952             while ((adjusted_pc%scale_factor)!=0) transfer_byte(zero);
1953     }
1954
1955     zmachine_pc = adjusted_pc;
1956     zcode_ha_size = 0;
1957 }
1958
1959 static void transfer_routine_g(void)
1960 {   int32 i, j, pc, new_pc, label, form_len, offset_of_next, addr,
1961           rstart_pc;
1962     void (* transfer_byte)(uchar *);
1963
1964     adjusted_pc = zmachine_pc - zcode_ha_size; rstart_pc = adjusted_pc;
1965
1966     if (asm_trace_level >= 3)
1967     {   printf("Backpatching routine at %05lx: initial size %d, %d labels\n",
1968              (long int) adjusted_pc, zcode_ha_size, next_label);
1969     }
1970
1971     transfer_byte =
1972         (temporary_files_switch)?transfer_to_temp_file:transfer_to_zcode_area;
1973
1974     /*  (1) Scan through for branches and make short/long decisions in each
1975             case.  Mark omitted bytes (bytes 2-4 in branches converted to
1976             short form) with DELETED_MV.                                     */
1977
1978     for (i=0, pc=adjusted_pc; i<zcode_ha_size; i++, pc++) {
1979       if (zcode_markers[i] >= BRANCH_MV && zcode_markers[i] < BRANCHMAX_MV) {
1980         int opmodeoffset = (zcode_markers[i] - BRANCH_MV);
1981         int32 opmodebyte;
1982         if (asm_trace_level >= 4)
1983             printf("Branch detected at offset %04x\n", pc);
1984         j = ((zcode_holding_area[i] << 24) 
1985             | (zcode_holding_area[i+1] << 16)
1986             | (zcode_holding_area[i+2] << 8)
1987             | (zcode_holding_area[i+3]));
1988         offset_of_next = pc + 4;
1989         addr = (label_offsets[j] - offset_of_next) + 2;
1990         if (asm_trace_level >= 4)
1991             printf("To label %d, which is (%d-2) = %d from here\n",
1992                 j, addr, label_offsets[j] - offset_of_next);
1993         if (addr >= -0x80 && addr < 0x80) {
1994             if (asm_trace_level >= 4) printf("...Byte form\n");
1995             zcode_markers[i+1] = DELETED_MV;
1996             zcode_markers[i+2] = DELETED_MV;
1997             zcode_markers[i+3] = DELETED_MV;
1998             opmodebyte = i - ((opmodeoffset+1)/2);
1999             if ((opmodeoffset & 1) == 0)
2000                 zcode_holding_area[opmodebyte] = 
2001                     (zcode_holding_area[opmodebyte] & 0xF0) | 0x01;
2002             else
2003                 zcode_holding_area[opmodebyte] = 
2004                     (zcode_holding_area[opmodebyte] & 0x0F) | 0x10;
2005         }
2006         else if (addr >= -0x8000 && addr < 0x8000) {
2007             if (asm_trace_level >= 4) printf("...Short form\n");
2008             zcode_markers[i+2] = DELETED_MV;
2009             zcode_markers[i+3] = DELETED_MV;
2010             opmodebyte = i - ((opmodeoffset+1)/2);
2011             if ((opmodeoffset & 1) == 0)
2012                 zcode_holding_area[opmodebyte] = 
2013                     (zcode_holding_area[opmodebyte] & 0xF0) | 0x02;
2014             else
2015                 zcode_holding_area[opmodebyte] = 
2016                     (zcode_holding_area[opmodebyte] & 0x0F) | 0x20;
2017         }
2018       }
2019     }
2020
2021     /*  (2) Calculate the new positions of the labels.  Note that since the
2022             long/short decision was taken on the basis of the old labels,
2023             and since the new labels are slightly closer together because
2024             of branch bytes deleted, there may be a few further branch
2025             optimisations which are possible but which have been missed
2026             (if two labels move inside the "short" range as a result of
2027             a previous optimisation).  However, this is acceptably uncommon. */
2028     if (next_label > 0) {
2029       if (asm_trace_level >= 4) {
2030         printf("Opening label: %d\n", first_label);
2031         for (i=0;i<next_label;i++)
2032             printf("Label %d offset %04x next -> %d previous -> %d\n",
2033                 i, label_offsets[i], label_next[i], label_prev[i]);
2034       }
2035
2036       for (i=0, pc=adjusted_pc, new_pc=adjusted_pc, label = first_label;
2037         i<zcode_ha_size; 
2038         i++, pc++) {
2039         while ((label != -1) && (label_offsets[label] == pc)) {
2040             if (asm_trace_level >= 4)
2041                 printf("Position of L%d corrected from %04x to %04x\n",
2042                 label, label_offsets[label], new_pc);
2043             label_offsets[label] = new_pc;
2044             label = label_next[label];
2045         }
2046         if (zcode_markers[i] != DELETED_MV) new_pc++;
2047       }
2048     }
2049
2050     /*  (3) As we are transferring, replace the label numbers in branch
2051             operands with offsets to those labels.  Also issue markers, now
2052             that we know where they occur in the final Z-code area.          */
2053
2054     for (i=0, new_pc=adjusted_pc; i<zcode_ha_size; i++) {
2055
2056       if (zcode_markers[i] >= BRANCH_MV && zcode_markers[i] < BRANCHMAX_MV) {
2057         form_len = 4;
2058         if (zcode_markers[i+1] == DELETED_MV) {
2059             form_len = 1;
2060         }
2061         else {
2062             if (zcode_markers[i+2] == DELETED_MV)
2063                 form_len = 2;
2064         }
2065         j = ((zcode_holding_area[i] << 24) 
2066             | (zcode_holding_area[i+1] << 16)
2067             | (zcode_holding_area[i+2] << 8)
2068             | (zcode_holding_area[i+3]));
2069
2070         /* At the moment, we can safely assume that the branch operand
2071            is the end of the opcode, so the next opcode starts right
2072            after it. */
2073         offset_of_next = new_pc + form_len;
2074
2075         addr = (label_offsets[j] - offset_of_next) + 2;
2076         if (asm_trace_level >= 4) {
2077             printf("Branch at offset %04x: %04x (%s)\n",
2078                 new_pc, addr, ((form_len == 1) ? "byte" :
2079                 ((form_len == 2) ? "short" : "long")));
2080         }
2081         if (form_len == 1) {
2082             if (addr < -0x80 && addr >= 0x80) {
2083                 error("*** Label out of range for byte branch ***");
2084             }
2085         zcode_holding_area[i] = (addr) & 0xFF;
2086         }
2087         else if (form_len == 2) {
2088             if (addr < -0x8000 && addr >= 0x8000) {
2089                 error("*** Label out of range for short branch ***");
2090             }
2091             zcode_holding_area[i] = (addr >> 8) & 0xFF;
2092             zcode_holding_area[i+1] = (addr) & 0xFF;
2093         }
2094         else {
2095             zcode_holding_area[i] = (addr >> 24) & 0xFF;
2096             zcode_holding_area[i+1] = (addr >> 16) & 0xFF;
2097             zcode_holding_area[i+2] = (addr >> 8) & 0xFF;
2098             zcode_holding_area[i+3] = (addr) & 0xFF;
2099         }
2100         transfer_byte(zcode_holding_area + i); new_pc++;
2101       }
2102       else if (zcode_markers[i] == LABEL_MV) {
2103           error("*** No LABEL opcodes in Glulx ***");
2104       }
2105       else if (zcode_markers[i] == DELETED_MV) {
2106         /* skip it */
2107       }
2108       else {
2109         switch(zcode_markers[i] & 0x7f) {
2110         case NULL_MV: 
2111             break;
2112         case ACTION_MV:
2113         case IDENT_MV:
2114             if (!module_switch) break;
2115         case OBJECT_MV:
2116         case VARIABLE_MV:
2117         default:
2118             if ((zcode_markers[i] & 0x7f) > LARGEST_BPATCH_MV) {
2119                 error("*** Illegal code backpatch value ***");
2120                 printf("Illegal value of %02x at PC = %04x\n",
2121                 zcode_markers[i] & 0x7f, new_pc);
2122                 break;
2123             }
2124           /* The backpatch table format for Glulx:
2125              First, the marker byte (0..LARGEST_BPATCH_MV).
2126              Then a byte indicating the data size to be patched (1, 2, 4).
2127              Then the four-byte address (new_pc).
2128           */
2129           write_byte_to_memory_block(&zcode_backpatch_table,
2130             zcode_backpatch_size++,
2131             zcode_markers[i]);
2132           write_byte_to_memory_block(&zcode_backpatch_table,
2133             zcode_backpatch_size++,
2134             4);
2135           write_byte_to_memory_block(&zcode_backpatch_table,
2136             zcode_backpatch_size++, ((new_pc >> 24) & 0xFF));
2137           write_byte_to_memory_block(&zcode_backpatch_table,
2138             zcode_backpatch_size++, ((new_pc >> 16) & 0xFF));
2139           write_byte_to_memory_block(&zcode_backpatch_table,
2140             zcode_backpatch_size++, ((new_pc >> 8) & 0xFF));
2141           write_byte_to_memory_block(&zcode_backpatch_table,
2142             zcode_backpatch_size++, (new_pc & 0xFF));
2143           break;
2144         }
2145         transfer_byte(zcode_holding_area + i); new_pc++;
2146       }
2147     }
2148
2149     if (asm_trace_level >= 3)
2150     {   printf("After branch optimisation, routine length is %d bytes\n",
2151              new_pc - rstart_pc);
2152     }
2153
2154     zmachine_pc = adjusted_pc;
2155     zcode_ha_size = 0;
2156 }
2157
2158
2159 /* ========================================================================= */
2160 /*   Front ends for the instruction assembler: convenient shorthand forms    */
2161 /*   used in various code generation routines all over Inform.               */
2162 /* ------------------------------------------------------------------------- */
2163
2164 void assemble_jump(int n)
2165 {
2166     if (!glulx_mode)
2167         assemblez_jump(n);
2168     else
2169         assembleg_jump(n);
2170 }
2171
2172 void assemblez_0(int internal_number)
2173 {   AI.internal_number = internal_number;
2174     AI.operand_count = 0;
2175     AI.store_variable_number = -1;
2176     AI.branch_label_number = -1;
2177     assemblez_instruction(&AI);
2178 }
2179
2180 void assemblez_0_to(int internal_number, assembly_operand o)
2181 {   AI.internal_number = internal_number;
2182     AI.operand_count = 0;
2183     AI.store_variable_number = o.value;
2184     AI.branch_label_number = -1;
2185     assemblez_instruction(&AI);
2186 }
2187
2188 void assemblez_0_branch(int internal_number, int label, int flag)
2189 {   AI.internal_number = internal_number;
2190     AI.operand_count = 0;
2191     AI.store_variable_number = -1;
2192     AI.branch_label_number = label;
2193     AI.branch_flag = flag;
2194     assemblez_instruction(&AI);
2195 }
2196
2197 void assemblez_1(int internal_number, assembly_operand o1)
2198 {   AI.internal_number = internal_number;
2199     AI.operand_count = 1;
2200     AI.operand[0] = o1;
2201     AI.store_variable_number = -1;
2202     AI.branch_label_number = -1;
2203     assemblez_instruction(&AI);
2204 }
2205
2206 void assemblez_1_to(int internal_number,
2207     assembly_operand o1, assembly_operand st)
2208 {   AI.internal_number = internal_number;
2209     AI.operand_count = 1;
2210     AI.operand[0] = o1;
2211     AI.store_variable_number = st.value;
2212     AI.branch_label_number = -1;
2213     assemblez_instruction(&AI);
2214 }
2215
2216 void assemblez_1_branch(int internal_number,
2217     assembly_operand o1, int label, int flag)
2218 {   AI.internal_number = internal_number;
2219     AI.operand_count = 1;
2220     AI.operand[0] = o1;
2221     AI.branch_label_number = label;
2222     AI.store_variable_number = -1;
2223     AI.branch_flag = flag;
2224     assemblez_instruction(&AI);
2225 }
2226
2227 void assemblez_2(int internal_number,
2228     assembly_operand o1, assembly_operand o2)
2229 {   AI.internal_number = internal_number;
2230     AI.operand_count = 2;
2231     AI.operand[0] = o1;
2232     AI.operand[1] = o2;
2233     AI.store_variable_number = -1;
2234     AI.branch_label_number = -1;
2235     assemblez_instruction(&AI);
2236 }
2237
2238 void assemblez_3(int internal_number,
2239     assembly_operand o1, assembly_operand o2, assembly_operand o3)
2240 {   AI.internal_number = internal_number;
2241     AI.operand_count = 3;
2242     AI.operand[0] = o1;
2243     AI.operand[1] = o2;
2244     AI.operand[2] = o3;
2245     AI.store_variable_number = -1;
2246     AI.branch_label_number = -1;
2247     assemblez_instruction(&AI);
2248 }
2249
2250 void assemblez_3_to(int internal_number,
2251     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2252     assembly_operand st)
2253 {   AI.internal_number = internal_number;
2254     AI.operand_count = 3;
2255     AI.operand[0] = o1;
2256     AI.operand[1] = o2;
2257     AI.operand[2] = o3;
2258     AI.store_variable_number = st.value;
2259     AI.branch_label_number = -1;
2260     assemblez_instruction(&AI);
2261 }
2262
2263 void assemblez_3_branch(int internal_number,
2264     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2265     int label, int flag)
2266 {   AI.internal_number = internal_number;
2267     AI.operand_count = 3;
2268     AI.operand[0] = o1;
2269     AI.operand[1] = o2;
2270     AI.operand[2] = o3;
2271     AI.store_variable_number = -1;
2272     AI.branch_label_number = label;
2273     AI.branch_flag = flag;
2274     assemblez_instruction(&AI);
2275 }
2276
2277 void assemblez_4(int internal_number,
2278     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2279     assembly_operand o4)
2280 {   AI.internal_number = internal_number;
2281     AI.operand_count = 4;
2282     AI.operand[0] = o1;
2283     AI.operand[1] = o2;
2284     AI.operand[2] = o3;
2285     AI.operand[3] = o4;
2286     AI.store_variable_number = -1;
2287     AI.branch_label_number = -1;
2288     assemblez_instruction(&AI);
2289 }
2290
2291 void assemblez_5(int internal_number,
2292     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2293     assembly_operand o4, assembly_operand o5)
2294 {   AI.internal_number = internal_number;
2295     AI.operand_count = 5;
2296     AI.operand[0] = o1;
2297     AI.operand[1] = o2;
2298     AI.operand[2] = o3;
2299     AI.operand[3] = o4;
2300     AI.operand[4] = o5;
2301     AI.store_variable_number = -1;
2302     AI.branch_label_number = -1;
2303     assemblez_instruction(&AI);
2304 }
2305
2306 void assemblez_6(int internal_number,
2307     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2308     assembly_operand o4, assembly_operand o5, assembly_operand o6)
2309 {   AI.internal_number = internal_number;
2310     AI.operand_count = 6;
2311     AI.operand[0] = o1;
2312     AI.operand[1] = o2;
2313     AI.operand[2] = o3;
2314     AI.operand[3] = o4;
2315     AI.operand[4] = o5;
2316     AI.operand[5] = o6;
2317     AI.store_variable_number = -1;
2318     AI.branch_label_number = -1;
2319     assemblez_instruction(&AI);
2320 }
2321
2322 void assemblez_4_branch(int internal_number,
2323     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2324     assembly_operand o4, int label, int flag)
2325 {   AI.internal_number = internal_number;
2326     AI.operand_count = 4;
2327     AI.operand[0] = o1;
2328     AI.operand[1] = o2;
2329     AI.operand[2] = o3;
2330     AI.operand[3] = o4;
2331     AI.store_variable_number = -1;
2332     AI.branch_label_number = label;
2333     AI.branch_flag = flag;
2334     assemblez_instruction(&AI);
2335 }
2336
2337 void assemblez_4_to(int internal_number,
2338     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2339     assembly_operand o4, assembly_operand st)
2340 {   AI.internal_number = internal_number;
2341     AI.operand_count = 4;
2342     AI.operand[0] = o1;
2343     AI.operand[1] = o2;
2344     AI.operand[2] = o3;
2345     AI.operand[3] = o4;
2346     AI.store_variable_number = st.value;
2347     AI.branch_label_number = -1;
2348     assemblez_instruction(&AI);
2349 }
2350
2351 void assemblez_5_to(int internal_number,
2352     assembly_operand o1, assembly_operand o2, assembly_operand o3,
2353     assembly_operand o4, assembly_operand o5, assembly_operand st)
2354 {   AI.internal_number = internal_number;
2355     AI.operand_count = 5;
2356     AI.operand[0] = o1;
2357     AI.operand[1] = o2;
2358     AI.operand[2] = o3;
2359     AI.operand[3] = o4;
2360     AI.operand[4] = o5;
2361     AI.store_variable_number = st.value;
2362     AI.branch_label_number = -1;
2363     assemblez_instruction(&AI);
2364 }
2365
2366 void assemblez_2_to(int internal_number,
2367     assembly_operand o1, assembly_operand o2, assembly_operand st)
2368 {   AI.internal_number = internal_number;
2369     AI.operand_count = 2;
2370     AI.operand[0] = o1;
2371     AI.operand[1] = o2;
2372     AI.store_variable_number = st.value;
2373     AI.branch_label_number = -1;
2374     assemblez_instruction(&AI);
2375 }
2376
2377 void assemblez_2_branch(int internal_number,
2378     assembly_operand o1, assembly_operand o2, int label, int flag)
2379 {   AI.internal_number = internal_number;
2380     AI.operand_count = 2;
2381     AI.operand[0] = o1;
2382     AI.operand[1] = o2;
2383     AI.branch_label_number = label;
2384     AI.store_variable_number = -1;
2385     AI.branch_flag = flag;
2386     assemblez_instruction(&AI);
2387 }
2388
2389 void assemblez_objcode(int internal_number,
2390     assembly_operand o1, assembly_operand st, int label, int flag)
2391 {   AI.internal_number = internal_number;
2392     AI.operand_count = 1;
2393     AI.operand[0] = o1;
2394     AI.branch_label_number = label;
2395     AI.store_variable_number = st.value;
2396     AI.branch_flag = flag;
2397     assemblez_instruction(&AI);
2398 }
2399
2400 extern void assemblez_inc(assembly_operand o1)
2401 {   int m = 0;
2402     if ((o1.value >= MAX_LOCAL_VARIABLES) 
2403         && (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
2404             m = VARIABLE_MV;
2405     AI.internal_number = inc_zc;
2406     AI.operand_count = 1;
2407     AI.operand[0].value = o1.value;
2408     AI.operand[0].type = SHORT_CONSTANT_OT;
2409     AI.operand[0].marker = m;
2410     AI.store_variable_number = -1;
2411     AI.branch_label_number = -1;
2412     assemblez_instruction(&AI);
2413 }
2414
2415 extern void assemblez_dec(assembly_operand o1)
2416 {   int m = 0;
2417     if ((o1.value >= MAX_LOCAL_VARIABLES) 
2418         && (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
2419             m = VARIABLE_MV;
2420     AI.internal_number = dec_zc;
2421     AI.operand_count = 1;
2422     AI.operand[0].value = o1.value;
2423     AI.operand[0].type = SHORT_CONSTANT_OT;
2424     AI.operand[0].marker = m;
2425     AI.store_variable_number = -1;
2426     AI.branch_label_number = -1;
2427     assemblez_instruction(&AI);
2428 }
2429
2430 extern void assemblez_store(assembly_operand o1, assembly_operand o2)
2431 {   int m = 0;
2432     if ((o1.value >= MAX_LOCAL_VARIABLES)
2433         && (o1.value<LOWEST_SYSTEM_VAR_NUMBER))
2434             m = VARIABLE_MV;
2435
2436     if ((o2.type == VARIABLE_OT) && (o2.value == 0))
2437     {
2438         /*  Assemble "pull VAR" rather than "store VAR sp",
2439             saving 1 byte  */
2440
2441         AI.internal_number = pull_zc;
2442         if (instruction_set_number == 6)
2443         {   AI.operand_count = 0;
2444             AI.store_variable_number = o1.value;
2445         }
2446         else
2447         {   AI.operand_count = 1;
2448             AI.operand[0].value = o1.value;
2449             AI.operand[0].type = SHORT_CONSTANT_OT;
2450             AI.operand[0].marker = m;
2451             AI.store_variable_number = -1;
2452         }
2453         AI.branch_label_number = -1;
2454         assemblez_instruction(&AI);
2455         return;
2456     }
2457
2458     if ((o1.type == VARIABLE_OT) && (o1.value == 0))
2459     {   /*  Assemble "push VAR" rather than "store sp VAR",
2460             saving 1 byte  */
2461
2462         AI.internal_number = push_zc;
2463         AI.operand_count = 1;
2464         AI.operand[0] = o2;
2465         AI.store_variable_number = -1;
2466         AI.branch_label_number = -1;
2467         assemblez_instruction(&AI);
2468         return;
2469     }
2470     AI.internal_number = store_zc;
2471     AI.operand_count = 2;
2472     AI.operand[0].value = o1.value;
2473     AI.operand[0].type = SHORT_CONSTANT_OT;
2474     AI.operand[0].marker = m;
2475     AI.operand[1] = o2;
2476     AI.store_variable_number = -1;
2477     AI.branch_label_number = -1;
2478     assemblez_instruction(&AI);
2479 }
2480
2481 void assemblez_jump(int n)
2482 {   assembly_operand AO;
2483     if (n==-4) assemblez_0(rtrue_zc);
2484     else if (n==-3) assemblez_0(rfalse_zc);
2485     else
2486     {   AO.type = LONG_CONSTANT_OT; AO.value = n; AO.marker = 0;
2487         assemblez_1(jump_zc, AO);
2488     }
2489 }
2490
2491 void assembleg_0(int internal_number)
2492 {   AI.internal_number = internal_number;
2493     AI.operand_count = 0;
2494     assembleg_instruction(&AI);
2495 }
2496
2497 void assembleg_1(int internal_number, assembly_operand o1)
2498 {   AI.internal_number = internal_number;
2499     AI.operand_count = 1;
2500     AI.operand[0] = o1;
2501     assembleg_instruction(&AI);
2502 }
2503
2504 void assembleg_2(int internal_number, assembly_operand o1,
2505   assembly_operand o2)
2506 {   AI.internal_number = internal_number;
2507     AI.operand_count = 2;
2508     AI.operand[0] = o1;
2509     AI.operand[1] = o2;
2510     assembleg_instruction(&AI);
2511 }
2512
2513 void assembleg_3(int internal_number, assembly_operand o1,
2514   assembly_operand o2, assembly_operand o3)
2515 {   AI.internal_number = internal_number;
2516     AI.operand_count = 3;
2517     AI.operand[0] = o1;
2518     AI.operand[1] = o2;
2519     AI.operand[2] = o3;
2520     assembleg_instruction(&AI);
2521 }
2522
2523 void assembleg_4(int internal_number, assembly_operand o1,
2524   assembly_operand o2, assembly_operand o3,
2525   assembly_operand o4)
2526 {   AI.internal_number = internal_number;
2527     AI.operand_count = 4;
2528     AI.operand[0] = o1;
2529     AI.operand[1] = o2;
2530     AI.operand[2] = o3;
2531     AI.operand[3] = o4;
2532     assembleg_instruction(&AI);
2533 }
2534
2535 void assembleg_5(int internal_number, assembly_operand o1,
2536   assembly_operand o2, assembly_operand o3,
2537   assembly_operand o4, assembly_operand o5)
2538 {   AI.internal_number = internal_number;
2539     AI.operand_count = 5;
2540     AI.operand[0] = o1;
2541     AI.operand[1] = o2;
2542     AI.operand[2] = o3;
2543     AI.operand[3] = o4;
2544     AI.operand[4] = o5;
2545     assembleg_instruction(&AI);
2546 }
2547
2548 void assembleg_0_branch(int internal_number,
2549     int label)
2550 {
2551     AI.internal_number = internal_number;
2552     AI.operand_count = 1;
2553     AI.operand[0].type = CONSTANT_OT;
2554     AI.operand[0].value = label;
2555     AI.operand[0].marker = BRANCH_MV;
2556     assembleg_instruction(&AI);
2557 }
2558
2559 void assembleg_1_branch(int internal_number,
2560     assembly_operand o1, int label)
2561 {
2562     /* Some clever optimizations first. A constant is always or never equal
2563        to zero. */
2564     if (o1.marker == 0 && is_constant_ot(o1.type)) {
2565         if ((internal_number == jz_gc && o1.value == 0)
2566           || (internal_number == jnz_gc && o1.value != 0)) {
2567             assembleg_0_branch(jump_gc, label);
2568             /* We clear the "can't reach statement" flag here, 
2569                so that "if (1)" doesn't produce that warning. */
2570             execution_never_reaches_here = 0;
2571             return;
2572         }
2573         if ((internal_number == jz_gc && o1.value != 0)
2574           || (internal_number == jnz_gc && o1.value == 0)) {
2575             /* assemble nothing at all! */
2576             return;
2577         }
2578     }
2579     AI.internal_number = internal_number;
2580     AI.operand_count = 2;
2581     AI.operand[0] = o1;
2582     AI.operand[1].type = CONSTANT_OT;
2583     AI.operand[1].value = label;
2584     AI.operand[1].marker = BRANCH_MV;
2585     assembleg_instruction(&AI);
2586 }
2587
2588 void assembleg_2_branch(int internal_number,
2589     assembly_operand o1, assembly_operand o2, int label)
2590 {
2591     AI.internal_number = internal_number;
2592     AI.operand_count = 3;
2593     AI.operand[0] = o1;
2594     AI.operand[1] = o2;
2595     AI.operand[2].type = CONSTANT_OT;
2596     AI.operand[2].value = label;
2597     AI.operand[2].marker = BRANCH_MV;
2598     assembleg_instruction(&AI);
2599 }
2600
2601 void assembleg_call_1(assembly_operand oaddr, assembly_operand o1, 
2602   assembly_operand odest)
2603 {
2604   assembleg_3(callfi_gc, oaddr, o1, odest);
2605 }
2606
2607 void assembleg_call_2(assembly_operand oaddr, assembly_operand o1, 
2608   assembly_operand o2, assembly_operand odest)
2609 {
2610   assembleg_4(callfii_gc, oaddr, o1, o2, odest);
2611 }
2612
2613 void assembleg_call_3(assembly_operand oaddr, assembly_operand o1, 
2614   assembly_operand o2, assembly_operand o3, assembly_operand odest)
2615 {
2616   assembleg_5(callfiii_gc, oaddr, o1, o2, o3, odest);
2617 }
2618
2619 void assembleg_inc(assembly_operand o1)
2620 {
2621   AI.internal_number = add_gc;
2622   AI.operand_count = 3;
2623   AI.operand[0] = o1;
2624   AI.operand[1] = one_operand;
2625   AI.operand[2] = o1;
2626   assembleg_instruction(&AI);
2627 }
2628
2629 void assembleg_dec(assembly_operand o1)
2630 {
2631   AI.internal_number = sub_gc;
2632   AI.operand_count = 3;
2633   AI.operand[0] = o1;
2634   AI.operand[1] = one_operand;
2635   AI.operand[2] = o1;
2636   assembleg_instruction(&AI);
2637 }
2638
2639 void assembleg_store(assembly_operand o1, assembly_operand o2)
2640 {
2641     /* Note the order is reversed: "o1 = o2;" */
2642     assembleg_2(copy_gc, o2, o1);
2643 }
2644
2645 void assembleg_jump(int n)
2646 {
2647   if (n==-4) {
2648       assembleg_1(return_gc, one_operand);
2649   }
2650   else if (n==-3) {
2651       assembleg_1(return_gc, zero_operand); 
2652   }
2653   else {
2654       assembleg_0_branch(jump_gc, n);
2655   }
2656 }
2657
2658 /* ========================================================================= */
2659 /*   Parsing and then calling the assembler for @ (assembly language)        */
2660 /*   statements                                                              */
2661 /* ------------------------------------------------------------------------- */
2662
2663 static assembly_operand parse_operand_z(void)
2664 {   assembly_operand AO;
2665
2666     AO = parse_expression(ASSEMBLY_CONTEXT);
2667     if (AO.type == EXPRESSION_OT)
2668     {   ebf_error("variable or constant", "expression");
2669         AO.type = SHORT_CONSTANT_OT;
2670     }
2671     return(AO);
2672 }
2673
2674 static void parse_assembly_z(void)
2675 {   int n, min, max, indirect_addressed, error_flag = FALSE;
2676     opcodez O;
2677
2678     AI.operand_count = 0;
2679     AI.store_variable_number = -1;
2680     AI.branch_label_number = -1;
2681     AI.text = NULL;
2682
2683     opcode_names.enabled = TRUE;
2684     get_next_token();
2685     opcode_names.enabled = FALSE;
2686
2687     if (token_type == DQ_TT)
2688     {   int i;
2689         AI.internal_number = -1;
2690
2691         custom_opcode_z.name = (uchar *) token_text;
2692         custom_opcode_z.version1 = instruction_set_number;
2693         custom_opcode_z.version2 = instruction_set_number;
2694         custom_opcode_z.extension = -1;
2695         custom_opcode_z.flags = 0;
2696         custom_opcode_z.op_rules = 0;
2697         custom_opcode_z.flags2_set = 0;
2698         custom_opcode_z.no = ZERO;
2699
2700         for (i=0; token_text[i]!=0; i++)
2701         {   if (token_text[i] == ':')
2702             {   token_text[i++] = 0;
2703                 break;
2704             }
2705         }
2706         if (token_text[i] == 0)
2707             error("Opcode specification should have form \"VAR:102\"");
2708
2709         n = -1;
2710         if (strcmp(token_text, "0OP")==0)      n=ZERO;
2711         if (strcmp(token_text, "1OP")==0)      n=ONE;
2712         if (strcmp(token_text, "2OP")==0)      n=TWO;
2713         if (strcmp(token_text, "VAR")==0)      n=VAR;
2714         if (strcmp(token_text, "EXT")==0)      n=EXT;
2715         if (strcmp(token_text, "VAR_LONG")==0) n=VAR_LONG;
2716         if (strcmp(token_text, "EXT_LONG")==0) n=EXT_LONG;
2717
2718         if (i>0) token_text[i-1] = ':';
2719
2720         if (n==-1)
2721         {   ebf_error("Expected 0OP, 1OP, 2OP, VAR, EXT, VAR_LONG or EXT_LONG",
2722                 token_text);
2723             n = EXT;
2724         }
2725         custom_opcode_z.no = n;
2726
2727         custom_opcode_z.code = atoi(token_text+i);
2728         while (isdigit(token_text[i])) i++;
2729
2730         {   max = 0; min = 0;
2731             switch(n)
2732             {   case ZERO: case ONE: max = 16; break;
2733                 case VAR: case VAR_LONG: min = 32; max = 64; break;
2734                 case EXT: case EXT_LONG: max = 256; break;
2735                 case TWO: max = 32; break;
2736             }
2737             if ((custom_opcode_z.code < min) || (custom_opcode_z.code >= max))
2738             {   char range[32];
2739                 sprintf(range, "%d to %d", min, max-1);
2740             error_named("For this operand type, opcode number must be in range",
2741                     range);
2742                 custom_opcode_z.code = min;
2743             }
2744         }
2745
2746         while (token_text[i++] != 0)
2747         {   switch(token_text[i-1])
2748             {   case 'B': custom_opcode_z.flags |= Br; break;
2749                 case 'S': custom_opcode_z.flags |= St; break;
2750                 case 'T': custom_opcode_z.op_rules = TEXT; break;
2751                 case 'I': custom_opcode_z.op_rules = VARIAB; break;
2752                 case 'F': custom_opcode_z.flags2_set = atoi(token_text+i);
2753                           while (isdigit(token_text[i])) i++; break;
2754                 default:
2755                     error("Unknown flag: options are B (branch), S (store), \
2756 T (text), I (indirect addressing), F** (set this Flags 2 bit)");
2757                     break;
2758             }
2759         }
2760         O = custom_opcode_z;
2761     }
2762     else
2763     {   if (token_type != OPCODE_NAME_TT)
2764         {   ebf_error("an opcode name", token_text);
2765             panic_mode_error_recovery();
2766             return;
2767         }
2768         AI.internal_number = token_value;
2769         O = internal_number_to_opcode_z(AI.internal_number);
2770     }
2771
2772     indirect_addressed = (O.op_rules == VARIAB);
2773
2774     if (O.op_rules == TEXT)
2775     {   get_next_token();
2776         if (token_type != DQ_TT)
2777             ebf_error("literal text in double-quotes", token_text);
2778         AI.text = token_text;
2779         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
2780         get_next_token();
2781         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
2782         {   assemblez_instruction(&AI);
2783             return;
2784         }
2785         ebf_error("semicolon ';' after print string", token_text);
2786         put_token_back();
2787         return;
2788     }
2789
2790     return_sp_as_variable = TRUE;
2791     do
2792     {   get_next_token();
2793
2794         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
2795
2796         if ((token_type == SEP_TT) && (token_value == ARROW_SEP))
2797         {   if (AI.store_variable_number != -1)
2798                 error("Only one '->' store destination can be given");
2799             get_next_token();
2800             if ((token_type != SYMBOL_TT)
2801                 && (token_type != LOCAL_VARIABLE_TT))
2802                 ebf_error("variable name or 'sp'", token_text);
2803             n = 255;
2804             if (token_type == LOCAL_VARIABLE_TT) n = token_value;
2805             else
2806             {   if (strcmp(token_text, "sp") == 0) n = 0;
2807                 else
2808                 {   if (stypes[token_value] != GLOBAL_VARIABLE_T)
2809                         error_named(
2810                             "Store '->' destination not 'sp' or a variable:",
2811                             token_text);
2812                     else n = svals[token_value];
2813                 }
2814             }
2815             AI.store_variable_number = n;
2816             continue;
2817         }
2818
2819         if ((token_type == SEP_TT) &&
2820             ((token_value == BRANCH_SEP) || (token_value == NBRANCH_SEP)))
2821         {   if (AI.branch_label_number != -1)
2822                 error("Only one '?' branch destination can be given");
2823
2824             AI.branch_flag = (token_value == BRANCH_SEP);
2825
2826             opcode_names.enabled = TRUE;
2827             get_next_token();
2828             opcode_names.enabled = FALSE;
2829
2830             n = -2;
2831             if ((token_type == OPCODE_NAME_TT)
2832                 && (token_value == rfalse_zc)) n = -3;
2833             else
2834             if ((token_type == OPCODE_NAME_TT)
2835                 && (token_value == rtrue_zc)) n = -4;
2836             else
2837             {   if (token_type == SYMBOL_TT)
2838                 {   put_token_back();
2839                     n = parse_label();
2840                 }
2841                 else
2842                     ebf_error("label name after '?' or '?~'", token_text);
2843             }
2844             AI.branch_label_number = n;
2845             continue;
2846         }
2847
2848         if (AI.operand_count == 8)
2849         {   error("No assembly instruction may have more than 8 operands");
2850             panic_mode_error_recovery(); break;
2851         }
2852
2853         if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
2854         {   if (!indirect_addressed)
2855                 error("This opcode does not use indirect addressing");
2856             if (AI.operand_count > 0)
2857             error("Indirect addressing can only be used on the first operand");
2858             AI.operand[AI.operand_count++] = parse_operand_z();
2859             get_next_token();
2860             if (!((token_type == SEP_TT) && (token_value == CLOSE_SQUARE_SEP)))
2861             {   ebf_error("']'", token_text);
2862                 put_token_back();
2863             }
2864         }
2865         else
2866         {   put_token_back();
2867             AI.operand[AI.operand_count++] = parse_operand_z();
2868             if ((indirect_addressed) && (AI.operand_count == 1)
2869                 && (AI.operand[AI.operand_count-1].type == VARIABLE_OT))
2870             {   AI.operand[AI.operand_count-1].type = SHORT_CONSTANT_OT;
2871                 AI.operand[AI.operand_count-1].marker = VARIABLE_MV;
2872             }
2873         }
2874
2875     } while (TRUE);
2876
2877     return_sp_as_variable = FALSE;
2878
2879
2880     if (O.version1 == 0)
2881     {   error_named("Opcode unavailable in this Z-machine version:",
2882             opcode_names.keywords[AI.internal_number]);
2883         return;
2884     }
2885
2886     if (((O.flags) & Br) != 0)
2887     {   if (AI.branch_label_number == -1)
2888         {   error_flag = TRUE;
2889             AI.branch_label_number = -2;
2890         }
2891     }
2892     else
2893     {   if (AI.branch_label_number != -1)
2894         {   error_flag = TRUE;
2895             AI.branch_label_number = -1;
2896         }
2897     }
2898     if (((O.flags) & St) != 0)
2899     {   if (AI.store_variable_number == -1)
2900         {   if (AI.operand_count == 0)
2901             {   error_flag = TRUE;
2902                 AI.store_variable_number = 255;
2903             }
2904             else
2905             {   AI.store_variable_number
2906                     = AI.operand[--AI.operand_count].value;
2907                 if (AI.operand[AI.operand_count].type != VARIABLE_OT)
2908             error("Store destination (the last operand) is not a variable");
2909             }
2910         }
2911     }
2912     else
2913     {   if (AI.store_variable_number != -1)
2914         {   error_flag = TRUE;
2915             AI.store_variable_number = -1;
2916         }
2917     }
2918
2919     min = 0; max = 0;
2920     switch(O.no)
2921     {   case TWO:      min = 2; max = 2;
2922                        /* Exception for the V6 set_colour, which can take
2923                           a third argument, thus forcing it into VAR form: */
2924                        if ((version_number == 6) && (O.code == 0x1b)) max = 3;
2925                        /* Also an exception for je, which can take from 1
2926                           argument (useless) to 4 arguments */
2927                        if (O.code == 0x01) { min = 1; max = 4; }
2928                        break;
2929         case VAR:      min = 0; max = 4; break;
2930         case VAR_LONG: min = 0; max = 8; break;
2931         case ONE:      min = 1; max = 1; break;
2932         case ZERO:     min = 0; max = 0; break;
2933         case EXT:      min = 0; max = 4; break;
2934         case EXT_LONG: min = 0; max = 8; break;
2935     }
2936
2937     if ((AI.operand_count >= min) && (AI.operand_count <= max))
2938         assemblez_instruction(&AI);
2939     else error_flag = TRUE;
2940
2941     if (error_flag)
2942     {   make_opcode_syntax_z(O);
2943         error_named("Assembly mistake: syntax is",
2944             opcode_syntax_string);
2945     }
2946 }
2947
2948 static assembly_operand parse_operand_g(void)
2949 {   assembly_operand AO;
2950
2951     AO = parse_expression(ASSEMBLY_CONTEXT);
2952     if (AO.type == EXPRESSION_OT)
2953     {   ebf_error("variable or constant", "expression");
2954         AO.type = CONSTANT_OT;
2955     }
2956     return(AO);
2957 }
2958
2959 static void parse_assembly_g(void)
2960 {
2961   opcodeg O;
2962   assembly_operand AO;
2963   int error_flag = FALSE, is_macro = FALSE;
2964
2965   AI.operand_count = 0;
2966
2967   opcode_names.enabled = TRUE;
2968   opcode_macros.enabled = TRUE;
2969   get_next_token();
2970   opcode_names.enabled = FALSE;
2971   opcode_macros.enabled = FALSE;
2972
2973   if (token_type == DQ_TT) {
2974     char *cx;
2975     int badflags;
2976
2977     AI.internal_number = -1;
2978
2979     /* The format is @"FlagsCount:Code". Flags (which are optional)
2980        can include "S" for store, "SS" for two stores, "B" for branch
2981        format, "R" if execution never continues after the opcode. The
2982        Count is the number of arguments (currently limited to 0-9),
2983        and the Code is a decimal integer representing the opcode
2984        number.
2985
2986        So: @"S3:123" for a three-argument opcode (load, load, store)
2987        whose opcode number is (decimal) 123. Or: @"2:234" for a
2988        two-argument opcode (load, load) whose number is 234. */
2989
2990     custom_opcode_g.name = (uchar *) token_text;
2991     custom_opcode_g.flags = 0;
2992     custom_opcode_g.op_rules = 0;
2993     custom_opcode_g.no = 0;
2994
2995     badflags = FALSE;
2996
2997     for (cx = token_text; *cx && *cx != ':'; cx++) {
2998       if (badflags)
2999       continue;
3000
3001       switch (*cx) {
3002       case 'S':
3003       if (custom_opcode_g.flags & St)
3004         custom_opcode_g.flags |= St2;
3005       else
3006         custom_opcode_g.flags |= St;
3007       break;
3008       case 'B':
3009       custom_opcode_g.flags |= Br;
3010       break;
3011       case 'R':
3012       custom_opcode_g.flags |= Rf;
3013       break;
3014       default:
3015       if (isdigit(*cx)) {
3016         custom_opcode_g.no = (*cx) - '0';
3017         break;
3018       }
3019       badflags = TRUE;
3020       error("Unknown custom opcode flag: options are B (branch), \
3021 S (store), SS (two stores), R (execution never continues)");
3022       break;
3023       }
3024     }
3025
3026     if (*cx != ':') {
3027       error("Custom opcode must have colon");
3028     }
3029     else {
3030       cx++;
3031       if (!(*cx))
3032       error("Custom opcode must have colon followed by opcode number");
3033       else
3034       custom_opcode_g.code = atoi(cx);
3035     }
3036
3037     O = custom_opcode_g;
3038   }
3039   else {
3040     if (token_type != OPCODE_NAME_TT && token_type != OPCODE_MACRO_TT) {
3041       ebf_error("an opcode name", token_text);
3042       panic_mode_error_recovery();
3043       return;
3044     }
3045     AI.internal_number = token_value;
3046     if (token_type == OPCODE_MACRO_TT) {
3047       O = internal_number_to_opmacro_g(AI.internal_number);
3048       is_macro = TRUE;
3049     }
3050     else
3051       O = internal_number_to_opcode_g(AI.internal_number);
3052   }
3053   
3054   return_sp_as_variable = TRUE;
3055
3056   while (1) {
3057     get_next_token();
3058     
3059     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) 
3060       break;
3061
3062     if (AI.operand_count == 8) {
3063       error("No assembly instruction may have more than 8 operands");
3064       panic_mode_error_recovery(); 
3065       break;
3066     }
3067
3068     if ((O.flags & Br) && (AI.operand_count == O.no-1)) {
3069       if (!((token_type == SEP_TT) && (token_value == BRANCH_SEP))) {
3070         error_flag = TRUE;
3071         error("Branch opcode must have '?' label");
3072         put_token_back();
3073       }
3074       AO.type = CONSTANT_OT;
3075       AO.value = parse_label();
3076       AO.marker = BRANCH_MV;
3077     }
3078     else {
3079       put_token_back();
3080       AO = parse_operand_g();
3081     }
3082
3083     AI.operand[AI.operand_count] = AO;
3084     AI.operand_count++;
3085   }
3086
3087   return_sp_as_variable = FALSE;
3088
3089   if (O.no != AI.operand_count) {
3090     error_flag = TRUE;
3091   }
3092
3093   if (!error_flag) {
3094     if (is_macro)
3095       assembleg_macro(&AI);
3096     else
3097       assembleg_instruction(&AI);
3098   }
3099
3100   if (error_flag) {
3101     make_opcode_syntax_g(O);
3102     error_named("Assembly mistake: syntax is",
3103       opcode_syntax_string);
3104   }
3105 }
3106
3107 extern void parse_assembly(void)
3108 {
3109   if (!glulx_mode)
3110     parse_assembly_z();
3111   else
3112     parse_assembly_g();
3113 }
3114
3115 /* ========================================================================= */
3116 /*   Data structure management routines                                      */
3117 /* ------------------------------------------------------------------------- */
3118
3119 extern void asm_begin_pass(void)
3120 {   no_instructions = 0;
3121     zmachine_pc = 0;
3122     no_sequence_points = 0;
3123     next_label = 0;
3124     next_sequence_point = 0;
3125     zcode_ha_size = 0;
3126 }
3127
3128 extern void init_asm_vars(void)
3129 {   int i;
3130
3131     for (i=0;i<16;i++) flags2_requirements[i]=0;
3132
3133     uses_unicode_features = FALSE;
3134     uses_memheap_features = FALSE;
3135     uses_acceleration_features = FALSE;
3136     uses_float_features = FALSE;
3137
3138     sequence_point_follows = TRUE;
3139     label_moved_error_already_given = FALSE;
3140
3141     initialise_memory_block(&zcode_area);
3142 }
3143
3144 extern void asm_allocate_arrays(void)
3145 {   if ((debugfile_switch) && (MAX_LABELS < 2000)) MAX_LABELS = 2000;
3146
3147     variable_tokens = my_calloc(sizeof(int32),  
3148         MAX_LOCAL_VARIABLES+MAX_GLOBAL_VARIABLES, "variable tokens");
3149     variable_usage = my_calloc(sizeof(int),  
3150         MAX_LOCAL_VARIABLES+MAX_GLOBAL_VARIABLES, "variable usage");
3151
3152     label_offsets = my_calloc(sizeof(int32), MAX_LABELS, "label offsets");
3153     label_symbols = my_calloc(sizeof(int32), MAX_LABELS, "label symbols");
3154     label_next = my_calloc(sizeof(int), MAX_LABELS, "label dll 1");
3155     label_prev = my_calloc(sizeof(int), MAX_LABELS, "label dll 1");
3156     sequence_point_labels
3157         = my_calloc(sizeof(int), MAX_LABELS, "sequence point labels");
3158     sequence_point_locations
3159         = my_calloc(sizeof(debug_location),
3160                     MAX_LABELS,
3161                     "sequence point locations");
3162
3163     zcode_holding_area = my_malloc(MAX_ZCODE_SIZE,"compiled routine code area");
3164     zcode_markers = my_malloc(MAX_ZCODE_SIZE, "compiled routine code area");
3165
3166     named_routine_symbols
3167         = my_calloc(sizeof(int32), MAX_SYMBOLS, "named routine symbols");
3168 }
3169
3170 extern void asm_free_arrays(void)
3171 {
3172     my_free(&variable_tokens, "variable tokens");
3173     my_free(&variable_usage, "variable usage");
3174
3175     my_free(&label_offsets, "label offsets");
3176     my_free(&label_symbols, "label symbols");
3177     my_free(&label_next, "label dll 1");
3178     my_free(&label_prev, "label dll 2");
3179     my_free(&sequence_point_labels, "sequence point labels");
3180     my_free(&sequence_point_locations, "sequence point locations");
3181
3182     my_free(&zcode_holding_area, "compiled routine code area");
3183     my_free(&zcode_markers, "compiled routine code markers");
3184
3185     my_free(&named_routine_symbols, "named routine symbols");
3186     deallocate_memory_block(&zcode_area);
3187 }
3188
3189 /* ========================================================================= */