// KDF9 syntax checker, soon to be assembler

// current bug: test13 - thinks it has EOF after the first line.  (first line fails)

/* TO DO:

         The declaration of a binary constant takes the form:-

         Vv = Bt/s where B is the label for a binary constant,

                         t is the binary integer expressed in
                           octal form,

                         s is the position of the least significant
                           bit expressed.
    As before, if the symbols /s are omitted a value s = 47 is assumed.
    A failure will be reported if any non-zero bit is lost off either
    end during the shifting process.

 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <fcntl.h>
#ifndef O_BINARY
#define O_BINARY  0
#endif

#define TRUE (0==0)
#define FALSE (0!=0)

#define DEBUG_PARSER 1
#define DEBUG_LEXER 1
#define DEBUG 1
int debug_parser = FALSE;
int debug_lexer = TRUE;

#define sourcefile stdin
#define curfile "stdin"

#define MAXLINE 1024

#include "assemble.h"

#include "from_kal3.c"

/* C[] is the source character token stream */

typedef struct sourceinfo { // ATOMS for processed input stream
    char *s; // string contents
    int l;   // lineno
    int col; // column
    int t;   // type - tag, "string", 'charconst', or char, so far
    char *f; // source or includefile  name
} sourceinfo;

static sourceinfo c[16*1024];

int nextfree, arraysize;
char onecharstr[1024];

int A[16*1024];
int next_free_a, a_size;

int cp;  // code pointer.  Has to be global state.
int ap;  // Analysis record pointer.

// Built-in phrase codes.  Must match with grammar file.
#define TYPE_EOF 0
#define TYPE_NEWLINE 1
#define TYPE_CHAR 2

int lineno = 1, col = 0;
int startline = TRUE;

#define MAXPOOL (1024*32)
char stringpool[MAXPOOL];
int nextstring = 0;

static char xline[1024];
static int xi = 0, xcur_line = 1;

static void xungetc(int c, FILE *f)
{
    if (xi > 0) {
	xi -= 1;
    } else if (c == '\n') {
	xcur_line -= 1;
	xi = strlen(xline);
    }
    ungetc(c, f);
}

static int xfgetc(FILE *f)
{
    int c, ch;
    c = fgetc(f);
    if (c == EOF) return EOF;
    ch = c&255;
    if (ch == '\n') {
	xline[xi] = '\0'; xi = 0;
//	(void)make_binary_tuple(LINE, xcur_line++, (int)strdup(xline));
    } else xline[xi++] = ch;
    if (xi == 1023) xi = 1022;
    xline[xi] = '\0';
    return c;
}

int str_to_pool(char *s)
{
    int tag;
    for (tag = 0; tag <= nextstring; tag++) {
        if (strcmp(stringpool+tag, s) == 0) {
            return tag; /* found, one way or another */
        }
    }
}

void stores(char *s, int lineno, int col, int type, char *fname) {
  int tag;

  if (nextstring + strlen(s) + 1 >= MAXPOOL) exit(1); // TODO: add message
  strcpy(stringpool+nextstring, s); /* Create a backstop for when not found */
  tag = str_to_pool(s);
  if (tag == nextstring) nextstring += strlen(s)+1; /* Not found, add it */

//  makespace(c, nextfree, arraysize);
  c[nextfree].s = stringpool+tag; c[nextfree].l = lineno; c[nextfree].col = col;
  c[nextfree].f = fname; c[nextfree].t = type;
  //fprintf(stderr, "%s @ %d, %d\n", c[nextfree].s, c[nextfree].l, c[nextfree].col);
  nextfree++;
}

void storec(int ch, int lineno, int col, int type, char *fname) {
  onecharstr[ch*2] = ch; onecharstr[ch*2+1] = '\0';  // convert char to 1-char string before saving.
  stores(&onecharstr[ch*2], lineno, col, type, fname);
}
/*>*/

int iskeyword(char *s) {
  int i;
  for (i = 0; i < MAX_KEYWORD; i++) if (strcmp(s, keyword[i]) == 0) return TRUE;
  return FALSE;
}

void line_reconstruction(void)
{
  static int whitespace;
  static int peek;
  int ch;
  /* Pre-process input ready for parsing.  Tokens are stored in array C[] */

  whitespace = FALSE;
  for (;;) {
    ch = xfgetc(sourcefile); if (ch == EOF) break;
    ch &= 255; // int, positive.

    // peek = xfgetc(sourcefile); xungetc(peek, sourcefile);

    // this parser is line-at-a-time.  If it was whole-file, we wouldn't return here
    switch (ch) {
    case '\n':
      lineno++; startline = TRUE; col = 0; whitespace = TRUE;
      storec(ch, lineno, col++, TYPE_NEWLINE, curfile);
      return;

    case '\t':
    case ' ':       col++; // Does not affect whitespace
      break;

    case '(':
      col++;
      {int c, lev = 1;
        for (;;) {
          c  = xfgetc(sourcefile); if (c == EOF) break;
          col++; if (c == '\n') {col = 1; lineno++;}
          if (c == '(') lev += 1;
          else if (c == ')') {
            lev -= 1;
            if (lev == 0) break;
	  }
        }
      }
      break; // go round enclosing loop again

    default:
      whitespace = FALSE;
      storec(ch, lineno, col++, TYPE_CHAR, curfile);
    }
  }
  // set up a dummy at the end because we sometimes look ahead by 1
  // in the parsing code and don't want to hit uninitialised data.
  c[nextfree].t = TYPE_EOF;
  c[nextfree].s = "<EOF>";
  c[nextfree].l = lineno;
  c[nextfree].col = col;
  /*>*/
}

int bestparse;        // for error reporting.
char *looking_for;    // 'while looking for <PHRASENAME>' (or literal) ...

void indent(int depth, FILE *f)
{
    int i;
    for (i = 0; i < depth; i++) fprintf(f, "  ");
}

int startparse(int pp) // depth is only for indentation in diags
{
  bestparse = -1; // for error reporting.
  looking_for = "<UNKNOWN>";    // 'while looking for <PHRASENAME>' (or literal) ...
  parse(pp, 0);
}

int parse(int pp, int depth) // depth is only for indentation in diags
{
  /*  Main parsing procedure.  This is a table-driven parser, with the tables
      being generated from the grammar rules embedded in the 'compile' procedure
      below.  The result of the parse is a tree structure, and the values of the
      nodes in the tree structure are used to drive a large 'case' statement
      which selects the actions to be performed after a successful parse.

      There is no grammatical structure embedded in this procedure.  If you're
      looking for the grammar definition, see the procedure called 'compile' instead.
   */
  int saved_cp, saved_ap, i, gp, alts, match;
  char saved_desc[256];

  /*  Initialisation */

  gp = phrase_start[pp-512-MAX_BIP];
  alts = gram[gp];

  /*  Debugging */
#ifdef DEBUG_PARSER
  if (debug_parser) {
    fprintf(stdout, "\n");
    indent(depth, stdout);
    fprintf(stdout, "Phrase %s/%d (%d alternatives) = ", phrasename[pp-512], pp, alts);
    fflush(stdout);
  }
#endif
  
  gp++; // gp now points to first element (length) of first alt

  saved_cp = cp;
  saved_ap = ap;
  

  for (i = 0; i < alts; i++) {
    /*  Starting with the root phrase, recursively examine each alternative */
    int each, phrases = gram[gp++], phrase_count, gap = 0;

    cp = saved_cp;
    ap = saved_ap;

    if (ap+3 > next_free_a) next_free_a = ap+3;
//    makespace(A, next_free_a, a_size);

    A[ap++] = pp;   // record which phrase (could be done outside loop)
    A[ap++] = i;    // and which alt.


    // Count slots needed.  *Could* be precalculated and stored
    // in the grammar, either embedded (after the ALT) or as a
    // separate table

    for (each = 0; each < phrases; each++) if (gram[gp+each] >= 512) gap++;

    A[ap++] = gap;    // Count of alts (gap)
    // ap+gap now points to the slot after the space required, which
    // is where the first subphrase will be stored.
    ap = ap+gap; // recursive subphrases are stored after this phrase.
                 // ap is left updated if successful.


    // successfully parsed phrases are stored in A[saved_ap+3+n]

    if (saved_ap+3+gap > next_free_a) next_free_a = saved_ap+3+gap;
//    makespace(A, next_free_a, a_size);

    /*  Debug */
    // this loop is only for diagnostics
#ifdef DEBUG_PARSER
    if (debug_parser) {
      char *saved_descp;
      fprintf(stdout, "\n");
      indent(depth, stdout);
      fprintf(stdout, "Alternative %d: (%d phrases) ", i+1, phrases);
      saved_descp = saved_desc; *saved_descp = '\0';
      for (each = 0; each < phrases; each++) {
        int phrase = gram[gp+each];
        if (phrase < 256) {
          saved_descp += sprintf(saved_descp, " '%c'", phrase);
        } else if (phrase < 512) {
          saved_descp += sprintf(saved_descp, " \"%s\"/%d", keyword[phrase-256], phrase-256);
        } else if (phrase < 512+MAX_BIP) {
          saved_descp += sprintf(saved_descp, " {%s/BIP%d}", phrasename[phrase-512], BIP[phrase-512]);
        } else {
          saved_descp += sprintf(saved_descp, " <%s/%d>", phrasename[phrase-512], phrase);
        }
      }
      fprintf(stdout, "%s\n", saved_desc);
      fflush(stdout);
    }
#endif
    

    match = TRUE; // stays true if all subphrases match
    phrase_count = 0; // only phrases which make it into the A record,
                      // i.e. excluding literals and keywords
    for (each = 0; each < phrases; each++) {
      /*  Within a single grammar rule (alternative), ensure that each subphrase is present */
      int phrase = gram[gp+each];

      /*  Debug */
#ifdef DEBUG_PARSER
      if (debug_parser) {
        indent(depth, stdout);
        fprintf(stdout, "Input token stream = '%s' '%s' '%s' ...\n",
          (cp < nextfree ? c[cp].s : "EOF"),
          (cp+1 < nextfree ? c[cp+1].s : "EOF"),
          (cp+2 < nextfree ? c[cp+2].s : "EOF"));
      }
#endif
      if (cp > bestparse) {
        static char s[128];
#ifdef DEBUG_PARSER
        if (phrase < 256) {
          sprintf(s, "'%c'", phrase);
        } else if (phrase < 512) {
          sprintf(s, "\"%s\"", keyword[phrase-256]);
        } else if (phrase < 512+MAX_BIP) {
          sprintf(s, "{%s}", phrasename[phrase-512]);
        } else {
          sprintf(s, "<%s>", phrasename[phrase-512]);
        }
#endif
        looking_for = s;
        bestparse = cp;
      }
#ifdef DEBUG_PARSER
      if (debug_parser) indent(depth, stdout);
#endif
      

      if (phrase < 256) {
	/*  Literal */
#ifdef DEBUG_PARSER
        if (debug_parser) fprintf(stdout, "'%c'", phrase);
#endif
        if ((c[cp].t != TYPE_CHAR) || (c[cp].s[0] != phrase)) match = FALSE; else cp++;
        // Don't record literals
        
      } else if (phrase < 512) {
	/*  Keyword */
#ifdef DEBUG_PARSER
        if (debug_parser) fprintf(stdout, "\"%s\"/%d", keyword[phrase-256], phrase-256);
#endif
        if (strcmp(keyword[phrase-256], c[cp].s) != 0) match = FALSE; else cp++;
        // Don't record keywords
        
      } else if (phrase < 512+MAX_BIP) {
	/*  Built-in phrase */
        int where = ap; // next phrase to be parsed will be stored at current 'ap'.
#ifdef DEBUG_PARSER
        if (debug_parser) fprintf(stdout, "{%s/BIP%d}", phrasename[phrase-512], BIP[phrase-512]);
#endif
        if (c[cp].t != BIP[phrase-512]) match = FALSE; else {
          A[ap++] = phrase;
          A[ap++] = 1;
          A[ap++] = 1;
          A[ap++] = cp++;
          A[saved_ap+3+phrase_count++] = where; // Record BIP
        }
      } else {
	/*  Recursive call to parser for a subphrase */
        int where = ap; // next phrase to be parsed will be stored at current 'ap'.
#ifdef DEBUG_PARSER
        if (debug_parser) fprintf(stdout, "<%s/%d>", phrasename[phrase-512], phrase);
#endif
        if (!parse(phrase, depth+1)) match = FALSE; else {
          A[saved_ap+3+phrase_count++] = where;
        }
      }
      /*  debug */
#ifdef DEBUG_PARSER
      if (debug_parser) {
        fprintf(stdout, "\n");
        indent(depth, stdout);
        fprintf(stdout, "Tried alternative %d: %s - result was %s\n", each+1, saved_desc, (match ? "TRUE" : "FALSE"));
        fflush(stdout);
      }
#endif
      if (!match) break;
    }
    gp += phrases; // move over all phrases, to next alt

    if (match) break;
#ifdef DEBUG_PARSER
    else if (debug_parser) {
      indent(depth, stdout);
      fprintf(stdout, "** Alternative %d FAILED.\n", i+1);
    }
#endif
    // gp now points to first element (length) of next alt, or start of next phrase
  }

  return(match);

}

long long compile(int ap)
{

    int saved_ap;
    int phrase;  // A[ap] is the phrase number. A[ap+1] is the alt.
    int alt;     // For consistency, in BIPs, the Alt should always be 1
                 // although that may not be the case at the moment :-(
    int phrases; // defined subphrases
    int i;

    // The following ecce command executed on this file will generate varcalc.g:
    // ecce -c "(v.//\\.s..(v/ /e)?m,k)0;%c" varcalc.c varcalc.g
    // May later tweak takeon.c to read from varcalc.c rather than varcalc.g
    // thus simplifying build process and becoming more like yacc.

    saved_ap = ap;
    phrase = A[ap++];
    alt = A[ap++];
    phrases = A[ap++];

#ifdef DEBUG
    fprintf(stdout, "compile(A[%d]) phrase=%s\n", saved_ap, phrasename[phrase-512]);
#endif

    switch (phrase) {

//\\  B<EOF> = 0;
    case P_EOF:
	    fprintf(stderr, "EOF!\n");
	    exit(0);

//\\  B<NEWLINE> = 1;
    case P_NEWLINE:
      return 0LL;

//\\  B<CHAR> = 2;
    case P_CHAR:  // only called in error messages
      fprintf(stderr, "%s", c[A[ap]].s);
      return 0LL;

// comments are handled by line reconstruction

// TO DO: Need special case to handle syntax errors - every char up to a ';' or <NEWLINE>


//\\  P<SS>=<SSLIST> <EOF>;
    case P_SS:
      compile(A[ap]);
      exit(0);

//\\  P<SIMPLE>=<BASIC><termin>,
//\\            <ERROR>;
    case P_SIMPLE:
      if (alt == 0) compile(A[ap]); else {
        int line, col, p;
        p = A[ap]; // first phrase - ERROR
	{ // compile ERROR inline
         int saved_ap = p;
         int phrase = A[p++];
         int alt = A[p++];
         int phrases = A[p++];
         p = A[p]; // first phrase - CHAR
         if (alt == 1) {  // compile CHAR inline
           int saved_ap = p;
           int phrase = A[p++];
           int alt = A[p++];
           int phrases = A[p++];
	   //	   p = A[p];
           line = c[A[p]].l;
           col = c[A[p]].col;
	   fprintf(stderr, "Syntax error at line %d, col %d: ", line, col); compile(A[ap]); fprintf(stderr, "\n");
         } else {
	   fprintf(stderr, "Syntax error: "); compile(A[ap]); fprintf(stderr, "\n");
         }
	}
      }
      return 0LL;

//\\  P<endoferror> = <termin>, <EOF>;
    case P_endoferror:
      return 0LL;

//\\  P<ERROR>=
//\\     <termin>,
//\\     <CHAR> <ERROR>;
    case P_ERROR:
      if (alt == 1) {
        compile(A[ap]); compile(A[ap+1]);
      }
      return 0LL;

//\\  P<SSLIST>=<SIMPLE><SSLIST>, ;
    case P_SSLIST:
      if (alt == 0) {
        compile(A[ap]);
        compile(A[ap+1]);
      }
      return 0LL;

//\\  P<BASIC>=<UCI>,<DIRECTIVE>,;
    case P_BASIC:
      if (alt != 2) compile(A[ap]);
      return 0LL;

//\\  P<DIRECTIVE>=
//\\     'FINISH';
    case P_DIRECTIVE:
         fprintf(stdout, "Finish();\n");
 	 exit(0);

//\\  P<termin>=
    case P_termin:
//\\     ';', <NEWLINE>;
         return 0LL;

// The first two UCIs may be accessing AA arrays and record fields (APP is (expr) and ENAME is _whatever)

//\\  P<UCI>=
    case P_UCI:
      switch (alt) {
      case 0:
//\\     '*`'<NAME><APP><opt_ENAME>,
      case 1:
//\\     '*'<opt_equals><NAME><APP><opt_ENAME>,
      case 2:
//\\     'J'<N><opt_P><J_INSTR>,



/*

         There exists a completely different method of introducing
    integer constants into a program, by use of the instruction SET.
    SET is a three-syllable instruction which is obeyed by the machine
    every time it is encountered during the operation of a program.
    It allows a signed integer of not more than 16 bits to be stored
    actually amongst the instruction syllables.  When SET is obeyed
    the specified integer constant is transferred to the top cell of
    the nesting store ready for immediate use.  The 16 bits are
    stored in digit positions 32 - 47 of N1, i.e. in the least sig-
    nificant 16 bits.  The bit in digit position 32, the sign digit,
    is copied into the remaining 32 bits 0 - 31 to give a true single-
    length signed constant in N1.

         The valid forms for the instruction SET are:-

           (a) SET n,   where n is a signed decimal integer in
                        the range -32768 to +32767.

           (b) SET Bt,  where t is an octal integer not greater
                        than (177777)8.

           (c) SET AYy, to give the true address of Yy.

    In form (c) the symbolic address Yy may be replaced by any of the
    valid forms listed in Para. 6 above.

         For forms (b) and (c) it should be noted that digit positions
    0 - 31 will all contain ones if t requires six octal digits or if
    the address is of syllable 4 or 5 of a word.  It is the programmer's
    responsibility to take account of this.

         The use of the instruction SET for small constants is more
    economical in space than the corresponding procedure using V-store
    declarations, since each constant declaration requires a main
    store word in which to store the constant required.  Further, each
    time a declared constant is required for use, a 'fetch' instruction
    has to be written in the program.  In contrast, SET is a single
    instruction which requires no main store space in which to store
    the constant.
 */
      case 3:
//\\     'SETB'<OCTAL>,
      case 4:
//\\     'SET'<opt_plus><N><opt_P><opt_COL>,
      case 5:
//\\     'JS'<N><opt_P>,
      case 6:
//\\     'EXIT'<N>,
        fprintf(stdout, "uci%d();\n", alt);
	return 0LL;
      case 7:
//\\     <opt_equals>'M'<N>'M'<N><MS_INSTR>,
//    ap +0             +1    +2 +3
              return store2syl((compile(A[ap+0])<<8) | twosylqx(compile(A[ap+3]), compile(A[ap+1]), compile(A[ap+2])));
      case 8:
//\\     'SH'<SH_INSTR>,

      case 9: // 002 set test register
//\\     '=TR',
        fprintf(stdout, "uci%d();\n", alt);
	return 0LL;

      case 10:
//\\     'ZERO',
	fprintf(stdout, "zero();\n");
        return 0LL;

      case 11: // 016 ROUND  round double number in N1,N2 to single in N1
               // 014 ROUNDH round to half word  TODO
               // 020 ROUNDF round floating point double number in N1,N2 to single in N1  TODO
//\\     'ROUND',

      case 12:
//\\     'ERASE',

      case 13: // 026 absolute value
//\\     'ABS',

      case 14: // 032 re-order N1, N2 so that the larger is in N1
//\\     'MAX',

      case 15: // 037 +1 if N1 - N2 > 0, -1 if N1 - N2 < 0, 0 if N1 - N2 = 0
//\\     'SIGN',

      case 16:
//\\     'CAB',
      case 17:
//\\     '/I',

      case 18: // 003 count number of bits in the word
//\\     'BITS',

      case 19: // 017 no-op
//\\     'DUMMY',

      case 20: // 012 permute top 3 nest cells, N1 becomes N3
//\\     'PERM',

      case 21: // 011 inclusive-or
//\\     'OR',

      case 22: // 001 clear overflow register
//\\     'VR',

      case 23: // 015 'not equivalent' - i.e. exclusive-or
//\\     'NEV',
        fprintf(stdout, "uci%d();\n", alt);
	return 0LL;

      case 24:
//\\     'NOT',
	fprintf(stdout, "not();\n");
        return 0LL;

      case 25: // 047 stretch 48.bit number to double length
//\\     'STR',

      case 26: // 050 convert double length integer in N1, N2 to single length in N1
//\\     'CONT',

      case 27:
//\\     'AND',

      case 28: // REVD 051 swap N1 and N3, N2 and N4
//\\     'REV'<opt_D>,

      case 29: // DUP  042 duplicate, i.e. put copy of N1 in N1
               // DUPD 043 double-length duplicate
//\\     'DUP'<opt_D>,
        fprintf(stdout, "uci%d();\n", alt);
	return 0LL;

      case 30: // NEGD 010 double-length negate
               // NEG  027 negate
//\\     'NEG'<opt_D>,
	fprintf(stdout, "neg");
	compile(A[ap]);
        fprintf(stdout, "();\n");
        return 0LL;

      case 31:
//\\     '/'<opt_D>,

      case 32: // 056 +   Add
               // 057 +D  Add double length
               // 023 +DF Add double length floating point  TODO
//\\     '+'<opt_D>,

      case 33: // 036 -   subtract
               // 075 -F  subtract floating point
               // 022 -DF subtract double length floating point
//\\     '-'<opt_D>,

      case 34: // 'X' is really multiply sign
               // xF   004 floating point multiply
               // xDF  005 floating point multiply -- double length result from 48-bit operands
               // x+F  like xDF but then followed by double length addition
//\\     'X'<opt_D>,

      case 35:
//\\     'EXIT',

      case 36:
//\\     'OUT',

      case 37:
//\\     '='<QS_INSTR>,

/*
    It is necessary on occasions to transfer information from
    one Q-store to another.  It should be remembered that in any
    such transfer the Q-store from which the information is copied
    will remain unchanged.  Only the sections of the Q-store into
    which the transfer is directed will be changed, those sections
    not involved in the transfer remaining unaltered.  In the instruct-
    ions listed below, information is transferred from a Q-store
    numbered k (which may take any value from 1 to 15, or 0 if re-
    quired) into the Q-store numbered q (which may take any value
    from 1 to 15). k is the number of the Q-store which remains
    unchanged, and q is the number of the Q-store which changes
    either wholly or in part.  The transfer instructions are:-

                   Ck  TO  Qq;    transfer counter only.

                   Ik  TO  Qq;    transfer increment only.

                   Mk  TO  Qq;    transfer modifier only.

                   IMk TO  Qq;    transfer increment and modifier.

                   CMk TO  Qq;    transfer counter and modifier.

                   CIk  TO  Qq;   transfer counter and increment

                   Qk  TO  Qq;    transfer whole of Qk.

    None of these instructions disturbs the nesting store in any way.
 */
      case 38:
//\\     <QSTR><N>'TOQ'<N>,
      case 39:
//\\     'I'<N>'='<opt_plus><N>,
      case 40:
//\\     <QSTR><N>,

/*
6.2 SPECIAL INSTRUCTIONS INVOLVING ONE PART OF A Q-STORE

         For each of the three parts of a Q-store there are a few
    special instructions which may refer only to that part and to no
    others.

         Firstly, for the counter there are two such instructions:-

                                 NCq;
                                 
                                 DCq;

    The first of these, NCq, changes the sign of the integer in the
    counter position of the Q-store.  The machine does this by sub-
    tracting the original counter from zero and replacing the result
    in the counter position.  The second, DCq, subtracts 1 from the
    integer in the counter position and replaces the result in the
    counter position.
*/
      case 41:
//\\     'NC'<N>,
      case 42:
//\\     'DC'<N>,

      case 43:
//\\     'LINK',
      case 44:
//\\     'M'<plus>'I'<N>,
      case 45:
//\\     'P'<IOM><ATOF>'Q'<N>,
      case 46:
//\\     'TLOQ'<N>,
      case 47:
//\\     'PARQ'<N>,
      case 48:
//\\     'BUSYQ'<N>,
      case 49:
//\\     'MANUALQ'<N>,
      case 50:
//\\     'ADVCA'<N>,
      case 51:
//\\     <OCTAL>'/'<OCTAL>'/'<OCTAL>,
      case 52:
//\\     <opt_equals>'E'<N><E_INSTR>,
      case 53:
//\\     'JSE'<N>,
      case 54:
//\\     'JE'<N>,
      case 55:
//\\     'PUT'<OCTAL>;
        fprintf(stdout, "uci%d();\n", alt);
        return 0LL;
      }

//\\  P<J_INSTR>=
    case P_J_INSTR:

//\\     'C'<N>'NZS',
//\\     'C'<N>'NZ',
//\\     'C'<N>'Z',
//\\     <COMP>'Z',
//\\     '=',
//\\     '#',
//\\     'V',
//\\     'NV',
//\\     'EN',
//\\     'NEN',
//\\     'EJ',
//\\     'NEJ',
//\\     'TR',
//\\     'NTR',
//\\     ;

//\\  P<MS_INSTR>=
    case P_MS_INSTR:
//\\     'QHN',
//\\     'QH',
//\\     'QN',
//\\     'Q',
//\\     'HN',
//\\     'H',
//\\     'N',
//\\     ;
      {static int qx[8] = {0116, 0106, 0112, 0102, 0114, 0104, 0110, 0100};
      return qx[alt];}


//\\  P<SH_INSTR>=
    case P_SH_INSTR:

//\\     'A'<opt_D><opt_plus><N>,
//\\     'L'<opt_D><opt_plus><N>,
//\\     'C'<opt_plus><N>,
//\\     'A'<opt_D>'C'<N>,
//\\     'L'<opt_D>'C'<N>,
//\\     'CC'<N>
//\\     ;

//\\  P<QS_INSTR>=
    case P_QS_INSTR:

//\\     'LINK',
//\\     'R'<QSTR><N>,
//\\     <opt_plus><QSTR><N>;

//\\  P<plus>=
    case P_plus:

//\\     '+',
//\\     '-';

//\\  P<opt_plus>=
    case P_opt_plus:

//\\     '+',
//\\     ;

//\\  P<opt_equals>=
    case P_opt_equals:
      return 1-alt; // 0 for nothing, 1 for equals.
//\\     '=',
//\\     ;

//\\  P<opt_P>=
    case P_opt_P:

//\\     'P',
//\\     ;

//\\  P<IOM>=
    case P_IOM:

//\\     'I',
//\\     'O',
//\\     'M';

//\\  P<ATOF>=
    case P_ATOF:

//\\     'A',
//\\     'B',
//\\     'C'
//\\     'D',
//\\     'E',
//\\     'F';

//\\  P<E_INSTR>=
    case P_E_INSTR:

//\\     'M'<N>'Q',
//\\     'M'<N>,
//\\     ;

//\\  P<QSTR>=
    case P_QSTR:

//\\     'M',
//\\     'I',
//\\     'C',
//\\     'Q';
      return 0LL;

//\\  P<opt_D>=
    case P_opt_D:
//\\     'D',
//\\     ;
      if (alt == 0) fprintf(stdout, "d");
      return 0LL;

//\\  P<opt_COL>=
    case P_opt_COL:

//\\     ':',
//\\     ;

//\\  P<COMP>=
    case P_COMP:
//\\     '=','>=','>','#','<=','<','\=','->';

// not sure about this one...
//\\  P<APP>=
//\\     ;

//\\ P<opt_ENAME>=;

//\\  P<N>=
//\\     <digit> <opt_digits>;

//\\ P<opt_digits>=
//\\     <digit> <opt_digits>, ;

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

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

//\\  P<NAME>=
//\\     <letter> <opt_rest_of_name>;

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

//\\ 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';

            return 0LL;

//\\ E
	    break;
    }
}

int main(int argc, char **argv)
{

    for (;;) {
        nextfree = 0; arraysize = 0;
        next_free_a = 0; a_size = 0;
        cp = 0;  // code pointer.  Has to be global state.
        ap = 0;  // Analysis record pointer.

	// parse on a line-by-line basis
        line_reconstruction();

#ifdef DEBUG_LEXER
	if (debug_lexer) {
	    int i; // DEBUG ONLY
	    fprintf(stderr, "\nLexical token stream:\n\n");
	    for (i = 0; i < nextfree; i++) {
		fprintf(stderr, "C[%d] => %s, line %d, col %d: [%0d] %s\n",
			i,  c[i].f, c[i].l, c[i].col, c[i].t, c[i].s);
	    }
	}
#endif

        if (startparse(PHRASE_BASE)) {
            (void)compile(0);
        } else {
	    fprintf(stdout, "Syntax error (unable to supply more detail.  Recompile with debug on.)\n");
	    exit(1);
	}
    }
    exit(0);
    return(0);
}