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