Update to commit e2647ad952b4d7afc9a186429c181efbc4958786
[inform.git] / src / states.c
1 /* ------------------------------------------------------------------------- */
2 /*   "states" :  Statement translator                                        */
3 /*                                                                           */
4 /*   Part of Inform 6.35                                                     */
5 /*   copyright (c) Graham Nelson 1993 - 2020                                 */
6 /*                                                                           */
7 /* Inform is free software: you can redistribute it and/or modify            */
8 /* it under the terms of the GNU General Public License as published by      */
9 /* the Free Software Foundation, either version 3 of the License, or         */
10 /* (at your option) any later version.                                       */
11 /*                                                                           */
12 /* Inform is distributed in the hope that it will be useful,                 */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
15 /* GNU General Public License for more details.                              */
16 /*                                                                           */
17 /* You should have received a copy of the GNU General Public License         */
18 /* along with Inform. If not, see https://gnu.org/licenses/                  *
19 /*                                                                           */
20 /* ------------------------------------------------------------------------- */
21
22 #include "header.h"
23
24 static int match_colon(void)
25 {   get_next_token();
26     if (token_type == SEP_TT)
27     {   if (token_value == SEMICOLON_SEP)
28             warning("Unlike C, Inform uses ':' to divide parts \
29 of a 'for' loop specification: replacing ';' with ':'");
30         else
31         if (token_value != COLON_SEP)
32         {   ebf_error("':'", token_text);
33             panic_mode_error_recovery();
34             return(FALSE);
35         }
36     }
37     else
38     {   ebf_error("':'", token_text);
39         panic_mode_error_recovery();
40         return(FALSE);
41     }
42     return(TRUE);
43 }
44
45 static void match_open_bracket(void)
46 {   get_next_token();
47     if ((token_type == SEP_TT) && (token_value == OPENB_SEP)) return;
48     put_token_back();
49     ebf_error("'('", token_text);
50 }
51
52 extern void match_close_bracket(void)
53 {   get_next_token();
54     if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP)) return;
55     put_token_back();
56     ebf_error("')'", token_text);
57 }
58
59 static void parse_action(void)
60 {   int level = 1, args = 0, codegen_action;
61     assembly_operand AO, AO2, AO3, AO4, AO5;
62
63     /* An action statement has the form <ACTION NOUN SECOND, ACTOR>
64        or <<ACTION NOUN SECOND, ACTOR>>. It simply compiles into a call
65        to R_Process() with those four arguments. (The latter form,
66        with double brackets, means "return true afterwards".)
67
68        The R_Process() function should be supplied by the library, 
69        although a stub is defined in the veneer.
70
71        The NOUN, SECOND, and ACTOR arguments are optional. If not
72        supplied, R_Process() will be called with fewer arguments. 
73        (But if you supply ACTOR, it must be preceded by a comma.
74        <ACTION, ACTOR> is equivalent to <ACTION 0 0, ACTOR>.)
75
76        To complicate life, the ACTION argument may be a bare action
77        name or a parenthesized expression. (So <Take> is equivalent
78        to <(##Take)>.) We have to peek at the first token, checking
79        whether it's an open-paren, to distinguish these cases.
80
81        You may ask why the ACTOR argument is last; the "natural"
82        Inform ordering would be "<floyd, take ball>". True! Sadly,
83        Inform's lexer isn't smart enough to parse this consistently,
84        so we can't do it.
85     */
86
87     dont_enter_into_symbol_table = TRUE;
88     get_next_token();
89     if ((token_type == SEP_TT) && (token_value == LESS_SEP))
90     {   level = 2; get_next_token();
91     }
92     dont_enter_into_symbol_table = FALSE;
93
94     /* Peek at the next token; see if it's an open-paren. */
95     if ((token_type==SEP_TT) && (token_value==OPENB_SEP))
96     {   put_token_back();
97         AO2 = parse_expression(ACTION_Q_CONTEXT);
98         codegen_action = TRUE;
99     }
100     else
101     {   codegen_action = FALSE;
102         AO2 = action_of_name(token_text);
103     }
104
105     get_next_token();
106     AO3 = zero_operand;
107     AO4 = zero_operand;
108     AO5 = zero_operand;
109     if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
110     {   put_token_back();
111         args = 1;
112         AO3 = parse_expression(ACTION_Q_CONTEXT);
113
114         get_next_token();
115     }
116     if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
117     {   put_token_back();
118         args = 2;
119         AO4 = parse_expression(QUANTITY_CONTEXT);
120         get_next_token();
121     }
122     if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
123     {
124         ebf_error("',' or '>'", token_text);
125     }
126
127     if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
128     {
129         if (!glulx_mode && (version_number < 4))
130         {
131             error("<x, y> syntax is not available in Z-code V3 or earlier");
132         }
133         args = 3;
134         AO5 = parse_expression(QUANTITY_CONTEXT);
135         get_next_token();
136         if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
137         {
138             ebf_error("'>'", token_text);
139         }
140     }
141
142     if (level == 2)
143     {   get_next_token();
144         if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
145         {   put_token_back();
146             ebf_error("'>>'", token_text);
147         }
148     }
149
150     if (!glulx_mode) {
151
152       AO = veneer_routine(R_Process_VR);
153
154       switch(args)
155       {   case 0:
156             if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
157             if (version_number>=5)
158                 assemblez_2(call_2n_zc, AO, AO2);
159             else
160             if (version_number==4)
161                 assemblez_2_to(call_vs_zc, AO, AO2, temp_var1);
162             else
163                 assemblez_2_to(call_zc, AO, AO2, temp_var1);
164             break;
165           case 1:
166             AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
167             if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
168             if (version_number>=5)
169                 assemblez_3(call_vn_zc, AO, AO2, AO3);
170             else
171             if (version_number==4)
172                 assemblez_3_to(call_vs_zc, AO, AO2, AO3, temp_var1);
173             else
174                 assemblez_3_to(call_zc, AO, AO2, AO3, temp_var1);
175             break;
176           case 2:
177             AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
178             AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
179             if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
180             if (version_number>=5)
181                 assemblez_4(call_vn_zc, AO, AO2, AO3, AO4);
182             else
183             if (version_number==4)
184                 assemblez_4_to(call_vs_zc, AO, AO2, AO3, AO4, temp_var1);
185             else
186                 assemblez_4_to(call_zc, AO, AO2, AO3, AO4, temp_var1);
187             break;
188           case 3:
189             AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
190             AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
191             AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
192             if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
193             if (version_number>=5)
194                 assemblez_5(call_vn2_zc, AO, AO2, AO3, AO4, AO5);
195             else
196             if (version_number==4)
197                 assemblez_5_to(call_vs2_zc, AO, AO2, AO3, AO4, AO5, temp_var1);
198             /* if V3 or earlier, we've already displayed an error */
199             break;
200             break;
201       }
202
203       if (level == 2) assemblez_0(rtrue_zc);
204
205     }
206     else {
207
208       AO = veneer_routine(R_Process_VR);
209
210       switch (args) {
211
212       case 0:
213         if (codegen_action) 
214           AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
215         assembleg_call_1(AO, AO2, zero_operand);
216         break;
217
218       case 1:
219         AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
220         if (codegen_action)
221           AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
222         assembleg_call_2(AO, AO2, AO3, zero_operand);
223         break;
224
225       case 2:
226         AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
227         AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
228         if (codegen_action) 
229           AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
230         assembleg_call_3(AO, AO2, AO3, AO4, zero_operand);
231         break;
232
233       case 3:
234         AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
235         if (!((AO5.type == LOCALVAR_OT) && (AO5.value == 0)))
236             assembleg_store(stack_pointer, AO5);
237         AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
238         if (!((AO4.type == LOCALVAR_OT) && (AO4.value == 0)))
239             assembleg_store(stack_pointer, AO4);
240         AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
241         if (!((AO3.type == LOCALVAR_OT) && (AO3.value == 0)))
242             assembleg_store(stack_pointer, AO3);
243         if (codegen_action) 
244           AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
245         if (!((AO2.type == LOCALVAR_OT) && (AO2.value == 0)))
246           assembleg_store(stack_pointer, AO2);
247         assembleg_3(call_gc, AO, four_operand, zero_operand);
248         break;
249       }
250
251       if (level == 2) 
252         assembleg_1(return_gc, one_operand);
253
254     }
255 }
256
257 extern int parse_label(void)
258 {
259     get_next_token();
260
261     if ((token_type == SYMBOL_TT) &&
262         (stypes[token_value] == LABEL_T))
263     {   sflags[token_value] |= USED_SFLAG;
264         return(svals[token_value]);
265     }
266
267     if ((token_type == SYMBOL_TT) && (sflags[token_value] & UNKNOWN_SFLAG))
268     {   assign_symbol(token_value, next_label, LABEL_T);
269         define_symbol_label(token_value);
270         next_label++;
271         sflags[token_value] |= CHANGE_SFLAG + USED_SFLAG;
272         return(svals[token_value]);
273     }
274
275     ebf_error("label name", token_text);
276     return 0;
277 }
278
279 static void parse_print_z(int finally_return)
280 {   int count = 0; assembly_operand AO;
281
282     /*  print <printlist> -------------------------------------------------- */
283     /*  print_ret <printlist> ---------------------------------------------- */
284     /*  <literal-string> --------------------------------------------------- */
285     /*                                                                       */
286     /*  <printlist> is a comma-separated list of items:                      */
287     /*                                                                       */
288     /*       <literal-string>                                                */
289     /*       <other-expression>                                              */
290     /*       (char) <expression>                                             */
291     /*       (address) <expression>                                          */
292     /*       (string) <expression>                                           */
293     /*       (a) <expression>                                                */
294     /*       (the) <expression>                                              */
295     /*       (The) <expression>                                              */
296     /*       (name) <expression>                                             */
297     /*       (number) <expression>                                           */
298     /*       (property) <expression>                                         */
299     /*       (<routine>) <expression>                                        */
300     /*       (object) <expression>     (for use in low-level code only)      */
301     /* --------------------------------------------------------------------- */
302
303     do
304     {   AI.text = token_text;
305         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
306         switch(token_type)
307         {   case DQ_TT:
308               if (strlen(token_text) > 32)
309               {   INITAOT(&AO, LONG_CONSTANT_OT);
310                   AO.marker = STRING_MV;
311                   AO.value  = compile_string(token_text, FALSE, FALSE);
312                   assemblez_1(print_paddr_zc, AO);
313                   if (finally_return)
314                   {   get_next_token();
315                       if ((token_type == SEP_TT)
316                           && (token_value == SEMICOLON_SEP))
317                       {   assemblez_0(new_line_zc);
318                           assemblez_0(rtrue_zc);
319                           return;
320                       }
321                       put_token_back();
322                   }
323                   break;
324               }
325               if (finally_return)
326               {   get_next_token();
327                   if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
328                   {   assemblez_0(print_ret_zc); return;
329                   }
330                   put_token_back();
331               }
332               assemblez_0(print_zc);
333               break;
334
335             case SEP_TT:
336               if (token_value == OPENB_SEP)
337               {   misc_keywords.enabled = TRUE;
338                   get_next_token();
339                   get_next_token();
340                   if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
341                   {   assembly_operand AO1;
342
343                       put_token_back(); put_token_back();
344                       local_variables.enabled = FALSE;
345                       get_next_token();
346                       misc_keywords.enabled = FALSE;
347                       local_variables.enabled = TRUE;
348
349                       if ((token_type == STATEMENT_TT)
350                           &&(token_value == STRING_CODE))
351                       {   token_type = MISC_KEYWORD_TT;
352                           token_value = STRING_MK;
353                       }
354
355                       switch(token_type)
356                       {
357                         case MISC_KEYWORD_TT:
358                           switch(token_value)
359                           {   case CHAR_MK:
360                                   if (runtime_error_checking_switch)
361                                   {   AO = veneer_routine(RT__ChPrintC_VR);
362                                       goto PrintByRoutine;
363                                   }
364                                   get_next_token();
365                                   AO1 = code_generate(
366                                       parse_expression(QUANTITY_CONTEXT),
367                                       QUANTITY_CONTEXT, -1);
368                                   assemblez_1(print_char_zc, AO1);
369                                   goto PrintTermDone;
370                               case ADDRESS_MK:
371                                   if (runtime_error_checking_switch)
372                                   {   AO = veneer_routine(RT__ChPrintA_VR);
373                                       goto PrintByRoutine;
374                                   }
375                                   get_next_token();
376                                   AO1 = code_generate(
377                                       parse_expression(QUANTITY_CONTEXT),
378                                       QUANTITY_CONTEXT, -1);
379                                   assemblez_1(print_addr_zc, AO1);
380                                   goto PrintTermDone;
381                               case STRING_MK:
382                                   if (runtime_error_checking_switch)
383                                   {   AO = veneer_routine(RT__ChPrintS_VR);
384                                       goto PrintByRoutine;
385                                   }
386                                   get_next_token();
387                                   AO1 = code_generate(
388                                       parse_expression(QUANTITY_CONTEXT),
389                                       QUANTITY_CONTEXT, -1);
390                                   assemblez_1(print_paddr_zc, AO1);
391                                   goto PrintTermDone;
392                               case OBJECT_MK:
393                                   if (runtime_error_checking_switch)
394                                   {   AO = veneer_routine(RT__ChPrintO_VR);
395                                       goto PrintByRoutine;
396                                   }
397                                   get_next_token();
398                                   AO1 = code_generate(
399                                       parse_expression(QUANTITY_CONTEXT),
400                                       QUANTITY_CONTEXT, -1);
401                                   assemblez_1(print_obj_zc, AO1);
402                                   goto PrintTermDone;
403                               case THE_MK:
404                                   AO = veneer_routine(DefArt_VR);
405                                   goto PrintByRoutine;
406                               case AN_MK:
407                               case A_MK:
408                                   AO = veneer_routine(InDefArt_VR);
409                                   goto PrintByRoutine;
410                               case CAP_THE_MK:
411                                   AO = veneer_routine(CDefArt_VR);
412                                   goto PrintByRoutine;
413                               case CAP_A_MK:
414                                   AO = veneer_routine(CInDefArt_VR);
415                                   goto PrintByRoutine;
416                               case NAME_MK:
417                                   AO = veneer_routine(PrintShortName_VR);
418                                   goto PrintByRoutine;
419                               case NUMBER_MK:
420                                   AO = veneer_routine(EnglishNumber_VR);
421                                   goto PrintByRoutine;
422                               case PROPERTY_MK:
423                                   AO = veneer_routine(Print__Pname_VR);
424                                   goto PrintByRoutine;
425                               default:
426                error_named("A reserved word was used as a print specification:",
427                                       token_text);
428                           }
429                           break;
430
431                         case SYMBOL_TT:
432                           if (sflags[token_value] & UNKNOWN_SFLAG)
433                           {   INITAOT(&AO, LONG_CONSTANT_OT);
434                               AO.value = token_value;
435                               AO.marker = SYMBOL_MV;
436                           }
437                           else
438                           {   INITAOT(&AO, LONG_CONSTANT_OT);
439                               AO.value = svals[token_value];
440                               AO.marker = IROUTINE_MV;
441                               if (stypes[token_value] != ROUTINE_T)
442                                 ebf_error("printing routine name", token_text);
443                           }
444                           sflags[token_value] |= USED_SFLAG;
445
446                           PrintByRoutine:
447
448                           get_next_token();
449                           if (version_number >= 5)
450                             assemblez_2(call_2n_zc, AO,
451                               code_generate(parse_expression(QUANTITY_CONTEXT),
452                                 QUANTITY_CONTEXT, -1));
453                           else if (version_number == 4)
454                             assemblez_2_to(call_vs_zc, AO,
455                               code_generate(parse_expression(QUANTITY_CONTEXT),
456                                 QUANTITY_CONTEXT, -1), temp_var1);
457                           else
458                             assemblez_2_to(call_zc, AO,
459                               code_generate(parse_expression(QUANTITY_CONTEXT),
460                                 QUANTITY_CONTEXT, -1), temp_var1);
461                           goto PrintTermDone;
462
463                         default: ebf_error("print specification", token_text);
464                           get_next_token();
465                           assemblez_1(print_num_zc,
466                           code_generate(parse_expression(QUANTITY_CONTEXT),
467                                 QUANTITY_CONTEXT, -1));
468                           goto PrintTermDone;
469                       }
470                   }
471                   put_token_back(); put_token_back(); put_token_back();
472                   misc_keywords.enabled = FALSE;
473                   assemblez_1(print_num_zc,
474                       code_generate(parse_expression(QUANTITY_CONTEXT),
475                           QUANTITY_CONTEXT, -1));
476                   break;
477               }
478
479             default:
480               put_token_back(); misc_keywords.enabled = FALSE;
481               assemblez_1(print_num_zc,
482                   code_generate(parse_expression(QUANTITY_CONTEXT),
483                       QUANTITY_CONTEXT, -1));
484               break;
485         }
486
487         PrintTermDone: misc_keywords.enabled = FALSE;
488
489         count++;
490         get_next_token();
491         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
492         if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
493         {   ebf_error("comma", token_text);
494             panic_mode_error_recovery(); return;
495         }
496         else get_next_token();
497     } while(TRUE);
498
499     if (count == 0) ebf_error("something to print", token_text);
500     if (finally_return)
501     {   assemblez_0(new_line_zc);
502         assemblez_0(rtrue_zc);
503     }
504 }
505
506 static void parse_print_g(int finally_return)
507 {   int count = 0; assembly_operand AO, AO2;
508
509     /*  print <printlist> -------------------------------------------------- */
510     /*  print_ret <printlist> ---------------------------------------------- */
511     /*  <literal-string> --------------------------------------------------- */
512     /*                                                                       */
513     /*  <printlist> is a comma-separated list of items:                      */
514     /*                                                                       */
515     /*       <literal-string>                                                */
516     /*       <other-expression>                                              */
517     /*       (char) <expression>                                             */
518     /*       (address) <expression>                                          */
519     /*       (string) <expression>                                           */
520     /*       (a) <expression>                                                */
521     /*       (A) <expression>                                                */
522     /*       (the) <expression>                                              */
523     /*       (The) <expression>                                              */
524     /*       (name) <expression>                                             */
525     /*       (number) <expression>                                           */
526     /*       (property) <expression>                                         */
527     /*       (<routine>) <expression>                                        */
528     /*       (object) <expression>     (for use in low-level code only)      */
529     /* --------------------------------------------------------------------- */
530
531     do
532     {   
533         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
534         switch(token_type)
535         {   case DQ_TT:
536               /* We can't compile a string into the instruction,
537                  so this always goes into the string area. */
538               {   INITAOT(&AO, CONSTANT_OT);
539                   AO.marker = STRING_MV;
540                   AO.value  = compile_string(token_text, FALSE, FALSE);
541                   assembleg_1(streamstr_gc, AO);
542                   if (finally_return)
543                   {   get_next_token();
544                       if ((token_type == SEP_TT)
545                           && (token_value == SEMICOLON_SEP))
546                       {   INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
547                           assembleg_1(streamchar_gc, AO); 
548                           INITAOTV(&AO, BYTECONSTANT_OT, 1);
549                           assembleg_1(return_gc, AO); 
550                           return;
551                       }
552                       put_token_back();
553                   }
554                   break;
555               }
556               break;
557
558             case SEP_TT:
559               if (token_value == OPENB_SEP)
560               {   misc_keywords.enabled = TRUE;
561                   get_next_token();
562                   get_next_token();
563                   if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
564                   {   assembly_operand AO1;
565                       int ln, ln2;
566
567                       put_token_back(); put_token_back();
568                       local_variables.enabled = FALSE;
569                       get_next_token();
570                       misc_keywords.enabled = FALSE;
571                       local_variables.enabled = TRUE;
572
573                       if ((token_type == STATEMENT_TT)
574                           &&(token_value == STRING_CODE))
575                       {   token_type = MISC_KEYWORD_TT;
576                           token_value = STRING_MK;
577                       }
578
579                       switch(token_type)
580                       {
581                         case MISC_KEYWORD_TT:
582                           switch(token_value)
583                           {   case CHAR_MK:
584                                   if (runtime_error_checking_switch)
585                                   {   AO = veneer_routine(RT__ChPrintC_VR);
586                                       goto PrintByRoutine;
587                                   }
588                                   get_next_token();
589                                   AO1 = code_generate(
590                                       parse_expression(QUANTITY_CONTEXT),
591                                       QUANTITY_CONTEXT, -1);
592                                   if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0))
593                                   {   assembleg_2(stkpeek_gc, zero_operand, 
594                                       stack_pointer);
595                                   }
596                                   INITAOTV(&AO2, HALFCONSTANT_OT, 0x100);
597                                   assembleg_2_branch(jgeu_gc, AO1, AO2, 
598                                       ln = next_label++);
599                                   ln2 = next_label++;
600                                   assembleg_1(streamchar_gc, AO1);
601                                   assembleg_jump(ln2);
602                                   assemble_label_no(ln);
603                                   assembleg_1(streamunichar_gc, AO1);
604                                   assemble_label_no(ln2);
605                                   goto PrintTermDone;
606                               case ADDRESS_MK:
607                                   if (runtime_error_checking_switch)
608                                       AO = veneer_routine(RT__ChPrintA_VR);
609                                   else
610                                       AO = veneer_routine(Print__Addr_VR);
611                                   goto PrintByRoutine;
612                               case STRING_MK:
613                                   if (runtime_error_checking_switch)
614                                   {   AO = veneer_routine(RT__ChPrintS_VR);
615                                       goto PrintByRoutine;
616                                   }
617                                   get_next_token();
618                                   AO1 = code_generate(
619                                       parse_expression(QUANTITY_CONTEXT),
620                                       QUANTITY_CONTEXT, -1);
621                                   assembleg_1(streamstr_gc, AO1);
622                                   goto PrintTermDone;
623                               case OBJECT_MK:
624                                   if (runtime_error_checking_switch)
625                                   {   AO = veneer_routine(RT__ChPrintO_VR);
626                                       goto PrintByRoutine;
627                                   }
628                                   get_next_token();
629                                   AO1 = code_generate(
630                                       parse_expression(QUANTITY_CONTEXT),
631                                       QUANTITY_CONTEXT, -1);
632                                   INITAOT(&AO2, BYTECONSTANT_OT);
633                                   AO2.value = GOBJFIELD_NAME();
634                                   assembleg_3(aload_gc, AO1, AO2, 
635                                     stack_pointer);
636                                   assembleg_1(streamstr_gc, stack_pointer);
637                                   goto PrintTermDone;
638                               case THE_MK:
639                                   AO = veneer_routine(DefArt_VR);
640                                   goto PrintByRoutine;
641                               case AN_MK:
642                               case A_MK:
643                                   AO = veneer_routine(InDefArt_VR);
644                                   goto PrintByRoutine;
645                               case CAP_THE_MK:
646                                   AO = veneer_routine(CDefArt_VR);
647                                   goto PrintByRoutine;
648                               case CAP_A_MK:
649                                   AO = veneer_routine(CInDefArt_VR);
650                                   goto PrintByRoutine;
651                               case NAME_MK:
652                                   AO = veneer_routine(PrintShortName_VR);
653                                   goto PrintByRoutine;
654                               case NUMBER_MK:
655                                   AO = veneer_routine(EnglishNumber_VR);
656                                   goto PrintByRoutine;
657                               case PROPERTY_MK:
658                                   AO = veneer_routine(Print__Pname_VR);
659                                   goto PrintByRoutine;
660                               default:
661                error_named("A reserved word was used as a print specification:",
662                                       token_text);
663                           }
664                           break;
665
666                         case SYMBOL_TT:
667                           if (sflags[token_value] & UNKNOWN_SFLAG)
668                           {   INITAOT(&AO, CONSTANT_OT);
669                               AO.value = token_value;
670                               AO.marker = SYMBOL_MV;
671                           }
672                           else
673                           {   INITAOT(&AO, CONSTANT_OT);
674                               AO.value = svals[token_value];
675                               AO.marker = IROUTINE_MV;
676                               if (stypes[token_value] != ROUTINE_T)
677                                 ebf_error("printing routine name", token_text);
678                           }
679                           sflags[token_value] |= USED_SFLAG;
680
681                           PrintByRoutine:
682
683                           get_next_token();
684                           INITAOT(&AO2, ZEROCONSTANT_OT);
685                           assembleg_call_1(AO,
686                             code_generate(parse_expression(QUANTITY_CONTEXT),
687                               QUANTITY_CONTEXT, -1),
688                             AO2);
689                           goto PrintTermDone;
690
691                         default: ebf_error("print specification", token_text);
692                           get_next_token();
693                           assembleg_1(streamnum_gc,
694                           code_generate(parse_expression(QUANTITY_CONTEXT),
695                                 QUANTITY_CONTEXT, -1));
696                           goto PrintTermDone;
697                       }
698                   }
699                   put_token_back(); put_token_back(); put_token_back();
700                   misc_keywords.enabled = FALSE;
701                   assembleg_1(streamnum_gc,
702                       code_generate(parse_expression(QUANTITY_CONTEXT),
703                           QUANTITY_CONTEXT, -1));
704                   break;
705               }
706
707             default:
708               put_token_back(); misc_keywords.enabled = FALSE;
709               assembleg_1(streamnum_gc,
710                   code_generate(parse_expression(QUANTITY_CONTEXT),
711                       QUANTITY_CONTEXT, -1));
712               break;
713         }
714
715         PrintTermDone: misc_keywords.enabled = FALSE;
716
717         count++;
718         get_next_token();
719         if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
720         if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
721         {   ebf_error("comma", token_text);
722             panic_mode_error_recovery(); return;
723         }
724         else get_next_token();
725     } while(TRUE);
726
727     if (count == 0) ebf_error("something to print", token_text);
728     if (finally_return)
729     {
730         INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
731         assembleg_1(streamchar_gc, AO); 
732         INITAOTV(&AO, BYTECONSTANT_OT, 1);
733         assembleg_1(return_gc, AO); 
734     }
735 }
736
737 static void parse_statement_z(int break_label, int continue_label)
738 {   int ln, ln2, ln3, ln4, flag;
739     assembly_operand AO, AO2, AO3, AO4;
740     debug_location spare_debug_location1, spare_debug_location2;
741
742     ASSERT_ZCODE();
743
744     if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
745     {   /*  That is, a full stop, signifying a label  */
746
747         get_next_token();
748         if (token_type == SYMBOL_TT)
749         {
750             if (sflags[token_value] & UNKNOWN_SFLAG)
751             {   assign_symbol(token_value, next_label, LABEL_T);
752                 sflags[token_value] |= USED_SFLAG;
753                 assemble_label_no(next_label);
754                 define_symbol_label(token_value);
755                 next_label++;
756             }
757             else
758             {   if (stypes[token_value] != LABEL_T) goto LabelError;
759                 if (sflags[token_value] & CHANGE_SFLAG)
760                 {   sflags[token_value] &= (~(CHANGE_SFLAG));
761                     assemble_label_no(svals[token_value]);
762                     define_symbol_label(token_value);
763                 }
764                 else error_named("Duplicate definition of label:", token_text);
765             }
766
767             get_next_token();
768             if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
769             {   ebf_error("';'", token_text);
770                 put_token_back(); return;
771             }
772
773             /*  Interesting point of Inform grammar: a statement can only
774                 consist solely of a label when it is immediately followed
775                 by a "}".                                                    */
776
777             get_next_token();
778             if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
779             {   put_token_back(); return;
780             }
781             statement_debug_location = get_token_location();
782             parse_statement(break_label, continue_label);
783             return;
784         }
785         LabelError: ebf_error("label name", token_text);
786     }
787
788     if ((token_type == SEP_TT) && (token_value == HASH_SEP))
789     {   parse_directive(TRUE);
790         parse_statement(break_label, continue_label); return;
791     }
792
793     if ((token_type == SEP_TT) && (token_value == AT_SEP))
794     {   parse_assembly(); return;
795     }
796
797     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
798
799     if (token_type == DQ_TT)
800     {   parse_print_z(TRUE); return;
801     }
802
803     if ((token_type == SEP_TT) && (token_value == LESS_SEP))
804     {   parse_action(); goto StatementTerminator; }
805
806     if (token_type == EOF_TT)
807     {   ebf_error("statement", token_text); return; }
808
809     if (token_type != STATEMENT_TT)
810     {   put_token_back();
811         AO = parse_expression(VOID_CONTEXT);
812         code_generate(AO, VOID_CONTEXT, -1);
813         if (vivc_flag) { panic_mode_error_recovery(); return; }
814         goto StatementTerminator;
815     }
816
817     statements.enabled = FALSE;
818
819     switch(token_value)
820     {
821     /*  -------------------------------------------------------------------- */
822     /*  box <string-1> ... <string-n> -------------------------------------- */
823     /*  -------------------------------------------------------------------- */
824
825         case BOX_CODE:
826              if (version_number == 3)
827                  warning("The 'box' statement has no effect in a version 3 game");
828              INITAOT(&AO3, LONG_CONSTANT_OT);
829                  AO3.value = begin_table_array();
830                  AO3.marker = ARRAY_MV;
831                  ln = 0; ln2 = 0;
832                  do
833                  {   get_next_token();
834                      if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
835                          break;
836                      if (token_type != DQ_TT)
837                          ebf_error("text of box line in double-quotes",
838                              token_text);
839                      {   int i, j;
840                          for (i=0, j=0; token_text[i] != 0; j++)
841                              if (token_text[i] == '@')
842                              {   if (token_text[i+1] == '@')
843                                  {   i = i + 2;
844                                      while (isdigit(token_text[i])) i++;
845                                  }
846                                  else
847                                  {   i++;
848                                      if (token_text[i] != 0) i++;
849                                      if (token_text[i] != 0) i++;
850                                  }
851                              }
852                              else i++;
853                          if (j > ln2) ln2 = j;
854                      }
855                      put_token_back();
856                      array_entry(ln++, FALSE, parse_expression(CONSTANT_CONTEXT));
857                  } while (TRUE);
858                  finish_array(ln, FALSE);
859                  if (ln == 0)
860                      error("No lines of text given for 'box' display");
861
862                  if (version_number == 3) return;
863
864                  INITAOTV(&AO2, SHORT_CONSTANT_OT, ln2);
865                  INITAOTV(&AO4, VARIABLE_OT, 255);
866                  assemblez_3_to(call_vs_zc, veneer_routine(Box__Routine_VR),
867                      AO2, AO3, AO4);
868                  return;
869
870     /*  -------------------------------------------------------------------- */
871     /*  break -------------------------------------------------------------- */
872     /*  -------------------------------------------------------------------- */
873
874         case BREAK_CODE:
875                  if (break_label == -1)
876                  error("'break' can only be used in a loop or 'switch' block");
877                  else
878                      assemblez_jump(break_label);
879                  break;
880
881     /*  -------------------------------------------------------------------- */
882     /*  continue ----------------------------------------------------------- */
883     /*  -------------------------------------------------------------------- */
884
885         case CONTINUE_CODE:
886                  if (continue_label == -1)
887                  error("'continue' can only be used in a loop block");
888                  else
889                      assemblez_jump(continue_label);
890                  break;
891
892     /*  -------------------------------------------------------------------- */
893     /*  do <codeblock> until (<condition>) --------------------------------- */
894     /*  -------------------------------------------------------------------- */
895
896         case DO_CODE:
897                  assemble_label_no(ln = next_label++);
898                  ln2 = next_label++; ln3 = next_label++;
899                  parse_code_block(ln3, ln2, 0);
900                  statements.enabled = TRUE;
901                  get_next_token();
902                  if ((token_type == STATEMENT_TT)
903                      && (token_value == UNTIL_CODE))
904                  {   assemble_label_no(ln2);
905                      match_open_bracket();
906                      AO = parse_expression(CONDITION_CONTEXT);
907                      match_close_bracket();
908                      code_generate(AO, CONDITION_CONTEXT, ln);
909                  }
910                  else error("'do' without matching 'until'");
911
912                  assemble_label_no(ln3);
913                  break;
914
915     /*  -------------------------------------------------------------------- */
916     /*  font on/off -------------------------------------------------------- */
917     /*  -------------------------------------------------------------------- */
918
919         case FONT_CODE:
920                  misc_keywords.enabled = TRUE;
921                  get_next_token();
922                  misc_keywords.enabled = FALSE;
923                  if ((token_type != MISC_KEYWORD_TT)
924                      || ((token_value != ON_MK)
925                          && (token_value != OFF_MK)))
926                  {   ebf_error("'on' or 'off'", token_text);
927                      panic_mode_error_recovery();
928                      break;
929                  }
930
931                  if (version_number >= 5)
932                  {   /* Use the V5 @set_font opcode, setting font 4
933                         (for font off) or 1 (for font on). */
934                      INITAOT(&AO, SHORT_CONSTANT_OT);
935                      if (token_value == ON_MK)
936                          AO.value = 1;
937                      else
938                          AO.value = 4;
939                      assemblez_1_to(set_font_zc, AO, temp_var1);
940                      break;
941                  }
942
943                  /* Set the fixed-pitch header bit. */
944                  INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
945                  INITAOTV(&AO2, SHORT_CONSTANT_OT, 8);
946                  INITAOTV(&AO3, VARIABLE_OT, 255);
947                  assemblez_2_to(loadw_zc, AO, AO2, AO3);
948
949                  if (token_value == ON_MK)
950                  {   INITAOTV(&AO4, LONG_CONSTANT_OT, 0xfffd);
951                      assemblez_2_to(and_zc, AO4, AO3, AO3);
952                  }
953                  else
954                  {   INITAOTV(&AO4, SHORT_CONSTANT_OT, 2);
955                      assemblez_2_to(or_zc, AO4, AO3, AO3);
956                  }
957
958                  assemblez_3(storew_zc, AO, AO2, AO3);
959                  break;
960
961     /*  -------------------------------------------------------------------- */
962     /*  for (<initialisation> : <continue-condition> : <updating>) --------- */
963     /*  -------------------------------------------------------------------- */
964
965         /*  Note that it's legal for any or all of the three sections of a
966             'for' specification to be empty.  This 'for' implementation
967             often wastes 3 bytes with a redundant branch rather than keep
968             expression parse trees for long periods (as previous versions
969             of Inform did, somewhat crudely by simply storing the textual
970             form of a 'for' loop).  It is adequate for now.                  */
971
972         case FOR_CODE:
973                  match_open_bracket();
974                  get_next_token();
975
976                  /*  Initialisation code  */
977
978                  if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
979                  {   put_token_back();
980                      if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
981                      {   sequence_point_follows = TRUE;
982                          statement_debug_location = get_token_location();
983                          code_generate(parse_expression(FORINIT_CONTEXT),
984                              VOID_CONTEXT, -1);
985                      }
986                      get_next_token();
987                      if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
988                      {   get_next_token();
989                          if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
990                          {   assemble_label_no(ln = next_label++);
991                              ln2 = next_label++;
992                              parse_code_block(ln2, ln, 0);
993                              sequence_point_follows = FALSE;
994                              if (!execution_never_reaches_here)
995                                  assemblez_jump(ln);
996                              assemble_label_no(ln2);
997                              return;
998                          }
999                          AO.type = OMITTED_OT;
1000                          goto ParseUpdate;
1001                      }
1002                      put_token_back();
1003                      if (!match_colon()) break;
1004                  }
1005
1006                  get_next_token();
1007                  AO.type = OMITTED_OT;
1008                  if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1009                  {   put_token_back();
1010                      spare_debug_location1 = get_token_location();
1011                      AO = parse_expression(CONDITION_CONTEXT);
1012                      if (!match_colon()) break;
1013                  }
1014                  get_next_token();
1015
1016                  ParseUpdate:
1017                  AO2.type = OMITTED_OT; flag = 0;
1018                  if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
1019                  {   put_token_back();
1020                      spare_debug_location2 = get_token_location();
1021                      AO2 = parse_expression(VOID_CONTEXT);
1022                      match_close_bracket();
1023                      flag = test_for_incdec(AO2);
1024                  }
1025
1026                  ln = next_label++;
1027                  ln2 = next_label++;
1028                  ln3 = next_label++;
1029
1030                  if ((AO2.type == OMITTED_OT) || (flag != 0))
1031                  {
1032                      assemble_label_no(ln);
1033                      if (flag==0) assemble_label_no(ln2);
1034
1035                      /*  The "finished yet?" condition  */
1036
1037                      if (AO.type != OMITTED_OT)
1038                      {   sequence_point_follows = TRUE;
1039                          statement_debug_location = spare_debug_location1;
1040                          code_generate(AO, CONDITION_CONTEXT, ln3);
1041                      }
1042
1043                  }
1044                  else
1045                  {
1046                      /*  This is the jump which could be avoided with the aid
1047                          of long-term expression storage  */
1048
1049                      sequence_point_follows = FALSE;
1050                      assemblez_jump(ln2);
1051
1052                      /*  The "update" part  */
1053
1054                      assemble_label_no(ln);
1055                      sequence_point_follows = TRUE;
1056                      statement_debug_location = spare_debug_location2;
1057                      code_generate(AO2, VOID_CONTEXT, -1);
1058
1059                      assemble_label_no(ln2);
1060
1061                      /*  The "finished yet?" condition  */
1062
1063                      if (AO.type != OMITTED_OT)
1064                      {   sequence_point_follows = TRUE;
1065                          statement_debug_location = spare_debug_location1;
1066                          code_generate(AO, CONDITION_CONTEXT, ln3);
1067                      }
1068                  }
1069
1070                  if (flag != 0)
1071                  {
1072                      /*  In this optimised case, update code is at the end
1073                          of the loop block, so "continue" goes there  */
1074
1075                      parse_code_block(ln3, ln2, 0);
1076                      assemble_label_no(ln2);
1077
1078                      sequence_point_follows = TRUE;
1079                      statement_debug_location = spare_debug_location2;
1080                      if (flag > 0)
1081                      {   INITAOTV(&AO3, SHORT_CONSTANT_OT, flag);
1082                          if (module_switch
1083                              && (flag>=MAX_LOCAL_VARIABLES) && (flag<LOWEST_SYSTEM_VAR_NUMBER))
1084                              AO3.marker = VARIABLE_MV;
1085                          assemblez_1(inc_zc, AO3);
1086                      }
1087                      else
1088                      {   INITAOTV(&AO3, SHORT_CONSTANT_OT, -flag);
1089                          if ((module_switch) && (flag>=MAX_LOCAL_VARIABLES)
1090                              && (flag<LOWEST_SYSTEM_VAR_NUMBER))
1091                              AO3.marker = VARIABLE_MV;
1092                          assemblez_1(dec_zc, AO3);
1093                      }
1094                      assemblez_jump(ln);
1095                  }
1096                  else
1097                  {
1098                      /*  In the unoptimised case, update code is at the
1099                          start of the loop block, so "continue" goes there  */
1100
1101                      parse_code_block(ln3, ln, 0);
1102                      if (!execution_never_reaches_here)
1103                      {   sequence_point_follows = FALSE;
1104                          assemblez_jump(ln);
1105                      }
1106                  }
1107
1108                  assemble_label_no(ln3);
1109                  return;
1110
1111     /*  -------------------------------------------------------------------- */
1112     /*  give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
1113     /*  -------------------------------------------------------------------- */
1114
1115         case GIVE_CODE:
1116                  AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1117                           QUANTITY_CONTEXT, -1);
1118                  if ((AO.type == VARIABLE_OT) && (AO.value == 0))
1119                  {   INITAOTV(&AO, SHORT_CONSTANT_OT, 252);
1120                      if (version_number != 6) assemblez_1(pull_zc, AO);
1121                      else assemblez_0_to(pull_zc, AO);
1122                      AO.type = VARIABLE_OT;
1123                  }
1124
1125                  do
1126                  {   get_next_token();
1127                      if ((token_type == SEP_TT)&&(token_value == SEMICOLON_SEP))
1128                          return;
1129                      if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
1130                          ln = clear_attr_zc;
1131                      else
1132                      {   if ((token_type == SYMBOL_TT)
1133                              && (stypes[token_value] != ATTRIBUTE_T))
1134                            warning_named("This is not a declared Attribute:",
1135                              token_text);
1136                          ln = set_attr_zc;
1137                          put_token_back();
1138                      }
1139                      AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1140                                QUANTITY_CONTEXT, -1);
1141                      if (runtime_error_checking_switch)
1142                      {   ln2 = (ln==set_attr_zc)?RT__ChG_VR:RT__ChGt_VR;
1143                          if (version_number >= 5)
1144                              assemblez_3(call_vn_zc, veneer_routine(ln2),
1145                              AO, AO2);
1146                          else
1147                          {   
1148                              assemblez_3_to(call_zc, veneer_routine(ln2),
1149                                  AO, AO2, temp_var1);
1150                          }
1151                      }
1152                      else
1153                          assemblez_2(ln, AO, AO2);
1154                  } while(TRUE);
1155
1156     /*  -------------------------------------------------------------------- */
1157     /*  if (<condition>) <codeblock> [else <codeblock>] -------------------- */
1158     /*  -------------------------------------------------------------------- */
1159
1160         case IF_CODE:
1161                  flag = FALSE;
1162                  ln2 = 0;
1163
1164                  match_open_bracket();
1165                  AO = parse_expression(CONDITION_CONTEXT);
1166                  match_close_bracket();
1167
1168                  statements.enabled = TRUE;
1169                  get_next_token();
1170                  if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
1171                      ln = -4;
1172                  else
1173                  if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
1174                      ln = -3;
1175                  else
1176                  {   put_token_back();
1177                      ln = next_label++;
1178                  }
1179
1180                  code_generate(AO, CONDITION_CONTEXT, ln);
1181
1182                  if (ln >= 0) parse_code_block(break_label, continue_label, 0);
1183                  else
1184                  {   get_next_token();
1185                      if ((token_type != SEP_TT)
1186                          || (token_value != SEMICOLON_SEP))
1187                      {   ebf_error("';'", token_text);
1188                          put_token_back();
1189                      }
1190                  }
1191
1192                  statements.enabled = TRUE;
1193                  get_next_token();
1194                  if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
1195                  {   flag = TRUE;
1196                      if (ln >= 0)
1197                      {   ln2 = next_label++;
1198                          if (!execution_never_reaches_here)
1199                          {   sequence_point_follows = FALSE;
1200                              assemblez_jump(ln2);
1201                          }
1202                      }
1203                  }
1204                  else put_token_back();
1205
1206                  if (ln >= 0) assemble_label_no(ln);
1207
1208                  if (flag)
1209                  {   parse_code_block(break_label, continue_label, 0);
1210                      if (ln >= 0) assemble_label_no(ln2);
1211                  }
1212
1213                  return;
1214
1215     /*  -------------------------------------------------------------------- */
1216     /*  inversion ---------------------------------------------------------- */
1217     /*  -------------------------------------------------------------------- */
1218
1219         case INVERSION_CODE:
1220                  INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
1221                  INITAOT(&AO2, SHORT_CONSTANT_OT);
1222
1223                  AO2.value  = 60;
1224                  assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1225                  assemblez_1(print_char_zc, temp_var1);
1226                  AO2.value  = 61;
1227                  assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1228                  assemblez_1(print_char_zc, temp_var1);
1229                  AO2.value  = 62;
1230                  assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1231                  assemblez_1(print_char_zc, temp_var1);
1232                  AO2.value  = 63;
1233                  assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
1234                  assemblez_1(print_char_zc, temp_var1);
1235                  break;
1236
1237     /*  -------------------------------------------------------------------- */
1238     /*  jump <label> ------------------------------------------------------- */
1239     /*  -------------------------------------------------------------------- */
1240
1241         case JUMP_CODE:
1242                  assemblez_jump(parse_label());
1243                  break;
1244
1245     /*  -------------------------------------------------------------------- */
1246     /*  move <expression> to <expression> ---------------------------------- */
1247     /*  -------------------------------------------------------------------- */
1248
1249         case MOVE_CODE:
1250                  misc_keywords.enabled = TRUE;
1251                  AO = parse_expression(QUANTITY_CONTEXT);
1252
1253                  get_next_token();
1254                  misc_keywords.enabled = FALSE;
1255                  if ((token_type != MISC_KEYWORD_TT)
1256                      || (token_value != TO_MK))
1257                  {   ebf_error("'to'", token_text);
1258                      panic_mode_error_recovery();
1259                      return;
1260                  }
1261
1262                  AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1263                      QUANTITY_CONTEXT, -1);
1264                  AO = code_generate(AO, QUANTITY_CONTEXT, -1);
1265                  if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
1266                  {   if (version_number >= 5)
1267                          assemblez_3(call_vn_zc, veneer_routine(RT__ChT_VR),
1268                              AO, AO2);
1269                      else
1270                      {   assemblez_3_to(call_zc, veneer_routine(RT__ChT_VR),
1271                              AO, AO2, temp_var1);
1272                      }
1273                  }
1274                  else
1275                      assemblez_2(insert_obj_zc, AO, AO2);
1276                  break;
1277
1278     /*  -------------------------------------------------------------------- */
1279     /*  new_line ----------------------------------------------------------- */
1280     /*  -------------------------------------------------------------------- */
1281
1282         case NEW_LINE_CODE:  assemblez_0(new_line_zc); break;
1283
1284     /*  -------------------------------------------------------------------- */
1285     /*  objectloop (<initialisation>) <codeblock> -------------------------- */
1286     /*  -------------------------------------------------------------------- */
1287
1288         case OBJECTLOOP_CODE:
1289
1290                  match_open_bracket();
1291                  get_next_token();
1292                  INITAOT(&AO, VARIABLE_OT);
1293                  if (token_type == LOCAL_VARIABLE_TT)
1294                      AO.value = token_value;
1295                  else
1296                  if ((token_type == SYMBOL_TT) &&
1297                      (stypes[token_value] == GLOBAL_VARIABLE_T))
1298                      AO.value = svals[token_value];
1299                  else
1300                  {   ebf_error("'objectloop' variable", token_text);
1301                      panic_mode_error_recovery(); break;
1302                  }
1303                  if ((module_switch) && (AO.value >= MAX_LOCAL_VARIABLES)
1304                      && (AO.value < LOWEST_SYSTEM_VAR_NUMBER))
1305                      AO.marker = VARIABLE_MV;
1306                  misc_keywords.enabled = TRUE;
1307                  get_next_token(); flag = TRUE;
1308                  misc_keywords.enabled = FALSE;
1309                  if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
1310                      flag = FALSE;
1311
1312                  ln = 0;
1313                  if ((token_type == MISC_KEYWORD_TT)
1314                      && (token_value == NEAR_MK)) ln = 1;
1315                  if ((token_type == MISC_KEYWORD_TT)
1316                      && (token_value == FROM_MK)) ln = 2;
1317                  if ((token_type == CND_TT) && (token_value == IN_COND))
1318                  {   get_next_token();
1319                      get_next_token();
1320                      if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
1321                          ln = 3;
1322                      put_token_back();
1323                      put_token_back();
1324                  }
1325
1326                  if (ln > 0)
1327                  {   /*  Old style (Inform 5) objectloops: note that we
1328                          implement objectloop (a in b) in the old way since
1329                          this runs through objects in a different order from
1330                          the new way, and there may be existing Inform code
1331                          relying on this.                                    */
1332                      assembly_operand AO4;
1333                      INITAO(&AO4);
1334
1335                      sequence_point_follows = TRUE;
1336                      AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1337                          QUANTITY_CONTEXT, -1);
1338                      match_close_bracket();
1339                      if (ln == 1)
1340                      {   INITAOTV(&AO3, VARIABLE_OT, 0);
1341                          if (runtime_error_checking_switch)
1342                                  AO2 = check_nonzero_at_runtime(AO2, -1,
1343                                      OBJECTLOOP_RTE);
1344                          assemblez_1_to(get_parent_zc, AO2, AO3);
1345                          assemblez_objcode(get_child_zc, AO3, AO3, -2, TRUE);
1346                          AO2 = AO3;
1347                      }
1348                      if (ln == 3)
1349                      {   INITAOTV(&AO3, VARIABLE_OT, 0);
1350                          if (runtime_error_checking_switch)
1351                          {   AO4 = AO2;
1352                              AO2 = check_nonzero_at_runtime(AO2, -1,
1353                                  CHILD_RTE);
1354                          }
1355                          assemblez_objcode(get_child_zc, AO2, AO3, -2, TRUE);
1356                          AO2 = AO3;
1357                      }
1358                      assemblez_store(AO, AO2);
1359                      assemblez_1_branch(jz_zc, AO, ln2 = next_label++, TRUE);
1360                      assemble_label_no(ln4 = next_label++);
1361                      parse_code_block(ln2, ln3 = next_label++, 0);
1362                      sequence_point_follows = FALSE;
1363                      assemble_label_no(ln3);
1364                      if (runtime_error_checking_switch)
1365                      {   AO2 = check_nonzero_at_runtime(AO, ln2,
1366                               OBJECTLOOP2_RTE);
1367                          if ((ln == 3)
1368                              && ((AO4.type != VARIABLE_OT)||(AO4.value != 0))
1369                              && ((AO4.type != VARIABLE_OT)
1370                                  ||(AO4.value != AO.value)))
1371                          {   assembly_operand en_ao;
1372                              INITAOTV(&en_ao, SHORT_CONSTANT_OT, OBJECTLOOP_BROKEN_RTE);
1373                              assemblez_2_branch(jin_zc, AO, AO4,
1374                                  next_label, TRUE);
1375                              assemblez_3(call_vn_zc, veneer_routine(RT__Err_VR),
1376                                  en_ao, AO);
1377                              assemblez_jump(ln2);
1378                              assemble_label_no(next_label++);
1379                          }
1380                      }
1381                      else AO2 = AO;
1382                      assemblez_objcode(get_sibling_zc, AO2, AO, ln4, TRUE);
1383                      assemble_label_no(ln2);
1384                      return;
1385                  }
1386
1387                  sequence_point_follows = TRUE;
1388                  INITAOTV(&AO2, SHORT_CONSTANT_OT, 1);
1389                  assemblez_store(AO, AO2);
1390
1391                  assemble_label_no(ln = next_label++);
1392                  ln2 = next_label++;
1393                  ln3 = next_label++;
1394                  if (flag)
1395                  {   put_token_back();
1396                      put_token_back();
1397                      sequence_point_follows = TRUE;
1398                      code_generate(parse_expression(CONDITION_CONTEXT),
1399                          CONDITION_CONTEXT, ln3);
1400                      match_close_bracket();
1401                  }
1402                  parse_code_block(ln2, ln3, 0);
1403
1404                  sequence_point_follows = FALSE;
1405                  assemble_label_no(ln3);
1406                  assemblez_inc(AO);
1407                  INITAOTV(&AO2, LONG_CONSTANT_OT, no_objects);
1408                  AO2.marker = NO_OBJS_MV;
1409                  assemblez_2_branch(jg_zc, AO, AO2, ln2, TRUE);
1410                  assemblez_jump(ln);
1411                  assemble_label_no(ln2);
1412                  return;
1413
1414     /*  -------------------------------------------------------------------- */
1415     /*  (see routine above) ------------------------------------------------ */
1416     /*  -------------------------------------------------------------------- */
1417
1418         case PRINT_CODE:
1419             get_next_token();
1420             parse_print_z(FALSE); return;
1421         case PRINT_RET_CODE:
1422             get_next_token();
1423             parse_print_z(TRUE); return;
1424
1425     /*  -------------------------------------------------------------------- */
1426     /*  quit --------------------------------------------------------------- */
1427     /*  -------------------------------------------------------------------- */
1428
1429         case QUIT_CODE:      assemblez_0(quit_zc); break;
1430
1431     /*  -------------------------------------------------------------------- */
1432     /*  read <expression> <expression> [<Routine>] ------------------------- */
1433     /*  -------------------------------------------------------------------- */
1434
1435         case READ_CODE:
1436                  INITAOTV(&AO, VARIABLE_OT, 252);
1437                  assemblez_store(AO,
1438                      code_generate(parse_expression(QUANTITY_CONTEXT),
1439                                    QUANTITY_CONTEXT, -1));
1440                  if (version_number > 3)
1441                  {   INITAOTV(&AO3, SHORT_CONSTANT_OT, 1);
1442                      INITAOTV(&AO4, SHORT_CONSTANT_OT, 0);
1443                      assemblez_3(storeb_zc, AO, AO3, AO4);
1444                  }
1445                  AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1446                            QUANTITY_CONTEXT, -1);
1447
1448                  get_next_token();
1449                  if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1450                      put_token_back();
1451                  else
1452                  {   if (version_number == 3)
1453                          error(
1454 "In Version 3 no status-line drawing routine can be given");
1455                      else
1456                      {   assembly_operand AO5;
1457                          /* Move the temp4 (buffer) value to the stack,
1458                             since the routine might alter temp4. */
1459                          assemblez_store(stack_pointer, AO);
1460                          AO = stack_pointer;
1461                          put_token_back();
1462                          AO5 = parse_expression(CONSTANT_CONTEXT);
1463
1464                          if (version_number >= 5)
1465                              assemblez_1(call_1n_zc, AO5);
1466                          else
1467                              assemblez_1_to(call_zc, AO5, temp_var1);
1468                      }
1469                  }
1470
1471                  if (version_number > 4)
1472                  {   assemblez_2_to(aread_zc, AO, AO2, temp_var1);
1473                  }
1474                  else assemblez_2(sread_zc, AO, AO2);
1475                  break;
1476
1477     /*  -------------------------------------------------------------------- */
1478     /*  remove <expression> ------------------------------------------------ */
1479     /*  -------------------------------------------------------------------- */
1480
1481         case REMOVE_CODE:
1482                  AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1483                      QUANTITY_CONTEXT, -1);
1484                  if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
1485                  {   if (version_number >= 5)
1486                          assemblez_2(call_2n_zc, veneer_routine(RT__ChR_VR),
1487                              AO);
1488                      else
1489                      {   assemblez_2_to(call_zc, veneer_routine(RT__ChR_VR),
1490                              AO, temp_var1);
1491                      }
1492                  }
1493                  else
1494                      assemblez_1(remove_obj_zc, AO);
1495                  break;
1496
1497     /*  -------------------------------------------------------------------- */
1498     /*  restore <label> ---------------------------------------------------- */
1499     /*  -------------------------------------------------------------------- */
1500
1501         case RESTORE_CODE:
1502                  if (version_number < 5)
1503                      assemblez_0_branch(restore_zc, parse_label(), TRUE);
1504                  else
1505                  {   INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
1506                      assemblez_0_to(restore_zc, temp_var1);
1507                      assemblez_2_branch(je_zc, temp_var1, AO2, parse_label(), TRUE);
1508                  }
1509                  break;
1510
1511     /*  -------------------------------------------------------------------- */
1512     /*  return [<expression>] ---------------------------------------------- */
1513     /*  -------------------------------------------------------------------- */
1514
1515         case RETURN_CODE:
1516                  get_next_token();
1517                  if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
1518                  {   assemblez_0(rtrue_zc); return; }
1519                  put_token_back();
1520                  AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
1521                      QUANTITY_CONTEXT, -1);
1522                  if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 0)
1523                      && (AO.marker == 0))
1524                  {   assemblez_0(rfalse_zc); break; }
1525                  if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 1)
1526                      && (AO.marker == 0))
1527                  {   assemblez_0(rtrue_zc); break; }
1528                  if ((AO.type == VARIABLE_OT) && (AO.value == 0))
1529                  {   assemblez_0(ret_popped_zc); break; }
1530                  assemblez_1(ret_zc, AO);
1531                  break;
1532
1533     /*  -------------------------------------------------------------------- */
1534     /*  rfalse ------------------------------------------------------------- */
1535     /*  -------------------------------------------------------------------- */
1536
1537         case RFALSE_CODE:  assemblez_0(rfalse_zc); break;
1538
1539     /*  -------------------------------------------------------------------- */
1540     /*  rtrue -------------------------------------------------------------- */
1541     /*  -------------------------------------------------------------------- */
1542
1543         case RTRUE_CODE:   assemblez_0(rtrue_zc); break;
1544
1545     /*  -------------------------------------------------------------------- */
1546     /*  save <label> ------------------------------------------------------- */
1547     /*  -------------------------------------------------------------------- */
1548
1549         case SAVE_CODE:
1550                  if (version_number < 5)
1551                      assemblez_0_branch(save_zc, parse_label(), TRUE);
1552                  else
1553                  {   INITAOTV(&AO, VARIABLE_OT, 255);
1554                      assemblez_0_to(save_zc, AO);
1555                      assemblez_1_branch(jz_zc, AO, parse_label(), FALSE);
1556                  }
1557                  break;
1558
1559     /*  -------------------------------------------------------------------- */
1560     /*  spaces <expression> ------------------------------------------------ */
1561     /*  -------------------------------------------------------------------- */
1562
1563         case SPACES_CODE:
1564                  AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1565                      QUANTITY_CONTEXT, -1);
1566                  INITAOTV(&AO2, VARIABLE_OT, 255);
1567
1568                  assemblez_store(AO2, AO);
1569
1570                  INITAOTV(&AO, SHORT_CONSTANT_OT, 32);
1571                  INITAOTV(&AO3, SHORT_CONSTANT_OT, 1);
1572
1573                  assemblez_2_branch(jl_zc, AO2, AO3, ln = next_label++, TRUE);
1574                  assemble_label_no(ln2 = next_label++);
1575                  assemblez_1(print_char_zc, AO);
1576                  assemblez_dec(AO2);
1577                  assemblez_1_branch(jz_zc, AO2, ln2, FALSE);
1578                  assemble_label_no(ln);
1579                  break;
1580
1581     /*  -------------------------------------------------------------------- */
1582     /*  string <expression> <literal-string> ------------------------------- */
1583     /*  -------------------------------------------------------------------- */
1584
1585         case STRING_CODE:
1586                  INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
1587                  INITAOTV(&AO2, SHORT_CONSTANT_OT, 12);
1588                  INITAOTV(&AO3, VARIABLE_OT, 252);
1589                  assemblez_2_to(loadw_zc, AO, AO2, AO3);
1590                  AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
1591                      QUANTITY_CONTEXT, -1);
1592                  get_next_token();
1593                  if (token_type == DQ_TT)
1594                  {   INITAOT(&AO4, LONG_CONSTANT_OT);
1595                      AO4.value = compile_string(token_text, TRUE, TRUE);
1596                  }
1597                  else
1598                  {   put_token_back();
1599                      AO4 = parse_expression(CONSTANT_CONTEXT);
1600                  }
1601                  assemblez_3(storew_zc, AO3, AO2, AO4);
1602                  break;
1603
1604     /*  -------------------------------------------------------------------- */
1605     /*  style roman/reverse/bold/underline/fixed --------------------------- */
1606     /*  -------------------------------------------------------------------- */
1607
1608         case STYLE_CODE:
1609                  if (version_number==3)
1610                  {   error(
1611 "The 'style' statement cannot be used for Version 3 games");
1612                      panic_mode_error_recovery();
1613                      break;
1614                  }
1615
1616                  misc_keywords.enabled = TRUE;
1617                  get_next_token();
1618                  misc_keywords.enabled = FALSE;
1619                  if ((token_type != MISC_KEYWORD_TT)
1620                      || ((token_value != ROMAN_MK)
1621                          && (token_value != REVERSE_MK)
1622                          && (token_value != BOLD_MK)
1623                          && (token_value != UNDERLINE_MK)
1624                          && (token_value != FIXED_MK)))
1625                  {   ebf_error(
1626 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
1627                          token_text);
1628                      panic_mode_error_recovery();
1629                      break;
1630                  }
1631
1632                  INITAOT(&AO, SHORT_CONSTANT_OT);
1633                  switch(token_value)
1634                  {   case ROMAN_MK: AO.value = 0; break;
1635                      case REVERSE_MK: AO.value = 1; break;
1636                      case BOLD_MK: AO.value = 2; break;
1637                      case UNDERLINE_MK: AO.value = 4; break;
1638                      case FIXED_MK: AO.value = 8; break;
1639                  }
1640                  assemblez_1(set_text_style_zc, AO); break;
1641
1642     /*  -------------------------------------------------------------------- */
1643     /*  switch (<expression>) <codeblock> ---------------------------------- */
1644     /*  -------------------------------------------------------------------- */
1645
1646         case SWITCH_CODE:
1647                  match_open_bracket();
1648                  AO = code_generate(parse_expression(QUANTITY_CONTEXT),
1649                      QUANTITY_CONTEXT, -1);
1650                  match_close_bracket();
1651
1652                  INITAOTV(&AO2, VARIABLE_OT, 255);
1653                  assemblez_store(AO2, AO);
1654
1655                  parse_code_block(ln = next_label++, continue_label, 1);
1656                  assemble_label_no(ln);
1657                  return;
1658
1659     /*  -------------------------------------------------------------------- */
1660     /*  while (<condition>) <codeblock> ------------------------------------ */
1661     /*  -------------------------------------------------------------------- */
1662
1663         case WHILE_CODE:
1664                  assemble_label_no(ln = next_label++);
1665                  match_open_bracket();
1666
1667                  code_generate(parse_expression(CONDITION_CONTEXT),
1668                      CONDITION_CONTEXT, ln2 = next_label++);
1669                  match_close_bracket();
1670
1671                  parse_code_block(ln2, ln, 0);
1672                  sequence_point_follows = FALSE;
1673                  assemblez_jump(ln);
1674                  assemble_label_no(ln2);
1675                  return;
1676
1677     /*  -------------------------------------------------------------------- */
1678
1679         case SDEFAULT_CODE:
1680                  error("'default' without matching 'switch'"); break;
1681         case ELSE_CODE:
1682                  error("'else' without matching 'if'"); break;
1683         case UNTIL_CODE:
1684                  error("'until' without matching 'do'");
1685                  panic_mode_error_recovery(); return;
1686     }
1687
1688     StatementTerminator:
1689
1690     get_next_token();
1691     if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1692     {   ebf_error("';'", token_text);
1693         put_token_back();
1694     }
1695 }
1696
1697 static void parse_statement_g(int break_label, int continue_label)
1698 {   int ln, ln2, ln3, ln4, flag, onstack;
1699     assembly_operand AO, AO2, AO3, AO4;
1700     debug_location spare_debug_location1, spare_debug_location2;
1701
1702     ASSERT_GLULX();
1703
1704     if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
1705     {   /*  That is, a full stop, signifying a label  */
1706
1707         get_next_token();
1708         if (token_type == SYMBOL_TT)
1709         {
1710             if (sflags[token_value] & UNKNOWN_SFLAG)
1711             {   assign_symbol(token_value, next_label, LABEL_T);
1712                 sflags[token_value] |= USED_SFLAG;
1713                 assemble_label_no(next_label);
1714                 define_symbol_label(token_value);
1715                 next_label++;
1716             }
1717             else
1718             {   if (stypes[token_value] != LABEL_T) goto LabelError;
1719                 if (sflags[token_value] & CHANGE_SFLAG)
1720                 {   sflags[token_value] &= (~(CHANGE_SFLAG));
1721                     assemble_label_no(svals[token_value]);
1722                     define_symbol_label(token_value);
1723                 }
1724                 else error_named("Duplicate definition of label:", token_text);
1725             }
1726
1727             get_next_token();
1728             if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
1729             {   ebf_error("';'", token_text);
1730                 put_token_back(); return;
1731             }
1732
1733             /*  Interesting point of Inform grammar: a statement can only
1734                 consist solely of a label when it is immediately followed
1735                 by a "}".                                                    */
1736
1737             get_next_token();
1738             if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
1739             {   put_token_back(); return;
1740             }
1741             /* The following line prevents labels from influencing the positions
1742                of sequence points. */
1743             statement_debug_location = get_token_location();
1744             parse_statement(break_label, continue_label);
1745             return;
1746         }
1747         LabelError: ebf_error("label name", token_text);
1748     }
1749
1750     if ((token_type == SEP_TT) && (token_value == HASH_SEP))
1751     {   parse_directive(TRUE);
1752         parse_statement(break_label, continue_label); return;
1753     }
1754
1755     if ((token_type == SEP_TT) && (token_value == AT_SEP))
1756     {   parse_assembly(); return;
1757     }
1758
1759     if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
1760
1761     if (token_type == DQ_TT)
1762     {   parse_print_g(TRUE); return;
1763     }
1764
1765     if ((token_type == SEP_TT) && (token_value == LESS_SEP))
1766     {   parse_action(); goto StatementTerminator; }
1767
1768     if (token_type == EOF_TT)
1769     {   ebf_error("statement", token_text); return; }
1770
1771     if (token_type != STATEMENT_TT)
1772     {   put_token_back();
1773         AO = parse_expression(VOID_CONTEXT);
1774         code_generate(AO, VOID_CONTEXT, -1);
1775         if (vivc_flag) { panic_mode_error_recovery(); return; }
1776         goto StatementTerminator;
1777     }
1778
1779     statements.enabled = FALSE;
1780
1781     switch(token_value)
1782     {
1783
1784     /*  -------------------------------------------------------------------- */
1785     /*  box <string-1> ... <string-n> -------------------------------------- */
1786     /*  -------------------------------------------------------------------- */
1787
1788         case BOX_CODE:
1789             INITAOT(&AO3, CONSTANT_OT);
1790                  AO3.value = begin_table_array();
1791                  AO3.marker = ARRAY_MV;
1792                  ln = 0; ln2 = 0;
1793                  do
1794                  {   get_next_token();
1795                      if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
1796                          break;
1797                      if (token_type != DQ_TT)
1798                          ebf_error("text of box line in double-quotes",
1799                              token_text);
1800                      {   int i, j;
1801                          for (i=0, j=0; token_text[i] != 0; j++)
1802                              if (token_text[i] == '@')
1803                              {   if (token_text[i+1] == '@')
1804                                  {   i = i + 2;
1805                                      while (isdigit(token_text[i])) i++;
1806                                  }
1807                                  else
1808                                  {   i++;
1809                                      if (token_text[i] != 0) i++;
1810                                      if (token_text[i] != 0) i++;
1811                                  }
1812                              }
1813                              else i++;
1814                          if (j > ln2) ln2 = j;
1815                      }
1816                      put_token_back();
1817                      array_entry(ln++, FALSE, parse_expression(CONSTANT_CONTEXT));
1818                  } while (TRUE);
1819                  finish_array(ln, FALSE);
1820                  if (ln == 0)
1821                      error("No lines of text given for 'box' display");
1822
1823                  INITAO(&AO2);
1824                  AO2.value = ln2; set_constant_ot(&AO2);
1825                  assembleg_call_2(veneer_routine(Box__Routine_VR),
1826                      AO2, AO3, zero_operand);
1827                  return;
1828
1829     /*  -------------------------------------------------------------------- */
1830     /*  break -------------------------------------------------------------- */
1831     /*  -------------------------------------------------------------------- */
1832
1833         case BREAK_CODE:
1834                  if (break_label == -1)
1835                  error("'break' can only be used in a loop or 'switch' block");
1836                  else
1837                      assembleg_jump(break_label);
1838                  break;
1839
1840     /*  -------------------------------------------------------------------- */
1841     /*  continue ----------------------------------------------------------- */
1842     /*  -------------------------------------------------------------------- */
1843
1844         case CONTINUE_CODE:
1845                  if (continue_label == -1)
1846                  error("'continue' can only be used in a loop block");
1847                  else
1848                      assembleg_jump(continue_label);
1849                  break;
1850
1851     /*  -------------------------------------------------------------------- */
1852     /*  do <codeblock> until (<condition>) --------------------------------- */
1853     /*  -------------------------------------------------------------------- */
1854
1855         case DO_CODE:
1856                  assemble_label_no(ln = next_label++);
1857                  ln2 = next_label++; ln3 = next_label++;
1858                  parse_code_block(ln3, ln2, 0);
1859                  statements.enabled = TRUE;
1860                  get_next_token();
1861                  if ((token_type == STATEMENT_TT)
1862                      && (token_value == UNTIL_CODE))
1863                  {   assemble_label_no(ln2);
1864                      match_open_bracket();
1865                      AO = parse_expression(CONDITION_CONTEXT);
1866                      match_close_bracket();
1867                      code_generate(AO, CONDITION_CONTEXT, ln);
1868                  }
1869                  else error("'do' without matching 'until'");
1870
1871                  assemble_label_no(ln3);
1872                  break;
1873
1874     /*  -------------------------------------------------------------------- */
1875     /*  font on/off -------------------------------------------------------- */
1876     /*  -------------------------------------------------------------------- */
1877
1878         case FONT_CODE:
1879                  misc_keywords.enabled = TRUE;
1880                  get_next_token();
1881                  misc_keywords.enabled = FALSE;
1882                  if ((token_type != MISC_KEYWORD_TT)
1883                      || ((token_value != ON_MK)
1884                          && (token_value != OFF_MK)))
1885                  {   ebf_error("'on' or 'off'", token_text);
1886                      panic_mode_error_recovery();
1887                      break;
1888                  }
1889
1890                  /* Call glk_set_style(normal or preformatted) */
1891                  INITAO(&AO);
1892                  AO.value = 0x0086;
1893                  set_constant_ot(&AO);
1894                  if (token_value == ON_MK)
1895                    AO2 = zero_operand;
1896                  else 
1897                    AO2 = two_operand;
1898                  assembleg_call_2(veneer_routine(Glk__Wrap_VR), 
1899                    AO, AO2, zero_operand);
1900                  break;
1901
1902     /*  -------------------------------------------------------------------- */
1903     /*  for (<initialisation> : <continue-condition> : <updating>) --------- */
1904     /*  -------------------------------------------------------------------- */
1905
1906         /*  Note that it's legal for any or all of the three sections of a
1907             'for' specification to be empty.  This 'for' implementation
1908             often wastes 3 bytes with a redundant branch rather than keep
1909             expression parse trees for long periods (as previous versions
1910             of Inform did, somewhat crudely by simply storing the textual
1911             form of a 'for' loop).  It is adequate for now.                  */
1912
1913         case FOR_CODE:
1914                  match_open_bracket();
1915                  get_next_token();
1916
1917                  /*  Initialisation code  */
1918
1919                  if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1920                  {   put_token_back();
1921                      if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
1922                      {   sequence_point_follows = TRUE;
1923                          statement_debug_location = get_token_location();
1924                          code_generate(parse_expression(FORINIT_CONTEXT),
1925                              VOID_CONTEXT, -1);
1926                      }
1927                      get_next_token();
1928                      if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
1929                      {   get_next_token();
1930                          if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
1931                          {   assemble_label_no(ln = next_label++);
1932                              ln2 = next_label++;
1933                              parse_code_block(ln2, ln, 0);
1934                              sequence_point_follows = FALSE;
1935                              if (!execution_never_reaches_here)
1936                                  assembleg_jump(ln);
1937                              assemble_label_no(ln2);
1938                              return;
1939                          }
1940                          AO.type = OMITTED_OT;
1941                          goto ParseUpdate;
1942                      }
1943                      put_token_back();
1944                      if (!match_colon()) break;
1945                  }
1946
1947                  get_next_token();
1948                  AO.type = OMITTED_OT;
1949                  if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
1950                  {   put_token_back();
1951                      spare_debug_location1 = get_token_location();
1952                      AO = parse_expression(CONDITION_CONTEXT);
1953                      if (!match_colon()) break;
1954                  }
1955                  get_next_token();
1956
1957                  ParseUpdate:
1958                  AO2.type = OMITTED_OT; flag = 0;
1959                  if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
1960                  {   put_token_back();
1961                      spare_debug_location2 = get_token_location();
1962                      AO2 = parse_expression(VOID_CONTEXT);
1963                      match_close_bracket();
1964                      flag = test_for_incdec(AO2);
1965                  }
1966
1967                  ln = next_label++;
1968                  ln2 = next_label++;
1969                  ln3 = next_label++;
1970
1971                  if ((AO2.type == OMITTED_OT) || (flag != 0))
1972                  {
1973                      assemble_label_no(ln);
1974                      if (flag==0) assemble_label_no(ln2);
1975
1976                      /*  The "finished yet?" condition  */
1977
1978                      if (AO.type != OMITTED_OT)
1979                      {   sequence_point_follows = TRUE;
1980                          statement_debug_location = spare_debug_location1;
1981                          code_generate(AO, CONDITION_CONTEXT, ln3);
1982                      }
1983
1984                  }
1985                  else
1986                  {
1987                      /*  This is the jump which could be avoided with the aid
1988                          of long-term expression storage  */
1989
1990                      sequence_point_follows = FALSE;
1991                      assembleg_jump(ln2);
1992
1993                      /*  The "update" part  */
1994
1995                      assemble_label_no(ln);
1996                      sequence_point_follows = TRUE;
1997                      statement_debug_location = spare_debug_location2;
1998                      code_generate(AO2, VOID_CONTEXT, -1);
1999
2000                      assemble_label_no(ln2);
2001
2002                      /*  The "finished yet?" condition  */
2003
2004                      if (AO.type != OMITTED_OT)
2005                      {   sequence_point_follows = TRUE;
2006                          statement_debug_location = spare_debug_location1;
2007                          code_generate(AO, CONDITION_CONTEXT, ln3);
2008                      }
2009                  }
2010
2011                  if (flag != 0)
2012                  {
2013                      /*  In this optimised case, update code is at the end
2014                          of the loop block, so "continue" goes there  */
2015
2016                      parse_code_block(ln3, ln2, 0);
2017                      assemble_label_no(ln2);
2018
2019                      sequence_point_follows = TRUE;
2020                      statement_debug_location = spare_debug_location2;
2021                      if (flag > 0)
2022                      {   INITAO(&AO3);
2023                          AO3.value = flag;
2024                          if (AO3.value >= MAX_LOCAL_VARIABLES)
2025                            AO3.type = GLOBALVAR_OT;
2026                          else
2027                            AO3.type = LOCALVAR_OT;
2028                          assembleg_3(add_gc, AO3, one_operand, AO3);
2029                      }
2030                      else
2031                      {   INITAO(&AO3);
2032                          AO3.value = -flag;
2033                          if (AO3.value >= MAX_LOCAL_VARIABLES)
2034                            AO3.type = GLOBALVAR_OT;
2035                          else
2036                            AO3.type = LOCALVAR_OT;
2037                          assembleg_3(sub_gc, AO3, one_operand, AO3);
2038                      }
2039                      assembleg_jump(ln);
2040                  }
2041                  else
2042                  {
2043                      /*  In the unoptimised case, update code is at the
2044                          start of the loop block, so "continue" goes there  */
2045
2046                      parse_code_block(ln3, ln, 0);
2047                      if (!execution_never_reaches_here)
2048                      {   sequence_point_follows = FALSE;
2049                          assembleg_jump(ln);
2050                      }
2051                  }
2052
2053                  assemble_label_no(ln3);
2054                  return;
2055
2056     /*  -------------------------------------------------------------------- */
2057     /*  give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
2058     /*  -------------------------------------------------------------------- */
2059
2060         case GIVE_CODE:
2061                  AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2062                           QUANTITY_CONTEXT, -1);
2063                  if ((AO.type == LOCALVAR_OT) && (AO.value == 0))
2064                      onstack = TRUE;
2065                  else
2066                      onstack = FALSE;
2067
2068                  do
2069                  {   get_next_token();
2070                      if ((token_type == SEP_TT) 
2071                        && (token_value == SEMICOLON_SEP)) {
2072                          if (onstack) {
2073                            assembleg_2(copy_gc, stack_pointer, zero_operand);
2074                          }
2075                          return;
2076                      }
2077                      if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
2078                          ln = 0;
2079                      else
2080                      {   if ((token_type == SYMBOL_TT)
2081                              && (stypes[token_value] != ATTRIBUTE_T))
2082                            warning_named("This is not a declared Attribute:",
2083                              token_text);
2084                          ln = 1;
2085                          put_token_back();
2086                      }
2087                      AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2088                                QUANTITY_CONTEXT, -1);
2089                      if (runtime_error_checking_switch && (!veneer_mode))
2090                      {   ln2 = (ln ? RT__ChG_VR : RT__ChGt_VR);
2091                          if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
2092                            /* already on stack */
2093                          }
2094                          else {
2095                            assembleg_store(stack_pointer, AO2);
2096                          }
2097                          if (onstack)
2098                            assembleg_2(stkpeek_gc, one_operand, stack_pointer);
2099                          else
2100                            assembleg_store(stack_pointer, AO);
2101                          assembleg_3(call_gc, veneer_routine(ln2), two_operand,
2102                            zero_operand);
2103                      }
2104                      else {
2105                          if (is_constant_ot(AO2.type) && AO2.marker == 0) {
2106                            AO2.value += 8;
2107                            set_constant_ot(&AO2);
2108                          }
2109                          else {
2110                            INITAOTV(&AO3, BYTECONSTANT_OT, 8);
2111                            assembleg_3(add_gc, AO2, AO3, stack_pointer);
2112                            AO2 = stack_pointer;
2113                          }
2114                          if (onstack) {
2115                            if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
2116                              assembleg_2(stkpeek_gc, one_operand, 
2117                                stack_pointer);
2118                            else
2119                              assembleg_2(stkpeek_gc, zero_operand, 
2120                                stack_pointer);
2121                          }
2122                          if (ln) 
2123                            AO3 = one_operand;
2124                          else
2125                            AO3 = zero_operand;
2126                          assembleg_3(astorebit_gc, AO, AO2, AO3);
2127                      }
2128                  } while(TRUE);
2129
2130     /*  -------------------------------------------------------------------- */
2131     /*  if (<condition>) <codeblock> [else <codeblock>] -------------------- */
2132     /*  -------------------------------------------------------------------- */
2133
2134         case IF_CODE:
2135                  flag = FALSE;
2136                  ln2 = 0;
2137
2138                  match_open_bracket();
2139                  AO = parse_expression(CONDITION_CONTEXT);
2140                  match_close_bracket();
2141
2142                  statements.enabled = TRUE;
2143                  get_next_token();
2144                  if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
2145                      ln = -4;
2146                  else
2147                  if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
2148                      ln = -3;
2149                  else
2150                  {   put_token_back();
2151                      ln = next_label++;
2152                  }
2153
2154                  code_generate(AO, CONDITION_CONTEXT, ln);
2155
2156                  if (ln >= 0) parse_code_block(break_label, continue_label, 0);
2157                  else
2158                  {   get_next_token();
2159                      if ((token_type != SEP_TT)
2160                          || (token_value != SEMICOLON_SEP))
2161                      {   ebf_error("';'", token_text);
2162                          put_token_back();
2163                      }
2164                  }
2165
2166                  statements.enabled = TRUE;
2167                  get_next_token();
2168                  if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
2169                  {   flag = TRUE;
2170                      if (ln >= 0)
2171                      {   ln2 = next_label++;
2172                          if (!execution_never_reaches_here)
2173                          {   sequence_point_follows = FALSE;
2174                              assembleg_jump(ln2);
2175                          }
2176                      }
2177                  }
2178                  else put_token_back();
2179
2180                  if (ln >= 0) assemble_label_no(ln);
2181
2182                  if (flag)
2183                  {   parse_code_block(break_label, continue_label, 0);
2184                      if (ln >= 0) assemble_label_no(ln2);
2185                  }
2186
2187                  return;
2188
2189     /*  -------------------------------------------------------------------- */
2190     /*  inversion ---------------------------------------------------------- */
2191     /*  -------------------------------------------------------------------- */
2192
2193         case INVERSION_CODE:
2194                  INITAOTV(&AO2, DEREFERENCE_OT, GLULX_HEADER_SIZE+8);
2195                  assembleg_2(copyb_gc, AO2, stack_pointer);
2196                  assembleg_1(streamchar_gc, stack_pointer);
2197                  AO2.value  = GLULX_HEADER_SIZE+9; 
2198                  assembleg_2(copyb_gc, AO2, stack_pointer);
2199                  assembleg_1(streamchar_gc, stack_pointer);
2200                  AO2.value  = GLULX_HEADER_SIZE+10; 
2201                  assembleg_2(copyb_gc, AO2, stack_pointer);
2202                  assembleg_1(streamchar_gc, stack_pointer);
2203                  AO2.value  = GLULX_HEADER_SIZE+11; 
2204                  assembleg_2(copyb_gc, AO2, stack_pointer);
2205                  assembleg_1(streamchar_gc, stack_pointer);
2206
2207                  if (/* DISABLES CODE */ (0)) {
2208                      INITAO(&AO);
2209                      AO.value = '(';
2210                      set_constant_ot(&AO);
2211                      assembleg_1(streamchar_gc, AO);
2212                      AO.value = 'G';
2213                      set_constant_ot(&AO);
2214                      assembleg_1(streamchar_gc, AO);
2215
2216                      AO2.value  = GLULX_HEADER_SIZE+12; 
2217                      assembleg_2(copyb_gc, AO2, stack_pointer);
2218                      assembleg_1(streamchar_gc, stack_pointer);
2219                      AO2.value  = GLULX_HEADER_SIZE+13; 
2220                      assembleg_2(copyb_gc, AO2, stack_pointer);
2221                      assembleg_1(streamchar_gc, stack_pointer);
2222                      AO2.value  = GLULX_HEADER_SIZE+14; 
2223                      assembleg_2(copyb_gc, AO2, stack_pointer);
2224                      assembleg_1(streamchar_gc, stack_pointer);
2225                      AO2.value  = GLULX_HEADER_SIZE+15; 
2226                      assembleg_2(copyb_gc, AO2, stack_pointer);
2227                      assembleg_1(streamchar_gc, stack_pointer);
2228
2229                      AO.marker = 0;
2230                      AO.value = ')';
2231                      set_constant_ot(&AO);
2232                      assembleg_1(streamchar_gc, AO);
2233                  }
2234
2235                  break;
2236
2237     /*  -------------------------------------------------------------------- */
2238     /*  jump <label> ------------------------------------------------------- */
2239     /*  -------------------------------------------------------------------- */
2240
2241         case JUMP_CODE:
2242                  assembleg_jump(parse_label());
2243                  break;
2244
2245     /*  -------------------------------------------------------------------- */
2246     /*  move <expression> to <expression> ---------------------------------- */
2247     /*  -------------------------------------------------------------------- */
2248
2249         case MOVE_CODE:
2250                  misc_keywords.enabled = TRUE;
2251                  AO = parse_expression(QUANTITY_CONTEXT);
2252
2253                  get_next_token();
2254                  misc_keywords.enabled = FALSE;
2255                  if ((token_type != MISC_KEYWORD_TT)
2256                      || (token_value != TO_MK))
2257                  {   ebf_error("'to'", token_text);
2258                      panic_mode_error_recovery();
2259                      return;
2260                  }
2261
2262                  AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2263                      QUANTITY_CONTEXT, -1);
2264                  AO = code_generate(AO, QUANTITY_CONTEXT, -1);
2265                  if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
2266                      assembleg_call_2(veneer_routine(RT__ChT_VR), AO, AO2,
2267                          zero_operand);
2268                  else
2269                      assembleg_call_2(veneer_routine(OB__Move_VR), AO, AO2,
2270                          zero_operand);
2271                  break;
2272
2273     /*  -------------------------------------------------------------------- */
2274     /*  new_line ----------------------------------------------------------- */
2275     /*  -------------------------------------------------------------------- */
2276
2277         case NEW_LINE_CODE:  
2278               INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
2279               assembleg_1(streamchar_gc, AO); 
2280               break;
2281
2282     /*  -------------------------------------------------------------------- */
2283     /*  objectloop (<initialisation>) <codeblock> -------------------------- */
2284     /*  -------------------------------------------------------------------- */
2285
2286         case OBJECTLOOP_CODE:
2287
2288                  match_open_bracket();
2289                  get_next_token();
2290                  if (token_type == LOCAL_VARIABLE_TT) {
2291                      INITAOTV(&AO, LOCALVAR_OT, token_value);
2292                  }
2293                  else if ((token_type == SYMBOL_TT) &&
2294                    (stypes[token_value] == GLOBAL_VARIABLE_T)) {
2295                      INITAOTV(&AO, GLOBALVAR_OT, svals[token_value]);
2296                  }
2297                  else {
2298                      ebf_error("'objectloop' variable", token_text);
2299                      panic_mode_error_recovery(); 
2300                      break;
2301                  }
2302                  misc_keywords.enabled = TRUE;
2303                  get_next_token(); flag = TRUE;
2304                  misc_keywords.enabled = FALSE;
2305                  if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
2306                      flag = FALSE;
2307
2308                  ln = 0;
2309                  if ((token_type == MISC_KEYWORD_TT)
2310                      && (token_value == NEAR_MK)) ln = 1;
2311                  if ((token_type == MISC_KEYWORD_TT)
2312                      && (token_value == FROM_MK)) ln = 2;
2313                  if ((token_type == CND_TT) && (token_value == IN_COND))
2314                  {   get_next_token();
2315                      get_next_token();
2316                      if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
2317                          ln = 3;
2318                      put_token_back();
2319                      put_token_back();
2320                  }
2321
2322                  if (ln != 0) {
2323                    /*  Old style (Inform 5) objectloops: note that we
2324                        implement objectloop (a in b) in the old way since
2325                        this runs through objects in a different order from
2326                        the new way, and there may be existing Inform code
2327                        relying on this.                                    */
2328                      assembly_operand AO4, AO5;
2329                      INITAO(&AO5);
2330
2331                      sequence_point_follows = TRUE;
2332                      AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2333                          QUANTITY_CONTEXT, -1);
2334                      match_close_bracket();
2335                      if (ln == 1) {
2336                          if (runtime_error_checking_switch)
2337                              AO2 = check_nonzero_at_runtime(AO2, -1,
2338                                  OBJECTLOOP_RTE);
2339                          INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2340                          assembleg_3(aload_gc, AO2, AO4, stack_pointer);
2341                          INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2342                          assembleg_3(aload_gc, stack_pointer, AO4, stack_pointer);
2343                          AO2 = stack_pointer;
2344                      }
2345                      else if (ln == 3) {
2346                          if (runtime_error_checking_switch) {
2347                              AO5 = AO2;
2348                              AO2 = check_nonzero_at_runtime(AO2, -1,
2349                                  CHILD_RTE);
2350                          }
2351                          INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHILD());
2352                          assembleg_3(aload_gc, AO2, AO4, stack_pointer);
2353                          AO2 = stack_pointer;
2354                      }
2355                      else {
2356                          /* do nothing */
2357                      }
2358                      assembleg_store(AO, AO2);
2359                      assembleg_1_branch(jz_gc, AO, ln2 = next_label++);
2360                      assemble_label_no(ln4 = next_label++);
2361                      parse_code_block(ln2, ln3 = next_label++, 0);
2362                      sequence_point_follows = FALSE;
2363                      assemble_label_no(ln3);
2364                      if (runtime_error_checking_switch) {
2365                          AO2 = check_nonzero_at_runtime(AO, ln2,
2366                               OBJECTLOOP2_RTE);
2367                          if ((ln == 3)
2368                              && ((AO5.type != LOCALVAR_OT)||(AO5.value != 0))
2369                              && ((AO5.type != LOCALVAR_OT)||(AO5.value != AO.value)))
2370                          {   assembly_operand en_ao;
2371                              INITAO(&en_ao);
2372                              en_ao.value = OBJECTLOOP_BROKEN_RTE;
2373                              set_constant_ot(&en_ao);
2374                              INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_PARENT());
2375                              assembleg_3(aload_gc, AO, AO4, stack_pointer);
2376                              assembleg_2_branch(jeq_gc, stack_pointer, AO5, 
2377                                  next_label);
2378                              assembleg_call_2(veneer_routine(RT__Err_VR),
2379                                  en_ao, AO, zero_operand);
2380                              assembleg_jump(ln2);
2381                              assemble_label_no(next_label++);
2382                          }
2383                      }
2384                      else {
2385                          AO2 = AO;
2386                      }
2387                      INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_SIBLING());
2388                      assembleg_3(aload_gc, AO2, AO4, AO);
2389                      assembleg_1_branch(jnz_gc, AO, ln4);
2390                      assemble_label_no(ln2);
2391                      return;
2392                  }
2393
2394                  sequence_point_follows = TRUE;
2395                  ln = symbol_index("Class", -1);
2396                  INITAOT(&AO2, CONSTANT_OT);
2397                  AO2.value = svals[ln];
2398                  AO2.marker = OBJECT_MV;
2399                  assembleg_store(AO, AO2);
2400
2401                  assemble_label_no(ln = next_label++);
2402                  ln2 = next_label++;
2403                  ln3 = next_label++;
2404                  if (flag)
2405                  {   put_token_back();
2406                      put_token_back();
2407                      sequence_point_follows = TRUE;
2408                      code_generate(parse_expression(CONDITION_CONTEXT),
2409                          CONDITION_CONTEXT, ln3);
2410                      match_close_bracket();
2411                  }
2412                  parse_code_block(ln2, ln3, 0);
2413
2414                  sequence_point_follows = FALSE;
2415                  assemble_label_no(ln3);
2416                  INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHAIN());
2417                  assembleg_3(aload_gc, AO, AO4, AO);
2418                  assembleg_1_branch(jnz_gc, AO, ln);
2419                  assemble_label_no(ln2);
2420                  return;
2421
2422     /*  -------------------------------------------------------------------- */
2423     /*  (see routine above) ------------------------------------------------ */
2424     /*  -------------------------------------------------------------------- */
2425
2426         case PRINT_CODE:
2427             get_next_token();
2428             parse_print_g(FALSE); return;
2429         case PRINT_RET_CODE:
2430             get_next_token();
2431             parse_print_g(TRUE); return;
2432
2433     /*  -------------------------------------------------------------------- */
2434     /*  quit --------------------------------------------------------------- */
2435     /*  -------------------------------------------------------------------- */
2436
2437         case QUIT_CODE:
2438                  assembleg_0(quit_gc); break;
2439
2440     /*  -------------------------------------------------------------------- */
2441     /*  remove <expression> ------------------------------------------------ */
2442     /*  -------------------------------------------------------------------- */
2443
2444         case REMOVE_CODE:
2445                  AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2446                      QUANTITY_CONTEXT, -1);
2447                  if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
2448                      assembleg_call_1(veneer_routine(RT__ChR_VR), AO,
2449                          zero_operand);
2450                  else
2451                      assembleg_call_1(veneer_routine(OB__Remove_VR), AO,
2452                          zero_operand);
2453                  break;
2454
2455     /*  -------------------------------------------------------------------- */
2456     /*  return [<expression>] ---------------------------------------------- */
2457     /*  -------------------------------------------------------------------- */
2458
2459         case RETURN_CODE:
2460           get_next_token();
2461           if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
2462             assembleg_1(return_gc, one_operand); 
2463             return; 
2464           }
2465           put_token_back();
2466           AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
2467             QUANTITY_CONTEXT, -1);
2468           assembleg_1(return_gc, AO);
2469           break;
2470
2471     /*  -------------------------------------------------------------------- */
2472     /*  rfalse ------------------------------------------------------------- */
2473     /*  -------------------------------------------------------------------- */
2474
2475         case RFALSE_CODE:   
2476           assembleg_1(return_gc, zero_operand); 
2477           break;
2478
2479     /*  -------------------------------------------------------------------- */
2480     /*  rtrue -------------------------------------------------------------- */
2481     /*  -------------------------------------------------------------------- */
2482
2483         case RTRUE_CODE:   
2484           assembleg_1(return_gc, one_operand); 
2485           break;
2486
2487     /*  -------------------------------------------------------------------- */
2488     /*  spaces <expression> ------------------------------------------------ */
2489     /*  -------------------------------------------------------------------- */
2490
2491         case SPACES_CODE:
2492                  AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2493                      QUANTITY_CONTEXT, -1);
2494
2495                  assembleg_store(temp_var1, AO);
2496
2497                  INITAO(&AO);
2498                  AO.value = 32; set_constant_ot(&AO);
2499
2500                  assembleg_2_branch(jlt_gc, temp_var1, one_operand, 
2501                      ln = next_label++);
2502                  assemble_label_no(ln2 = next_label++);
2503                  assembleg_1(streamchar_gc, AO);
2504                  assembleg_dec(temp_var1);
2505                  assembleg_1_branch(jnz_gc, temp_var1, ln2);
2506                  assemble_label_no(ln);
2507                  break;
2508
2509     /*  -------------------------------------------------------------------- */
2510     /*  string <expression> <literal-string> ------------------------------- */
2511     /*  -------------------------------------------------------------------- */
2512
2513         case STRING_CODE:
2514                  AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
2515                      QUANTITY_CONTEXT, -1);
2516                  get_next_token();
2517                  if (token_type == DQ_TT)
2518                  {   INITAOT(&AO4, CONSTANT_OT);
2519                      AO4.value = compile_string(token_text, TRUE, TRUE);
2520                      AO4.marker = STRING_MV;
2521                  }
2522                  else
2523                  {   put_token_back();
2524                      AO4 = parse_expression(CONSTANT_CONTEXT);
2525                  }
2526                  assembleg_call_2(veneer_routine(Dynam__String_VR),
2527                    AO2, AO4, zero_operand);
2528                  break;
2529
2530     /*  -------------------------------------------------------------------- */
2531     /*  style roman/reverse/bold/underline/fixed --------------------------- */
2532     /*  -------------------------------------------------------------------- */
2533
2534         case STYLE_CODE:
2535                  misc_keywords.enabled = TRUE;
2536                  get_next_token();
2537                  misc_keywords.enabled = FALSE;
2538                  if ((token_type != MISC_KEYWORD_TT)
2539                      || ((token_value != ROMAN_MK)
2540                          && (token_value != REVERSE_MK)
2541                          && (token_value != BOLD_MK)
2542                          && (token_value != UNDERLINE_MK)
2543                          && (token_value != FIXED_MK)))
2544                  {   ebf_error(
2545 "'roman', 'bold', 'underline', 'reverse' or 'fixed'",
2546                          token_text);
2547                      panic_mode_error_recovery();
2548                      break;
2549                  }
2550
2551                  /* Call glk_set_style() */
2552
2553                  INITAO(&AO);
2554                  AO.value = 0x0086;
2555                  set_constant_ot(&AO);
2556                  switch(token_value)
2557                  {   case ROMAN_MK:
2558                      default: 
2559                          AO2 = zero_operand; /* normal */
2560                          break;
2561                      case REVERSE_MK: 
2562                          INITAO(&AO2);
2563                          AO2.value = 5; /* alert */
2564                          set_constant_ot(&AO2);
2565                          break;
2566                      case BOLD_MK: 
2567                          INITAO(&AO2);
2568                          AO2.value = 4; /* subheader */
2569                          set_constant_ot(&AO2);
2570                          break;
2571                      case UNDERLINE_MK: 
2572                          AO2 = one_operand; /* emphasized */
2573                          break;
2574                      case FIXED_MK: 
2575                          AO2 = two_operand; /* preformatted */
2576                          break;
2577                  }
2578                  assembleg_call_2(veneer_routine(Glk__Wrap_VR), 
2579                    AO, AO2, zero_operand);
2580                  break;
2581
2582     /*  -------------------------------------------------------------------- */
2583     /*  switch (<expression>) <codeblock> ---------------------------------- */
2584     /*  -------------------------------------------------------------------- */
2585
2586         case SWITCH_CODE:
2587                  match_open_bracket();
2588                  AO = code_generate(parse_expression(QUANTITY_CONTEXT),
2589                      QUANTITY_CONTEXT, -1);
2590                  match_close_bracket();
2591
2592                  assembleg_store(temp_var1, AO); 
2593
2594                  parse_code_block(ln = next_label++, continue_label, 1);
2595                  assemble_label_no(ln);
2596                  return;
2597
2598     /*  -------------------------------------------------------------------- */
2599     /*  while (<condition>) <codeblock> ------------------------------------ */
2600     /*  -------------------------------------------------------------------- */
2601
2602         case WHILE_CODE:
2603                  assemble_label_no(ln = next_label++);
2604                  match_open_bracket();
2605
2606                  code_generate(parse_expression(CONDITION_CONTEXT),
2607                      CONDITION_CONTEXT, ln2 = next_label++);
2608                  match_close_bracket();
2609
2610                  parse_code_block(ln2, ln, 0);
2611                  sequence_point_follows = FALSE;
2612                  assembleg_jump(ln);
2613                  assemble_label_no(ln2);
2614                  return;
2615
2616     /*  -------------------------------------------------------------------- */
2617
2618         case SDEFAULT_CODE:
2619                  error("'default' without matching 'switch'"); break;
2620         case ELSE_CODE:
2621                  error("'else' without matching 'if'"); break;
2622         case UNTIL_CODE:
2623                  error("'until' without matching 'do'");
2624                  panic_mode_error_recovery(); return;
2625
2626     /*  -------------------------------------------------------------------- */
2627
2628     /* And a useful default, which will never be triggered in a complete
2629        Inform compiler, but which is important in development. */
2630
2631         default:
2632           error("*** Statement code gen: Can't generate yet ***\n");
2633           panic_mode_error_recovery(); return;
2634     }
2635
2636     StatementTerminator:
2637
2638     get_next_token();
2639     if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
2640     {   ebf_error("';'", token_text);
2641         put_token_back();
2642     }
2643 }
2644
2645 extern void parse_statement(int break_label, int continue_label)
2646 {
2647   if (!glulx_mode)
2648     parse_statement_z(break_label, continue_label);
2649   else
2650     parse_statement_g(break_label, continue_label);
2651 }
2652
2653 /* ========================================================================= */
2654 /*   Data structure management routines                                      */
2655 /* ------------------------------------------------------------------------- */
2656
2657 extern void init_states_vars(void)
2658 {
2659 }
2660
2661 extern void states_begin_pass(void)
2662 {
2663 }
2664
2665 extern void states_allocate_arrays(void)
2666 {
2667 }
2668
2669 extern void states_free_arrays(void)
2670 {
2671 }
2672
2673 /* ========================================================================= */