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