//\\ # This is an extended grammar which now accepts constructs from multiple versions of Imp
//\\ # - it was primarily based on a correct Imp80 grammar, then modified to add Imp77 constructs
//\\ # followed by features from Pdp15 Imp, old Emas "Imp9", and Hamish's 68000 extensions, etc
//\\ # The original base grammar was:
//\\ #   https://history.dcs.ed.ac.uk/archive/os/emas/emas2/compilers/imp80/imp80ps04.txt
//\\ #
//\\ # Since this accepts multiple dialects, I'm tempted to call it "PImp", short for "Polyglot Imp"...
//\\ #
//\\ # There is good info re the phrase structure grammar to be found at
//\\ # http://www.ancientgeek.org.uk/EMAS/EMAS_Manuals/IMP/A_Syntactic_and_Semantic_Definition_of_the_IMP_Language.pdf
//\\ #
//\\ # Built-in Phrases used by the line reconstruction phase:
//\\ #
//\\ # stropped letter (%a %b etc)
//\\ B<stropped> = 0;
//\\ #
//\\ # single-quoted string
//\\ B<sqstring> = 1;
//\\ #
//\\ # double-quoted string
//\\ B<dqstring> = 2;
//\\ #
//\\ B<NL> = 3;
//\\ #
//\\ B<char> = 4;
//\\ #
//\\ # All parsers need an <EOF> phrase.
//\\ #
//\\ B<EOF> = 5;

//\\ C<immediate> = {
//\\ // WARNING: currently parse-time phrases are not being handled properly
//\\ //          by compile(). Are they set to -1 or skipped completely?
//\\ #define INCLUDE_AST_DEBUG "show_imp_ast.c"
//\\ int kw(int AST_op, int idx, int ap)
//\\ {
//\\   int data[4];
//\\ 
//\\   int i;
//\\ 
//\\   char *k = keyword(idx);
//\\ 
//\\   data[1] =  idx;
//\\ 
//\\   data[2] = A[ap+3]; // index of c[] array element
//\\   data[3] = strlen(k);
//\\ 
//\\   return mktuple(AST_op, 1, 3, data);
//\\ 
//\\ }
//\\ // variables used in line_reconstruction() moved here so they are available to semantic code in grammar.
//\\ #define STROPPED_KEYWORDS 1  /* alters behaviour of parse() */
//\\ int at_startofstatement = TRUE;
//\\ 
//\\ int saved = TRUE;
//\\ 
//\\ int at_startofline = TRUE;
//\\ 
//\\ int in_keyword = FALSE;
//\\ 
//\\ int in_alphanumeric = FALSE;
//\\ 
//\\ };

//\\ #
//\\ # We have one semantic phrase in this grammar:
//\\ #
//\\ # OK, this is slightly trickier than you might expect... you can't place the <COLON> immediate code after the ':'
//\\ # because the parser pre-fetches the next token in order to compare against <COLON> even though <COLON> doesn't
//\\ # actually examine any text.  So... we put the test *before* the ':', and *UNDO* its actions in the following
//\\ # alternative if the ':' was not matched.
//\\ #
//\\ # Anyway, the outcome is that if a <COLON> is followed by a '!' comment, that comment is handled by the
//\\ # line reconstruction code and is *not* passed back to the parser a character at a time as it was previously doing!
//\\ #
//\\ # This in turn solves the problem of line reconstruction finding a ' or a " in the comment and gobbling up characters
//\\ # - possibly over multiple line - until it hits a matching quote.  PHEW.  It took a long time to get here!
//\\ #

//\\ P<LABEL-COLON> = 
//\\    <immediate:saved = at_startofstatement; at_startofstatement = TRUE; return TRUE;> ':',
//\\    <immediate:at_startofstatement = saved; return FALSE;>;

case P_LABEL_COLON:
  if (alt == 0)        {
    T[1] = -1; // successful semantic call  
    T[2] = lit(AST__LIT, ':', A[ap+1]);
    T[0] = mktuple(AST_LABEL_COLON, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[1] = -1; // successful semantic call
    T[0] = mktuple(AST_LABEL_COLON, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ ##P<LABEL-COLON> =
//\\ ##   ':';
//\\ # SS is the primary entry point.
//\\ #

//\\ P<SS> = 
//\\    <EXTERNALS> <LAST-ITEMS-IN-FILE>;

case P_SS:
  T[1] = build_ast(A[ap+0], depth+1); // <EXTERNALS>
  T[2] = build_ast(A[ap+1], depth+1); // <LAST-ITEMS-IN-FILE>
  return mktuple(AST_SS, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);


//\\ #
//\\ # I'm taking the long way to handle alphanumerics and variable names, for now
//\\ # At some point (soon) I hope to add regular expression matching, to shorten
//\\ # these rules and speed up parsing.  But this works, quite reliably.
//\\ #
//\\ ## P<letter> = "[A-Z]";
//\\ #

//\\ P<letter> = 
//\\    'A',
//\\    'B',
//\\    'C',
//\\    'D',
//\\    'E',
//\\    'F',
//\\    'G',
//\\    'H',
//\\    'I',
//\\    'J',
//\\    'K',
//\\    'L',
//\\    'M',
//\\    'N',
//\\    'O',
//\\    'P',
//\\    'Q',
//\\    'R',
//\\    'S',
//\\    'T',
//\\    'U',
//\\    'V',
//\\    'W',
//\\    'X',
//\\    'Y',
//\\    'Z';

case P_letter:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, 'A', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, 'B', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 2) {  
    T[1] = lit(AST__LIT, 'C', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 3) {  
    T[1] = lit(AST__LIT, 'D', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 4) {  
    T[1] = lit(AST__LIT, 'E', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*4*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 5) {  
    T[1] = lit(AST__LIT, 'F', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*5*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 6) {  
    T[1] = lit(AST__LIT, 'G', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*6*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 7) {  
    T[1] = lit(AST__LIT, 'H', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*7*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 8) {  
    T[1] = lit(AST__LIT, 'I', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*8*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 9) {  
    T[1] = lit(AST__LIT, 'J', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*9*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 10) {  
    T[1] = lit(AST__LIT, 'K', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*10*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 11) {  
    T[1] = lit(AST__LIT, 'L', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*11*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 12) {  
    T[1] = lit(AST__LIT, 'M', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*12*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 13) {  
    T[1] = lit(AST__LIT, 'N', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*13*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 14) {  
    T[1] = lit(AST__LIT, 'O', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*14*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 15) {  
    T[1] = lit(AST__LIT, 'P', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*15*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 16) {  
    T[1] = lit(AST__LIT, 'Q', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*16*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 17) {  
    T[1] = lit(AST__LIT, 'R', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*17*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 18) {  
    T[1] = lit(AST__LIT, 'S', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*18*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 19) {  
    T[1] = lit(AST__LIT, 'T', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*19*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 20) {  
    T[1] = lit(AST__LIT, 'U', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*20*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 21) {  
    T[1] = lit(AST__LIT, 'V', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*21*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 22) {  
    T[1] = lit(AST__LIT, 'W', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*22*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 23) {  
    T[1] = lit(AST__LIT, 'X', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*23*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 24) {  
    T[1] = lit(AST__LIT, 'Y', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*24*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = lit(AST__LIT, 'Z', A[ap+0]);
    T[0] = mktuple(AST_letter, alt /*25*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ ## P<digit> = "[0-9]";
//\\ #

//\\ P<digit> = 
//\\    '0',
//\\    '1',
//\\    '2',
//\\    '3',
//\\    '4',
//\\    '5',
//\\    '6',
//\\    '7',
//\\    '8',
//\\    '9';

case P_digit:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '0', A[ap+0]);
    T[0] = mktuple(AST_digit, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, '1', A[ap+0]);
    T[0] = mktuple(AST_digit, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 2) {  
    T[1] = lit(AST__LIT, '2', A[ap+0]);
    T[0] = mktuple(AST_digit, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 3) {  
    T[1] = lit(AST__LIT, '3', A[ap+0]);
    T[0] = mktuple(AST_digit, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 4) {  
    T[1] = lit(AST__LIT, '4', A[ap+0]);
    T[0] = mktuple(AST_digit, alt /*4*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 5) {  
    T[1] = lit(AST__LIT, '5', A[ap+0]);
    T[0] = mktuple(AST_digit, alt /*5*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 6) {  
    T[1] = lit(AST__LIT, '6', A[ap+0]);
    T[0] = mktuple(AST_digit, alt /*6*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 7) {  
    T[1] = lit(AST__LIT, '7', A[ap+0]);
    T[0] = mktuple(AST_digit, alt /*7*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 8) {  
    T[1] = lit(AST__LIT, '8', A[ap+0]);
    T[0] = mktuple(AST_digit, alt /*8*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = lit(AST__LIT, '9', A[ap+0]);
    T[0] = mktuple(AST_digit, alt /*9*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];




//\\ P<alphanumeric> = 
//\\    <letter>,
//\\    <digit>;

case P_alphanumeric:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <letter>
    T[0] = mktuple(AST_alphanumeric, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <digit>
    T[0] = mktuple(AST_alphanumeric, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];




//\\ P<opt-letter-or-digit-seq> = 
//\\    <letter> <opt-letter-or-digit-seq>,
//\\    <digit> <opt-letter-or-digit-seq>,
//\\   ;

case P_opt_letter_or_digit_seq:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <letter>
    T[2] = build_ast(A[ap+1], depth+1); // <opt-letter-or-digit-seq>
    T[0] = mktuple(AST_opt_letter_or_digit_seq, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <digit>
    T[2] = build_ast(A[ap+1], depth+1); // <opt-letter-or-digit-seq>
    T[0] = mktuple(AST_opt_letter_or_digit_seq, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_opt_letter_or_digit_seq, alt /*2*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ #More than one newline (or semicolon)

//\\ P<BLANKS> = 
//\\    <S> <BLANKS>,
//\\   ;

case P_BLANKS:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <S>
    T[2] = build_ast(A[ap+1], depth+1); // <BLANKS>
    T[0] = mktuple(AST_BLANKS, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_BLANKS, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # The last items in a file.
//\\ # the final EOF below is only for begin/endofprogram which *can* be followed by code but shouldn't

//\\ P<LAST-ITEMS-IN-FILE> = 
//\\    "end" "of" "file" <BLANKS> <EOF>,
//\\    "end" "of" "perm" <BLANKS> <EOF>,
//\\    "end" "of" "prim" <BLANKS> <EOF>,
//\\    <BLANKS> <EOF>;

case P_LAST_ITEMS_IN_FILE:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_end, A[ap+0]);  
    T[2] = kw(AST__KW, KW_of, A[ap+1]);  
    T[3] = kw(AST__KW, KW_file, A[ap+2]);
    T[4] = build_ast(A[ap+3], depth+1); // <BLANKS>
    T[5] = bip(AST_EOF, A[ap+4]);
    T[0] = mktuple(AST_LAST_ITEMS_IN_FILE, alt /*0*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_end, A[ap+0]);  
    T[2] = kw(AST__KW, KW_of, A[ap+1]);  
    T[3] = kw(AST__KW, KW_perm, A[ap+2]);
    T[4] = build_ast(A[ap+3], depth+1); // <BLANKS>
    T[5] = bip(AST_EOF, A[ap+4]);
    T[0] = mktuple(AST_LAST_ITEMS_IN_FILE, alt /*1*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else if (alt == 2) {  
    T[1] = kw(AST__KW, KW_end, A[ap+0]);  
    T[2] = kw(AST__KW, KW_of, A[ap+1]);  
    T[3] = kw(AST__KW, KW_prim, A[ap+2]);
    T[4] = build_ast(A[ap+3], depth+1); // <BLANKS>
    T[5] = bip(AST_EOF, A[ap+4]);
    T[0] = mktuple(AST_LAST_ITEMS_IN_FILE, alt /*2*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <BLANKS>
    T[2] = bip(AST_EOF, A[ap+1]);
    T[0] = mktuple(AST_LAST_ITEMS_IN_FILE, alt /*3*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];




//\\ P<program> = 
//\\    "programme",
//\\    "program";

case P_program:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_programme, A[ap+0]);
    T[0] = mktuple(AST_program, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_program, A[ap+0]);
    T[0] = mktuple(AST_program, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # I haven't specified any phrases to be external-only.  There might be some,
//\\ # but I'll leave it to compile() to reject them.

//\\ P<EXTERNALS> = 
//\\    <EXTERNAL-OR-INTERNAL> <EXTERNALS>,
//\\   ;

case P_EXTERNALS:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <EXTERNAL-OR-INTERNAL>
    T[2] = build_ast(A[ap+1], depth+1); // <EXTERNALS>
    T[0] = mktuple(AST_EXTERNALS, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_EXTERNALS, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # I cleaned up label handling, we can afford the overhead of backtracking over one <NAME>...
//\\ # - this isn't the 70's any more.  Labels are not valid outside blocks.

//\\ P<INTERNALS> = 
//\\    <OPT-LABEL-DEFINITION> <INTERNAL> <INTERNALS>,
//\\    <OPT-LABEL-DEFINITION>;

case P_INTERNALS:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-LABEL-DEFINITION>
    T[2] = build_ast(A[ap+1], depth+1); // <INTERNAL>
    T[3] = build_ast(A[ap+2], depth+1); // <INTERNALS>
    T[0] = mktuple(AST_INTERNALS, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-LABEL-DEFINITION>
    T[0] = mktuple(AST_INTERNALS, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # top-level begin/end block can either be %begin/%endofprogram,
//\\ # or %begin/%end/%endoffile.  However in some cases things can
//\\ # be placed between the %end and the %endoffile.
//\\ #
//\\ # I've also seen %routine xxx/%endofprogram in FMACS/BOOT.imp
//\\ #
//\\ # There's a %begin/%end without an %endoffile in FMACS/FIRST4.imp

//\\ P<outer-level-end> = 
//\\    "end" "of" <program>,
//\\    "end";

case P_outer_level_end:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_end, A[ap+0]);  
    T[2] = kw(AST__KW, KW_of, A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <program>
    T[0] = mktuple(AST_outer_level_end, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_end, A[ap+0]);
    T[0] = mktuple(AST_outer_level_end, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # these are allowed at the external level and also inside procedures/main program.
//\\ # The phrases that are internal-only include these as the final alternative,
//\\ # hence why the empty statement can only occur as the last item in this list.
//\\ #
//\\ # If using this grammar as a 'SOAP' replacement, you'll want to allow syntactically
//\\ # incorrect statements also, and if so, those should be handled here after the <S> rule.
//\\ #

//\\ P<EXTERNAL-OR-INTERNAL> = 
//\\    "begin" <S> <INTERNALS> <outer-level-end> <S>,
//\\    <Percent-SEX> <RT> <spec> <NAME> <Opt-ALIAS> <FPP> <S>,
//\\    <Percent-SEX> <RT> <NAME> <Opt-ALIAS> <FPP> <S> <INTERNALS> <outer-level-end> <S>,
//\\    <OPT-68K> <Percent-SEX> <RT> <NAME> <Opt-ALIAS> <FPP> <S>,
//\\    <DECLARATION-S>,
//\\    "record" "format" <RECFMT-spec-OR-BODY> <S>,
//\\    "switch" <NAME> <Opt-NAME-LIST> '(' <EXPR> ':' <EXPR> ')' <REST-OF-SWLIST> <S>,
//\\    "include" <STR-CONST>,
//\\    "option" <STR-CONST>,
//\\    "from" <NAME> "include" <NAME> <Opt-NAME-LIST>,
//\\    "end" "of" "list" <S>,
//\\    "list" <S>,
//\\    "end" "of" "mcode" <S>,
//\\    "mcode" <S>,
//\\    "trusted" "program" <S>,
//\\    "main" "ep" <NAME> <S>,
//\\    "control" <INT-CONST> <S>,
//\\    "diagnose" <INT-CONST> <S>,
//\\    "reals" "long",
//\\    "reals" "normal",
//\\    <COMMENT>,
//\\    <S>;

case P_EXTERNAL_OR_INTERNAL:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_begin, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <S>
    T[3] = build_ast(A[ap+2], depth+1); // <INTERNALS>
    T[4] = build_ast(A[ap+3], depth+1); // <outer-level-end>
    T[5] = build_ast(A[ap+4], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*0*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <Percent-SEX>
    T[2] = build_ast(A[ap+1], depth+1); // <RT>
    T[3] = build_ast(A[ap+2], depth+1); // <spec>
    T[4] = build_ast(A[ap+3], depth+1); // <NAME>
    T[5] = build_ast(A[ap+4], depth+1); // <Opt-ALIAS>
    T[6] = build_ast(A[ap+5], depth+1); // <FPP>
    T[7] = build_ast(A[ap+6], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*1*/, /*phrases*/ 7, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7]*/);
  } else if (alt == 2) {
    T[1] = build_ast(A[ap+0], depth+1); // <Percent-SEX>
    T[2] = build_ast(A[ap+1], depth+1); // <RT>
    T[3] = build_ast(A[ap+2], depth+1); // <NAME>
    T[4] = build_ast(A[ap+3], depth+1); // <Opt-ALIAS>
    T[5] = build_ast(A[ap+4], depth+1); // <FPP>
    T[6] = build_ast(A[ap+5], depth+1); // <S>
    T[7] = build_ast(A[ap+6], depth+1); // <INTERNALS>
    T[8] = build_ast(A[ap+7], depth+1); // <outer-level-end>
    T[9] = build_ast(A[ap+8], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*2*/, /*phrases*/ 9, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8], T[9]*/);
  } else if (alt == 3) {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-68K>
    T[2] = build_ast(A[ap+1], depth+1); // <Percent-SEX>
    T[3] = build_ast(A[ap+2], depth+1); // <RT>
    T[4] = build_ast(A[ap+3], depth+1); // <NAME>
    T[5] = build_ast(A[ap+4], depth+1); // <Opt-ALIAS>
    T[6] = build_ast(A[ap+5], depth+1); // <FPP>
    T[7] = build_ast(A[ap+6], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*3*/, /*phrases*/ 7, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7]*/);
  } else if (alt == 4) {
    T[1] = build_ast(A[ap+0], depth+1); // <DECLARATION-S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*4*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 5) {  
    T[1] = kw(AST__KW, KW_record, A[ap+0]);  
    T[2] = kw(AST__KW, KW_format, A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <RECFMT-spec-OR-BODY>
    T[4] = build_ast(A[ap+3], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*5*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else if (alt == 6) {  
    T[1] = kw(AST__KW, KW_switch, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-NAME-LIST>  
    T[4] = lit(AST__LIT, '(', A[ap+3]);
    T[5] = build_ast(A[ap+4], depth+1); // <EXPR>  
    T[6] = lit(AST__LIT, ':', A[ap+5]);
    T[7] = build_ast(A[ap+6], depth+1); // <EXPR>  
    T[8] = lit(AST__LIT, ')', A[ap+7]);
    T[9] = build_ast(A[ap+8], depth+1); // <REST-OF-SWLIST>
    T[10] = build_ast(A[ap+9], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*6*/, /*phrases*/ 10, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8], T[9], T[10]*/);
  } else if (alt == 7) {  
    T[1] = kw(AST__KW, KW_include, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <STR-CONST>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*7*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 8) {  
    T[1] = kw(AST__KW, KW_option, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <STR-CONST>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*8*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 9) {  
    T[1] = kw(AST__KW, KW_from, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>  
    T[3] = kw(AST__KW, KW_include, A[ap+2]);
    T[4] = build_ast(A[ap+3], depth+1); // <NAME>
    T[5] = build_ast(A[ap+4], depth+1); // <Opt-NAME-LIST>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*9*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else if (alt == 10) {  
    T[1] = kw(AST__KW, KW_end, A[ap+0]);  
    T[2] = kw(AST__KW, KW_of, A[ap+1]);  
    T[3] = kw(AST__KW, KW_list, A[ap+2]);
    T[4] = build_ast(A[ap+3], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*10*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else if (alt == 11) {  
    T[1] = kw(AST__KW, KW_list, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*11*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 12) {  
    T[1] = kw(AST__KW, KW_end, A[ap+0]);  
    T[2] = kw(AST__KW, KW_of, A[ap+1]);  
    T[3] = kw(AST__KW, KW_mcode, A[ap+2]);
    T[4] = build_ast(A[ap+3], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*12*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else if (alt == 13) {  
    T[1] = kw(AST__KW, KW_mcode, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*13*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 14) {  
    T[1] = kw(AST__KW, KW_trusted, A[ap+0]);  
    T[2] = kw(AST__KW, KW_program, A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*14*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 15) {  
    T[1] = kw(AST__KW, KW_main, A[ap+0]);  
    T[2] = kw(AST__KW, KW_ep, A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <NAME>
    T[4] = build_ast(A[ap+3], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*15*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else if (alt == 16) {  
    T[1] = kw(AST__KW, KW_control, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <INT-CONST>
    T[3] = build_ast(A[ap+2], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*16*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 17) {  
    T[1] = kw(AST__KW, KW_diagnose, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <INT-CONST>
    T[3] = build_ast(A[ap+2], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*17*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 18) {  
    T[1] = kw(AST__KW, KW_reals, A[ap+0]);  
    T[2] = kw(AST__KW, KW_long, A[ap+1]);
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*18*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 19) {  
    T[1] = kw(AST__KW, KW_reals, A[ap+0]);  
    T[2] = kw(AST__KW, KW_normal, A[ap+1]);
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*19*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 20) {
    T[1] = build_ast(A[ap+0], depth+1); // <COMMENT>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*20*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <S>
    T[0] = mktuple(AST_EXTERNAL_OR_INTERNAL, alt /*21*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # These are all extensions used by 68000 Imp.
//\\ #
//\\ # %begin
//\\ # %recordformat f(%byte ldte,lsap,rdte,rsap)
//\\ # @#ldte %record(f)cur
//\\ # ( I have no idea what "@#ldte " means. )
//\\ #
//\\ # @400(a5) %record(*)%namearray in(0:7)
//\\ # @16_3F00-192 %routine         closeinput
//\\ # @724(a5) %integername heapfront
//\\ #
//\\ # '@' <68K-code-address> before a routine name is an external spec in 68000 Imp, and
//\\ # <Opt-68K-code-address> after an external %spec is a perm routine spec in 68000 Imp.
//\\ # as in: %integerfnspec(16_1124) REM(%integer a,b)  { found in APM-gdmr/I/GGPERM.imp }
//\\ #

//\\ P<OPT-68K> = 
//\\    '@' <68K-stuff>,
//\\   ;

case P_OPT_68K:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '@', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <68K-stuff>
    T[0] = mktuple(AST_OPT_68K, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_OPT_68K, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<68K-stuff> = 
//\\    '-' <INT-CONST> '(' <NAME> ')',
//\\    <INT-CONST> '(' <NAME> ')',
//\\    <INT-CONST> '-' <INT-CONST>,
//\\    <INT-CONST>,
//\\    '#' <NAME>;

case P_68K_stuff:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '-', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <INT-CONST>  
    T[3] = lit(AST__LIT, '(', A[ap+2]);
    T[4] = build_ast(A[ap+3], depth+1); // <NAME>  
    T[5] = lit(AST__LIT, ')', A[ap+4]);
    T[0] = mktuple(AST_68K_stuff, alt /*0*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <INT-CONST>  
    T[2] = lit(AST__LIT, '(', A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <NAME>  
    T[4] = lit(AST__LIT, ')', A[ap+3]);
    T[0] = mktuple(AST_68K_stuff, alt /*1*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else if (alt == 2) {
    T[1] = build_ast(A[ap+0], depth+1); // <INT-CONST>  
    T[2] = lit(AST__LIT, '-', A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <INT-CONST>
    T[0] = mktuple(AST_68K_stuff, alt /*2*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 3) {
    T[1] = build_ast(A[ap+0], depth+1); // <INT-CONST>
    T[0] = mktuple(AST_68K_stuff, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = lit(AST__LIT, '#', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[0] = mktuple(AST_68K_stuff, alt /*4*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];



//\\ # this is for 68000 Imp:
//\\ #
//\\ # %externalrealfnspecalias READ %alias "readreal"
//\\ # %externalintegerfnspecalias READ
//\\ # I have no idea what a "specalias" is :-(
//\\ #
//\\ # %integerarrayspec(16_C00000) frame(0:32767)
//\\ # %integerfnspec(16_1124) REM(%integer a,b)
//\\ # %bytespec(16_7fffc)status
//\\ #
//\\ # I think these extensions are also covered with a *different* extension in the same compiler :-(
//\\ # i.e.
//\\ #   @16_7fffc %byte status  ???
//\\ #

//\\ P<spec> = 
//\\    "specalias",
//\\    "spec" <Opt-68K-code-address>;

case P_spec:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_specalias, A[ap+0]);
    T[0] = mktuple(AST_spec, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_spec, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-68K-code-address>
    T[0] = mktuple(AST_spec, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];




//\\ P<Opt-68K-code-address> = 
//\\    '(' <INT-CONST> ')',
//\\   ;

case P_Opt_68K_code_address:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '(', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <INT-CONST>  
    T[3] = lit(AST__LIT, ')', A[ap+2]);
    T[0] = mktuple(AST_Opt_68K_code_address, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_Opt_68K_code_address, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<OPT-spec> = 
//\\    <spec>,
//\\   ;

case P_OPT_spec:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <spec>
    T[0] = mktuple(AST_OPT_spec, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_spec, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # All labels come through here.  Because of an interaction with comments,
//\\ # we use some parse-time code in phrase <LABEL-COLON> to modify how line reconstruction
//\\ # handles the comments.  btw Numeric labels are a historical form...

//\\ P<OPT-LABEL-DEFINITION> = 
//\\    <NAME> '(' <CEXPR> ')' <LABEL-COLON> <OPT-LABEL-DEFINITION>,
//\\    <NAME> '(' '*' ')' <LABEL-COLON> <OPT-LABEL-DEFINITION>,
//\\    <NAME> <LABEL-COLON> <OPT-LABEL-DEFINITION>,
//\\    <DIGIT-SEQ> <LABEL-COLON> <OPT-LABEL-DEFINITION>,
//\\   ;

case P_OPT_LABEL_DEFINITION:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>  
    T[2] = lit(AST__LIT, '(', A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <CEXPR>  
    T[4] = lit(AST__LIT, ')', A[ap+3]);
    T[5] = build_ast(A[ap+4], depth+1); // <LABEL-COLON>
    T[6] = build_ast(A[ap+5], depth+1); // <OPT-LABEL-DEFINITION>
    T[0] = mktuple(AST_OPT_LABEL_DEFINITION, alt /*0*/, /*phrases*/ 6, T /*T[1], T[2], T[3], T[4], T[5], T[6]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>  
    T[2] = lit(AST__LIT, '(', A[ap+1]);  
    T[3] = lit(AST__LIT, '*', A[ap+2]);  
    T[4] = lit(AST__LIT, ')', A[ap+3]);
    T[5] = build_ast(A[ap+4], depth+1); // <LABEL-COLON>
    T[6] = build_ast(A[ap+5], depth+1); // <OPT-LABEL-DEFINITION>
    T[0] = mktuple(AST_OPT_LABEL_DEFINITION, alt /*1*/, /*phrases*/ 6, T /*T[1], T[2], T[3], T[4], T[5], T[6]*/);
  } else if (alt == 2) {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>
    T[2] = build_ast(A[ap+1], depth+1); // <LABEL-COLON>
    T[3] = build_ast(A[ap+2], depth+1); // <OPT-LABEL-DEFINITION>
    T[0] = mktuple(AST_OPT_LABEL_DEFINITION, alt /*2*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 3) {
    T[1] = build_ast(A[ap+0], depth+1); // <DIGIT-SEQ>
    T[2] = build_ast(A[ap+1], depth+1); // <LABEL-COLON>
    T[3] = build_ast(A[ap+2], depth+1); // <OPT-LABEL-DEFINITION>
    T[0] = mktuple(AST_OPT_LABEL_DEFINITION, alt /*3*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_OPT_LABEL_DEFINITION, alt /*4*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # fault statements can only appear in the outer block of a program;
//\\ # they cannot appear in external routines.  This should be checked
//\\ # by the compile() procedure.

//\\ P<FAULT-S> = 
//\\    "fault" <FAULT-ACTION> <MORE-FAULTS> <S>;

case P_FAULT_S:
  T[1] = kw(AST__KW, KW_fault, A[ap+0]);
  T[2] = build_ast(A[ap+1], depth+1); // <FAULT-ACTION>
  T[3] = build_ast(A[ap+2], depth+1); // <MORE-FAULTS>
  T[4] = build_ast(A[ap+3], depth+1); // <S>
  return mktuple(AST_FAULT_S, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);



//\\ P<FAULT-LIST> = 
//\\    <DIGIT-SEQ> <MORE-NUMBERS>;

case P_FAULT_LIST:
  T[1] = build_ast(A[ap+0], depth+1); // <DIGIT-SEQ>
  T[2] = build_ast(A[ap+1], depth+1); // <MORE-NUMBERS>
  return mktuple(AST_FAULT_LIST, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);



//\\ P<MORE-NUMBERS> = 
//\\    ',' <DIGIT-SEQ> <MORE-NUMBERS>,
//\\   ;

case P_MORE_NUMBERS:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <DIGIT-SEQ>
    T[3] = build_ast(A[ap+2], depth+1); // <MORE-NUMBERS>
    T[0] = mktuple(AST_MORE_NUMBERS, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_MORE_NUMBERS, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<FAULT-ACTION> = 
//\\    <FAULT-LIST> '-' '>' <LABEL>;

case P_FAULT_ACTION:
  T[1] = build_ast(A[ap+0], depth+1); // <FAULT-LIST>
  T[2] = lit(AST__LIT, '-', A[ap+1]);
  T[3] = lit(AST__LIT, '>', A[ap+2]);
  T[4] = build_ast(A[ap+3], depth+1); // <LABEL>
  return mktuple(AST_FAULT_ACTION, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);



//\\ P<MORE-FAULTS> = 
//\\    ',' <FAULT-ACTION> <MORE-FAULTS>,
//\\   ;

case P_MORE_FAULTS:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <FAULT-ACTION>
    T[3] = build_ast(A[ap+2], depth+1); // <MORE-FAULTS>
    T[0] = mktuple(AST_MORE_FAULTS, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_MORE_FAULTS, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # The "spec" form below is for old EMAS Imp procedure parameters:
//\\ #
//\\ # %routine integrate(%realname y, %real a,b, %integer n, %c
//\\ #                    %realfn f)
//\\ #   %spec f(%real x)
//\\ #
//\\ # the fully-qualified form (%realfnspec f(%real x)) is also valid but comes in via the <EXTERNAL> route.
//\\ #
//\\ # There are other types of %spec related to parameters to procedures as well -
//\\ # %recordspec for sure.  Not so sure if there is an arrayspec.
//\\ # They are only allowed in the body of a procedure.
//\\ #
//\\ # (Btw in the older compilers, all declarations in a block had to precede any code.)
//\\ #
//\\ # strictly speaking the <UI> <REST-OF-SS1> form, <UI> "while" <SC>, should only
//\\ # allow a single <UI>, not the <UI> <AUI> form. (EMAS Imp)
//\\ # (page 4.4 of https://history.dcs.ed.ac.uk/archive/docs/Edinburgh_IMP_Language_Manual.pdf )

//\\ P<INTERNAL> = 
//\\    <NESTED-BLOCK>,
//\\    <UI> <REST-OF-SS1>,
//\\    '*' <UCI>,
//\\    <CYCLE-S>,
//\\    <IF-S>,
//\\    <FAULT-S>,
//\\    "on" <OPT-event> <EVENT-LIST> <REST-OF-NAME-LIST> "start" <S> <INTERNALS> "finish" <S>,
//\\    "spec" <NAME> <FPP> <S>,
//\\    <EXTERNAL-OR-INTERNAL>;

case P_INTERNAL:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <NESTED-BLOCK>
    T[0] = mktuple(AST_INTERNAL, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <UI>
    T[2] = build_ast(A[ap+1], depth+1); // <REST-OF-SS1>
    T[0] = mktuple(AST_INTERNAL, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 2) {  
    T[1] = lit(AST__LIT, '*', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <UCI>
    T[0] = mktuple(AST_INTERNAL, alt /*2*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 3) {
    T[1] = build_ast(A[ap+0], depth+1); // <CYCLE-S>
    T[0] = mktuple(AST_INTERNAL, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 4) {
    T[1] = build_ast(A[ap+0], depth+1); // <IF-S>
    T[0] = mktuple(AST_INTERNAL, alt /*4*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 5) {
    T[1] = build_ast(A[ap+0], depth+1); // <FAULT-S>
    T[0] = mktuple(AST_INTERNAL, alt /*5*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 6) {  
    T[1] = kw(AST__KW, KW_on, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-event>
    T[3] = build_ast(A[ap+2], depth+1); // <EVENT-LIST>
    T[4] = build_ast(A[ap+3], depth+1); // <REST-OF-NAME-LIST>  
    T[5] = kw(AST__KW, KW_start, A[ap+4]);
    T[6] = build_ast(A[ap+5], depth+1); // <S>
    T[7] = build_ast(A[ap+6], depth+1); // <INTERNALS>  
    T[8] = kw(AST__KW, KW_finish, A[ap+7]);
    T[9] = build_ast(A[ap+8], depth+1); // <S>
    T[0] = mktuple(AST_INTERNAL, alt /*6*/, /*phrases*/ 9, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8], T[9]*/);
  } else if (alt == 7) {  
    T[1] = kw(AST__KW, KW_spec, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[3] = build_ast(A[ap+2], depth+1); // <FPP>
    T[4] = build_ast(A[ap+3], depth+1); // <S>
    T[0] = mktuple(AST_INTERNAL, alt /*7*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <EXTERNAL-OR-INTERNAL>
    T[0] = mktuple(AST_INTERNAL, alt /*8*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # unlike with old-style parsers, the whole of the block content ends up in an AST item.
//\\ #
//\\ # Unfortunately there is a problem caused by 68000 Imp: some files contain only
//\\ # begin/end with no endoffile.  Some are begin/end;endoffile instead of begin/endofprogram
//\\ # A few are routine blah/endofprogram !
//\\ # One had begin/endofprogram followed by more routines.
//\\ # (and see elsewhere for 68000's external routine specs which are of the form
//\\ #   @address %routine blah
//\\ #  - with no %spec keyword, but no routine body either..)
//\\ #

//\\ P<NESTED-BLOCK> = 
//\\    "begin" <S> <INTERNALS> "end" <S>;

case P_NESTED_BLOCK:
  T[1] = kw(AST__KW, KW_begin, A[ap+0]);
  T[2] = build_ast(A[ap+1], depth+1); // <S>
  T[3] = build_ast(A[ap+2], depth+1); // <INTERNALS>
  T[4] = kw(AST__KW, KW_end, A[ap+3]);
  T[5] = build_ast(A[ap+4], depth+1); // <S>
  return mktuple(AST_NESTED_BLOCK, alt /*0*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);


//\\ # compound statements - blah %and blah %and blah - a short form of startfinish block

//\\ P<AUI> = 
//\\    "and" <UI>,
//\\   ;

case P_AUI:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_and, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <UI>
    T[0] = mktuple(AST_AUI, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_AUI, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<OPT-ASSIGN> = 
//\\    '-' '>' <STRING-RESOLUTION-EXPR>,
//\\    <ASSOP> <EXPR>,
//\\   ;

case P_OPT_ASSIGN:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '-', A[ap+0]);  
    T[2] = lit(AST__LIT, '>', A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <STRING-RESOLUTION-EXPR>
    T[0] = mktuple(AST_OPT_ASSIGN, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <ASSOP>
    T[2] = build_ast(A[ap+1], depth+1); // <EXPR>
    T[0] = mktuple(AST_OPT_ASSIGN, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_OPT_ASSIGN, alt /*2*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # the compound statement form ends in UIs which change control flow, ie
//\\ # you cannot say: %if whatever %then blah %and ->lab %and this will never happen
//\\ # tempted to add %caption here ;-)  But that may be a step too far.
//\\ # "%monitor 9" would be trapped by "%fault 9 -> lab"

//\\ P<UI> = 
//\\    <NAME> <Opt-PARAMETERS-OR-POINTERINDEX> <Opt-RECORDFIELD> <OPT-ASSIGN> <AUI>,
//\\    "print" "text" <sqstring> <AUI>,
//\\    '-' '>' <LABEL>,
//\\    "return",
//\\    "true",
//\\    "false",
//\\    "result" <ASSOP> <EXPR>,
//\\    "monitorstop",
//\\    "monitor" <DIGIT-SEQ> <AUI>,
//\\    "monitor" <AUI>,
//\\    "stop",
//\\    "signal" <OPT-event> <CEXPR> <OPEXPR2>,
//\\    "exit",
//\\    "continue";

case P_UI:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-PARAMETERS-OR-POINTERINDEX>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-RECORDFIELD>
    T[4] = build_ast(A[ap+3], depth+1); // <OPT-ASSIGN>
    T[5] = build_ast(A[ap+4], depth+1); // <AUI>
    T[0] = mktuple(AST_UI, alt /*0*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_print, A[ap+0]);  
    T[2] = kw(AST__KW, KW_text, A[ap+1]);
    T[3] = bip(AST_sqstring, A[ap+2]);
    T[4] = build_ast(A[ap+3], depth+1); // <AUI>
    T[0] = mktuple(AST_UI, alt /*1*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else if (alt == 2) {  
    T[1] = lit(AST__LIT, '-', A[ap+0]);  
    T[2] = lit(AST__LIT, '>', A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <LABEL>
    T[0] = mktuple(AST_UI, alt /*2*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 3) {  
    T[1] = kw(AST__KW, KW_return, A[ap+0]);
    T[0] = mktuple(AST_UI, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 4) {  
    T[1] = kw(AST__KW, KW_true, A[ap+0]);
    T[0] = mktuple(AST_UI, alt /*4*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 5) {  
    T[1] = kw(AST__KW, KW_false, A[ap+0]);
    T[0] = mktuple(AST_UI, alt /*5*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 6) {  
    T[1] = kw(AST__KW, KW_result, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <ASSOP>
    T[3] = build_ast(A[ap+2], depth+1); // <EXPR>
    T[0] = mktuple(AST_UI, alt /*6*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 7) {  
    T[1] = kw(AST__KW, KW_monitorstop, A[ap+0]);
    T[0] = mktuple(AST_UI, alt /*7*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 8) {  
    T[1] = kw(AST__KW, KW_monitor, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <DIGIT-SEQ>
    T[3] = build_ast(A[ap+2], depth+1); // <AUI>
    T[0] = mktuple(AST_UI, alt /*8*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 9) {  
    T[1] = kw(AST__KW, KW_monitor, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <AUI>
    T[0] = mktuple(AST_UI, alt /*9*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 10) {  
    T[1] = kw(AST__KW, KW_stop, A[ap+0]);
    T[0] = mktuple(AST_UI, alt /*10*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 11) {  
    T[1] = kw(AST__KW, KW_signal, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-event>
    T[3] = build_ast(A[ap+2], depth+1); // <CEXPR>
    T[4] = build_ast(A[ap+3], depth+1); // <OPEXPR2>
    T[0] = mktuple(AST_UI, alt /*11*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else if (alt == 12) {  
    T[1] = kw(AST__KW, KW_exit, A[ap+0]);
    T[0] = mktuple(AST_UI, alt /*12*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_continue, A[ap+0]);
    T[0] = mktuple(AST_UI, alt /*13*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];




//\\ P<LABEL> = 
//\\    <NAME> '(' <EXPR> ')',
//\\    <NAME>,
//\\    <DIGIT-SEQ>;

case P_LABEL:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>  
    T[2] = lit(AST__LIT, '(', A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <EXPR>  
    T[4] = lit(AST__LIT, ')', A[ap+3]);
    T[0] = mktuple(AST_LABEL, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>
    T[0] = mktuple(AST_LABEL, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <DIGIT-SEQ>
    T[0] = mktuple(AST_LABEL, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # prim and perm added by gt

//\\ P<FILE-END-TYPE> = 
//\\    "file",
//\\    "prim",
//\\    "perm";

case P_FILE_END_TYPE:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_file, A[ap+0]);
    T[0] = mktuple(AST_FILE_END_TYPE, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_prim, A[ap+0]);
    T[0] = mktuple(AST_FILE_END_TYPE, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_perm, A[ap+0]);
    T[0] = mktuple(AST_FILE_END_TYPE, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # I added an old record declaration syntax for examples out of ai2logo.i
//\\ #
//\\ # %OWNRECORDARRAY INDEX42( 0:1022)           (PIC DIR)
//\\ #
//\\ # %SYSTEMROUTINESPEC FINFO(%STRING(15) S,%INTEGER LEV,%C
//\\ #    %RECORDNAME R, %INTEGERNAME FLAG)
//\\ #
//\\ # %RECORD R(F)
//\\ #
//\\ # I'm not sure where/if this is handled:
//\\ #
//\\ # %record(f)%array portinfo(1:31)
//\\ #
//\\ # I need to get the old Imp manuals out and check a couple of things, in particular
//\\ #   %recordformatspec and %arrayformatspec ...
//\\ #
//\\ # The grammar below allows some initialisations that the compilers don't support
//\\ # but it's cleaner to reject them in compile()
//\\ #
//\\ # I had to add initialisations with pointers for these examples from
//\\ # 68000 Imp: %bytename b == length(s)
//\\ # %ownrecord(i tc f)%namearray tc refs(1:maxtc) == nil(*)
//\\ #
//\\ # These are 68000 syntax which is rejected by Imp77:
//\\ # %conststring(1) %array(1:max params) parameters="B","W","L"
//\\ # %string(255) %array(0:maxfiles) list
//\\ #
//\\ # The equivalent Imp77 syntax would be
//\\ #
//\\ # %conststring(1) %array parameters(1:max params)="B","W","L"
//\\ # %string(255) %array list(0:maxfiles)
//\\ #
//\\ # Finally here's a one-off hack for a construct I've only seen *once*
//\\ # in APM-gdmr/I/PRIM22.imp ...
//\\ # %constchar                    snl=char<10>
//\\ #

//\\ P<DECLARATION-S> = 
//\\    <OPT-68K> <XOWN> <XTYPE> <OWNDEC> <S>,
//\\    <OPT-68K> <XTYPE> <DECLN> <S>,
//\\    <OPT-68K> <OPT-XOWN> "record" "array" <RADEC> <REST-OF-RADEC> <S>,
//\\    <OPT-68K> <OPT-XOWN> "record" <RDEC> <REST-OF-RDEC> <S>,
//\\    "const" "char" <NAME> '=' 'C' 'H' 'A' 'R' '<' <INT-CONST> '>' <S>;

case P_DECLARATION_S:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-68K>
    T[2] = build_ast(A[ap+1], depth+1); // <XOWN>
    T[3] = build_ast(A[ap+2], depth+1); // <XTYPE>
    T[4] = build_ast(A[ap+3], depth+1); // <OWNDEC>
    T[5] = build_ast(A[ap+4], depth+1); // <S>
    T[0] = mktuple(AST_DECLARATION_S, alt /*0*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-68K>
    T[2] = build_ast(A[ap+1], depth+1); // <XTYPE>
    T[3] = build_ast(A[ap+2], depth+1); // <DECLN>
    T[4] = build_ast(A[ap+3], depth+1); // <S>
    T[0] = mktuple(AST_DECLARATION_S, alt /*1*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else if (alt == 2) {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-68K>
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-XOWN>  
    T[3] = kw(AST__KW, KW_record, A[ap+2]);  
    T[4] = kw(AST__KW, KW_array, A[ap+3]);
    T[5] = build_ast(A[ap+4], depth+1); // <RADEC>
    T[6] = build_ast(A[ap+5], depth+1); // <REST-OF-RADEC>
    T[7] = build_ast(A[ap+6], depth+1); // <S>
    T[0] = mktuple(AST_DECLARATION_S, alt /*2*/, /*phrases*/ 7, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7]*/);
  } else if (alt == 3) {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-68K>
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-XOWN>  
    T[3] = kw(AST__KW, KW_record, A[ap+2]);
    T[4] = build_ast(A[ap+3], depth+1); // <RDEC>
    T[5] = build_ast(A[ap+4], depth+1); // <REST-OF-RDEC>
    T[6] = build_ast(A[ap+5], depth+1); // <S>
    T[0] = mktuple(AST_DECLARATION_S, alt /*3*/, /*phrases*/ 6, T /*T[1], T[2], T[3], T[4], T[5], T[6]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_const, A[ap+0]);  
    T[2] = kw(AST__KW, KW_char, A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <NAME>  
    T[4] = lit(AST__LIT, '=', A[ap+3]);  
    T[5] = lit(AST__LIT, 'C', A[ap+4]);  
    T[6] = lit(AST__LIT, 'H', A[ap+5]);  
    T[7] = lit(AST__LIT, 'A', A[ap+6]);  
    T[8] = lit(AST__LIT, 'R', A[ap+7]);  
    T[9] = lit(AST__LIT, '<', A[ap+8]);
    T[10] = build_ast(A[ap+9], depth+1); // <INT-CONST>  
    T[11] = lit(AST__LIT, '>', A[ap+10]);
    T[12] = build_ast(A[ap+11], depth+1); // <S>
    T[0] = mktuple(AST_DECLARATION_S, alt /*4*/, /*phrases*/ 12, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8], T[9], T[10], T[11], T[12]*/);
  }
  return T[0];




//\\ P<OPT-XOWN> = 
//\\    <XOWN>,
//\\   ;

case P_OPT_XOWN:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <XOWN>
    T[0] = mktuple(AST_OPT_XOWN, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_XOWN, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # old-style record array declaration

//\\ P<RADEC> = 
//\\    <NAME> <Opt-NAME-LIST> <BPAIR> '(' <RECFMT-REF> ')';

case P_RADEC:
  T[1] = build_ast(A[ap+0], depth+1); // <NAME>
  T[2] = build_ast(A[ap+1], depth+1); // <Opt-NAME-LIST>
  T[3] = build_ast(A[ap+2], depth+1); // <BPAIR>
  T[4] = lit(AST__LIT, '(', A[ap+3]);
  T[5] = build_ast(A[ap+4], depth+1); // <RECFMT-REF>
  T[6] = lit(AST__LIT, ')', A[ap+5]);
  return mktuple(AST_RADEC, alt /*0*/, /*phrases*/ 6, T /*T[1], T[2], T[3], T[4], T[5], T[6]*/);



//\\ P<REST-OF-RADEC> = 
//\\    ',' <RADEC>,
//\\   ;

case P_REST_OF_RADEC:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <RADEC>
    T[0] = mktuple(AST_REST_OF_RADEC, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_RADEC, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # old-style record declaration

//\\ P<RDEC> = 
//\\    <NAME> <Opt-NAME-LIST> '(' <RECFMT-REF> ')';

case P_RDEC:
  T[1] = build_ast(A[ap+0], depth+1); // <NAME>
  T[2] = build_ast(A[ap+1], depth+1); // <Opt-NAME-LIST>
  T[3] = lit(AST__LIT, '(', A[ap+2]);
  T[4] = build_ast(A[ap+3], depth+1); // <RECFMT-REF>
  T[5] = lit(AST__LIT, ')', A[ap+4]);
  return mktuple(AST_RDEC, alt /*0*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);



//\\ P<REST-OF-RDEC> = 
//\\    ',' <RDEC> <REST-OF-RDEC>,
//\\   ;

case P_REST_OF_RDEC:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <RDEC>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-RDEC>
    T[0] = mktuple(AST_REST_OF_RDEC, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_RDEC, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # %on %event * %start or %on %event 1,2,3,etc %start

//\\ P<EVENT-LIST> = 
//\\    '*',
//\\    <CEXPR>;

case P_EVENT_LIST:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '*', A[ap+0]);
    T[0] = mktuple(AST_EVENT_LIST, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <CEXPR>
    T[0] = mktuple(AST_EVENT_LIST, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # Added old-style while/until for: %UNTIL NEXTINSYM=NL %THEN %CYCLE
//\\ # and %WHILE NEXTINSYM#NL %THEN SKIPINSYM

//\\ P<CYCLE-S> = 
//\\    "cycle" <Opt-CYCPARM> <S> <INTERNALS> "repeat" <Opt-UNTIL> <S>,
//\\    <Percent-WUF> "cycle" <S> <INTERNALS> "repeat" <Opt-UNTIL> <S>,
//\\    <Percent-WU> "then" "cycle" <S> <INTERNALS> "repeat" <Opt-UNTIL> <S>,
//\\    <Percent-WU> "then" <UI>;

case P_CYCLE_S:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_cycle, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-CYCPARM>
    T[3] = build_ast(A[ap+2], depth+1); // <S>
    T[4] = build_ast(A[ap+3], depth+1); // <INTERNALS>  
    T[5] = kw(AST__KW, KW_repeat, A[ap+4]);
    T[6] = build_ast(A[ap+5], depth+1); // <Opt-UNTIL>
    T[7] = build_ast(A[ap+6], depth+1); // <S>
    T[0] = mktuple(AST_CYCLE_S, alt /*0*/, /*phrases*/ 7, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <Percent-WUF>  
    T[2] = kw(AST__KW, KW_cycle, A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <S>
    T[4] = build_ast(A[ap+3], depth+1); // <INTERNALS>  
    T[5] = kw(AST__KW, KW_repeat, A[ap+4]);
    T[6] = build_ast(A[ap+5], depth+1); // <Opt-UNTIL>
    T[7] = build_ast(A[ap+6], depth+1); // <S>
    T[0] = mktuple(AST_CYCLE_S, alt /*1*/, /*phrases*/ 7, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7]*/);
  } else if (alt == 2) {
    T[1] = build_ast(A[ap+0], depth+1); // <Percent-WU>  
    T[2] = kw(AST__KW, KW_then, A[ap+1]);  
    T[3] = kw(AST__KW, KW_cycle, A[ap+2]);
    T[4] = build_ast(A[ap+3], depth+1); // <S>
    T[5] = build_ast(A[ap+4], depth+1); // <INTERNALS>  
    T[6] = kw(AST__KW, KW_repeat, A[ap+5]);
    T[7] = build_ast(A[ap+6], depth+1); // <Opt-UNTIL>
    T[8] = build_ast(A[ap+7], depth+1); // <S>
    T[0] = mktuple(AST_CYCLE_S, alt /*2*/, /*phrases*/ 8, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <Percent-WU>  
    T[2] = kw(AST__KW, KW_then, A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <UI>
    T[0] = mktuple(AST_CYCLE_S, alt /*3*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  }
  return T[0];




//\\ P<IF-S> = 
//\\    <Percent-IU> <CONDITION> <THEN-S>;

case P_IF_S:
  T[1] = build_ast(A[ap+0], depth+1); // <Percent-IU>
  T[2] = build_ast(A[ap+1], depth+1); // <CONDITION>
  T[3] = build_ast(A[ap+2], depth+1); // <THEN-S>
  return mktuple(AST_IF_S, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);


//\\ # /home/gtoal/gtoal.com/athome/edinburgh/APM-gdmr/I/LIB.imp
//\\ # contains:
//\\ #          %elseif 'A'<=sym<='Z' %start
//\\ #
//\\ # which is a form of Hamish's that is equivalent to
//\\ #
//\\ #  %finish %else %if 'A'<=sym<='Z' %start
//\\ #
//\\ # or the more concise
//\\ #
//\\ #  %else %if 'A'<=sym<='Z'
//\\ #
//\\ # An identical issue is: %elsestart
//\\ # in APM-gdmr/ETHER/PROFILE.imp
//\\ #

//\\ P<FINISH-S> = 
//\\    "else" <Percent-IU> <CONDITION> <Opt-start> <S> <INTERNALS> <FINISH-S>,
//\\    "else" <Opt-start> <S> <INTERNALS> "finish" <S>,
//\\    "finish" <Opt-ELSE-S>;

case P_FINISH_S:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_else, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Percent-IU>
    T[3] = build_ast(A[ap+2], depth+1); // <CONDITION>
    T[4] = build_ast(A[ap+3], depth+1); // <Opt-start>
    T[5] = build_ast(A[ap+4], depth+1); // <S>
    T[6] = build_ast(A[ap+5], depth+1); // <INTERNALS>
    T[7] = build_ast(A[ap+6], depth+1); // <FINISH-S>
    T[0] = mktuple(AST_FINISH_S, alt /*0*/, /*phrases*/ 7, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_else, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-start>
    T[3] = build_ast(A[ap+2], depth+1); // <S>
    T[4] = build_ast(A[ap+3], depth+1); // <INTERNALS>  
    T[5] = kw(AST__KW, KW_finish, A[ap+4]);
    T[6] = build_ast(A[ap+5], depth+1); // <S>
    T[0] = mktuple(AST_FINISH_S, alt /*1*/, /*phrases*/ 6, T /*T[1], T[2], T[3], T[4], T[5], T[6]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_finish, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-ELSE-S>
    T[0] = mktuple(AST_FINISH_S, alt /*2*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];




//\\ P<Opt-start> = 
//\\    "start",
//\\   ;

case P_Opt_start:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_start, A[ap+0]);
    T[0] = mktuple(AST_Opt_start, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_Opt_start, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # see the comments on <FINISH-S> above.

//\\ P<Opt-ELSE-S> = 
//\\    "else" "start" <S> <INTERNALS> "finish" <S>,
//\\    "else" <IF-S>,
//\\    "else" <UI> <S>,
//\\    <S>;

case P_Opt_ELSE_S:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_else, A[ap+0]);  
    T[2] = kw(AST__KW, KW_start, A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <S>
    T[4] = build_ast(A[ap+3], depth+1); // <INTERNALS>  
    T[5] = kw(AST__KW, KW_finish, A[ap+4]);
    T[6] = build_ast(A[ap+5], depth+1); // <S>
    T[0] = mktuple(AST_Opt_ELSE_S, alt /*0*/, /*phrases*/ 6, T /*T[1], T[2], T[3], T[4], T[5], T[6]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_else, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <IF-S>
    T[0] = mktuple(AST_Opt_ELSE_S, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 2) {  
    T[1] = kw(AST__KW, KW_else, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <UI>
    T[3] = build_ast(A[ap+2], depth+1); // <S>
    T[0] = mktuple(AST_Opt_ELSE_S, alt /*2*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <S>
    T[0] = mktuple(AST_Opt_ELSE_S, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];




//\\ P<THEN-S> = 
//\\    <OPT-then> "start" <S> <INTERNALS> <FINISH-S>,
//\\    "then" <UI> <Opt-ELSE-S>;

case P_THEN_S:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-then>  
    T[2] = kw(AST__KW, KW_start, A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <S>
    T[4] = build_ast(A[ap+3], depth+1); // <INTERNALS>
    T[5] = build_ast(A[ap+4], depth+1); // <FINISH-S>
    T[0] = mktuple(AST_THEN_S, alt /*0*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_then, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <UI>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-ELSE-S>
    T[0] = mktuple(AST_THEN_S, alt /*1*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  }
  return T[0];




//\\ P<OPT-then> = 
//\\    "then",
//\\   ;

case P_OPT_then:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_then, A[ap+0]);
    T[0] = mktuple(AST_OPT_then, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_then, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<OPT-start> = 
//\\    "start",
//\\   ;

case P_OPT_start:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_start, A[ap+0]);
    T[0] = mktuple(AST_OPT_start, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_start, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<S> = 
//\\    <NL>,
//\\    ';';

case P_S:
  if (alt == 0)        {
    T[1] = bip(AST_NL, A[ap+0]);
    T[0] = mktuple(AST_S, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = lit(AST__LIT, ';', A[ap+0]);
    T[0] = mktuple(AST_S, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # Most comments are handled in the line reconstruction phase.
//\\ # Comments starting with %COMMENT are an exception.
//\\ # Some older compilers treated '!' comments like %COMMENT,
//\\ # with "%c" at the end of a comment causing continuation!
//\\ # This phrase does not allow ';' in a comment to terminate
//\\ # the comment, but some versions of Imp (I think PDP15)
//\\ # did, so that will have to be handled with a command-line
//\\ # option and a parse-time phrase if it ever is needed.
//\\ #

//\\ P<COMMENT> = 
//\\    "comment" <Parsed-OldStyle-Comment>,
//\\    '!' <Parsed-OldStyle-Comment>;

case P_COMMENT:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_comment, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Parsed-OldStyle-Comment>
    T[0] = mktuple(AST_COMMENT, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {  
    T[1] = lit(AST__LIT, '!', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Parsed-OldStyle-Comment>
    T[0] = mktuple(AST_COMMENT, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];




//\\ P<Parsed-OldStyle-Comment> = 
//\\    <char> <Parsed-OldStyle-Comment>,
//\\    <dqstring> <Parsed-OldStyle-Comment>,
//\\    <sqstring> <Parsed-OldStyle-Comment>,
//\\    <letter> <Parsed-OldStyle-Comment>,
//\\    <digit> <Parsed-OldStyle-Comment>,
//\\    <stropped> <Parsed-OldStyle-Comment>,
//\\    <NL>;

case P_Parsed_OldStyle_Comment:
  if (alt == 0)        {
    T[1] = bip(AST_char, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Parsed-OldStyle-Comment>
    T[0] = mktuple(AST_Parsed_OldStyle_Comment, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 1) {
    T[1] = bip(AST_dqstring, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Parsed-OldStyle-Comment>
    T[0] = mktuple(AST_Parsed_OldStyle_Comment, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 2) {
    T[1] = bip(AST_sqstring, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Parsed-OldStyle-Comment>
    T[0] = mktuple(AST_Parsed_OldStyle_Comment, alt /*2*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 3) {
    T[1] = build_ast(A[ap+0], depth+1); // <letter>
    T[2] = build_ast(A[ap+1], depth+1); // <Parsed-OldStyle-Comment>
    T[0] = mktuple(AST_Parsed_OldStyle_Comment, alt /*3*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 4) {
    T[1] = build_ast(A[ap+0], depth+1); // <digit>
    T[2] = build_ast(A[ap+1], depth+1); // <Parsed-OldStyle-Comment>
    T[0] = mktuple(AST_Parsed_OldStyle_Comment, alt /*4*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 5) {
    T[1] = bip(AST_stropped, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Parsed-OldStyle-Comment>
    T[0] = mktuple(AST_Parsed_OldStyle_Comment, alt /*5*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[1] = bip(AST_NL, A[ap+0]);
    T[0] = mktuple(AST_Parsed_OldStyle_Comment, alt /*6*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];




//\\ P<NL-or-SEMI> = 
//\\    <NL>,
//\\    <semi>;

case P_NL_or_SEMI:
  if (alt == 0)        {
    T[1] = bip(AST_NL, A[ap+0]);
    T[0] = mktuple(AST_NL_or_SEMI, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <semi>
    T[0] = mktuple(AST_NL_or_SEMI, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];




//\\ P<semi> = 
//\\    ';';

case P_semi:
  T[1] = lit(AST__LIT, ';', A[ap+0]);
  return mktuple(AST_semi, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);


//\\ # <DIGIT-SEQ> '_' <DIGIT-SEQ>, and  <DIGIT-SEQ> '_' <NAME>, added by gt
//\\ # <NAME> <sqstring> is really X'....' but type checking stops me matching 'X'
//\\ # VERY hacky stopgap just to get stuff to parse. Needs proper syntax
//\\ # which needs the ability to recognise individual digits and letters
//\\ # rather than the current typed 'alphanumeric' hack in line_reconstruction ...
//\\ # Doesn't handle %real well, and indeed not at all if containing an '@' sign.
//\\ # E"ebcdic" etc also not handled.  Hamish's 40_XXX comes in here.
//\\ #
//\\ ## P<basedconst> =  "[0-9][0-9]*_[0-9A-Z][0-9A-Z]*"
//\\ #

//\\ P<INT-CONST> = 
//\\    <DIGIT-SEQ> '_' <alphanumeric-SEQ>,
//\\    <DIGIT-SEQ>,
//\\    <OLDSTYLE-BASE>;

case P_INT_CONST:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <DIGIT-SEQ>  
    T[2] = lit(AST__LIT, '_', A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <alphanumeric-SEQ>
    T[0] = mktuple(AST_INT_CONST, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <DIGIT-SEQ>
    T[0] = mktuple(AST_INT_CONST, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <OLDSTYLE-BASE>
    T[0] = mktuple(AST_INT_CONST, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];




//\\ P<alphanumeric-SEQ> = 
//\\    <alphanumeric> <Opt-alphanumeric-SEQ>;

case P_alphanumeric_SEQ:
  T[1] = build_ast(A[ap+0], depth+1); // <alphanumeric>
  T[2] = build_ast(A[ap+1], depth+1); // <Opt-alphanumeric-SEQ>
  return mktuple(AST_alphanumeric_SEQ, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);



//\\ P<Opt-alphanumeric-SEQ> = 
//\\    <alphanumeric> <Opt-alphanumeric-SEQ>,
//\\   ;

case P_Opt_alphanumeric_SEQ:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <alphanumeric>
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-alphanumeric-SEQ>
    T[0] = mktuple(AST_Opt_alphanumeric_SEQ, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_Opt_alphanumeric_SEQ, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<STR-CONST> = 
//\\    <OPT-DQ-LETTER> <dqstring>,
//\\    <sqstring>;

case P_STR_CONST:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-DQ-LETTER>
    T[2] = bip(AST_dqstring, A[ap+1]);
    T[0] = mktuple(AST_STR_CONST, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[1] = bip(AST_sqstring, A[ap+0]);
    T[0] = mktuple(AST_STR_CONST, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # current line reconstruction doesn't support this. Letters come through as part of <alphanumeric>s.

//\\ P<OPT-DQ-LETTER> = 
//\\    'E',
//\\   ;

case P_OPT_DQ_LETTER:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, 'E', A[ap+0]);
    T[0] = mktuple(AST_OPT_DQ_LETTER, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_DQ_LETTER, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<NUMERIC-CONST> = 
//\\    <INT-CONST>,
//\\    <REAL-CONST>;

case P_NUMERIC_CONST:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <INT-CONST>
    T[0] = mktuple(AST_NUMERIC_CONST, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <REAL-CONST>
    T[0] = mktuple(AST_NUMERIC_CONST, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # <CONST> is somewhat generic and should be replaced with the more specific version when possible

//\\ P<CONST> = 
//\\    <INT-CONST>,
//\\    <REAL-CONST>,
//\\    <STR-CONST>;

case P_CONST:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <INT-CONST>
    T[0] = mktuple(AST_CONST, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <REAL-CONST>
    T[0] = mktuple(AST_CONST, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <STR-CONST>
    T[0] = mktuple(AST_CONST, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # <sqstring> has to be checked for length and content depending on prefix.
//\\ #
//\\ ## P<lettercharconst> = <squote> <schar> <squote> |
//\\ ##   "[RHX]" <squote> <hexchars> <squote> |
//\\ ##   "B" <squote> <binchars> <squote> |
//\\ ##   "K" <squote> <octchars> <squote> |
//\\ ##   "[CMD]" <squote> <mchars> <squote>;
//\\ #

//\\ P<OLDSTYLE-BASE> = 
//\\    <letter> <sqstring>;

case P_OLDSTYLE_BASE:
  T[1] = build_ast(A[ap+0], depth+1); // <letter>
  T[2] = bip(AST_sqstring, A[ap+1]);
  return mktuple(AST_OLDSTYLE_BASE, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);


//\\ # Note: a <DIGIT-SEQ> can be both an integer constant and a real constant.
//\\ # Imp77 supports constants like this: %constlongreal PI = 16_3.243F6A89
//\\ # which are not handled here yet.
//\\ #
//\\ ## P<realconst> = "[0-9][0-9]*\.[0-9][0-9]*E[0-9][0-9]*" |
//\\ ##                "[0-9][0-9]*\.[0-9][0-9]*" |
//\\ ##                "[0-9][0-9]*@[0-9][0-9]*"
//\\ #

//\\ P<REAL-CONST> = 
//\\    <DIGIT-SEQ> <OPT-FRACPT> <OPT-EXPONENT>,
//\\    <FRACPT> <OPT-EXPONENT>;

case P_REAL_CONST:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <DIGIT-SEQ>
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-FRACPT>
    T[3] = build_ast(A[ap+2], depth+1); // <OPT-EXPONENT>
    T[0] = mktuple(AST_REAL_CONST, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <FRACPT>
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-EXPONENT>
    T[0] = mktuple(AST_REAL_CONST, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];




//\\ P<FRACPT> = 
//\\    '.' <DIGIT-SEQ>;

case P_FRACPT:
  T[1] = lit(AST__LIT, '.', A[ap+0]);
  T[2] = build_ast(A[ap+1], depth+1); // <DIGIT-SEQ>
  return mktuple(AST_FRACPT, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);



//\\ P<OPT-FRACPT> = 
//\\    <FRACPT>,
//\\   ;

case P_OPT_FRACPT:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <FRACPT>
    T[0] = mktuple(AST_OPT_FRACPT, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_FRACPT, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<OPT-Plus-Minus> = 
//\\    '+',
//\\    '-',
//\\   ;

case P_OPT_Plus_Minus:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '+', A[ap+0]);
    T[0] = mktuple(AST_OPT_Plus_Minus, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, '-', A[ap+0]);
    T[0] = mktuple(AST_OPT_Plus_Minus, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_Plus_Minus, alt /*2*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<OPT-EXPONENT> = 
//\\    '@' <OPT-Plus-Minus> <DIGIT-SEQ>,
//\\   ;

case P_OPT_EXPONENT:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '@', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-Plus-Minus>
    T[3] = build_ast(A[ap+2], depth+1); // <DIGIT-SEQ>
    T[0] = mktuple(AST_OPT_EXPONENT, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_OPT_EXPONENT, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<DIGIT-SEQ> = 
//\\    <digit> <rest-of-number>;

case P_DIGIT_SEQ:
  T[1] = build_ast(A[ap+0], depth+1); // <digit>
  T[2] = build_ast(A[ap+1], depth+1); // <rest-of-number>
  return mktuple(AST_DIGIT_SEQ, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);



//\\ P<rest-of-number> = 
//\\    <DIGIT-SEQ>,
//\\   ;

case P_rest_of_number:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <DIGIT-SEQ>
    T[0] = mktuple(AST_rest_of_number, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_rest_of_number, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<NAME> = 
//\\    <letter> <!SQUO-STRING> <opt-letter-or-digit-seq>;

case P_NAME:
  T[1] = build_ast(A[ap+0], depth+1); // <letter>
  T[2] = -1; // <!SQUO-STRING>
  T[3] = build_ast(A[ap+2], depth+1); // <opt-letter-or-digit-seq>
  return mktuple(AST_NAME, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);


//\\ ## P<NAME> =
//\\ ##    <alphanumeric> <!SQUO-STRING> <rest-of-name>;
//\\ ## P<rest-of-name> =
//\\ ##    <NAME>,
//\\ ##   ;

//\\ P<SQUO-STRING> = 
//\\    <sqstring>;

case P_SQUO_STRING:
  T[1] = bip(AST_sqstring, A[ap+0]);
  return mktuple(AST_SQUO_STRING, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);


//\\ # A UCI is a machine code instruction.
//\\ # (Hamish's PDP15 imp machine code syntax (which is not introduced by '*') is definitely not supported.)
//\\ #
//\\ # Machine-specific machine-code removed. May cause problems with ';' and quoted chars in machine code
//\\ #

//\\ P<UCI> = 
//\\    <NL-or-SEMI>,
//\\    <char> <UCI>,
//\\    <dqstring> <UCI>,
//\\    <sqstring> <UCI>,
//\\    <stropped> <UCI>;

case P_UCI:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <NL-or-SEMI>
    T[0] = mktuple(AST_UCI, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {
    T[1] = bip(AST_char, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <UCI>
    T[0] = mktuple(AST_UCI, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 2) {
    T[1] = bip(AST_dqstring, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <UCI>
    T[0] = mktuple(AST_UCI, alt /*2*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 3) {
    T[1] = bip(AST_sqstring, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <UCI>
    T[0] = mktuple(AST_UCI, alt /*3*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[1] = bip(AST_stropped, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <UCI>
    T[0] = mktuple(AST_UCI, alt /*4*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];



//\\ # Imp does not let you mix and/or without explicit brackets. They do not have a precedence relationship

//\\ P<REST-OF-COND> = 
//\\    "and" <SC> <REST-OF-ANDC>,
//\\    "or" <SC> <REST-OF-ORC>,
//\\   ;

case P_REST_OF_COND:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_and, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <SC>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-ANDC>
    T[0] = mktuple(AST_REST_OF_COND, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_or, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <SC>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-ORC>
    T[0] = mktuple(AST_REST_OF_COND, alt /*1*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_COND, alt /*2*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<REST-OF-ANDC> = 
//\\    "and" <SC> <REST-OF-ANDC>,
//\\   ;

case P_REST_OF_ANDC:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_and, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <SC>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-ANDC>
    T[0] = mktuple(AST_REST_OF_ANDC, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_ANDC, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<REST-OF-ORC> = 
//\\    "or" <SC> <REST-OF-ORC>,
//\\   ;

case P_REST_OF_ORC:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_or, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <SC>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-ORC>
    T[0] = mktuple(AST_REST_OF_ORC, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_ORC, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<CONDITION> = 
//\\    <SC> <REST-OF-COND>;

case P_CONDITION:
  T[1] = build_ast(A[ap+0], depth+1); // <SC>
  T[2] = build_ast(A[ap+1], depth+1); // <REST-OF-COND>
  return mktuple(AST_CONDITION, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);


//\\ # <NAME> <OPT-ACTUAL-PARAMETERS> added by gt for predicates
//\\ # RESTOFSC handles double-sided conditions such as '0' <= ch <= '9'

//\\ P<SC> = 
//\\    <STRING-RESOLUTION>,
//\\    <EXPR> <COMP> <EXPR> <OPT-DOUBLE-SIDED>,
//\\    <NAME> <OPT-ACTUAL-PARAMETERS>,
//\\    '(' <CONDITION> ')',
//\\    "not" <SC>;

case P_SC:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <STRING-RESOLUTION>
    T[0] = mktuple(AST_SC, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <EXPR>
    T[2] = build_ast(A[ap+1], depth+1); // <COMP>
    T[3] = build_ast(A[ap+2], depth+1); // <EXPR>
    T[4] = build_ast(A[ap+3], depth+1); // <OPT-DOUBLE-SIDED>
    T[0] = mktuple(AST_SC, alt /*1*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else if (alt == 2) {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-ACTUAL-PARAMETERS>
    T[0] = mktuple(AST_SC, alt /*2*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 3) {  
    T[1] = lit(AST__LIT, '(', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <CONDITION>  
    T[3] = lit(AST__LIT, ')', A[ap+2]);
    T[0] = mktuple(AST_SC, alt /*3*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_not, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <SC>
    T[0] = mktuple(AST_SC, alt /*4*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];




//\\ P<OPT-DOUBLE-SIDED> = 
//\\    <COMP> <EXPR>,
//\\   ;

case P_OPT_DOUBLE_SIDED:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <COMP>
    T[2] = build_ast(A[ap+1], depth+1); // <EXPR>
    T[0] = mktuple(AST_OPT_DOUBLE_SIDED, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_OPT_DOUBLE_SIDED, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<STRING-RESOLUTION> = 
//\\    <STRING-EXPR> '-' '>' <STRING-RESOLUTION-EXPR>;

case P_STRING_RESOLUTION:
  T[1] = build_ast(A[ap+0], depth+1); // <STRING-EXPR>
  T[2] = lit(AST__LIT, '-', A[ap+1]);
  T[3] = lit(AST__LIT, '>', A[ap+2]);
  T[4] = build_ast(A[ap+3], depth+1); // <STRING-RESOLUTION-EXPR>
  return mktuple(AST_STRING_RESOLUTION, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);


//\\ # Current Imp77 restricts string resolution to -> a.("test").b  with a and b being optional.
//\\ # Older Emas implementations allowed multiple parts I'm fairly sure, eg -> a.("match1").b.("match2").c
//\\ #
//\\ # Also, behaviour changed re initial ("match") with no assignment variable before it -
//\\ # used to be that "match" had to start the string, but now there can be text before
//\\ # it, and a null match has to be coded as -> a.("match").b %and a = ""
//\\ #
//\\ # So if we need to distinguish between these variations, do it in compile()
//\\ #

//\\ P<STRING-RESOLUTION-EXPR> = 
//\\    <STR-MATCH> <OPT-STR-ASSIGN>,
//\\    <STR-ASSIGN> <OPT-STR-MATCH>;

case P_STRING_RESOLUTION_EXPR:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <STR-MATCH>
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-STR-ASSIGN>
    T[0] = mktuple(AST_STRING_RESOLUTION_EXPR, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <STR-ASSIGN>
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-STR-MATCH>
    T[0] = mktuple(AST_STRING_RESOLUTION_EXPR, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];




//\\ P<STRING-LVALUE> = 
//\\    <NAME> <Opt-PARAMETERS-OR-POINTERINDEX> <Opt-RECORDFIELD-OR-POINTERINDEX>;

case P_STRING_LVALUE:
  T[1] = build_ast(A[ap+0], depth+1); // <NAME>
  T[2] = build_ast(A[ap+1], depth+1); // <Opt-PARAMETERS-OR-POINTERINDEX>
  T[3] = build_ast(A[ap+2], depth+1); // <Opt-RECORDFIELD-OR-POINTERINDEX>
  return mktuple(AST_STRING_LVALUE, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);



//\\ P<STRING-RVALUE> = 
//\\    <STRING-LVALUE>,
//\\    <STR-CONST>;

case P_STRING_RVALUE:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <STRING-LVALUE>
    T[0] = mktuple(AST_STRING_RVALUE, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <STR-CONST>
    T[0] = mktuple(AST_STRING_RVALUE, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # No bracketed expressions, only '.' operator allowed, although once again,
//\\ # Hamish has an idiosyncratic extension where strings in a printstring are
//\\ # separated by semi-colons - I think it is some approximation to C's printf?
//\\ #

//\\ P<STRING-EXPR> = 
//\\    <STRING-RVALUE> <REST-OF-STRING-EXPR>;

case P_STRING_EXPR:
  T[1] = build_ast(A[ap+0], depth+1); // <STRING-RVALUE>
  T[2] = build_ast(A[ap+1], depth+1); // <REST-OF-STRING-EXPR>
  return mktuple(AST_STRING_EXPR, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);



//\\ P<REST-OF-STRING-EXPR> = 
//\\    '.' <STRING-RVALUE> <REST-OF-STRING-EXPR>,
//\\   ;

case P_REST_OF_STRING_EXPR:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '.', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <STRING-RVALUE>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-STRING-EXPR>
    T[0] = mktuple(AST_REST_OF_STRING_EXPR, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_STRING_EXPR, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<STR-MATCH> = 
//\\    '(' <STRING-EXPR> ')';

case P_STR_MATCH:
  T[1] = lit(AST__LIT, '(', A[ap+0]);
  T[2] = build_ast(A[ap+1], depth+1); // <STRING-EXPR>
  T[3] = lit(AST__LIT, ')', A[ap+2]);
  return mktuple(AST_STR_MATCH, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);



//\\ P<STR-ASSIGN> = 
//\\    <STRING-LVALUE>;

case P_STR_ASSIGN:
  T[1] = build_ast(A[ap+0], depth+1); // <STRING-LVALUE>
  return mktuple(AST_STR_ASSIGN, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);


//\\ # ping-pong.  Can't allow -> (a).b.c.(d) or -> a.(b).(c).d

//\\ P<OPT-STR-ASSIGN> = 
//\\    '.' <STR-ASSIGN> <OPT-STR-MATCH>,
//\\   ;

case P_OPT_STR_ASSIGN:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '.', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <STR-ASSIGN>
    T[3] = build_ast(A[ap+2], depth+1); // <OPT-STR-MATCH>
    T[0] = mktuple(AST_OPT_STR_ASSIGN, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_OPT_STR_ASSIGN, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<OPT-STR-MATCH> = 
//\\    '.' <STR-MATCH> <OPT-STR-ASSIGN>,
//\\   ;

case P_OPT_STR_MATCH:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '.', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <STR-MATCH>
    T[3] = build_ast(A[ap+2], depth+1); // <OPT-STR-ASSIGN>
    T[0] = mktuple(AST_OPT_STR_MATCH, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_OPT_STR_MATCH, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # Ordering is important, eg '##' must come before '#'
//\\ #
//\\ # I really pity people who use the sort of grammar that requires
//\\ # eliminating shift-reduce conflicts before they can parse anything :-)
//\\ #

//\\ P<COMP> = 
//\\    '=' '=',
//\\    '=',
//\\    <NOT-EQUALS-ADDRESS>,
//\\    <NOT-EQUALS>,
//\\    '<' '=',
//\\    '<',
//\\    '>' '=',
//\\    '>';

case P_COMP:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '=', A[ap+0]);  
    T[2] = lit(AST__LIT, '=', A[ap+1]);
    T[0] = mktuple(AST_COMP, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, '=', A[ap+0]);
    T[0] = mktuple(AST_COMP, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 2) {
    T[1] = build_ast(A[ap+0], depth+1); // <NOT-EQUALS-ADDRESS>
    T[0] = mktuple(AST_COMP, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 3) {
    T[1] = build_ast(A[ap+0], depth+1); // <NOT-EQUALS>
    T[0] = mktuple(AST_COMP, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 4) {  
    T[1] = lit(AST__LIT, '<', A[ap+0]);  
    T[2] = lit(AST__LIT, '=', A[ap+1]);
    T[0] = mktuple(AST_COMP, alt /*4*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 5) {  
    T[1] = lit(AST__LIT, '<', A[ap+0]);
    T[0] = mktuple(AST_COMP, alt /*5*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 6) {  
    T[1] = lit(AST__LIT, '>', A[ap+0]);  
    T[2] = lit(AST__LIT, '=', A[ap+1]);
    T[0] = mktuple(AST_COMP, alt /*6*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {  
    T[1] = lit(AST__LIT, '>', A[ap+0]);
    T[0] = mktuple(AST_COMP, alt /*7*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # '<>' is a really obscure form but it definitely used to be used.  I'll
//\\ # post a reference as soon as I locate one.
//\\ #

//\\ P<NOT-EQUALS> = 
//\\    '#',
//\\    '\\' '=',
//\\    '<' '>';

case P_NOT_EQUALS:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '#', A[ap+0]);
    T[0] = mktuple(AST_NOT_EQUALS, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, '\\', A[ap+0]);  
    T[2] = lit(AST__LIT, '=', A[ap+1]);
    T[0] = mktuple(AST_NOT_EQUALS, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {  
    T[1] = lit(AST__LIT, '<', A[ap+0]);  
    T[2] = lit(AST__LIT, '>', A[ap+1]);
    T[0] = mktuple(AST_NOT_EQUALS, alt /*2*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];




//\\ P<NOT-EQUALS-ADDRESS> = 
//\\    '#' '#',
//\\    '\\' '=' '=';

case P_NOT_EQUALS_ADDRESS:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '#', A[ap+0]);  
    T[2] = lit(AST__LIT, '#', A[ap+1]);
    T[0] = mktuple(AST_NOT_EQUALS_ADDRESS, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {  
    T[1] = lit(AST__LIT, '\\', A[ap+0]);  
    T[2] = lit(AST__LIT, '=', A[ap+1]);  
    T[3] = lit(AST__LIT, '=', A[ap+2]);
    T[0] = mktuple(AST_NOT_EQUALS_ADDRESS, alt /*1*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  }
  return T[0];



//\\ # Procedure application, i.e. actual parameters to routine or function call

//\\ P<OPT-ACTUAL-PARAMETERS> = 
//\\    '(' <EXPR> <REST-OF-ACTUAL-PARAMETERS> ')',
//\\   ;

case P_OPT_ACTUAL_PARAMETERS:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '(', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <EXPR>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-ACTUAL-PARAMETERS>  
    T[4] = lit(AST__LIT, ')', A[ap+3]);
    T[0] = mktuple(AST_OPT_ACTUAL_PARAMETERS, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else               {
    T[0] = mktuple(AST_OPT_ACTUAL_PARAMETERS, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<REST-OF-ACTUAL-PARAMETERS> = 
//\\    ',' <EXPR> <REST-OF-ACTUAL-PARAMETERS>,
//\\   ;

case P_REST_OF_ACTUAL_PARAMETERS:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <EXPR>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-ACTUAL-PARAMETERS>
    T[0] = mktuple(AST_REST_OF_ACTUAL_PARAMETERS, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_ACTUAL_PARAMETERS, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # handling precedence withh the grammar rather than Edinburgh-style in the AST. Tradeoff of speed for simplicity.
//\\ # CEXPR not handled yet

//\\ P<EXPR> = 
//\\    <MEDIUMPREC-EXPR> <REST-OF-EXPR>;

case P_EXPR:
  T[1] = build_ast(A[ap+0], depth+1); // <MEDIUMPREC-EXPR>
  T[2] = build_ast(A[ap+1], depth+1); // <REST-OF-EXPR>
  return mktuple(AST_EXPR, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);



//\\ P<REST-OF-EXPR> = 
//\\    <OP-LOW> <MEDIUMPREC-EXPR> <REST-OF-EXPR>,
//\\   ;

case P_REST_OF_EXPR:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <OP-LOW>
    T[2] = build_ast(A[ap+1], depth+1); // <MEDIUMPREC-EXPR>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-EXPR>
    T[0] = mktuple(AST_REST_OF_EXPR, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_EXPR, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<MEDIUMPREC-EXPR> = 
//\\    <HIGHPREC-EXPR> <REST-OF-MEDIUMPREC-EXPR>;

case P_MEDIUMPREC_EXPR:
  T[1] = build_ast(A[ap+0], depth+1); // <HIGHPREC-EXPR>
  T[2] = build_ast(A[ap+1], depth+1); // <REST-OF-MEDIUMPREC-EXPR>
  return mktuple(AST_MEDIUMPREC_EXPR, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);



//\\ P<REST-OF-MEDIUMPREC-EXPR> = 
//\\    <OP-MED> <HIGHPREC-EXPR> <REST-OF-MEDIUMPREC-EXPR>,
//\\   ;

case P_REST_OF_MEDIUMPREC_EXPR:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <OP-MED>
    T[2] = build_ast(A[ap+1], depth+1); // <HIGHPREC-EXPR>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-MEDIUMPREC-EXPR>
    T[0] = mktuple(AST_REST_OF_MEDIUMPREC_EXPR, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_MEDIUMPREC_EXPR, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<HIGHPREC-EXPR> = 
//\\    <RIGHT-ASSOC-EXPR> <REST-OF-HIGHPREC-EXPR>;

case P_HIGHPREC_EXPR:
  T[1] = build_ast(A[ap+0], depth+1); // <RIGHT-ASSOC-EXPR>
  T[2] = build_ast(A[ap+1], depth+1); // <REST-OF-HIGHPREC-EXPR>
  return mktuple(AST_HIGHPREC_EXPR, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);



//\\ P<REST-OF-HIGHPREC-EXPR> = 
//\\    <OP-HIGH-LEFTASSOC> <RIGHT-ASSOC-EXPR> <REST-OF-HIGHPREC-EXPR>,
//\\   ;

case P_REST_OF_HIGHPREC_EXPR:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <OP-HIGH-LEFTASSOC>
    T[2] = build_ast(A[ap+1], depth+1); // <RIGHT-ASSOC-EXPR>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-HIGHPREC-EXPR>
    T[0] = mktuple(AST_REST_OF_HIGHPREC_EXPR, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_HIGHPREC_EXPR, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<RIGHT-ASSOC-EXPR> = 
//\\    <REST-OF-RIGHTASSOC-EXPR> <UNARY-EXPR>;

case P_RIGHT_ASSOC_EXPR:
  T[1] = build_ast(A[ap+0], depth+1); // <REST-OF-RIGHTASSOC-EXPR>
  T[2] = build_ast(A[ap+1], depth+1); // <UNARY-EXPR>
  return mktuple(AST_RIGHT_ASSOC_EXPR, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);



//\\ P<REST-OF-RIGHTASSOC-EXPR> = 
//\\    <RIGHTASSOC-EXPR-with-OP> <REST-OF-RIGHTASSOC-EXPR>,
//\\   ;

case P_REST_OF_RIGHTASSOC_EXPR:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <RIGHTASSOC-EXPR-with-OP>
    T[2] = build_ast(A[ap+1], depth+1); // <REST-OF-RIGHTASSOC-EXPR>
    T[0] = mktuple(AST_REST_OF_RIGHTASSOC_EXPR, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_RIGHTASSOC_EXPR, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<RIGHTASSOC-EXPR-with-OP> = 
//\\    <UNARY-EXPR> <OP-HIGH-RIGHTASSOC>;

case P_RIGHTASSOC_EXPR_with_OP:
  T[1] = build_ast(A[ap+0], depth+1); // <UNARY-EXPR>
  T[2] = build_ast(A[ap+1], depth+1); // <OP-HIGH-RIGHTASSOC>
  return mktuple(AST_RIGHTASSOC_EXPR_with_OP, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);



//\\ P<UNARY-EXPR> = 
//\\    <Opt-UNARY-OP> <OPERAND>;

case P_UNARY_EXPR:
  T[1] = build_ast(A[ap+0], depth+1); // <Opt-UNARY-OP>
  T[2] = build_ast(A[ap+1], depth+1); // <OPERAND>
  return mktuple(AST_UNARY_EXPR, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);


//\\ # These pointer arithmetic elements are for Hamish's PDP9/15 Imp (old): INDP == INDEX0++P
//\\ # and for Hamish's 68000 Imp:     %if tp[1]_mode # litmode %then lo = minint %else lo = tp[1]_val
//\\ # I hope this grammar definition causes the right precedence level...
//\\ #
//\\ # They can also be used in LVALUEs.

//\\ P<Opt-PARAMETERS-OR-POINTERINDEX> = 
//\\    '[' <EXPR> ']',
//\\    '+' '+' <EXPR>,
//\\    '-' '-' <EXPR>,
//\\    <OPT-ACTUAL-PARAMETERS>;

case P_Opt_PARAMETERS_OR_POINTERINDEX:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '[', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <EXPR>  
    T[3] = lit(AST__LIT, ']', A[ap+2]);
    T[0] = mktuple(AST_Opt_PARAMETERS_OR_POINTERINDEX, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, '+', A[ap+0]);  
    T[2] = lit(AST__LIT, '+', A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <EXPR>
    T[0] = mktuple(AST_Opt_PARAMETERS_OR_POINTERINDEX, alt /*1*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 2) {  
    T[1] = lit(AST__LIT, '-', A[ap+0]);  
    T[2] = lit(AST__LIT, '-', A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <EXPR>
    T[0] = mktuple(AST_Opt_PARAMETERS_OR_POINTERINDEX, alt /*2*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-ACTUAL-PARAMETERS>
    T[0] = mktuple(AST_Opt_PARAMETERS_OR_POINTERINDEX, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];




//\\ P<Opt-RECORDFIELD> = 
//\\    '_' <NAME> <Opt-PARAMETERS-OR-POINTERINDEX> <Opt-RECORDFIELD>,
//\\   ;

case P_Opt_RECORDFIELD:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '_', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-PARAMETERS-OR-POINTERINDEX>
    T[4] = build_ast(A[ap+3], depth+1); // <Opt-RECORDFIELD>
    T[0] = mktuple(AST_Opt_RECORDFIELD, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else               {
    T[0] = mktuple(AST_Opt_RECORDFIELD, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<Opt-RECORDFIELD-OR-POINTERINDEX> = 
//\\    '_' <NAME> <Opt-PARAMETERS-OR-POINTERINDEX> <Opt-RECORDFIELD-OR-POINTERINDEX>,
//\\   ;

case P_Opt_RECORDFIELD_OR_POINTERINDEX:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '_', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-PARAMETERS-OR-POINTERINDEX>
    T[4] = build_ast(A[ap+3], depth+1); // <Opt-RECORDFIELD-OR-POINTERINDEX>
    T[0] = mktuple(AST_Opt_RECORDFIELD_OR_POINTERINDEX, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else               {
    T[0] = mktuple(AST_Opt_RECORDFIELD_OR_POINTERINDEX, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # The old form of modulus (!X!) is for really ancient compilers such as Hamish's Pdp15 Imp.
//\\ # Unfortunately there are obscure cases where an ambiguous parse results:
//\\ #
//\\ #  putact(condop!!polarity!!1+polarity<<7,item,0)
//\\ #
//\\ # Does that mean
//\\ #   putact(condop !!  polarity   !!  1 + polarity<<7, item, 0)
//\\ # or
//\\ #   putact(condop !  !polarity!  !   1 + polarity<<7, item, 0)
//\\ #
//\\ # I need to check but I *hope* that the grammar here causes the first of the above to be selected.
//\\ # If not, we'll need a command-line option here to force the version of Imp being used.
//\\ #
//\\ # I just hope that there's no version of Imp that ever supported factorials with a postfix '!'
//\\ #

//\\ P<OPERAND> = 
//\\    <NAME> <Opt-PARAMETERS-OR-POINTERINDEX> <Opt-RECORDFIELD-OR-POINTERINDEX>,
//\\    <CONST>,
//\\    '(' <EXPR> ')',
//\\    '|' <EXPR> '|',
//\\    '!' <EXPR> '!';

case P_OPERAND:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-PARAMETERS-OR-POINTERINDEX>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-RECORDFIELD-OR-POINTERINDEX>
    T[0] = mktuple(AST_OPERAND, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <CONST>
    T[0] = mktuple(AST_OPERAND, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 2) {  
    T[1] = lit(AST__LIT, '(', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <EXPR>  
    T[3] = lit(AST__LIT, ')', A[ap+2]);
    T[0] = mktuple(AST_OPERAND, alt /*2*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 3) {  
    T[1] = lit(AST__LIT, '|', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <EXPR>  
    T[3] = lit(AST__LIT, '|', A[ap+2]);
    T[0] = mktuple(AST_OPERAND, alt /*3*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {  
    T[1] = lit(AST__LIT, '!', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <EXPR>  
    T[3] = lit(AST__LIT, '!', A[ap+2]);
    T[0] = mktuple(AST_OPERAND, alt /*4*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  }
  return T[0];



//\\ # <OP> is only used in <CEXPR>s now and will be removed entirely
//\\ # once CEXPRs are recoded to use the same grammar as EXPRs.
//\\ #
//\\ # *However* I am considering doing away with CEXPRs altogether,
//\\ # and just using <EXPR> everywhere, in conjunction with a parse-time
//\\ # test to check whether any of the terms were in fact *not* constants.
//\\ #
//\\ # Also... it's not obvious if we could in fact use EXPRs everywhere *without*
//\\ # the overhead of having to organise the code/name tables so that they
//\\ # can be checked for being constants at parse time, and merely reject
//\\ # them from the compile() procedure instead?  This would be possible
//\\ # as long as there are no parse ambiguities caused by checking after
//\\ # parsing. I know that's a problem in C but Imp's simpler syntax
//\\ # might let us get away with it!
//\\ #
//\\ # Note that none of these options eliminates the possibility of implementing
//\\ # conditional compilation the EMAS Imp80 way using
//\\ #
//\\ # %if <CEXPR> %start
//\\ #   ! conditional code
//\\ # %finish
//\\ #
//\\ # (Though I've always had questions about that on EMAS if there's a
//\\ #  label inside the block - the ability to use that construct for
//\\ #  conditional compilation depends on whether that label is ever
//\\ #  jumped to from code outside the block! - doing it properly requires
//\\ #  full flow control analysis and a transitive closure on the flow graph!)
//\\ #

//\\ P<OP> = 
//\\    <OP-HIGH-LEFTASSOC>,
//\\    <OP-HIGH-RIGHTASSOC>,
//\\    <OP-MED>,
//\\    <OP-LOW>;

case P_OP:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <OP-HIGH-LEFTASSOC>
    T[0] = mktuple(AST_OP, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <OP-HIGH-RIGHTASSOC>
    T[0] = mktuple(AST_OP, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 2) {
    T[1] = build_ast(A[ap+0], depth+1); // <OP-MED>
    T[0] = mktuple(AST_OP, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <OP-LOW>
    T[0] = mktuple(AST_OP, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # highest precedence, left-associative

//\\ P<OP-HIGH-LEFTASSOC> = 
//\\    '<' '<',
//\\    '>' '>';

case P_OP_HIGH_LEFTASSOC:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '<', A[ap+0]);  
    T[2] = lit(AST__LIT, '<', A[ap+1]);
    T[0] = mktuple(AST_OP_HIGH_LEFTASSOC, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {  
    T[1] = lit(AST__LIT, '>', A[ap+0]);  
    T[2] = lit(AST__LIT, '>', A[ap+1]);
    T[0] = mktuple(AST_OP_HIGH_LEFTASSOC, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];



//\\ # highest precedence, right-associative (only exponentiation)
//\\ #
//\\ # I found this expression the 68000 Imp compiler:
//\\ #
//\\ #           y = |r|+0.5/10.0\{^}m;  !modulus, rounded
//\\ #
//\\ # which I parse as:
//\\ #
//\\ #           y = |r|+( 0.5 / (10.0\{^}m));  !modulus, rounded
//\\ #
//\\ # I presume this is a clever way to round the last digit of a decimal,
//\\ # but damn, how it works is beyond me.
//\\ # Typical Hamish code! Brilliant (I presume) but obscure and uncommented.
//\\ #

//\\ P<OP-HIGH-RIGHTASSOC> = 
//\\    <INTEGER-EXP>,
//\\    <REAL-EXP>;

case P_OP_HIGH_RIGHTASSOC:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <INTEGER-EXP>
    T[0] = mktuple(AST_OP_HIGH_RIGHTASSOC, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <REAL-EXP>
    T[0] = mktuple(AST_OP_HIGH_RIGHTASSOC, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];




//\\ P<INTEGER-EXP> = 
//\\    '*' '*' '*' '*',
//\\    '\\' '\\',
//\\    '^' '^';

case P_INTEGER_EXP:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '*', A[ap+0]);  
    T[2] = lit(AST__LIT, '*', A[ap+1]);  
    T[3] = lit(AST__LIT, '*', A[ap+2]);  
    T[4] = lit(AST__LIT, '*', A[ap+3]);
    T[0] = mktuple(AST_INTEGER_EXP, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, '\\', A[ap+0]);  
    T[2] = lit(AST__LIT, '\\', A[ap+1]);
    T[0] = mktuple(AST_INTEGER_EXP, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {  
    T[1] = lit(AST__LIT, '^', A[ap+0]);  
    T[2] = lit(AST__LIT, '^', A[ap+1]);
    T[0] = mktuple(AST_INTEGER_EXP, alt /*2*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];




//\\ P<REAL-EXP> = 
//\\    '*' '*',
//\\    '\\',
//\\    '^';

case P_REAL_EXP:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '*', A[ap+0]);  
    T[2] = lit(AST__LIT, '*', A[ap+1]);
    T[0] = mktuple(AST_REAL_EXP, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, '\\', A[ap+0]);
    T[0] = mktuple(AST_REAL_EXP, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = lit(AST__LIT, '^', A[ap+0]);
    T[0] = mktuple(AST_REAL_EXP, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # middle-precedence operators.  All left-associative.

//\\ P<OP-MED> = 
//\\    '*',
//\\    '/' '/',
//\\    '/',
//\\    '&';

case P_OP_MED:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '*', A[ap+0]);
    T[0] = mktuple(AST_OP_MED, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, '/', A[ap+0]);  
    T[2] = lit(AST__LIT, '/', A[ap+1]);
    T[0] = mktuple(AST_OP_MED, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 2) {  
    T[1] = lit(AST__LIT, '/', A[ap+0]);
    T[0] = mktuple(AST_OP_MED, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = lit(AST__LIT, '&', A[ap+0]);
    T[0] = mktuple(AST_OP_MED, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # lowest precedence operators.  All left-associative.

//\\ P<OP-LOW> = 
//\\    '+',
//\\    '-',
//\\    '!' '!',
//\\    '!',
//\\    '.';

case P_OP_LOW:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '+', A[ap+0]);
    T[0] = mktuple(AST_OP_LOW, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, '-', A[ap+0]);
    T[0] = mktuple(AST_OP_LOW, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 2) {  
    T[1] = lit(AST__LIT, '!', A[ap+0]);  
    T[2] = lit(AST__LIT, '!', A[ap+1]);
    T[0] = mktuple(AST_OP_LOW, alt /*2*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 3) {  
    T[1] = lit(AST__LIT, '!', A[ap+0]);
    T[0] = mktuple(AST_OP_LOW, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = lit(AST__LIT, '.', A[ap+0]);
    T[0] = mktuple(AST_OP_LOW, alt /*4*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # You would think that unary operators always have the highest precedence,
//\\ # but not so - here's a tricky one...
//\\ #
//\\ # I = -1 >> 1
//\\ #
//\\ # This always has the value 0, regardless of integer size, because a unary minus
//\\ # in front of a constant is *NOT* interpreted as a negative constant, but rather
//\\ # the positive constant preceded by a unary negation operator.
//\\ #
//\\ # It gets worse... unary negation is implemented as binary subtraction with
//\\ # an inserted '0' left operand, i.e.
//\\ #
//\\ # 0 - 1 >> 1
//\\ #
//\\ # Shifts have higher precedence than subtraction, so this becomes:
//\\ #
//\\ # 0 - (1 >> 1)
//\\ #
//\\ # which evaluates to 0.
//\\ #
//\\ # The 68000 Imp compiler includes this statement which I hope is correct! dict(firstpos)_val = -cad>>1
//\\ #
//\\ # Some versions of Imp (I think Imp80) forbid a unary '+' before constants,
//\\ # so A + +3 would be illegal (although A + -3 would not)
//\\ #
//\\ # and none of this applies to binary-not (\) so \3 really is higher
//\\ # priority than '>>' and \3 >> 1 does what you would expect.  I hope.
//\\ #

//\\ P<Opt-UNARY-OP> = 
//\\    '+',
//\\    '-',
//\\    <UNARY-NOT>,
//\\   ;

case P_Opt_UNARY_OP:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '+', A[ap+0]);
    T[0] = mktuple(AST_Opt_UNARY_OP, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, '-', A[ap+0]);
    T[0] = mktuple(AST_Opt_UNARY_OP, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 2) {
    T[1] = build_ast(A[ap+0], depth+1); // <UNARY-NOT>
    T[0] = mktuple(AST_Opt_UNARY_OP, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_Opt_UNARY_OP, alt /*3*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # fortunately unary backslash is unambiguous with ERCC style exponentiation binary operator

//\\ P<UNARY-NOT> = 
//\\    '\\',
//\\    '~';

case P_UNARY_NOT:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '\\', A[ap+0]);
    T[0] = mktuple(AST_UNARY_NOT, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = lit(AST__LIT, '~', A[ap+0]);
    T[0] = mktuple(AST_UNARY_NOT, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];




//\\ P<Percent-IU> = 
//\\    "if",
//\\    "unless";

case P_Percent_IU:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_if, A[ap+0]);
    T[0] = mktuple(AST_Percent_IU, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_unless, A[ap+0]);
    T[0] = mktuple(AST_Percent_IU, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # rest of %switch list
//\\ # This reminds me, isn't there an optional %label declaration in Imp?  Haven't seen an example yet,
//\\ # I need to check the manuals to make sure I'm not confusing this with C...

//\\ P<REST-OF-SWLIST> = 
//\\    ',' <NAME> <Opt-NAME-LIST> '(' <EXPR> ':' <EXPR> ')' <REST-OF-SWLIST>,
//\\   ;

case P_REST_OF_SWLIST:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-NAME-LIST>  
    T[4] = lit(AST__LIT, '(', A[ap+3]);
    T[5] = build_ast(A[ap+4], depth+1); // <EXPR>  
    T[6] = lit(AST__LIT, ':', A[ap+5]);
    T[7] = build_ast(A[ap+6], depth+1); // <EXPR>  
    T[8] = lit(AST__LIT, ')', A[ap+7]);
    T[9] = build_ast(A[ap+8], depth+1); // <REST-OF-SWLIST>
    T[0] = mktuple(AST_REST_OF_SWLIST, alt /*0*/, /*phrases*/ 9, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8], T[9]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_SWLIST, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<Opt-NAME-LIST> = 
//\\    ',' <NAME> <Opt-NAME-LIST>,
//\\   ;

case P_Opt_NAME_LIST:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-NAME-LIST>
    T[0] = mktuple(AST_Opt_NAME_LIST, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_Opt_NAME_LIST, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<REST-OF-NAME-LIST> = 
//\\    ',' <CEXPR> <REST-OF-NAME-LIST>,
//\\   ;

case P_REST_OF_NAME_LIST:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <CEXPR>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-NAME-LIST>
    T[0] = mktuple(AST_REST_OF_NAME_LIST, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_NAME_LIST, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # Still to handle operator precedence etc for <CEXPR>s the same way as for <EXPR>s.
//\\ # However it is such a major duplication of effort that it might be much easier to
//\\ # just use <EXPR>s and have a semantic test for constantcy.
//\\ # The problem is the ambiguity of <NAMES>.  And you don't want any of the decorated
//\\ # forms of a name (records, function calls, pointers, maybe even rejecting const
//\\ # array elements?) - just simple literals and const integer operands.

//\\ P<CEXPR> = 
//\\    <Opt-UNARY-OP> <COPERAND> <REST-OF-CEXPR>;

case P_CEXPR:
  T[1] = build_ast(A[ap+0], depth+1); // <Opt-UNARY-OP>
  T[2] = build_ast(A[ap+1], depth+1); // <COPERAND>
  T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-CEXPR>
  return mktuple(AST_CEXPR, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);



//\\ P<REST-OF-CEXPR> = 
//\\    <OP> <COPERAND> <REST-OF-CEXPR>,
//\\   ;

case P_REST_OF_CEXPR:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <OP>
    T[2] = build_ast(A[ap+1], depth+1); // <COPERAND>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-CEXPR>
    T[0] = mktuple(AST_REST_OF_CEXPR, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_CEXPR, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<COPERAND> = 
//\\    <NAME>,
//\\    <CONST>,
//\\    '(' <CEXPR> ')',
//\\    '|' <CEXPR> '|',
//\\    '!' <CEXPR> '!';

case P_COPERAND:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>
    T[0] = mktuple(AST_COPERAND, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <CONST>
    T[0] = mktuple(AST_COPERAND, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 2) {  
    T[1] = lit(AST__LIT, '(', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <CEXPR>  
    T[3] = lit(AST__LIT, ')', A[ap+2]);
    T[0] = mktuple(AST_COPERAND, alt /*2*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 3) {  
    T[1] = lit(AST__LIT, '|', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <CEXPR>  
    T[3] = lit(AST__LIT, '|', A[ap+2]);
    T[0] = mktuple(AST_COPERAND, alt /*3*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {  
    T[1] = lit(AST__LIT, '!', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <CEXPR>  
    T[3] = lit(AST__LIT, '!', A[ap+2]);
    T[0] = mktuple(AST_COPERAND, alt /*4*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  }
  return T[0];




//\\ P<OPT-event> = 
//\\    "event",
//\\   ;

case P_OPT_event:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_event, A[ap+0]);
    T[0] = mktuple(AST_OPT_event, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_event, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<FPP> = 
//\\    '(' <FORMAL-PARAMETER-DECLARATION> <REST-OF-FORMAL-PARAMETER-LIST> ')',
//\\   ;

case P_FPP:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '(', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <FORMAL-PARAMETER-DECLARATION>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-FORMAL-PARAMETER-LIST>  
    T[4] = lit(AST__LIT, ')', A[ap+3]);
    T[0] = mktuple(AST_FPP, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else               {
    T[0] = mktuple(AST_FPP, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<REST-OF-FORMAL-PARAMETER-LIST> = 
//\\    <Opt-Comma> <FORMAL-PARAMETER-DECLARATION> <REST-OF-FORMAL-PARAMETER-LIST>,
//\\   ;

case P_REST_OF_FORMAL_PARAMETER_LIST:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <Opt-Comma>
    T[2] = build_ast(A[ap+1], depth+1); // <FORMAL-PARAMETER-DECLARATION>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-FORMAL-PARAMETER-LIST>
    T[0] = mktuple(AST_REST_OF_FORMAL_PARAMETER_LIST, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_FORMAL_PARAMETER_LIST, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # %routine y (%integer %name %array (1) %name b)
//\\ # %routine r10(%integer%array%name a(1:10),%integer k)

//\\ P<FORMAL-PARAMETER-DECLARATION> = 
//\\    <XTYPE> <OPT-arrayname> <NAME> <OPT-68K-Bounds> <Opt-NAME-LIST>,
//\\    <RT> <OPT-name> <NAME> <Opt-NAME-LIST> <FPP>,
//\\    "name" <Opt-68K-reg> <NAME> <Opt-NAME-LIST>;

case P_FORMAL_PARAMETER_DECLARATION:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <XTYPE>
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-arrayname>
    T[3] = build_ast(A[ap+2], depth+1); // <NAME>
    T[4] = build_ast(A[ap+3], depth+1); // <OPT-68K-Bounds>
    T[5] = build_ast(A[ap+4], depth+1); // <Opt-NAME-LIST>
    T[0] = mktuple(AST_FORMAL_PARAMETER_DECLARATION, alt /*0*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <RT>
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-name>
    T[3] = build_ast(A[ap+2], depth+1); // <NAME>
    T[4] = build_ast(A[ap+3], depth+1); // <Opt-NAME-LIST>
    T[5] = build_ast(A[ap+4], depth+1); // <FPP>
    T[0] = mktuple(AST_FORMAL_PARAMETER_DECLARATION, alt /*1*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_name, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-68K-reg>
    T[3] = build_ast(A[ap+2], depth+1); // <NAME>
    T[4] = build_ast(A[ap+3], depth+1); // <Opt-NAME-LIST>
    T[0] = mktuple(AST_FORMAL_PARAMETER_DECLARATION, alt /*2*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  }
  return T[0];



//\\ # More Hamish idiosyncracy!:
//\\ #
//\\ # @16_1114%record(*)%map ZNEW(%name(d0) v)
//\\ #  - APM-gdmr/I/VPERM19.imp
//\\ #      d0 being a register
//\\ #

//\\ P<Opt-68K-reg> = 
//\\    '(' <NAME> ')',
//\\   ;

case P_Opt_68K_reg:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '(', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>  
    T[3] = lit(AST__LIT, ')', A[ap+2]);
    T[0] = mktuple(AST_Opt_68K_reg, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_Opt_68K_reg, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<OPT-name> = 
//\\    "name",
//\\   ;

case P_OPT_name:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_name, A[ap+0]);
    T[0] = mktuple(AST_OPT_name, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_name, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # added predicate - gt

//\\ P<RT> = 
//\\    "routine",
//\\    "predicate",
//\\    <XTYPE> <FN-MAP>;

case P_RT:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_routine, A[ap+0]);
    T[0] = mktuple(AST_RT, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_predicate, A[ap+0]);
    T[0] = mktuple(AST_RT, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <XTYPE>
    T[2] = build_ast(A[ap+1], depth+1); // <FN-MAP>
    T[0] = mktuple(AST_RT, alt /*2*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];



//\\ # note map is equivalent to "name function"

//\\ P<FN-MAP> = 
//\\    <FN>,
//\\    "map";

case P_FN_MAP:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <FN>
    T[0] = mktuple(AST_FN_MAP, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_map, A[ap+0]);
    T[0] = mktuple(AST_FN_MAP, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];




//\\ P<FN> = 
//\\    "fn",
//\\    "function";

case P_FN:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_fn, A[ap+0]);
    T[0] = mktuple(AST_FN, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_function, A[ap+0]);
    T[0] = mktuple(AST_FN, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # Confirmed that label is used.  Found one in 68000 code for labels used in embeddded machine code:
//\\ # %label f1,f2,f3,f4,f5,f6,f7,b0,b1,b2,b3,b4,b5,b6,b7,end
//\\ #
//\\ # "long long" would be added here if we supported 64 bit ints or 128bit reals...
//\\ # Okain "long" added here by making <BTYPE> optional.
//\\ # (BTYPE being integer/real/longreal)
//\\ #

//\\ P<BASE-XTYPE> = 
//\\    "integer",
//\\    "real",
//\\    "label",
//\\    "long" <Opt-BTYPE>,
//\\    "byte" <Opt-INTEGER>,
//\\    "mite" <Opt-INTEGER>,
//\\    "short" <Opt-INTEGER>,
//\\    "half" <Opt-INTEGER>,
//\\    "string" <REPFACT>,
//\\    "record" <Opt-RFREF>;

case P_BASE_XTYPE:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_integer, A[ap+0]);
    T[0] = mktuple(AST_BASE_XTYPE, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_real, A[ap+0]);
    T[0] = mktuple(AST_BASE_XTYPE, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 2) {  
    T[1] = kw(AST__KW, KW_label, A[ap+0]);
    T[0] = mktuple(AST_BASE_XTYPE, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 3) {  
    T[1] = kw(AST__KW, KW_long, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-BTYPE>
    T[0] = mktuple(AST_BASE_XTYPE, alt /*3*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 4) {  
    T[1] = kw(AST__KW, KW_byte, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-INTEGER>
    T[0] = mktuple(AST_BASE_XTYPE, alt /*4*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 5) {  
    T[1] = kw(AST__KW, KW_mite, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-INTEGER>
    T[0] = mktuple(AST_BASE_XTYPE, alt /*5*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 6) {  
    T[1] = kw(AST__KW, KW_short, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-INTEGER>
    T[0] = mktuple(AST_BASE_XTYPE, alt /*6*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 7) {  
    T[1] = kw(AST__KW, KW_half, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-INTEGER>
    T[0] = mktuple(AST_BASE_XTYPE, alt /*7*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 8) {  
    T[1] = kw(AST__KW, KW_string, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <REPFACT>
    T[0] = mktuple(AST_BASE_XTYPE, alt /*8*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_record, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-RFREF>
    T[0] = mktuple(AST_BASE_XTYPE, alt /*9*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];



//\\ # does %record(i tc f)%name match <XTYPE>?
//\\ #
//\\ # Courtesy of Hamish, two more language extensions:
//\\ #
//\\ # Two <OPT-68K-qualifier>s to allow one or both of %writeonly %volatile %byte %integer device
//\\ #

//\\ P<XTYPE> = 
//\\    <OPT-68K-qualifier> <BASE-XTYPE> <OPT-name>;

case P_XTYPE:
  T[1] = build_ast(A[ap+0], depth+1); // <OPT-68K-qualifier>
  T[2] = build_ast(A[ap+1], depth+1); // <BASE-XTYPE>
  T[3] = build_ast(A[ap+2], depth+1); // <OPT-name>
  return mktuple(AST_XTYPE, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);



//\\ P<68K-memptr> = 
//\\    "read" "only" <68K-memptr>,
//\\    "write" "only" <68K-memptr>,
//\\    "volatile" <68K-memptr>,
//\\   ;

case P_68K_memptr:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_read, A[ap+0]);  
    T[2] = kw(AST__KW, KW_only, A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <68K-memptr>
    T[0] = mktuple(AST_68K_memptr, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_write, A[ap+0]);  
    T[2] = kw(AST__KW, KW_only, A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <68K-memptr>
    T[0] = mktuple(AST_68K_memptr, alt /*1*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 2) {  
    T[1] = kw(AST__KW, KW_volatile, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <68K-memptr>
    T[0] = mktuple(AST_68K_memptr, alt /*2*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_68K_memptr, alt /*3*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<OPT-68K-qualifier> = 
//\\    <68K-register>,
//\\    <68K-memptr>,
//\\   ;

case P_OPT_68K_qualifier:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <68K-register>
    T[0] = mktuple(AST_OPT_68K_qualifier, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <68K-memptr>
    T[0] = mktuple(AST_OPT_68K_qualifier, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_68K_qualifier, alt /*2*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # C-like register qualifiers (Hamish, again)
//\\ # %register(a2)%integer r1,r2
//\\ # %register(a2)%byte%name bn
//\\ # %register(a3)%short%name sn

//\\ P<68K-register> = 
//\\    "register" '(' <NAME> ')';

case P_68K_register:
  T[1] = kw(AST__KW, KW_register, A[ap+0]);
  T[2] = lit(AST__LIT, '(', A[ap+1]);
  T[3] = build_ast(A[ap+2], depth+1); // <NAME>
  T[4] = lit(AST__LIT, ')', A[ap+3]);
  return mktuple(AST_68K_register, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);


//\\ # '*' added by gt for recordformat(*)
//\\ # () moved from point of call to here to support old style "%recordname fred" without format. (Uses a formatspec instead)

//\\ P<Opt-RFREF> = 
//\\    '(' <RECFMT-REF> ')',
//\\    '(' '*' ')',
//\\   ;

case P_Opt_RFREF:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '(', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <RECFMT-REF>  
    T[3] = lit(AST__LIT, ')', A[ap+2]);
    T[0] = mktuple(AST_Opt_RFREF, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, '(', A[ap+0]);  
    T[2] = lit(AST__LIT, '*', A[ap+1]);  
    T[3] = lit(AST__LIT, ')', A[ap+2]);
    T[0] = mktuple(AST_Opt_RFREF, alt /*1*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_Opt_RFREF, alt /*2*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # RF in the rules below is short for Record Format

//\\ P<RECFMT-REF> = 
//\\    <NAME>,
//\\    <RECFMT-DEC> <REST-OF-RECFMT-DEC> <ALT-RECFMT-DEC>;

case P_RECFMT_REF:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>
    T[0] = mktuple(AST_RECFMT_REF, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <RECFMT-DEC>
    T[2] = build_ast(A[ap+1], depth+1); // <REST-OF-RECFMT-DEC>
    T[3] = build_ast(A[ap+2], depth+1); // <ALT-RECFMT-DEC>
    T[0] = mktuple(AST_RECFMT_REF, alt /*1*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  }
  return T[0];



//\\ # Imp variant record. NOT the same as C's which is per field.  This is per record.
//\\ # Still to check: a ( ... %or ... ) subgroup in a record definition, where the ...
//\\ # represents several declarations, with the whole ( ... ) group being a part
//\\ # of an enclosing record.
//\\ #

//\\ P<ALT-RECFMT-DEC> = 
//\\    "or" <RECFMT-DEC> <REST-OF-RECFMT-DEC> <ALT-RECFMT-DEC>,
//\\   ;

case P_ALT_RECFMT_DEC:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_or, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <RECFMT-DEC>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-RECFMT-DEC>
    T[4] = build_ast(A[ap+3], depth+1); // <ALT-RECFMT-DEC>
    T[0] = mktuple(AST_ALT_RECFMT_DEC, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else               {
    T[0] = mktuple(AST_ALT_RECFMT_DEC, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<REST-OF-RECFMT-DEC> = 
//\\    ',' <RECFMT-DEC> <REST-OF-RECFMT-DEC>,
//\\   ;

case P_REST_OF_RECFMT_DEC:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <RECFMT-DEC>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-RECFMT-DEC>
    T[0] = mktuple(AST_REST_OF_RECFMT_DEC, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_RECFMT_DEC, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<RECFMT-DEC> = 
//\\    <XTYPE> <RECFMT-ELMNT>,
//\\    '(' <RECFMT-DEC> <REST-OF-RECFMT-DEC> <ALT-RECFMT-DEC> ')';

case P_RECFMT_DEC:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <XTYPE>
    T[2] = build_ast(A[ap+1], depth+1); // <RECFMT-ELMNT>
    T[0] = mktuple(AST_RECFMT_DEC, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {  
    T[1] = lit(AST__LIT, '(', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <RECFMT-DEC>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-RECFMT-DEC>
    T[4] = build_ast(A[ap+3], depth+1); // <ALT-RECFMT-DEC>  
    T[5] = lit(AST__LIT, ')', A[ap+4]);
    T[0] = mktuple(AST_RECFMT_DEC, alt /*1*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  }
  return T[0];



//\\ # Now "name" has been removed from <OPT-arrayname-or-name>, check at the point
//\\ # of invocation, that "name" still works, now it as been added to <XTYPE>...
//\\ #

//\\ P<RECFMT-ELMNT> = 
//\\    <OPT-arrayname> <NAME> <Opt-NAME-LIST>,
//\\    "array" <ADECLN-in-record>;

case P_RECFMT_ELMNT:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-arrayname>
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-NAME-LIST>
    T[0] = mktuple(AST_RECFMT_ELMNT, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_array, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <ADECLN-in-record>
    T[0] = mktuple(AST_RECFMT_ELMNT, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];



//\\ # Array declaration

//\\ P<ADECLN-in-record> = 
//\\    <NAME> <Opt-NAME-LIST> <BPAIR> <REST-OF-ARLIST-in-record>;

case P_ADECLN_in_record:
  T[1] = build_ast(A[ap+0], depth+1); // <NAME>
  T[2] = build_ast(A[ap+1], depth+1); // <Opt-NAME-LIST>
  T[3] = build_ast(A[ap+2], depth+1); // <BPAIR>
  T[4] = build_ast(A[ap+3], depth+1); // <REST-OF-ARLIST-in-record>
  return mktuple(AST_ADECLN_in_record, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);



//\\ P<REST-OF-ARLIST-in-record> = 
//\\    ',' <ADECLN-in-record>,
//\\   ;

case P_REST_OF_ARLIST_in_record:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <ADECLN-in-record>
    T[0] = mktuple(AST_REST_OF_ARLIST_in_record, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_ARLIST_in_record, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<LOWERBOUND> = 
//\\    <EXPR>,
//\\    <BASE-XTYPE> <NAME>;

case P_LOWERBOUND:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <EXPR>
    T[0] = mktuple(AST_LOWERBOUND, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <BASE-XTYPE>
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[0] = mktuple(AST_LOWERBOUND, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];



//\\ # Another Hamishism... %integer %array %name fred(1:*)
//\\ # which in Imp77 would be %integer %array (1) fred
//\\ # (reject the '*' in other contexts)
//\\ #

//\\ P<UPPERBOUND> = 
//\\    '*',
//\\    <EXPR>,
//\\    <BASE-XTYPE> <NAME>;

case P_UPPERBOUND:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '*', A[ap+0]);
    T[0] = mktuple(AST_UPPERBOUND, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <EXPR>
    T[0] = mktuple(AST_UPPERBOUND, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <BASE-XTYPE>
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[0] = mktuple(AST_UPPERBOUND, alt /*2*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];



//\\ # List of lower/upper bound pairs, for array declarations.

//\\ P<BPAIR> = 
//\\    '(' <LOWERBOUND> ':' <UPPERBOUND> <REST-OF-BPLIST> ')';

case P_BPAIR:
  T[1] = lit(AST__LIT, '(', A[ap+0]);
  T[2] = build_ast(A[ap+1], depth+1); // <LOWERBOUND>
  T[3] = lit(AST__LIT, ':', A[ap+2]);
  T[4] = build_ast(A[ap+3], depth+1); // <UPPERBOUND>
  T[5] = build_ast(A[ap+4], depth+1); // <REST-OF-BPLIST>
  T[6] = lit(AST__LIT, ')', A[ap+5]);
  return mktuple(AST_BPAIR, alt /*0*/, /*phrases*/ 6, T /*T[1], T[2], T[3], T[4], T[5], T[6]*/);



//\\ P<BPAIR68K> = 
//\\    '(' <LOWERBOUND> ':' <UPPERBOUND> <REST-OF-BPLIST68K> ')';

case P_BPAIR68K:
  T[1] = lit(AST__LIT, '(', A[ap+0]);
  T[2] = build_ast(A[ap+1], depth+1); // <LOWERBOUND>
  T[3] = lit(AST__LIT, ':', A[ap+2]);
  T[4] = build_ast(A[ap+3], depth+1); // <UPPERBOUND>
  T[5] = build_ast(A[ap+4], depth+1); // <REST-OF-BPLIST68K>
  T[6] = lit(AST__LIT, ')', A[ap+5]);
  return mktuple(AST_BPAIR68K, alt /*0*/, /*phrases*/ 6, T /*T[1], T[2], T[3], T[4], T[5], T[6]*/);


//\\ # Multi-dimensional arrays

//\\ P<REST-OF-BPLIST> = 
//\\    ',' <EXPR> ':' <EXPR> <REST-OF-BPLIST>,
//\\   ;

case P_REST_OF_BPLIST:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <EXPR>  
    T[3] = lit(AST__LIT, ':', A[ap+2]);
    T[4] = build_ast(A[ap+3], depth+1); // <EXPR>
    T[5] = build_ast(A[ap+4], depth+1); // <REST-OF-BPLIST>
    T[0] = mktuple(AST_REST_OF_BPLIST, alt /*0*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_BPLIST, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<REST-OF-BPLIST68K> = 
//\\    ',' <LOWERBOUND> ':' <UPPERBOUND> <REST-OF-BPLIST68K>,
//\\   ;

case P_REST_OF_BPLIST68K:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <LOWERBOUND>  
    T[3] = lit(AST__LIT, ':', A[ap+2]);
    T[4] = build_ast(A[ap+3], depth+1); // <UPPERBOUND>
    T[5] = build_ast(A[ap+4], depth+1); // <REST-OF-BPLIST68K>
    T[0] = mktuple(AST_REST_OF_BPLIST68K, alt /*0*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_BPLIST68K, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # <Opt-DIMENSIONS> added to handle:
//\\ #
//\\ # %routine y (%integer %name %array (1) %name b)
//\\ #
//\\ # and <OPT-68K-Bounds> added to handle:
//\\ #
//\\ # %routine extract params(%string(255) %name in,out,
//\\ #    %integer %array(1:max params) %name params)
//\\ #

//\\ P<OPT-arrayname> = 
//\\    "array" <Opt-DIMENSIONS> "name",
//\\    "array" <OPT-68K-Bounds> "name",
//\\   ;

case P_OPT_arrayname:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_array, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-DIMENSIONS>  
    T[3] = kw(AST__KW, KW_name, A[ap+2]);
    T[0] = mktuple(AST_OPT_arrayname, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_array, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-68K-Bounds>  
    T[3] = kw(AST__KW, KW_name, A[ap+2]);
    T[0] = mktuple(AST_OPT_arrayname, alt /*1*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_OPT_arrayname, alt /*2*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # for the example from 68000 Imp,
//\\ # %routine y (%integer %name %array (1) %name b)

//\\ P<Opt-DIMENSIONS> = 
//\\    '(' <INT-CONST> ')',
//\\   ;

case P_Opt_DIMENSIONS:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '(', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <INT-CONST>  
    T[3] = lit(AST__LIT, ')', A[ap+2]);
    T[0] = mktuple(AST_Opt_DIMENSIONS, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_Opt_DIMENSIONS, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<Opt-INTEGER> = 
//\\    "integer",
//\\   ;

case P_Opt_INTEGER:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_integer, A[ap+0]);
    T[0] = mktuple(AST_Opt_INTEGER, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_Opt_INTEGER, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # "42(2)" is equivalent to "42, 42".  (*) means 'as many more are needed to fill the array' so must come last.
//\\ # However it looks like <REPFACT> is also used as the string length indicator?!

//\\ P<REPFACT> = 
//\\    '(' <Opt-STAROREXPR> ')',
//\\   ;

case P_REPFACT:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '(', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <Opt-STAROREXPR>  
    T[3] = lit(AST__LIT, ')', A[ap+2]);
    T[0] = mktuple(AST_REPFACT, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REPFACT, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<Opt-STAROREXPR> = 
//\\    <STAROREXPR>,
//\\   ;

case P_Opt_STAROREXPR:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <STAROREXPR>
    T[0] = mktuple(AST_Opt_STAROREXPR, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_Opt_STAROREXPR, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # Used in switch label.  (*) marks a catch-all. (like default: in C)
//\\ # Or at least SHOULD be used in switch label.  Looks like it isn't... just used in <REPFACT>?

//\\ P<STAROREXPR> = 
//\\    <Opt-UNARY-OP> <COPERAND> <REST-OF-CEXPR>,
//\\    '*';

case P_STAROREXPR:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <Opt-UNARY-OP>
    T[2] = build_ast(A[ap+1], depth+1); // <COPERAND>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-CEXPR>
    T[0] = mktuple(AST_STAROREXPR, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {  
    T[1] = lit(AST__LIT, '*', A[ap+0]);
    T[0] = mktuple(AST_STAROREXPR, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # Opt- added here to allow plain "%long" as a declaration at <XTYPE>

//\\ P<Opt-BTYPE> = 
//\\    "real",
//\\    "integer",
//\\    "long" "real",
//\\   ;

case P_Opt_BTYPE:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_real, A[ap+0]);
    T[0] = mktuple(AST_Opt_BTYPE, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_integer, A[ap+0]);
    T[0] = mktuple(AST_Opt_BTYPE, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 2) {  
    T[1] = kw(AST__KW, KW_long, A[ap+0]);  
    T[2] = kw(AST__KW, KW_real, A[ap+1]);
    T[0] = mktuple(AST_Opt_BTYPE, alt /*2*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_Opt_BTYPE, alt /*3*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<Opt-Comma> = 
//\\    ',',
//\\   ;

case P_Opt_Comma:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[0] = mktuple(AST_Opt_Comma, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_Opt_Comma, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<Opt-ALIAS> = 
//\\    "alias" <TEXTTEXT>,
//\\   ;

case P_Opt_ALIAS:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_alias, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <TEXTTEXT>
    T[0] = mktuple(AST_Opt_ALIAS, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_Opt_ALIAS, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<TEXTTEXT> = 
//\\    <dqstring>;

case P_TEXTTEXT:
  T[1] = bip(AST_dqstring, A[ap+0]);
  return mktuple(AST_TEXTTEXT, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);


//\\ # if we add a "C" type (to reverse the order of parameter evaluation) it would be done here.
//\\ # I don't think you would write %permroutine since they are built in to the compiler, but
//\\ # depending on how the compiler is implemented, you might, and if so they would be added here.
//\\ # I do have a vague recollection of perm routines being matched up with internal code using
//\\ # a file or declarations containing magic numbers, eg something like:
//\\ # %perm (5) %routine write(%integer n, sp)
//\\ # - but that may be a manufactured memory!
//\\ #

//\\ P<Percent-SEX> = 
//\\    "system",
//\\    "external",
//\\    "dynamic",
//\\    "prim",
//\\   ;

case P_Percent_SEX:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_system, A[ap+0]);
    T[0] = mktuple(AST_Percent_SEX, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_external, A[ap+0]);
    T[0] = mktuple(AST_Percent_SEX, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 2) {  
    T[1] = kw(AST__KW, KW_dynamic, A[ap+0]);
    T[0] = mktuple(AST_Percent_SEX, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 3) {  
    T[1] = kw(AST__KW, KW_prim, A[ap+0]);
    T[0] = mktuple(AST_Percent_SEX, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_Percent_SEX, alt /*4*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<RECFMT-spec-OR-BODY> = 
//\\    "spec" <NAME>,
//\\    <NAME> '(' <RECFMT-DEC> <REST-OF-RECFMT-DEC> <ALT-RECFMT-DEC> ')';

case P_RECFMT_spec_OR_BODY:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_spec, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[0] = mktuple(AST_RECFMT_spec_OR_BODY, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>  
    T[2] = lit(AST__LIT, '(', A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <RECFMT-DEC>
    T[4] = build_ast(A[ap+3], depth+1); // <REST-OF-RECFMT-DEC>
    T[5] = build_ast(A[ap+4], depth+1); // <ALT-RECFMT-DEC>  
    T[6] = lit(AST__LIT, ')', A[ap+5]);
    T[0] = mktuple(AST_RECFMT_spec_OR_BODY, alt /*1*/, /*phrases*/ 6, T /*T[1], T[2], T[3], T[4], T[5], T[6]*/);
  }
  return T[0];



//\\ # 68000 Imp has a non-standard syntax for some array declarations, eg
//\\ #
//\\ # %conststring(1) %array(1:max params) parameters="B","W","L"
//\\ # %string(255) %array(0:maxfiles) list
//\\ #
//\\ # The equivalent Imp77 syntax would be
//\\ #
//\\ # %conststring(1) %array parameters(1:max params)="B","W","L"
//\\ # %string(255) %array list(0:maxfiles)
//\\ #
//\\ # Putting bounds after a %name is also from the 68000:
//\\ #
//\\ #    %integer%array%name an10(1:10)
//\\ #
//\\ # which is likely the same as
//\\ #
//\\ #    %integer%array(1)%name an10
//\\ #
//\\ #  in Imp77.  We just haven't been told the lower bound...
//\\ #
//\\ # meanwhile this broke: %string (64) %array %format sform1(0 : 1022)
//\\ #
//\\ # I'm not sure if there is any significant difference nowadays between own declarations and non-own declarations...
//\\ # the used to be distinguished by allowing initialisations... maybe worth merging the definitions now?

//\\ P<DECLN> = 
//\\    <OPT-arrayname> <OPT-spec> <NAME-or-STAR-68K> <OPT-68K-Bounds> <Opt-Init-assign> <Opt-Assign-NAME-LIST>,
//\\    "array" <OPT-spec> <OPT-format> <NAME> <Opt-NAME-LIST> <BPAIR> <REST-OF-ARLIST>,
//\\    "array" <BPAIR> <OPT-spec> <OPT-format> <NAME> <Opt-NAME-LIST> <REST-OF-ARLIST-68K>;

case P_DECLN:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-arrayname>
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-spec>
    T[3] = build_ast(A[ap+2], depth+1); // <NAME-or-STAR-68K>
    T[4] = build_ast(A[ap+3], depth+1); // <OPT-68K-Bounds>
    T[5] = build_ast(A[ap+4], depth+1); // <Opt-Init-assign>
    T[6] = build_ast(A[ap+5], depth+1); // <Opt-Assign-NAME-LIST>
    T[0] = mktuple(AST_DECLN, alt /*0*/, /*phrases*/ 6, T /*T[1], T[2], T[3], T[4], T[5], T[6]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_array, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-spec>
    T[3] = build_ast(A[ap+2], depth+1); // <OPT-format>
    T[4] = build_ast(A[ap+3], depth+1); // <NAME>
    T[5] = build_ast(A[ap+4], depth+1); // <Opt-NAME-LIST>
    T[6] = build_ast(A[ap+5], depth+1); // <BPAIR>
    T[7] = build_ast(A[ap+6], depth+1); // <REST-OF-ARLIST>
    T[0] = mktuple(AST_DECLN, alt /*1*/, /*phrases*/ 7, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_array, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <BPAIR>
    T[3] = build_ast(A[ap+2], depth+1); // <OPT-spec>
    T[4] = build_ast(A[ap+3], depth+1); // <OPT-format>
    T[5] = build_ast(A[ap+4], depth+1); // <NAME>
    T[6] = build_ast(A[ap+5], depth+1); // <Opt-NAME-LIST>
    T[7] = build_ast(A[ap+6], depth+1); // <REST-OF-ARLIST-68K>
    T[0] = mktuple(AST_DECLN, alt /*2*/, /*phrases*/ 7, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7]*/);
  }
  return T[0];




//\\ P<OWNDEC> = 
//\\    <OPT-arrayname> <OPT-spec> <SINGLE-OWNDEC> <REST-OF-OWNDEC>,
//\\    "array" <OPT-format> <OPT-spec> <BPAIR> <NAME> <Opt-Init-assign-array>,
//\\    "array" <OPT-format> <OPT-spec> <NAME> <BPAIR> <Opt-Init-assign-array>;

case P_OWNDEC:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <OPT-arrayname>
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-spec>
    T[3] = build_ast(A[ap+2], depth+1); // <SINGLE-OWNDEC>
    T[4] = build_ast(A[ap+3], depth+1); // <REST-OF-OWNDEC>
    T[0] = mktuple(AST_OWNDEC, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_array, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-format>
    T[3] = build_ast(A[ap+2], depth+1); // <OPT-spec>
    T[4] = build_ast(A[ap+3], depth+1); // <BPAIR>
    T[5] = build_ast(A[ap+4], depth+1); // <NAME>
    T[6] = build_ast(A[ap+5], depth+1); // <Opt-Init-assign-array>
    T[0] = mktuple(AST_OWNDEC, alt /*1*/, /*phrases*/ 6, T /*T[1], T[2], T[3], T[4], T[5], T[6]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_array, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-format>
    T[3] = build_ast(A[ap+2], depth+1); // <OPT-spec>
    T[4] = build_ast(A[ap+3], depth+1); // <NAME>
    T[5] = build_ast(A[ap+4], depth+1); // <BPAIR>
    T[6] = build_ast(A[ap+5], depth+1); // <Opt-Init-assign-array>
    T[0] = mktuple(AST_OWNDEC, alt /*2*/, /*phrases*/ 6, T /*T[1], T[2], T[3], T[4], T[5], T[6]*/);
  }
  return T[0];




//\\ P<REST-OF-ARLIST> = 
//\\    ',' <NAME> <Opt-NAME-LIST> <BPAIR> <REST-OF-ARLIST>,
//\\   ;

case P_REST_OF_ARLIST:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-NAME-LIST>
    T[4] = build_ast(A[ap+3], depth+1); // <BPAIR>
    T[5] = build_ast(A[ap+4], depth+1); // <REST-OF-ARLIST>
    T[0] = mktuple(AST_REST_OF_ARLIST, alt /*0*/, /*phrases*/ 5, T /*T[1], T[2], T[3], T[4], T[5]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_ARLIST, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<REST-OF-ARLIST-68K> = 
//\\    ',' <NAME> <Opt-NAME-LIST> <REST-OF-ARLIST-68K>,
//\\   ;

case P_REST_OF_ARLIST_68K:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-NAME-LIST>
    T[4] = build_ast(A[ap+3], depth+1); // <REST-OF-ARLIST-68K>
    T[0] = mktuple(AST_REST_OF_ARLIST_68K, alt /*0*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_ARLIST_68K, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<OPT-68K-Bounds> = 
//\\    <BPAIR68K>,
//\\   ;

case P_OPT_68K_Bounds:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <BPAIR68K>
    T[0] = mktuple(AST_OPT_68K_Bounds, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_68K_Bounds, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<OPT-format> = 
//\\    "format",
//\\   ;

case P_OPT_format:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_format, A[ap+0]);
    T[0] = mktuple(AST_OPT_format, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_format, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ #
//\\ # This is the same ugly hack as <Opt-Assign-NAME-LIST> below
//\\ # The AST handling has to check for and reject the '*' in all contexts except for
//\\ # 68000-style declarations such as "@16_4000c0 %byte *,acia s,*,acia d"
//\\ #
//\\ # Below is a note from inside the 68K compiler that may be relevant:
//\\ #
//\\ #! %record(*) or %string(*) needs %name (or @)
//\\ #! %string alone allowed only for %const%string
//\\ #

//\\ P<NAME-or-STAR-68K> = 
//\\    '*',
//\\    <NAME>;

case P_NAME_or_STAR_68K:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '*', A[ap+0]);
    T[0] = mktuple(AST_NAME_or_STAR_68K, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>
    T[0] = mktuple(AST_NAME_or_STAR_68K, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # <Opt-Init-assign> added by gt
//\\ # This hideous hack with '*' for an anonymous entry is yet another of Hamish's idiosyncrasies:
//\\ #
//\\ # @16_7fffc %byte status,data,*,control
//\\ #                            ^
//\\ #  "/home/gtoal/gtoal.com/athome/edinburgh/APM-gdmr/ETHER/SPY.imp"
//\\ #
//\\ # @16_4000c0 %byte *,acia s,*,acia d
//\\ #
//\\ # and would appear to just be a lazy way to skip over an address when assigning multiple
//\\ # individual scalars to addresses...
//\\ #
//\\ # Obviously it should not be allowed in any other context - some semantic checking needed here...
//\\ #

//\\ P<Opt-Assign-NAME-LIST> = 
//\\    ',' '*' <Opt-Assign-NAME-LIST>,
//\\    ',' <NAME> <Opt-Init-assign> <Opt-Assign-NAME-LIST>,
//\\   ;

case P_Opt_Assign_NAME_LIST:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);  
    T[2] = lit(AST__LIT, '*', A[ap+1]);
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-Assign-NAME-LIST>
    T[0] = mktuple(AST_Opt_Assign_NAME_LIST, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 1) {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-Init-assign>
    T[4] = build_ast(A[ap+3], depth+1); // <Opt-Assign-NAME-LIST>
    T[0] = mktuple(AST_Opt_Assign_NAME_LIST, alt /*1*/, /*phrases*/ 4, T /*T[1], T[2], T[3], T[4]*/);
  } else               {
    T[0] = mktuple(AST_Opt_Assign_NAME_LIST, alt /*2*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # Need <EXPR> instead of <CEXPR> to catch = tostring(i) because cexpr only got tostring
//\\ # Need '== <EXPR>' instead of '== <LVALUE>' to catch '== length(s)', i.e. a %map although it looks like a fn call.
//\\ # - the latter being more of a failing of LVALUE that here.
//\\ # Removed:
//\\ #   '==' <LVALUE>,
//\\ #   '=' <CEXPR>,
//\\ # These will be improved once we have semantic checks...
//\\ #

//\\ P<Opt-Init-assign> = 
//\\    <ASSOP> <EXPR>,
//\\   ;

case P_Opt_Init_assign:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <ASSOP>
    T[2] = build_ast(A[ap+1], depth+1); // <EXPR>
    T[0] = mktuple(AST_Opt_Init_assign, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_Opt_Init_assign, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # removed string resolution from assop - too much type checking

//\\ P<ASSOP> = 
//\\    '=' '=',
//\\    <SCALAR-ASSIGN>;

case P_ASSOP:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '=', A[ap+0]);  
    T[2] = lit(AST__LIT, '=', A[ap+1]);
    T[0] = mktuple(AST_ASSOP, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[1] = build_ast(A[ap+0], depth+1); // <SCALAR-ASSIGN>
    T[0] = mktuple(AST_ASSOP, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];



//\\ # An initialised array declaration does not need a %C following the '=' before the list of initial values.
//\\ # this is a stupid hack to get around comments in the middle of array declarations :-(
//\\ # note that it gobbles the newline
//\\ # This has to handle: "== nil(*)" from %ownrecord(i tc f)%namearray tc refs(1:maxtc) == nil(*)
//\\ # Turns out <SCALAR-ASSIGN> didn't include '==' so switched to <ASSOP> instead

//\\ P<Opt-Init-assign-array> = 
//\\    <ASSOP> <stupid> <Opt-UNARY-OP> <COPERAND> <REST-OF-CEXPR> <REPFACT> <ROCL>,
//\\   ;

case P_Opt_Init_assign_array:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <ASSOP>
    T[2] = build_ast(A[ap+1], depth+1); // <stupid>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-UNARY-OP>
    T[4] = build_ast(A[ap+3], depth+1); // <COPERAND>
    T[5] = build_ast(A[ap+4], depth+1); // <REST-OF-CEXPR>
    T[6] = build_ast(A[ap+5], depth+1); // <REPFACT>
    T[7] = build_ast(A[ap+6], depth+1); // <ROCL>
    T[0] = mktuple(AST_Opt_Init_assign_array, alt /*0*/, /*phrases*/ 7, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7]*/);
  } else               {
    T[0] = mktuple(AST_Opt_Init_assign_array, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # the version without "for" is to support an old-style statement, %WHILE <cond> %THEN <ui>

//\\ P<Percent-WU> = 
//\\    "while" <CONDITION>,
//\\    "until" <CONDITION>;

case P_Percent_WU:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_while, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <CONDITION>
    T[0] = mktuple(AST_Percent_WU, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_until, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <CONDITION>
    T[0] = mktuple(AST_Percent_WU, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];




//\\ P<Percent-WUF> = 
//\\    "while" <CONDITION>,
//\\    "until" <CONDITION>,
//\\    "for" <NAME> <SCALAR-ASSIGN> <EXPR> ',' <EXPR> ',' <EXPR>;

case P_Percent_WUF:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_while, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <CONDITION>
    T[0] = mktuple(AST_Percent_WUF, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_until, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <CONDITION>
    T[0] = mktuple(AST_Percent_WUF, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_for, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <NAME>
    T[3] = build_ast(A[ap+2], depth+1); // <SCALAR-ASSIGN>
    T[4] = build_ast(A[ap+3], depth+1); // <EXPR>  
    T[5] = lit(AST__LIT, ',', A[ap+4]);
    T[6] = build_ast(A[ap+5], depth+1); // <EXPR>  
    T[7] = lit(AST__LIT, ',', A[ap+6]);
    T[8] = build_ast(A[ap+7], depth+1); // <EXPR>
    T[0] = mktuple(AST_Percent_WUF, alt /*2*/, /*phrases*/ 8, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8]*/);
  }
  return T[0];




//\\ P<SCALAR-ASSIGN> = 
//\\    '=',
//\\    '<' '-';

case P_SCALAR_ASSIGN:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, '=', A[ap+0]);
    T[0] = mktuple(AST_SCALAR_ASSIGN, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = lit(AST__LIT, '<', A[ap+0]);  
    T[2] = lit(AST__LIT, '-', A[ap+1]);
    T[0] = mktuple(AST_SCALAR_ASSIGN, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  }
  return T[0];




//\\ P<Opt-UNTIL> = 
//\\    "until" <CONDITION>,
//\\   ;

case P_Opt_UNTIL:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_until, A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <CONDITION>
    T[0] = mktuple(AST_Opt_UNTIL, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_Opt_UNTIL, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<Opt-CYCPARM> = 
//\\    <NAME> <SCALAR-ASSIGN> <EXPR> ',' <EXPR> ',' <EXPR>,
//\\   ;

case P_Opt_CYCPARM:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <NAME>
    T[2] = build_ast(A[ap+1], depth+1); // <SCALAR-ASSIGN>
    T[3] = build_ast(A[ap+2], depth+1); // <EXPR>  
    T[4] = lit(AST__LIT, ',', A[ap+3]);
    T[5] = build_ast(A[ap+4], depth+1); // <EXPR>  
    T[6] = lit(AST__LIT, ',', A[ap+5]);
    T[7] = build_ast(A[ap+6], depth+1); // <EXPR>
    T[0] = mktuple(AST_Opt_CYCPARM, alt /*0*/, /*phrases*/ 7, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7]*/);
  } else               {
    T[0] = mktuple(AST_Opt_CYCPARM, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # gt changed signal to allow 2 exprs.  Mouses Imp77 adds an optional string!
//\\ # 68000: %signal 5,,holeend,"HEAPPUT: heap corrupt" %if holeend>lhb_limit

//\\ P<OPEXPR2> = 
//\\    ',' <OPT-EXPR> <OPEXPR>,
//\\   ;

case P_OPEXPR2:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-EXPR>
    T[3] = build_ast(A[ap+2], depth+1); // <OPEXPR>
    T[0] = mktuple(AST_OPEXPR2, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_OPEXPR2, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<OPT-EXPR> = 
//\\    <EXPR>,
//\\   ;

case P_OPT_EXPR:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <EXPR>
    T[0] = mktuple(AST_OPT_EXPR, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_OPT_EXPR, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # single optional ", expr" for use with %signal event (, subevent)?

//\\ P<OPEXPR> = 
//\\    ',' <OPT-EXPR> <OPSTRING>,
//\\   ;

case P_OPEXPR:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <OPT-EXPR>
    T[3] = build_ast(A[ap+2], depth+1); // <OPSTRING>
    T[0] = mktuple(AST_OPEXPR, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_OPEXPR, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # %signal 3,4,position,"Set input fails" %unless position=0

//\\ P<OPSTRING> = 
//\\    ',' <STRING-EXPR>,
//\\   ;

case P_OPSTRING:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <STRING-EXPR>
    T[0] = mktuple(AST_OPSTRING, alt /*0*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else               {
    T[0] = mktuple(AST_OPSTRING, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # reversed conditions and 1-line cycles

//\\ P<REST-OF-SS1> = 
//\\    <Percent-IU> <CONDITION> <S>,
//\\    <Percent-WUF> <S>,
//\\    <S>,
//\\   ;

case P_REST_OF_SS1:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <Percent-IU>
    T[2] = build_ast(A[ap+1], depth+1); // <CONDITION>
    T[3] = build_ast(A[ap+2], depth+1); // <S>
    T[0] = mktuple(AST_REST_OF_SS1, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else if (alt == 1) {
    T[1] = build_ast(A[ap+0], depth+1); // <Percent-WUF>
    T[2] = build_ast(A[ap+1], depth+1); // <S>
    T[0] = mktuple(AST_REST_OF_SS1, alt /*1*/, /*phrases*/ 2, T /*T[1], T[2]*/);
  } else if (alt == 2) {
    T[1] = build_ast(A[ap+0], depth+1); // <S>
    T[0] = mktuple(AST_REST_OF_SS1, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_SS1, alt /*3*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<REST-OF-OWNDEC> = 
//\\    ',' <SINGLE-OWNDEC> <REST-OF-OWNDEC>,
//\\   ;

case P_REST_OF_OWNDEC:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <SINGLE-OWNDEC>
    T[3] = build_ast(A[ap+2], depth+1); // <REST-OF-OWNDEC>
    T[0] = mktuple(AST_REST_OF_OWNDEC, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);
  } else               {
    T[0] = mktuple(AST_REST_OF_OWNDEC, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<SINGLE-OWNDEC> = 
//\\    <NAME> <Opt-ALIAS> <Opt-Init-assign>;

case P_SINGLE_OWNDEC:
  T[1] = build_ast(A[ap+0], depth+1); // <NAME>
  T[2] = build_ast(A[ap+1], depth+1); // <Opt-ALIAS>
  T[3] = build_ast(A[ap+2], depth+1); // <Opt-Init-assign>
  return mktuple(AST_SINGLE_OWNDEC, alt /*0*/, /*phrases*/ 3, T /*T[1], T[2], T[3]*/);



//\\ P<ROCL> = 
//\\    ',' <stupid> <Opt-UNARY-OP> <COPERAND> <REST-OF-CEXPR> <REPFACT> <ROCL>,
//\\   ;

case P_ROCL:
  if (alt == 0)        {  
    T[1] = lit(AST__LIT, ',', A[ap+0]);
    T[2] = build_ast(A[ap+1], depth+1); // <stupid>
    T[3] = build_ast(A[ap+2], depth+1); // <Opt-UNARY-OP>
    T[4] = build_ast(A[ap+3], depth+1); // <COPERAND>
    T[5] = build_ast(A[ap+4], depth+1); // <REST-OF-CEXPR>
    T[6] = build_ast(A[ap+5], depth+1); // <REPFACT>
    T[7] = build_ast(A[ap+6], depth+1); // <ROCL>
    T[0] = mktuple(AST_ROCL, alt /*0*/, /*phrases*/ 7, T /*T[1], T[2], T[3], T[4], T[5], T[6], T[7]*/);
  } else               {
    T[0] = mktuple(AST_ROCL, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];




//\\ P<stupid> = 
//\\    <COMMENT>,
//\\   ;

case P_stupid:
  if (alt == 0)        {
    T[1] = build_ast(A[ap+0], depth+1); // <COMMENT>
    T[0] = mktuple(AST_stupid, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {
    T[0] = mktuple(AST_stupid, alt /*1*/, /*phrases*/ 0, T /**/);
  }
  return T[0];



//\\ # extrinsic is an old form meaning roughly "external spec"

//\\ P<XOWN> = 
//\\    "own",
//\\    "external",
//\\    "extrinsic",
//\\    "constant",
//\\    "const";

case P_XOWN:
  if (alt == 0)        {  
    T[1] = kw(AST__KW, KW_own, A[ap+0]);
    T[0] = mktuple(AST_XOWN, alt /*0*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 1) {  
    T[1] = kw(AST__KW, KW_external, A[ap+0]);
    T[0] = mktuple(AST_XOWN, alt /*1*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 2) {  
    T[1] = kw(AST__KW, KW_extrinsic, A[ap+0]);
    T[0] = mktuple(AST_XOWN, alt /*2*/, /*phrases*/ 1, T /*T[1]*/);
  } else if (alt == 3) {  
    T[1] = kw(AST__KW, KW_constant, A[ap+0]);
    T[0] = mktuple(AST_XOWN, alt /*3*/, /*phrases*/ 1, T /*T[1]*/);
  } else               {  
    T[1] = kw(AST__KW, KW_const, A[ap+0]);
    T[0] = mktuple(AST_XOWN, alt /*4*/, /*phrases*/ 1, T /*T[1]*/);
  }
  return T[0];


//\\ E
