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