/* EPC Imp to C Translation Release 4 Version Apr 95 */

#include "imptoc.h"

/*!This version of ECCE, derived from a paper copy believed to */
/*!date from 1975, removes PDP9/15 machine code, and other */
/*!IMP9/15 system dependencies, and I'm hopeful that as a result */
/*!it might well work if compiled with a generic Imp compiler. */

/*!RWT Feb 2002 */

/*!Code slightly rearranged to fit the model of Peter Stephen's Imp to C */
/*!translator.  This now compiles and runs exactly as on the pdp9/15 */
/*!Remember to run it with redirected input, eg ecce < file.txt > file2.txt */

/*!The I/O library currently assumes you are running on Unix. */
/*!NOTE: There IS a bug in this implementation.  Lines of more */
/*!than 120 characters have a newline inserted at the 120th character */
/*!on output.  This *may* be an original bug rather than an artifact */
/*!of the translation or run-time library.. */

/*!GT 02 Mar 2002 */

int outstream;

static int in = 1;		/* current input stream */

#define min 1			/* main input stream */
#define mout 1			/* main output stream */
#define sin 2			/* secondary input stream */
#define sextra 122		/* extra buff for sin */
#define size 30000		/* of edit buffer (bytes) */
static int mon = 0;		/* monitor indic */
static int print1 = 0;
static int print2 = 0;		/* print indicators */

#define stop (-5000)		/* loop stop (const) */
int i, j, k, pp1, sym;
int code;			/* command code letter */
int text;			/* text pointer */
int num;			/* repetition number */
int *mainfp;			/* == fp or mfp (for sin) */

#define cbase 1
#define tbase 120
static int c[tbase - (cbase) + 1];	/* command -> <- text */

/* each command unit -- letter, parenthesis or comma -- is */
/* represented by a trio:  code(+lim)  text  num */
/* in the case of parentheses and commas 'text' is a pointer */
/* to another command unit (not to a text string) */
int ci;				/* command index (ad) */
int ti;				/* text index (ad) */
static int cmax = 0;		/* command max (ad) */
int stored[192 + 1];		/* defs of x,y,z */
static int pos1 = 0;
static int pos2 = 0;
static int pos3 = 0;
unsigned char byte[size + 1];
static int top = 2;		/* top of buff (index) */
static int bot = size - sextra;	/* bottom of buff (index) */
int lbeg;			/* line start (index) */
int pp;				/* previous pointer (index) */
static int fp = 0;		/* file pointer (index) */
int lend;			/* line end (index) */
static int fend;		/* end of file in buff (index) */
static int ms = 0;		/* match start (index) */
static int ml = 0;		/* match limit (index) */

/* significance of file pointers: */
/* [nl] o n e nl t w . . . o nl n e x t nl . . nl l a s t nl [nl] */
/*      !        !   !     !  !                                ! */
/*      t        l   p     f  l                                f */
/*      o        b   p     p  e                                e */
/*      p        e            n                                n */
/*               g            d                                d */

int type, chain;		/* command input vars */
static int pend = 0;		/* ditto */

static void prompt (char *s)
{				/* Emulating pdp9/15 routine */
   int oldstream, c;

   c = s[1 - 1];
   if (c != 0) {
/* c = 0 is supposed to flush output on the 9/15 */
      oldstream = outstream;
      selectoutput (0);
      fprintf (out_file, "%c", c);
      selectoutput (oldstream);
   }
}

static void loadpp (int k)
{				/* !!also increments pp */
   byte[pp] = k;
   pp++;
}

static void loadfp (int k)
{
   byte[fp] = k;
}

static void leftstar ()
{
   for (;;) {
      if (pp == lbeg)
	 return;
      fp--;
      pp--;
      loadfp (byte[pp]);
   }
}

static void rightstar ()
{
   for (;;) {
      if (fp == lend)
	 return;
      loadpp (byte[fp]);
      fp++;
   }
}

static int symtype[95 - 32] =
{64, 3, 3, 3, 2, 3, 3, 11,
 9, 64, 3, 12, 2, 3, 3, 0,
 0, 0, 0, 0, 0, 0, 0, 0,
 0, 3, 1, 3, 3, 3, 64, 3,
 2, 10, 18, 5, 8, 52, 10, 2,
 6, 10, 10, 10, 56, 2, 2, 10,
 50, 10, 22, 5, 5, 6, 2, 32,
 32, 32, 3, 10, 3, 3, 3};

/*     !  "  #  $  %  &  '  (  )  *  +  ,  -  .  / */
/*  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  [  \  ]  ^  _ */

static void readsym ()
{
   if (pend != 0) {
      sym = pend;
      pend = 0;
   } else {
      while (pos3 != 0) {
	 sym = stored[pos3];
	 pos3++;
	 if (sym != nl)
	    return;
	 pos3 = pos2;
	 pos2 = pos1;
	 pos1 = 0;
      }
      sym = fgetc (in_file);
   }
}

static void readitem ()
{
   type = 1;
   for (;;) {
      do
	 readsym ();
      while (sym == ' ');
      if (sym < 32)
	 return;		/* nl */
      if (sym >= 96)
	 sym -= 32;		/* ensure upper case */
      type = symtype[sym - 33];
      if ((type & 15) != 0)
	 return;
      if (type != 32)
	 break;
      pos1 = pos2;
      pos2 = pos3;
      pos3 = ((sym - 'X') << 6) + 1;
   }
   if (type == 0) {
      num = sym - '0';
      for (;;) {
	 pend = fgetc (in_file);
	 if (('0' > pend) || (pend > '9'))
	    break;
	 num = ((((num << 2) + num) << 1) - '0') + pend;
      }
   } else {
      type = 0;
      num = 0;
      if (sym == '*')
	 return;
      num = stop + 1;
      if (sym == '?')
	 return;
      num = stop;		/* '!' */
   }
}

static void unchain ()
{
   do {
      text = chain;
      if (text == 0)
	 return;
      chain = c[text + 1 - (cbase)];
      c[text + 1 - (cbase)] = ci;
   } while (c[text - (cbase)] != 'X');
}

static void stack (int v)
{
   c[ci - (cbase)] = v;
   ci++;
}

static void makespace ()
{
int k, p1, p2;

   if (((*mainfp - pp) - 240) > 0)
      return;
   selectoutput (mout);
   p1 = top;
   p2 = (unsigned) (p1 + lbeg) >> 1;	/* output about half */
   if (code == 'C')
      p2 = lbeg;		/* but all if closing */
   if (p2 == top) {
      assert (_IMP_MONITOR_);
      exit (0);
   }				/* !!logical error */
   do {
      k = byte[p1];
      fprintf (out_file, "%c", k);
      p1++;
   } while (k != nl || (p1 - p2) < 0);
   selectoutput (0);
   lbeg = (top + lbeg) - p1;
   p2 = pp;
   pp = top;
   for (;;) {
      if (p1 == p2)
	 return;
      loadpp (byte[p1]);
      p1++;
   }
}

static void readline ()
{
int k;

/*    %ON %EVENT 9 %START */
/*       ->eof */
/*    %FINISH */
   if (fp != fend) {
      lend = fp;
      while (byte[lend] != nl)
	 lend++;
      return;
   }
   ms = 0;
   print1 = 0;
   print2 = 0;
   selectinput (in);
   fp = (bot - sextra) + 1;
   do {
      if (fp != bot)
	 k = fgetc (in_file);
      else
	 k = nl;
      if (k < 0)
	 goto eof;
      loadfp (k);
      fp++;
   } while (k != nl);
   fend = fp;
   lend = fend - 1;
   fp = (bot - sextra) + 1;
   selectinput (0);
   return;
 eof:
   fp = bot;
   lend = fp;
   fend = lend;
   loadfp (nl);
   selectinput (0);
}

static void switchinputs ()
{
static int mfp;
static int mlend;
static int mend;
static int sfp;
static int send;

   if (in == min) {
      leftstar ();
      in = sin;
      mfp = fp;
      mlend = lend;
      mend = fend;
      mainfp = &mfp;
      bot += sextra;
      fp = sfp;
      fend = send;
      readline ();
   } else {
      pp = lbeg;
      in = min;
      bot -= sextra;
      sfp = fp;
      send = fend;
      fp = mfp;
      lend = mlend;
      fend = mend;
      mainfp = &fp;
   }
}

static void printline ()
{
int p;

   print1 = lend;
   print2 = fp + pp;
   p = lbeg;
   for (;;) {
      if (p == pp) {
	 if (p != lbeg && num == 0)
	    fprintf (out_file, "%c", '^');
	 p = fp;
      }
      if (p == lend)
	 break;
      fprintf (out_file, "%c", byte[p]);
      p++;
   }
   if (p == fend)
      fprintf (out_file, "%s", "**END**");
   fprintf (out_file, "%s", "\n");
}

static int matched ()
{
int i, j, k, l, t1, fp1, lim;

   lim = c[ci - 3 - (cbase)] & (~127);
   t1 = c[text - (cbase)];
 l1:
   pp1 = pp;
   fp1 = fp;
   if (fp != ms || (code != 'F' && code != 'U'))
      goto l3;
   k = byte[fp];
 l2:
   loadpp (k);
   fp++;
 l3:
   if (fp == lend)
      goto l10;
   k = byte[fp];
   if (k != t1)
      goto l2;
   i = fp;
   j = text;
 l6:
   i++;
   j--;
   l = c[j - (cbase)];
   if (byte[i] == l)
      goto l6;
   if (l != 0)
      goto l2;
   ms = fp;
   ml = i;
   return 1;
 l10:
   lim -= 128;
   if (lim != 0 && fp != fend) {
      if (code != 'U') {
	 loadpp (nl);
	 lbeg = pp;
      } else
	 pp = pp1;
      fp++;
      makespace ();
      readline ();
      goto l1;
   }
   pp = pp1;
   fp = fp1;
   return 0;
}

int main ()
{				/* edit15: ecce for pdp9/15 */
/*initialise */
int t_value;
int t_line;
char *t_file;
int s_value;
int s_line;
char *s_file;

/*%ON %EVENT 9 %START */
/*    printstring("Caught event"); newline */
/*    ->eof */
/*%FINISH */

   selectinput (0);
   pp = top - 1;
   loadpp (nl);			/* for bouncing off */
   lbeg = pp;
   mainfp = &fp;
   stored[1] = nl;
   stored[65] = nl;
   stored[129] = nl;
   selectoutput (0);
   fprintf (out_file, "%s", "EDIT\n");
   readline ();

/*read command line */

 l1:
   prompt (">");
   readitem ();
   if (sym < 0)
      goto eof;
   if (type == 1)
      goto l1;
   ci = cbase;
   ti = tbase;
   chain = 0;
   if (type == 0 && cmax != 0) {
      c[cmax + 2 - (cbase)] = num;
      readitem ();
      if (type != 1)
	 goto er2;
      goto go;
   }
   if (sym == '%') {
      readsym ();
      if (sym >= 96)
	 sym -= 32;
      code = sym;
      if (code <= 32)
	 goto er5;
      readitem ();
      {
	 t_value = (unsigned) symtype[code - 33] >> 4;
	 t_line = __LINE__;
	 t_file = __FILE__;
	 goto t_despatch;
      }
   }
 l2:
   i = type & 15;
   if (i < 4)
      goto er2;
   code = sym;
   text = 0;
   num = 1;			/* default values */
   readitem ();
   {
      t_value = i;
      t_line = __LINE__;
      t_file = __FILE__;
      goto t_despatch;
   }
 t_2:
   /* %X, %Y, %Z */
   if (sym != '=')
      goto er1;
   i = (code - 'X') << 6;
   for (;;) {
      readsym ();
      i++;
      stored[i] = sym;
      if (sym == nl)
	 goto l1;
   }
 t_3:
   /* %M, %F, %Q */
   mon = 'M' - code;
   goto l1;
 t_4:
   /* find */
   if (type != 0)
      num = 0;
 t_5:
   /* +del,trav,uncover */
   code += num << 7;
   num = 1;
   if (type == 0)
      readitem ();
 t_6:
   /* +insert,subst,verify */
   if (type != 3)
      goto er4;
   text = ti;
   i = sym;
 l61:
   readsym ();
   if (sym != nl) {
      if (sym != i) {
	 if (ti <= ci)
	    goto er6;
	 c[ti - (cbase)] = sym;
	 ti--;
	 goto l61;
      }
   } else {
      pend = sym;
      if (code != 'S' && code != 'I')
	 goto er4;
   }
   if (ti == text && code != 'S')
      goto er4;
   c[ti - (cbase)] = 0;
   ti--;
   goto l81;
 t_8:
   /* move,erase */
   if (sym != '-')
      goto l100;
   code += 10;
 l81:
   readitem ();
   goto l101;
 t_9:
   /* close bracket */
   unchain ();
   if (text == 0)
      goto er3;
   code = 'Z';
   c[text + 2 - (cbase)] = num;
   text += 3;
 t_10:
   /* +get,kill,etc. */
 l100:
   if (type == 3)
      goto er1;
 l101:
   if (type == 0)
      readitem ();
   goto put;
 t_11:
   /* open bracket */
   code = 'X';
   goto l121;
 t_12:
   /* comma */
   code = 'Y';
   if (type == 1)
      readitem ();
 l121:
   text = chain;
   chain = ci;
   num = 0;
 put:
   stack (code);
   stack (text);
   stack (num);
   if ((ci + 4) >= ti)
      goto er6;
   if (type != 1)
      goto l2;
   unchain ();
   if (text != 0)
      goto er3;
   cmax = ci;
   stack ('Z');
   stack (cbase);
   stack (1);			/* extra close b */
   stack (0);
   goto go;

/*command input error reports */

 er1:
   fprintf (out_file, "%s", " ");
   fprintf (out_file, "%c", code);
 er2:
   code = sym;
   goto er5;
 er3:
   fprintf (out_file, "%s", " ()");
   goto er7;
 er4:
   fprintf (out_file, "%s", " TEXT FOR");
 t_0:

 er5:
   fprintf (out_file, "%s", " ");
   fprintf (out_file, "%c", code & 127);
   goto er7;
 er6:
   fprintf (out_file, "%s", " SIZE");
 er7:
   fprintf (out_file, "%c", '?');
   fprintf (out_file, "%s", "\n");
   if (ci != cbase)
      cmax = 0;
 l10:
   if (sym < 32)
      goto l1;
   readsym ();
   goto l10;

/*execute command line */

 go:
   ci = cbase;
 get:
   code = c[ci - (cbase)] & 127;
   if (code == 0)
      goto l99;
   text = c[ci + 1 - (cbase)];
   num = c[ci + 2 - (cbase)];
   ci += 3;
 rep:
   num--;
   {
      s_value = code;
      s_line = __LINE__;
      s_file = __FILE__;
      goto s_despatch;
   }
 ok:
   if (num != 0 && num != stop)
      goto rep;
   goto get;
 s_92:
   /* invert */
 no:
   if (num < 0)
      goto get;
   if (c[ci - (cbase)] == '\\') {
      ci += 3;
      goto get;
   }
 skp:
   i = c[ci - (cbase)];
   if (i == 'X')
      ci = c[ci + 1 - (cbase)];
   ci += 3;
   if (i > 'X') {
      num = c[ci - 1 - (cbase)] - 1;
      goto no;
   }
   if (i != 0)
      goto skp;

/*execution error report */

   fprintf (out_file, "%s", "FAILURE: ");
   if (code == 'O' || code == 'W') {
      fprintf (out_file, "%c", code - 10);
      code = '-';
   }
   fprintf (out_file, "%c", code);
   if (text != 0) {
      fprintf (out_file, "%c", '\'');
      while (c[text - (cbase)] != 0) {
	 fprintf (out_file, "%c", c[text - (cbase)]);
	 text--;
      }
      fprintf (out_file, "%c", '\'');
   }
   fprintf (out_file, "%s", "\n");
   print1 = 0;

/*end of command line */

 l99:
   if (sym != nl)
      goto l1;
   if ((mon < 0 || print1 == lend) && (mon <= 0 || print2 == (fp + pp)))
      goto l1;
   num = 0;
   printline ();
   goto l1;

/*individual commands */

 s_88:
   /* open bracket */
   c[text + 2 - (cbase)] = num + 1;
   goto get;
 s_90:
   /* close bracket */
   if (num == 0 || num == stop)
      goto get;
   c[ci - 1 - (cbase)] = num;
 s_89:
   /* +comma */
   ci = text;
   goto get;
 s_82:
   /* right shift */
   if (fp == lend)
      goto no;
   loadpp (byte[fp]);
   fp++;
   goto ok;
 s_76:
   /* left shift */
   if (in == sin || pp == lbeg)
      goto no;
   fp--;
   pp--;
   loadfp (byte[pp]);
   ms = 0;
   goto ok;
 s_69:
   /* erase */
   if (fp == lend)
      goto no;
   fp++;
   goto ok;
 s_79:
   /* erase back */
   if (pp == lbeg)
      goto no;
   pp--;
   goto ok;
 s_86:
   /* verify */
   i = fp - 1;
   j = text + 1;
 v1:
   i++;
   j--;
   k = c[j - (cbase)];
   if (byte[i] == k)
      goto v1;
   if (k != 0)
      goto no;
   ms = fp;
   ml = i;
   goto ok;
 s_70:
   /* find */
   if (matched () == 0)
      goto no;
   goto ok;
 s_85:
   /* uncover */
   if (matched () == 0)
      goto no;
   pp = pp1;
   goto ok;
 s_68:
   /* delete */
   if (matched () == 0)
      goto no;
   fp = ml;
   goto ok;
 s_84:
   /* traverse */
   if (matched () == 0)
      goto no;
 s_83:
   /* +substitute */
   if (fp == ms)
      fp = ml;
 s_73:
   /* +insert */
   makespace ();
/*!  ->no %IF pp-lbeg+lend-fp > 80 */
   i = text;
 i1:
   if (c[i - (cbase)] == 0)
      goto ok;
   loadpp (c[i - (cbase)]);
   i--;
   goto i1;
 s_71:
   /* get (line from tt) */
   prompt (":");
/*!  make space */
   i = fgetc (in_file);
   if (i == ':')
      goto no;
   leftstar ();
   while (i != nl) {
      loadpp (i);
      i = fgetc (in_file);
   }
 s_66:
   /* +break (insert newline) */
   makespace ();
   loadpp (nl);
   lbeg = pp;
   goto ok;
 s_80:
   /* print */
   printline ();
   if (num == 0)
      goto get;
 s_77:
   /* +move */
   rightstar ();
   if (fp == fend)
      goto no;
   loadpp (nl);
   lbeg = pp;
 m1:
   fp++;
   makespace ();
   readline ();
   goto ok;
 s_75:
   /* kill (line) */
   pp = lbeg;
   fp = lend;
 k1:
   if (fp == fend)
      goto no;
   goto m1;
 s_74:
   /* join (delete newline) */
   rightstar ();
/*!  ->no %IF pp-lbeg > 80 */
   goto k1;
 s_87:
   /* move back */
   if (in == sin)
      goto no;
   makespace ();
   if (lbeg == top)
      goto no;
   lend = ((fp - pp) + lbeg) - 1;
 w1:
   k = byte[pp - 1];
   if (k == nl && pp != lbeg)
      goto w2;
   fp--;
   pp--;
   loadfp (k);
   goto w1;
 w2:
   lbeg = pp;
   ms = 0;
   goto ok;
 t_1:
   /* %S, %C ... */
   if (code == 'C')
      goto eof;
   switchinputs ();
   goto l99;
 eof:
   code = 'C';			/* +eof on command stream */
   if (in == sin)
      switchinputs ();
   for (;;) {
      rightstar ();
      if (fp == fend)
	 break;
      loadpp (nl);
      lbeg = pp;
      fp++;
      makespace ();
      readline ();
   }
   selectoutput (mout);
   while (top != pp) {
      fprintf (out_file, "%c", byte[top]);
      top++;
   }
   selectoutput (0);
   if (code != 'C')
      assert (_IMP_MONITOR_);
   goto s_skip;
 s_despatch:
   switch (s_value) {
   case '\\':
      goto s_92;
   case 'X':
      goto s_88;
   case 'Z':
      goto s_90;
   case 'Y':
      goto s_89;
   case 'R':
      goto s_82;
   case 'L':
      goto s_76;
   case 'E':
      goto s_69;
   case 'O':
      goto s_79;
   case 'V':
      goto s_86;
   case 'F':
      goto s_70;
   case 'U':
      goto s_85;
   case 'D':
      goto s_68;
   case 'T':
      goto s_84;
   case 'S':
      goto s_83;
   case 'I':
      goto s_73;
   case 'G':
      goto s_71;
   case 'B':
      goto s_66;
   case 'P':
      goto s_80;
   case 'M':
      goto s_77;
   case 'K':
      goto s_75;
   case 'J':
      goto s_74;
   case 'W':
      goto s_87;
   default:
      BADSWITCH (s_value, s_line, s_file);
   }
 s_skip:;
   goto t_skip;
 t_despatch:
   switch (t_value) {
   case 2:
      goto t_2;
   case 3:
      goto t_3;
   case 4:
      goto t_4;
   case 5:
      goto t_5;
   case 6:
      goto t_6;
   case 8:
      goto t_8;
   case 9:
      goto t_9;
   case 10:
      goto t_10;
   case 11:
      goto t_11;
   case 12:
      goto t_12;
   case 0:
      goto t_0;
   case 1:
      goto t_1;
   default:
      BADSWITCH (t_value, t_line, t_file);
   }
 t_skip:;
}

/* end of automatic translation */