Implement a Makefile for Inform.
[inform.git] / src / states.c
diff --git a/src/states.c b/src/states.c
new file mode 100644 (file)
index 0000000..cd3b695
--- /dev/null
@@ -0,0 +1,2674 @@
+/* ------------------------------------------------------------------------- */
+/*   "states" :  Statement translator                                        */
+/*                                                                           */
+/* Copyright (c) Graham Nelson 1993 - 2018                                   */
+/*                                                                           */
+/* This file is part of Inform.                                              */
+/*                                                                           */
+/* Inform is free software: you can redistribute it and/or modify            */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation, either version 3 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* Inform is distributed in the hope that it will be useful,                 */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
+/* GNU General Public License for more details.                              */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License         */
+/* along with Inform. If not, see https://gnu.org/licenses/                  */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+#include "header.h"
+
+static int match_colon(void)
+{   get_next_token();
+    if (token_type == SEP_TT)
+    {   if (token_value == SEMICOLON_SEP)
+            warning("Unlike C, Inform uses ':' to divide parts \
+of a 'for' loop specification: replacing ';' with ':'");
+        else
+        if (token_value != COLON_SEP)
+        {   ebf_error("':'", token_text);
+            panic_mode_error_recovery();
+            return(FALSE);
+        }
+    }
+    else
+    {   ebf_error("':'", token_text);
+        panic_mode_error_recovery();
+        return(FALSE);
+    }
+    return(TRUE);
+}
+
+static void match_open_bracket(void)
+{   get_next_token();
+    if ((token_type == SEP_TT) && (token_value == OPENB_SEP)) return;
+    put_token_back();
+    ebf_error("'('", token_text);
+}
+
+extern void match_close_bracket(void)
+{   get_next_token();
+    if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP)) return;
+    put_token_back();
+    ebf_error("')'", token_text);
+}
+
+static void parse_action(void)
+{   int level = 1, args = 0, codegen_action;
+    assembly_operand AO, AO2, AO3, AO4, AO5;
+
+    /* An action statement has the form <ACTION NOUN SECOND, ACTOR>
+       or <<ACTION NOUN SECOND, ACTOR>>. It simply compiles into a call
+       to R_Process() with those four arguments. (The latter form,
+       with double brackets, means "return true afterwards".)
+
+       The R_Process() function should be supplied by the library, 
+       although a stub is defined in the veneer.
+
+       The NOUN, SECOND, and ACTOR arguments are optional. If not
+       supplied, R_Process() will be called with fewer arguments. 
+       (But if you supply ACTOR, it must be preceded by a comma.
+       <ACTION, ACTOR> is equivalent to <ACTION 0 0, ACTOR>.)
+
+       To complicate life, the ACTION argument may be a bare action
+       name or a parenthesized expression. (So <Take> is equivalent
+       to <(##Take)>.) We have to peek at the first token, checking
+       whether it's an open-paren, to distinguish these cases.
+
+       You may ask why the ACTOR argument is last; the "natural"
+       Inform ordering would be "<floyd, take ball>". True! Sadly,
+       Inform's lexer isn't smart enough to parse this consistently,
+       so we can't do it.
+    */
+
+    dont_enter_into_symbol_table = TRUE;
+    get_next_token();
+    if ((token_type == SEP_TT) && (token_value == LESS_SEP))
+    {   level = 2; get_next_token();
+    }
+    dont_enter_into_symbol_table = FALSE;
+
+    /* Peek at the next token; see if it's an open-paren. */
+    if ((token_type==SEP_TT) && (token_value==OPENB_SEP))
+    {   put_token_back();
+        AO2 = parse_expression(ACTION_Q_CONTEXT);
+        codegen_action = TRUE;
+    }
+    else
+    {   codegen_action = FALSE;
+        AO2 = action_of_name(token_text);
+    }
+
+    get_next_token();
+    AO3 = zero_operand;
+    AO4 = zero_operand;
+    AO5 = zero_operand;
+    if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
+    {   put_token_back();
+        args = 1;
+        AO3 = parse_expression(ACTION_Q_CONTEXT);
+
+        get_next_token();
+    }
+    if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
+    {   put_token_back();
+        args = 2;
+        AO4 = parse_expression(QUANTITY_CONTEXT);
+        get_next_token();
+    }
+    if (!((token_type == SEP_TT) && (token_value == GREATER_SEP || token_value == COMMA_SEP)))
+    {
+        ebf_error("',' or '>'", token_text);
+    }
+
+    if ((token_type == SEP_TT) && (token_value == COMMA_SEP))
+    {
+        if (!glulx_mode && (version_number < 4))
+        {
+            error("<x, y> syntax is not available in Z-code V3 or earlier");
+        }
+        args = 3;
+        AO5 = parse_expression(QUANTITY_CONTEXT);
+        get_next_token();
+        if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
+        {
+            ebf_error("'>'", token_text);
+        }
+    }
+
+    if (level == 2)
+    {   get_next_token();
+        if (!((token_type == SEP_TT) && (token_value == GREATER_SEP)))
+        {   put_token_back();
+            ebf_error("'>>'", token_text);
+        }
+    }
+
+    if (!glulx_mode) {
+
+      AO = veneer_routine(R_Process_VR);
+
+      switch(args)
+      {   case 0:
+            if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
+            if (version_number>=5)
+                assemblez_2(call_2n_zc, AO, AO2);
+            else
+            if (version_number==4)
+                assemblez_2_to(call_vs_zc, AO, AO2, temp_var1);
+            else
+                assemblez_2_to(call_zc, AO, AO2, temp_var1);
+            break;
+          case 1:
+            AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
+            if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
+            if (version_number>=5)
+                assemblez_3(call_vn_zc, AO, AO2, AO3);
+            else
+            if (version_number==4)
+                assemblez_3_to(call_vs_zc, AO, AO2, AO3, temp_var1);
+            else
+                assemblez_3_to(call_zc, AO, AO2, AO3, temp_var1);
+            break;
+          case 2:
+            AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
+            AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
+            if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
+            if (version_number>=5)
+                assemblez_4(call_vn_zc, AO, AO2, AO3, AO4);
+            else
+            if (version_number==4)
+                assemblez_4_to(call_vs_zc, AO, AO2, AO3, AO4, temp_var1);
+            else
+                assemblez_4(call_zc, AO, AO2, AO3, AO4);
+            break;
+          case 3:
+            AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
+            AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
+            AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
+            if (codegen_action) AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
+            if (version_number>=5)
+                assemblez_5(call_vn2_zc, AO, AO2, AO3, AO4, AO5);
+            else
+            if (version_number==4)
+                assemblez_5_to(call_vs2_zc, AO, AO2, AO3, AO4, AO5, temp_var1);
+            /* if V3 or earlier, we've already displayed an error */
+            break;
+            break;
+      }
+
+      if (level == 2) assemblez_0(rtrue_zc);
+
+    }
+    else {
+
+      AO = veneer_routine(R_Process_VR);
+
+      switch (args) {
+
+      case 0:
+        if (codegen_action) 
+          AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
+        assembleg_call_1(AO, AO2, zero_operand);
+        break;
+
+      case 1:
+        AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
+        if (codegen_action)
+          AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
+        assembleg_call_2(AO, AO2, AO3, zero_operand);
+        break;
+
+      case 2:
+        AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
+        AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
+        if (codegen_action) 
+          AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
+        assembleg_call_3(AO, AO2, AO3, AO4, zero_operand);
+        break;
+
+      case 3:
+        AO5 = code_generate(AO5, QUANTITY_CONTEXT, -1);
+        if (!((AO5.type == LOCALVAR_OT) && (AO5.value == 0)))
+            assembleg_store(stack_pointer, AO5);
+        AO4 = code_generate(AO4, QUANTITY_CONTEXT, -1);
+        if (!((AO4.type == LOCALVAR_OT) && (AO4.value == 0)))
+            assembleg_store(stack_pointer, AO4);
+        AO3 = code_generate(AO3, QUANTITY_CONTEXT, -1);
+        if (!((AO3.type == LOCALVAR_OT) && (AO3.value == 0)))
+            assembleg_store(stack_pointer, AO3);
+        if (codegen_action) 
+          AO2 = code_generate(AO2, QUANTITY_CONTEXT, -1);
+        if (!((AO2.type == LOCALVAR_OT) && (AO2.value == 0)))
+          assembleg_store(stack_pointer, AO2);
+        assembleg_3(call_gc, AO, four_operand, zero_operand);
+        break;
+      }
+
+      if (level == 2) 
+        assembleg_1(return_gc, one_operand);
+
+    }
+}
+
+extern int parse_label(void)
+{
+    get_next_token();
+
+    if ((token_type == SYMBOL_TT) &&
+        (stypes[token_value] == LABEL_T))
+    {   sflags[token_value] |= USED_SFLAG;
+        return(svals[token_value]);
+    }
+
+    if ((token_type == SYMBOL_TT) && (sflags[token_value] & UNKNOWN_SFLAG))
+    {   assign_symbol(token_value, next_label, LABEL_T);
+        define_symbol_label(token_value);
+        next_label++;
+        sflags[token_value] |= CHANGE_SFLAG + USED_SFLAG;
+        return(svals[token_value]);
+    }
+
+    ebf_error("label name", token_text);
+    return 0;
+}
+
+static void parse_print_z(int finally_return)
+{   int count = 0; assembly_operand AO;
+
+    /*  print <printlist> -------------------------------------------------- */
+    /*  print_ret <printlist> ---------------------------------------------- */
+    /*  <literal-string> --------------------------------------------------- */
+    /*                                                                       */
+    /*  <printlist> is a comma-separated list of items:                      */
+    /*                                                                       */
+    /*       <literal-string>                                                */
+    /*       <other-expression>                                              */
+    /*       (char) <expression>                                             */
+    /*       (address) <expression>                                          */
+    /*       (string) <expression>                                           */
+    /*       (a) <expression>                                                */
+    /*       (the) <expression>                                              */
+    /*       (The) <expression>                                              */
+    /*       (name) <expression>                                             */
+    /*       (number) <expression>                                           */
+    /*       (property) <expression>                                         */
+    /*       (<routine>) <expression>                                        */
+    /*       (object) <expression>     (for use in low-level code only)      */
+    /* --------------------------------------------------------------------- */
+
+    do
+    {   AI.text = token_text;
+        if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
+        switch(token_type)
+        {   case DQ_TT:
+              if (strlen(token_text) > 32)
+              {   INITAOT(&AO, LONG_CONSTANT_OT);
+                  AO.marker = STRING_MV;
+                  AO.value  = compile_string(token_text, FALSE, FALSE);
+                  assemblez_1(print_paddr_zc, AO);
+                  if (finally_return)
+                  {   get_next_token();
+                      if ((token_type == SEP_TT)
+                          && (token_value == SEMICOLON_SEP))
+                      {   assemblez_0(new_line_zc);
+                          assemblez_0(rtrue_zc);
+                          return;
+                      }
+                      put_token_back();
+                  }
+                  break;
+              }
+              if (finally_return)
+              {   get_next_token();
+                  if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
+                  {   assemblez_0(print_ret_zc); return;
+                  }
+                  put_token_back();
+              }
+              assemblez_0(print_zc);
+              break;
+
+            case SEP_TT:
+              if (token_value == OPENB_SEP)
+              {   misc_keywords.enabled = TRUE;
+                  get_next_token();
+                  get_next_token();
+                  if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
+                  {   assembly_operand AO1;
+
+                      put_token_back(); put_token_back();
+                      local_variables.enabled = FALSE;
+                      get_next_token();
+                      misc_keywords.enabled = FALSE;
+                      local_variables.enabled = TRUE;
+
+                      if ((token_type == STATEMENT_TT)
+                          &&(token_value == STRING_CODE))
+                      {   token_type = MISC_KEYWORD_TT;
+                          token_value = STRING_MK;
+                      }
+
+                      switch(token_type)
+                      {
+                        case MISC_KEYWORD_TT:
+                          switch(token_value)
+                          {   case CHAR_MK:
+                                  if (runtime_error_checking_switch)
+                                  {   AO = veneer_routine(RT__ChPrintC_VR);
+                                      goto PrintByRoutine;
+                                  }
+                                  get_next_token();
+                                  AO1 = code_generate(
+                                      parse_expression(QUANTITY_CONTEXT),
+                                      QUANTITY_CONTEXT, -1);
+                                  assemblez_1(print_char_zc, AO1);
+                                  goto PrintTermDone;
+                              case ADDRESS_MK:
+                                  if (runtime_error_checking_switch)
+                                  {   AO = veneer_routine(RT__ChPrintA_VR);
+                                      goto PrintByRoutine;
+                                  }
+                                  get_next_token();
+                                  AO1 = code_generate(
+                                      parse_expression(QUANTITY_CONTEXT),
+                                      QUANTITY_CONTEXT, -1);
+                                  assemblez_1(print_addr_zc, AO1);
+                                  goto PrintTermDone;
+                              case STRING_MK:
+                                  if (runtime_error_checking_switch)
+                                  {   AO = veneer_routine(RT__ChPrintS_VR);
+                                      goto PrintByRoutine;
+                                  }
+                                  get_next_token();
+                                  AO1 = code_generate(
+                                      parse_expression(QUANTITY_CONTEXT),
+                                      QUANTITY_CONTEXT, -1);
+                                  assemblez_1(print_paddr_zc, AO1);
+                                  goto PrintTermDone;
+                              case OBJECT_MK:
+                                  if (runtime_error_checking_switch)
+                                  {   AO = veneer_routine(RT__ChPrintO_VR);
+                                      goto PrintByRoutine;
+                                  }
+                                  get_next_token();
+                                  AO1 = code_generate(
+                                      parse_expression(QUANTITY_CONTEXT),
+                                      QUANTITY_CONTEXT, -1);
+                                  assemblez_1(print_obj_zc, AO1);
+                                  goto PrintTermDone;
+                              case THE_MK:
+                                  AO = veneer_routine(DefArt_VR);
+                                  goto PrintByRoutine;
+                              case AN_MK:
+                              case A_MK:
+                                  AO = veneer_routine(InDefArt_VR);
+                                  goto PrintByRoutine;
+                              case CAP_THE_MK:
+                                  AO = veneer_routine(CDefArt_VR);
+                                  goto PrintByRoutine;
+                              case CAP_A_MK:
+                                  AO = veneer_routine(CInDefArt_VR);
+                                  goto PrintByRoutine;
+                              case NAME_MK:
+                                  AO = veneer_routine(PrintShortName_VR);
+                                  goto PrintByRoutine;
+                              case NUMBER_MK:
+                                  AO = veneer_routine(EnglishNumber_VR);
+                                  goto PrintByRoutine;
+                              case PROPERTY_MK:
+                                  AO = veneer_routine(Print__Pname_VR);
+                                  goto PrintByRoutine;
+                              default:
+               error_named("A reserved word was used as a print specification:",
+                                      token_text);
+                          }
+                          break;
+
+                        case SYMBOL_TT:
+                          if (sflags[token_value] & UNKNOWN_SFLAG)
+                          {   INITAOT(&AO, LONG_CONSTANT_OT);
+                              AO.value = token_value;
+                              AO.marker = SYMBOL_MV;
+                          }
+                          else
+                          {   INITAOT(&AO, LONG_CONSTANT_OT);
+                              AO.value = svals[token_value];
+                              AO.marker = IROUTINE_MV;
+                              if (stypes[token_value] != ROUTINE_T)
+                                ebf_error("printing routine name", token_text);
+                          }
+                          sflags[token_value] |= USED_SFLAG;
+
+                          PrintByRoutine:
+
+                          get_next_token();
+                          if (version_number >= 5)
+                            assemblez_2(call_2n_zc, AO,
+                              code_generate(parse_expression(QUANTITY_CONTEXT),
+                                QUANTITY_CONTEXT, -1));
+                          else if (version_number == 4)
+                            assemblez_2_to(call_vs_zc, AO,
+                              code_generate(parse_expression(QUANTITY_CONTEXT),
+                                QUANTITY_CONTEXT, -1), temp_var1);
+                          else
+                            assemblez_2_to(call_zc, AO,
+                              code_generate(parse_expression(QUANTITY_CONTEXT),
+                                QUANTITY_CONTEXT, -1), temp_var1);
+                          goto PrintTermDone;
+
+                        default: ebf_error("print specification", token_text);
+                          get_next_token();
+                          assemblez_1(print_num_zc,
+                          code_generate(parse_expression(QUANTITY_CONTEXT),
+                                QUANTITY_CONTEXT, -1));
+                          goto PrintTermDone;
+                      }
+                  }
+                  put_token_back(); put_token_back(); put_token_back();
+                  misc_keywords.enabled = FALSE;
+                  assemblez_1(print_num_zc,
+                      code_generate(parse_expression(QUANTITY_CONTEXT),
+                          QUANTITY_CONTEXT, -1));
+                  break;
+              }
+
+            default:
+              put_token_back(); misc_keywords.enabled = FALSE;
+              assemblez_1(print_num_zc,
+                  code_generate(parse_expression(QUANTITY_CONTEXT),
+                      QUANTITY_CONTEXT, -1));
+              break;
+        }
+
+        PrintTermDone: misc_keywords.enabled = FALSE;
+
+        count++;
+        get_next_token();
+        if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
+        if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
+        {   ebf_error("comma", token_text);
+            panic_mode_error_recovery(); return;
+        }
+        else get_next_token();
+    } while(TRUE);
+
+    if (count == 0) ebf_error("something to print", token_text);
+    if (finally_return)
+    {   assemblez_0(new_line_zc);
+        assemblez_0(rtrue_zc);
+    }
+}
+
+static void parse_print_g(int finally_return)
+{   int count = 0; assembly_operand AO, AO2;
+
+    /*  print <printlist> -------------------------------------------------- */
+    /*  print_ret <printlist> ---------------------------------------------- */
+    /*  <literal-string> --------------------------------------------------- */
+    /*                                                                       */
+    /*  <printlist> is a comma-separated list of items:                      */
+    /*                                                                       */
+    /*       <literal-string>                                                */
+    /*       <other-expression>                                              */
+    /*       (char) <expression>                                             */
+    /*       (address) <expression>                                          */
+    /*       (string) <expression>                                           */
+    /*       (a) <expression>                                                */
+    /*       (A) <expression>                                                */
+    /*       (the) <expression>                                              */
+    /*       (The) <expression>                                              */
+    /*       (name) <expression>                                             */
+    /*       (number) <expression>                                           */
+    /*       (property) <expression>                                         */
+    /*       (<routine>) <expression>                                        */
+    /*       (object) <expression>     (for use in low-level code only)      */
+    /* --------------------------------------------------------------------- */
+
+    do
+    {   
+        if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
+        switch(token_type)
+        {   case DQ_TT:
+              /* We can't compile a string into the instruction,
+                 so this always goes into the string area. */
+              {   INITAOT(&AO, CONSTANT_OT);
+                  AO.marker = STRING_MV;
+                  AO.value  = compile_string(token_text, FALSE, FALSE);
+                  assembleg_1(streamstr_gc, AO);
+                  if (finally_return)
+                  {   get_next_token();
+                      if ((token_type == SEP_TT)
+                          && (token_value == SEMICOLON_SEP))
+                      {   INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
+                          assembleg_1(streamchar_gc, AO); 
+                          INITAOTV(&AO, BYTECONSTANT_OT, 1);
+                          assembleg_1(return_gc, AO); 
+                          return;
+                      }
+                      put_token_back();
+                  }
+                  break;
+              }
+              break;
+
+            case SEP_TT:
+              if (token_value == OPENB_SEP)
+              {   misc_keywords.enabled = TRUE;
+                  get_next_token();
+                  get_next_token();
+                  if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
+                  {   assembly_operand AO1;
+                      int ln, ln2;
+
+                      put_token_back(); put_token_back();
+                      local_variables.enabled = FALSE;
+                      get_next_token();
+                      misc_keywords.enabled = FALSE;
+                      local_variables.enabled = TRUE;
+
+                      if ((token_type == STATEMENT_TT)
+                          &&(token_value == STRING_CODE))
+                      {   token_type = MISC_KEYWORD_TT;
+                          token_value = STRING_MK;
+                      }
+
+                      switch(token_type)
+                      {
+                        case MISC_KEYWORD_TT:
+                          switch(token_value)
+                          {   case CHAR_MK:
+                                  if (runtime_error_checking_switch)
+                                  {   AO = veneer_routine(RT__ChPrintC_VR);
+                                      goto PrintByRoutine;
+                                  }
+                                  get_next_token();
+                                  AO1 = code_generate(
+                                      parse_expression(QUANTITY_CONTEXT),
+                                      QUANTITY_CONTEXT, -1);
+                                  if ((AO1.type == LOCALVAR_OT) && (AO1.value == 0))
+                                  {   assembleg_2(stkpeek_gc, zero_operand, 
+                                      stack_pointer);
+                                  }
+                                  INITAOTV(&AO2, HALFCONSTANT_OT, 0x100);
+                                  assembleg_2_branch(jgeu_gc, AO1, AO2, 
+                                      ln = next_label++);
+                                  ln2 = next_label++;
+                                  assembleg_1(streamchar_gc, AO1);
+                                  assembleg_jump(ln2);
+                                  assemble_label_no(ln);
+                                  assembleg_1(streamunichar_gc, AO1);
+                                  assemble_label_no(ln2);
+                                  goto PrintTermDone;
+                              case ADDRESS_MK:
+                                  if (runtime_error_checking_switch)
+                                      AO = veneer_routine(RT__ChPrintA_VR);
+                                  else
+                                      AO = veneer_routine(Print__Addr_VR);
+                                  goto PrintByRoutine;
+                              case STRING_MK:
+                                  if (runtime_error_checking_switch)
+                                  {   AO = veneer_routine(RT__ChPrintS_VR);
+                                      goto PrintByRoutine;
+                                  }
+                                  get_next_token();
+                                  AO1 = code_generate(
+                                      parse_expression(QUANTITY_CONTEXT),
+                                      QUANTITY_CONTEXT, -1);
+                                  assembleg_1(streamstr_gc, AO1);
+                                  goto PrintTermDone;
+                              case OBJECT_MK:
+                                  if (runtime_error_checking_switch)
+                                  {   AO = veneer_routine(RT__ChPrintO_VR);
+                                      goto PrintByRoutine;
+                                  }
+                                  get_next_token();
+                                  AO1 = code_generate(
+                                      parse_expression(QUANTITY_CONTEXT),
+                                      QUANTITY_CONTEXT, -1);
+                                  INITAOT(&AO2, BYTECONSTANT_OT);
+                                  AO2.value = GOBJFIELD_NAME();
+                                  assembleg_3(aload_gc, AO1, AO2, 
+                                    stack_pointer);
+                                  assembleg_1(streamstr_gc, stack_pointer);
+                                  goto PrintTermDone;
+                              case THE_MK:
+                                  AO = veneer_routine(DefArt_VR);
+                                  goto PrintByRoutine;
+                              case AN_MK:
+                              case A_MK:
+                                  AO = veneer_routine(InDefArt_VR);
+                                  goto PrintByRoutine;
+                              case CAP_THE_MK:
+                                  AO = veneer_routine(CDefArt_VR);
+                                  goto PrintByRoutine;
+                              case CAP_A_MK:
+                                  AO = veneer_routine(CInDefArt_VR);
+                                  goto PrintByRoutine;
+                              case NAME_MK:
+                                  AO = veneer_routine(PrintShortName_VR);
+                                  goto PrintByRoutine;
+                              case NUMBER_MK:
+                                  AO = veneer_routine(EnglishNumber_VR);
+                                  goto PrintByRoutine;
+                              case PROPERTY_MK:
+                                  AO = veneer_routine(Print__Pname_VR);
+                                  goto PrintByRoutine;
+                              default:
+               error_named("A reserved word was used as a print specification:",
+                                      token_text);
+                          }
+                          break;
+
+                        case SYMBOL_TT:
+                          if (sflags[token_value] & UNKNOWN_SFLAG)
+                          {   INITAOT(&AO, CONSTANT_OT);
+                              AO.value = token_value;
+                              AO.marker = SYMBOL_MV;
+                          }
+                          else
+                          {   INITAOT(&AO, CONSTANT_OT);
+                              AO.value = svals[token_value];
+                              AO.marker = IROUTINE_MV;
+                              if (stypes[token_value] != ROUTINE_T)
+                                ebf_error("printing routine name", token_text);
+                          }
+                          sflags[token_value] |= USED_SFLAG;
+
+                          PrintByRoutine:
+
+                          get_next_token();
+                          INITAOT(&AO2, ZEROCONSTANT_OT);
+                          assembleg_call_1(AO,
+                            code_generate(parse_expression(QUANTITY_CONTEXT),
+                              QUANTITY_CONTEXT, -1),
+                            AO2);
+                          goto PrintTermDone;
+
+                        default: ebf_error("print specification", token_text);
+                          get_next_token();
+                          assembleg_1(streamnum_gc,
+                          code_generate(parse_expression(QUANTITY_CONTEXT),
+                                QUANTITY_CONTEXT, -1));
+                          goto PrintTermDone;
+                      }
+                  }
+                  put_token_back(); put_token_back(); put_token_back();
+                  misc_keywords.enabled = FALSE;
+                  assembleg_1(streamnum_gc,
+                      code_generate(parse_expression(QUANTITY_CONTEXT),
+                          QUANTITY_CONTEXT, -1));
+                  break;
+              }
+
+            default:
+              put_token_back(); misc_keywords.enabled = FALSE;
+              assembleg_1(streamnum_gc,
+                  code_generate(parse_expression(QUANTITY_CONTEXT),
+                      QUANTITY_CONTEXT, -1));
+              break;
+        }
+
+        PrintTermDone: misc_keywords.enabled = FALSE;
+
+        count++;
+        get_next_token();
+        if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) break;
+        if ((token_type != SEP_TT) || (token_value != COMMA_SEP))
+        {   ebf_error("comma", token_text);
+            panic_mode_error_recovery(); return;
+        }
+        else get_next_token();
+    } while(TRUE);
+
+    if (count == 0) ebf_error("something to print", token_text);
+    if (finally_return)
+    {
+        INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
+        assembleg_1(streamchar_gc, AO); 
+        INITAOTV(&AO, BYTECONSTANT_OT, 1);
+        assembleg_1(return_gc, AO); 
+    }
+}
+
+static void parse_statement_z(int break_label, int continue_label)
+{   int ln, ln2, ln3, ln4, flag;
+    assembly_operand AO, AO2, AO3, AO4;
+    debug_location spare_debug_location1, spare_debug_location2;
+
+    ASSERT_ZCODE();
+
+    if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
+    {   /*  That is, a full stop, signifying a label  */
+
+        get_next_token();
+        if (token_type == SYMBOL_TT)
+        {
+            if (sflags[token_value] & UNKNOWN_SFLAG)
+            {   assign_symbol(token_value, next_label, LABEL_T);
+                sflags[token_value] |= USED_SFLAG;
+                assemble_label_no(next_label);
+                define_symbol_label(token_value);
+                next_label++;
+            }
+            else
+            {   if (stypes[token_value] != LABEL_T) goto LabelError;
+                if (sflags[token_value] & CHANGE_SFLAG)
+                {   sflags[token_value] &= (~(CHANGE_SFLAG));
+                    assemble_label_no(svals[token_value]);
+                    define_symbol_label(token_value);
+                }
+                else error_named("Duplicate definition of label:", token_text);
+            }
+
+            get_next_token();
+            if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
+            {   ebf_error("';'", token_text);
+                put_token_back(); return;
+            }
+
+            /*  Interesting point of Inform grammar: a statement can only
+                consist solely of a label when it is immediately followed
+                by a "}".                                                    */
+
+            get_next_token();
+            if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
+            {   put_token_back(); return;
+            }
+            statement_debug_location = get_token_location();
+            parse_statement(break_label, continue_label);
+            return;
+        }
+        LabelError: ebf_error("label name", token_text);
+    }
+
+    if ((token_type == SEP_TT) && (token_value == HASH_SEP))
+    {   parse_directive(TRUE);
+        parse_statement(break_label, continue_label); return;
+    }
+
+    if ((token_type == SEP_TT) && (token_value == AT_SEP))
+    {   parse_assembly(); return;
+    }
+
+    if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
+
+    if (token_type == DQ_TT)
+    {   parse_print_z(TRUE); return;
+    }
+
+    if ((token_type == SEP_TT) && (token_value == LESS_SEP))
+    {   parse_action(); goto StatementTerminator; }
+
+    if (token_type == EOF_TT)
+    {   ebf_error("statement", token_text); return; }
+
+    if (token_type != STATEMENT_TT)
+    {   put_token_back();
+        AO = parse_expression(VOID_CONTEXT);
+        code_generate(AO, VOID_CONTEXT, -1);
+        if (vivc_flag) { panic_mode_error_recovery(); return; }
+        goto StatementTerminator;
+    }
+
+    statements.enabled = FALSE;
+
+    switch(token_value)
+    {
+    /*  -------------------------------------------------------------------- */
+    /*  box <string-1> ... <string-n> -------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case BOX_CODE:
+             if (version_number == 3)
+                 warning("The 'box' statement has no effect in a version 3 game");
+             INITAOT(&AO3, LONG_CONSTANT_OT);
+                 AO3.value = begin_table_array();
+                 AO3.marker = ARRAY_MV;
+                 ln = 0; ln2 = 0;
+                 do
+                 {   get_next_token();
+                     if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
+                         break;
+                     if (token_type != DQ_TT)
+                         ebf_error("text of box line in double-quotes",
+                             token_text);
+                     {   int i, j;
+                         for (i=0, j=0; token_text[i] != 0; j++)
+                             if (token_text[i] == '@')
+                             {   if (token_text[i+1] == '@')
+                                 {   i = i + 2;
+                                     while (isdigit(token_text[i])) i++;
+                                 }
+                                 else
+                                 {   i++;
+                                     if (token_text[i] != 0) i++;
+                                     if (token_text[i] != 0) i++;
+                                 }
+                             }
+                             else i++;
+                         if (j > ln2) ln2 = j;
+                     }
+                     put_token_back();
+                     array_entry(ln++,parse_expression(CONSTANT_CONTEXT));
+                 } while (TRUE);
+                 finish_array(ln);
+                 if (ln == 0)
+                     error("No lines of text given for 'box' display");
+
+                 if (version_number == 3) return;
+
+                 INITAOTV(&AO2, SHORT_CONSTANT_OT, ln2);
+                 INITAOTV(&AO4, VARIABLE_OT, 255);
+                 assemblez_3_to(call_vs_zc, veneer_routine(Box__Routine_VR),
+                     AO2, AO3, AO4);
+                 return;
+
+    /*  -------------------------------------------------------------------- */
+    /*  break -------------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case BREAK_CODE:
+                 if (break_label == -1)
+                 error("'break' can only be used in a loop or 'switch' block");
+                 else
+                     assemblez_jump(break_label);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  continue ----------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case CONTINUE_CODE:
+                 if (continue_label == -1)
+                 error("'continue' can only be used in a loop block");
+                 else
+                     assemblez_jump(continue_label);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  do <codeblock> until (<condition>) --------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case DO_CODE:
+                 assemble_label_no(ln = next_label++);
+                 ln2 = next_label++; ln3 = next_label++;
+                 parse_code_block(ln3, ln2, 0);
+                 statements.enabled = TRUE;
+                 get_next_token();
+                 if ((token_type == STATEMENT_TT)
+                     && (token_value == UNTIL_CODE))
+                 {   assemble_label_no(ln2);
+                     match_open_bracket();
+                     AO = parse_expression(CONDITION_CONTEXT);
+                     match_close_bracket();
+                     code_generate(AO, CONDITION_CONTEXT, ln);
+                 }
+                 else error("'do' without matching 'until'");
+
+                 assemble_label_no(ln3);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  font on/off -------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case FONT_CODE:
+                 misc_keywords.enabled = TRUE;
+                 get_next_token();
+                 misc_keywords.enabled = FALSE;
+                 if ((token_type != MISC_KEYWORD_TT)
+                     || ((token_value != ON_MK)
+                         && (token_value != OFF_MK)))
+                 {   ebf_error("'on' or 'off'", token_text);
+                     panic_mode_error_recovery();
+                     break;
+                 }
+
+                 if (version_number >= 5)
+                 {   /* Use the V5 @set_font opcode, setting font 4
+                        (for font off) or 1 (for font on). */
+                     INITAOT(&AO, SHORT_CONSTANT_OT);
+                     if (token_value == ON_MK)
+                         AO.value = 1;
+                     else
+                         AO.value = 4;
+                     assemblez_1_to(set_font_zc, AO, temp_var1);
+                     break;
+                 }
+
+                 /* Set the fixed-pitch header bit. */
+                 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
+                 INITAOTV(&AO2, SHORT_CONSTANT_OT, 8);
+                 INITAOTV(&AO3, VARIABLE_OT, 255);
+                 assemblez_2_to(loadw_zc, AO, AO2, AO3);
+
+                 if (token_value == ON_MK)
+                 {   INITAOTV(&AO4, LONG_CONSTANT_OT, 0xfffd);
+                     assemblez_2_to(and_zc, AO4, AO3, AO3);
+                 }
+                 else
+                 {   INITAOTV(&AO4, SHORT_CONSTANT_OT, 2);
+                     assemblez_2_to(or_zc, AO4, AO3, AO3);
+                 }
+
+                 assemblez_3(storew_zc, AO, AO2, AO3);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  for (<initialisation> : <continue-condition> : <updating>) --------- */
+    /*  -------------------------------------------------------------------- */
+
+        /*  Note that it's legal for any or all of the three sections of a
+            'for' specification to be empty.  This 'for' implementation
+            often wastes 3 bytes with a redundant branch rather than keep
+            expression parse trees for long periods (as previous versions
+            of Inform did, somewhat crudely by simply storing the textual
+            form of a 'for' loop).  It is adequate for now.                  */
+
+        case FOR_CODE:
+                 match_open_bracket();
+                 get_next_token();
+
+                 /*  Initialisation code  */
+
+                 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
+                 {   put_token_back();
+                     if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
+                     {   sequence_point_follows = TRUE;
+                         statement_debug_location = get_token_location();
+                         code_generate(parse_expression(FORINIT_CONTEXT),
+                             VOID_CONTEXT, -1);
+                     }
+                     get_next_token();
+                     if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
+                     {   get_next_token();
+                         if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
+                         {   assemble_label_no(ln = next_label++);
+                             ln2 = next_label++;
+                             parse_code_block(ln2, ln, 0);
+                             sequence_point_follows = FALSE;
+                             if (!execution_never_reaches_here)
+                                 assemblez_jump(ln);
+                             assemble_label_no(ln2);
+                             return;
+                         }
+                         AO.type = OMITTED_OT;
+                         goto ParseUpdate;
+                     }
+                     put_token_back();
+                     if (!match_colon()) break;
+                 }
+
+                 get_next_token();
+                 AO.type = OMITTED_OT;
+                 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
+                 {   put_token_back();
+                     spare_debug_location1 = get_token_location();
+                     AO = parse_expression(CONDITION_CONTEXT);
+                     if (!match_colon()) break;
+                 }
+                 get_next_token();
+
+                 ParseUpdate:
+                 AO2.type = OMITTED_OT; flag = 0;
+                 if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
+                 {   put_token_back();
+                     spare_debug_location2 = get_token_location();
+                     AO2 = parse_expression(VOID_CONTEXT);
+                     match_close_bracket();
+                     flag = test_for_incdec(AO2);
+                 }
+
+                 ln = next_label++;
+                 ln2 = next_label++;
+                 ln3 = next_label++;
+
+                 if ((AO2.type == OMITTED_OT) || (flag != 0))
+                 {
+                     assemble_label_no(ln);
+                     if (flag==0) assemble_label_no(ln2);
+
+                     /*  The "finished yet?" condition  */
+
+                     if (AO.type != OMITTED_OT)
+                     {   sequence_point_follows = TRUE;
+                         statement_debug_location = spare_debug_location1;
+                         code_generate(AO, CONDITION_CONTEXT, ln3);
+                     }
+
+                 }
+                 else
+                 {
+                     /*  This is the jump which could be avoided with the aid
+                         of long-term expression storage  */
+
+                     sequence_point_follows = FALSE;
+                     assemblez_jump(ln2);
+
+                     /*  The "update" part  */
+
+                     assemble_label_no(ln);
+                     sequence_point_follows = TRUE;
+                     statement_debug_location = spare_debug_location2;
+                     code_generate(AO2, VOID_CONTEXT, -1);
+
+                     assemble_label_no(ln2);
+
+                     /*  The "finished yet?" condition  */
+
+                     if (AO.type != OMITTED_OT)
+                     {   sequence_point_follows = TRUE;
+                         statement_debug_location = spare_debug_location1;
+                         code_generate(AO, CONDITION_CONTEXT, ln3);
+                     }
+                 }
+
+                 if (flag != 0)
+                 {
+                     /*  In this optimised case, update code is at the end
+                         of the loop block, so "continue" goes there  */
+
+                     parse_code_block(ln3, ln2, 0);
+                     assemble_label_no(ln2);
+
+                     sequence_point_follows = TRUE;
+                     statement_debug_location = spare_debug_location2;
+                     if (flag > 0)
+                     {   INITAOTV(&AO3, SHORT_CONSTANT_OT, flag);
+                         if (module_switch
+                             && (flag>=MAX_LOCAL_VARIABLES) && (flag<LOWEST_SYSTEM_VAR_NUMBER))
+                             AO3.marker = VARIABLE_MV;
+                         assemblez_1(inc_zc, AO3);
+                     }
+                     else
+                     {   INITAOTV(&AO3, SHORT_CONSTANT_OT, -flag);
+                         if ((module_switch) && (flag>=MAX_LOCAL_VARIABLES)
+                             && (flag<LOWEST_SYSTEM_VAR_NUMBER))
+                             AO3.marker = VARIABLE_MV;
+                         assemblez_1(dec_zc, AO3);
+                     }
+                     assemblez_jump(ln);
+                 }
+                 else
+                 {
+                     /*  In the unoptimised case, update code is at the
+                         start of the loop block, so "continue" goes there  */
+
+                     parse_code_block(ln3, ln, 0);
+                     if (!execution_never_reaches_here)
+                     {   sequence_point_follows = FALSE;
+                         assemblez_jump(ln);
+                     }
+                 }
+
+                 assemble_label_no(ln3);
+                 return;
+
+    /*  -------------------------------------------------------------------- */
+    /*  give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case GIVE_CODE:
+                 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
+                          QUANTITY_CONTEXT, -1);
+                 if ((AO.type == VARIABLE_OT) && (AO.value == 0))
+                 {   INITAOTV(&AO, SHORT_CONSTANT_OT, 252);
+                     if (version_number != 6) assemblez_1(pull_zc, AO);
+                     else assemblez_0_to(pull_zc, AO);
+                     AO.type = VARIABLE_OT;
+                 }
+
+                 do
+                 {   get_next_token();
+                     if ((token_type == SEP_TT)&&(token_value == SEMICOLON_SEP))
+                         return;
+                     if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
+                         ln = clear_attr_zc;
+                     else
+                     {   if ((token_type == SYMBOL_TT)
+                             && (stypes[token_value] != ATTRIBUTE_T))
+                           warning_named("This is not a declared Attribute:",
+                             token_text);
+                         ln = set_attr_zc;
+                         put_token_back();
+                     }
+                     AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
+                               QUANTITY_CONTEXT, -1);
+                     if (runtime_error_checking_switch)
+                     {   ln2 = (ln==set_attr_zc)?RT__ChG_VR:RT__ChGt_VR;
+                         if (version_number >= 5)
+                             assemblez_3(call_vn_zc, veneer_routine(ln2),
+                             AO, AO2);
+                         else
+                         {   
+                             assemblez_3_to(call_zc, veneer_routine(ln2),
+                                 AO, AO2, temp_var1);
+                         }
+                     }
+                     else
+                         assemblez_2(ln, AO, AO2);
+                 } while(TRUE);
+
+    /*  -------------------------------------------------------------------- */
+    /*  if (<condition>) <codeblock> [else <codeblock>] -------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case IF_CODE:
+                 flag = FALSE;
+                 ln2 = 0;
+
+                 match_open_bracket();
+                 AO = parse_expression(CONDITION_CONTEXT);
+                 match_close_bracket();
+
+                 statements.enabled = TRUE;
+                 get_next_token();
+                 if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
+                     ln = -4;
+                 else
+                 if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
+                     ln = -3;
+                 else
+                 {   put_token_back();
+                     ln = next_label++;
+                 }
+
+                 code_generate(AO, CONDITION_CONTEXT, ln);
+
+                 if (ln >= 0) parse_code_block(break_label, continue_label, 0);
+                 else
+                 {   get_next_token();
+                     if ((token_type != SEP_TT)
+                         || (token_value != SEMICOLON_SEP))
+                     {   ebf_error("';'", token_text);
+                         put_token_back();
+                     }
+                 }
+
+                 statements.enabled = TRUE;
+                 get_next_token();
+                 if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
+                 {   flag = TRUE;
+                     if (ln >= 0)
+                     {   ln2 = next_label++;
+                         if (!execution_never_reaches_here)
+                         {   sequence_point_follows = FALSE;
+                             assemblez_jump(ln2);
+                         }
+                     }
+                 }
+                 else put_token_back();
+
+                 if (ln >= 0) assemble_label_no(ln);
+
+                 if (flag)
+                 {   parse_code_block(break_label, continue_label, 0);
+                     if (ln >= 0) assemble_label_no(ln2);
+                 }
+
+                 return;
+
+    /*  -------------------------------------------------------------------- */
+    /*  inversion ---------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case INVERSION_CODE:
+                 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
+                 INITAOT(&AO2, SHORT_CONSTANT_OT);
+
+                 AO2.value  = 60;
+                 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
+                 assemblez_1(print_char_zc, temp_var1);
+                 AO2.value  = 61;
+                 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
+                 assemblez_1(print_char_zc, temp_var1);
+                 AO2.value  = 62;
+                 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
+                 assemblez_1(print_char_zc, temp_var1);
+                 AO2.value  = 63;
+                 assemblez_2_to(loadb_zc, AO, AO2, temp_var1);
+                 assemblez_1(print_char_zc, temp_var1);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  jump <label> ------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case JUMP_CODE:
+                 assemblez_jump(parse_label());
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  move <expression> to <expression> ---------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case MOVE_CODE:
+                 misc_keywords.enabled = TRUE;
+                 AO = parse_expression(QUANTITY_CONTEXT);
+
+                 get_next_token();
+                 misc_keywords.enabled = FALSE;
+                 if ((token_type != MISC_KEYWORD_TT)
+                     || (token_value != TO_MK))
+                 {   ebf_error("'to'", token_text);
+                     panic_mode_error_recovery();
+                     return;
+                 }
+
+                 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
+                     QUANTITY_CONTEXT, -1);
+                 AO = code_generate(AO, QUANTITY_CONTEXT, -1);
+                 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
+                 {   if (version_number >= 5)
+                         assemblez_3(call_vn_zc, veneer_routine(RT__ChT_VR),
+                             AO, AO2);
+                     else
+                     {   assemblez_3_to(call_zc, veneer_routine(RT__ChT_VR),
+                             AO, AO2, temp_var1);
+                     }
+                 }
+                 else
+                     assemblez_2(insert_obj_zc, AO, AO2);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  new_line ----------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case NEW_LINE_CODE:  assemblez_0(new_line_zc); break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  objectloop (<initialisation>) <codeblock> -------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case OBJECTLOOP_CODE:
+
+                 match_open_bracket();
+                 get_next_token();
+                 INITAOT(&AO, VARIABLE_OT);
+                 if (token_type == LOCAL_VARIABLE_TT)
+                     AO.value = token_value;
+                 else
+                 if ((token_type == SYMBOL_TT) &&
+                     (stypes[token_value] == GLOBAL_VARIABLE_T))
+                     AO.value = svals[token_value];
+                 else
+                 {   ebf_error("'objectloop' variable", token_text);
+                     panic_mode_error_recovery(); break;
+                 }
+                 if ((module_switch) && (AO.value >= MAX_LOCAL_VARIABLES)
+                     && (AO.value < LOWEST_SYSTEM_VAR_NUMBER))
+                     AO.marker = VARIABLE_MV;
+                 misc_keywords.enabled = TRUE;
+                 get_next_token(); flag = TRUE;
+                 misc_keywords.enabled = FALSE;
+                 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
+                     flag = FALSE;
+
+                 ln = 0;
+                 if ((token_type == MISC_KEYWORD_TT)
+                     && (token_value == NEAR_MK)) ln = 1;
+                 if ((token_type == MISC_KEYWORD_TT)
+                     && (token_value == FROM_MK)) ln = 2;
+                 if ((token_type == CND_TT) && (token_value == IN_COND))
+                 {   get_next_token();
+                     get_next_token();
+                     if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
+                         ln = 3;
+                     put_token_back();
+                     put_token_back();
+                 }
+
+                 if (ln > 0)
+                 {   /*  Old style (Inform 5) objectloops: note that we
+                         implement objectloop (a in b) in the old way since
+                         this runs through objects in a different order from
+                         the new way, and there may be existing Inform code
+                         relying on this.                                    */
+                     assembly_operand AO4;
+                     INITAO(&AO4);
+
+                     sequence_point_follows = TRUE;
+                     AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
+                         QUANTITY_CONTEXT, -1);
+                     match_close_bracket();
+                     if (ln == 1)
+                     {   INITAOTV(&AO3, VARIABLE_OT, 0);
+                         if (runtime_error_checking_switch)
+                                 AO2 = check_nonzero_at_runtime(AO2, -1,
+                                     OBJECTLOOP_RTE);
+                         assemblez_1_to(get_parent_zc, AO2, AO3);
+                         assemblez_objcode(get_child_zc, AO3, AO3, -2, TRUE);
+                         AO2 = AO3;
+                     }
+                     if (ln == 3)
+                     {   INITAOTV(&AO3, VARIABLE_OT, 0);
+                         if (runtime_error_checking_switch)
+                         {   AO4 = AO2;
+                             AO2 = check_nonzero_at_runtime(AO2, -1,
+                                 CHILD_RTE);
+                         }
+                         assemblez_objcode(get_child_zc, AO2, AO3, -2, TRUE);
+                         AO2 = AO3;
+                     }
+                     assemblez_store(AO, AO2);
+                     assemblez_1_branch(jz_zc, AO, ln2 = next_label++, TRUE);
+                     assemble_label_no(ln4 = next_label++);
+                     parse_code_block(ln2, ln3 = next_label++, 0);
+                     sequence_point_follows = FALSE;
+                     assemble_label_no(ln3);
+                     if (runtime_error_checking_switch)
+                     {   AO2 = check_nonzero_at_runtime(AO, ln2,
+                              OBJECTLOOP2_RTE);
+                         if ((ln == 3)
+                             && ((AO4.type != VARIABLE_OT)||(AO4.value != 0))
+                             && ((AO4.type != VARIABLE_OT)
+                                 ||(AO4.value != AO.value)))
+                         {   assembly_operand en_ao;
+                             INITAOTV(&en_ao, SHORT_CONSTANT_OT, OBJECTLOOP_BROKEN_RTE);
+                             assemblez_2_branch(jin_zc, AO, AO4,
+                                 next_label, TRUE);
+                             assemblez_3(call_vn_zc, veneer_routine(RT__Err_VR),
+                                 en_ao, AO);
+                             assemblez_jump(ln2);
+                             assemble_label_no(next_label++);
+                         }
+                     }
+                     else AO2 = AO;
+                     assemblez_objcode(get_sibling_zc, AO2, AO, ln4, TRUE);
+                     assemble_label_no(ln2);
+                     return;
+                 }
+
+                 sequence_point_follows = TRUE;
+                 INITAOTV(&AO2, SHORT_CONSTANT_OT, 1);
+                 assemblez_store(AO, AO2);
+
+                 assemble_label_no(ln = next_label++);
+                 ln2 = next_label++;
+                 ln3 = next_label++;
+                 if (flag)
+                 {   put_token_back();
+                     put_token_back();
+                     sequence_point_follows = TRUE;
+                     code_generate(parse_expression(CONDITION_CONTEXT),
+                         CONDITION_CONTEXT, ln3);
+                     match_close_bracket();
+                 }
+                 parse_code_block(ln2, ln3, 0);
+
+                 sequence_point_follows = FALSE;
+                 assemble_label_no(ln3);
+                 assemblez_inc(AO);
+                 INITAOTV(&AO2, LONG_CONSTANT_OT, no_objects);
+                 AO2.marker = NO_OBJS_MV;
+                 assemblez_2_branch(jg_zc, AO, AO2, ln2, TRUE);
+                 assemblez_jump(ln);
+                 assemble_label_no(ln2);
+                 return;
+
+    /*  -------------------------------------------------------------------- */
+    /*  (see routine above) ------------------------------------------------ */
+    /*  -------------------------------------------------------------------- */
+
+        case PRINT_CODE:
+            get_next_token();
+            parse_print_z(FALSE); return;
+        case PRINT_RET_CODE:
+            get_next_token();
+            parse_print_z(TRUE); return;
+
+    /*  -------------------------------------------------------------------- */
+    /*  quit --------------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case QUIT_CODE:      assemblez_0(quit_zc); break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  read <expression> <expression> [<Routine>] ------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case READ_CODE:
+                 INITAOTV(&AO, VARIABLE_OT, 252);
+                 assemblez_store(AO,
+                     code_generate(parse_expression(QUANTITY_CONTEXT),
+                                   QUANTITY_CONTEXT, -1));
+                 if (version_number > 3)
+                 {   INITAOTV(&AO3, SHORT_CONSTANT_OT, 1);
+                     INITAOTV(&AO4, SHORT_CONSTANT_OT, 0);
+                     assemblez_3(storeb_zc, AO, AO3, AO4);
+                 }
+                 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
+                           QUANTITY_CONTEXT, -1);
+
+                 get_next_token();
+                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
+                     put_token_back();
+                 else
+                 {   if (version_number == 3)
+                         error(
+"In Version 3 no status-line drawing routine can be given");
+                     else
+                     {   assembly_operand AO5;
+                         /* Move the temp4 (buffer) value to the stack,
+                            since the routine might alter temp4. */
+                         assemblez_store(stack_pointer, AO);
+                         AO = stack_pointer;
+                         put_token_back();
+                         AO5 = parse_expression(CONSTANT_CONTEXT);
+
+                         if (version_number >= 5)
+                             assemblez_1(call_1n_zc, AO5);
+                         else
+                             assemblez_1_to(call_zc, AO5, temp_var1);
+                     }
+                 }
+
+                 if (version_number > 4)
+                 {   assemblez_2_to(aread_zc, AO, AO2, temp_var1);
+                 }
+                 else assemblez_2(sread_zc, AO, AO2);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  remove <expression> ------------------------------------------------ */
+    /*  -------------------------------------------------------------------- */
+
+        case REMOVE_CODE:
+                 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
+                     QUANTITY_CONTEXT, -1);
+                 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
+                 {   if (version_number >= 5)
+                         assemblez_2(call_2n_zc, veneer_routine(RT__ChR_VR),
+                             AO);
+                     else
+                     {   assemblez_2_to(call_zc, veneer_routine(RT__ChR_VR),
+                             AO, temp_var1);
+                     }
+                 }
+                 else
+                     assemblez_1(remove_obj_zc, AO);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  restore <label> ---------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case RESTORE_CODE:
+                 if (version_number < 5)
+                     assemblez_0_branch(restore_zc, parse_label(), TRUE);
+                 else
+                 {   INITAOTV(&AO2, SHORT_CONSTANT_OT, 2);
+                     assemblez_0_to(restore_zc, temp_var1);
+                     assemblez_2_branch(je_zc, temp_var1, AO2, parse_label(), TRUE);
+                 }
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  return [<expression>] ---------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case RETURN_CODE:
+                 get_next_token();
+                 if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))
+                 {   assemblez_0(rtrue_zc); return; }
+                 put_token_back();
+                 AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
+                     QUANTITY_CONTEXT, -1);
+                 if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 0)
+                     && (AO.marker == 0))
+                 {   assemblez_0(rfalse_zc); break; }
+                 if ((AO.type == SHORT_CONSTANT_OT) && (AO.value == 1)
+                     && (AO.marker == 0))
+                 {   assemblez_0(rtrue_zc); break; }
+                 if ((AO.type == VARIABLE_OT) && (AO.value == 0))
+                 {   assemblez_0(ret_popped_zc); break; }
+                 assemblez_1(ret_zc, AO);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  rfalse ------------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case RFALSE_CODE:  assemblez_0(rfalse_zc); break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  rtrue -------------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case RTRUE_CODE:   assemblez_0(rtrue_zc); break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  save <label> ------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case SAVE_CODE:
+                 if (version_number < 5)
+                     assemblez_0_branch(save_zc, parse_label(), TRUE);
+                 else
+                 {   INITAOTV(&AO, VARIABLE_OT, 255);
+                     assemblez_0_to(save_zc, AO);
+                     assemblez_1_branch(jz_zc, AO, parse_label(), FALSE);
+                 }
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  spaces <expression> ------------------------------------------------ */
+    /*  -------------------------------------------------------------------- */
+
+        case SPACES_CODE:
+                 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
+                     QUANTITY_CONTEXT, -1);
+                 INITAOTV(&AO2, VARIABLE_OT, 255);
+
+                 assemblez_store(AO2, AO);
+
+                 INITAOTV(&AO, SHORT_CONSTANT_OT, 32);
+                 INITAOTV(&AO3, SHORT_CONSTANT_OT, 1);
+
+                 assemblez_2_branch(jl_zc, AO2, AO3, ln = next_label++, TRUE);
+                 assemble_label_no(ln2 = next_label++);
+                 assemblez_1(print_char_zc, AO);
+                 assemblez_dec(AO2);
+                 assemblez_1_branch(jz_zc, AO2, ln2, FALSE);
+                 assemble_label_no(ln);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  string <expression> <literal-string> ------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case STRING_CODE:
+                 INITAOTV(&AO, SHORT_CONSTANT_OT, 0);
+                 INITAOTV(&AO2, SHORT_CONSTANT_OT, 12);
+                 INITAOTV(&AO3, VARIABLE_OT, 252);
+                 assemblez_2_to(loadw_zc, AO, AO2, AO3);
+                 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
+                     QUANTITY_CONTEXT, -1);
+                 get_next_token();
+                 if (token_type == DQ_TT)
+                 {   INITAOT(&AO4, LONG_CONSTANT_OT);
+                     AO4.value = compile_string(token_text, TRUE, TRUE);
+                 }
+                 else
+                 {   put_token_back();
+                     AO4 = parse_expression(CONSTANT_CONTEXT);
+                 }
+                 assemblez_3(storew_zc, AO3, AO2, AO4);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  style roman/reverse/bold/underline/fixed --------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case STYLE_CODE:
+                 if (version_number==3)
+                 {   error(
+"The 'style' statement cannot be used for Version 3 games");
+                     panic_mode_error_recovery();
+                     break;
+                 }
+
+                 misc_keywords.enabled = TRUE;
+                 get_next_token();
+                 misc_keywords.enabled = FALSE;
+                 if ((token_type != MISC_KEYWORD_TT)
+                     || ((token_value != ROMAN_MK)
+                         && (token_value != REVERSE_MK)
+                         && (token_value != BOLD_MK)
+                         && (token_value != UNDERLINE_MK)
+                         && (token_value != FIXED_MK)))
+                 {   ebf_error(
+"'roman', 'bold', 'underline', 'reverse' or 'fixed'",
+                         token_text);
+                     panic_mode_error_recovery();
+                     break;
+                 }
+
+                 INITAOT(&AO, SHORT_CONSTANT_OT);
+                 switch(token_value)
+                 {   case ROMAN_MK: AO.value = 0; break;
+                     case REVERSE_MK: AO.value = 1; break;
+                     case BOLD_MK: AO.value = 2; break;
+                     case UNDERLINE_MK: AO.value = 4; break;
+                     case FIXED_MK: AO.value = 8; break;
+                 }
+                 assemblez_1(set_text_style_zc, AO); break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  switch (<expression>) <codeblock> ---------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case SWITCH_CODE:
+                 match_open_bracket();
+                 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
+                     QUANTITY_CONTEXT, -1);
+                 match_close_bracket();
+
+                 INITAOTV(&AO2, VARIABLE_OT, 255);
+                 assemblez_store(AO2, AO);
+
+                 parse_code_block(ln = next_label++, continue_label, 1);
+                 assemble_label_no(ln);
+                 return;
+
+    /*  -------------------------------------------------------------------- */
+    /*  while (<condition>) <codeblock> ------------------------------------ */
+    /*  -------------------------------------------------------------------- */
+
+        case WHILE_CODE:
+                 assemble_label_no(ln = next_label++);
+                 match_open_bracket();
+
+                 code_generate(parse_expression(CONDITION_CONTEXT),
+                     CONDITION_CONTEXT, ln2 = next_label++);
+                 match_close_bracket();
+
+                 parse_code_block(ln2, ln, 0);
+                 sequence_point_follows = FALSE;
+                 assemblez_jump(ln);
+                 assemble_label_no(ln2);
+                 return;
+
+    /*  -------------------------------------------------------------------- */
+
+        case SDEFAULT_CODE:
+                 error("'default' without matching 'switch'"); break;
+        case ELSE_CODE:
+                 error("'else' without matching 'if'"); break;
+        case UNTIL_CODE:
+                 error("'until' without matching 'do'");
+                 panic_mode_error_recovery(); return;
+    }
+
+    StatementTerminator:
+
+    get_next_token();
+    if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
+    {   ebf_error("';'", token_text);
+        put_token_back();
+    }
+}
+
+static void parse_statement_g(int break_label, int continue_label)
+{   int ln, ln2, ln3, ln4, flag, onstack;
+    assembly_operand AO, AO2, AO3, AO4;
+    debug_location spare_debug_location1, spare_debug_location2;
+
+    ASSERT_GLULX();
+
+    if ((token_type == SEP_TT) && (token_value == PROPERTY_SEP))
+    {   /*  That is, a full stop, signifying a label  */
+
+        get_next_token();
+        if (token_type == SYMBOL_TT)
+        {
+            if (sflags[token_value] & UNKNOWN_SFLAG)
+            {   assign_symbol(token_value, next_label, LABEL_T);
+                sflags[token_value] |= USED_SFLAG;
+                assemble_label_no(next_label);
+                define_symbol_label(token_value);
+                next_label++;
+            }
+            else
+            {   if (stypes[token_value] != LABEL_T) goto LabelError;
+                if (sflags[token_value] & CHANGE_SFLAG)
+                {   sflags[token_value] &= (~(CHANGE_SFLAG));
+                    assemble_label_no(svals[token_value]);
+                    define_symbol_label(token_value);
+                }
+                else error_named("Duplicate definition of label:", token_text);
+            }
+
+            get_next_token();
+            if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
+            {   ebf_error("';'", token_text);
+                put_token_back(); return;
+            }
+
+            /*  Interesting point of Inform grammar: a statement can only
+                consist solely of a label when it is immediately followed
+                by a "}".                                                    */
+
+            get_next_token();
+            if ((token_type == SEP_TT) && (token_value == CLOSE_BRACE_SEP))
+            {   put_token_back(); return;
+            }
+            /* The following line prevents labels from influencing the positions
+               of sequence points. */
+            statement_debug_location = get_token_location();
+            parse_statement(break_label, continue_label);
+            return;
+        }
+        LabelError: ebf_error("label name", token_text);
+    }
+
+    if ((token_type == SEP_TT) && (token_value == HASH_SEP))
+    {   parse_directive(TRUE);
+        parse_statement(break_label, continue_label); return;
+    }
+
+    if ((token_type == SEP_TT) && (token_value == AT_SEP))
+    {   parse_assembly(); return;
+    }
+
+    if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) return;
+
+    if (token_type == DQ_TT)
+    {   parse_print_g(TRUE); return;
+    }
+
+    if ((token_type == SEP_TT) && (token_value == LESS_SEP))
+    {   parse_action(); goto StatementTerminator; }
+
+    if (token_type == EOF_TT)
+    {   ebf_error("statement", token_text); return; }
+
+    if (token_type != STATEMENT_TT)
+    {   put_token_back();
+        AO = parse_expression(VOID_CONTEXT);
+        code_generate(AO, VOID_CONTEXT, -1);
+        if (vivc_flag) { panic_mode_error_recovery(); return; }
+        goto StatementTerminator;
+    }
+
+    statements.enabled = FALSE;
+
+    switch(token_value)
+    {
+
+    /*  -------------------------------------------------------------------- */
+    /*  box <string-1> ... <string-n> -------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case BOX_CODE:
+            INITAOT(&AO3, CONSTANT_OT);
+                 AO3.value = begin_table_array();
+                 AO3.marker = ARRAY_MV;
+                 ln = 0; ln2 = 0;
+                 do
+                 {   get_next_token();
+                     if ((token_type==SEP_TT)&&(token_value==SEMICOLON_SEP))
+                         break;
+                     if (token_type != DQ_TT)
+                         ebf_error("text of box line in double-quotes",
+                             token_text);
+                     {   int i, j;
+                         for (i=0, j=0; token_text[i] != 0; j++)
+                             if (token_text[i] == '@')
+                             {   if (token_text[i+1] == '@')
+                                 {   i = i + 2;
+                                     while (isdigit(token_text[i])) i++;
+                                 }
+                                 else
+                                 {   i++;
+                                     if (token_text[i] != 0) i++;
+                                     if (token_text[i] != 0) i++;
+                                 }
+                             }
+                             else i++;
+                         if (j > ln2) ln2 = j;
+                     }
+                     put_token_back();
+                     array_entry(ln++,parse_expression(CONSTANT_CONTEXT));
+                 } while (TRUE);
+                 finish_array(ln);
+                 if (ln == 0)
+                     error("No lines of text given for 'box' display");
+
+                 INITAO(&AO2);
+                 AO2.value = ln2; set_constant_ot(&AO2);
+                 assembleg_call_2(veneer_routine(Box__Routine_VR),
+                     AO2, AO3, zero_operand);
+                 return;
+
+    /*  -------------------------------------------------------------------- */
+    /*  break -------------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case BREAK_CODE:
+                 if (break_label == -1)
+                 error("'break' can only be used in a loop or 'switch' block");
+                 else
+                     assembleg_jump(break_label);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  continue ----------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case CONTINUE_CODE:
+                 if (continue_label == -1)
+                 error("'continue' can only be used in a loop block");
+                 else
+                     assembleg_jump(continue_label);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  do <codeblock> until (<condition>) --------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case DO_CODE:
+                 assemble_label_no(ln = next_label++);
+                 ln2 = next_label++; ln3 = next_label++;
+                 parse_code_block(ln3, ln2, 0);
+                 statements.enabled = TRUE;
+                 get_next_token();
+                 if ((token_type == STATEMENT_TT)
+                     && (token_value == UNTIL_CODE))
+                 {   assemble_label_no(ln2);
+                     match_open_bracket();
+                     AO = parse_expression(CONDITION_CONTEXT);
+                     match_close_bracket();
+                     code_generate(AO, CONDITION_CONTEXT, ln);
+                 }
+                 else error("'do' without matching 'until'");
+
+                 assemble_label_no(ln3);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  font on/off -------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case FONT_CODE:
+                 misc_keywords.enabled = TRUE;
+                 get_next_token();
+                 misc_keywords.enabled = FALSE;
+                 if ((token_type != MISC_KEYWORD_TT)
+                     || ((token_value != ON_MK)
+                         && (token_value != OFF_MK)))
+                 {   ebf_error("'on' or 'off'", token_text);
+                     panic_mode_error_recovery();
+                     break;
+                 }
+
+                 /* Call glk_set_style(normal or preformatted) */
+                 INITAO(&AO);
+                 AO.value = 0x0086;
+                 set_constant_ot(&AO);
+                 if (token_value == ON_MK)
+                   AO2 = zero_operand;
+                 else 
+                   AO2 = two_operand;
+                 assembleg_call_2(veneer_routine(Glk__Wrap_VR), 
+                   AO, AO2, zero_operand);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  for (<initialisation> : <continue-condition> : <updating>) --------- */
+    /*  -------------------------------------------------------------------- */
+
+        /*  Note that it's legal for any or all of the three sections of a
+            'for' specification to be empty.  This 'for' implementation
+            often wastes 3 bytes with a redundant branch rather than keep
+            expression parse trees for long periods (as previous versions
+            of Inform did, somewhat crudely by simply storing the textual
+            form of a 'for' loop).  It is adequate for now.                  */
+
+        case FOR_CODE:
+                 match_open_bracket();
+                 get_next_token();
+
+                 /*  Initialisation code  */
+
+                 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
+                 {   put_token_back();
+                     if (!((token_type==SEP_TT)&&(token_value==SUPERCLASS_SEP)))
+                     {   sequence_point_follows = TRUE;
+                         statement_debug_location = get_token_location();
+                         code_generate(parse_expression(FORINIT_CONTEXT),
+                             VOID_CONTEXT, -1);
+                     }
+                     get_next_token();
+                     if ((token_type==SEP_TT)&&(token_value == SUPERCLASS_SEP))
+                     {   get_next_token();
+                         if ((token_type==SEP_TT)&&(token_value == CLOSEB_SEP))
+                         {   assemble_label_no(ln = next_label++);
+                             ln2 = next_label++;
+                             parse_code_block(ln2, ln, 0);
+                             sequence_point_follows = FALSE;
+                             if (!execution_never_reaches_here)
+                                 assembleg_jump(ln);
+                             assemble_label_no(ln2);
+                             return;
+                         }
+                         AO.type = OMITTED_OT;
+                         goto ParseUpdate;
+                     }
+                     put_token_back();
+                     if (!match_colon()) break;
+                 }
+
+                 get_next_token();
+                 AO.type = OMITTED_OT;
+                 if (!((token_type==SEP_TT)&&(token_value==COLON_SEP)))
+                 {   put_token_back();
+                     spare_debug_location1 = get_token_location();
+                     AO = parse_expression(CONDITION_CONTEXT);
+                     if (!match_colon()) break;
+                 }
+                 get_next_token();
+
+                 ParseUpdate:
+                 AO2.type = OMITTED_OT; flag = 0;
+                 if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP)))
+                 {   put_token_back();
+                     spare_debug_location2 = get_token_location();
+                     AO2 = parse_expression(VOID_CONTEXT);
+                     match_close_bracket();
+                     flag = test_for_incdec(AO2);
+                 }
+
+                 ln = next_label++;
+                 ln2 = next_label++;
+                 ln3 = next_label++;
+
+                 if ((AO2.type == OMITTED_OT) || (flag != 0))
+                 {
+                     assemble_label_no(ln);
+                     if (flag==0) assemble_label_no(ln2);
+
+                     /*  The "finished yet?" condition  */
+
+                     if (AO.type != OMITTED_OT)
+                     {   sequence_point_follows = TRUE;
+                         statement_debug_location = spare_debug_location1;
+                         code_generate(AO, CONDITION_CONTEXT, ln3);
+                     }
+
+                 }
+                 else
+                 {
+                     /*  This is the jump which could be avoided with the aid
+                         of long-term expression storage  */
+
+                     sequence_point_follows = FALSE;
+                     assembleg_jump(ln2);
+
+                     /*  The "update" part  */
+
+                     assemble_label_no(ln);
+                     sequence_point_follows = TRUE;
+                     statement_debug_location = spare_debug_location2;
+                     code_generate(AO2, VOID_CONTEXT, -1);
+
+                     assemble_label_no(ln2);
+
+                     /*  The "finished yet?" condition  */
+
+                     if (AO.type != OMITTED_OT)
+                     {   sequence_point_follows = TRUE;
+                         statement_debug_location = spare_debug_location1;
+                         code_generate(AO, CONDITION_CONTEXT, ln3);
+                     }
+                 }
+
+                 if (flag != 0)
+                 {
+                     /*  In this optimised case, update code is at the end
+                         of the loop block, so "continue" goes there  */
+
+                     parse_code_block(ln3, ln2, 0);
+                     assemble_label_no(ln2);
+
+                     sequence_point_follows = TRUE;
+                     statement_debug_location = spare_debug_location2;
+                     if (flag > 0)
+                     {   INITAO(&AO3);
+                         AO3.value = flag;
+                         if (AO3.value >= MAX_LOCAL_VARIABLES)
+                           AO3.type = GLOBALVAR_OT;
+                         else
+                           AO3.type = LOCALVAR_OT;
+                         assembleg_3(add_gc, AO3, one_operand, AO3);
+                     }
+                     else
+                     {   INITAO(&AO3);
+                         AO3.value = -flag;
+                         if (AO3.value >= MAX_LOCAL_VARIABLES)
+                           AO3.type = GLOBALVAR_OT;
+                         else
+                           AO3.type = LOCALVAR_OT;
+                         assembleg_3(sub_gc, AO3, one_operand, AO3);
+                     }
+                     assembleg_jump(ln);
+                 }
+                 else
+                 {
+                     /*  In the unoptimised case, update code is at the
+                         start of the loop block, so "continue" goes there  */
+
+                     parse_code_block(ln3, ln, 0);
+                     if (!execution_never_reaches_here)
+                     {   sequence_point_follows = FALSE;
+                         assembleg_jump(ln);
+                     }
+                 }
+
+                 assemble_label_no(ln3);
+                 return;
+
+    /*  -------------------------------------------------------------------- */
+    /*  give <expression> [~]attr [, [~]attr [, ...]] ---------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case GIVE_CODE:
+                 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
+                          QUANTITY_CONTEXT, -1);
+                 if ((AO.type == LOCALVAR_OT) && (AO.value == 0))
+                     onstack = TRUE;
+                 else
+                     onstack = FALSE;
+
+                 do
+                 {   get_next_token();
+                     if ((token_type == SEP_TT) 
+                       && (token_value == SEMICOLON_SEP)) {
+                         if (onstack) {
+                           assembleg_2(copy_gc, stack_pointer, zero_operand);
+                         }
+                         return;
+                     }
+                     if ((token_type == SEP_TT)&&(token_value == ARTNOT_SEP))
+                         ln = 0;
+                     else
+                     {   if ((token_type == SYMBOL_TT)
+                             && (stypes[token_value] != ATTRIBUTE_T))
+                           warning_named("This is not a declared Attribute:",
+                             token_text);
+                         ln = 1;
+                         put_token_back();
+                     }
+                     AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
+                               QUANTITY_CONTEXT, -1);
+                     if (runtime_error_checking_switch && (!veneer_mode))
+                     {   ln2 = (ln ? RT__ChG_VR : RT__ChGt_VR);
+                         if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0)) {
+                           /* already on stack */
+                         }
+                         else {
+                           assembleg_store(stack_pointer, AO2);
+                         }
+                         if (onstack)
+                           assembleg_2(stkpeek_gc, one_operand, stack_pointer);
+                         else
+                           assembleg_store(stack_pointer, AO);
+                         assembleg_3(call_gc, veneer_routine(ln2), two_operand,
+                           zero_operand);
+                     }
+                     else {
+                         if (is_constant_ot(AO2.type) && AO2.marker == 0) {
+                           AO2.value += 8;
+                           set_constant_ot(&AO2);
+                         }
+                         else {
+                           INITAOTV(&AO3, BYTECONSTANT_OT, 8);
+                           assembleg_3(add_gc, AO2, AO3, stack_pointer);
+                           AO2 = stack_pointer;
+                         }
+                         if (onstack) {
+                           if ((AO2.type == LOCALVAR_OT) && (AO2.value == 0))
+                             assembleg_2(stkpeek_gc, one_operand, 
+                               stack_pointer);
+                           else
+                             assembleg_2(stkpeek_gc, zero_operand, 
+                               stack_pointer);
+                         }
+                         if (ln) 
+                           AO3 = one_operand;
+                         else
+                           AO3 = zero_operand;
+                         assembleg_3(astorebit_gc, AO, AO2, AO3);
+                     }
+                 } while(TRUE);
+
+    /*  -------------------------------------------------------------------- */
+    /*  if (<condition>) <codeblock> [else <codeblock>] -------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case IF_CODE:
+                 flag = FALSE;
+                 ln2 = 0;
+
+                 match_open_bracket();
+                 AO = parse_expression(CONDITION_CONTEXT);
+                 match_close_bracket();
+
+                 statements.enabled = TRUE;
+                 get_next_token();
+                 if ((token_type == STATEMENT_TT)&&(token_value == RTRUE_CODE))
+                     ln = -4;
+                 else
+                 if ((token_type == STATEMENT_TT)&&(token_value == RFALSE_CODE))
+                     ln = -3;
+                 else
+                 {   put_token_back();
+                     ln = next_label++;
+                 }
+
+                 code_generate(AO, CONDITION_CONTEXT, ln);
+
+                 if (ln >= 0) parse_code_block(break_label, continue_label, 0);
+                 else
+                 {   get_next_token();
+                     if ((token_type != SEP_TT)
+                         || (token_value != SEMICOLON_SEP))
+                     {   ebf_error("';'", token_text);
+                         put_token_back();
+                     }
+                 }
+
+                 statements.enabled = TRUE;
+                 get_next_token();
+                 if ((token_type == STATEMENT_TT) && (token_value == ELSE_CODE))
+                 {   flag = TRUE;
+                     if (ln >= 0)
+                     {   ln2 = next_label++;
+                         if (!execution_never_reaches_here)
+                         {   sequence_point_follows = FALSE;
+                             assembleg_jump(ln2);
+                         }
+                     }
+                 }
+                 else put_token_back();
+
+                 if (ln >= 0) assemble_label_no(ln);
+
+                 if (flag)
+                 {   parse_code_block(break_label, continue_label, 0);
+                     if (ln >= 0) assemble_label_no(ln2);
+                 }
+
+                 return;
+
+    /*  -------------------------------------------------------------------- */
+    /*  inversion ---------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case INVERSION_CODE:
+                 INITAOTV(&AO2, DEREFERENCE_OT, GLULX_HEADER_SIZE+8);
+                 assembleg_2(copyb_gc, AO2, stack_pointer);
+                 assembleg_1(streamchar_gc, stack_pointer);
+                 AO2.value  = GLULX_HEADER_SIZE+9; 
+                 assembleg_2(copyb_gc, AO2, stack_pointer);
+                 assembleg_1(streamchar_gc, stack_pointer);
+                 AO2.value  = GLULX_HEADER_SIZE+10; 
+                 assembleg_2(copyb_gc, AO2, stack_pointer);
+                 assembleg_1(streamchar_gc, stack_pointer);
+                 AO2.value  = GLULX_HEADER_SIZE+11; 
+                 assembleg_2(copyb_gc, AO2, stack_pointer);
+                 assembleg_1(streamchar_gc, stack_pointer);
+
+                 if (/* DISABLES CODE */ (0)) {
+                     INITAO(&AO);
+                     AO.value = '(';
+                     set_constant_ot(&AO);
+                     assembleg_1(streamchar_gc, AO);
+                     AO.value = 'G';
+                     set_constant_ot(&AO);
+                     assembleg_1(streamchar_gc, AO);
+
+                     AO2.value  = GLULX_HEADER_SIZE+12; 
+                     assembleg_2(copyb_gc, AO2, stack_pointer);
+                     assembleg_1(streamchar_gc, stack_pointer);
+                     AO2.value  = GLULX_HEADER_SIZE+13; 
+                     assembleg_2(copyb_gc, AO2, stack_pointer);
+                     assembleg_1(streamchar_gc, stack_pointer);
+                     AO2.value  = GLULX_HEADER_SIZE+14; 
+                     assembleg_2(copyb_gc, AO2, stack_pointer);
+                     assembleg_1(streamchar_gc, stack_pointer);
+                     AO2.value  = GLULX_HEADER_SIZE+15; 
+                     assembleg_2(copyb_gc, AO2, stack_pointer);
+                     assembleg_1(streamchar_gc, stack_pointer);
+
+                     AO.marker = 0;
+                     AO.value = ')';
+                     set_constant_ot(&AO);
+                     assembleg_1(streamchar_gc, AO);
+                 }
+
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  jump <label> ------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case JUMP_CODE:
+                 assembleg_jump(parse_label());
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  move <expression> to <expression> ---------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case MOVE_CODE:
+                 misc_keywords.enabled = TRUE;
+                 AO = parse_expression(QUANTITY_CONTEXT);
+
+                 get_next_token();
+                 misc_keywords.enabled = FALSE;
+                 if ((token_type != MISC_KEYWORD_TT)
+                     || (token_value != TO_MK))
+                 {   ebf_error("'to'", token_text);
+                     panic_mode_error_recovery();
+                     return;
+                 }
+
+                 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
+                     QUANTITY_CONTEXT, -1);
+                 AO = code_generate(AO, QUANTITY_CONTEXT, -1);
+                 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
+                     assembleg_call_2(veneer_routine(RT__ChT_VR), AO, AO2,
+                         zero_operand);
+                 else
+                     assembleg_call_2(veneer_routine(OB__Move_VR), AO, AO2,
+                         zero_operand);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  new_line ----------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case NEW_LINE_CODE:  
+              INITAOTV(&AO, BYTECONSTANT_OT, 0x0A);
+              assembleg_1(streamchar_gc, AO); 
+              break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  objectloop (<initialisation>) <codeblock> -------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case OBJECTLOOP_CODE:
+
+                 match_open_bracket();
+                 get_next_token();
+                 if (token_type == LOCAL_VARIABLE_TT) {
+                     INITAOTV(&AO, LOCALVAR_OT, token_value);
+                 }
+                 else if ((token_type == SYMBOL_TT) &&
+                   (stypes[token_value] == GLOBAL_VARIABLE_T)) {
+                     INITAOTV(&AO, GLOBALVAR_OT, svals[token_value]);
+                 }
+                 else {
+                     ebf_error("'objectloop' variable", token_text);
+                     panic_mode_error_recovery(); 
+                     break;
+                 }
+                 misc_keywords.enabled = TRUE;
+                 get_next_token(); flag = TRUE;
+                 misc_keywords.enabled = FALSE;
+                 if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
+                     flag = FALSE;
+
+                 ln = 0;
+                 if ((token_type == MISC_KEYWORD_TT)
+                     && (token_value == NEAR_MK)) ln = 1;
+                 if ((token_type == MISC_KEYWORD_TT)
+                     && (token_value == FROM_MK)) ln = 2;
+                 if ((token_type == CND_TT) && (token_value == IN_COND))
+                 {   get_next_token();
+                     get_next_token();
+                     if ((token_type == SEP_TT) && (token_value == CLOSEB_SEP))
+                         ln = 3;
+                     put_token_back();
+                     put_token_back();
+                 }
+
+                 if (ln != 0) {
+                   /*  Old style (Inform 5) objectloops: note that we
+                       implement objectloop (a in b) in the old way since
+                       this runs through objects in a different order from
+                       the new way, and there may be existing Inform code
+                       relying on this.                                    */
+                     assembly_operand AO4, AO5;
+                     INITAO(&AO5);
+
+                     sequence_point_follows = TRUE;
+                     AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
+                         QUANTITY_CONTEXT, -1);
+                     match_close_bracket();
+                     if (ln == 1) {
+                         if (runtime_error_checking_switch)
+                             AO2 = check_nonzero_at_runtime(AO2, -1,
+                                 OBJECTLOOP_RTE);
+                         INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_PARENT());
+                         assembleg_3(aload_gc, AO2, AO4, stack_pointer);
+                         INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHILD());
+                         assembleg_3(aload_gc, stack_pointer, AO4, stack_pointer);
+                         AO2 = stack_pointer;
+                     }
+                     else if (ln == 3) {
+                         if (runtime_error_checking_switch) {
+                             AO5 = AO2;
+                             AO2 = check_nonzero_at_runtime(AO2, -1,
+                                 CHILD_RTE);
+                         }
+                         INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHILD());
+                         assembleg_3(aload_gc, AO2, AO4, stack_pointer);
+                         AO2 = stack_pointer;
+                     }
+                     else {
+                         /* do nothing */
+                     }
+                     assembleg_store(AO, AO2);
+                     assembleg_1_branch(jz_gc, AO, ln2 = next_label++);
+                     assemble_label_no(ln4 = next_label++);
+                     parse_code_block(ln2, ln3 = next_label++, 0);
+                     sequence_point_follows = FALSE;
+                     assemble_label_no(ln3);
+                     if (runtime_error_checking_switch) {
+                         AO2 = check_nonzero_at_runtime(AO, ln2,
+                              OBJECTLOOP2_RTE);
+                         if ((ln == 3)
+                             && ((AO5.type != LOCALVAR_OT)||(AO5.value != 0))
+                             && ((AO5.type != LOCALVAR_OT)||(AO5.value != AO.value)))
+                         {   assembly_operand en_ao;
+                             INITAO(&en_ao);
+                             en_ao.value = OBJECTLOOP_BROKEN_RTE;
+                             set_constant_ot(&en_ao);
+                             INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_PARENT());
+                             assembleg_3(aload_gc, AO, AO4, stack_pointer);
+                             assembleg_2_branch(jeq_gc, stack_pointer, AO5, 
+                                 next_label);
+                             assembleg_call_2(veneer_routine(RT__Err_VR),
+                                 en_ao, AO, zero_operand);
+                             assembleg_jump(ln2);
+                             assemble_label_no(next_label++);
+                         }
+                     }
+                     else {
+                         AO2 = AO;
+                     }
+                     INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_SIBLING());
+                     assembleg_3(aload_gc, AO2, AO4, AO);
+                     assembleg_1_branch(jnz_gc, AO, ln4);
+                     assemble_label_no(ln2);
+                     return;
+                 }
+
+                 sequence_point_follows = TRUE;
+                 ln = symbol_index("Class", -1);
+                 INITAOT(&AO2, CONSTANT_OT);
+                 AO2.value = svals[ln];
+                 AO2.marker = OBJECT_MV;
+                 assembleg_store(AO, AO2);
+
+                 assemble_label_no(ln = next_label++);
+                 ln2 = next_label++;
+                 ln3 = next_label++;
+                 if (flag)
+                 {   put_token_back();
+                     put_token_back();
+                     sequence_point_follows = TRUE;
+                     code_generate(parse_expression(CONDITION_CONTEXT),
+                         CONDITION_CONTEXT, ln3);
+                     match_close_bracket();
+                 }
+                 parse_code_block(ln2, ln3, 0);
+
+                 sequence_point_follows = FALSE;
+                 assemble_label_no(ln3);
+                 INITAOTV(&AO4, BYTECONSTANT_OT, GOBJFIELD_CHAIN());
+                 assembleg_3(aload_gc, AO, AO4, AO);
+                 assembleg_1_branch(jnz_gc, AO, ln);
+                 assemble_label_no(ln2);
+                 return;
+
+    /*  -------------------------------------------------------------------- */
+    /*  (see routine above) ------------------------------------------------ */
+    /*  -------------------------------------------------------------------- */
+
+        case PRINT_CODE:
+            get_next_token();
+            parse_print_g(FALSE); return;
+        case PRINT_RET_CODE:
+            get_next_token();
+            parse_print_g(TRUE); return;
+
+    /*  -------------------------------------------------------------------- */
+    /*  quit --------------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case QUIT_CODE:
+                 assembleg_0(quit_gc); break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  remove <expression> ------------------------------------------------ */
+    /*  -------------------------------------------------------------------- */
+
+        case REMOVE_CODE:
+                 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
+                     QUANTITY_CONTEXT, -1);
+                 if ((runtime_error_checking_switch) && (veneer_mode == FALSE))
+                     assembleg_call_1(veneer_routine(RT__ChR_VR), AO,
+                         zero_operand);
+                 else
+                     assembleg_call_1(veneer_routine(OB__Remove_VR), AO,
+                         zero_operand);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  return [<expression>] ---------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case RETURN_CODE:
+          get_next_token();
+          if ((token_type == SEP_TT) && (token_value == SEMICOLON_SEP)) {
+            assembleg_1(return_gc, one_operand); 
+            return; 
+          }
+          put_token_back();
+          AO = code_generate(parse_expression(RETURN_Q_CONTEXT),
+            QUANTITY_CONTEXT, -1);
+          assembleg_1(return_gc, AO);
+          break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  rfalse ------------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case RFALSE_CODE:   
+          assembleg_1(return_gc, zero_operand); 
+          break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  rtrue -------------------------------------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case RTRUE_CODE:   
+          assembleg_1(return_gc, one_operand); 
+          break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  spaces <expression> ------------------------------------------------ */
+    /*  -------------------------------------------------------------------- */
+
+        case SPACES_CODE:
+                 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
+                     QUANTITY_CONTEXT, -1);
+
+                 assembleg_store(temp_var1, AO);
+
+                 INITAO(&AO);
+                 AO.value = 32; set_constant_ot(&AO);
+
+                 assembleg_2_branch(jlt_gc, temp_var1, one_operand, 
+                     ln = next_label++);
+                 assemble_label_no(ln2 = next_label++);
+                 assembleg_1(streamchar_gc, AO);
+                 assembleg_dec(temp_var1);
+                 assembleg_1_branch(jnz_gc, temp_var1, ln2);
+                 assemble_label_no(ln);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  string <expression> <literal-string> ------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case STRING_CODE:
+                 AO2 = code_generate(parse_expression(QUANTITY_CONTEXT),
+                     QUANTITY_CONTEXT, -1);
+                 get_next_token();
+                 if (token_type == DQ_TT)
+                 {   INITAOT(&AO4, CONSTANT_OT);
+                     AO4.value = compile_string(token_text, TRUE, TRUE);
+                     AO4.marker = STRING_MV;
+                 }
+                 else
+                 {   put_token_back();
+                     AO4 = parse_expression(CONSTANT_CONTEXT);
+                 }
+                 assembleg_call_2(veneer_routine(Dynam__String_VR),
+                   AO2, AO4, zero_operand);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  style roman/reverse/bold/underline/fixed --------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case STYLE_CODE:
+                 misc_keywords.enabled = TRUE;
+                 get_next_token();
+                 misc_keywords.enabled = FALSE;
+                 if ((token_type != MISC_KEYWORD_TT)
+                     || ((token_value != ROMAN_MK)
+                         && (token_value != REVERSE_MK)
+                         && (token_value != BOLD_MK)
+                         && (token_value != UNDERLINE_MK)
+                         && (token_value != FIXED_MK)))
+                 {   ebf_error(
+"'roman', 'bold', 'underline', 'reverse' or 'fixed'",
+                         token_text);
+                     panic_mode_error_recovery();
+                     break;
+                 }
+
+                 /* Call glk_set_style() */
+
+                 INITAO(&AO);
+                 AO.value = 0x0086;
+                 set_constant_ot(&AO);
+                 switch(token_value)
+                 {   case ROMAN_MK:
+                     default: 
+                         AO2 = zero_operand; /* normal */
+                         break;
+                     case REVERSE_MK: 
+                         INITAO(&AO2);
+                         AO2.value = 5; /* alert */
+                         set_constant_ot(&AO2);
+                         break;
+                     case BOLD_MK: 
+                         INITAO(&AO2);
+                         AO2.value = 4; /* subheader */
+                         set_constant_ot(&AO2);
+                         break;
+                     case UNDERLINE_MK: 
+                         AO2 = one_operand; /* emphasized */
+                         break;
+                     case FIXED_MK: 
+                         AO2 = two_operand; /* preformatted */
+                         break;
+                 }
+                 assembleg_call_2(veneer_routine(Glk__Wrap_VR), 
+                   AO, AO2, zero_operand);
+                 break;
+
+    /*  -------------------------------------------------------------------- */
+    /*  switch (<expression>) <codeblock> ---------------------------------- */
+    /*  -------------------------------------------------------------------- */
+
+        case SWITCH_CODE:
+                 match_open_bracket();
+                 AO = code_generate(parse_expression(QUANTITY_CONTEXT),
+                     QUANTITY_CONTEXT, -1);
+                 match_close_bracket();
+
+                 assembleg_store(temp_var1, AO); 
+
+                 parse_code_block(ln = next_label++, continue_label, 1);
+                 assemble_label_no(ln);
+                 return;
+
+    /*  -------------------------------------------------------------------- */
+    /*  while (<condition>) <codeblock> ------------------------------------ */
+    /*  -------------------------------------------------------------------- */
+
+        case WHILE_CODE:
+                 assemble_label_no(ln = next_label++);
+                 match_open_bracket();
+
+                 code_generate(parse_expression(CONDITION_CONTEXT),
+                     CONDITION_CONTEXT, ln2 = next_label++);
+                 match_close_bracket();
+
+                 parse_code_block(ln2, ln, 0);
+                 sequence_point_follows = FALSE;
+                 assembleg_jump(ln);
+                 assemble_label_no(ln2);
+                 return;
+
+    /*  -------------------------------------------------------------------- */
+
+        case SDEFAULT_CODE:
+                 error("'default' without matching 'switch'"); break;
+        case ELSE_CODE:
+                 error("'else' without matching 'if'"); break;
+        case UNTIL_CODE:
+                 error("'until' without matching 'do'");
+                 panic_mode_error_recovery(); return;
+
+    /*  -------------------------------------------------------------------- */
+
+    /* And a useful default, which will never be triggered in a complete
+       Inform compiler, but which is important in development. */
+
+        default:
+          error("*** Statement code gen: Can't generate yet ***\n");
+          panic_mode_error_recovery(); return;
+    }
+
+    StatementTerminator:
+
+    get_next_token();
+    if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
+    {   ebf_error("';'", token_text);
+        put_token_back();
+    }
+}
+
+extern void parse_statement(int break_label, int continue_label)
+{
+  if (!glulx_mode)
+    parse_statement_z(break_label, continue_label);
+  else
+    parse_statement_g(break_label, continue_label);
+}
+
+/* ========================================================================= */
+/*   Data structure management routines                                      */
+/* ------------------------------------------------------------------------- */
+
+extern void init_states_vars(void)
+{
+}
+
+extern void states_begin_pass(void)
+{
+}
+
+extern void states_allocate_arrays(void)
+{
+}
+
+extern void states_free_arrays(void)
+{
+}
+
+/* ========================================================================= */