#include "imptoc.h"

// IMP77 compiler first pass.  The comments are mostly from Andy Davis and John McMullin.
// This is 99% automatically translated from Imp77 to C with some manual tweaks for a few
// constructs my translator doesn't handle yet.  I've edited the source to make the
// formatting match the original Imp version, to make comparisons easier.

// It has *not* yet been converted into more idiomatic C - until it is confirmed to be
// working exactly as the original, I'll leave it as this literal transliteration.  Once it
// is more robust, there are a lot of constructs which can be improved to make the source
// more readable.  (For example unless/while/until statements, not to mention all the Imp I/O)

// ############################################################
// # This program is a Copyright work.                        #
// #                                                          #
// # Over the last 40+ years a long and distinguished list of #
// # institutions, individuals and other entities have made   #
// # contributions to portions of this program and may have a #
// # reasonable claim over rights to certain parts of the     #
// # program.                                                 #
// #                                                          #
// # This version is therefore provided for education and     #
// # demonstration purposes only                              #
// ############################################################

// Apologies to Peter Robertson for the statement above by ABD -
// I'll get with you soon to replace it with a more appropriate
// copyright.  I'm well aware that pass1 is 99% your work with
// only minor tweaks from others (and early inspiration from Hamish)

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#include <stdarg.h>

#include "impsig.h"  // Support equivalents for %on %event n,n,n %start, and %signal %event n,n,n
                     // Once tested this will migrate into imptoc.h

int main (int argc, char **argv) { ENTER();
   static const char *version = "8.4";

// configuration parameters
   
// #define minusone (0xFFFF)
   #define minusone (-1)

   // Wee change needed to cross-compile the compiler when going from 16 bit to 32 bit world
// %owninteger minus one = 16_7fff;   // You know, that was wrong too - should have been 16_ffff ...
   #define maxint  ( (((unsigned int)minusone) >> 1) / 10 )
   #define maxdig  ( (((unsigned int)minusone) >> 1) - (maxint * 10) )
   static const int bytesize = 8;             // bits per byte
   #define maxtag 800                         // max no. of tags
   static const int maxdict = 6000;           // max extent of dictionary
   #define namebits 11                        // size of name table as a power of two
   #define maxnames ((1 << namebits) - 1)     // table limit (a mask, eg 255)
   static int sparenames = maxnames;
   static const int litmax = 50;              // max no. of constants/stat.
   static const int recsize = 520;            // size of analysis record
   static const int dimlimit = 6;             // maximum array dimension

   // symbols
   const int ff = 12;
   #define nl 10                              // form feed
   const int marker = '^';                    // marker for faults
   const int squote = '"';                    // string quote
   const int cquote = '\'';                   // character quote (= 39 would be safer given current bug in imp2c)

   // streams
   const int report = 0,  source = 1;
   const int object = 1, listing = 2;

   // types
   const int integer  = 1;
   const int real     = 2;
   const int stringv  = 3;
   const int record   = 4;

   // forms
   #define iform ((integer << 4) + 1)
   const int var      = 91;
   const int _const_  = 93;
   const int swit     = 105;
   const int comment  = 22;
   const int termin   = 20;
   const int lab      = 3;
   const int jump     = 54;
   const int recfm    = 4;
   const int proc     = 7;                    // class for proc

   // phrase entries
   const int escdec   = 252;
   const int escproc  = 253;
   const int escarray = 254;
   const int escrec   = 255;

   // %recordformat arfm(%shortinteger class,sub,link,ptype,papp,pformat,x,pos);!imp77:
   typedef struct arfm
   {
      int class, sub, link, ptype, papp, pformat, x, pos;
   } arfm;

   typedef struct tagfm
   {
      int app, format;
      int flags, index, text, link;
   } tagfm;

   // flags
   // *===.===.===.===.===.====.====.====.===.======.======*
   // ! u ! c ! c ! p ! s ! a  ! o ! pr ! s ! type ! form !
   // ! 1 ! 1 ! 1 ! 1 ! 1 ! 1  ! 1 ! 1  ! 1 !  3   !  4   !
   // *===^===^===^===^===^====^====^====^===^======^======*
   //   u   c   c   p   s   a    o   p    s    t      f
   //   s   l   o   a   u   n    w   r    p    y      o
   //   e   o   n   r   b   a    n   o    e    p      r
   //   d   s   s   a   n   m        t    c    e      m
   //       e   t   m   a   e
   //       d   s       m
   //                   e
   // 
   // 

   static const int usedbit    = 0b1000000000000000;
   static const int closed     = 0b0100000000000000;
   static const int constbit   = 0b0010000000000000;
   static const int parameters = 0b0001000000000000;
   static const int subname    = 0b0000100000000000;
   static const int aname      = 0b0000010000000000;
   static const int ownbit     = 0b0000001000000000;
   static const int prot       = 0b0000000100000000;
   static const int spec       = 0b0000000010000000;
   
   static const int transbit   = 0x4000;
   static const int error      = 0x8000;

   arfm ar[recsize+1];                        // (1:recsize) - Rebased to 0 rather than 1 for efficiency

// I turned a few of these back into shorts to see if that fixed
// the problem with keywords not being recognised.  It didn't,
// though it did fix the diagnostic printing of Atom1 which
// should be 0x8000 - -32768...

   static int class       = 0;                // class of atom wanted
   static int x           = 0;                // usually last tag
   static int atom1       = 0;                // atom class (major)
   static int atom2       = 0;                // atom class (minor)
   static int subatom     = 0;                // extra info about atom
   static int type        = 0;
   static int app         = 0;
   static int format      = 0;                // atom info
   int hashvalue;
   static int faulty      = 0;                // fault indicator
   static int faultrate   = 0;                // fault rate count
   static int lines       = 0;                // current line number
   static int textline    = 0;                // starting line for string const
   static int margin      = 0;                // statement start margin
   static int errormargin = 0;
   static int errorsym    = 0;
   static int column      = 0;
   static int stats       = 0;                // statements compiled
   static int monpos      = 0;                // flag for diagnose
   static int sym         = nl;               // current input symbol
   static int symtype     = 0;                // type of current symbol
   static int quote       = 0;                // >0 strings, <0 chars
   static int endmark     = 0;                // %end flag
   static int cont        = ' ';
   static int csym        = ' ';              // listing continuation marker
   static int decl        = 0;                // current declarator flags
   static int dim         = 0;                // arrayname dimension
   static int specgiven   = 0;

   static int escapeclass = 0;                // when and where to escape
   static int protection  = 0;
   static int atomflags   = 0;
   static int otype       = 0;                // current 'own' type
   static int realsln     = 1;                // =4 for %REALSLONG
   static int last1       = 0;                // previous atom class
   static int gentype     = 0;
   static int ptype       = 0;                // current phrase type
   static int papp        = 0;                // current phrase parameters
   static int pformat     = 0;                // current phrase format
   static int force       = 0;                // force next ptype
   static int g           = 0;
   static int gg          = 0;
   static int mapgg       = 0;                // grammar entries
   static int fdef        = 0;                // current format definition
   static int this        = -1;               // current recordformat tag
   static int nmin        = 0;                // analysis record atom pointer
   static int nmax        = 0;                // analysis record phrase pointer
   static int rbase       = 0;                // record format definition base
   static int dmax        = 1;
   static int tmin        = maxtag;           // upper bound on tags
   static int ss          = 0;                // source statement entry
   char includefile[64];
   static int includelist = 0;
   static int includelevel = 0;
   static int include     = 0;                // =0 unused, #0being used
   static int perm        = 1;                // 1 = compiling perm, 0 = program
   static int progmode    = 0;                // -1 = file, 1 = begin/eop
   static int sstype      = 0;                // -1:exec stat
                                              // 0: declaration
                                              // 1: block in
                                              // 2: block out
   static int specmode     = 0;               // >=0: definition
                                              // -1: proc spec
                                              // -2: recordformat
   static int ocount       = -1;              // own constants wanted
   static int limit        = 0;               // lookup limit
   static int copy         = 0;               // duplicate name flag
   static int order        = 0;               // out of sequence flag
   static int forwarn      = 0;               // non-local flag
   static int dubious      = 0;               // flag for dubious statements
   static int dp           = 1;
   static int pos1         = 0;
   static int pos2         = 0;               // error position
   static int pos          = 0;               // input line index
   static int dimension    = 0;               // current array dimension
   static int local        = 0;               // search limit for locals
   static int fmbase       = 0;               // entry for format decls
   static int searchbase   = 0;               // entry for record_names
   static int formatlist   = 0;               // size of current format list
   int recid;
   static unsigned char _char_[134] = {       // input line
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
     10, 10, 10, 10
   };
   int litpool[litmax+1];
   static int lit = 0;        // current literal (integer)
   static int lp = 0;         // literals pointer
   static int blockx = 0;     // block tag
   static int list = 1;       // <= to enable
// static int list = -1;      // <= to enable
#ifdef INCLUDE_UNUSED  // Either never written to, or written to but never read from
   static int control = 0;
#endif
   static int diag = 0;       // diagnose flags
// static int diag = -1;      // diagnose flags ALL ON.
   int hash[maxnames+1];
   tagfm tag[maxtag+1];
   int dict[maxdict+1];       // (1:maxdict) - Rebased to 0 rather than 1 for efficiency
   unsigned char buff[512+1]; // (1:512) - Rebased to 0 rather than 1 for efficiency
   static int bp = 0;

   /* grammar related constants */
   #define maxgrammar 1720         // This would be better coming from tables.h
   static int gmin = maxgrammar;   // upper bound on grammar
   static const int manifest = 120, figurative = 130;
   // Sometimes I have had to change const ints into #defines because
   // C does not consider a const int to be a proper constant in some contexts
   // (in particular, in array bound dimension expressions) - it is treated
   // more like a variable that happens to be stored in read-only memory.
   #define actions 180    // This was 179 in the original pass1.c before I corrected it to match the grammar
   #define phrasal 200

   static const unsigned char amap[16] = {
     89,   91,   92,  104,   94,   93,  105,  100,  101,  102,  103,  106,  107,  108,  109,   89
 //   ?     v     n     l    fm const  swit    rp    fp    mp    pp     a    an    na    nan    ?
   };

   static const unsigned char atoms[16] = {
     89, 1, 1, 10,  9,  1,  10,  7, 7, 7, 7,  4,  1,  4,  1, 89
   // ?  v   n  l  fm const swit rp fp mp pp  a   an  na nan ?
   };

   // *** start of generated tables ***
   #include "tables.h"
   // *** end of generated tables ***

   auto void flushbuffer (int limit) { ENTER();
      int j;
      if (bp >= limit) {
         if (faulty == 0) {
            selectoutput (object);
            for (j = 1; j <= bp; j += 1) {
               printsymbol (buff[j]);
            }
            selectoutput (listing);
         }
         bp = 0;
      }
   }

   auto void addchar (unsigned char ch) { ENTER();
      bp += 1;
      buff[bp] = ch;
   }

   auto void op (int code, int param) { ENTER();
      buff[bp + 1] = code;
      buff[bp + 2] = param >> 8;
      buff[bp + 3] = param;
      bp += 3;
   }

   auto void setconst (int m) { ENTER();
      buff[bp + 1] = 'N';
      buff[bp + 5] = m;
      m = m >> 8;
      buff[bp + 4] = m;
      m = m >> 8;
      buff[bp + 3] = m;
      m = m >> 8;
      buff[bp + 2] = m;
      bp += 5;
   }

#ifdef INCLUDE_UNUSED  // Either never written to, or written to but never read from
   auto void octal (int n) { ENTER();
      int m;
      m = n >> 3;
      if (m != 0)
         octal (m);
      addchar ((n & 7) + '0');
   }

   auto void hexadecimal (int n) { ENTER();
      int m;
      m = n >> 4;
      if (m != 0)
         hexadecimal (m);
      if ((n & 15) > 9)
         addchar ((n & 15) + 'A');
      else
         addchar ((n & 15) + '0');
   }
#endif

   auto void printident (int p, int mode) { ENTER();

      auto void putit (int ch) { ENTER();
         if (mode == 0) {
            printsymbol (ch);
         } else {
            addchar (ch);
         }
      }

      int k, l;
      p = tag[p].text;
      if (p == 0) {
         putit ('?');
         return;
      }
      p += 1;             // advance to name string
      k = dict[p];
      l = k & 255;        // length
      while (l > 0) {
         putit (k >> 8);
         l -= 1;
         p += 1;
         k = dict[p];
         if (l == 0) break;
         putit (k & 255);
         l -= 1;
      }
   }
   
   auto void abandon (int n) { ENTER();
       static const void *reason[ 10 ] = {
        &&reason_0, &&reason_1, &&reason_2, &&reason_3, &&reason_4,
        &&reason_5, &&reason_6, &&reason_7, &&reason_8, &&reason_9,
      };
      int stream;
      stream = listing;
      for (;;) {
         if (sym != nl) newline ();
         printsymbol ('*'); write (lines, 4); space ();
         if ((n < 0) || (n > 9)) BADSWITCH(n,__LINE__,__FILE__);
         goto *reason[n];
       reason_0:                /* 0 */
         printstring ("compiler error!");          goto more;
       reason_1:                /* 1 */
         printstring ("switch vector too large");  goto more;
       reason_2:                /* 2 */
         printstring ("too many names");           goto more;
       reason_3:                /* 3 */
         printstring ("program too complex");      goto more;
       reason_4:                /* 4 */
         printstring ("feature not implemented");  goto more;
       reason_5:                /* 5 */
         printstring ("input ended: ");
         if (quote != 0) {
            if (quote < 0) printsymbol (cquote); else printsymbol (squote);
         } else {
            printstring ("%endof");
            if (progmode >= 0) printstring ("program"); else printstring ("file");
         }
         printstring (" missing?");                goto more;
       reason_6:                /* 6 */
         printstring ("too many faults!");         goto more;
       reason_7:                /* 7 */
         printstring ("string constant too long"); goto more;
       reason_8:                /* 8 */
         printstring ("dictionary full");          goto more;
       reason_9:                /* 9 */
         printstring (concat ("Included file ", concat (includefile, " does not exist")));

       more:
         newline ();
         printstring ("***  compilation abandoned ***"); newline ();
         if (stream == report) break;
         closeoutput ();
         stream = report;
         selectoutput (report);
      }
      if ((diag&4096) != 0) signal_event(15, 15, 0);
      exit (0);
   }

   auto void compileblock (int level, int blocktag, int dmin, int tmax, int id) { ENTER();

      auto int gapp (void);
      auto void deletenames (int quiet);
      auto void analyse (void);
      auto void compile (void);

      int open;     open = closed;        // zero if can return from proc
#ifdef INCLUDE_UNUSED  // Either never written to, or written to but never read from
      int dbase;    dbase = dmax;         // dictionary base
#endif
      int tbase;      tbase = tmax;       // tag base
      int tstart;     tstart = tmax;
      int _label_;    _label_ = 4;        // first internal label
      int access;     access = 1;         // non-zero if accessible
      int inhibit;    inhibit = 0;        // non-zero inhibits declaratons

      int *bflags;    bflags = &tag[blocktag].flags /* Pointer assignment */ ;
      int blocktype;  blocktype = (*bflags >> 4) & 7;
      int blockform;  blockform = *bflags & 15;
      int blockfm;    blockfm = tag[blocktag].format;
      int blockotype; blockotype = otype;
      int *blockapp;  blockapp = &tag[blocktag].app /* Pointer assignment */ ;

      int l, newapp;

      auto void fault (int n) { ENTER();
         // -5 : -1 - warnings
         // 0 : 22 - errors

         static const void *fm[ 23 ] = {
           &&fm_0,  &&fm_1,  &&fm_2,  &&fm_3,  &&fm_4,  &&fm_5,  &&fm_6,  &&fm_7,  &&fm_8,  &&fm_9,  &&fm_10,
           &&fm_11, &&fm_12, &&fm_13, &&fm_14, &&fm_15, &&fm_16, &&fm_17, &&fm_18, &&fm_19, &&fm_20, &&fm_21, 
           &&fm_22 };
         static const void *fm_minus[ 6 ] = {
           &&fm_default,
           &&fm_minus_1, &&fm_minus_2, &&fm_minus_3, &&fm_minus_4, &&fm_minus_5
         };
         int st;

         auto void printss (void) { ENTER();
            int s, p;

            if (pos == 0) return;
            space ();
            p = 1;
            for (;;) {
               if (p == pos1) printsymbol (marker);
               if (p == pos) break;
               s = _char_[p]; p += 1;
               if ((s == nl) || ((s == '%') && (p == pos))) break;
               if (s < ' ') {             // beware of tabs
                  if (s == ff) s = nl; else s = ' ';
               }
               printsymbol (s);
            }
            if (list <= 0) pos = 0;
         }
         
         if (pos2 > pos1) pos1 = pos2;
         if (sym != nl) newline ();
         st = report;
         if (n == -3) st = listing;        // don't report unused on the console
         for (;;) {
            selectoutput (st);
            if (n < 0) { printsymbol ('?'); pos1 = 0; } else printsymbol ('*');
            if (st != report) {
               if ((list <= 0) && (pos1 != 0)) {
                  spaces (pos1 + margin); printstring ("      ! ");
               }
            } else {
               if (include != 0) printstring (includefile);
               write (lines, 4); printsymbol (csym); space ();
            }
            if ((-5 <= n) && (n < 0)) {
               goto *fm_minus[-n];
            } else if ((0 <= n) && (n <= 22)) {
               goto *fm[n];
            }
            printstring ("fault"); write (n, 2);
            goto ps;
          fm_default:
            BADSWITCH(n,__LINE__,__FILE__);
          fm_minus_5:           /* -5 */
            printstring ("Dubious statement");  dubious = 0;   goto psd;
          fm_minus_4:           /* -4 */
            printstring ("Non-local");
            pos1 = forwarn; forwarn = 0;                       goto ps;
          fm_minus_3:           /* -3 */
            printident (x, 0); printstring (" unused");        goto nps;
          fm_minus_2:           /* -2 */
            printstring ("\"}\"");                             goto miss;
          fm_minus_1:           /* -1 */
            printstring ("access");                            goto psd;
          fm_0:         /* 0 */
            printstring ("form");                              goto ps;
          fm_1:         /* 1 */
            printstring ("atom");                              goto ps;
          fm_2:         /* 2 */
            printstring ("not declared");                      goto ps;
          fm_3:         /* 3 */
            printstring ("too complex");                       goto ps;
          fm_4:         /* 4 */
            printstring ("duplicate "); printident (x, 0);     goto ps;
          fm_5:         /* 5 */
            printstring ("type");                              goto ps;
          fm_6:         /* 6 */
            printstring ("match");                             goto psd;
          fm_7:         /* 7 */
            printstring ("context");                           goto psd;
          fm_8:         /* 8 */
            printstring ("%cycle");                            goto miss;
          fm_9:         /* 9 */
            printstring ("%start");                            goto miss;
          fm_10:                /* 10 */
            printstring ("size"); if (pos1 == 0) write (lit, 1); goto ps;
          fm_11:                /* 11 */
            printstring ("bounds");
            if (!(ocount < 0)) write (ocount, 1);              goto ps;
          fm_12:                /* 12 */
            printstring ("index");                             goto ps;
          fm_13:                /* 13 */
            printstring ("order");                             goto psd;
          fm_14:                /* 14 */
            printstring ("not a location");                    goto ps;
          fm_15:                /* 15 */
            printstring ("%begin");                            goto miss;
          fm_16:                /* 16 */
            printstring ("%end");                              goto miss;
          fm_17:                /* 17 */
            printstring ("%repeat");                           goto miss;
          fm_18:                /* 18 */
            printstring ("%finish");                           goto miss;
          fm_19:                /* 19 */
            printstring ("result");                            goto miss;
          fm_20:                /* 20 */
            printsymbol ('"'); printident (x, 0); printsymbol ('"'); goto miss;
          fm_21:                /* 21 */
            printstring ("context "); printident (this, 0);    goto ps;
          fm_22:                /* 22 */
            printstring ("format");                            goto ps;
          miss:
            printstring (" missing");                          goto nps;
          psd:
            pos1 = 0;
          ps:
            printss ();
          nps:
            newline ();
            if (st == listing) break;
            st = listing;
         }
         if (n >= 0) {
            if ((diag&4096) != 0) signal_event(15,15,0);
            if (n != 13) {  // order is fairly safe
               ocount = -1;
               gg = 0;
               copy = 0; quote = 0;
               searchbase = 0; escapeclass = 0;
               gg = 0; // looks redundant but is in original Imp version
            }
            faulty += 1;

            // check that there haven't been too many faults

            faultrate += 3; if (faultrate > 30) abandon (6);
            if (faultrate <= 0) faultrate = 3;
         }
         tbase = tstart;
         if ((list <= 0) && (sym != nl)) {
            errormargin = column;
            errorsym = sym; sym = nl;
         }
      }
      
      dmin -= 1; dict[dmin] = -1;
      // end marker for starts & cycles
      if (dmax == dmin) abandon (2);
      
      if ((list > 0) && (level > 0)) {
         write (lines, 5); spaces (level * 3 - 1);
         if (blocktag == 0) {
            printstring ("Begin");
         } else {
            printstring ("Procedure "); printident (blocktag, 0);
         }
         newline ();
      }

      // deal with procedure definition (parameters)
      if (blocktag != 0) {                                   // proc
         analyse (); if (ss != 0) compile ();

         if (blockotype != 0) {                              // external-ish
            if ((*bflags & spec) == 0) {                      // definition
               if ((progmode <= 0) && (level == 1)) progmode = -1; else fault (7);
            }
         }
         
         newapp = gapp ();                                   // generate app grammar
         if (specgiven != 0) {                               // definition after spec
            if (newapp != *blockapp) fault (6);               // different from spec
         }
         *blockapp = newapp;                                 // use the latest
         
         if (level < 0) {                                    // not procedure definition
            deletenames (0);
            return;
         }
      } else {
         open = 0;                                           // can return from a block?
      }
      
      for (;;) {
         analyse ();
         if (ss != 0) {
            compile ();
            if (dubious != 0) fault (-5);
            flushbuffer (128);                              // flush if bp >= 128
            if (sstype > 0) {                               // block in or out
               if (sstype == 2) break;                       // out
               compileblock (specmode, blockx, dmin, tmax, id);
               if (ss < 0) break;                            // endofprogram
            }
         }
      }
      if ((list > 0) && (level > 0)) {
         write (lines, 5); spaces (level * 3 - 1);
         printstring ("End");
         newline ();
      }
      deletenames (0);
      return;

      // generate app grammar (backwards)
      auto int gapp (void) { ENTER();
         static const int comma = 140;                       // psep
         auto void setcell (int g, int tt);
         auto void class (tagfm * v);
         tagfm *v;
         int p, link, tp, c, ap, t;

         if (tmax == local) return (0);                      // no app needed

         p = gmax1; link = 0; t = tmax;
         
         for (;;) {
            v = &tag[t] /* Pointer assignment */ ; t -= 1;
            class (v);                                       // deduce class from tag
            if (c < 0) {                                     // insert %PARAM
               c = -c;
               setcell (196, tp);
               tp = -1;
            }
            setcell (c, tp);
            if (t == local) break;                           // end of parameters
            setcell (comma, -1);                             // add the separating comma
         }
         if (gmax > gmin) abandon (3);

         return (link);

         auto void setcell (int g, int tt) { ENTER();
            // add the cell to the grammar, combining common tails
            while (p != gmax) {
               p += 1;
               if ((glink (p) == link) && (gram (p) == g)) {
                  if ((tt < 0) || ((gram (p + 1) == tt) && (glink (p + 1) == ap))) {
                     link = p;
                     // already there
                     return;
                  }
               }
            }
           
            // add a new cell
            gmax += 1;
            gram (gmax) = g;      // I tried being very explicit about type conversions and
            glink (gmax) = link;  // sign extending but it made zero difference to the current problem.
            link = gmax;                    // making some of the scalar ints in this file into shorts did
                                            // help with the display of Atom1 when it contained 'error' (0x8000)
                                            // but that was only cosmetic - no changes to program behaviour.

            if (tt >= 0) {  // set type cell
               gmax += 1;
               gram (gmax) = tt;  // macros are in tables.h
               glink (gmax) = ap;
            }
            p = gmax;
            
         }

         auto void class (tagfm * v) { ENTER();
            #define err 89
            #define rtp 100
            #define fnp 101
            #define mapp 102
            #define predp 103
            static const int classmap[16] = {
              err,1764, 247, err,err,err,err, -rtp, -fnp, -mapp, -predp, err, 214,
              err, 229, err
            };
            #undef err
            #undef rtp
            #undef fnp
            #undef mapp
            #undef predp
            int tags, type, form;

            ap = 0;
            tags = v->flags;
            type = (tags >> 4) & 7; form = tags & 15;
            tp = (v->format << 3) | type;
            c = classmap[form];
            if ((type == 0) && (form == 2)) { c = 208; tp = 0; }        // %name
            if ((tags & parameters) != 0) ap = v->app;
         }
      }

      auto void deletenames (int quiet) { ENTER();
         int flags;
         tagfm *tx;

         while (tmax > tbase) {
            x = tmax; tmax -= 1;
            tx = &tag[x] /* Pointer assignment */ ;
            flags = tx->flags;
            if (((flags & spec) != 0) && ((flags & ownbit) == 0)) fault (20);
            // /* spec with no definition & not external */
            if (((flags & usedbit) == 0) && (level >= 0) && (list <= 0)) {
               if (quiet == 0) fault (-3);                            // unused
            }
            dict[tx->text] = tx->link;
         }
      }
      
      auto void analyse (void) { ENTER();
         static const int orderbits = 0x3000, orderbit = 0x1000;
         static const int escape = 0x1000;
         int strp, mark, flags, proterr, k, s, c;
         static int key = 0;
         int node;
         int *z;
         arfm *arp;
         static const void *act[ phrasal-actions+1 ] = {
           &&act_default, // act(180) not present
           &&act_181,  &&act_182,  &&act_183,  &&act_184, 
           &&act_185,  &&act_186,  &&act_187,  &&act_188, 
           &&act_189,  &&act_190,  &&act_191,  &&act_192, 
           &&act_193,  &&act_194,  &&act_195,  &&act_196, 
           &&act_197,  &&act_198,  &&act_199,
           &&act_default // act(200) not present
         };
         static const void *paction[ 16 ] = {
           &&paction_0, &&paction_1, &&paction_2, &&paction_3,
           &&paction_4, &&paction_5, &&paction_6, &&paction_7, 
           &&paction_default, &&paction_default, &&paction_default, &&paction_default,
           &&paction_default, &&paction_default, &&paction_default, &&paction_default, 
         };

         auto void traceanalysis (void) { ENTER();
            // diagnostic trace routine (diagnose&1 # 0)
            int a;

            auto void show (int a) { ENTER();
               if ((0 < a) && (a < 130)) {
                  space ();
                  printstring (text (a));
               } else
                  write (a, 3);
            }

            static int la1 = 0, la2 = 0, lsa = 0, lt = 0;
            if ((monpos != pos) && (sym != nl)) newline ();
            monpos = pos;
            write (g, 3);
            space ();
            printstring (text (class));
            if ((gg & transbit) != 0) printsymbol ('"');
            a = (gg >> 8) & 15;
            if (a != 0) {
               printsymbol ('{');
               write (a, 0);
               printsymbol ('}');
            }
            if ((atom1 != la1) || (atom2 != la2) || (lsa != subatom) || (lt != type)) {
               printstring (" [");
               la1 = atom1;
               show (la1);
               la2 = atom2;
               show (la2);
               lsa = subatom;
               write (lsa, 3);
               lt = type;
               write (lt, 5);
               printsymbol (']');
            }
            newline ();
         }

         auto void getsym (void) { ENTER();
            readsymbol (sym);
            if (sym < 0) abandon (5);
            if (pos != 133) pos += 1;
            _char_[pos] = sym;
            if (list <= 0) printsymbol (sym);
            column += 1;
         }

         auto void readsym_ (int LINE) { ENTER();
            static int last = 0;
            static const unsigned char mapped[128] = {
              0,  0,  0,  0,   0,  0,  0,  0,    0,  0, 10,  0,   3,  0,  0,  0,
              0,  0,  0,  0,   0,  0,  0,  0,    0,  0,  0,  0,   0,  0,  0,  0,
              0,  '!','"','#', '$',  1,'&', 39,  '(',')','*','+', ',','-','.','/',
              '0','1','2','3', '4','5','6','7',  '8','9',':',';', '<','=','>','?',
              '@','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','[', '\\',']','^','_',
              '`','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', 2 , '|','}','~',  0
            };

            // ! 0 = space
            // ! 1 = %
            // ! 2 = {
            // ! 3 = ff
            // ! other values represent themselves

            if (sym == nl) {
             s1:
               lines += 1;
               if (endmark != 0) printsymbol (endmark);
             s11:
               pos = 0; pos1 = 0; pos2 = 0; margin = 0; column = 0;
               last = 0;
               endmark = 0;
               if (list <= 0) {
                  if (include != 0) {
                     printstring (" &"); write (lines, -4);
                  } else write (lines, 5);
                  csym = cont; printsymbol (csym);
                  space ();
                  if (errormargin != 0) {
                     lines -= 1;
                     spaces (errormargin);
                     errormargin = 0;
                     if (errorsym != 0) {
                        printsymbol (errorsym);
                        pos = 1; _char_[1] = errorsym;
                        sym = errorsym; errorsym = 0;
                        goto s5;
                     }
                  }
               }
             s2:
               symtype = 1;
            }
          s3:
            readsymbol (sym);
            if (sym < 0) abandon (5);
            if (pos != 133) pos += 1;
            _char_[pos] = sym;
            if (list <= 0) printsymbol (sym);
            column += 1;
          s5:
            if (sym != nl) {
               last = sym;
               if (quote != 0) return;                                  // dont alter strings
               sym = mapped[sym & 127];
               if (sym <= 3) {
                  // special symbol
                  if (sym == 0) goto s2;
                  // space (or dubious control)
                  if (sym == 1) { symtype = 2; goto s3; }               // %
                  if (sym == 3) { cont = '+'; goto s11; }               // ff
                  // must be {...
                  for (;;) {
                     getsym ();
                     if (sym == '}') goto s3;
                     if (sym == nl)  goto s4;
                  }
               }
               key = kdict (sym);
               if (((key & 3) == 0) && (symtype == 2)) {
                  // keyword
                  if ((sym == 'C') && (nextsymbol() == nl)) {          // %c...
                     getsym (); cont = '+'; goto s1;
                  }
               } else {
                 symtype = (key & 3) - 2; // 1, 0, -1, -2
               }
               return;
            }
          s4:
            symtype = quote;
            if ((last == 0) && (quote == 0)) goto s1;
            cont = '+';
         }
#define readsym() readsym_(__LINE__)

         auto int formatselected (void) { ENTER();
            formatlist = tag[format].app;                // number of names
            if (formatlist < 0) {                        // forward ref
               atom1 = error + 22;
               return (0);
            }
            if (sym == '_') {
               escapeclass = escrec;
               searchbase = tag[format].format;
            }
            return (1);
         }

         auto void codeatom (int target) { ENTER();
            int dbase;
#ifdef INCLUDE_UNUSED  // Either never written to, or written to but never read from
            int da;
#endif
            int base, n;
#ifdef INCLUDE_UNUSED  // Either never written to, or written to but never read from
            int mul;
#endif
            int pendquote;
            int j, k, l, pt;
            
            auto void lookup (int d) { ENTER();
               int newname, vid, k1;
#ifdef INCLUDE_UNUSED  // Either never written to, or written to but never read from
               int k2;
#endif
               int form;
               tagfm *t;
               int new;

               // twee little function because SKIMP86 can't do string compare properly
               // returns 1 if the two names are the same, else zero
               auto int dictmatch (int ptr1, int ptr2) { ENTER();
                  int len;
                 
                  // start with a cheap check of the length and first character
                  if (dict[ptr1] != dict[ptr2]) {
                     return (0);
                  }
                  len = dict[ptr1] & 255;
                  ptr1 += 1;
                  ptr2 += 1;
                  len -= 1;
                  while (len >= 2) {
                     if (dict[ptr1] != dict[ptr2]) {
                        return (0);
                     }
                     ptr1 += 1;
                     ptr2 += 1;
                     len -= 2;
                  }
                  // if the string was odd length, we might need one last byte checked
                  if (len == 1) {
                     if ((dict[ptr1] & 255) != (dict[ptr2] & 255)) { // is endianness relevant?
                        return (0);
                     }
                  }
                  return (1);
               }

               // first locate the text of the name
               new = dmax + 1;                   // points to text of string in dictionary
               k1 = hashvalue & maxnames;        // rather crude hash!
               for (;;) {
                  newname = hash[k1];
                  if (newname == 0) break;       // not in
                  if (dictmatch (newname + 1, new) == 1) goto in;
                  k1 = (k1 + 1) & maxnames;
               }

               // not found
               sparenames -= 1;
               if (sparenames <= 0) abandon (2);
               hash[k1] = dmax;                  // put it in
               dict[dmax] = -1;
               newname = dmax; dmax = dp; goto notin;

             in:
               if ((this >= 0) && (d != 0)) searchbase = rbase;    // record elem defn
               if (searchbase != 0) {            // record subname
                  new = -1;
                  x = searchbase;
                  for (;;) {
                     if (x < formatlist) goto notin;
                     if (tag[x].text == newname) break;
                     x -= 1;
                  }
               } else {                          // hash in for normal names
                  x = dict[newname];
                  if (x <= limit) goto notin;    // wrong level
               }

               subatom = x;                      // name found, extract info
               t = &tag[x] /* Pointer assignment */ ;
               atomflags = t->flags;
               format = t->format; app = t->app;
               protection = atomflags & prot;
               type = (atomflags >> 4) & 7; atom1 = amap[atomflags & 15];
               
               if ((diag & 8) != 0) {
                  printstring ("lookup:");
                  write (atom1, 3);
                  write (type, 1);
                  write (app, 3);
                  write (format, 5);
                  write (atomflags, 3);
                  newline ();
               }

               if (d == 0) {                              // old name wanted
                  t->flags = t->flags | usedbit;
                  searchbase = 0;

                  if (((atomflags & subname) != 0) && (format != 0)) {  // a record
                     if (formatselected () == 0) return;
                  }
                  
                  if ((atomflags & parameters) != 0) {    // proc or array
                     if (app == 0) {                      // no parameters needed
                        atom2 = atom1;
                        atom1 -= 4;
                        if ((97 <= atom1) && (atom1 <= 98)) {
                           mapgg = atom1; atom1 = var;
                        }
                     } else {
                        if (sym == '(') {
                           searchbase = 0;                // ignore format for now
                           if (atom1 >= 106) {            // arrays
                              app = phrase (app + 200);
                              escapeclass = escarray;
                              atom1 = ((atom1 - 106) >> 1) + 91;  // a,an->v na,nan->n
                           } else {
                              // procedures
                              escapeclass = escproc;
                              atom1 -= 4;
                           }
                           phrase (200) = app;
                        }
                     }
                     pos2 = pos;
                     return;
                  }
                  
                  // deal with constintegers etc
                  if (((atomflags & constbit) != 0) && (atom1 == var)) {
                     mapgg = _const_; atom2 = _const_;
                     if (type == integer) subatom = -subatom;
                  }
                  return;
               }
                                                                // new name wanted
               if (tbase != tstart) goto notin;                 // don't fault proc parm-parm
               if (d == (lab + spec + usedbit)) {
                  t->flags = t->flags | usedbit;
                  return;
               }
               if ((atomflags & spec) != 0) {                   // a spec has been given
                  if (d == lab) {                               // define label
                     t->flags = t->flags - spec;
                     return;
                  }
                  if ((7 <= (decl & 15)) && ((decl & 15) <= 10) && ((decl & spec) == 0)) {
                     // procedure definition after spec
                    if (((decl ^ atomflags) & 0b1111111) == 0) { // correct type?
                        t->flags = t->flags - spec;
                        specgiven = 1;
                        return;
                     }
                     // note that an external procedure must be speced as a
                     // non-external procedure.
                  }
                  if ((decl & 15) == recfm) {                    // recordformat
                     t->flags = (record << 4) + recfm;
                     t->format = fdef;
                     return;
                  }
               }
               if ((last1 == jump) && (atom1 == swit)) return;
               if (copy == 0) copy = x;
             notin:
               app = 0;  vid = 0;
               atom1 = error + 2;

               if (d == 0) return;                              // old name wanted
               type = (d >> 4) & 7; form = d & 15; atom1 = amap[form];
               
               if (this < 0) {                                  // normal scope
                  new = newname;
                  tmax += 1; x = tmax;
               } else {                                         // recordformat scope
                  new = -1;
                  recid -= 1; vid = recid;
                  tmin -= 1;  x = tmin;
                  formatlist = tmin;
               }
               
               if ((11 <= form && form <= 14)) {                // arrays
                  if (dim == 0) dim = 1;                  // set dim for owns
                  app = dim;
               }
               
               if (((otype > 2) && ((d & spec) == 0)) || (perm != 0) || (level == includelevel)) d = d | usedbit;

               // external definitions need not be used in the file in which
               // they are defined, so inhibit a useless unused warning.

               t = &tag[x] /* Pointer assignment */ ;
               if (form == lab) {
                  id += 1;  vid = id;
               }
               t->index = vid;
               t->text = newname;
               t->flags = d;
               t->app = app;
               t->format = fdef; format = fdef;
               subatom = x;
               
               if (new >= 0) {                                    // insert into hash table
                  t->link = dict[new]; dict[new] = x;
                  if (gmin == maxgrammar) {                       // proc param params
                     tmin -= 1;  subatom = tmin;
                     tag[tmin] = *t; // ASSIGN COMPLETE STRUCT. Dioes this work in C?  Use memmove??
                  }
               }
               if (tmax >= tmin) abandon (3);
            }
            
          top:
            pos1 = pos;
            subatom = 0; pendquote = 0; atomflags = 0;
            
            // app and format must be left for assigning to papp & pformat
            if (symtype == -2) goto name;                         // letter
            if (symtype < 0) goto number;                         // digit
            if (symtype == 0) {
               atom1 = termin;  atom2 = 0;
               return;
            }
            if (symtype != 2) {                   // catch keywords here
               if (quote != 0) goto text;         // completion of text
               if (sym == squote) goto strings;   // start of string
               if (sym == cquote) goto symbols;   // start of symbol
               if ((sym == '.') && ('0' <= nextsymbol()) && (nextsymbol() <= '9')) goto number;
            }
            
            // locate atom in fixed dict
            k = key >> 2; readsym ();
            for (;;) {
               j = kdict (k);
               if ((j & 0x4000) != 0) break;
               if (((j & 127) != sym) || (symtype < 0)) {
                  if (!(j < 0)) goto err;
                  k += 1;
               } else {
                  l = (j >> 7) & 127; readsym ();
                  if (j > 0) {
                     if (l != 0) {
                        if ((l != sym) || (symtype < 0)) {
                           goto err;
                        }
                        readsym ();
                     }
                     l = 1;
                  }
                  k += l;
               }
            }
            atom1 = j & 127;
            if (atom1 == 0) {                        // comma
               atom1 = 19; subatom = 19; atom2 = 0;
               if (sym == nl) {
                  if (ocount >= 0) return;
                  // special action needs to be taken with <comma nl> as
                  // const array lists can be enormous
                  readsym ();
               }
               return;
            }
            atom2 = (j >> 7) & 127;
            subatom = kdict (k + 1) & 0x3FFF;
            // !!!!cont = ' '
            return;

            // report an error. adjust the error marker (pos1) to point
            // to the faulty character in an atom, but care needs to be taken
            // to prevent misleading reports in cases like ...?????

          err:
            atom1 = error + 1;  atom2 = 0;
            if (pos - pos1 > 2) pos1 = pos;
            return;

            // take care with strings and symbol constants.
            // make sure the constant is valid here before sucking it in
            // (and potentially losing many lines)

          symbols:
            atom1 = var;  atom2 = _const_;  type = integer;
            mapgg = _const_;  protection = prot;
            subatom = lp;  if (lp >= litmax) abandon (3);
            quote = ~pendquote;
            return;
            
            // an integer constant is acceptable so get it in and
            // get the next atom
          chars:
            n = 0; cont = cquote;
            for (;;) {
               readsym ();
               if (sym == cquote) {
                  if (nextsymbol() != cquote) break;
                  readsym ();
               }
               if ((n & (~(-1 >> bytesize))) != 0) {   // overflow
                  pos1 = pos;  atom1 = error + 10;  return;
               }
               if (quote == 0) goto err;
               n = (n << bytesize) + sym;
               quote += 1;
            }
            quote = 0;  cont = ' ';
            if (sym != nl) readsym ();
            litpool[lp] = n;  lp += 1;
            goto top;
            
            // sniff the grammar before getting the string
          strings:
            atom1 = var;  atom2 = _const_;  type = stringv;
            subatom = strp | 0x4000;
            mapgg = _const_;  protection = prot;
            quote = subatom;
            textline = lines;   // in case of errors
            return;

            // a string constant is ok here, so pull it in and get
            // the next atom
            // ABD - temp variable to help pack bytes into words
            int flipflop;

          text:
            if (quote < 0) goto chars;                // character consts
            l = strp;                                 // point to beginning
            k = 0;                                    // length so far
            flipflop = 0;                             // space for the length is up the spout

            for (;;) {
               cont = squote; quote = 1;
               for (;;) {
                  readsym ();
                  if (sym == squote) {                // terminator?
                     if (nextsymbol() != squote) break;   // yes ->
                     readsym ();                      // skip quote
                  }
                  if (flipflop >= 0) {
                     glink (strp) = ((sym << 8) + flipflop);
                     strp += 1;
                     flipflop = -1;
                  } else {
                     flipflop = sym;
                  }
                  k += 1;
                  if (k > 255) { lines = textline; abandon (7); }  // too many chars
               }
               if (flipflop >= 0) {                    // tail-end charlie
                  glink (strp) = flipflop;
                  strp += 1;
               }
               glink (l) = (glink (l) | k);  // plug in length

               quote = 0;  cont = ' ';  readsym ();
               codeatom (target);
               if (!((atom1 == 48) && (sym == squote))) return; // fold "???"."+++"
            }
            
            auto void get (int limit) { ENTER();
               int s, shift;
               shift = 0;
               if (base != 10) {
                  if (base == 16) {
                     shift = 4;
                  } else {
                     if (base == 8) {
                        shift = 3;
                     } else {
                        if (base == 2) {
                           shift = 1;
                        }
                     }
                  }
               }
               n = 0;
               for (;;) {
                  if (symtype == -1) {        // digit
                     s = sym - '0';
                  } else {
                     if (symtype < 0) {       // letter
                        s = sym - 'A' + 10;
                     } else {
                        return;
                     }
                  }
                  if (s >= limit) return;
                  pt += 1;  glink (pt) = sym;
                  if (base == 10) {
                    if ((n >= maxint) && (((s > maxdig) || (n > maxint)))) {
                        // too big for an integer,
                        // so call it a real
                        base = 0;  type = real;  n = 0;
                     }
                  }
                  if (shift == 0) {
                     n = n * base + s;
                  } else {
                     n = (n << shift) + s;
                  }
                  readsym ();
               }
            }
          number:
            base = 10;
          bxk:
            atom1 = var;  atom2 = _const_;  type = integer;  subatom = lp;
            mapgg = _const_;  protection = prot;
            if (lp >= litmax) abandon (3);
            pt = strp;
#ifdef INCLUDE_UNUSED  // Either never written to, or written to but never read from
            mul = 0;
#endif
            for (;;) {
               get (base);
               if (!((sym == '_') && (base != 0) && (pendquote == 0))) break;   // change of base
               pt += 1; glink (pt) = '_';
               readsym ();
               base = n;
            }
            
            if (pendquote != 0) {
               if (sym != cquote) goto err;
               readsym ();
            }
            if (sym == '.') {                                // a real constant
               pt += 1;  glink (pt) = '.';
               readsym ();
               type = real;  n = base;  base = 0;  get (n);
            }
            
            if (sym == '@') {                                // an exponent
               pt += 1;  glink (pt) = '@';  k = pt;
               readsym ();
               type = integer;  base = 10;
               if (sym == '-') {
                  readsym ();  get (10);  n = -n;
               } else {
                  get (10);
               }
               pt = k + 1;  glink (pt) = lp;  litpool[lp] = n;  lp += 1;
               if (base == 0) atom1 = error + 10;
               type = real;                                  // exponents force the type
            }

            if (type == real) {
               glink (strp) = (pt - strp);         // store the length (difference)
               subatom = strp | 0x2000;  strp = pt + 1;
            } else {
               litpool[lp] = n;
               lp += 1;
            }
            return;
            
          name:
            if ((27 <= target) && (target <= 41)) { atom1 = 0; return; }
            hashvalue = 0;
            
            // ABD changed to remove dependency on direct addressing
            dp = dmax + 1;
            dbase = dp;
            n = 0;
            dict[dp] = 0;
            for (;;) {
               hashvalue += (hashvalue + sym);                 // is this good enough?
               dict[dp] = dict[dp] | (sym << 8);
               n += 1;
               dp += 1;
               readsym ();
               if (symtype >= 0) break;
               dict[dp] = sym;
               n += 1;
               readsym ();
               if (symtype >= 0) break;
            }
            if (sym == cquote) {
               pendquote = 100;
               if (hashvalue == 'M') goto symbols;
               readsym ();
               if (hashvalue == 'X') { base = 16; goto bxk; }
               if ((hashvalue == 'K') || (hashvalue == 'O')) { base = 8; goto bxk; }
               if (hashvalue == 'B') { base = 2; goto bxk; }
               goto err;
            }
            dict[dbase] = dict[dbase] | n;
            if ((n & 1) == 0) dp += 1;
            if (dp >= dmin) abandon (8);
            
            atom2 = 90;                                           // ident
            if ((last1 == 0) && (sym == ':')) {                   // label
               limit = local; lookup (lab); return;
            }
            if (last1 == jump) {                                  // ->label
               limit = local;  lookup (lab + spec + usedbit);  return;
            }
            if ((decl != 0) && (target == 90)) {                  // identifier
               searchbase = fmbase;
               limit = local;  lookup (decl);
               searchbase = 0;
            } else {
               limit = 0;  lookup (0);
            }
         }

         auto int parsedmachinecode (void) { ENTER();
            // *opcode_??????????
            if (!(symtype == -2)) { atom1 = error; return (0); }  // starts with letter
            flushbuffer (128);                                    // flush if bp >= 128
            addchar ('w');
            for (;;) {
               addchar (sym); readsym ();
               if ((sym == '_') || (symtype == 0)) break;         // pull in letters and digits
            }
            addchar ('_');
            if (symtype != 0) {                                   // not terminator
               readsym ();
               while (symtype != 0) {
                  if (symtype < 0) {                              // complex
                     codeatom (0);  if ((atom1 & error) != 0) return (0);
                     if ((atom2 == _const_) && (type == integer)) {
                        if (subatom < 0) setconst (tag[-subatom].format); else setconst (litpool[subatom]);
                     } else if ((91 <= atom1) && (atom1 <= 109)) {
                        if ((atom1 == 104) && ((tag[subatom].flags & closed) == 0)) {
                           this = subatom;  atom1 = error + 21;
                           return (0);
                        }
                        op (' ', tag[subatom].index);
                     } else {
                        atom1 = error; return (0);
                     }
                  } else {
                     if (symtype == 2) sym = sym | 128;           // underline with %
                     addchar (sym); readsym ();
                  }
               }
            }
            addchar (';');
            return (1);
         }
         
         if (gg == 0) cont = ' ';
         last1 = 0; mapgg = 0;
         s = 0; ss = 0; sstype = -1; fdef = 0;
         fmbase = 0;
         app = 0;
         
         // deal with alignment following an error in one statement
         // of several on a line
         margin = column;                                         // start of statement
         pos = 0;
         strp = gmax + 1; lp = 0;
         tbase = tstart;                                          // ??????????????
         local = tbase;
         
         if (((gg == 0) || (ocount >= 0))) {                      // data or not continuation(z)
          again:
            while (symtype == 0) {                                // skip redundant terminators
               c = cont;
               cont = ' '; if (ocount >= 0) cont = '+';
               readsym ();
               cont = c;
            }
            if (sym == '!') goto skip;                            // comment
            this = -1;
            codeatom (0);
            if (atom1 == comment) {
             skip:
               quote = 1;
               c = cont;
               while (sym != nl) { readsym (); cont = c; }        // skip to end of line
               quote = 0;  symtype = 0;
               goto again;
            }
         }
         decl = 0; mark = 0;
         gentype = 0; force = 0;
         dim = 0; proterr = 0;
         node = 0; nmax = 0; nmin = recsize + 1;
         order = 1;  gmin = maxgrammar + 1;
         if (gg != 0) { sstype = 0; goto more; }                  // continuation
         ptype = 0;  specgiven = 0;
         
         stats += 1;  if (perm == 0) op ('O', lines);

         if ((atom1 & error) != 0) goto fail1;                    // first atom faulty

         if (escapeclass != 0) {                                  // enter the hard way after
            g = impphrase; sstype = -1; goto a3;
         }
         
         g = initial (atom1);                                     // pick up entry point
         if (g == 0) {                                            // invalid first atom
            g = initial (0);  sstype = 0;  goto a3;               // declarator?
         }
         if (g < 0) {                                             // phrase imp
            g = g & 255;
            nmax = 1;
            ar[1].class = 0; ar[1].link = 0; ar[1].sub = impphrase;
         }

         gg = gram (g); class = gg & 255; sstype = ((gg >> 12) & 3) - 1;
         goto a1;
         
       act_194:         /* 194 */
         ptype = type; papp = app; pformat = format;  goto more;
       act_196:         /* 196 */
         k = g + 1;  goto a610;
       act_188:         /* 188 */
         k = ar[nmax].sub + 1;
       a610:
         papp = glink (k);
         k = gram (k);
         if (k == 0) goto more;                                   // %name
         ptype = k & 7; pformat = k >> 3;
       act_183:         /* 183 */
         k = type;  if (((gentype == 0) || (k == real))) gentype = k;
         if (pformat < 0) {                                       // general type
            app = papp;  format = pformat;
            if (((ptype == real) && (type == integer))) k = real;
            if (force != 0) { k = force; force = 0; }
         }
         if (!((papp == app) && ((ptype == k) || (ptype == 0)))) goto fail2;
         if ((pformat == format) || (pformat == 0) || (format == 0)) goto more;
         goto fail2;
       act_197:         /* 197 */
         arp = &ar[nmin] /* Pointer assignment */ ;
         k = arp->sub;
         if (!(blockform == (k & 15))) goto fail3;
         arp->sub = k >> 4;
         
         type = blocktype;
         ptype = blocktype;  pformat = blockfm;  papp = app;
         if (ptype != record) pformat = -1;
         goto more;
       act_195:         /* 195 */
         if ((type != 0) && (type != integer) && (type != real)) goto fail2;
         arp = &ar[nmin] /* Pointer assignment */ ;
         k = arp->sub;
         arp->sub = k >> 2;
         k = k & 3;
                                                                // 1 = check integer
                                                                // 2 = check real
                                                                // 3 = check real + int
         if (k == 0) goto more;                                 // 0 = no action
         if (k == 1) {
            force = integer;
            if ((type == integer) || (type == 0)) goto more;
            goto fail2;
         }
         if (!((ptype == real) || (ptype == 0))) goto fail2;    // {or added?}
         if (k == 3) force = integer;
         goto more;
       act_198:         /* 198 */
         // %OTHER
         k = (gg >> 8) & 15;
         if (k == 0) {                                          // restore atom
            atom1 = last1;
            goto more;
         }
         if (k == 1) {                                          // test string
            if (!(type == stringv)) goto fail2;
            goto more;
         }
         if (k == 2) {                                          // {fault record comparisons}
            if (type == record) goto fail2;
            goto more;
         }
         if (k == 3) {                                          // check OWN variable coming
            codeatom (0);
            if ((atomflags & ownbit) == 0) goto a7;
            goto more;
         }
         if (x <= local) forwarn = pos1;                        // %for TEST
         goto more;
       paction_1:               /* 1 */
         if (type == record) g = phrase (242); else pformat = -1;  goto a3;
       paction_2:               /* 2 */
         ptype = real; pformat = -1;                               goto a3;
       paction_3:               /* 3 */
         ptype = stringv; pformat = -1;                            goto a3;
       paction_4:               /* 4 */
         ptype = integer; pformat = -1;                            goto a3;
       paction_5:               /* 5 */
         if (ptype == integer) goto a3;
         if (ptype == real) { g = phrase (212); pformat = -1; }
         if (ptype == stringv) g = phrase (213);
                                                                   goto a3;
       paction_6:               /* 6 */
         ptype = gram (ar[nmax].sub + 1) & 7; pformat = -1;        goto a3;
       paction_7:               /* 7 */
         if (ptype == integer) ptype = real; pformat = -1;         goto a3;
       a1:
         last1 = class; atom1 = 0; s = subatom;
       a2:
         if ((gg & transbit) == 0) {                        // insert into analysis record
            z = &node /* Pointer assignment */ ;
            for (;;) {                                      // insert cell in order
               k = *z;
               if (((gg & orderbits) == 0) || (k == 0)) break;
               gg -= orderbit; z = &ar[k].link /* Pointer assignment */ ;
            }
            if ((mapgg != 0) && ((gg & 255) == var)) gg = mapgg;
            nmin -= 1; if (nmin == nmax) goto fail0;
            *z = nmin;
            arp = &ar[nmin] /* Pointer assignment */ ;
            arp->sub = s; arp->class = (gg & 255) | mark;
            arp->link = k;
         }
         mark = 0; mapgg = 0;
       more:
         g = glink (g);                                    // chain down the grammar
       paction_0:               /* 0 */
       a3:
         gg = gram (g);  class = gg & 255;
         if ((diag & 1) != 0) traceanalysis ();
         if (class == 0) goto a5;                          // end of phrase
         if (class < actions) {                            // not a phrase or an action
            if (class >= figurative) class = atomic (class);
            if (class >= manifest) goto a2;
            if (atom1 == 0) codeatom (class);
            if (escapeclass != 0) {                        // escape to new grammar
               class = escapeclass; escapeclass = 0;
               g += escape;

               // note that following an escape the next item is
               // forced to be transparent!

             esc:
               gg = 0;
               arp = &ar[nmax + 1] /* Pointer assignment */ ;
               arp->papp = papp;  arp->x = x;  goto a4;
            }

            if ((class == atom1) || (class == atom2)) goto a1;

          a7:
            if (gg >= 0) goto fail1;                        // no alternative
            g += 1;
            goto a3;
         }
         
         if (class >= phrasal) {                            // a phrase
          a4:
            nmax += 1; if (nmax == nmin) goto fail0;
            arp = &ar[nmax] /* Pointer assignment */ ;
            arp->ptype = ptype;
            arp->pos = pos1;
            arp->pformat = pformat;
            arp->link = gentype;
            arp->class = node;
            arp->sub = g;
            node = 0;
            g = phrase (class);
            if (force != 0) { ptype = force; force = 0; }
            gentype = 0;
            goto *paction[(gg >> 8) & 15];
          paction_default:
            BADSWITCH((gg >> 8) & 15, __LINE__, __FILE__);
         }
         if ((class < actions) || (class > phrasal)) BADSWITCH(class, __LINE__, __FILE__);
         goto *act[class-actions];                          // only actions left
       act_default: BADSWITCH(class, __LINE__, __FILE__);

       a5:
         // REVERSE LINKS
         s = 0;
         while (node != 0) {
            z = &ar[node].link /* Pointer assignment */ ;
            k = *z; *z = s; s = node; node = k;
         }
         ss = s;
       a6:
         if (nmax != 0) {
            k = gentype;                                    // type of phrase
            arp = &ar[nmax] /* Pointer assignment */ ; nmax -= 1;
            node = arp->class;
            gentype = arp->link;
            ptype = arp->ptype;
            pformat = arp->pformat;
            g = arp->sub;
            if ((g & escape) != 0) {
               g -= escape;
               papp = arp->papp;
               mark = 255;
               subatom = s;
               goto a3;
            }
            if ((gentype == 0) || (k == real)) gentype = k;
            type = gentype;
            
            k = gg;                                          // exit-point code
            for (;;) {
               gg = gram (g);
               if (k == 0) goto a2;
               if (gg >= 0) goto fail1;                      // no alternative phrase
               k -= orderbit;
               g += 1;                                       // sideways step
            }
         }
         
         if (copy != 0) fault (4);
         if (order == 0) fault (13);
         if (forwarn != 0) fault (-4);
         pos1 = 0;
         faultrate -= 1;
         return;
         
       act_193:         /* 193 */
         if (!((sym == '=') || (sym == '<'))) { gg = 0; goto a5; }  // cdummy
       act_181:         /* 181 */
         atom1 = amap[decl & 15];                            // dummy
         goto more;

       act_182:         /* 182 */
         class = escdec; g = glink (g) | escape; // original Imp77 source had this looking like a comment!  Checking with others.
         decl = 0; otype = 0; goto esc; // decl

       act_199:         /* 199 */                            // COMPILE
         s = 0;
         while (node != 0) {
            z = &ar[node].link /* Pointer assignment */ ;
            k = *z; *z = s; s = node; node = k;
         }
         ss = s;
         
         if (quote != 0) codeatom (28);                      // expend
         compile (); if ((atom1 & error) == 0) goto more;
         goto fail1;
         
       act_184:         /* 184 */
         if (!(type == integer)) goto fail4;
         if (subatom < 0) lit = tag[-subatom].format; else lit = litpool[subatom];
         if (lit != 0) goto fail4;
         goto more;
       act_185:         /* 185 */                            // APPLYPARAMETERS
         s = 0;
         while (node != 0) {
            z = &ar[node].link /* Pointer assignment */ ;
            k = *z; *z = s; s = node; node = k;
         }
         ss = s;
         
         atom1 = ar[s].class; atom2 = 0;
         if ((atom1 == 97) || (atom1 == 98)) atom1 = var;
         arp = &ar[nmax] /* Pointer assignment */ ;
         x = arp->x;
         pos1 = arp->pos;
         pos2 = 0;
         app = 0;
         format = tag[x].format;
         flags = tag[x].flags;
         type = (flags >> 4) & 7;
         protection = flags & prot;
         if ((flags & aname) != 0) protection = 0;
         
         if (((flags & subname) != 0) && (format != 0)) {
            if (formatselected () == 0) goto fail1;
         }
         
         goto a6;
         
       act_187:         /* 187 */
         protection = prot; goto more;                       // %SETPROT
       act_186:         /* 186 */
         if ((protection & prot) == 0) goto more;
         proterr = nmin;
         goto a7;
       act_191:         /* 191 */
         k = protection;                                     // %GUARD
         codeatom (0);
         if ((atomflags & aname) == 0) protection = k;
         goto more;
         
       act_192:         /* 192 */
         if (parsedmachinecode () == 0) goto fail1;
         goto more;
         
       act_189:         /* 189 */
         k = gapp ();                                        // %GAPP
         deletenames (1);
         tmax = tbase; tbase = gram (gmin);                  // restore tmax
         local = tbase;
         gmin += 1;
         
         x = ar[ar[nmax].class].sub;
         tag[x].app = k;                                     // update app
         goto more;
         
       act_190:         /* 190 */
         gmin -= 1;                                          // %LOCAL
         if (gmin <= gmax) abandon (2);
         gram (gmin) = tbase; tbase = tmax;
         local = tbase;
         goto more;
         
         // errors
         
       fail4:    k = error + 10;            goto failed;         // *size
       fail3:    k = error + 7;             goto failed;         // *context
       fail2:    k = error + 5;  pos2 = 0;  goto failed;         // *type
       fail0:    k = error + 3;             goto failed;         // *too complex
       fail1:    k = atom1;      pos2 = 0;
       failed:
         if ((diag & 32) != 0) {
            int gtsaved = outstream;            selectoutput(0);
            printstring ("Atom1 =");        write (atom1, 3);  // A secondary issue is that shorts are not always converting to ints properly.
                                                               // Atom1 is displaying as 32769 instead of -32768 (0x8000 - error)
            printstring ("  Atom2 =");      write (atom2, 3);
            printstring ("  subatom =");    write (subatom, 3);     newline ();
            printstring ("Type =");         write (type, 1);
            printstring ("   Ptype =");     write (ptype, 1);       newline ();
            printstring ("App =");          write (app, 1);
            printstring ("   Papp =");      write (papp, 1);        newline ();
            printstring ("Format =");       write (format, 1);
            printstring ("   Pformat =");   write (pformat, 1);     newline ();
            selectoutput(gtsaved);
            signal_event(13,15,0);
         }

         while (((sym != nl) && (sym != ';'))) { quote = 0; readsym (); }
         if ((k & error) != 0) {
            fault (k & 255);
         } else {
            if (proterr == nmin) fault (14); else fault (0);
         }
         gg = 0; ss = 0; symtype = 0;
      }                                                    // of analyse
      
      auto void compile (void) { ENTER();
         static const int then = 4, else_ = 8, loop = 16;

         static const void *c[ actions+1 ] = {  // was 176, now 180+1 - need to examine this table closely
           &&c_0,        &&c_default,  &&c_default,  &&c_default,
           &&c_default,  &&c_default,  &&c_default,  &&c_default,
           &&c_default,  &&c_default,  &&c_default,  &&c_default,
           &&c_default,  &&c_default,  &&c_default,  &&c_default,
           &&c_default,  &&c_default,  &&c_default,  &&c_default,
           &&c_default,  &&c_default,  &&c_default,  &&c_default,
           &&c_default,  &&c_default,  &&c_default,  &&c_27,
           &&c_28,       &&c_29,       &&c_30,       &&c_31,
           &&c_32,       &&c_33,       &&c_34,       &&c_35,
           &&c_36,       &&c_37,       &&c_38,       &&c_39,
           &&c_default,  &&c_41,       &&c_42,       &&c_43,
           &&c_44,       &&c_45,       &&c_46,       &&c_47,
           &&c_48,       &&c_49,       &&c_50,       &&c_51,
           &&c_52,       &&c_53,       &&c_default,  &&c_55,
           &&c_56,       &&c_57,       &&c_58,       &&c_59,
           &&c_60,       &&c_default,  &&c_62,       &&c_63,
           &&c_64,       &&c_65,       &&c_default,  &&c_67,
           &&c_68,       &&c_69,       &&c_70,       &&c_71,
           &&c_72,       &&c_default,  &&c_74,       &&c_75,
           &&c_76,       &&c_77,       &&c_78,       &&c_79,
           &&c_80,       &&c_81,       &&c_82,       &&c_83,
           &&c_84,       &&c_85,       &&c_86,       &&c_87,
           &&c_88,       &&c_89,       &&c_90,       &&c_91,
           &&c_92,       &&c__const_,  &&c_default,  &&c_default,
           &&c_96,       &&c_97,       &&c_98,       &&c_99,
           &&c_100,      &&c_101,      &&c_102,      &&c_103,
           &&c_104,      &&c_swit,     &&c_106,      &&c_107,
           &&c_108,      &&c_109,      &&c_default,  &&c_default,
           &&c_default,  &&c_default,  &&c_default,  &&c_default,
           &&c_default,  &&c_default,  &&c_default,  &&c_default,
           &&c_120,      &&c_121,      &&c_122,      &&c_default,
           &&c_124,      &&c_125,      &&c_126,      &&c_127,
           &&c_128,      &&c_default,  &&c_130,      &&c_131,
           &&c_132,      &&c_133,      &&c_134,      &&c_135,
           &&c_136,      &&c_137,      &&c_138,      &&c_139,
           &&c_140,      &&c_141,      &&c_142,      &&c_143,
           &&c_144,      &&c_145,      &&c_146,      &&c_147,
           &&c_148,      &&c_149,      &&c_default,  &&c_151,
           &&c_152,      &&c_153,      &&c_154,      &&c_155,
           &&c_156,      &&c_157,      &&c_158,      &&c_159,
           &&c_160,      &&c_161,      &&c_162,      &&c_163,
           &&c_164,      &&c_165,      &&c_166,      &&c_167,
           &&c_168,      &&c_default,  &&c_170,      &&c_171,
           &&c_172,      &&c_173,      &&c_174,      &&c_175,
         };
         
         static const void *litop[ 13 ] = { // (1:12) - Rebased to 0 rather than 1 for efficiency
           &&litop_default, &&litop_1, &&litop_2, &&litop_3, &&litop_4, &&litop_5,
           &&litop_6, &&litop_7, &&litop_8, &&litop_9, &&litop_10, &&litop_11, &&litop_12, 
         };
         
         static const unsigned char operator[15] = {
           0, '[', ']', 'X', '/', '&', '!', '%', '+', '-', '*', 'Q', 'x', '.', 'v'
         };  // (1:14) - Rebased to 0 rather than 1 for efficiency
         static const unsigned char cc[8] = { '#','=',')','<','(','>', 'k','t' };
         static const unsigned char anyform[16] = { 1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1 };

         static const int decmap[16] = {
           1,             2,
           0x100B,   0x100D,    0x140C,    0x140E,
           3,             4,
           0x1007,   0x1008,    0x1009,    0x100A,
           6,             0,         0,         0
         };
         static unsigned char cnest[16];
         int lmode, clab, dupid;
         int resln;
         static int lastdef = 0;
         static int lb, ub;
         int cp, ord;
         int next, link, j, k, n;
#ifdef INCLUDE_UNUSED  // Either never written to, or written to but never read from
         int done;
#endif
         int class;
         int lit2, defs, decs, cident;
         int pending;
         static int pstack[40+1]; // (1:40) - Rebased to 0 rather than 1 for efficiency
         static char name[9] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
         static int count = 0;

         auto void deflab (int l) { ENTER();
            op (':', l);
            access = 1;
         }

         auto void getnext (void) { ENTER();
            arfm *p;
          gn:
            if (next == 0) {                               // end of phrase
               if (link == 0) { class = 0; return; }       // end of statement
               p = &ar[link] /* Pointer assignment */ ;
               next = p->link;
               link = p->sub;
            }
            for (;;) {
               p = &ar[next] /* Pointer assignment */ ;
               x = p->sub;
               class = p->class;
               if (class < actions) break;                 // an atom
               if (x == 0) {                               // null phrase
                  next = p->link; goto gn;
               }
               if (p->link != 0) {                         // follow a phrase
                  p->sub = link; link = next;
               }
               next = x;
            }
            next = p->link;
            if ((diag & 2) != 0) {
               if (!(*name == '\0')) spaces (8 - strlen (name));
               strncpy(name, text (class), 9);
               write (x, 2);
               space ();
               printstring (name);
               space ();
               count -= 1;
               if (count <= 0) {
                  count = 5;
                  name[0] = '\0';
                  newline ();
               }
            }
         }
         
         auto void setsubs (int n) { ENTER();
            // update the app field in n array descriptors
            int p;
            p = tmax;
            while (n > 0) {
               if (p < tbase) signal_event(15,15,0);
               tag[p].app = dimension;
               p -= 1; n -= 1;
            }
         }
         
         auto void setbp (void) { ENTER();
            // define a constant bound pair from the last stacked constants
            pending -= 2;
            lb = pstack[pending + 1]; ub = pstack[pending + 2];
            if (ub - lb + 1 < 0) {
               pos1 = 0; next = link; fault (11);
               ub = lb;
            }
            setconst (lb); setconst (ub);
            if (!(class == 146)) addchar ('b');
         }
         
         auto void compileend (int type) { ENTER();
            // type = 0:eof, 1:eop, 2:end
            if (access != 0) {
               open = 0;
               if (blockform > proc) fault (19);               // can reach end
            }
           
            while (dict[dmin] >= 0) {                          // finishes & repeats
               fault (17 + (dict[dmin] & 1));
               dmin += 1;
            }
            // /*delete names(0);*/
            addchar (';');
            if (type == 1) addchar (';');                      // endofprogram
            
            *bflags = *bflags | open;                          // show if it returns
            
            if ((blocktag != 0) && (level != 1)) deflab (0);   // for jump around
            if (type != 2) {                                   // eop, eof
               if (level != type) fault (16);                  // end missing
            } else {
               if (level == 0) {
                  fault (15);                                  // spurious end
               }
            }

            endmark = 11;                           // ******Mouses specific******
         }
         
         auto void def (int p) { ENTER();
            // dump a descriptor
            int t, f, type;
            tagfm *v;
            flushbuffer (1);                                   // flush if bp > 0
            defs += 1;
            v = &tag[p] /* Pointer assignment */ ;
            t = 0;
            if (!(v->index < 0)) {                             // no index for subnames
               if (v->index == 0) { id += 1; v->index = id; }
               lastdef = v->index;
               t = lastdef;
            }
            op ('$', t);
            printident (p, 1);                                 // output the name
            t = v->flags;
            type = t;
            if ((type & (7 << 4)) >= (6 << 4)) type = type & (~(7 << 4));  // routine & pred
            op (',', type & 0b1111111);                        // type & form
            f = v->format;
            if ((t & 0x70) == (record << 4)) f = tag[f].index;
            if (f < 0) f = v->index;
            op (',', f);                                       // format
            f = otype + ((t >> 4) & 0b1111000);
            if (class == 125) f = f | 8;                       // add spec from %DUP
            dim = v->app;                                      // dimension
            if (!((0 < dim) && (dim <= dimlimit))) dim = 0;
            op (',', f + (dim << 8));                          // otype & spec & prot
            if ((t & parameters) == 0) defs = 0;
            f = t & 15;
            if ((v->flags & spec) != 0) {
               if (!((3 <= f) && (f <= 10))) v->flags = v->flags & (~spec);
               ocount = -1;                                    // external specs have no constants
            }
            dimension = 0;
            if ((otype == 2) && ((f == 2) || (f == 12) || (f == 14))) {
               v->flags = v->flags - 1;                        // convert to simple
            }
         }
         
         auto void defslab (int n) { ENTER();
            // define a switch label, x defines the switch tag
            int p, l, b, w, bit;
            p = tag[x].format;                                 // pointer to table
            l = dict[p];                                       // lower bound
            if ((l <= n) && (n <= dict[p + 1])) {
               b = n - l;
               w = (b >> 4) + p;
               bit = 1 << (b & 15);
               if ((dict[w + 2] & bit) != 0) {                 // already set
                  if (pending != 0) fault (4);
                  return;
               }
               if (pending != 0) dict[w + 2] = dict[w + 2] | bit;
               setconst (n);
               op ('_', tag[x].index);
            } else {
               fault (12);
            }
            access = 1;
         }

         auto void call (void) { ENTER();
            tagfm *t;
            t = &tag[x] /* Pointer assignment */ ;
            op ('@', t->index);
            if ((t->flags & closed) != 0) access = 0;           // never comes back
            if (t->app == 0) addchar ('E');                     // no parameters
         }
         
         auto void popdef (void) { ENTER();
            setconst (pstack[pending]); pending -= 1;
         }
         
         auto void poplit (void) { ENTER();
            if (pending == 0) lit = 0; else {
               lit = pstack[pending]; pending -= 1;
            }
         }
         
         // conditions & jumps
         auto void push (int x) { ENTER();
            if ((cnest[cp] & 2) != x) {
               cnest[cp] = cnest[cp] | 1; x += 4;
            }
            if ((cnest[cp] & 1) != 0) clab += 1;
            cnest[cp + 1] = x; cp += 1;
         }
         
         auto void poplabel (int mode) { ENTER();
            lmode = dict[dmin];
            if ((lmode < 0) || ((lmode & 1) != mode)) {
               fault (mode + 8);
            } else {
               dmin += 1; _label_ -= 3;
            }
         }
         
         if (sstype < 0) {                                  // executable statement
            if (level == 0) {                               // outermost level
               fault (13);                                  // *order
            } else {
               if (access == 0) {
                  access = 1; fault (-1);                   // only a warning
               }
            }
         }

         if ((diag & 2) != 0) {
            if (sym != nl) newline ();
            printstring ("ss =");
            write (ss, 1);
            newline ();
            count = 5;
            name[0] = '\0';
         }
         
         next = ss;
         pending = 0; lmode = 0;
         link = 0; decs = 0;
         defs = 0; resln = 0;
#ifdef INCLUDE_UNUSED  // Either never written to, or written to but never read from
         done = 0;
#endif
         ord = level;
         if (this >= 0) ord = 1;                           // recordformat declarations
       c_0:                     /* 0 */
       top:
         if (next != link) {
            getnext ();
            if ((class > actions) || (class < 0)) BADSWITCH(class, __LINE__, __FILE__);
            goto *c[class];
      c_default:
            BADSWITCH(class, __LINE__, __FILE__);
         }

         // all done, tidy up declarations and jumps
         if (((diag & 2) != 0) && (count != 5)) newline ();

         if ((lmode & (loop | then | else_)) != 0) {        // pending labels and jumps
            if ((lmode & loop) != 0) op ('B', _label_ - 1); // repeat
            if ((lmode & then) != 0) deflab (_label_);      // entry from then
            if ((lmode & else_) != 0) deflab (_label_ - 1); // entry from else
         }
         
         if (decs == 0) return;
         if (atom1 != 0) { atom1 = error; return; }         // %integerroutine
         order = ord;
         decl = (decl & (~15)) + decmap[decl & 15];         // construct declarator flags
         atom1 = atoms[decl & 15];                          // generate class
         if (otype != 0) {                                  // own, const etc.
            if (atom1 != proc) atom1 += 1;
            if (otype == 2) {                               // const
               n = decl & 15;
               if ((n & 1) != 0) {
                  decl = decl | prot;
                  if ((decl & 0b1111111) == iform) decl = decl | constbit;
               }
            } else {
               decl = decl | ownbit;
            }
         }
         if (((sstype == 0) && (atom1 == proc))) sstype = 1;
         if ((decl & spec) != 0) atom1 += 1;                // onto spec variant
         if (atom1 == 5) { ocount = 0; cont = '+'; }        // own array
         if (anyform[decl & 15] == 0) {                     // check meaningful
            if (((decl >> 4) & 7) == record) {
              if ((tag[fdef].flags & spec) != 0) this = fdef;
               if (fdef == this) atom1 = error + 21;        // *context for format
            }
            if (fdef == 0) atom1 = error + 10;              // *size
         }
         return;
         
       atop:
         access = 0;   goto top;
         // declarators
       c_88:                    /* 88 */                    // RTYPE
       c_28:                    /* 28 */
         decl = x & (~7);                                   // stype
         fdef = x & 7;                                      // precision
         if ((x & 0b1110001) == ((real << 4) + 1)) fdef = realsln; // convert to long
         decs = 1;   goto top;
       c_34:                    /* 34 */                    // OWN
       c_35:                    /* 35 */
         otype = x; ord = 1;   goto top;                    // external
       c_152:                   /* 152 */
         decl = decl + (x << 1);   goto top;                // xname
       c_31:                    /* 31 */                    // PROC
       c_32:                    /* 32 */
         specmode = level + 1;                              // fn/map
         if (x == 9) decl = decl | prot;                    // function
       c_29:                    /* 29 */
         ord = 1;                                           // array
         dim = 0;
       c_30:                    /* 30 */
         decl += x;                                         // name
         decs = 1;
         goto top;
       c_27:                    /* 27 */
         lit = 0;                                           // arrayd
         if (pending != 0) {
            poplit ();
            if (!((0 < lit) && (lit <= dimlimit))) {
               atom1 = error + 11; return;
            }
         }
         dim = lit;
         decl += x; decs = 1;
         goto top;
       c_37:                    /* 37 */
         x = x | subname;                                   // record
       c_36:                    /* 36 */
         lit = 0;                                           // string
         if (pending != 0) {
            poplit ();
            if (!((0 < lit) && (lit <= 255))) {             // max length wrong
               atom1 = error + 10; return;
            }
         }
         fdef = lit;                                        // format or length
       c_33:                    /* 33 */
         decl = x;                                          // switch
         decs = 1;
         goto top;
       c_39:                    /* 39 */
         decl = decl | spec;                                // spec
         ocount = -1;                                       // no initialisation
         specmode = -1;
         goto top;
       c_38:                    /* 38 */
         decl = 64 + 4;                                     // recordformat (spec)
         order = 1;
         atom1 = x;
         if (atom1 == 12) decl = decl | spec;               // formatspec
         fdef = tmax + 1;                                   // format tag
         return;
       c_175:                   /* 175 */
         id += 1; tag[x].index = id; return;                // FSID
       c_41:                    /* 41 */
         decs = 1; decl = x | spec | closed;   goto top;    // label
       c_133:                   /* 133 */
         recid = 0; rbase = tmin - 1;                       // fname
         this = x;
         fmbase = fdef; formatlist = tmin;
         def (this);                           goto top;
       c_148:                   /* 148 */
         if (next == 0) { fdef = 0; goto top; }             // reclb
         getnext ();                                        // skip name
         fdef = x;
         goto top;
         
       c_127:                   /* 127 */
         addchar ('}');                     goto top;      // %POUT
       c_126:                   /* 126 */
         addchar ('{');                     goto top;      // %PIN
       c_174:                   /* 174 */
         setbp ();                                          // rangerb
       c_171:                   /* 171 */                   // FMLB
       c_172:                   /* 172 */                   // FMRB
       c_173:                   /* 173 */
         addchar ('~');
         addchar (class - 171 + 'A');       goto top;       // fmor
       c_168:                   /* 168 */
         rbase = -rbase;                                    // orrb
         sstype = 0; specmode = 0;
         
       c_147:                   /* 147 */
         searchbase = 0;                                    // recrb
         tag[this].app = tmin;
         tag[this].format = rbase;
         goto top;
         
       c_45:                    /* 45 */
         if (x == 36) addchar ('U');        goto top;       // sign
       c_46:                    /* 46 */
         addchar ('\\');                    goto top;       // uop
       c_47:                    /* 47 */                    // MOD
       c_48:                    /* 48 */                    // DOT
       c_42:                    /* 42 */                    // OP1
       c_43:                    /* 43 */                    // OP2
       c_44:                    /* 44 */
         addchar (operator[x]);             goto top;       // op3
       c_56:                    /* 56 */                    // AND
       c_57:                    /* 57 */
         push (x); goto top;                                // or
       c_58:                    /* 58 */
         cnest[cp] = cnest[cp] ^ 2;         goto top;       // not
       c_138:                   /* 138 */
         x = 128 + 32 + 16 + 4;                             // csep: treat like %while
       c_59:                    /* 59 */                    // WHILE
       c_60:                    /* 60 */
         if (class == 138) op ('f', _label_ - 1); else deflab (_label_ - 1); // until
       c_166:                   /* 166 */                   // RUNTIL
       c_62:                    /* 62 */
         lmode = (lmode & (else_ | loop)) | (x >> 3);       // cword
         clab = _label_; cp = 1; cnest[1] = x & 7;
         goto top;
       c_72:                    /* 72 */
         poplabel (0);                                      // repeat
         if ((lmode & 32) != 0) deflab (_label_ + 1); goto atop;
       c_69:                    /* 69 */
         poplabel (1);                       goto top;      // finish
       c_163:                   /* 163 */                   // XELSE
       c_70:                    /* 70 */
         poplabel (1);                                      // finish else ...
         if ((lmode & 3) == 3) fault (7);                   // dangling else
       c_68:                    /* 68 */
         lmode = (lmode & else_) | 3;                       // ...else...
         if (access != 0) {
            op ('F', _label_ - 1); lmode = else_ | 3;
         }
         deflab (_label_);
         if (next != 0) goto top;
       c_120:                   /* 120 */                   // mstart
       c_67:                    /* 67 */                    // START
       c_71:                    /* 71 */                    // CYCLE
       stcy:
         if (lmode == 0) { deflab (_label_ - 1); lmode = loop; }  // cycle
         dmin -= 1; if (dmin <= dmax) abandon (3);
         dict[dmin] = lmode;
         _label_ += 3;
         return;
         
       c_64:                    /* 64 */
         if (((dict[dmin] >= 0) || (inhibit != 0))) fault (13);  // on event
         inhibit = 1;
         n = 0;
         if (pending == 0) n = 0xFFFF;                      // * = all events
         while (pending > 0) {
            poplit (); if ((lit & (~15)) != 0) fault (10);  // too big
            j = 1 << lit;
            if ((n & j) != 0) dubious = 1;
            n = n | j;                                      // construct bit mask
         }
         op ('o', n); op (',', _label_);
         lmode = then | 1;  goto stcy;
         
       c_104:                   /* 104 */
         op ('J', tag[x].index);                            // l
         inhibit = 1;       goto atop;
       c_149:                   /* 149 */
         stats -= 1;                                        // lab
         access = 1; inhibit = 1;
         op ('L', tag[x].index);  goto top;
         
       c_63:                    /* 63 */
         j = dmin; l = _label_ - 3;                         // exit, continue
         for (;;) {
            if (dict[j] < 0) { fault (7); goto top; }
            if ((dict[j] & 1) == 0) break;
            j += 1; l -= 3;
         }
         if (x == 32) l += 1;                              // continue
         op ('F', l);
         dict[j] = dict[j] | x;                            // show given
         goto atop;

       c_50:                    /* 50 */
         addchar ('C');                   goto cop;        // acomp
       c_49:                    /* 49 */
         if (next != 0) {                                  // comparator
            addchar ('"');
            push (0);                                      // double sided
         } else {
            addchar ('?');
         }

       cop:
         if ((cnest[cp] & 2) != 0) x = x ^ 1;              // invert the condition
         j = cp; l = clab;
         while ((cnest[j] & 4) == 0) {
            j -= 1;
            l = l - (cnest[j] & 1);
         }
         op (cc[x], l);
         if ((cnest[cp] & 1) != 0) deflab (clab + 1);
         cp -= 1;
         clab = clab - (cnest[cp] & 1);
         goto top;
         
       c_78:                    /* 78 */                  // Freturn
       c_79:                    /* 79 */                  // Mreturn
       c_80:                    /* 80 */
         open = 0;                                        // return, true, false
       c_82:                    /* 82 */
         access = 0;                                      // stop
       c_89:                    /* 89 */                  // ADDOP
       c_81:                    /* 81 */
         addchar (x);                       goto top;     // monitor
       c_65:                    /* 65 */
         poplit (); op ('e', lit);          goto atop;    // signal
       c_51:                    /* 51 */
         addchar ('S');                     goto top;     // eq
       c_53:                    /* 53 */
         addchar ('j');                     goto top;     // jam transfer
       c_52:                    /* 52 */
         addchar ('Z');                     goto top;     // eqeq
       c_74:                    /* 74 */
         if (level == 0) {                                // begin
            if (progmode <= 0) progmode = 1; else fault (7);
            // {Permit BEGIN after external defs}
         }
         specmode = level + 1;
         blockx = 0;
         addchar ('H');
         return;
       c_77:                    /* 77 */
         perm = 0; lines = 0; stats = 0;                  // endofperm
         closeinput ();
         selectinput (source);
         list -= 1;
         tbase = tmax; tstart = tmax;
         return;
       c_76:                    /* 76 */
         if (((include != 0) && (x == 0))) {               // end of ...
            lines = include; sstype = 0;                   // include
            closeinput ();
            list = includelist;
            includelevel = 0;
            include = 0; selectinput (source); return;
         }
         ss = -1;                                         // prog/file
       c_75:                    /* 75 */
         compileend (x); return;                          // %end
       c_85:                    /* 85 */

         /*

This decode confirms that %diagnose only saves 16 bits to the icode file,
and that the 16 bits are present.  Currently pass2 is picking up 0 for the parameter

     7  %diagnose 16_FFFFFFFF

        LINE 7
        DIAG ffff

          */
         
         if (x == 0) {                                    // control
#ifdef INCLUDE_UNUSED  // Either never written to, or written to but never read from
            control = lit;
#endif
            // %control neither used here not passed on to pass2...
fprintf(stderr, "*NOT* setting %%control flag in icode to %08x\n", (unsigned int)lit);
         } else {
            if (((lit >> 14) & 3) == 1) diag = lit & 0x3FFF;
fprintf(stderr, "setting %%diagnose flag in icode to %08x\n", (unsigned int)lit);
         }
         op ('z' - x, lit);   // But it *is* passed on to pass2 which is a relief...
         goto top;
       c_83:                    /* 83 */
         list = list + x - 2;                goto top;    // %LIST/%endoflist
       c_84:                    /* 84 */
         realsln = x;                        goto top;    // %REALS long/normal
       c_86:                    /* 86 */
         if (include != 0) {                              // include "file"
            fault (7); return;
         }
         getnext ();                                      // sconst
         x -= 0x4000;
         j = glink (x);
         k = j & 255;
         // ABD - another little copy loop because SKIMP can't do the string map
         includefile[0] = '\0';
         for (;;) {
            k -= 1; if (k < 0) break;
            strcat (includefile, tostring (j >> 8)); // inefficient in C transation...
            x += 1;
            j = glink (x);
            k -= 1; if (k < 0) break;
            strcat (includefile, tostring (j & 255));
         }
         // include file = string(x-16_4000+stbase)
         // remove this event block for SKIMP or pre-event IMP versions
         {
           if (on_event(9)) {
             abandon (9);
           }
           openinput (3, includefile);
         }
         include = lines; lines = 0;
         includelist = list; includelevel = level;
         selectinput (3);
         goto top;
         
       c_154:                   /* 154 */
         dimension += 1;                                  // dbsep
         if (dimension == (dimlimit + 1)) fault (11);
         goto top;
       c_145:                   /* 145 */
         setbp ();                           goto top;   // crb
       c_146:                   /* 146 */
         setbp ();                                        // rcrb
       c_142:                   /* 142 */                 // BPLRB
         if (dimension == 0) dimension = 1;
         op ('d', dimension); op (',', defs);
         if (class != 146) {
            setsubs (defs);
            if ((dict[dmin] >= 0) || (inhibit != 0) || (level == 0)) fault (13);
         }
         dimension = 0; defs = 0;
         goto top;
       c_128:                   /* 128 */
         id = dupid;                         goto top;    // EDUP
       c_130:                   /* 130 */
         blockx = x;
         if ((((decl & spec) == 0) && (level != 0))) op ('F', 0);  // jump round proc
       c_125:                   /* 125 */
         dupid = id;                                       // %DUP
         if (level < 0) return;                            // {spec about}
       c_90:                    /* 90 */
         def (x);   goto top;                              // ident
       c_131:                   /* 131 */                  // CIDENT
         if ((tag[x].flags & (0b1111111 + constbit)) == (iform + constbit)) {
            tag[x].format = lit;
         } else {
            if (pending != 0) setconst (lit);
            def (x);
            op ('A', 1);
         }
         cident = x;
         goto top;
       c_124:                   /* 124 */
         if ((tag[cident].flags & prot) != 0) dubious = 1; // %DUBIOUS
         goto top;
       c_97:                    /* 97 */                   // F
       c_98:                    /* 98 */                   // M
       c_99:                    /* 99 */                   // P
       c_96:                    /* 96 */
         call ();   goto top;                              // r
       c_165:                   /* 165 */                  // NLAB
       c_100:                   /* 100 */                  // RP
       c_101:                   /* 101 */                  // FP
       c_102:                   /* 102 */                  // MP
       c_103:                   /* 103 */                  // PP
       c_91:                    /* 91 */                   // V
       c_92:                    /* 92 */                   // N
       c_106:                   /* 106 */                  // A
       c_107:                   /* 107 */                  // AN
       c_108:                   /* 108 */                  // NA
       c_109:                   /* 109 */                  // NAN
         k = tag[x].index;
         if (k < 0) op ('n', -k); else op ('@', k);
         goto top;
       c_121:                   /* 121 */
         setconst (0);                         goto top;   // special for zero
       c_167:                   /* 167 */
         addchar ('G');                        goto pstr;  // aconst (alias)
       c__const_:               /* _const_ */              // CONST
         if (x < 0) {                                      // constinteger
            setconst (tag[-x].format);         goto top;
         }
         if ((x & 0x4000) != 0) {                          // strings
            addchar ('\''); // addchar (39) would be safer given current bug in imp2c!
          pstr:
            x -= 0x4000;
            j = glink (x);
            k = j & 255;
            addchar (k);
            for (;;) {
               k -= 1; if (k < 0) goto top;
               addchar (j >> 8);
               x += 1;
               j = glink (x);
               k -= 1; if (k < 0) goto top;
               addchar (j & 255);
            }
         }
         if ((x & 0x2000) != 0) {                         // real - ABD also string-like, but NOT packed
            x -= 0x2000;
            k = glink (x);
            op ('D', k); addchar (',');
            for (;;) {
               if (k == 0) goto top;
               k -= 1;
               x += 1; j = glink (x);
               if (j == '@') {
                  op ('@', litpool[glink (x + 1)]); goto top;
               }
               addchar (j);
            }
         }
         setconst (litpool[x]);
         goto top;
         
       c_137:                   /* 137 */
         addchar ('i');                     goto top;    // asep
       c_141:                   /* 141 */
         addchar ('a');                     goto top;    // arb

         // own arrays
       c_132:                   /* 132 */
         ocount = ub - lb + 1;
         def (x);                                         // oident
         dimension = 1; setsubs (1);
         if (next == 0) {                                 // no initialisation
            if (ocount > 0) op ('A', ocount);
            ocount = -1;
         } else {                                         // initialisation given
            getnext ();
         }
         goto top;
       c_162:                   /* 162 */
         lit = ocount; goto ins;                          // indef
       c_143:                   /* 143 */
         poplit ();                                       // orb
       ins:
         if (lit < 0) { fault (10); lit = 0; }
         getnext ();
         goto inst;
       c_139:                   /* 139 */                 // OSEP(X=19)
       c_153:                   /* 153 */
         lit = 1;
       inst:
         if (pending != 0) popdef ();                     // ownt (x=0)
         op ('A', lit);
         ocount -= lit;
         if (ocount >= 0) {
            if (x != 0) goto top;                         // more coming
            if (ocount == 0) { ocount = -1; return; }     // all done
         }
         fault (11); return;

       c_swit:                  /* swit */
         op ('W', tag[x].index); inhibit = 1; goto atop;
       c_134:                   /* 134 */
         def (x);                                         // swid
         n = ub - lb + 1;
         n = (n + 15) >> 4;                               // slots needed (includes zero)
         j = dmax; dmax = dmax + n + 2;
         if (dmax >= dmin) abandon (1);
         tag[x].format = j;
         dict[j] = lb;
         dict[j + 1] = ub;
         for (;;) {
            n -= 1;
            if (n < 0) goto top;
            j += 1; dict[j + 1] = 0;
         }
       c_151:                   /* 151 */
         stats -= 1;                                      // slab
         if (x < tbase) { fault (7); return; }
         if (pending != 0) {                              // explicit label
            defslab (pstack[1]);
         } else {
            if (tag[x].app != 0) { fault (4); return; }
            tag[x].app = 1;
            n = tag[x].format;
            for (j = dict[n]; j <= dict[n + 1]; j += 1) {
               defslab (j);
               flushbuffer (128);                        // flush if bp >= 128
            }
         }
         inhibit = 1;
         return;
         
       c_140:                   /* 140 */
         addchar ('p');                      goto top;   // psep
       c_144:                   /* 144 */                // PRB
         addchar ('p');
         addchar ('E');                      goto top;
         
         // constant expressions
       c_155:                   /* 155 */                // PCONST
         if (x < 0) lit = tag[-x].format; else lit = litpool[x];
         pending += 1; pstack[pending] = lit; goto top;
       c_156:                   /* 156 */
         lit = pstack[pending]; if (lit < 0) lit = -lit;
         pstack[pending] = lit;  goto top;               // cmod
       c_157:                   /* 157 */
         lit = -pstack[pending]; pstack[pending] = lit; goto top;  // csign
       c_158:                   /* 158 */
         lit = ~pstack[pending]; pstack[pending] = lit; goto top;  // cuop
       c_159:                   /* 159 */                // COP1
       c_160:                   /* 160 */                // COP2
       c_161:                   /* 161 */
         pending -= 1;                                   // cop3
         lit2 = pstack[pending + 1];  lit = pstack[pending];
         if (((x >> 2) < 1) || ((x >> 2) > 12)) BADSWITCH(x >> 2, __LINE__, __FILE__);
         goto *litop[x >> 2];
      litop_default:
         BADSWITCH(x >> 2, __LINE__, __FILE__);

      litop_1:          /* 1 */
         lit = lit << lit2;           goto setl;
       litop_2:         /* 2 */
         lit = (unsigned int)lit >> (unsigned int)lit2;           goto setl;
       litop_3:         /* 3 */
         n = 1;                                          // lit = lit\\lit2
         if (lit2 < 0) fault (10);
         while (lit2 > 0) {
            lit2 -= 1;
            n = n * lit;
         }
         lit = n;                     goto setl;
       litop_4:         /* 4 */
         if (lit2 == 0) fault (10); else lit = ((int) (lit) / (int) (lit2));
                                      goto setl;
       litop_5:         /* 5 */
         lit = lit & lit2;            goto setl;
       litop_6:         /* 6 */
         lit = lit | lit2;            goto setl;
       litop_7:         /* 7 */
         lit = lit ^ lit2;            goto setl;
       litop_8:         /* 8 */
         lit += lit2;                 goto setl;
       litop_9:         /* 9 */
         lit -= lit2;                 goto setl;
       litop_10:                /* 10 */
         lit = lit * lit2;            goto setl;
       litop_11:                /* 11 */
         lit += lit2;                 goto setl;
       litop_12:                /* 12 */
         n = 1;                                          // lit = lit\\lit2
         if (lit2 < 0) fault (10);
         while (lit2 > 0) {
            lit2 -= 1;
            n = n * lit;
         }
         lit = n;                     goto setl;
       setl:
         pstack[pending] = lit;       goto top;
         
       c_170:                   /* 170 */
         // Fault(4) %if IMPCOM_Option # ""
         // IMPCOM_Option = String(x-x'4000'+Stbase); ! Option string
         goto top;
         
         // string resolution
       c_135:                   /* 135 */
         resln = 2;                   goto top;           // dotl
       c_136:                   /* 136 */
         resln += 1;                  goto top;           // dotr
       c_55:                    /* 55 */
         op ('r', resln);  resln = 0; goto top;           // resop
       c_164:                   /* 164 */
         op ('r', resln + 4); resln = 0;                  // cresop
       c_122:                   /* 122 */
         x = 6;                       goto cop;           // %PRED
       c_87:                    /* 87 */
         setconst (pstack[1]);                            // mass
         { bp += 1; buff[bp] = 'P'; } goto top;
      }
      
   }                                                  // of compile block

   if (on_event(9)) {
     abandon (5);
   }

   selectoutput(0);
   
   if (argc != 3) {
     fprintf(stderr, "pass1: parameters should be source.imp,stdperm.imp  source.icd,source.lis\n");
     exit(1);
   }
   
   // *Temporary* new code for C/Linux:
   {// i77p1 $1,$INCDIR/stdperm.imp $SRCNAME.icd,$LISTFILE
     char *source = strdup(argv[1]);
     char *perm = strchr(source, ',');
     char *icode = strdup(argv[2]);
     char *list = strchr(icode, ',');

     if (perm == NULL) {
       fprintf(stderr, "pass1: first parameter should be source.imp,stdperm.imp\n");
       exit(1);
     }
     *perm++ = '\0';
     if (!openinput(1, source)) {       // source
       fprintf(stderr, "pass1: could not open source file \"%s\"\n", source);
       exit(1);           
     }
     if (!openinput(2, perm)) {         // prims+perms
       fprintf(stderr, "pass1: could not open prims+perms file \"%s\"\n", perm);
       exit(1);           
     }

     if (list == NULL) {
       fprintf(stderr, "pass1: second parameter should be source.icd,source.lis\n");
       exit(1);
     }
     *list++ = '\0';
     //openoutput(0, "/dev/stderr"); // console report - shouldn't in and out 0 already be stdin/stdout?
     if (!openoutput(1, icode)) {       // object
       fprintf(stderr, "pass1: could not open object (icode) file \"%s\"\n", icode);
       exit(1);           
     }
     if (!openoutput(2, list)) {        // listing
       fprintf(stderr, "pass1: could not open listing file \"%s\"\n", list);
       exit(1);           
     }
   }
   
   selectinput (2);
   selectoutput (listing);

   // Initialise entire record to 0:  Note NULL is not necessarily represented by 0.
   // which could be a (miniscule) problem if using this in the Imp to C translator,
   // but in this case, tagfm records contain no pointers so this is extremely safe.

   // btw although assigning 0 to a struct is not supported in this C, assigning
   // one struct to another struct (not pointers but the actual data) *is* supported
   // and indeed is used in this translation.

   // So an alternative to using memset to zero a struct would be to declare a
   // const struct with __zero_## attached to it, and explicitly assign zero to
   // each of the fields in the declaration, then assign that struct when 0 is asked for.
   
   memset(&tag[maxtag], 0, sizeof(tag[maxtag]));          // %begin defn
   memset(&tag[0], 0, sizeof(tag[0]));
   
   tag[0].flags = 7;                                      // %begin tag!
   for (x = 0; x <= maxnames; x += 1) hash[x] = 0;
   printstring ("         Edinburgh IMP77 Compiler - Version ");
   // printstring(" Preston IMP2020 Compiler - Version ")
   printstring ((char *)version);
   newlines (2);
   op ('l', 0);
   compileblock (0, 0, maxdict, 0, 0);
   addchar (nl);                                          // {for bouncing off}
   flushbuffer (0);                                       // flush if bp >= 0

   x = listing;
   newline ();
   for (;;) {
      if (faulty == 0) {
         write (stats, 5);
         printstring (" Statements compiled");
      } else {
         printstring (" Program contains ");
         write (faulty, 1);
         printstring (" fault");
         if (!(faulty == 1)) printsymbol ('s');
      }
      newline ();
      if (x == report) break;
      x = report;
      selectoutput (report);
   }
   if (faulty != 0) exit (0);                             // try to flag to shell that we failed

}