    // It is here for incorporating as the basis of a compile() function to do something useful with an AST.
    // For example this generated the code that was manually converted into algol60-indent.h

//\\ B<eof> = 0;
//\\#
//\\ B<ch> = 1;
//\\#
//\\ B<nl> = 2;
//\\#
//\\ P<PUSHDECS> =
   case P_PUSHDECS:
#ifdef IN_PARSER

  PushDecl(42);
  // Any time the global variables use to populate the VarDecl[] array are changed, this code should mirror them.
  // Find them with: grep "^  [A-Z][A-Z]" imp80-init.g
  PushDecl(Object);
  PushDecl(Basetype);
  PushDecl(Signedness);
  PushDecl(Precision);
  PushDecl(Proc);
  PushDecl(NameInfo);
  PushDecl(Spec);
  PushDecl(IsArray);
  PushDecl(Area);
  PushDecl(Linkage);
  PushDecl(ParentVarIDX);
  PushDecl(ParentTypeIDX);

  compile(P(1), depth+1); // Aha! Bug fixed.  I had forgotten to reinit after saving the previous state!
  
  return -1;
  /* Should any of these be stacked too?  Specifically ParentVarIDX and ParentTypeIDX, especially if
     compiling declarations with a recordformat or procedure FPP list.
   */
#ifdef NEVER
  int ParentVarIDX = -1, ParentTypeIDX = -1;        // VarDeclIDX for procedure to which parameters are being attached.
  int DTag = -1, VTag = -1, ATag = -1;              // Tag for declarations, VTag for use. ATag for an alias.   GLOBALS.
  char *SDTag = NULL, /*  *SVTag = NULL, */   *SATag = NULL; // STag, VTag and ATag converted to a char *.  
  wchar_t *wSDTag = NULL, *wSVTag = NULL, *wSATag = NULL; // STag, VTag and ATag converted to a wchar_t *.  
#endif

#endif
     {                              //\\    <INITDECS>;
     t[1] = compile(P(1), depth+1 /* P_INITDECS */);
     return t[0] = P_mktuple(P_PUSHDECS, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<POPDECS> =
   case P_POPDECS:
#ifdef IN_PARSER

  ParentTypeIDX = PopDecl();
  ParentVarIDX = PopDecl();
  Linkage = PopDecl();
  Area = PopDecl();
  IsArray = PopDecl();
  Spec = PopDecl();
  NameInfo = PopDecl();
  Proc = PopDecl();
  Precision = PopDecl();
  Signedness = PopDecl();
  Basetype = PopDecl();
  Object = PopDecl();
  {int check = PopDecl(); if (check != 42) fprintf(stderr, "* Error: Unbalanced Decl stack\n"); }
  return -1;

#endif
     {                              //\\    ;

     return t[0] = P_mktuple(P_POPDECS, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<INITDECS> =
   case P_INITDECS:
#ifdef IN_PARSER

  ParentTypeIDX = -1;
  ParentVarIDX = -1;
  Object     = UNINIT_OBJECT;
  Basetype   = UNINIT_BASETYPE;
  Signedness = UNINIT_SIGNEDNESS;
  Precision  = UNINIT_PRECISION;
  Proc       = UNINIT_PROC;
  NameInfo   = NO_NAME;           // UNINIT_AN_N
  //IsFormat   = NO_FORMAT;       // UNINIT_ISFORMAT
  Spec       = NO_SPEC;           // UNINIT_SPEC
  IsArray    = SCALAR;            // UNINIT_ISARRAY
  // TO DO: Do I need an "IS_INITIALISED" tag as well?  So far, only reason for
  //        having one would be to suppress the keyword "extern" in declarations
  //        such as "%externalinteger fred = 1" which would otherwise be declared
  //        in C as "extern int fred = 1;" rather than "int fred = 1;" (at least
  //        if declared at the top level.  Placing that declaration within
  //        a nested routine is a separate issue and may be a problem. Exbedding
  //        that declaration to the top level may not be possible due to scoping rules.)
  // NOTE: A data declaration (e.g. %integer I) at the top level of a file of externals
  // or before the begin/endofprogram block is an error in Imp77 and I'm guessing in Imp80.
  Area       = (ctrl_depth() < 1 ? EXTDATA : STACK);  // UNINIT_AREA
  // However a %routine at the same level (as opposed to an %externalroutine) appears to be accepted.
  Linkage    = UNINIT_LINKAGE;    // Ditto? Check with ERCC compiler. Or ask Bob.
  return -1;

#endif
     {                              //\\    ;

     return t[0] = P_mktuple(P_INITDECS, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<nls> =
   case P_nls:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <nl> <nls>,
       t[1] = wlit(P(1) /*, L"nl" */);
       t[2] = compile(P(2), depth+1 /* P_nls */);
       return t[0] = P_mktuple(P_nls, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_nls, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<READLINEP> =
   case P_READLINEP:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <nls>,
       t[1] = compile(P(1), depth+1 /* P_nls */);
       return t[0] = P_mktuple(P_READLINEP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_READLINEP, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<S> =
   case P_S:
#ifdef IN_PARSER

  if (alt == 0) codegen("\n"); 

#endif
     if (alt == 0)               {  //\\    <nl>,
       t[1] = wlit(P(1) /*, L"nl" */);
       return t[0] = P_mktuple(P_S, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ';';
       t[1] = wlit(P(1) /*, L';' */);
       return t[0] = P_mktuple(P_S, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<DOWN> =
   case P_DOWN:
#ifdef IN_PARSER

  // unconditionally set in a %begin.  Could just put the 'push_scope_level()' in
  // the code for <begin_block> but for now I'll follow the structure of the
  // ERCC compilers and grammar.
  push_scope_level();

  // Note that it turns out we need an initial 'push_scope_level();' before we can
  // do *anything*, even prims/perms or external data.  That has now been added to
  // the 'init' rule called in P<SS>.  This is because C, unlike say Modula2 (or C++)
  // has no concept of module initialisation.

#endif
     {                              //\\    ;

     return t[0] = P_mktuple(P_DOWN, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<UP> =
   case P_UP:
#ifdef IN_PARSER

  // called on %end and %endofprogram
  pop_scope_level();

#endif
     {                              //\\    ;

     return t[0] = P_mktuple(P_UP, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<SS> =
   case P_SS:
#ifdef IN_PARSER

  compile(P(1), depth+1); // perform initialisation
  compile(P(2), depth+1); // Read in the entire source and perform line reconstruction.
  int SS = compile(P(3), depth+1); // Get the tree representing the entire program
  compile(P(4), depth+1); // clean up at end.
  return SS; // Pass back parse tree for generate_c() to walk and output the C code.

#endif
     {                              //\\    <init> <Imp77_stropping> <STATEMENTS> <terminate>;
     t[1] = -1; /* semantic procedure init */;
     t[2] = -1; /* semantic procedure Imp77_stropping */;
     t[3] = compile(P(3), depth+1 /* P_STATEMENTS */);
     t[4] = -1; /* semantic procedure terminate */;
     return t[0] = P_mktuple(P_SS, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<BINOP> =
   case P_BINOP:
#ifdef IN_PARSER

                     
     // Phrase is used to convert an OP into a more useful AST phrase.
     // (the default for char syms is separate P() items for each char, which is unweildy)

     // It would be cleaner to return the OP_xxx enum rather than the string.
     // I should do so later.  (The string is decoded in PushBinOp())

     // TO DO: every P_mktuple(AST_*) operation must synthesize the type of its
     // result from the types of the operands.

     if (alt == 0)               {  //\\    '+',
       t[1] = wstrtopool(L"+");
       t[2] = OP_ADD;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 1)        {  //\\    '-',
       t[1] = wstrtopool(L"-");
       t[2] = OP_SUB;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 2)        {  //\\    '&',
       t[1] = wstrtopool(L"&");
       t[2] = OP_AND;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 3)        {  //\\    '*' '*' '*' '*',
       t[1] = wstrtopool(L"****");
       t[2] = OP_IEXP;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);
       
     } else if (alt == 4)        {  //\\    '*' '*',
       t[1] = wstrtopool(L"**");
       t[2] = OP_REXP;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 5)        {  //\\    '*',
       t[1] = wstrtopool(L"*");
       t[2] = OP_MULT;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 6)        {  //\\    '!' '!',
       t[1] = wstrtopool(L"!!");
       t[2] = OP_EOR;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 7)        {  //\\    '!',
       t[1] = wstrtopool(L"!");
       t[2] = OP_OR;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 8)        {  //\\    '/' '/',
       t[1] = wstrtopool(L"//");
       t[2] = OP_INTDIV;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 9)        {  //\\    '/',
       // %begin
       //   %real r
       //   r = 3/5     ;! beware: a naive conversion to C will cause a result of 1.0 (because both operands of '/' will be ints)
       //   print(r,5)  ;! 0.6
       // %endofprogram
       t[1] = wstrtopool(L"/");
       t[2] = OP_REALDIV;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 10)        {  //\\    '>' '>',
       t[1] = wstrtopool(L">>");
       t[2] = OP_RSHIFT;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 11)        {  //\\    '<' '<',
       t[1] = wstrtopool(L"<<");
       t[2] = OP_LSHIFT;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 12)        {  //\\    '.',
       t[1] = wstrtopool(L".");
       t[2] = OP_CONCAT;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 13)        {  //\\    '\' '\',
       t[1] = wstrtopool(L"\\\\");
       t[2] = OP_IEXP;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 14)        {  //\\    '\',
       t[1] = wstrtopool(L"\\");
       t[2] = OP_REXP;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else if (alt == 15)        {  //\\    '^' '^',
       t[1] = wstrtopool(L"^^");                                    // NOTE: soap80 does not recognise ^^, only ****
       t[2] = OP_IEXP;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     } else                      {  //\\    '^';
       t[1] = wstrtopool(L"^");
       t[2] = OP_REXP;
       return t[0] = P_mktuple(AST_BINOP, alt, 2/*phrases*/, t);

     }
     return -1;

#endif
     if (alt == 0)               {  //\\    '+',
       t[1] = wlit(P(1) /*, L'+' */);
       return t[0] = P_mktuple(P_BINOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    '-',
       t[1] = wlit(P(1) /*, L'-' */);
       return t[0] = P_mktuple(P_BINOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 2)        {  //\\    '&',
       t[1] = wlit(P(1) /*, L'&' */);
       return t[0] = P_mktuple(P_BINOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 3)        {  //\\    '*' '*' '*' '*',
       t[1] = wlit(P(1) /*, L'*' */);
       t[2] = wlit(P(2) /*, L'*' */);
       t[3] = wlit(P(3) /*, L'*' */);
       t[4] = wlit(P(4) /*, L'*' */);
       return t[0] = P_mktuple(P_BINOP, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 4)        {  //\\    '*' '*',
       t[1] = wlit(P(1) /*, L'*' */);
       t[2] = wlit(P(2) /*, L'*' */);
       return t[0] = P_mktuple(P_BINOP, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 5)        {  //\\    '*',
       t[1] = wlit(P(1) /*, L'*' */);
       return t[0] = P_mktuple(P_BINOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 6)        {  //\\    '!' '!',
       t[1] = wlit(P(1) /*, L'!' */);
       t[2] = wlit(P(2) /*, L'!' */);
       return t[0] = P_mktuple(P_BINOP, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 7)        {  //\\    '!',
       t[1] = wlit(P(1) /*, L'!' */);
       return t[0] = P_mktuple(P_BINOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 8)        {  //\\    '/' '/',
       t[1] = wlit(P(1) /*, L'/' */);
       t[2] = wlit(P(2) /*, L'/' */);
       return t[0] = P_mktuple(P_BINOP, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 9)        {  //\\    '/',
       t[1] = wlit(P(1) /*, L'/' */);
       return t[0] = P_mktuple(P_BINOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 10)        {  //\\    '>' '>',
       t[1] = wlit(P(1) /*, L'>' */);
       t[2] = wlit(P(2) /*, L'>' */);
       return t[0] = P_mktuple(P_BINOP, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 11)        {  //\\    '<' '<',
       t[1] = wlit(P(1) /*, L'<' */);
       t[2] = wlit(P(2) /*, L'<' */);
       return t[0] = P_mktuple(P_BINOP, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 12)        {  //\\    '.',
       t[1] = wlit(P(1) /*, L'.' */);
       return t[0] = P_mktuple(P_BINOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 13)        {  //\\    '\' '\',
       t[1] = wlit(P(1) /*, L'\\' */);
       t[2] = wlit(P(2) /*, L'\\' */);
       return t[0] = P_mktuple(P_BINOP, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 14)        {  //\\    '\',
       t[1] = wlit(P(1) /*, L'\\' */);
       return t[0] = P_mktuple(P_BINOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 15)        {  //\\    '^' '^',
       t[1] = wlit(P(1) /*, L'^' */);
       t[2] = wlit(P(2) /*, L'^' */);
       return t[0] = P_mktuple(P_BINOP, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    '^';
       t[1] = wlit(P(1) /*, L'^' */);
       return t[0] = P_mktuple(P_BINOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<OP> =
   case P_OP:
#ifdef IN_PARSER

    PushBinOp(compile(P(1), depth+1)); // TORP
    return -1;

#endif
     {                              //\\    <BINOP>;
     t[1] = compile(P(1), depth+1 /* P_BINOP */);
     return t[0] = P_mktuple(P_OP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<MONOP> =
   case P_MONOP:
#ifdef IN_PARSER

     if (alt == 4) return -1;
  
     if (alt == 0)               {  //\\    '+',
       // return -1; // simpler, but generated C would not retain the unary +
       t[1] = wstrtopool(L"+");
       t[2] = OP_POS;
     } else if (alt == 1)        {  //\\    '-',
       t[1] = wstrtopool(L"-");
       t[2] = OP_NEG;
     } else if (alt == 2)        {  //\\    '\\',
       t[1] = wstrtopool(L"\\");
       t[2] = OP_NOT;
     } else if (alt == 3)        {  //\\    '~',
       t[1] = wstrtopool(L"~");
       t[2] = OP_NOT;
     }
     return t[0] = P_mktuple(AST_MONOP, alt, 2/*phrases*/, t);

#endif
     if (alt == 0)               {  //\\    '+',
       t[1] = wlit(P(1) /*, L'+' */);
       return t[0] = P_mktuple(P_MONOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    '-',
       t[1] = wlit(P(1) /*, L'-' */);
       return t[0] = P_mktuple(P_MONOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 2)        {  //\\    '\',
       t[1] = wlit(P(1) /*, L'\\' */);
       return t[0] = P_mktuple(P_MONOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 3)        {  //\\    '~',
       t[1] = wlit(P(1) /*, L'~' */);
       return t[0] = P_mktuple(P_MONOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_MONOP, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<UOP> =
   case P_UOP:
#ifdef IN_PARSER

  {
     int Expr = compile(P(1), depth+1);
     if (Expr != -1) PushMonOp(Expr); // TORP
     return -1;
  }

#endif
     {                              //\\    <MONOP>;
     t[1] = compile(P(1), depth+1 /* P_MONOP */);
     return t[0] = P_mktuple(P_UOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<ASSOP> =
   case P_ASSOP:
#ifdef IN_PARSER

     if (alt == 0)               {
       t[1] = wstrtopool(L"==");
       t[2] = OP_ASSIGN_ADDR;
     } else if (alt == 1)        {
       t[1] = wstrtopool(L"=");
       t[2] = OP_ASSIGN_VALUE;
     } else if (alt == 2)        {
       t[1] = wstrtopool(L"<-");
       t[2] = OP_JAM_TRANSFER;
     } else if (alt == 3)        {
       t[1] = wstrtopool(L"->");
       t[2] = OP_UNCOND_STR_RESOL;
     }
     return t[0] = P_mktuple(AST_ASSOP, alt, 2/*phrases*/, t);

#endif
     if (alt == 0)               {  //\\    '=' '=',
       t[1] = wlit(P(1) /*, L'=' */);
       t[2] = wlit(P(2) /*, L'=' */);
       return t[0] = P_mktuple(P_ASSOP, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    '=',
       t[1] = wlit(P(1) /*, L'=' */);
       return t[0] = P_mktuple(P_ASSOP, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 2)        {  //\\    '<' '-',
       t[1] = wlit(P(1) /*, L'<' */);
       t[2] = wlit(P(2) /*, L'-' */);
       return t[0] = P_mktuple(P_ASSOP, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    '-' '>';
       t[1] = wlit(P(1) /*, L'-' */);
       t[2] = wlit(P(2) /*, L'>' */);
       return t[0] = P_mktuple(P_ASSOP, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<COMP1> =
   case P_COMP1:
#ifdef IN_PARSER

  {
    // Some work required to distinguish address comparisons and conditional resolution from simple arithmetic comparisons or string comparisons
    const char *C_Comp[] = { "== &", ">=", ">", "!= &", "!= &", "!=", "<=", "<", "-> /*STRRES*/", "==", "!=", "!=" };
    // (The '&'s above are temporary)
    codegen(" %s ", C_Comp[alt]);
    return -1; // TO DO: return one of several possible AST_something tuples
  }

#endif
     if (alt == 0)               {  //\\    '=' '=',
       t[1] = wlit(P(1) /*, L'=' */);
       t[2] = wlit(P(2) /*, L'=' */);
       return t[0] = P_mktuple(P_COMP1, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    '>' '=',
       t[1] = wlit(P(1) /*, L'>' */);
       t[2] = wlit(P(2) /*, L'=' */);
       return t[0] = P_mktuple(P_COMP1, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 2)        {  //\\    '>',
       t[1] = wlit(P(1) /*, L'>' */);
       return t[0] = P_mktuple(P_COMP1, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 3)        {  //\\    '#' '#',
       t[1] = wlit(P(1) /*, L'#' */);
       t[2] = wlit(P(2) /*, L'#' */);
       return t[0] = P_mktuple(P_COMP1, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 4)        {  //\\    '\' '=' '=',
       t[1] = wlit(P(1) /*, L'\\' */);
       t[2] = wlit(P(2) /*, L'=' */);
       t[3] = wlit(P(3) /*, L'=' */);
       return t[0] = P_mktuple(P_COMP1, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 5)        {  //\\    '<' '>',
       t[1] = wlit(P(1) /*, L'<' */);
       t[2] = wlit(P(2) /*, L'>' */);
       return t[0] = P_mktuple(P_COMP1, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 6)        {  //\\    '<' '=',
       t[1] = wlit(P(1) /*, L'<' */);
       t[2] = wlit(P(2) /*, L'=' */);
       return t[0] = P_mktuple(P_COMP1, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 7)        {  //\\    '<',
       t[1] = wlit(P(1) /*, L'<' */);
       return t[0] = P_mktuple(P_COMP1, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 8)        {  //\\    '-' '>',
       t[1] = wlit(P(1) /*, L'-' */);
       t[2] = wlit(P(2) /*, L'>' */);
       return t[0] = P_mktuple(P_COMP1, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 9)        {  //\\    '=',
       t[1] = wlit(P(1) /*, L'=' */);
       return t[0] = P_mktuple(P_COMP1, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 10)        {  //\\    '#',
       t[1] = wlit(P(1) /*, L'#' */);
       return t[0] = P_mktuple(P_COMP1, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    '\' '=';
       t[1] = wlit(P(1) /*, L'\\' */);
       t[2] = wlit(P(2) /*, L'=' */);
       return t[0] = P_mktuple(P_COMP1, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<COMP2> =
   case P_COMP2:
#ifdef IN_PARSER

#endif
     {                              //\\    <COMP1>;
     t[1] = compile(P(1), depth+1 /* P_COMP1 */);
     return t[0] = P_mktuple(P_COMP2, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<VARNAME> =
   case P_VARNAME:
#ifdef IN_PARSER

  {
  // We want to return an AST record with the VarDecl contents
  // (which includes the TypeDecl information)

  int VTagAtom = SubPhraseIdx(Ph, 2);
  wSVTag = Atom2WStr(VTagAtom);
  VTag=wstrtopool(wSVTag);

  // Use the scope tools to find it:
  // (Question: are there any separate namespaces in Imp as there are in C?)
  int VarIDX = lookup_by_strpoolidx("decl", VTag); // This (currently) just returns a raw index into the VarDecl[] array. Would be nice to strongly type it.
  if (VarIDX == -1) {
    fprintf(stderr, "* NAME NOT SET(#3): %ls\n", wSVTag); //exit(1);
    return -1;
  }
  t[1] = VarIDX;
  int rvalue = P_mktuple(AST_RVALUE, 0/*alt no*/, 1/*phrases*/, t);
  P_TYPEINFO(rvalue) = VarDecl[VarIDX].type;
  return t[0] = rvalue;
  }

#endif
     {                              //\\    <!CONST> «[A-Z][A-Z0-9]*»;
     t[1] = -1; /* ignore negative guard */;
     t[2] = wlit(P(2));
     return t[0] = P_mktuple(P_VARNAME, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<TAG> =
   case P_TAG:
#ifdef IN_PARSER

  {
  // check to see which is in the most accessible format:
  //Diagnose("", SubPhraseIdx(Ph, 2),0, debug_declarations);
  VTag = SubPhraseIdx(Ph, 2);
  //Diagnose("", VTag,0, debug_declarations);
  
  //if (SVTag != NULL) free(SVTag); SVTag=Atom2Str(VTag); // *short term* cache. Diags
  if (wSVTag != NULL) free(wSVTag); wSVTag=Atom2WStr(VTag);
  
  t[1] = VTag;
  return t[0] = P_mktuple(AST_TOKEN, 0/*alt no*/, 1/*phrases*/, t);
  }

#endif
     {                              //\\    <!CONST> «[A-Z][A-Z0-9]*»;
     t[1] = -1; /* ignore negative guard */;
     t[2] = wlit(P(2));
     return t[0] = P_mktuple(P_TAG, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<BigCharConst> =
   case P_BigCharConst:
#ifdef IN_PARSER

#endif
     {                              //\\    «'([^']|'')*'»;
     t[1] = wlit(P(1));
     return t[0] = P_mktuple(P_BigCharConst, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<CharConst> =
   case P_CharConst:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    «''''»,
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_CharConst, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    «''»,
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_CharConst, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    «'.'»;
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_CharConst, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<OptExponent> =
   case P_OptExponent:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    '@' <N>,
       t[1] = wlit(P(1) /*, L'@' */);
       t[2] = compile(P(2), depth+1 /* P_N */);
       return t[0] = P_mktuple(P_OptExponent, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    '@' '-' <N>,
       t[1] = wlit(P(1) /*, L'@' */);
       t[2] = wlit(P(2) /*, L'-' */);
       t[3] = compile(P(3), depth+1 /* P_N */);
       return t[0] = P_mktuple(P_OptExponent, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_OptExponent, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<OptDecimal> =
   case P_OptDecimal:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    '.' <N>,
       t[1] = wlit(P(1) /*, L'.' */);
       t[2] = compile(P(2), depth+1 /* P_N */);
       return t[0] = P_mktuple(P_OptDecimal, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    '.',
       t[1] = wlit(P(1) /*, L'.' */);
       return t[0] = P_mktuple(P_OptDecimal, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_OptDecimal, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Based> =
   case P_Based:
#ifdef IN_PARSER

#endif
     {                              //\\    «[0-9A-Za-z][0-9A-Za-z]*»;
     t[1] = wlit(P(1));
     return t[0] = P_mktuple(P_Based, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<LITCONST> =
   case P_LITCONST:
#ifdef IN_PARSER

  //  <--------------------------------------------------------------------------------------------------- FIX!  TO DO

#endif
     if (alt == 0)               {  //\\    <N> '_' <Based>,
       t[1] = compile(P(1), depth+1 /* P_N */);
       t[2] = wlit(P(2) /*, L'_' */);
       t[3] = compile(P(3), depth+1 /* P_Based */);
       return t[0] = P_mktuple(P_LITCONST, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <N> <OptDecimal> <OptExponent>,
       t[1] = compile(P(1), depth+1 /* P_N */);
       t[2] = compile(P(2), depth+1 /* P_OptDecimal */);
       t[3] = compile(P(3), depth+1 /* P_OptExponent */);
       return t[0] = P_mktuple(P_LITCONST, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 2)        {  //\\    '.' <N> <OptExponent>,
       t[1] = wlit(P(1) /*, L'.' */);
       t[2] = compile(P(2), depth+1 /* P_N */);
       t[3] = compile(P(3), depth+1 /* P_OptExponent */);
       return t[0] = P_mktuple(P_LITCONST, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 3)        {  //\\    <CharConst>,
       t[1] = compile(P(1), depth+1 /* P_CharConst */);
       return t[0] = P_mktuple(P_LITCONST, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 4)        {  //\\    <ALIASTEXT>,
       t[1] = compile(P(1), depth+1 /* P_ALIASTEXT */);
       return t[0] = P_mktuple(P_LITCONST, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 5)        {  //\\    'E' <ALIASTEXT>,
       t[1] = wlit(P(1) /*, L'E' */);
       t[2] = compile(P(2), depth+1 /* P_ALIASTEXT */);
       return t[0] = P_mktuple(P_LITCONST, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    «[MBKXRH]» <BigCharConst>;
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_BigCharConst */);
       return t[0] = P_mktuple(P_LITCONST, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<CONST> =
   case P_CONST:
#ifdef IN_PARSER
  // Pushes an AST_ATOM_LIT:

  t[1] = compile(P(1), depth+1);
  t[2] = -1; // type info, TO DO.
  t[0] = P_mktuple(AST_CONST, 0/*alt no*/, 2/*phrases*/, t);

  //Diagnose("NEW CONSTANT: ", t[1], 0, TRUE);
  //{int child=P_P(t[1],1); Diagnose("CONSTANT CHILD: ", child, 0, TRUE);}
  
  PushConst(t[0]);

  // <--------------------------------------------------------------- FIX!  TO DO

#endif
     {                              //\\    <LITCONST>;
     t[1] = compile(P(1), depth+1 /* P_LITCONST */);
     return t[0] = P_mktuple(P_CONST, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<N> =
   case P_N:
#ifdef IN_PARSER

#endif
     {                              //\\    «[0-9][0-9]*»;
     t[1] = wlit(P(1));
     return t[0] = P_mktuple(P_N, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<dq> =
   case P_dq:
#ifdef IN_PARSER

#endif
     {                              //\\    '"';
     t[1] = wlit(P(1) /*, L'"' */);
     return t[0] = P_mktuple(P_dq, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<any> =
   case P_any:
#ifdef IN_PARSER

#endif
     {                              //\\    «.»;
     t[1] = wlit(P(1));
     return t[0] = P_mktuple(P_any, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<stringchars> =
   case P_stringchars:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <dq> <dq> <stringchars>,
       t[1] = compile(P(1), depth+1 /* P_dq */);
       t[2] = compile(P(2), depth+1 /* P_dq */);
       t[3] = compile(P(3), depth+1 /* P_stringchars */);
       return t[0] = P_mktuple(P_stringchars, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <!dq> <any> <stringchars>,
       t[1] = -1; /* ignore negative guard */;
       t[2] = compile(P(2), depth+1 /* P_any */);
       t[3] = compile(P(3), depth+1 /* P_stringchars */);
       return t[0] = P_mktuple(P_stringchars, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_stringchars, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<ALIASTEXT> =
   case P_ALIASTEXT:
#ifdef IN_PARSER

#endif
     {                              //\\    <dq> <stringchars> <dq>;
     t[1] = compile(P(1), depth+1 /* P_dq */);
     t[2] = compile(P(2), depth+1 /* P_stringchars */);
     t[3] = compile(P(3), depth+1 /* P_dq */);
     return t[0] = P_mktuple(P_ALIASTEXT, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<semi> =
   case P_semi:
#ifdef IN_PARSER
 return -1; 
#endif
     {                              //\\    ';';
     t[1] = wlit(P(1) /*, L';' */);
     return t[0] = P_mktuple(P_semi, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Comment> =
   case P_Comment:
#ifdef IN_PARSER


  // TO DO: tweaking this to suppress a later error, but would be nice to know why compile() had not tagged the result properly
  // Add | AST_ATOM_LIT ?

  t[1] = -1; /* easier if I dont care how the comment was started... */    // compile(P(1), depth+1);
  
  // compiling literals through the default path causes them to be printed.  This may be wanted at the initial
  // stages of bringing up a new program but by the time it's developed as far as we are now, we generally don't
  // want bits of text showing up at random!  I think it's anything created by wlit() and can be suppressed by
  // redefining wlit() at the appropriate place.  By the time this code is complete there should be no drop-throughs,
  // and any text that we want to be reserved should be passed back via AST_* tuples.  So issues such as this rule
  // should go away.
  // Note that for now, line reconstruction loses all spaces in parsed comments, and the path of literal text
  // through the compiler loses embedded '{comments}' at the moment too, so comments are not really well handled
  // for now and will require some major restructuring of the line reconstruction phase.

  // The reason that spaces are stripped in "!" comments is that "!" is ambiguous with the "OR" operator (and
  // in previous compilers, with !MOD!) so it is not safe to stop stripping spaces just because a "!" has been
  // seen in the input.  Because "LABEL: ! comment text" is valid, the line reconstruction *has to* interact
  // with the parser state, which is appalling language design and forces a specific implementation on the
  // compiler-writer.  You cannot, for example, have a completely independent pre-processing stage, and you can't
  // have a parser that parses first to a tree and then performs all the actions on the parsed tree - the levels
  // are all mixed up together.  Hence why this issue has not been handled earlier. I've been trying to keep my
  // options open as to how the parser interacts with the line reconstruction and with the decision to handle
  // declarations and scope at parse time versus at compile time from the fully-parsed program. (i.e. statement-at-a-time
  // compiling versus program-at-a-time compiling of the parse tree)
  
  t[2] = compile(P(2), depth+1);
  t[0] = P_mktuple(AST_COMMENT, 0/*alt no*/, 2/*phrases*/, t);
  generate_c(t[0], depth+1);
  return t[0];

#endif
     if (alt == 0)               {  //\\    '!' <TEXT>,
       t[1] = wlit(P(1) /*, L'!' */);
       t[2] = compile(P(2), depth+1 /* P_TEXT */);
       return t[0] = P_mktuple(P_Comment, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    '|' <TEXT>,
       t[1] = wlit(P(1) /*, L'|' */);
       t[2] = compile(P(2), depth+1 /* P_TEXT */);
       return t[0] = P_mktuple(P_Comment, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "comment" <TEXT>;
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_TEXT */);
       return t[0] = P_mktuple(P_Comment, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<TEXT> =
   case P_TEXT:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <!S> «.» <TEXT>,
       t[1] = -1; /* ignore negative guard */;
       t[2] = wlit(P(2));
       t[3] = compile(P(3), depth+1 /* P_TEXT */);
       return t[0] = P_mktuple(P_TEXT, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_TEXT, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Opt_Record_Field> =
   case P_Opt_Record_Field:
#ifdef IN_PARSER

  // NOW PUNTED TO Compile_Var() so should not get called here during parse
  // but will be called later.
  if (alt == 0) {
    t[1] = -1; // reserve for parent // object
    t[2] = compile(P(2), depth+1);   // field
    t[3] = compile(P(3), depth+1);   // app
    t[4] = compile(P(4), depth+1);   // subfields
    // AST entry name yet to be determined...
    return P_mktuple(AST_PENDING_APP_OR_FIELD, 0/*alt no*/, 4/*phrases*/, t);
  } else {
    return -1;
  }

#endif
     if (alt == 0)               {  //\\    '_' <TAG> <APP> <Opt_Record_Field>,
       t[1] = wlit(P(1) /*, L'_' */);
       t[2] = compile(P(2), depth+1 /* P_TAG */);
       t[3] = compile(P(3), depth+1 /* P_APP */);
       t[4] = compile(P(4), depth+1 /* P_Opt_Record_Field */);
       return t[0] = P_mktuple(P_Opt_Record_Field, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_Opt_Record_Field, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<VAR> =
   case P_VAR:
#ifdef IN_PARSER

  {

    int varname   = compile(P(1), depth+1); // RVALUE containing VarDecl[VarIDX]
    int app       = compile(P(2), depth+1); // -1 or MkApp(Expr, Rest); - we don't yet know if an array or a fn call
    int subfields = compile(P(3), depth+1); // -1 or AST_PENDING_APP_OR_FIELD
                                          // (this will recursively create
                                          //  tuples for any subfields)

    int Var = AST_mktuple(AST_PENDING_APP_OR_FIELD, varname, -1 /*field*/, app, subfields);    
    PushVar(Var);  // Punt to reverse-polish stack evaluation of precedence
    return -1;

  }

#endif
     {                              //\\    <VARNAME> <APP> <Opt_Record_Field>;
     t[1] = compile(P(1), depth+1 /* P_VARNAME */);
     t[2] = compile(P(2), depth+1 /* P_APP */);
     t[3] = compile(P(3), depth+1 /* P_Opt_Record_Field */);
     return t[0] = P_mktuple(P_VAR, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<OPERAND> =
   case P_OPERAND:
#ifdef IN_PARSER


  // shunting yard algorithm.  Note need to distinguish between the use of
  // VAR and CONST in expressions (which are getting the shunting yard treatment)
  // and many other places in the grammar, where they are not.

  // NOTE: parentheses in Imp serve two purposes: 1) overriding the precedence of
  // operators, and 2) forcing the order of evaluation specifically to avoid
  // overflows in intermediate results.  So although we normally output expressions
  // using minimal brackets and only insert them when needed due to differences
  // between Imp and C precedences, we will leave user-supplied parentheses in place
  // when outputting the C version of an expression to explicitly preserve option (2).

  if (alt == 2) {  // '('<EXPR>')'
    // compile the expr and reduce it to a single irreducible object so it is treated
    // like a variable or a constant and its subexpressions are not examined when
    // handling C's operator precedence.

    // Compiling <EXPR> should return an AST_EXPRESSION

    // a + (b + c) was coming out as (a + b + c) - the TORP was picking up
    // the "a +" that was already on the stack and adding it to the Expr.  What
    // was needed was to seal a false bottom on the stack so that Expr is
    // constructed independent of anything preceding it. [*** FIXED ***]

    t[1] = compile(P(2), depth+1);
    int AstTuple = P_mktuple(AST_USER_PARENS, 0, 1, t);
               
    PushParen(L"("); PushExpr(AstTuple); PushParen(L")"); // AstTuple is opaque to the RP code.  It treats it like any atom.
    return -1;
  }
  // otherwise, compile <VAR> or <CONST>, which will push them on the TORP stack   <--------------------------------- FIX!  TO DO

#endif
     if (alt == 0)               {  //\\    <VAR>,
       t[1] = compile(P(1), depth+1 /* P_VAR */);
       return t[0] = P_mktuple(P_OPERAND, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <CONST>,
       t[1] = compile(P(1), depth+1 /* P_CONST */);
       return t[0] = P_mktuple(P_OPERAND, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    '(' <EXPR> ')';
       t[1] = wlit(P(1) /*, L'(' */);
       t[2] = compile(P(2), depth+1 /* P_EXPR */);
       t[3] = wlit(P(3) /*, L')' */);
       return t[0] = P_mktuple(P_OPERAND, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<CONSTVAR> =
   case P_CONSTVAR:
#ifdef IN_PARSER

  {
  // alt=0: symbolic constant
  // alt=1: literal constant
//  t[1] = compile(P(1), depth+1);
//  PushConst(P_mktuple(AST_RVALUE, 0/*alt no*/, 1/*phrases*/, t));

  int ConstVar = compile(P(1), depth+1);
  if (P_alt(ConstVar) == 0 && P_P(ConstVar,1) == -1) {
    fprintf(stderr, "* NAME NOT SET(#4): %ls\n", wSVTag); // exit(1);
  }
  
  // if (..?) {   // TO DO: Check the type and if it was a constant, mark it as so:
  // P_ISCONST(ConstVar) = 1;
  //
  
  PushConst(ConstVar);
  return -1;
  }

#endif
     {                              //\\    <VARNAME>;
     t[1] = compile(P(1), depth+1 /* P_VARNAME */);
     return t[0] = P_mktuple(P_CONSTVAR, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<COPERAND> =
   case P_COPERAND:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <CONSTVAR>,
       t[1] = compile(P(1), depth+1 /* P_CONSTVAR */);
       return t[0] = P_mktuple(P_COPERAND, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <CONST>,
       t[1] = compile(P(1), depth+1 /* P_CONST */);
       return t[0] = P_mktuple(P_COPERAND, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    '(' <CEXPR> ')';
       t[1] = wlit(P(1) /*, L'(' */);
       t[2] = compile(P(2), depth+1 /* P_CEXPR */);
       t[3] = wlit(P(3) /*, L')' */);
       return t[0] = P_mktuple(P_COPERAND, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<CEXPR> =
   case P_CEXPR:
#ifdef IN_PARSER

  {
    // CODE BELOW same as following P<EXPR> but uncommented.
    int Expr;
    int SaveOperBottom = OperStack_bottom; OperStack_bottom = OperStack_nextfree;
    int SaveDataBottom = DataStack_bottom; DataStack_bottom = DataStack_nextfree;
    t[2] = compile(P(1), depth+1);
    t[1] = ExPop();
    DataStack_bottom = SaveDataBottom; OperStack_bottom = SaveOperBottom;

    // TO DO: Modify the tuple below to mark it as evaluating to a constant
    // compatible with contexts in C that require a constant expression:
    // *OR* return AST_CONSTANT_EXPRESSION tuple? (which does not yet exist)
    Expr = P_mktuple(AST_EXPRESSION, 0, 2, t); // converts to a single object

    // if (...?) {  // TO DO: Test and confirm <EXPR> evaluates to a constant...
    //   P_ISCONST(Expr) = 1;
    // }

    //Diagnose("CEXPR: ", Expr, 0, debug_declarations);
    return Expr;
  }

#endif
     {                              //\\    <CTORP>;
     t[1] = compile(P(1), depth+1 /* P_CTORP */);
     return t[0] = P_mktuple(P_CEXPR, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<CTORP> =
   case P_CTORP:
#ifdef IN_PARSER

#endif
     {                              //\\    <UOP> <COPERAND> <RESTOFCEXPR>;
     t[1] = compile(P(1), depth+1 /* P_UOP */);
     t[2] = compile(P(2), depth+1 /* P_COPERAND */);
     t[3] = compile(P(3), depth+1 /* P_RESTOFCEXPR */);
     return t[0] = P_mktuple(P_CTORP, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<STAROREXPR> =
   case P_STAROREXPR:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <UOP> <COPERAND> <RESTOFCEXPR>,
       t[1] = compile(P(1), depth+1 /* P_UOP */);
       t[2] = compile(P(2), depth+1 /* P_COPERAND */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFCEXPR */);
       return t[0] = P_mktuple(P_STAROREXPR, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    '*';
       t[1] = wlit(P(1) /*, L'*' */);
       return t[0] = P_mktuple(P_STAROREXPR, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<TORP> =
   case P_TORP:
#ifdef IN_PARSER

#endif
     {                              //\\    <UOP> <OPERAND> <RESTOFEXPR>;
     t[1] = compile(P(1), depth+1 /* P_UOP */);
     t[2] = compile(P(2), depth+1 /* P_OPERAND */);
     t[3] = compile(P(3), depth+1 /* P_RESTOFEXPR */);
     return t[0] = P_mktuple(P_TORP, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<EXPR> =
   case P_EXPR:
#ifdef IN_PARSER

  {
    // CODE BELOW same as previous P<CEXPR> but commented.
    int Expr;

    // Previously I had many calls to <EXPR> duplicating the 'false bottom'
    // code below, until I realised I could safely use it *everywhere* and
    // therefore placed a single instance here instead.
    
    int SaveOperBottom = OperStack_bottom; OperStack_bottom = OperStack_nextfree;
    int SaveDataBottom = DataStack_bottom; DataStack_bottom = DataStack_nextfree;
    t[2] = compile(P(1), depth+1); // walk the CST expression tree to process each atom sequentially left to right, as input to the shunting yard algorithm
    t[1] = ExPop();               // now convert the reverse-polish stack back into an AST tree, with precedence now magically applied.
    DataStack_bottom = SaveDataBottom;
    OperStack_bottom = SaveOperBottom;

    Expr = P_mktuple(AST_EXPRESSION, 0, 2, t); // converts to a single object

    // We do not print <EXPR>s immediately because a bracketed (<EXPR>) which is a subexpression of a larger <EXPR> has to be reprocessed
    // in order to apply operator precedence.  A consequence of this is that <EXPR>s in other contexts will have to be output via generate_c()
    // at the point of call.
    
    //Diagnose("EXPR: ", Expr, 0, debug_declarations);
    return Expr;
  }

#endif
     {                              //\\    <TORP>;
     t[1] = compile(P(1), depth+1 /* P_TORP */);
     return t[0] = P_mktuple(P_EXPR, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFEXPR> =
   case P_RESTOFEXPR:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <OP> <OPERAND> <RESTOFEXPR>,
       t[1] = compile(P(1), depth+1 /* P_OP */);
       t[2] = compile(P(2), depth+1 /* P_OPERAND */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFEXPR */);
       return t[0] = P_mktuple(P_RESTOFEXPR, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFEXPR, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFCEXPR> =
   case P_RESTOFCEXPR:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <OP> <COPERAND> <RESTOFCEXPR>,
       t[1] = compile(P(1), depth+1 /* P_OP */);
       t[2] = compile(P(2), depth+1 /* P_COPERAND */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFCEXPR */);
       return t[0] = P_mktuple(P_RESTOFCEXPR, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFCEXPR, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<APP> =
   case P_APP:
#ifdef IN_PARSER

  if (alt == 0) {
    int Expr = compile(P(2), depth+1);
    int Rest = compile(P(3), depth+1);
    return MkApp(Expr, Rest);
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    '(' <EXPR> <RESTOFAPP> ')',
       t[1] = wlit(P(1) /*, L'(' */);
       t[2] = compile(P(2), depth+1 /* P_EXPR */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFAPP */);
       t[4] = wlit(P(4) /*, L')' */);
       return t[0] = P_mktuple(P_APP, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_APP, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFAPP> =
   case P_RESTOFAPP:
#ifdef IN_PARSER

  if (alt == 0) {
    int Expr = compile(P(3), depth+1);
    int Rest = compile(P(4), depth+1);
    return MkApp(Expr, Rest);
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    ',' <READLINEP> <EXPR> <RESTOFAPP>,
       t[1] = wlit(P(1) /*, L',' */);
       t[2] = compile(P(2), depth+1 /* P_READLINEP */);
       t[3] = compile(P(3), depth+1 /* P_EXPR */);
       t[4] = compile(P(4), depth+1 /* P_RESTOFAPP */);
       return t[0] = P_mktuple(P_RESTOFAPP, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFAPP, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<PC_IU> =
   case P_PC_IU:
#ifdef IN_PARSER

  if (alt == 0) {
    codegen("if ");
  } else {
    codegen("unless ");
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    "if",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_PC_IU, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "unless";
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_PC_IU, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<TOP_LEVEL_CONDITION> =
   case P_TOP_LEVEL_CONDITION:
#ifdef IN_PARSER

  codegen(" (");
  compile(P(1), depth+1); compile(P(2), depth+1);
  codegen(") ");
  return -1;

#endif
     {                              //\\    <SC> <RESTOFCOND>;
     t[1] = compile(P(1), depth+1 /* P_SC */);
     t[2] = compile(P(2), depth+1 /* P_RESTOFCOND */);
     return t[0] = P_mktuple(P_TOP_LEVEL_CONDITION, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<CYCPARM> =
   case P_CYCPARM:
#ifdef IN_PARSER

  // %for J = I, -1, 1
  // for (J = I; J < 1; J += -1)
  // if the step is positive use '<', if negative use '>', if unknown use '!='...
  
  codegen("for (");
  int Control = compile(P(1), depth+1);
  // TO DO: check type of Control and also that it is not a literal constant! (P_alt(Control) == ?)
  if (Control == -1 || P_P(Control,1) == -1) {
    fprintf(stderr, "* NAME NOT SET(#5): %ls\n", wSVTag); // exit(1);
    return -1;
  }
  generate_c(Control, depth+1);

  int Expr1 = compile(P(3), depth+1);
  int Expr2 = compile(P(5), depth+1);
  int Expr3 = compile(P(7), depth+1);

  codegen(" = ");
  generate_c(Expr1, depth+1);
  codegen("; ");
  generate_c(compile(P(1), depth+1), depth+1);
  codegen(" != (");
  generate_c(Expr3, depth+1);
  codegen(")+(");
  generate_c(Expr2, depth+1);
  codegen("); ");
  generate_c(compile(P(1), depth+1), depth+1);
  codegen(" += ");
  generate_c(Expr2, depth+1);
  codegen(") ");
  return -1;

#endif
     {                              //\\    <VARNAME> '=' <EXPR> ',' <EXPR> ',' <EXPR>;
     t[1] = compile(P(1), depth+1 /* P_VARNAME */);
     t[2] = wlit(P(2) /*, L'=' */);
     t[3] = compile(P(3), depth+1 /* P_EXPR */);
     t[4] = wlit(P(4) /*, L',' */);
     t[5] = compile(P(5), depth+1 /* P_EXPR */);
     t[6] = wlit(P(6) /*, L',' */);
     t[7] = compile(P(7), depth+1 /* P_EXPR */);
     return t[0] = P_mktuple(P_CYCPARM, alt, 7/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<PC_WUF> =
   case P_PC_WUF:
#ifdef IN_PARSER

  if (alt == 0) {
    codegen("while "); compile(P(2), depth+1);
  } else if (alt == 1) {
    // TO DO: restructure so that while is tested at end of loop rather than beginning!
    // Note that for now compiling these causes them to also be printed on the fly.
    codegen("until "); compile(P(2), depth+1);
    t[1] = P(2);
    int Cond = t[0] = P_mktuple(AST_DEFER_UNCOMPILED_PHRASE, /*alt*/0, /*count*/1, t);
    return Cond;
  } else if (alt == 2) {
    compile(P(2), depth+1);
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    "while" <TOP_LEVEL_CONDITION>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_TOP_LEVEL_CONDITION */);
       return t[0] = P_mktuple(P_PC_WUF, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    "until" <TOP_LEVEL_CONDITION>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_TOP_LEVEL_CONDITION */);
       return t[0] = P_mktuple(P_PC_WUF, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "for" <CYCPARM>;
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_CYCPARM */);
       return t[0] = P_mktuple(P_PC_WUF, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<ALIAS> =
   case P_ALIAS:
#ifdef IN_PARSER
 return -1; 
#endif
     if (alt == 0)               {  //\\    "alias" <ALIASTEXT>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_ALIASTEXT */);
       return t[0] = P_mktuple(P_ALIAS, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_ALIAS, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<DECLNAMES> =
   case P_DECLNAMES:
#ifdef IN_PARSER

  if (alt == 0) {
    //codegen(", ");
    fprintf(stderr, "? Warning: <DECLNAMES> being compiled by default code - so no calls to Declaration() for each <DECLNAME>\n");
    compile(P(3), depth+1);
    compile(P(4), depth+1);
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    ',' <READLINEP> <DECLNAME> <DECLNAMES>,
       t[1] = wlit(P(1) /*, L',' */);
       t[2] = compile(P(2), depth+1 /* P_READLINEP */);
       t[3] = compile(P(3), depth+1 /* P_DECLNAME */);
       t[4] = compile(P(4), depth+1 /* P_DECLNAMES */);
       return t[0] = P_mktuple(P_DECLNAMES, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_DECLNAMES, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<DECLNAME> =
   case P_DECLNAME:
#ifdef IN_PARSER

  // check to see which is in the most accessible format:
  DTag = SubPhraseIdx(Ph, 2); // Set a global for use by <DECLARE>
  return -1;

#endif
     {                              //\\    <!CONST> «[A-Z][A-Z0-9]*»;
     t[1] = -1; /* ignore negative guard */;
     t[2] = wlit(P(2));
     return t[0] = P_mktuple(P_DECLNAME, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<FULLTYPE> =
   case P_FULLTYPE:
#ifdef IN_PARSER
 return -1; 
#endif
     if (alt == 0)               {  //\\    "integer",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_FULLTYPE, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_FULLTYPE, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<BTYPE> =
   case P_BTYPE:
#ifdef IN_PARSER

  Basetype = (alt == 0 ? FLOAT : INTEGER);
  return -1;

#endif
     if (alt == 0)               {  //\\    "real",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_BTYPE, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "integer";
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_BTYPE, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<STRLEN> =
   case P_STRLEN:
#ifdef IN_PARSER
  //  <---------------------------------------------------------------- FIX!  TO DO
  // TO DO.

#endif
     if (alt == 0)               {  //\\    '(' <STAROREXPR> ')',
       t[1] = wlit(P(1) /*, L'(' */);
       t[2] = compile(P(2), depth+1 /* P_STAROREXPR */);
       t[3] = wlit(P(3) /*, L')' */);
       return t[0] = P_mktuple(P_STRLEN, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_STRLEN, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<XTYPE> =
   case P_XTYPE:
#ifdef IN_PARSER

  switch (alt) {
  case 0: Signedness = SIGNED;   Precision = WORD;     Basetype = INTEGER;     break; // integer
  case 1: Signedness = SIGNED;   Precision = WORD;     Basetype = FLOAT;       break; // real
  case 2: Signedness = SIGNED;   Precision = QUADWORD;                         break; // long long (integer | real)
  case 3: Signedness = SIGNED;   Precision = LONGWORD;                         break; // long (integer | real)
  case 4: Signedness = SIGNED;   Precision = BYTE;     Basetype = INTEGER;     break; // byte (integer)?   (no %mite in this variant of Imp)
  case 5: Signedness = SIGNED;   Precision = COMPOUND; Basetype = STRINGTYPE;  break; // string
  case 6: Signedness = UNSIGNED; Precision = SHORT;    Basetype = INTEGER;     break; // half (integer)?
  case 7: Signedness = SIGNED;   Precision = SHORT;    Basetype = INTEGER;     break; // short (integer)?
  case 8: Signedness = SIGNED;   Precision = COMPOUND; Basetype = RECORD;
          compile(P(3), depth+1); // compiling <RFREF> assigns <RFREF> type to global "RecordTypeIDX" which is picked up by Declaration()
                                  // TO DO: Add RecordTypeIDX to the PUSH/POPDECL stack.
                                  // (Note: inline definition of RFREF not yet handled.)
                                                                               break; // record
  }
  if (debug_declarations > 1) fprintf(stderr, "[ Sign=%d Prec=%d Type=%d ]", Signedness, Precision, Basetype);
  //  <----------------------------------------------------------------------------------------------  FIX!  TO DO

#endif
     if (alt == 0)               {  //\\    "integer",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_XTYPE, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    "real",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_XTYPE, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 2)        {  //\\    "long" "long" <BTYPE>,
       t[1] = wlit(P(1));
       t[2] = wlit(P(2));
       t[3] = compile(P(3), depth+1 /* P_BTYPE */);
       return t[0] = P_mktuple(P_XTYPE, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 3)        {  //\\    "long" <BTYPE>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_BTYPE */);
       return t[0] = P_mktuple(P_XTYPE, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 4)        {  //\\    "byte" <FULLTYPE>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_FULLTYPE */);
       return t[0] = P_mktuple(P_XTYPE, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 5)        {  //\\    "string" <STRLEN>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_STRLEN */);
       return t[0] = P_mktuple(P_XTYPE, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 6)        {  //\\    "half" <FULLTYPE>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_FULLTYPE */);
       return t[0] = P_mktuple(P_XTYPE, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 7)        {  //\\    "short" <FULLTYPE>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_FULLTYPE */);
       return t[0] = P_mktuple(P_XTYPE, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "record" '(' <RFREF> ')';
       t[1] = wlit(P(1));
       t[2] = wlit(P(2) /*, L'(' */);
       t[3] = compile(P(3), depth+1 /* P_RFREF */);
       t[4] = wlit(P(4) /*, L')' */);
       return t[0] = P_mktuple(P_XTYPE, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RT> =
   case P_RT:
#ifdef IN_PARSER

  if (alt == 0) {
    Proc = ROUTINE;
    if (debug_declarations > 1) fprintf(stderr, "[Proc=%d]", Proc);
  }
  //  <----------------------------------------------------------------------------------------------  FIX!  TO DO

#endif
     if (alt == 0)               {  //\\    "routine",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_RT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <XTYPE> <FM>;
       t[1] = compile(P(1), depth+1 /* P_XTYPE */);
       t[2] = compile(P(2), depth+1 /* P_FM */);
       return t[0] = P_mktuple(P_RT, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<FM> =
   case P_FM:
#ifdef IN_PARSER

  if (alt == 1) Proc = MAP; else Proc = FN;
  if (debug_declarations > 1) fprintf(stderr, "[Proc=%d]", Proc);
  return -1;

#endif
     if (alt == 0)               {  //\\    "fn",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_FM, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    "map",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_FM, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "function";
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_FM, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<FP> =
   case P_FP:
#ifdef IN_PARSER

#endif
     {                              //\\    <PUSHDECS> <FPDEL> <POPDECS>;
     t[1] = compile(P(1), depth+1 /* P_PUSHDECS */);
     t[2] = compile(P(2), depth+1 /* P_FPDEL */);
     t[3] = compile(P(3), depth+1 /* P_POPDECS */);
     return t[0] = P_mktuple(P_FP, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<FPDEL> =
   case P_FPDEL:
#ifdef IN_PARSER

  // Need to check I set up Object = here correctly.  Was a bit of a rush late one night.
  Area = PARAMETER;
  if (alt == 0) { // a simple object
    // <XTYPE><Opt_AN_N_type><DECLNAME><DECLNAMES>,
    Object = VAR; Proc = NONE; Linkage = AUTO;
    compile(P(1), depth+1); // <<XTYPE>
    compile(P(2), depth+1); // <Opt_AN_N_type>
    compile(P(3), depth+1); // <DECLNAME> 
    int ParamIDX = Declaration(depth+1, FALSE /* A, B, C form not allowed */); //codegen("/*A %s:%d*/",__FILE__,__LINE__);
    {
      int MoreDecls = P(4);  // ',' <READLINEP><DECLNAME> <DECLNAMES>, ''
      while (P_alt(MoreDecls) == 0) {
        codegen(", ");/*a*/
        compile(P_P(MoreDecls, 3), depth+1); // <DECLNAME>
        int NextParamIDX = Declaration(depth+1, TRUE /* A, B, C format allowed */); //codegen("/*B %s:%d*/",__FILE__,__LINE__);
        MoreDecls = P_P(MoreDecls, 4);
      }
    }
    return -1;
  } else if (alt == 1) {  // A procedure parameter
    // <RT><Opt_N_type><DECLNAME><DECLNAMES><FPP>
    Object = CODE; // TO DO: Or should this be VAR?  Not yet tested.
    compile(P(1), depth+1); // <RT>
    compile(P(2), depth+1); // <Opt_N_type>
    compile(P(5), depth+1); // <FPP>           Reordered so FPP is handled before names
    compile(P(3), depth+1); // <DECLNAME> 
    int ProcParamIDX = Declaration(depth+1, FALSE /* A, B, C form not allowed */); codegen("/*C %s:%d*/",__FILE__,__LINE__);
    {
      int MoreDecls = P(4);  // ',' <READLINEP><DECLNAME> <DECLNAMES>, ''
      while (P_alt(MoreDecls) == 0) {
        codegen(", /*b*/");
        compile(P_P(MoreDecls, 3), depth+1); // <DECLNAME>
        int NextProcParamIDX = Declaration(depth+1, TRUE /* A, B, C format allowed */); codegen("/*D %s:%d*/",__FILE__,__LINE__);
        MoreDecls = P_P(MoreDecls, 4);
      }
    }
    return -1;
  } else if (alt == 2) {    // "name"<DECLNAME><DECLNAMES>
    // NOTE: generated C might consider using GCC's "__attribute((may_alias))" to better replicate Imp semantics?
    Object = VAR;
    Basetype = GENERIC;
    NameInfo = OBJECTNAME;
    //IsFormat = UNINIT_ISFORMAT;
    Spec = NO_SPEC;
    //Signedness = UNINIT_SIGNEDNESS;
    //Precision = UNINIT_PRECISION; // or maybe COMPOUND
    Proc = NONE; // unless the %name parameter is a %fn perhaps? Haven't thought this one through yet.
    //IsArray = UNINIT_ISARRAY;
    //Linkage = UNINIT_LINKAGE;
    compile(P(2), depth+1); // <DECLNAME>
    int NameIDX = Declaration(depth+1, FALSE /* A, B, C form not allowed */); //codegen("/*E %s:%d*/",__FILE__,__LINE__);
    {
      int MoreDecls = P(4);  // ',' <READLINEP><DECLNAME> <DECLNAMES>, ''
      while (P_alt(MoreDecls) == 0) {
        codegen(", /*c*/");
        compile(P_P(MoreDecls, 3), depth+1); // <DECLNAME>
        int NextNameIDX = Declaration(depth+1, TRUE /* A, B, C format allowed */); codegen("/*F %s:%d*/",__FILE__,__LINE__);
        MoreDecls = P_P(MoreDecls, 4);
      }
    }
    return -1;
  }

#endif
     if (alt == 0)               {  //\\    <XTYPE> <Opt_AN_N_type> <DECLNAME> <DECLNAMES>,
       t[1] = compile(P(1), depth+1 /* P_XTYPE */);
       t[2] = compile(P(2), depth+1 /* P_Opt_AN_N_type */);
       t[3] = compile(P(3), depth+1 /* P_DECLNAME */);
       t[4] = compile(P(4), depth+1 /* P_DECLNAMES */);
       return t[0] = P_mktuple(P_FPDEL, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <RT> <Opt_N_type> <DECLNAME> <DECLNAMES> <FPP>,
       t[1] = compile(P(1), depth+1 /* P_RT */);
       t[2] = compile(P(2), depth+1 /* P_Opt_N_type */);
       t[3] = compile(P(3), depth+1 /* P_DECLNAME */);
       t[4] = compile(P(4), depth+1 /* P_DECLNAMES */);
       t[5] = compile(P(5), depth+1 /* P_FPP */);
       return t[0] = P_mktuple(P_FPDEL, alt, 5/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "name" <DECLNAME> <DECLNAMES>;
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_DECLNAME */);
       t[3] = compile(P(3), depth+1 /* P_DECLNAMES */);
       return t[0] = P_mktuple(P_FPDEL, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Opt_N_type> =
   case P_Opt_N_type:
#ifdef IN_PARSER
 return -1; 
#endif
     if (alt == 0)               {  //\\    "name",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_Opt_N_type, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_Opt_N_type, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Opt_AN_N_type> =
   case P_Opt_AN_N_type:
#ifdef IN_PARSER

  switch (alt) {
  case 0: NameInfo = ARRAYNAME;  break;
  case 1: NameInfo = OBJECTNAME; break;
  case 2: NameInfo = NO_NAME;     break;
  }
  if (debug_declarations > 1) fprintf(stderr, "[NameInfo=%d]", NameInfo);
  return -1;

#endif
     if (alt == 0)               {  //\\    "array" "name",
       t[1] = wlit(P(1));
       t[2] = wlit(P(2));
       return t[0] = P_mktuple(P_Opt_AN_N_type, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    "name",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_Opt_AN_N_type, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_Opt_AN_N_type, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<FPP> =
   case P_FPP:
#ifdef IN_PARSER

  if (alt == 1) codegen("void"); // proc with no parameters
  Area = PARAMETER;
  //  <--------------------------------------------------------------------------------------------- FIX!  TO DO

#endif
     if (alt == 0)               {  //\\    '(' <FP> <RESTOFFPLIST> ')',
       t[1] = wlit(P(1) /*, L'(' */);
       t[2] = compile(P(2), depth+1 /* P_FP */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFFPLIST */);
       t[4] = wlit(P(4) /*, L')' */);
       return t[0] = P_mktuple(P_FPP, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_FPP, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Opt_comma> =
   case P_Opt_comma:
#ifdef IN_PARSER
 return -1; 
#endif
     if (alt == 0)               {  //\\    ',',
       t[1] = wlit(P(1) /*, L',' */);
       return t[0] = P_mktuple(P_Opt_comma, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_Opt_comma, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFFPLIST> =
   case P_RESTOFFPLIST:
#ifdef IN_PARSER

  if (alt == 0) codegen(", ");
  //  <-------------------------------------------------------------------------------------------- FIX!  TO DO

#endif
     if (alt == 0)               {  //\\    <Opt_comma> <READLINEP> <FP> <RESTOFFPLIST>,
       t[1] = compile(P(1), depth+1 /* P_Opt_comma */);
       t[2] = compile(P(2), depth+1 /* P_READLINEP */);
       t[3] = compile(P(3), depth+1 /* P_FP */);
       t[4] = compile(P(4), depth+1 /* P_RESTOFFPLIST */);
       return t[0] = P_mktuple(P_RESTOFFPLIST, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFFPLIST, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<ENDLIST> =
   case P_ENDLIST:
#ifdef IN_PARSER

                      
  // Need a routine to unwind the control stack and show what was expected.
  
  if (alt == 0) {
    if (debug_compiler) fprintf(stderr, "[end of program]\n");
    if (ctrl_depth() != 1) {
      fprintf(stderr, "\n* Spurious %%ENDOFPROGRAM\n"); exit(1);
    }
    int EXPECTED = pop_ctrl();
    if (EXPECTED != ENDOFPROGRAM) {
      fprintf(stderr, "\n* %%ENDOFPROGRAM not expected here (expecting %s)\n",
             ctrl_debug[EXPECTED]); exit(1);
      // A.k.a "%FINISH missing" or "%REPEAT missing" or "%END missing" ... also needed everywhere a pop_ctrl() doesn't match what's expected.
    }
    codegen("\n  exit(0);\n} /* End of program */\n");
  } else if (alt == 1) {
    if (debug_compiler) fprintf(stderr, "[end of perm]\n");
  } else if (alt == 2) {
    if (debug_compiler) fprintf(stderr, "[end of file]\n");
    if (ctrl_depth() != 0) { // might not be the case for an unbalanced %include file...
      fprintf(stderr, "\n* Spurious %%ENDOFFILE\n"); exit(1);
    }
  } else if (alt == 3) {
    if (debug_compiler) fprintf(stderr, "[end of list]\n");
  } else if (alt == 4) {
    if (debug_compiler) fprintf(stderr, "[end of Rt/Fn/Map/begin block]\n");
    if (ctrl_depth() < 1) {
      fprintf(stderr, "\n* Spurious %%END (ctrl_depth()=%d))\n", ctrl_depth()); exit(1);
    }
    int EXPECTED = pop_ctrl();
    if (EXPECTED != END) {
      fprintf(stderr, "\n* %%END not expected here (expecting %s)\n",
              ctrl_debug[EXPECTED]); exit(1);
    }
    codegen("\n}\n"); // no semicolon
  }
  //  <-------------------------------------------------------------------------------------------- FIX!  TO DO

#endif
     if (alt == 0)               {  //\\    "ofprogram" <UP>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_UP */);
       return t[0] = P_mktuple(P_ENDLIST, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    "ofperm",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_ENDLIST, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 2)        {  //\\    "offile",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_ENDLIST, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 3)        {  //\\    "oflist" <LISTOFF>,
       t[1] = wlit(P(1));
       t[2] = -1; /* semantic procedure LISTOFF */;
       return t[0] = P_mktuple(P_ENDLIST, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <UP>;
       t[1] = compile(P(1), depth+1 /* P_UP */);
       return t[0] = P_mktuple(P_ENDLIST, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<ARRAYFORMAT> =
   case P_ARRAYFORMAT:
#ifdef IN_PARSER

  if (alt == 0) Object = ARRAYFORMAT;
  //IsFormat = (alt == 0 ? IS_FORMAT : NO_FORMAT );
  //if (debug_declarations > 1) fprintf(stderr, "[format=%d]", IsFormat);
  return -1;

#endif
     if (alt == 0)               {  //\\    "format",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_ARRAYFORMAT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_ARRAYFORMAT, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFSC> =
   case P_RESTOFSC:
#ifdef IN_PARSER

  return -1; // let the parent level handle it.

#endif
     if (alt == 0)               {  //\\    <COMP2> <EXPR>,
       t[1] = compile(P(1), depth+1 /* P_COMP2 */);
       t[2] = compile(P(2), depth+1 /* P_EXPR */);
       return t[0] = P_mktuple(P_RESTOFSC, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFSC, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<SC> =
   case P_SC:
#ifdef IN_PARSER
 // %not is '!' in C
  if (alt == 0) {
    int Expr1 = compile(P(1), depth+1);
    generate_c(Expr1, depth+1);          // TO DO: <EXPR>s need false bottom!
    compile(P(2), depth+1);
    int Expr2 = compile(P(3), depth+1);
    generate_c(Expr2, depth+1);
    int RestofSC = P(4);
    if (P_alt(RestofSC) == 0) {
      int Comp2 = P_P(RestofSC, 1);
      int Expr3 = P_P(RestofSC, 2);
      codegen(" && ");
      generate_c(Expr2, depth+1);
      compile(Comp2, depth+1);
      Expr3 = compile(Expr3, depth+1);
      generate_c(Expr3, depth+1);
    }
    compile(P(4), depth+1); // RESTOFSC
  } else if (alt == 1) {
    compile(P(2), depth+1); // SC
    compile(P(3), depth+1); // RESTOFCOND
  } else {                  // NOT SC
    codegen("!");  // not sure about priorities for booleans
    codegen("(");
    compile(P(2), depth+1);
    codegen(")");
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    <EXPR> <COMP1> <EXPR> <RESTOFSC>,
       t[1] = compile(P(1), depth+1 /* P_EXPR */);
       t[2] = compile(P(2), depth+1 /* P_COMP1 */);
       t[3] = compile(P(3), depth+1 /* P_EXPR */);
       t[4] = compile(P(4), depth+1 /* P_RESTOFSC */);
       return t[0] = P_mktuple(P_SC, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    '(' <SC> <RESTOFCOND> ')',
       t[1] = wlit(P(1) /*, L'(' */);
       t[2] = compile(P(2), depth+1 /* P_SC */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFCOND */);
       t[4] = wlit(P(4) /*, L')' */);
       return t[0] = P_mktuple(P_SC, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "not" <SC>;
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_SC */);
       return t[0] = P_mktuple(P_SC, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFCOND> =
   case P_RESTOFCOND:
#ifdef IN_PARSER

  // TO DO: Only one of them needs to have () added around the other, because the
  //        operator precedences of && and || in C are not equal. (&& is higher than || so we need () around "and" SC's in a RESTOFORC.)
  if (alt == 0) {
    codegen(" && ");
    compile(P(2), depth+1);
    compile(P(3), depth+1);
  } else if (alt == 1) {
    codegen(" || ");
    compile(P(2), depth+1);
    compile(P(3), depth+1);
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    "and" <SC> <RESTOFANDC>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_SC */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFANDC */);
       return t[0] = P_mktuple(P_RESTOFCOND, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    "or" <SC> <RESTOFORC>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_SC */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFORC */);
       return t[0] = P_mktuple(P_RESTOFCOND, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFCOND, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFANDC> =
   case P_RESTOFANDC:
#ifdef IN_PARSER

  if (alt == 0) {
    codegen(" && ");
    compile(P(2), depth+1);
    compile(P(3), depth+1);
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    "and" <SC> <RESTOFANDC>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_SC */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFANDC */);
       return t[0] = P_mktuple(P_RESTOFANDC, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFANDC, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFORC> =
   case P_RESTOFORC:
#ifdef IN_PARSER

  if (alt == 0) {
    codegen(" || ");
    compile(P(2), depth+1);     // NEED () AROUND THE <SC> IF IT CONTAINS AN "&&"
    compile(P(3), depth+1);
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    "or" <SC> <RESTOFORC>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_SC */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFORC */);
       return t[0] = P_mktuple(P_RESTOFORC, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFORC, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Opt_RtFnMapSpec> =
   case P_Opt_RtFnMapSpec:
#ifdef IN_PARSER

  if (alt == 0) {
    Spec = SPEC;
  } else if (alt == 1) {
    // Procedures of all kinds require a %end
    push_ctrl(END); // we will probably later distinguish between END and PROCEND etc.
    Spec = NO_SPEC;
  }
  if (debug_declarations > 1) fprintf(stderr, "[Spec=%d]", Spec);
  return -1;

#endif
     if (alt == 0)               {  //\\    "spec",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_Opt_RtFnMapSpec, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_Opt_RtFnMapSpec, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<VSPECQ> =
   case P_VSPECQ:
#ifdef IN_PARSER

  if (alt == 0) Spec = SPEC;
  if (debug_declarations > 1) fprintf(stderr, "[Spec=%d]", Spec);
  return -1;

#endif
     if (alt == 0)               {  //\\    "spec",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_VSPECQ, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_VSPECQ, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFBPLIST> =
   case P_RESTOFBPLIST:
#ifdef IN_PARSER

  if (alt == 0) {
  int LowIDX = compile(P(2), depth+1);
  int HighIDX = compile(P(4), depth+1);
  AddDims(LowIDX, HighIDX);
  compile(P(5), depth+1);
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    ',' <EXPR> ':' <EXPR> <RESTOFBPLIST>,
       t[1] = wlit(P(1) /*, L',' */);
       t[2] = compile(P(2), depth+1 /* P_EXPR */);
       t[3] = wlit(P(3) /*, L':' */);
       t[4] = compile(P(4), depth+1 /* P_EXPR */);
       t[5] = compile(P(5), depth+1 /* P_RESTOFBPLIST */);
       return t[0] = P_mktuple(P_RESTOFBPLIST, alt, 5/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFBPLIST, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<BPAIR> =
   case P_BPAIR:
#ifdef IN_PARSER

  {
  // TO DO: list of upper/lower bounds
  int LowIDX = compile(P(2), depth+1);
  int HighIDX = compile(P(4), depth+1);
  AddDims(LowIDX, HighIDX);
  compile(P(5), depth+1);
  // We now have ArrayDims of pairs of Low:High on the Dims stack, ready for Declaration(depth+1, ) to use.
  }
  return -1;

#endif
     {                              //\\    '(' <EXPR> ':' <EXPR> <RESTOFBPLIST> ')';
     t[1] = wlit(P(1) /*, L'(' */);
     t[2] = compile(P(2), depth+1 /* P_EXPR */);
     t[3] = wlit(P(3) /*, L':' */);
     t[4] = compile(P(4), depth+1 /* P_EXPR */);
     t[5] = compile(P(5), depth+1 /* P_RESTOFBPLIST */);
     t[6] = wlit(P(6) /*, L')' */);
     return t[0] = P_mktuple(P_BPAIR, alt, 6/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFARLIST> =
   case P_RESTOFARLIST:
#ifdef IN_PARSER

  if (alt == 0) compile(P(2), depth+1);
  return -1;

#endif
     if (alt == 0)               {  //\\    ',' <ADECLN>,
       t[1] = wlit(P(1) /*, L',' */);
       t[2] = compile(P(2), depth+1 /* P_ADECLN */);
       return t[0] = P_mktuple(P_RESTOFARLIST, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFARLIST, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<ADECLN> =
   case P_ADECLN:
#ifdef IN_PARSER

    ArrayDims = 0; compile(P(3), depth+1); // <BPAIR>
    compile(P(1), depth+1); // <DECLNAME>
    int ADeclIDX = Declaration(depth+1, FALSE /* A, B, C form not allowed */); // codegen("/*G %s:%d*/",__FILE__,__LINE__);
    codegen(";\n");
    {
      int MoreDecls = P(2);  // P<DECLNAMES> = ',' <READLINEP><DECLNAME> <DECLNAMES>, ''
      while (P_alt(MoreDecls) == 0) {
        //codegen(", /*e*/");
        compile(P_P(MoreDecls, 3), depth+1); // <DECLNAME>
        int NextADeclIDX = Declaration(depth+1, FALSE /* A, B, C form not allowed */); //codegen("/*H %s:%d*/",__FILE__,__LINE__); // for now.  Syntax of multiples is complex.
        codegen(";\n");
        MoreDecls = P_P(MoreDecls, 4); // <DECLNAMES>
      }
    }
    // more array declarations on the same line are effectively independent in terms of bounds (but not type, area etc)
    compile(P(4), depth+1);
    return -1;

#endif
     {                              //\\    <DECLNAME> <DECLNAMES> <BPAIR> <RESTOFARLIST>;
     t[1] = compile(P(1), depth+1 /* P_DECLNAME */);
     t[2] = compile(P(2), depth+1 /* P_DECLNAMES */);
     t[3] = compile(P(3), depth+1 /* P_BPAIR */);
     t[4] = compile(P(4), depth+1 /* P_RESTOFARLIST */);
     return t[0] = P_mktuple(P_ADECLN, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<DECLN> =
   case P_DECLN:
#ifdef IN_PARSER

  if (alt == 0) {
    compile(P(1), depth+1);
    compile(P(2), depth+1);
    int DeclIDX = Declaration(depth+1, TRUE /* A, B, C form allowed */); //codegen("/*I %s:%d*/",__FILE__,__LINE__);
    {
      int MoreDecls = P(3);  // ',' <READLINEP><DECLNAME> <DECLNAMES>, ''
      while (P_alt(MoreDecls) == 0) {
        codegen("; ");/*d*/
        compile(P_P(MoreDecls, 3), depth+1); // <DECLNAME>
        int NextDeclIDX = Declaration(depth+1, TRUE /* A, B, C format allowed */); //codegen("/*J %s:%d*/",__FILE__,__LINE__);
        MoreDecls = P_P(MoreDecls, 4);
      }
    }
    codegen(";\n");
    return -1;
  } else if (alt == 1) {
    IsArray = ARRAY;
    compile(P(2), depth+1);
    compile(P(3), depth+1);
    return -1;
  }

#endif
     if (alt == 0)               {  //\\    <Opt_AN_N_type> <DECLNAME> <DECLNAMES>,
       t[1] = compile(P(1), depth+1 /* P_Opt_AN_N_type */);
       t[2] = compile(P(2), depth+1 /* P_DECLNAME */);
       t[3] = compile(P(3), depth+1 /* P_DECLNAMES */);
       return t[0] = P_mktuple(P_DECLN, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "array" <ARRAYFORMAT> <ADECLN>;
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_ARRAYFORMAT */);
       t[3] = compile(P(3), depth+1 /* P_ADECLN */);
       return t[0] = P_mktuple(P_DECLN, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<OWNDEC> =
   case P_OWNDEC:
#ifdef IN_PARSER

  if (debug_declarations > 1) fprintf(stderr, "[IsArray=%d]", IsArray);
  if (alt == 0) {
    compile(P(1), depth+1); // <Opt_AN_N_type>
    compile(P(2), depth+1); // <VSPECQ>
    compile(P(3), depth+1); // <DECLNAME>
    compile(P(4), depth+1); // <ALIAS>
    
    int OwnDecIDX = Declaration(depth+1, FALSE /* A, B, C form not allowed */);  //codegen("/*K %s:%d*/",__FILE__,__LINE__);
    compile(P(5), depth+1); // <Opt_Const_Init>
    codegen(";\n");
 
    int MoreDecTuple = compile(P(6), depth+1); // <RESTOFOWNDEC>
  } else if (alt == 1) {
    IsArray = ARRAY; // Must be set to SCALAR somewhere for default.
    compile(P(2), depth+1); // <ARRAYFORMAT>
    compile(P(3), depth+1); // <DECLNAME>
    compile(P(4), depth+1); // <ALIAS>
    ArrayDims = 0;
    int BPairTuple = compile(P(5), depth+1); // <BPAIR>
    int ArrayDeclIDX = Declaration(depth+1, FALSE /* A, B, C form not allowed */);  //codegen("/*L %s:%d*/",__FILE__,__LINE__);
    int ConstListTuple = compile(P(6), depth+1); // <CONSTLIST>
    codegen(";\n");
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    <Opt_AN_N_type> <VSPECQ> <DECLNAME> <ALIAS> <Opt_Const_Init> <RESTOFOWNDEC>,
       t[1] = compile(P(1), depth+1 /* P_Opt_AN_N_type */);
       t[2] = compile(P(2), depth+1 /* P_VSPECQ */);
       t[3] = compile(P(3), depth+1 /* P_DECLNAME */);
       t[4] = compile(P(4), depth+1 /* P_ALIAS */);
       t[5] = compile(P(5), depth+1 /* P_Opt_Const_Init */);
       t[6] = compile(P(6), depth+1 /* P_RESTOFOWNDEC */);
       return t[0] = P_mktuple(P_OWNDEC, alt, 6/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "array" <ARRAYFORMAT> <DECLNAME> <ALIAS> <BPAIR> <CONSTLIST>;
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_ARRAYFORMAT */);
       t[3] = compile(P(3), depth+1 /* P_DECLNAME */);
       t[4] = compile(P(4), depth+1 /* P_ALIAS */);
       t[5] = compile(P(5), depth+1 /* P_BPAIR */);
       t[6] = compile(P(6), depth+1 /* P_CONSTLIST */);
       return t[0] = P_mktuple(P_OWNDEC, alt, 6/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFOWNDEC> =
   case P_RESTOFOWNDEC:
#ifdef IN_PARSER

  if (alt == 0) {
    // only for formatting... compile(P(2), depth+1); // <READLINEP>
    compile(P(3), depth+1); // <DECLNAME>
    compile(P(4), depth+1); // <ALIAS>
    (void)Declaration(depth+1, FALSE /* A, B, C form not allowed */); //codegen("/*M %s:%d*/",__FILE__,__LINE__);
    compile(P(5), depth+1); // <Opt_Const_Init>
    codegen("; ");
    
    compile(P(6), depth+1); //<RESTOFOWNDEC>
  } else if (alt == 1) {
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    ',' <READLINEP> <DECLNAME> <ALIAS> <Opt_Const_Init> <RESTOFOWNDEC>,
       t[1] = wlit(P(1) /*, L',' */);
       t[2] = compile(P(2), depth+1 /* P_READLINEP */);
       t[3] = compile(P(3), depth+1 /* P_DECLNAME */);
       t[4] = compile(P(4), depth+1 /* P_ALIAS */);
       t[5] = compile(P(5), depth+1 /* P_Opt_Const_Init */);
       t[6] = compile(P(6), depth+1 /* P_RESTOFOWNDEC */);
       return t[0] = P_mktuple(P_RESTOFOWNDEC, alt, 6/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFOWNDEC, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<XOWN> =
   case P_XOWN:
#ifdef IN_PARSER

  switch (alt) {
  case 0: Area = OWN;                    break;
  case 1: Area = EXTDATA;                break;
  case 2: Area = EXTDATA;  Spec = SPEC;  break;
  case 3: Area = CONSTANT;               break;
  case 4: Area = CONSTANT;               break;
  }
  if (debug_declarations > 1) fprintf(stderr, "[Area=%d]", Area );
  return -1;

#endif
     if (alt == 0)               {  //\\    "own",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_XOWN, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    "external",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_XOWN, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 2)        {  //\\    "extrinsic",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_XOWN, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 3)        {  //\\    "constant",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_XOWN, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "const";
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_XOWN, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Opt_Const_Init> =
   case P_Opt_Const_Init:
#ifdef IN_PARSER

  if (alt == 0) {
    int SaveOperBottom = OperStack_bottom; OperStack_bottom = OperStack_nextfree;
    int SaveDataBottom = DataStack_bottom; DataStack_bottom = DataStack_nextfree;
    compile(P(2), depth+1);
    compile(P(3), depth+1);
    compile(P(4), depth+1);
    t[1] = ExPop();
    codegen(" = ");
    generate_c(t[1], depth+1);
    t[2] = -1;
    DataStack_bottom = SaveDataBottom; OperStack_bottom = SaveOperBottom;
    return -1; // t[0] = MkInit(AST_INITIALISER, /*alt*/0, /*count*/2, t);
  }

#endif
     if (alt == 0)               {  //\\    '=' <UOP> <COPERAND> <RESTOFCEXPR>,
       t[1] = wlit(P(1) /*, L'=' */);
       t[2] = compile(P(2), depth+1 /* P_UOP */);
       t[3] = compile(P(3), depth+1 /* P_COPERAND */);
       t[4] = compile(P(4), depth+1 /* P_RESTOFCEXPR */);
       return t[0] = P_mktuple(P_Opt_Const_Init, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_Opt_Const_Init, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<REPFACT> =
   case P_REPFACT:
#ifdef IN_PARSER
  //  <---------------------------------------------------------------- FIX!  TO DO
  // TO DO.

#endif
     if (alt == 0)               {  //\\    '(' <STAROREXPR> ')',
       t[1] = wlit(P(1) /*, L'(' */);
       t[2] = compile(P(2), depth+1 /* P_STAROREXPR */);
       t[3] = wlit(P(3) /*, L')' */);
       return t[0] = P_mktuple(P_REPFACT, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_REPFACT, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<CONSTLISTITEM> =
   case P_CONSTLISTITEM:
#ifdef IN_PARSER

  {
    int SaveOperBottom = OperStack_bottom; OperStack_bottom = OperStack_nextfree;
    int SaveDataBottom = DataStack_bottom; DataStack_bottom = DataStack_nextfree;
    compile(P(1), depth+1);
    compile(P(2), depth+1);
    compile(P(3), depth+1);

// TO DO: these are crashing with an array bound exceeded:

    if (P_alt(P(4)) == 0) { // initialiser includes a repeat count:       // P<REPFACT>          = '('<STAROREXPR>')', ''
      t[1] = ExPop();

      //int Count = compile(P(4), depth+1);  // We need this as an actual number, not as a string representing an expression.
      //t[2] = ExPop();
      codegen("[ LOW ... HIGH ] = "); generate_c(t[2], depth+1);

      generate_c(t[1], depth+1);
    } else {
      t[1] = ExPop();
      generate_c(t[1], depth+1);
      t[2] = -1;
    }
    DataStack_bottom = SaveDataBottom; OperStack_bottom = SaveOperBottom;
    return t[0] = -1; // MkInit(AST_INITIALISER, /*alt*/0, /*count*/2, t);
  }

#endif
     {                              //\\    <UOP> <COPERAND> <RESTOFCEXPR> <REPFACT>;
     t[1] = compile(P(1), depth+1 /* P_UOP */);
     t[2] = compile(P(2), depth+1 /* P_COPERAND */);
     t[3] = compile(P(3), depth+1 /* P_RESTOFCEXPR */);
     t[4] = compile(P(4), depth+1 /* P_REPFACT */);
     return t[0] = P_mktuple(P_CONSTLISTITEM, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<CONSTLIST> =
   case P_CONSTLIST:
#ifdef IN_PARSER
  //  <----------------------- FIX!  TO DO
  if (alt == 0) {
    codegen(" = {"); if (P_alt(P(2)) == 0) codegen("\n"); // copy newline if present in original
    compile(P(3), depth+1);
    compile(P(4), depth+1);
    codegen("}");
    return -1;
  } else return -1;

#endif
     if (alt == 0)               {  //\\    '=' <READLINEP> <CONSTLISTITEM> <ROCL>,
       t[1] = wlit(P(1) /*, L'=' */);
       t[2] = compile(P(2), depth+1 /* P_READLINEP */);
       t[3] = compile(P(3), depth+1 /* P_CONSTLISTITEM */);
       t[4] = compile(P(4), depth+1 /* P_ROCL */);
       return t[0] = P_mktuple(P_CONSTLIST, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_CONSTLIST, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<ROCL> =
   case P_ROCL:
#ifdef IN_PARSER
  //  <----------------------- FIX!  TO DO
  if (alt == 0) {
    codegen(", "); if (P_alt(P(2)) == 0) codegen("\n"); // copy newline if present in original
    compile(P(3), depth+1);
    compile(P(4), depth+1);
    return -1;
  } else return -1;

#endif
     if (alt == 0)               {  //\\    ',' <READLINEP> <CONSTLISTITEM> <ROCL>,
       t[1] = wlit(P(1) /*, L',' */);
       t[2] = compile(P(2), depth+1 /* P_READLINEP */);
       t[3] = compile(P(3), depth+1 /* P_CONSTLISTITEM */);
       t[4] = compile(P(4), depth+1 /* P_ROCL */);
       return t[0] = P_mktuple(P_ROCL, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_ROCL, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<on_event_block> =
   case P_on_event_block:
#ifdef IN_PARSER

  // Shouldn't this allow %on %event * %start ???
  if (debug_compiler) fprintf(stderr, "[on event block]\n");
  codegen("if (_imp_onevent(");
  generate_c(compile(P(3),depth+1), depth+1);
  generate_c(compile(P(4),depth+1), depth+1);
  codegen(")) {\n");
  push_ctrl(FINISH);
  return -1;

#endif
     {                              //\\    "on" <PC_EVENTQ> <CEXPR> <RESTOFNLIST> "start" <S>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_PC_EVENTQ */);
     t[3] = compile(P(3), depth+1 /* P_CEXPR */);
     t[4] = compile(P(4), depth+1 /* P_RESTOFNLIST */);
     t[5] = wlit(P(5));
     t[6] = compile(P(6), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_on_event_block, alt, 6/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFNLIST> =
   case P_RESTOFNLIST:
#ifdef IN_PARSER

  if (alt == 0) {
    codegen(", ");
    generate_c(compile(P(2), depth+1), depth+1);
    compile(P(3), depth+1);
    compile(P(4), depth+1);
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    ',' <CEXPR> <RESTOFNLIST>,
       t[1] = wlit(P(1) /*, L',' */);
       t[2] = compile(P(2), depth+1 /* P_CEXPR */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFNLIST */);
       return t[0] = P_mktuple(P_RESTOFNLIST, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFNLIST, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<PC_EVENTQ> =
   case P_PC_EVENTQ:
#ifdef IN_PARSER
 return -1; 
#endif
     if (alt == 0)               {  //\\    "event",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_PC_EVENTQ, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_PC_EVENTQ, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Opt_EXPR> =
   case P_Opt_EXPR:
#ifdef IN_PARSER

  if (alt == 0) {
    codegen(", ");
    generate_c(compile(P(2), depth+1), depth+1);
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    ',' <EXPR>,
       t[1] = wlit(P(1) /*, L',' */);
       t[2] = compile(P(2), depth+1 /* P_EXPR */);
       return t[0] = P_mktuple(P_Opt_EXPR, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_Opt_EXPR, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFREPEAT> =
   case P_RESTOFREPEAT:
#ifdef IN_PARSER

  {
  int EXPECTED = pop_ctrl();
  if (EXPECTED != REPEAT && EXPECTED != REPEATUNTIL && EXPECTED != REPEATPUSHEDUNTIL) {
    fprintf(stderr, "\n* %%REPEAT not expected here (expecting %s)\n", ctrl_debug[EXPECTED]); exit(1);
  }

  if (EXPECTED == REPEATUNTIL) {
    // if this was a %cycle ... %repeat with a possible %until after it, the
    // %cycle could have been emitted as "do {" and this code must be either "} until (cond)" or "} while (1)"

    if (alt == 0) {
      if (debug_compiler) fprintf(stderr, "[until condition]\n");
      codegen("} until ");
      compile(P(2), depth+1);
      codegen(";");
    } else if (alt == 1) {
      codegen("} while (1);");
    }
  } else if (EXPECTED == REPEATPUSHEDUNTIL) {
    int SavedUntilCond = pop_ctrl(); // mildly dirty pushing both codes, and conditions, on the same stack...

    if (alt == 0) {
      fprintf(stderr, "? WARNING: Having an %%until at both ends of a %%cycle is a bit dodgy, don't you think?\n");
      // %until cond1 %cycle ... %repeat %until cond2?!
      codegen("} while (!");
      compile(P(2), depth+1);  // conds include the brackets
      codegen(" && !"); // or "||" ?
      compile(SavedUntilCond, depth+1);
      codegen(");");
    } else if (alt == 1) {
      // %until cond %cycle ... %repeat
      if (debug_compiler) fprintf(stderr, "[deferred condition from earlier until cycle]\n");
      codegen("} while (!");
      compile(SavedUntilCond, depth+1);
      codegen(");");
    }
  } else if (EXPECTED == REPEAT) {

    if (alt == 0) {
      fprintf(stderr, "* %%UNTIL is not allowed at the end of a %%WHILE or %%FOR cycle.\n"); exit(1);
    }
    codegen("}"); // no semicolon
  }
  return -1;
  }

#endif
     if (alt == 0)               {  //\\    "until" <TOP_LEVEL_CONDITION>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_TOP_LEVEL_CONDITION */);
       return t[0] = P_mktuple(P_RESTOFREPEAT, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFREPEAT, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<FINISHELSEQ> =
   case P_FINISHELSEQ:
#ifdef IN_PARSER

  {
    int EXPECTED = pop_ctrl();

    if (alt == 0) {
      if (debug_compiler) fprintf(stderr, "[FINISHELSEQ]\n");
      codegen(" else ");
    } else codegen("\n"); // following a %finish
  }
  // recurse on AFTERELSE  <----------------------------------------------------------------- FIX!  TO DO

#endif
     if (alt == 0)               {  //\\    "else" <AFTERELSE>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_AFTERELSE */);
       return t[0] = P_mktuple(P_FINISHELSEQ, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_FINISHELSEQ, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<AFTERELSE> =
   case P_AFTERELSE:
#ifdef IN_PARSER

  if (alt == 0) {
    if (debug_compiler) fprintf(stderr, "[afterelse: start]\n");
    push_ctrl(FINISH);
    codegen("{\n");
    return -1;
  } else if (alt == 1) {
    if (debug_compiler) fprintf(stderr, "[afterelse: if or unless <COND> start]\n");
    //push_ctrl(FINISHELSE);
    compile(P(1), depth+1);
    compile(P(2), depth+1);
    compile(P(3), depth+1);
    return -1;
  } else {
    if (debug_compiler) fprintf(stderr, "[afterelse: <UI>]\n");
    // recurse
  }
  // recursively handle alt 2  <------------------------------------------------------------- FIX!  TO DO

#endif
     if (alt == 0)               {  //\\    "start",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_AFTERELSE, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <PC_IU> <TOP_LEVEL_CONDITION> <RESTOFIU>,
       t[1] = compile(P(1), depth+1 /* P_PC_IU */);
       t[2] = compile(P(2), depth+1 /* P_TOP_LEVEL_CONDITION */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFIU */);
       return t[0] = P_mktuple(P_AFTERELSE, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <UI_BLOCK>;
       t[1] = compile(P(1), depth+1 /* P_UI_BLOCK */);
       return t[0] = P_mktuple(P_AFTERELSE, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<ELSEQ> =
   case P_ELSEQ:
#ifdef IN_PARSER

  if (alt == 0) {
    if (debug_compiler) fprintf(stderr, "[ELSEQ]\n");
    codegen(" else ");
    // recurse   <--------------------------------------------------------------------------- FIX!  TO DO
  }

#endif
     if (alt == 0)               {  //\\    "else" <AFTERELSE>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_AFTERELSE */);
       return t[0] = P_mktuple(P_ELSEQ, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_ELSEQ, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFIU> =
   case P_RESTOFIU:
#ifdef IN_PARSER

  if (alt < 2) {
    if (debug_compiler) fprintf(stderr, "[then start]\n");
    push_ctrl(FINISHELSE);
    codegen(" {\n");
    return -1;
  } else {
    if (debug_compiler) fprintf(stderr, "[then UI]\n");
    // recursively handle the rest   <--------------------------------------------------------- FIX!  TO DO
  }

#endif
     if (alt == 0)               {  //\\    "start",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_RESTOFIU, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    "then" "start",
       t[1] = wlit(P(1));
       t[2] = wlit(P(2));
       return t[0] = P_mktuple(P_RESTOFIU, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "then" <UI_BLOCK> <ELSEQ>;
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_UI_BLOCK */);
       t[3] = compile(P(3), depth+1 /* P_ELSEQ */);
       return t[0] = P_mktuple(P_RESTOFIU, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<SEX> =
   case P_SEX:
#ifdef IN_PARSER

  Linkage = alt+1;
  // %routine without one of the above is auto if nested but not sure what at external level if no %external keyword.
  if (debug_declarations > 1) fprintf(stderr, "[Linkage=%d]", Linkage);
  return -1;

#endif
     if (alt == 0)               {  //\\    "external",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_SEX, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    "system",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_SEX, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 2)        {  //\\    "dynamic",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_SEX, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 3)        {  //\\    "prim",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_SEX, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 4)        {  //\\    "perm",
       t[1] = wlit(P(1));
       return t[0] = P_mktuple(P_SEX, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_SEX, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RFSTMNT> =
   case P_RFSTMNT:
#ifdef IN_PARSER

  {

    // All that has been done prior to this is <INITDECS> and Object = RECORDFORMAT;

    int RecFmtVarIDX;  // a VarDecl index
    int RecFmtTypeIDX; // a TypeDecl index
    if (debug_compiler) fprintf(stderr, "[record format statement]\n");
    // Object = RECORDFORMAT; // already set in <record_format_declaration>
    if (alt == 0) {
      // "spec"<DECLNAME>
      Spec = SPEC;
      compile(P(2), depth+1); // set up the record format name
      RTag = DTag; // tag of record format name

      // Declaration() returns a VarDecl index, not a TypeDecl index!:
      RecFmtVarIDX  = Declaration(depth+1, FALSE /* A, B, C form not allowed */);  // RecordFormatIDX recfm
      RecFmtTypeIDX = VarDecl[RecFmtVarIDX].type;
      
      if (TypeDecl[RecFmtTypeIDX].recfm != -1) {
        fprintf(stderr, "? %%recordformat %ls is already defined.\n", Atom2WStr(DTag));
      }
      // We do not create the anonymous table just for the %spec - the absence (indicated by recfm == -1)
      // is how we know the spec exists.

      codegen("typedef struct "); PrintAtom(RTag); codegen(" "); PrintAtom(RTag); codegen(";\n");
      RTag = -1;
    } else {
      Spec = NO_SPEC;
      // <DECLNAME>'('<PUSHDECS><RFDEC><RESTOFRFDEC><ALTRFDEC><POPDECS>')'
      compile(P(1), depth+1); // set up the record format name
      RTag = DTag;

      // Declaration() returns a VarDecl index, not a TypeDecl index!:
      RecFmtVarIDX  = Declaration(depth+1, FALSE /* A, B, C form not allowed */);  // RecordFormatIDX recfm
      RecFmtTypeIDX = VarDecl[RecFmtVarIDX].type;
      if (TypeDecl[RecFmtTypeIDX].recfm != -1) {
        fprintf(stderr, "* %%recordformat %ls is already defined.\n", Atom2WStr(DTag));
      }
      if (TypeDecl[RecFmtTypeIDX].recfm == -1) {
        TypeDecl[RecFmtTypeIDX].recfm = anonymous_table(); // now prepare the container for the fields.
        RecFmTableIDX = TypeDecl[RecFmtTypeIDX].recfm;
      }

      // We have created a holder for the record format definition, which is probably added from within P<RFDEC>
      // Add fields with: add_entry_to_anonymous_table(RecFmTableIDX, Atom2WStr(DTag), VarIDX)


      codegen("typedef struct "); PrintAtom(RTag); codegen(" {\n");

      compile(P(3), depth+1); // <PUSHDECS>, also calls <INITDECS>

      // Get record fields
      compile(P(4), depth+1); // <RFDEC>           <-- this adds the field to the container
      compile(P(5), depth+1); // <RESTOFRFDEC>

      // %OR% alternative record format
      compile(P(6), depth+1); // <ALTRFDEC>
    
      compile(P(7), depth+1); // <POPDECS>
      codegen("} "); PrintAtom(RTag); codegen(";\n");
      RTag = -1; // Done compiling a recordformat

      // TO DO: The compiled %recordformat (currently in RecFmtTypeIDX) has to be added to scope "decl" by name
      // so that it can be found when a record of this format is declared.  (or scope "recordformat" if they are
      // allowed a separate namespace - I think Imp80 and Imp77 differ in this respect).   (Unless Declaration()
      // has already done this for us?)
    }
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    "spec" <DECLNAME>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_DECLNAME */);
       return t[0] = P_mktuple(P_RFSTMNT, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <DECLNAME> '(' <PUSHDECS> <RFDEC> <RESTOFRFDEC> <ALTRFDEC> <POPDECS> ')';
       t[1] = compile(P(1), depth+1 /* P_DECLNAME */);
       t[2] = wlit(P(2) /*, L'(' */);
       t[3] = compile(P(3), depth+1 /* P_PUSHDECS */);
       t[4] = compile(P(4), depth+1 /* P_RFDEC */);
       t[5] = compile(P(5), depth+1 /* P_RESTOFRFDEC */);
       t[6] = compile(P(6), depth+1 /* P_ALTRFDEC */);
       t[7] = compile(P(7), depth+1 /* P_POPDECS */);
       t[8] = wlit(P(8) /*, L')' */);
       return t[0] = P_mktuple(P_RFSTMNT, alt, 8/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RFREF> =
   case P_RFREF:
#ifdef IN_PARSER
 // <-- looks like an RFSTMNT must be for the variation: %record (%integer A,B) fred
  if (alt == 0) {
    // TO DO:
    // We set RecordTypeIDX to the VarIDX corresponding to the previously declared %recordformat '<VARNAME>' -
    // from that we get the 'recfm' field which is the index of the anonymous symbol table entry containing the fields.
    int VarnameTuple = compile(P(1), depth+1);
    RecordTypeIDX = P_P(VarnameTuple, 1);
    // (might have been preferable to invent a <FORMATNAME> rather than use <VARNAME> which returns an RVALUE tuple.)
  } else {
    fprintf(stderr, "* Inline record format references have not yet been implemented. You need to use a %%recordformat.\n");
    RecordTypeIDX = -1;
  }

#endif
     if (alt == 0)               {  //\\    <VARNAME>,
       t[1] = compile(P(1), depth+1 /* P_VARNAME */);
       return t[0] = P_mktuple(P_RFREF, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <RFDEC> <RESTOFRFDEC> <ALTRFDEC>;
       t[1] = compile(P(1), depth+1 /* P_RFDEC */);
       t[2] = compile(P(2), depth+1 /* P_RESTOFRFDEC */);
       t[3] = compile(P(3), depth+1 /* P_ALTRFDEC */);
       return t[0] = P_mktuple(P_RFREF, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFRFDEC> =
   case P_RESTOFRFDEC:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[more record format declarations]\n");
  //compile(P(3), depth+1);  // <RFDEC>
  //compile(P(4), depth+1);  // <RESTOFRFDEC>
  //return -1;

#endif
     if (alt == 0)               {  //\\    ',' <READLINEP> <RFDEC> <RESTOFRFDEC>,
       t[1] = wlit(P(1) /*, L',' */);
       t[2] = compile(P(2), depth+1 /* P_READLINEP */);
       t[3] = compile(P(3), depth+1 /* P_RFDEC */);
       t[4] = compile(P(4), depth+1 /* P_RESTOFRFDEC */);
       return t[0] = P_mktuple(P_RESTOFRFDEC, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFRFDEC, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RFDEC> =
   case P_RFDEC:
#ifdef IN_PARSER

  // I think that the second form is for a nested record declaration
  if (debug_compiler) fprintf(stderr, "[record format declaration (RFDEC)]\n");
  // <-------------------------------- DROP THROUGH AND COMPILE
  if (alt == 0) {
    compile(P(1), depth+1);
    Object = VAR;
    Area = FIELD; // whatever the parent record's area may be once used in a record declaration
    compile(P(2), depth+1);
    compile(P(3), depth+1);
    int FieldVarIDX = Declaration(depth+1, FALSE /* A, B, C form not allowed */);
    if (RecFmTableIDX != -1) {
      add_entry_to_anonymous_table(RecFmTableIDX, Atom2WStr(DTag), FieldVarIDX);
    } else {
      fprintf(stderr, "* no currently open %%recordformat into which field \"%ls\" can be added.\n", Atom2WStr(DTag));
    }
    codegen(";\n");
    return FieldVarIDX;   // TO DO: both these returns may need to be wrapped in some sort of AST list.  AST_RECORDFORMAT? AST_FIELD?
  } else {
    int FieldVarTuple = compile(P(2), depth+1);
    // TO DO: compile(P(3), depth+1);
    // TO DO: compile(P(4), depth+1);
    return FieldVarTuple; // TO DO
  }

#endif
     if (alt == 0)               {  //\\    <INITDECS> <XTYPE> <RFELMNT>,
       t[1] = compile(P(1), depth+1 /* P_INITDECS */);
       t[2] = compile(P(2), depth+1 /* P_XTYPE */);
       t[3] = compile(P(3), depth+1 /* P_RFELMNT */);
       return t[0] = P_mktuple(P_RFDEC, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    '(' <RFDEC> <RESTOFRFDEC> <ALTRFDEC> ')';
       t[1] = wlit(P(1) /*, L'(' */);
       t[2] = compile(P(2), depth+1 /* P_RFDEC */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFRFDEC */);
       t[4] = compile(P(4), depth+1 /* P_ALTRFDEC */);
       t[5] = wlit(P(5) /*, L')' */);
       return t[0] = P_mktuple(P_RFDEC, alt, 5/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RFELMNT> =
   case P_RFELMNT:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[record format element]\n");
  // a declaration of a record field - more restrictive in what it can be compared to regular declarations
  // <-------------------------------- DROP THROUGH AND COMPILE

#endif
     if (alt == 0)               {  //\\    <Opt_AN_N_type> <DECLNAME> <DECLNAMES>,
       t[1] = compile(P(1), depth+1 /* P_Opt_AN_N_type */);
       t[2] = compile(P(2), depth+1 /* P_DECLNAME */);
       t[3] = compile(P(3), depth+1 /* P_DECLNAMES */);
       return t[0] = P_mktuple(P_RFELMNT, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    "array" <ADECLN>;
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_ADECLN */);
       return t[0] = P_mktuple(P_RFELMNT, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<ALTRFDEC> =
   case P_ALTRFDEC:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[alternative record format declaration]\n");
  // <-------------------------------- DROP THROUGH AND COMPILE

#endif
     if (alt == 0)               {  //\\    "or" <RFDEC> <RESTOFRFDEC> <ALTRFDEC>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_RFDEC */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFRFDEC */);
       t[4] = compile(P(4), depth+1 /* P_ALTRFDEC */);
       return t[0] = P_mktuple(P_ALTRFDEC, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_ALTRFDEC, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<ASM> =
   case P_ASM:
#ifdef IN_PARSER
 return -1; 
#endif
     if (alt == 0)               {  //\\    <!semi> <nl> <eof> «.» <ASM>,
       t[1] = -1; /* ignore negative guard */;
       t[2] = wlit(P(2) /*, L"nl" */);
       t[3] = wlit(P(3) /*, L"eof" */);
       t[4] = wlit(P(4));
       t[5] = compile(P(5), depth+1 /* P_ASM */);
       return t[0] = P_mktuple(P_ASM, alt, 5/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_ASM, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Call_or_Assign_AUI> =
   case P_Call_or_Assign_AUI:
#ifdef IN_PARSER

  // The other call to <VAR> is as an operand in an EXPR where it is pushed
  // onto the TORP stack in order to have operator precedence applied to the
  // EXPR as a whole.  The call to <VAR> actually just puts it on the
  // stack and returns -1.  So to get a <VAR> here we don't look at the
  // *result* of calling <VAR> but rather we pop the unprocessed item off
  // the stack that was placed there by <VAR>.

  compile(P(1), depth+1); // Pushes VAR

  Op_or_Data TOSPop = DataStack(--DataStack_nextfree); ; // NOT ExPop(). We're not applying precedence to a tree.
  if (TOSPop.type != 'D') { fprintf(stderr, "** Internal error in %s at line %d\n", __FILE__, __LINE__); exit(1); }
  int Var = TOSPop.idx;

  //Diagnose("Assignment or call: ", Var,0, debug_declarations);

  if (alt == 0) { // <VAR><ASSOP><EXPR>  - Assignment
    int Assop = compile(P(2), depth+1);
    int Expr = compile(P(3), depth+1);
    int Assign = Mk_AST_assignment(Var, Assop, Expr, depth);
    generate_c(Assign, depth+1);
  } else { // <VAR>  = Call
    generate_c(Var, depth+1);
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    <VAR> <ASSOP> <EXPR>,
       t[1] = compile(P(1), depth+1 /* P_VAR */);
       t[2] = compile(P(2), depth+1 /* P_ASSOP */);
       t[3] = compile(P(3), depth+1 /* P_EXPR */);
       return t[0] = P_mktuple(P_Call_or_Assign_AUI, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <VAR>;
       t[1] = compile(P(1), depth+1 /* P_VAR */);
       return t[0] = P_mktuple(P_Call_or_Assign_AUI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<SWITCHIDX> =
   case P_SWITCHIDX:
#ifdef IN_PARSER

  if (alt == 0) {
    return compile(P(2), depth+1); // AST_EXPR tuple.
  } else {
    return -1;
  }

#endif
     if (alt == 0)               {  //\\    '(' <EXPR> ')',
       t[1] = wlit(P(1) /*, L'(' */);
       t[2] = compile(P(2), depth+1 /* P_EXPR */);
       t[3] = wlit(P(3) /*, L')' */);
       return t[0] = P_mktuple(P_SWITCHIDX, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_SWITCHIDX, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Goto> =
   case P_Goto:
#ifdef IN_PARSER
  // CHANGED FROM <APP> TO NEW <SWITCHIDX> to restrict to *one* index.
                                              // changed <VARNAME> to <TAG> to inhibit NAME NOT SET errors
  if (debug_compiler) fprintf(stderr, "[go to]\n");
  int SWIdx = compile(P(4), depth+1);
  if (SWIdx != -1) {
    // switch label destination
    codegen("goto_switch(");
    //generate_c(compile(P(3), depth+1), depth+1);
    int SwitchName = compile(P(3), depth+1); // VARNAME
    if (P_P(SwitchName,1) == -1) {
      codegen("* ERROR: %%switch %ls NOT DECLARED\n", wSVTag); // exit(1);
    }
    codegen("%ls, ", wSVTag);
    generate_c(SWIdx, depth+1);  // If the constant is < 0 we want to output "M<const>" instead of "-<const>"
    codegen(")");
    //Diagnose("Switch index: ", SWIdx, 0, TRUE);
  } else {
    // plain goto
    codegen("goto ");
    //generate_c(compile(P(3), depth+1), depth+1);
    int Label = compile(P(3), depth+1);
    if (P_P(Label,1) == -1) {
      // Simple Label has not yet been defined.  Add it to the name table as a %spec so it can be faulted if missing at the end of the program.

      // Since I'm getting a NAME NOT SET start turn from lunarlander.imp, I suspect the check for a name
      // in the symtab stuff is too low-level as it should not be faulting unknown labels.
    }
    codegen("%ls", wSVTag);
  }
  return -1;

#endif
     {                              //\\    '-' '>' <TAG> <SWITCHIDX>;
     t[1] = wlit(P(1) /*, L'-' */);
     t[2] = wlit(P(2) /*, L'>' */);
     t[3] = compile(P(3), depth+1 /* P_TAG */);
     t[4] = compile(P(4), depth+1 /* P_SWITCHIDX */);
     return t[0] = P_mktuple(P_Goto, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<return> =
   case P_return:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[return]\n");
  codegen("return");
  return -1;

#endif
     {                              //\\    "return";
     t[1] = wlit(P(1));
     return t[0] = P_mktuple(P_return, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<result> =
   case P_result:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[result]\n");

  codegen("return ");
  // Assop will modify the result, possibly with a cast (for <-) or removing an indirection (for ==)

  // TO DO: possibly needs a new AST_RESULT tuple similar to AST_ASSIGN

  // We need to determine the result type of this function, and use it in the AST_RESULT/AST_ASSIGN tuple to
  // cause the appropriate cast if needed.

  int Expr = compile(P(3), depth+1);
  int Type = P_TYPEINFO(Expr);   // P_TYPEINFO(X) is the hidden type field of any AST expression
  //Describe_Type(Type);
  
  generate_c(Expr, depth+1);

  return -1;

#endif
     {                              //\\    "result" <ASSOP> <EXPR>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_ASSOP */);
     t[3] = compile(P(3), depth+1 /* P_EXPR */);
     return t[0] = P_mktuple(P_result, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<monitor_AUI> =
   case P_monitor_AUI:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[print diagnostics]\n");
  codegen("assert(_IMP_MONITOR_)"); // not ideal - assert will cause an exit from the program - %monitor should not.
  return -1;

#endif
     {                              //\\    "monitor";
     t[1] = wlit(P(1));
     return t[0] = P_mktuple(P_monitor_AUI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<stop> =
   case P_stop:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[stop program]\n");
  codegen("exit(0)");
  return -1;

#endif
     {                              //\\    "stop";
     t[1] = wlit(P(1));
     return t[0] = P_mktuple(P_stop, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<signal> =
   case P_signal:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[signal event]\n");
  codegen("_imp_signal(");
  generate_c(compile(P(3), depth+1), depth+1);
  generate_c(compile(P(4), depth+1), depth+1);
  codegen(")");
  return -1;

#endif
     {                              //\\    "signal" <PC_EVENTQ> <CEXPR> <Opt_EXPR>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_PC_EVENTQ */);
     t[3] = compile(P(3), depth+1 /* P_CEXPR */);
     t[4] = compile(P(4), depth+1 /* P_Opt_EXPR */);
     return t[0] = P_mktuple(P_signal, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<exit> =
   case P_exit:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[exit from cycle]\n");
  codegen("break");
  return -1;

#endif
     {                              //\\    "exit";
     t[1] = wlit(P(1));
     return t[0] = P_mktuple(P_exit, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<continue> =
   case P_continue:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[continue at end of cycle]\n");
  codegen("continue");
  return -1;

#endif
     {                              //\\    "continue";
     t[1] = wlit(P(1));
     return t[0] = P_mktuple(P_continue, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Unconditional_Instructions> =
   case P_Unconditional_Instructions:
#ifdef IN_PARSER

  if (alt == 0) {
    compile(P(1), depth+1); // <UI> must be encapsulated in a {...} block if more than 1 statement
    compile(P(2), depth+1);
  } else if (alt == 1) { // PC_IU is just "if" or "unless"
    compile(P(2), depth+1);
    compile(P(3), depth+1);
    compile(P(1), depth+1);
    compile(P(4), depth+1);
  } else if (alt == 2) { // but PC_WUF is a full while/until/for condition
    if (P_alt(P(2)) == 0) {
      compile(P(2), depth+1); // "while"<TOP_LEVEL_CONDITION>,
      compile(P(1), depth+1); // <UI_BLOCK>
    } else if (P_alt(P(2)) == 1) {
      codegen("do ");
      compile(P(1), depth+1); // <UI_BLOCK>
      compile(P(2), depth+1); // "until"<TOP_LEVEL_CONDITION>,
    } else {
      compile(P(2), depth+1); // "for"<CYCPARM> {
      compile(P(1), depth+1); // <UI_BLOCK>
    }
    compile(P(3), depth+1);
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    <UI_BLOCK> <S>,
       t[1] = compile(P(1), depth+1 /* P_UI_BLOCK */);
       t[2] = compile(P(2), depth+1 /* P_S */);
       return t[0] = P_mktuple(P_Unconditional_Instructions, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <UI_BLOCK> <PC_IU> <TOP_LEVEL_CONDITION> <S>,
       t[1] = compile(P(1), depth+1 /* P_UI_BLOCK */);
       t[2] = compile(P(2), depth+1 /* P_PC_IU */);
       t[3] = compile(P(3), depth+1 /* P_TOP_LEVEL_CONDITION */);
       t[4] = compile(P(4), depth+1 /* P_S */);
       return t[0] = P_mktuple(P_Unconditional_Instructions, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <UI_BLOCK> <PC_WUF> <S>;
       t[1] = compile(P(1), depth+1 /* P_UI_BLOCK */);
       t[2] = compile(P(2), depth+1 /* P_PC_WUF */);
       t[3] = compile(P(3), depth+1 /* P_S */);
       return t[0] = P_mktuple(P_Unconditional_Instructions, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<UI> =
   case P_UI:
#ifdef IN_PARSER

  if (alt == 0) {
    compile(P(1), depth+1); codegen("; ");
    compile(P(2), depth+1);
    return -1;
  } else {
    compile(P(1), depth+1);
    codegen("; ");
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    <NONFINAL_UI> <AUI>,
       t[1] = compile(P(1), depth+1 /* P_NONFINAL_UI */);
       t[2] = compile(P(2), depth+1 /* P_AUI */);
       return t[0] = P_mktuple(P_UI, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <NONFINAL_UI>,
       t[1] = compile(P(1), depth+1 /* P_NONFINAL_UI */);
       return t[0] = P_mktuple(P_UI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <FINAL_UI>;
       t[1] = compile(P(1), depth+1 /* P_FINAL_UI */);
       return t[0] = P_mktuple(P_UI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<AUI> =
   case P_AUI:
#ifdef IN_PARSER

#endif
     {                              //\\    "and" <UI>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_UI */);
     return t[0] = P_mktuple(P_AUI, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<UI_BLOCK> =
   case P_UI_BLOCK:
#ifdef IN_PARSER

  if (alt == 0) {
    codegen("{ ");
    compile(P(1), depth+1); codegen("; ");
    compile(P(2), depth+1);
    codegen(" }");
    return -1;
  } else {
    compile(P(1), depth+1); codegen("; ");
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    <NONFINAL_UI> <AUI>,
       t[1] = compile(P(1), depth+1 /* P_NONFINAL_UI */);
       t[2] = compile(P(2), depth+1 /* P_AUI */);
       return t[0] = P_mktuple(P_UI_BLOCK, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <NONFINAL_UI>,
       t[1] = compile(P(1), depth+1 /* P_NONFINAL_UI */);
       return t[0] = P_mktuple(P_UI_BLOCK, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <FINAL_UI>;
       t[1] = compile(P(1), depth+1 /* P_FINAL_UI */);
       return t[0] = P_mktuple(P_UI_BLOCK, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<NONFINAL_UI> =
   case P_NONFINAL_UI:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <Call_or_Assign_AUI>,
       t[1] = compile(P(1), depth+1 /* P_Call_or_Assign_AUI */);
       return t[0] = P_mktuple(P_NONFINAL_UI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <monitor_AUI>;
       t[1] = compile(P(1), depth+1 /* P_monitor_AUI */);
       return t[0] = P_mktuple(P_NONFINAL_UI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<FINAL_UI> =
   case P_FINAL_UI:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <Goto>,
       t[1] = compile(P(1), depth+1 /* P_Goto */);
       return t[0] = P_mktuple(P_FINAL_UI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <return>,
       t[1] = compile(P(1), depth+1 /* P_return */);
       return t[0] = P_mktuple(P_FINAL_UI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 2)        {  //\\    <result>,
       t[1] = compile(P(1), depth+1 /* P_result */);
       return t[0] = P_mktuple(P_FINAL_UI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 3)        {  //\\    <stop>,
       t[1] = compile(P(1), depth+1 /* P_stop */);
       return t[0] = P_mktuple(P_FINAL_UI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 4)        {  //\\    <signal>,
       t[1] = compile(P(1), depth+1 /* P_signal */);
       return t[0] = P_mktuple(P_FINAL_UI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 5)        {  //\\    <exit>,
       t[1] = compile(P(1), depth+1 /* P_exit */);
       return t[0] = P_mktuple(P_FINAL_UI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <continue>;
       t[1] = compile(P(1), depth+1 /* P_continue */);
       return t[0] = P_mktuple(P_FINAL_UI, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<More_STATEMENTS> =
   case P_More_STATEMENTS:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <STATEMENT> <More_STATEMENTS>,
       t[1] = compile(P(1), depth+1 /* P_STATEMENT */);
       t[2] = compile(P(2), depth+1 /* P_More_STATEMENTS */);
       return t[0] = P_mktuple(P_More_STATEMENTS, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_More_STATEMENTS, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<STATEMENTS> =
   case P_STATEMENTS:
#ifdef IN_PARSER

#endif
     {                              //\\    <STATEMENT> <More_STATEMENTS> <eof>;
     t[1] = compile(P(1), depth+1 /* P_STATEMENT */);
     t[2] = compile(P(2), depth+1 /* P_More_STATEMENTS */);
     t[3] = wlit(P(3) /*, L"eof" */);
     return t[0] = P_mktuple(P_STATEMENTS, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Labels> =
   case P_Labels:
#ifdef IN_PARSER

  if (debug_compiler || debug_declarations) fprintf(stderr, "[label]\n");

  // MAYBE USE <VARNAME> RATHER THAN <DECLNAME> and handle declaration here rather than in Declaration(depth+1, ) since labels
  // need to be handled a bit differently from variables?  Yeah, making that change... And indeed later changed <VARNAME> to
  // <TAG> because varname caused a NAME NOT SET error

  // Note that labels are currently *not* having a ';' added after them.  This may be OK but my previous imptoc
  // inserted them and I suspect for a reason, though right now I can't remember what that reason might have been.
  // I'll add the semicolons back in later if some circumstance arises where the lack of them causes problems.

  int LabelTag;
  int SwitchName = compile(P(1), depth+1); LabelTag = VTag;
  if (alt < 2 && P_P(SwitchName, 1) == -1) {
    fprintf(stderr, "* ERROR: %%switch %ls NOT DECLARED\n", wSVTag); // exit(1);
  //} else if (alt < 2 && P_P(SwitchName, 1) != -1) {
  //  fprintf(stderr, "* ERROR: SWITCH LABEL %d SET TWICE\n", TO DO!); // exit(1);
  } else if (alt == 2 && P_P(SwitchName, 1) != -1) {
    fprintf(stderr, "* ERROR: LABEL %ls SET TWICE\n", wSVTag); // exit(1);
  }
  if (alt == 0) {
    Object = VAR; // SWITCHDEFN;  no, SWITCHDEFN is for %switch fred(1:10)
    Basetype = SWITCHLABEL;
    codegen("%s_default:", Atom2Str(LabelTag));
  }  else if (alt == 1) {
    Object = VAR; // SWITCHDEFN;
    Basetype = SWITCHLABEL;
    codegen("%s_", Atom2Str(LabelTag));
    Cpool_nextfree = 0; // Reset
    Start_Divert_C_to_Cpool();
    int len = generate_c(compile(P(3), depth+1), depth+1); // NO: needs to be a decimal constant with special handling for negative numbers.
    End_Divert_C_to_Cpool();
    if (Cpool(0) == '-') {
      codegen("M%s", &Cpool(1));
    } else {
      codegen("%s", &Cpool(0));
    }
    Cpool_nextfree = 0; // return unused space.
    codegen(":");
  } else {

    // TO DO: See lunarlander.imp - I'm getting a NAME NOT SET with "start turn"

    Object = VAR; // LABELDEFN; no, LABELDEFN is for %label Fred
    Basetype = JUMPLABEL;
    codegen("%s: ", Atom2Str(LabelTag));  // TO DO: This outputs a ' ' after the tag.  We should suppress the space at the
                                                 // point where it was added and add any needed spaces at the point of instantiation.
  }
  // PENDING! (TO DO) - the declaration code for actual labels (rather than declaration of labels) is currently
  // non-existent and calling Declaration(depth+1, ) below outputs random crap.  I'm not 100% sure that I should even
  // be using the 'Declaration(depth+1, )' method to handle the labels themselves.  Maybe it would be more sensible to
  // put that code here in the grammar where the labels are instanced.
  
  // TO DO: (void)Declaration(depth+1, FALSE /* A, B, C form not allowed */);
  
  return -1;


#endif
     if (alt == 0)               {  //\\    <TAG> '(' '*' ')' ':' <COLON>,
       t[1] = compile(P(1), depth+1 /* P_TAG */);
       t[2] = wlit(P(2) /*, L'(' */);
       t[3] = wlit(P(3) /*, L'*' */);
       t[4] = wlit(P(4) /*, L')' */);
       t[5] = wlit(P(5) /*, L':' */);
       t[6] = -1; /* semantic procedure COLON */;
       return t[0] = P_mktuple(P_Labels, alt, 6/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <TAG> '(' <EXPR> ')' ':' <COLON>,
       t[1] = compile(P(1), depth+1 /* P_TAG */);
       t[2] = wlit(P(2) /*, L'(' */);
       t[3] = compile(P(3), depth+1 /* P_EXPR */);
       t[4] = wlit(P(4) /*, L')' */);
       t[5] = wlit(P(5) /*, L':' */);
       t[6] = -1; /* semantic procedure COLON */;
       return t[0] = P_mktuple(P_Labels, alt, 6/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <TAG> ':' <COLON>;
       t[1] = compile(P(1), depth+1 /* P_TAG */);
       t[2] = wlit(P(2) /*, L':' */);
       t[3] = -1; /* semantic procedure COLON */;
       return t[0] = P_mktuple(P_Labels, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<If_or_Unless> =
   case P_If_or_Unless:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[if or unless]\n");
  //  <-------------------------------------------------------------------------- FIX!  TO DO

#endif
     {                              //\\    <PC_IU> <TOP_LEVEL_CONDITION> <RESTOFIU> <S>;
     t[1] = compile(P(1), depth+1 /* P_PC_IU */);
     t[2] = compile(P(2), depth+1 /* P_TOP_LEVEL_CONDITION */);
     t[3] = compile(P(3), depth+1 /* P_RESTOFIU */);
     t[4] = compile(P(4), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_If_or_Unless, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<Opt_CYCPARM> =
   case P_Opt_CYCPARM:
#ifdef IN_PARSER

  if (alt == 0) {
    push_ctrl(REPEAT); // for loop
    compile(P(1), depth+1);
  } else if (alt == 1) {
    push_ctrl(REPEATUNTIL); // plain %cycle
    codegen("do ");
  }
  return -1;

#endif
     if (alt == 0)               {  //\\    <CYCPARM>,
       t[1] = compile(P(1), depth+1 /* P_CYCPARM */);
       return t[0] = P_mktuple(P_Opt_CYCPARM, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_Opt_CYCPARM, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<start_of_cycle> =
   case P_start_of_cycle:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[cycle]\n");

  if (alt == 0) {

    compile(P(2), depth+1);  // if <Opt_CYCPARM> was empty, we should push_ctrl(REPEATUNTIL);, otherwise...
  } else {

    if (P_alt(P(1)) == 1) { // %until
      fprintf(stderr, "? Please recode the source file so that loops with \"%%until <cond> %%cycle ... %%repeat\""
                      "are replaced by \"%%cycle ... %%repeat %%until <cond>\"");
      // In the meantime we just lose the condition at the top and hopefully at some point in the near
      // future I'll have stacked it and will be able to pop it off the stack on the %repeat ...
      codegen("/* Deferred: "); // Because compile() currently outputs the condition as well as returning it as a tuple.
      int UntilCond =  compile(P(1), depth+1);
      codegen(" */");
      codegen("\ndo ");
      push_ctrl(UntilCond);               // Save the condition for testing at the end of the loop
      push_ctrl(REPEATPUSHEDUNTIL);       // %until not allowed after %repeat
    } else {
      push_ctrl(REPEAT);       // %until not allowed after %repeat
      compile(P(1), depth+1);
    }
  }
  codegen("{\n");
  return -1;

#endif
     if (alt == 0)               {  //\\    "cycle" <Opt_CYCPARM> <S>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_Opt_CYCPARM */);
       t[3] = compile(P(3), depth+1 /* P_S */);
       return t[0] = P_mktuple(P_start_of_cycle, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <PC_WUF> "cycle" <S>;
       t[1] = compile(P(1), depth+1 /* P_PC_WUF */);
       t[2] = wlit(P(2));
       t[3] = compile(P(3), depth+1 /* P_S */);
       return t[0] = P_mktuple(P_start_of_cycle, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<end_of_cycle> =
   case P_end_of_cycle:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[repeat]\n");

  // <RESTOFREPEAT> handles the control stack and whether a %until is allowed
  compile(P(2), depth+1);
  compile(P(3), depth+1);
  return -1;

#endif
     {                              //\\    "repeat" <RESTOFREPEAT> <S>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_RESTOFREPEAT */);
     t[3] = compile(P(3), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_end_of_cycle, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<regular_declaration> =
   case P_regular_declaration:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[auto declaration]\n");
  compile(P(1), depth+1); Object = VAR; Linkage = AUTO; Proc = NONE;
  compile(P(2), depth+1);
  compile(P(3), depth+1);
  compile(P(4), depth+1);
  return -1;

#endif
     {                              //\\    <INITDECS> <XTYPE> <DECLN> <S>;
     t[1] = compile(P(1), depth+1 /* P_INITDECS */);
     t[2] = compile(P(2), depth+1 /* P_XTYPE */);
     t[3] = compile(P(3), depth+1 /* P_DECLN */);
     t[4] = compile(P(4), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_regular_declaration, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<proc_declaration> =
   case P_proc_declaration:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[procedure declaration]\n");

  compile(P(1), depth+1);  Object = CODE;

  compile(P(2), depth+1); // SEX
  compile(P(3), depth+1); // RT
  compile(P(4), depth+1); // Set up Spec and flag for <DOWN?>
  compile(P(6), depth+1); // ALIAS
  compile(P(5), depth+1); // DECLNAME reordered so name handled after params set up
                          // (but work to be done to associate param list with Rt)

  ParentVarIDX = Declaration(depth+1, FALSE /* A, B, C form not allowed */); //codegen("/*P %s:%d*/",__FILE__,__LINE__); // BUT TO DO: NEEDS MORE WORK
  ParentTypeIDX = VarDecl[ParentVarIDX].type;
  
  codegen("(");
  push_scope_level(); // aka <DOWN>.  popped at end of param list if a spec, otherwise on %end of routine. Ensures params are like locals of procedure.
  compile(P(7), depth+1); // FPP (or void if none)
  codegen(")");
  if (Spec == SPEC) {
    pop_scope_level(); // aka <UP>
    codegen(";\n");
  } else {
    // pop scope level on %end of procedure.
    // Parameters have been declared as if within procedure body.
    codegen(" {\n");
  }
  return -1;

#endif
     {                              //\\    <INITDECS> <SEX> <RT> <Opt_RtFnMapSpec> <DECLNAME> <ALIAS> <FPP> <S>;
     t[1] = compile(P(1), depth+1 /* P_INITDECS */);
     t[2] = compile(P(2), depth+1 /* P_SEX */);
     t[3] = compile(P(3), depth+1 /* P_RT */);
     t[4] = compile(P(4), depth+1 /* P_Opt_RtFnMapSpec */);
     t[5] = compile(P(5), depth+1 /* P_DECLNAME */);
     t[6] = compile(P(6), depth+1 /* P_ALIAS */);
     t[7] = compile(P(7), depth+1 /* P_FPP */);
     t[8] = compile(P(8), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_proc_declaration, alt, 8/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<own_or_external_declaration> =
   case P_own_or_external_declaration:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[own/external/const declaration]\n");

  compile(P(1), depth+1);   Object = VAR;

  compile(P(2), depth+1);
  compile(P(3), depth+1);
  compile(P(4), depth+1);
  compile(P(5), depth+1);
  return -1;

#endif
     {                              //\\    <INITDECS> <XOWN> <XTYPE> <OWNDEC> <S>;
     t[1] = compile(P(1), depth+1 /* P_INITDECS */);
     t[2] = compile(P(2), depth+1 /* P_XOWN */);
     t[3] = compile(P(3), depth+1 /* P_XTYPE */);
     t[4] = compile(P(4), depth+1 /* P_OWNDEC */);
     t[5] = compile(P(5), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_own_or_external_declaration, alt, 5/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<record_format_declaration> =
   case P_record_format_declaration:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[record format declaration]\n");
  compile(P(1), depth+1);
  // IsFormat = IS_FORMAT; ... deprecated
  Object = RECORDFORMAT;
  compile(P(4), depth+1);
  return -1;

#endif
     {                              //\\    <INITDECS> "record" "format" <RFSTMNT> <S>;
     t[1] = compile(P(1), depth+1 /* P_INITDECS */);
     t[2] = wlit(P(2));
     t[3] = wlit(P(3));
     t[4] = compile(P(4), depth+1 /* P_RFSTMNT */);
     t[5] = compile(P(5), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_record_format_declaration, alt, 5/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<various_ends> =
   case P_various_ends:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[end of something]\n");
  //  <-------------------------------------------------------------------------- FIX!  TO DO

#endif
     {                              //\\    "end" <ENDLIST> <S>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_ENDLIST */);
     t[3] = compile(P(3), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_various_ends, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<include_file> =
   case P_include_file:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[push an include file]\n");
  // TO DO: not handled in previous imptoc - it was assumed that incuded files could be translated separately
  // but that is not correct.  Compilation of include files depends on what has gone before.  So they have to
  // be translated in the context of the parent file, so as well as pushing the input file on the include stack,
  // we have to switch output to the .h.tmp version of the .inc file, and switch back to the current context on EOF
  // (the mechanics of handling include files was already worked out for takeon where .g files can contain I<...> )
  // Note that include files will probably be handled like C and allow a search path via a -I option.
  codegen("\n#include \"...\"\n");
  return -1;

#endif
     {                              //\\    "include" <CONST> <INCLUDE>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_CONST */);
     t[3] = -1; /* semantic procedure INCLUDE */;
     return t[0] = P_mktuple(P_include_file, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<begin_block> =
   case P_begin_block:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[begin block]\n");
  if (ctrl_depth() <= 0) {
    push_ctrl(ENDOFPROGRAM);
    codegen("\nint _imp_mainep(int _imp_argc, char **_imp_argv) {\n");
  } else {
    push_ctrl(END); // Also pushed at the start of a rt/fn/map
    codegen("\n{ /* %%begin block */\n");
  }
  compile(P(2), depth+1); // ARGH! This was missing and nested scopes were not being created!
  return -1;

#endif
     {                              //\\    "begin" <DOWN> <S>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_DOWN */);
     t[3] = compile(P(3), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_begin_block, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<ONESWDECL> =
   case P_ONESWDECL:
#ifdef IN_PARSER

  if (debug_declarations > 1) fprintf(stderr, "[one switch declaration]");
  // Will require *either* exbedded code at end of scope block with actual switch statement and gotos,
  // *or* we have to backpatch this declaration with assignment of an array of labels (in the style &&labname)
  // *or* we generate *all* labels at the point of declaration but output the unused ones at the end of
  // the scope block with a jump to the default if given, or an error message if not. (i.e. the BADSWITCH()
  // code from before)
  // We do at a minimum require a hook between closing a scope and executing pending code.

/*
  This is what the last iteration of imptoc did with switch declarations:

        static int Bip_sw;
        static void *Bip[40 / *999:1038* /] = {
            &&Bip_999,  &&Bip_1000, &&Bip_1001, &&Bip_1002, &&Bip_1003,
            &&Bip_1004, &&Bip_1005, &&Bip_1006, &&Bip_1007, &&Bip_1008,
            &&Bip_1009, &&Bip_1010, &&Bip_1011, &&Bip_1012, &&Bip_1013,
            &&Bip_1014, &&Bip_1015, &&Bip_1016, &&Bip_1017, &&Bip_1018,
            &&Bip_1019, &&Bip_1020, &&Bip_1021, &&Bip_1022, &&Bip_1023,
            &&Bip_1024, &&Bip_1025, &&Bip_1026, &&Bip_1027, &&Bip_1028,
            &&Bip_1029, &&Bip_1030, &&Bip_1031, &&Bip_1032, &&Bip_1033,
            &&Bip_1034, &&Bip_1035, &&Bip_1036, &&Bip_1037, &&Bip_1038,
        };

        goto *Bip[Bip_sw = (Item)-999];

or

        static int S_sw;
        static void *S[5 / *1:5* /] = {
            &&S_1, &&S_2, &&S_3, &&S_4, &&S_default,
        };
        goto *S[S_sw = (A[P + 1]) - 1];
        
        S_4:;
            // code for each switch entry

Then if there is no S_default created due to a S(*): in Imp, add this at the foot of the procedure or block:

        goto S_skip;
        S_default:
            fprintf(stderr, "\nSwitch label 'S(%d):' not set in %s\n", S_sw + 1,
                    __PRETTY_FUNCTION__);
            fflush(stderr);
            abort();
        S_skip:;

although the goto above would be better coded as:

        S_sw = (A[P + 1]) - 1;
        if (1 <= S_sw && S_sw <= 5) goto *S[S_sw]; else goto S_default;

and of course there is the saving of __LINE__ and __FILE__ to be done, using the values
from the Imp source where the ->S(A[P + 1]) occurred.  Which could probably best be
implemented using a macro?  e.g. goto_switch(S, A[P + 1]);
Perhaps:

#define goto_switch(S, N) \
  do { \
    S ## _sw = N; \
    _sw_line = __LINE__; \
    _sw_file = __FILE__; \
    if (S ## _low <= S ## _sw && S ## _sw <= S ## _high) \
      goto *S[S ## _sw - S ## _low]; \
    else \
      goto S ## _default; \
  } while (0)

Initialising the switch without exbedding code is going to be tricky.  For now the best I can think of is a nested procedure call:

At the switch declaration:
 
#define declare_switch(S, low, high) static int S ## _sw; const int S ## _low = low, S ## _high = high; static void **S; auto void init_ ## S(void); init_ ## S();

then at the end of the block:

void init_S(void) { const static void *_S[5 / * 1:5 * /] = {
  &&S_1, &&S_2, &&S_3, &&S_4, &&S_default,
}; S = _S; }

So to do all this we need to keep track of the switch bounds (associated with the switch name), and
an array of whether each label is present (low:high) (plus a separate one for default:) stored in
the var information for that name.

I still need a good mechanism to trigger code generation on popping the scope at the end of a rt/fn/map/begin block.

*/

  // <INITDECS><DECLNAME><DECLNAMES>'('<EXPR>':'<EXPR>')'
  
  compile(P(1), depth+1); // <INITDECS>
  Object = SWITCHDEFN;
  IsArray = ARRAY;
  Basetype = SWITCHLABEL;
  Area = CONSTANT;
  // NameInfo under consideration. May depend on whether the
  // switch label is implemented as a pointer to an array or
  // the array itself - exbedded array declaration or placed
  // at end of the block?

  // LIKE BPAIR BUT ONE-DIMENSION ONLY:
  int LowIDX = compile(P(5), depth+1);
  int HighIDX = compile(P(7), depth+1);
  AddDims(LowIDX, HighIDX);

  compile(P(2), depth+1); // NAME
  int SwitchDeclIDX = Declaration(depth+1, FALSE /* switch declarations cannot be A, B, C(L:H) - they must all be handled separately. */);
  
  int next_name = P(3);
  while (next_name != -1 && P_alt(next_name) == 0) {
    // replace the name but keep the other parameters the same:
    compile(P_P(next_name, 3), depth+1); // ',' <READLINEP><DECLNAME> <DECLNAMES>, ''
    int MoreSwitchDeclIDX = Declaration(depth+1, FALSE /* switch declarations cannot be A, B, C(L:H) - they must all be handled separately. */);
    next_name = P_P(next_name, 4);
  }

#endif
     {                              //\\    <INITDECS> <DECLNAME> <DECLNAMES> '(' <EXPR> ':' <EXPR> ')';
     t[1] = compile(P(1), depth+1 /* P_INITDECS */);
     t[2] = compile(P(2), depth+1 /* P_DECLNAME */);
     t[3] = compile(P(3), depth+1 /* P_DECLNAMES */);
     t[4] = wlit(P(4) /*, L'(' */);
     t[5] = compile(P(5), depth+1 /* P_EXPR */);
     t[6] = wlit(P(6) /*, L':' */);
     t[7] = compile(P(7), depth+1 /* P_EXPR */);
     t[8] = wlit(P(8) /*, L')' */);
     return t[0] = P_mktuple(P_ONESWDECL, alt, 8/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<RESTOFSWLIST> =
   case P_RESTOFSWLIST:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    ',' <ONESWDECL> <RESTOFSWLIST>,
       t[1] = wlit(P(1) /*, L',' */);
       t[2] = compile(P(2), depth+1 /* P_ONESWDECL */);
       t[3] = compile(P(3), depth+1 /* P_RESTOFSWLIST */);
       return t[0] = P_mktuple(P_RESTOFSWLIST, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_RESTOFSWLIST, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<switch_declaration> =
   case P_switch_declaration:
#ifdef IN_PARSER

#endif
     {                              //\\    "switch" <ONESWDECL> <RESTOFSWLIST> <S>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_ONESWDECL */);
     t[3] = compile(P(3), depth+1 /* P_RESTOFSWLIST */);
     t[4] = compile(P(4), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_switch_declaration, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<list_on> =
   case P_list_on:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[turn on listing]\n");
  return -1;

#endif
     {                              //\\    "list" <S> <LISTON>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_S */);
     t[3] = -1; /* semantic procedure LISTON */;
     return t[0] = P_mktuple(P_list_on, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<else> =
   case P_else:
#ifdef IN_PARSER

  {
    if (debug_compiler) fprintf(stderr, "[(finish) else (start)]\n");
    int EXPECTED = pop_ctrl();
    if (EXPECTED == ELSE || EXPECTED == FINISHELSE) {
      push_ctrl(FINISH);
      codegen("} else {");           // NOTE: a plain "%else" represents "%finish %else %start"
    } else {
      // TO DO:
      
      // And today's exercise is... try to remember how to extract the line/column from the "else" symbol
      // to report the error better :-/
      
      fprintf(stderr, "\n* Spurious %%ELSE\n"); exit(1);
    }
  }
  return -1;

#endif
     {                              //\\    "else" <S>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_else, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<finish_opt_else> =
   case P_finish_opt_else:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[finish_opt_else]\n");
  {
    if (ctrl_depth() <= 1) {
      fprintf(stderr, "\n* Spurious %%FINISH\n"); exit(1); // at least until we get around to handling ERCC conditional compilation tests
    }
    int EXPECTED = pop_ctrl();
    codegen("\n}");
    if (EXPECTED == FINISH) {
      push_ctrl(ELSE);
    } else if (EXPECTED == FINISHELSE) {
      push_ctrl(ELSE);
    } else {
      fprintf(stderr, "\n* %%FINISH not expected (expecting %s)\n", ctrl_debug[EXPECTED]); exit(1);
    }
    // recurse on FINISHELSEQ
  }

#endif
     {                              //\\    "finish" <FINISHELSEQ> <S>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_FINISHELSEQ */);
     t[3] = compile(P(3), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_finish_opt_else, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<embedded_assembler> =
   case P_embedded_assembler:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[embedded assembly code]\n");
  codegen("asm(/*to do*/)");
  return -1;

#endif
     {                              //\\    '*' <ASM> <S>;
     t[1] = wlit(P(1) /*, L'*' */);
     t[2] = compile(P(2), depth+1 /* P_ASM */);
     t[3] = compile(P(3), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_embedded_assembler, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<trusted> =
   case P_trusted:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[trusted program pragma]\n");
  return -1;

#endif
     {                              //\\    "trustedprogram" <S>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_trusted, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<mainep> =
   case P_mainep:
#ifdef IN_PARSER

  if (debug_compiler) fprintf(stderr, "[use this routine for main()]\n");

// TO DO: Declaration()
  return -1;

#endif
     {                              //\\    "mainep" <DECLNAME> <S>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_DECLNAME */);
     t[3] = compile(P(3), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_mainep, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<control> =
   case P_control:
#ifdef IN_PARSER

  // pragma?
  if (debug_compiler) fprintf(stderr, "[%%control - fine control over compiler options]\n");

#endif
     {                              //\\    "control" <CONST> <S>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_CONST */);
     t[3] = compile(P(3), depth+1 /* P_S */);
     return t[0] = P_mktuple(P_control, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<PSEMI> =
   case P_PSEMI:
#ifdef IN_PARSER

  // print a semicolon after certain statements. This is for C's benefit and only really an issue
  // when generating C on the fly from compile() statements.  Once these have moved to AST_* tuples
  // and are generated *after* parsing, there will be no need for this here.
  codegen("/*5*/; ");
  return -1;

#endif
     {                              //\\    ;

     return t[0] = P_mktuple(P_PSEMI, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<STATEMENT> =
   case P_STATEMENT:
#ifdef IN_PARSER

  switch (alt) {
  case 0: // <Labels>
  case 1: // <Unconditional_Instructions>
  case 2: // <Comment><S>
  case 3: // <If_or_Unless>
  case 4: // <start_of_cycle>
  case 5: // <end_of_cycle>
  case 6: // <regular_declaration>
  case 7: // <various_ends>
  case 8: // <record_format_declaration>
  case 9: // <proc_declaration>
  case 10: // <own_or_external_declaration>
  case 11: // <include_file>
  case 12: // <begin_block>
  case 13: // <on_event_block>
  case 14: // <switch_declaration>
  case 15: // <list_on>
  case 16: // <else>
  case 17: // <finish_opt_else>
  case 18: // <embedded_assembler> <PSEMI>
  case 19: // <trusted> <PSEMI>
  case 20: // <mainep> <PSEMI>
  case 21: // <control> <PSEMI>
  case 22: // <S>
    break;
  default:
    fprintf(stderr, "** Error: STATEMENT.alt = %d\n", alt);
    break;
  }
  // drop through and return a <STATEMENT> to P<SS>

#endif
     if (alt == 0)               {  //\\    <Labels>,
       t[1] = compile(P(1), depth+1 /* P_Labels */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <Unconditional_Instructions>,
       t[1] = compile(P(1), depth+1 /* P_Unconditional_Instructions */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 2)        {  //\\    <Comment> <S>,
       t[1] = compile(P(1), depth+1 /* P_Comment */);
       t[2] = compile(P(2), depth+1 /* P_S */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 3)        {  //\\    <If_or_Unless>,
       t[1] = compile(P(1), depth+1 /* P_If_or_Unless */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 4)        {  //\\    <start_of_cycle>,
       t[1] = compile(P(1), depth+1 /* P_start_of_cycle */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 5)        {  //\\    <end_of_cycle>,
       t[1] = compile(P(1), depth+1 /* P_end_of_cycle */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 6)        {  //\\    <regular_declaration>,
       t[1] = compile(P(1), depth+1 /* P_regular_declaration */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 7)        {  //\\    <various_ends>,
       t[1] = compile(P(1), depth+1 /* P_various_ends */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 8)        {  //\\    <record_format_declaration>,
       t[1] = compile(P(1), depth+1 /* P_record_format_declaration */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 9)        {  //\\    <proc_declaration>,
       t[1] = compile(P(1), depth+1 /* P_proc_declaration */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 10)        {  //\\    <own_or_external_declaration>,
       t[1] = compile(P(1), depth+1 /* P_own_or_external_declaration */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 11)        {  //\\    <include_file>,
       t[1] = compile(P(1), depth+1 /* P_include_file */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 12)        {  //\\    <begin_block>,
       t[1] = compile(P(1), depth+1 /* P_begin_block */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 13)        {  //\\    <on_event_block>,
       t[1] = compile(P(1), depth+1 /* P_on_event_block */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 14)        {  //\\    <switch_declaration>,
       t[1] = compile(P(1), depth+1 /* P_switch_declaration */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 15)        {  //\\    <list_on>,
       t[1] = compile(P(1), depth+1 /* P_list_on */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 16)        {  //\\    <else>,
       t[1] = compile(P(1), depth+1 /* P_else */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 17)        {  //\\    <finish_opt_else>,
       t[1] = compile(P(1), depth+1 /* P_finish_opt_else */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 18)        {  //\\    <embedded_assembler> <PSEMI>,
       t[1] = compile(P(1), depth+1 /* P_embedded_assembler */);
       t[2] = compile(P(2), depth+1 /* P_PSEMI */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 19)        {  //\\    <trusted> <PSEMI>,
       t[1] = compile(P(1), depth+1 /* P_trusted */);
       t[2] = compile(P(2), depth+1 /* P_PSEMI */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 20)        {  //\\    <mainep> <PSEMI>,
       t[1] = compile(P(1), depth+1 /* P_mainep */);
       t[2] = compile(P(2), depth+1 /* P_PSEMI */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 21)        {  //\\    <control> <PSEMI>,
       t[1] = compile(P(1), depth+1 /* P_control */);
       t[2] = compile(P(2), depth+1 /* P_PSEMI */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <S>;
       t[1] = compile(P(1), depth+1 /* P_S */);
       return t[0] = P_mktuple(P_STATEMENT, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ E
