BSD 3 development
authorBill Joy <wnj@ucbvax.Berkeley.EDU>
Sat, 20 Oct 1979 11:16:11 +0000 (03:16 -0800)
committerBill Joy <wnj@ucbvax.Berkeley.EDU>
Sat, 20 Oct 1979 11:16:11 +0000 (03:16 -0800)
Work on file usr/src/cmd/pxp/pp.c
Work on file usr/src/cmd/pxp/error.c
Work on file usr/src/cmd/pxp/printf.c
Work on file usr/src/cmd/pxp/nl.c
Work on file usr/src/cmd/pxp/yyput.c
Work on file usr/src/cmd/pxp/yyrecover.c
Work on file usr/src/cmd/pxp/yymain.c

Synthesized-from: 3bsd

usr/src/cmd/pxp/error.c [new file with mode: 0644]
usr/src/cmd/pxp/nl.c [new file with mode: 0644]
usr/src/cmd/pxp/pp.c [new file with mode: 0644]
usr/src/cmd/pxp/printf.c [new file with mode: 0644]
usr/src/cmd/pxp/yymain.c [new file with mode: 0644]
usr/src/cmd/pxp/yyput.c [new file with mode: 0644]
usr/src/cmd/pxp/yyrecover.c [new file with mode: 0644]

diff --git a/usr/src/cmd/pxp/error.c b/usr/src/cmd/pxp/error.c
new file mode 100644 (file)
index 0000000..9b8eb80
--- /dev/null
@@ -0,0 +1,131 @@
+/* Copyright (c) 1979 Regents of the University of California */
+/*
+ * pi - Pascal interpreter code translator
+ *
+ * Charles Haley, Bill Joy UCB
+ * Version 1.2 January 1979
+ *
+ *
+ * pxp - Pascal execution profiler
+ *
+ * Bill Joy UCB
+ * Version 1.2 January 1979
+ */
+
+#include "0.h"
+#include "yy.h"
+
+#ifdef PXP
+extern int yyline;
+extern char errout;
+#endif
+
+char   errpfx  'E';
+extern int yyline;
+/*
+ * Panic is called when impossible
+ * (supposedly, anyways) situations
+ * are encountered.
+#ifdef PI
+ * Panic messages should be short
+ * as they do not go to the message
+ * file.
+#endif
+ */
+panic(s)
+       char *s;
+{
+
+#ifdef DEBUG
+       fprintf(stderr, "Snark (%s) line=%d yyline=%d\n", s, line, yyline);
+#endif
+#ifdef PXP
+       Perror( "Snark in pxp", s);
+#endif
+#ifdef PI
+       Perror( "Snark in pi", s);
+#endif
+       pexit(DIED);
+}
+
+extern char *errfile;
+/*
+ * Error is called for
+ * semantic errors and
+ * prints the error and
+ * a line number.
+ */
+error(a1, a2, a3, a4)
+{
+#ifdef PI
+       char buf[256];
+       register int i;
+#endif
+#ifdef PXP
+/*
+       int ofout;
+*/
+#endif
+
+       if (errpfx == 'w' && opt('w') != 0)
+               return;
+#ifdef PXP
+/*
+       flush();
+       ofout = fout[0];
+       fout[0] = errout;
+*/
+#endif
+#ifdef PI
+       Enocascade = 0;
+       geterr(a1, buf);
+       a1 = buf;
+#endif
+       if (line < 0)
+               line = -line;
+       yySsync();
+       yysetfile(filename);
+#ifdef PI
+       if (errpfx == ' ') {
+               printf("  ");
+               for (i = line; i >= 10; i =/ 10)
+                       putchar(' ');
+               printf("... ");
+       } else if (Enoline)
+               printf("  %c - ", errpfx);
+       else
+#endif
+               fprintf(stderr, "%c %d - ", errpfx, line);
+       fprintf(stderr, a1, a2, a3, a4);
+       if (errpfx == 'E')
+#ifdef PI
+               eflg++, cgenflg++;
+#endif
+#ifdef PXP
+               eflg++;
+#endif
+       errpfx = 'E';
+#ifdef PI
+       if (Eholdnl)
+               Eholdnl = 0;
+       else
+#endif
+               putc('\n', stderr);
+#ifdef PXP
+/*
+       flush();
+       fout[0] = ofout;
+*/
+#endif
+}
+
+#ifdef PI
+cerror(a1, a2, a3, a4)
+{
+
+       if (Enocascade)
+               return;
+       setpfx(' ');
+       error(a1, a2, a3, a4);
+}
+#endif
diff --git a/usr/src/cmd/pxp/nl.c b/usr/src/cmd/pxp/nl.c
new file mode 100644 (file)
index 0000000..4f632df
--- /dev/null
@@ -0,0 +1,690 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+/*
+ * pi - Pascal interpreter code translator
+ *
+ * Charles Haley, Bill Joy UCB
+ * Version 1.2 January 1979
+ */
+
+#include "0.h"
+#include "opcode.h"
+
+#ifdef PI
+/*
+ * Array of information about pre-defined, block 0 symbols.
+ */
+int    *biltins[] {
+
+       /*
+        * Types
+        */
+       "boolean",
+       "char",
+       "integer",
+       "real",
+       "_nil",         /* dummy name */
+       0,
+
+       /*
+        * Ranges
+        */
+       TINT,           0177777, 0177600, 0, 0177,
+       TINT,           0177777, 0100000, 0, 077777,
+       TINT,           0100000, 0, 077777, 0177777,
+       TCHAR,          0, 0, 0, 127,
+       TBOOL,          0, 0, 0, 1,
+       TDOUBLE,        0, 0, 0, 0,             /* fake for reals */
+       0,
+
+       /*
+        * Built-in composite types
+        */
+       "Boolean",
+       "intset",
+       "alfa",
+       "text",
+       "input", 
+       "output", 
+
+       /*
+        * Built-in constants
+        */
+       "true",         TBOOL,  1, 0,
+       "false",        TBOOL,  0, 0,
+       "minchar",      T1CHAR, 0, 0,
+       "maxchar",      T1CHAR, 0177, 0,
+       "bell",         T1CHAR, 07, 0,
+       "tab",          T1CHAR, 011, 0,
+       "minint",       T4INT,  0100000, 0,             /* Must be last 2! */
+       "maxint",       T4INT,  077777, 0177777,
+       0,
+
+       /*
+        * Built-in functions
+        */
+#ifndef PI0
+       "abs",          O_ABS2,
+       "arctan",       O_ATAN,
+       "card",         O_CARD|NSTAND,
+       "chr",          O_CHR2,
+       "clock",        O_CLCK|NSTAND,
+       "cos",          O_COS,
+       "eof",          O_EOF,
+       "eoln",         O_EOLN,
+       "eos",          0,
+       "exp",          O_EXP,
+       "expo",         O_EXPO|NSTAND,
+       "ln",           O_LN,
+       "odd",          O_ODD2,
+       "ord",          O_ORD2,
+       "pred",         O_PRED2,
+       "round",        O_ROUND,
+       "sin",          O_SIN,
+       "sqr",          O_SQR2,
+       "sqrt",         O_SQRT,
+       "succ",         O_SUCC2,
+       "trunc",        O_TRUNC,
+       "undefined",    O_UNDEF|NSTAND,
+       /*
+        * Extensions
+        */
+       "argc",         O_ARGC|NSTAND,
+       "random",       O_RANDOM|NSTAND,
+       "seed",         O_SEED|NSTAND,
+       "wallclock",    O_WCLCK|NSTAND,
+       "sysclock",     O_SCLCK|NSTAND,
+       0,
+
+       /*
+        * Built-in procedures
+        */
+       "date",         O_DATE|NSTAND,
+       "flush",        O_FLUSH|NSTAND,
+       "get",          O_GET,
+       "getseg",       0,
+       "halt",         O_HALT|NSTAND,
+       "linelimit",    O_LLIMIT|NSTAND,
+       "message",      O_MESSAGE|NSTAND,
+       "new",          O_NEW,
+       "pack",         O_PACK,
+       "page",         O_PAGE,
+       "put",          O_PUT,
+       "putseg",       0,
+       "read",         O_READ4,
+       "readln",       O_READLN,
+       "remove",       O_REMOVE|NSTAND,
+       "reset",        O_RESET,
+       "rewrite",      O_REWRITE,
+       "time",         O_TIME|NSTAND,
+       "unpack",       O_UNPACK,
+       "write",        O_WRIT2,
+       "writeln",      O_WRITLN,
+       /*
+        * Extensions
+        */
+       "argv",         O_ARGV|NSTAND,
+       "null",         O_NULL|NSTAND,
+       "stlimit",      O_STLIM|NSTAND,
+       0,
+#else
+       "abs",
+       "arctan",
+       "card",
+       "chr",
+       "clock",
+       "cos",
+       "eof",
+       "eoln",
+       "eos",
+       "exp",
+       "expo",
+       "ln",
+       "odd",
+       "ord",
+       "pred",
+       "round",
+       "sin",
+       "sqr",
+       "sqrt",
+       "succ",
+       "trunc",
+       "undefined",
+       /*
+        * Extensions
+        */
+       "argc",
+       "random",
+       "seed",
+       "wallclock",
+       "sysclock",
+       0,
+
+       /*
+        * Built-in procedures
+        */
+       "date",
+       "flush",
+       "get",
+       "getseg",
+       "halt",
+       "linelimit",
+       "message",
+       "new",
+       "pack",
+       "page",
+       "put",
+       "putseg",
+       "read",
+       "readln",
+       "remove",
+       "reset",
+       "rewrite",
+       "time",
+       "unpack",
+       "write",
+       "writeln",
+       /*
+        * Extensions
+        */
+       "argv",
+       "null",
+       "stlimit",
+       0,
+#endif
+};
+\f
+/*
+ * NAMELIST SEGMENT DEFINITIONS
+ */
+struct nls {
+       struct nl *nls_low;
+       struct nl *nls_high;
+} ntab[MAXNL], *nlact;
+
+struct nl nl[INL];
+struct nl *nlp nl;
+struct nls *nlact ntab;
+/*
+ * Initnl initializes the first namelist segment and then
+ * uses the array biltins to initialize the name list for
+ * block 0.
+ */
+initnl()
+{
+       register int *q;
+       register struct nl *p;
+       register int i;
+
+#ifdef DEBUG
+       if (hp21mx) {
+               MININT = -32768.;
+               MAXINT = 32767.;
+#ifndef PI0
+               genmx();
+#endif
+       }
+#endif
+       ntab[0].nls_low = nl;
+       ntab[0].nls_high = &nl[INL];
+       defnl(0, 0, 0, 0);
+       /*
+        * Fundamental types
+        */
+       for (q = biltins; *q != 0; q++)
+               hdefnl(*q, TYPE, nlp, 0);
+       q++;
+
+       /*
+        * Ranges
+        */
+       while (*q) {
+               p = defnl(0, RANGE, nl+*q, 0);
+               nl[*q++].type = p;
+               for (i = 0; i < 4; i++)
+                       p->value[i] = *q++;
+       }
+       q++;
+
+#ifdef DEBUG
+       if (hp21mx) {
+               nl[T4INT].range[0] = MININT;
+               nl[T4INT].range[1] = MAXINT;
+       }
+#endif
+
+       /*
+        * Pre-defined composite types
+        */
+       hdefnl(*q++, TYPE, nl+T1BOOL, 0);
+       enter(defnl((intset = *q++), TYPE, nlp+1, 0));
+       defnl(0, SET, nlp+1, 0);
+       defnl(0, RANGE, nl+TINT, 0)->value[3] = 127;
+     p=        defnl(0, RANGE, nl+TINT, 0);
+       p->value[1] = 1;
+       p->value[3] = 10;
+       defnl(0, ARRAY, nl+T1CHAR, 1)->chain = p;
+       hdefnl(*q++, TYPE, nlp-1, 0);   /* "alfa" */
+       hdefnl(*q++, TYPE, nlp+1, 0);   /* "text" */
+     p=        defnl(0, FILE, nl+T1CHAR, 0);
+       p->nl_flags =| NFILES;
+#ifndef PI0
+       input = hdefnl(*q++, VAR, p, -2);       /* "input" */
+       output = hdefnl(*q++, VAR, p, -4);      /* "output" */
+#else
+       input = hdefnl(*q++, VAR, p, 0);        /* "input" */
+       output = hdefnl(*q++, VAR, p, 0);       /* "output" */
+#endif
+
+       /*
+        * Pre-defined constants
+        */
+       for (; *q; q =+ 4)
+               hdefnl(q[0], CONST, nl+q[1], q[2])->value[1] = q[3];
+
+#ifdef DEBUG
+       if (hp21mx) {
+               nlp[-2].range[0] = MININT;
+               nlp[-1].range[0] = MAXINT;
+       }
+#endif
+
+       /*
+        * Built-in procedures and functions
+        */
+#ifndef PI0
+       for (q++; *q; q =+ 2)
+               hdefnl(q[0], FUNC, 0, q[1]);
+       for (q++; *q; q =+ 2)
+               hdefnl(q[0], PROC, 0, q[1]);
+#else
+       for (q++; *q;)
+               hdefnl(*q++, FUNC, 0, 0);
+       for (q++; *q;)
+               hdefnl(*q++, PROC, 0, 0);
+#endif
+}
+
+hdefnl(sym, cls, typ, val)
+{
+       register struct nl *p;
+
+#ifndef PI1
+       if (sym)
+               hash(sym, 0);
+#endif
+       p = defnl(sym, cls, typ, val);
+       if (sym)
+               enter(p);
+       return (p);
+}
+
+/*
+ * Free up the name list segments
+ * at the end of a statement/proc/func
+ * All segments are freed down to the one in which
+ * p points.
+ */
+nlfree(p)
+       struct nl *p;
+{
+
+       nlp = p;
+       while (nlact->nls_low > nlp || nlact->nls_high < nlp) {
+               free(nlact->nls_low);
+               nlact->nls_low = NIL;
+               nlact->nls_high = NIL;
+               --nlact;
+               if (nlact < &ntab[0])
+                       panic("nlfree");
+       }
+}
+#endif
+\f
+char   VARIABLE[]      "variable";
+
+char   *classes[] {
+       "undefined",
+       "constant",
+       "type",
+       VARIABLE,
+       "array",
+       "pointer or file",
+       "record",
+       "field",
+       "procedure",
+       "function",
+       VARIABLE,
+       VARIABLE,
+       "pointer",
+       "file",
+       "set",
+       "subrange",
+       "label",
+       "withptr",
+       "scalar",
+       "string",
+       "program",
+       "improper",
+#ifdef DEBUG
+       "variant",
+#endif
+};
+
+char   snark[] "SNARK";
+
+#ifdef PI
+#ifdef DEBUG
+char   *ctext[]
+{
+       "BADUSE",
+       "CONST",
+       "TYPE",
+       "VAR",
+       "ARRAY",
+       "PTRFILE",
+       "RECORD",
+       "FIELD",
+       "PROC",
+       "FUNC",
+       "FVAR",
+       "REF",
+       "PTR",
+       "FILE",
+       "SET",
+       "RANGE",
+       "LABEL",
+       "WITHPTR",
+       "SCAL",
+       "STR",
+       "PROG",
+       "IMPROPER",
+       "VARNT"
+};
+
+char   *stars  "\t***";
+
+/*
+ * Dump the namelist from the
+ * current nlp down to 'to'.
+ * All the namelist is dumped if
+ * to is NIL.
+ */
+dumpnl(to, rout)
+       struct nl *to;
+{
+       register struct nl *p;
+       register int j;
+       struct nls *nlsp;
+       int i, v, head;
+
+       if (opt('y') == 0)
+               return;
+       if (to != NIL)
+               printf("\n\"%s\" Block=%d\n", rout, cbn);
+       nlsp = nlact;
+       head = NIL;
+       for (p = nlp; p != to;) {
+               if (p == nlsp->nls_low) {
+                       if (nlsp == &ntab[0])
+                               break;
+                       nlsp--;
+                       p = nlsp->nls_high;
+               }
+               p--;
+               if (head == NIL) {
+                       printf("\tName\tClass  Bn+Flags\tType\tVal\tChn\n");
+                       head++;
+               }
+               printf("%3d:", nloff(p));
+               if (p->symbol)
+                       printf("\t%.7s", p->symbol);
+               else
+                       printf(stars);
+               if (p->class)
+                       printf("\t%s", ctext[p->class]);
+               else
+                       printf(stars);
+               if (p->nl_flags) {
+                       putchar('\t');
+                       if (p->nl_flags & 037)
+                               printf("%d ", p->nl_flags & 037);
+#ifndef PI0
+                       if (p->nl_flags & NMOD)
+                               putchar('M');
+                       if (p->nl_flags & NUSED)
+                               putchar('U');
+#endif
+                       if (p->nl_flags & NFILES)
+                               putchar('F');
+               } else
+                       printf(stars);
+               if (p->type)
+                       printf("\t[%d]", nloff(p->type));
+               else
+                       printf(stars);
+               v = p->value[0];
+               switch (p->class) {
+                       case TYPE:
+                               break;
+                       case VARNT:
+                               goto con;
+                       case CONST:
+                               switch (nloff(p->type)) {
+                                       default:
+                                               printf("\t%d", v);
+                                               break;
+                                       case TDOUBLE:
+                                               printf("\t%f", p->real);
+                                               break;
+                                       case TINT:
+con:
+                                               printf("\t%ld", p->range[0]);
+                                               break;
+                                       case TSTR:
+                                               printf("\t'%s'", v);
+                                               break;
+                                       }
+                               break;
+                       case VAR:
+                       case REF:
+                       case WITHPTR:
+                               printf("\t%d,%d", cbn, v);
+                               break;
+                       case SCAL:
+                       case RANGE:
+                               printf("\t%ld..%ld", p->range[0], p->range[1]);
+                               break;
+                       case RECORD:
+                               printf("\t%d(%d)", v, p->value[NL_FLDSZ]);
+                               break;
+                       case FIELD:
+                               printf("\t%d", v);
+                               break;
+                       case STR:
+                               printf("\t\"%s\"", p->value[1]);
+                               goto casedef;
+                       case FVAR:
+                       case FUNC:
+                       case PROC:
+                       case PROG:
+                               if (cbn == 0) {
+                                       printf("\t<%o>", p->value[0] & 0377);
+#ifndef PI0
+                                       if (p->value[0] & NSTAND)
+                                               printf("\tNSTAND");
+#endif
+                                       break;
+                               }
+                               v = p->value[1];
+                       default:
+casedef:
+                               if (v)
+                                       printf("\t<%d>", v);
+                               else
+                                       printf(stars);
+               }
+               if (p->chain)
+                       printf("\t[%d]", nloff(p->chain));
+               switch (p->class) {
+                       case RECORD:
+                               if (p->value[NL_VARNT])
+                                       printf("\tVARNT=[%d]", nloff(p->value[NL_VARNT]));
+                               if (p->value[NL_TAG])
+                                       printf(" TAG=[%d]", nloff(p->value[NL_TAG]));
+                               break;
+                       case VARNT:
+                               printf("\tVTOREC=[%d]", nloff(p->value[NL_VTOREC]));
+                               break;
+               }
+               putchar('\n');
+       }
+       if (head == 0)
+               printf("\tNo entries\n");
+}
+#endif
+
+\f
+/*
+ * Define a new name list entry
+ * with initial symbol, class, type
+ * and value[0] as given.  A new name
+ * list segment is allocated to hold
+ * the next name list slot if necessary.
+ */
+defnl(sym, cls, typ, val)
+       char *sym;
+       int cls;
+       struct nl *typ;
+       int val;
+{
+       register struct nl *p;
+       register int *q, i;
+       char *cp;
+
+       p = nlp;
+
+       /*
+        * Zero out this entry
+        */
+       q = p;
+       i = (sizeof *p)/2;
+       do
+               *q++ = 0;
+       while (--i);
+
+       /*
+        * Insert the values
+        */
+       p->symbol = sym;
+       p->class = cls;
+       p->type = typ;
+       p->nl_block = cbn;
+       p->value[0] = val;
+
+       /*
+        * Insure that the next namelist
+        * entry actually exists. This is
+        * really not needed here, it would
+        * suffice to do it at entry if we
+        * need the slot.  It is done this
+        * way because, historically, nlp
+        * always pointed at the next namelist
+        * slot.
+        */
+       nlp++;
+       if (nlp >= nlact->nls_high) {
+               i = NLINC;
+               cp = alloc(NLINC * sizeof *nlp);
+               if (cp == -1) {
+                       i = NLINC / 2;
+                       cp = alloc((NLINC / 2) * sizeof *nlp);
+               }
+               if (cp == -1) {
+                       error("Ran out of memory (defnl)");
+                       pexit(DIED);
+               }
+               nlact++;
+               if (nlact >= &ntab[MAXNL]) {
+                       error("Ran out of name list tables");
+                       pexit(DIED);
+               }
+               nlp = cp;
+               nlact->nls_low = nlp;
+               nlact->nls_high = nlact->nls_low + i;
+       }
+       return (p);
+}
+
+/*
+ * Make a duplicate of the argument
+ * namelist entry for, e.g., type
+ * declarations of the form 'type a = b'
+ * and array indicies.
+ */
+nlcopy(p)
+       struct nl *p;
+{
+       register int *p1, *p2, i;
+
+       p1 = p;
+       p = p2 = defnl(0, 0, 0, 0);
+       i = (sizeof *p)/2;
+       do
+               *p2++ = *p1++;
+       while (--i);
+       return (p);
+}
+
+/*
+ * Compute a namelist offset
+ */
+nloff(p)
+       struct nl *p;
+{
+
+       return (p - nl);
+}
+\f
+/*
+ * Enter a symbol into the block
+ * symbol table.  Symbols are hashed
+ * 64 ways based on low 6 bits of the
+ * character pointer into the string
+ * table.
+ */
+enter(np)
+       struct nl *np;
+{
+       register struct nl *rp, *hp;
+       register struct nl *p;
+       int i;
+
+       rp = np;
+       if (rp == NIL)
+               return (NIL);
+#ifndef PI1
+       if (cbn > 0)
+               if (rp->symbol == input->symbol || rp->symbol == output->symbol)
+                       error("Pre-defined files input and output must not be redefined");
+#endif
+       i = rp->symbol;
+       i =& 077;
+       hp = disptab[i];
+       if (rp->class != BADUSE && rp->class != FIELD)
+       for (p = hp; p != NIL && (p->nl_block & 037) == cbn; p = p->nl_next)
+               if (p->symbol == rp->symbol && p->class != BADUSE && p->class != FIELD) {
+#ifndef PI1
+                       error("%s is already defined in this block", rp->symbol);
+#endif
+                       break;
+
+               }
+       rp->nl_next = hp;
+       disptab[i] = rp;
+       return (rp);
+}
+#endif
+
+double MININT          -2147483648.;
+double MAXINT          2147483647.;
diff --git a/usr/src/cmd/pxp/pp.c b/usr/src/cmd/pxp/pp.c
new file mode 100644 (file)
index 0000000..f68de0d
--- /dev/null
@@ -0,0 +1,384 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+/*
+ * pxp - Pascal execution profiler
+ *
+ * Bill Joy UCB
+ * Version 1.2 January 1979
+ */
+
+#include "0.h"
+
+#define noprint() nopflg
+
+int    pplev[3];       /* STAT, DECL, PRFN */
+int    nopflg;
+
+setprint()
+{
+
+       if (profile == 0) {
+               if (table)
+                       nopflg = 1;
+               else
+                       nopflg = 0;
+               return;
+       }
+       nopflg = !all && nowcnt() == 0 || !opt('z');
+}
+
+printon()
+{
+
+       if (profile == 0) {
+               if (table)
+                       nopflg = 1;
+               return;
+       }
+       nopflg = 0;
+}
+
+printoff()
+{
+
+       nopflg = 1;
+}
+
+ppkw(s)
+       register char *s;
+{
+       register char *cp, i;
+
+       if (noprint())
+               return;
+       /*
+        * First real thing printed
+        * is always a keyword
+        * or includes an "id" (if a comment)
+        * (See ppnl below)
+        */
+       hadsome = 1;
+       if (underline) {
+               for (cp = s; *cp; cp++)
+                       putchar('_');
+               for (cp = s; *cp; cp++)
+                       putchar('\b');
+       }
+       printf(s);
+}
+
+ppid(s)
+       register char *s;
+{
+
+       if (noprint())
+               return;
+       hadsome = 1;
+       if (s == NIL)
+               s = "{identifier}";
+       printf(s);
+}
+
+ppbra(s)
+       char *s;
+{
+
+       if (noprint())
+               return;
+       if (s != NIL)
+               printf(s);
+}
+
+ppsep(s)
+       char *s;
+{
+
+       if (noprint())
+               return;
+       printf(s);
+}
+
+ppket(s)
+       char *s;
+{
+
+       if (noprint())
+               return;
+       if (s != NIL)
+               printf(s);
+}
+
+char   killsp;
+
+ppunspac()
+{
+
+       killsp = 1;
+}
+
+ppspac()
+{
+
+       if (killsp) {
+               killsp = 0;
+               return;
+       }
+       if (noprint())
+               return;
+       putchar(' ');
+}
+
+ppitem()
+{
+
+       if (noprint())
+               return;
+       ppnl();
+       indent();
+}
+
+int    owenl, owenlb;
+
+ppsnlb()
+{
+
+       if (nopflg)
+               return;
+       owenlb++;
+}
+
+ppsnl()
+{
+
+       if (nopflg)
+               return;
+       owenl++;
+}
+
+pppay()
+{
+
+       while (owenl || owenlb) {
+               putchar('\n');
+               if (owenlb) {
+                       putchar(' ');
+                       owenlb--;
+               } else
+                       owenl--;
+       }
+}
+
+ppnl()
+{
+
+       if (noprint())
+               return;
+       if (hadsome == 0)
+               return;
+       pppay();
+       putchar('\n');
+}
+
+indent()
+{
+       register i;
+
+       if (noprint())
+               return;
+       linopr();
+       if (profile == 0) {
+               indent1(pplev[PRFN] + pplev[DECL] + pplev[STAT]);
+               return;
+       }
+       indent1(pplev[PRFN] + pplev[STAT]);
+       switch (i = shudpcnt()) {
+               case 1:
+                       printf("%7.7ld.", nowcnt());
+                       dashes('-');
+                       putchar('|');
+                       break;
+               case 0:
+               case -1:
+                       printf("        ");
+                       dashes(' ');
+                       putchar(i == 0 ? '|' : ' ');
+                       break;
+       }
+       indent1(pplev[DECL]);
+}
+
+dashes(c)
+       char c;
+{
+       register i;
+
+       for (i = unit - 1; i != 0; i--)
+               putchar(c);
+}
+
+indent1(in)
+       int in;
+{
+       register i;
+
+       if (noprint())
+               return;
+       i = in;
+       if (profile == 0)
+               while (i >= 8) {
+                       putchar('\t');
+                       i =- 8;
+               }
+       while (i > 0) {
+               putchar(' ');
+               i--;
+       }
+}
+
+linopr()
+{
+
+       if (noprint())
+               return;
+       if (profile) {
+               if (line < 0)
+                       line = -line;
+               printf("%6d  ", line);
+       }
+}
+
+indentlab()
+{
+
+       indent1(pplev[PRFN]);
+}
+
+ppop(s)
+       char *s;
+{
+
+       if (noprint())
+               return;
+       printf(s);
+}
+
+ppnumb(s)
+       char *s;
+{
+
+       if (noprint())
+               return;
+       if (s == NIL)
+               s = "{number}";
+       printf(s);
+}
+
+ppgoin(lv)
+{
+
+       pplev[lv] =+ unit;
+}
+
+ppgoout(lv)
+{
+
+       pplev[lv] =- unit;
+       if (pplev[lv] < 0)
+               panic("pplev");
+}
+
+ppstr(s)
+       char *s;
+{
+       register char *cp;
+
+       if (noprint())
+               return;
+       if (s == NIL) {
+               printf("{string}");
+               return;
+       }
+       putchar('\'');
+       cp = s;
+       while (*cp) {
+               putchar(*cp);
+               if (*cp == '\'')
+                       putchar('\'');
+               cp++;
+       }
+       putchar('\'');
+}
+
+pplab(s)
+       char *s;
+{
+
+       if (noprint())
+               return;
+       if (s == NIL)
+               s = "{integer label}";
+       printf(s);
+}
+
+int    outcol;
+
+
+putchar(c)
+       char c;
+{
+
+       putc(c, stdout);
+       if (ferror(stdout))
+               outerr();
+       switch (c) {
+               case '\n':
+                       outcol = 0;
+                       flush();
+                       break;
+               case '\t':
+                       outcol =+ 8;
+                       outcol =& ~07;
+                       break;
+               case '\b':
+                       if (outcol)
+                               outcol--;
+                       break;
+               default:
+                       outcol++;
+               case '\f':
+                       break;
+       }
+}
+
+flush()
+{
+
+       fflush(stdout);
+       if (ferror(stdout))
+               outerr();
+}
+
+pptab()
+{
+       register int i;
+
+       if (noprint())
+               return;
+       i = pplev[PRFN] + profile ? 44 + unit : 28;
+/*
+       if (outcol > i + 8) {
+               ppnl();
+               i =+ 8;
+       }
+*/
+       do
+               putchar('\t');
+       while (outcol < i);
+}
+
+outerr()
+{
+
+       perror(stdoutn);
+       pexit(DIED);
+}
diff --git a/usr/src/cmd/pxp/printf.c b/usr/src/cmd/pxp/printf.c
new file mode 100644 (file)
index 0000000..f9de40e
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (c) 1979 Regents of the University of California */
+/*
+ * Hacked "printf" which prints through putchar.
+ * DONT USE WITH STDIO!
+ */
+printf(fmt, args)
+char *fmt;
+{
+       _doprnt(fmt, &args, 0);
+}
+
+_strout(count, string, adjust, foo, fillch)
+register char *string;
+register int count;
+int adjust;
+register struct { int a[6]; } *foo;
+{
+
+       while (adjust < 0) {
+               if (*string=='-' && fillch=='0') {
+                       if (foo)
+                               fputc(*string++, foo);
+                       else
+                               putchar(*string++);
+                       count--;
+               }
+               if (foo)
+                       fputc(fillch, foo);
+               else
+                       putchar(fillch);
+               adjust++;
+       }
+       while (--count>=0)
+               if (foo)
+                       fputc(*string++, foo);
+               else
+                       putchar(*string++);
+       while (adjust) {
+               if (foo)
+                       fputc(fillch, foo);
+               else
+                       putchar(fillch);
+               adjust--;
+       }
+}
diff --git a/usr/src/cmd/pxp/yymain.c b/usr/src/cmd/pxp/yymain.c
new file mode 100644 (file)
index 0000000..c412c10
--- /dev/null
@@ -0,0 +1,174 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+/*
+ * pi - Pascal interpreter code translator
+ *
+ * Charles Haley, Bill Joy UCB
+ * Version 1.2 November 1978
+ *
+ *
+ * pxp - Pascal execution profiler
+ *
+ * Bill Joy UCB
+ * Version 1.2 November 1978
+ */
+
+#include "0.h"
+#include "yy.h"
+
+int    line = 1;
+
+/*
+ * Yymain initializes each of the utility
+ * clusters and then starts the processing
+ * by calling yyparse.
+ */
+yymain()
+{
+
+       /*
+        * Initialize the scanner
+        */
+#ifdef PXP
+       if (bracket == 0) {
+#endif
+               if (getline() == -1) {
+                       Perror(filename, "No lines in file");
+                       pexit(NOSTART);
+               }
+#ifdef PXP
+       } else
+               yyline = 0;
+#endif
+
+#ifdef PI
+       magic();
+
+#endif
+       /*
+        * Initialize the clusters
+        *
+       initstring();
+        */
+       inithash();
+       inittree();
+#ifdef PI
+       initnl();
+#endif
+
+       /*
+        * Process the input
+        */
+       yyparse();
+#ifdef PI
+       magic2();
+#ifdef DEBUG
+       dumpnl(0);
+#endif
+#endif
+#ifdef PXP
+       prttab();
+       if (onefile) {
+               extern int outcol;
+
+               if (outcol)
+                       putchar('\n');
+               flush();
+               if (eflg) {
+                       writef(2, "File not rewritten because of errors\n");
+                       pexit(ERRS);
+               }
+               signal(1, 1);
+               signal(2, 1);
+               copyfile();
+       }
+#endif
+       pexit(eflg ? ERRS : AOK);
+}
+
+#ifdef PXP
+copyfile()
+{
+       register int c;
+       char buf[BUFSIZ];
+
+       if (freopen(stdoutn, "r", stdin) == NULL) {
+               perror(stdoutn);
+               pexit(ERRS);
+       }
+       if (freopen(firstname, "w", stdout) == NULL) {
+               perror(firstname);
+               pexit(ERRS);
+       }
+       while ((c = getchar()) > 0)
+               putchar(c);
+       if (ferror(stdout))
+               perror(stdout);
+}
+#endif
+
+static
+struct {
+       int             magic;
+       unsigned        txt_size;
+       unsigned        data_size;
+       unsigned        bss_size;
+       unsigned        syms_size;
+       unsigned        entry_point;
+       unsigned        tr_size;
+       unsigned        dr_size;
+} header;
+
+#ifdef PI
+magic()
+{
+
+    /*
+     * this is the size of /usr/lib/npxheader
+     */
+#define        HEAD_BYTES      1024
+       short           buf[HEAD_BYTES / sizeof ( short )];
+       unsigned        *ubuf = buf;
+       register int    hf, i;
+
+       hf = open("/usr/lib/npx_header", 0);
+       if (hf >= 0 && read(hf, buf, HEAD_BYTES) > sizeof header) {
+               header.magic = ubuf[0];
+               header.txt_size = ubuf[1];
+               header.data_size = ubuf[2];
+               header.bss_size = ubuf[3];
+               header.syms_size = ubuf[4];
+               header.entry_point = ubuf[5];
+               header.tr_size = ubuf[6];
+               header.dr_size = ubuf[7];
+               for (i = 0; i < HEAD_BYTES / sizeof ( short ); i++)
+                       word(buf[i]);
+       }
+       close(hf);
+       word(0404);
+}
+
+magic2()
+{
+       short i;
+
+       if  (header.magic != 0407)
+               panic ( "magic2" );
+       pflush();
+       lseek(ofil, 0l, 0);
+       header.data_size = ( unsigned ) lc - header.txt_size;
+       header.data_size =- sizeof header;
+       write(ofil, &header, sizeof header);
+       lseek(ofil, ( long ) ( HEAD_BYTES - sizeof ( short ) ) , 0);
+       i = ( ( unsigned ) lc) - HEAD_BYTES;
+       write(ofil, &i, 2);
+}
+#endif
+
+#ifdef PXP
+writef(i, cp)
+{
+
+       write(i, cp, strlen(cp));
+}
+#endif
diff --git a/usr/src/cmd/pxp/yyput.c b/usr/src/cmd/pxp/yyput.c
new file mode 100644 (file)
index 0000000..cdd921d
--- /dev/null
@@ -0,0 +1,282 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+/*
+ * pi - Pascal interpreter code translator
+ *
+ * Charles Haley, Bill Joy UCB
+ * Version 1.2 January 1979
+ *
+ *
+ * pxp - Pascal execution profiler
+ *
+ * Bill Joy UCB
+ * Version 1.2 January 1979
+ */
+
+#include "0.h"
+#include "tree.h"
+#include "yy.h"
+
+/*
+ * Structure describing queued listing lines during the forward move
+ * of error recovery.  These lines will be stroed by yyoutline during
+ * the forward move and flushed by yyoutfl or yyflush when an
+ * error occurs or a program termination.
+ */
+struct B {
+       int     Bmagic;
+       int     Bline;
+       int     Bseekp;
+       char    *Bfile;
+       int     Bseqid;
+       struct  B *Bnext;
+} *bottled;
+
+/*
+ * Filename gives the current input file, lastname is
+ * the last filename we printed, and lastid is the seqid of the last line
+ * we printed, to help us avoid printing
+ * multiple copies of lines.
+ */
+extern char *filename;
+char   *lastname;
+int    lastid;
+
+char   hadsome;
+char   holdbl;
+\f
+/*
+ * Print the current line in the input line
+ * buffer or, in a forward move of the recovery, queue it for printing.
+ */
+yyoutline()
+{
+       register struct B *bp;
+
+       if (Recovery) {
+               bp = tree(6, T_BOTTLE, yyline, yylinpt, filename, yyseqid);
+               if (bottled != NIL)
+                       bp->Bnext = bottled->Bnext, bottled->Bnext = bp;
+               else
+                       bp->Bnext = bp;
+               bottled = bp;
+               return;
+       }
+       yyoutfl(yyseqid);
+       if (yyseqid != lastid)
+               yyprline(charbuf, yyline, filename, yyseqid);
+}
+
+/*
+ * Flush all the bottled output.
+ */
+yyflush()
+{
+
+       yyoutfl(32767);
+}
+
+/*
+ * Flush the listing to the sequence id toseqid
+ */
+yyoutfl(toseqid)
+       int toseqid;
+{
+       register struct B *bp;
+
+       bp = bottled;
+       if (bp == NIL)
+               return;
+       bp = bp->Bnext;
+       while (bp->Bseqid <= toseqid) {
+               yygetline(bp->Bfile, bp->Bseekp, bp->Bline, bp->Bseqid);
+               if (bp->Bnext == bp) {
+                       bottled = NIL;
+                       break;
+               }
+               bp = bp->Bnext;
+               bottled->Bnext = bp;
+       }
+}
+\f
+int    yygetunit -1;
+char   *yygetfile;
+
+/*
+ * Yysync guarantees that the line associated
+ * with the current token was the last line
+ * printed for a syntactic error message.
+ */
+yysync()
+{
+
+       yyoutfl(yyeseqid);
+       if (lastid != yyeseqid)
+               yygetline(yyefile, yyseekp, yyeline, yyeseqid);
+}
+
+yySsync()
+{
+
+       yyoutfl(OY.Yyeseqid);
+}
+
+/*
+ * Yygetline gets a line from a file after we have
+ * lost it.  The pointer efile gives the name of the file,
+ * seekp its offset in the file, and eline its line number.
+ * If this routine has been called before the last file
+ * it worked on will be open in yygetunit, with the files
+ * name being given in yygetfile.  Note that this unit must
+ * be opened independently of the unit in use for normal i/o
+ * to this file; if it were a dup seeks would seek both files.
+ */
+yygetline(efile, seekp, eline, eseqid)
+       char *efile;
+       int seekp, eline, eseqid;
+{
+       register int cnt;
+       register char *bp;
+       char buf[CBSIZE + 1];
+
+       if (lastid == eseqid)
+               return;
+       if (eseqid == yyseqid) {
+               bp = charbuf;
+               yyprtd++;
+       } else {
+               bp = buf;
+               if (efile != yygetfile) {
+                       close(yygetunit);
+                       yygetfile = efile;
+                       yygetunit = open(yygetfile, 0);
+                       if (yygetunit < 0)
+oops:
+                               perror(yygetfile), pexit(DIED);
+               } 
+               if (lseek(yygetunit, (long)seekp, 0) < 0)
+                       goto oops;
+               cnt = read(yygetunit, bp, CBSIZE);
+               if (cnt < 0)
+                       goto oops;
+               bp[cnt] = 0;
+       }
+       yyprline(bp, eline, efile, eseqid);
+}
+
+yyretrieve()
+{
+
+       yygetline(OY.Yyefile, OY.Yyseekp, OY.Yyeline, OY.Yyeseqid);
+}
+\f
+/*
+ * Print the line in the character buffer which has
+ * line number line.  The buffer may be terminated by a new
+ * line character or a null character.  We process
+ * form feed directives, lines with only a form feed character, and
+ * suppress numbering lines which are empty here.
+ */
+yyprline(buf, line, file, id)
+       register char *buf;
+       int line;
+       char *file;
+       int id;
+{
+
+       lastid = id;
+       if (buf[0] == '\f' && buf[1] == '\n') {
+               printf("\f\n");
+               hadsome = 0;
+               holdbl = 0;
+               return;
+       }
+       if (holdbl) {
+               putchar('\n');
+               holdbl = 0;
+       }
+       if (buf[0] == '\n')
+               holdbl = 1;
+       else {
+               yysetfile(file);
+               yyprintf(buf, line);
+       }
+       hadsome = 1;
+}
+
+yyprintf(cp, line)
+       register char *cp;
+       int line;
+{
+
+       printf("%6d  ", line);
+       while (*cp != 0 && *cp != '\n')
+               putchar(graphic(*cp++));
+       putchar('\n');
+}
+
+graphic(ch)
+       register CHAR ch;
+{
+
+       switch (ch) {
+               default:
+                       if (ch >= ' ')
+                               return (ch);
+               case 0177:
+                       return ('?');
+               case '\n':
+               case '\t':
+                       return (ch);
+       }
+}
+\f
+extern int nopflg;
+
+char   printed 1;
+/*
+ * Set the current file name to be file,
+ * printing the name, or a header on a new
+ * page if required.
+ */
+yysetfile(file)
+       register char *file;
+{
+
+#ifdef PXP
+       if (nopflg == 1)
+               return;
+#endif
+
+       if (lastname == file)
+               return;
+       if (file == filename && opt('n') && (printed & 02) == 0) {
+               printed =| 02;
+               header();
+       } else
+               yyputfn(file);
+       lastname = file;
+}
+
+/*
+ * Put out an include file name
+ * if an error occurs but the name has
+ * not been printed (or if another name
+ * has been printed since it has).
+ */
+yyputfn(cp)
+       register char *cp;
+{
+       extern int outcol;
+
+       if (cp == lastname && printed)
+               return;
+       lastname = cp;
+       printed = 1;
+#ifdef PXP
+       if (outcol)
+               putchar('\n');
+#endif
+       printf("%s:\n", cp);
+       hadsome = 1;
+}
diff --git a/usr/src/cmd/pxp/yyrecover.c b/usr/src/cmd/pxp/yyrecover.c
new file mode 100644 (file)
index 0000000..a322b09
--- /dev/null
@@ -0,0 +1,859 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+/*
+ * pi - Pascal interpreter code translator
+ *
+ * Charles Haley, Bill Joy UCB
+ * Version 1.1 February 1978
+ *
+ *
+ * pxp - Pascal execution profiler
+ *
+ * Bill Joy UCB
+ * Version 1.1 February 1978
+ */
+
+#include "0.h"
+#include "yy.h"
+
+/*
+ * Very simplified version of Graham-Rhodes error recovery
+ * method for LALR parsers.  Backward move is embodied in
+ * default reductions of the yacc parser until an error condition
+ * is reached.  Forward move is over a small number of input tokens
+ * and cannot "condense".  The basic corrections are:
+ *
+ *     1) Delete the input token.
+ *
+ *     2) Replace the current input with a legal input.
+ *
+ *     3) Insert a legal token.
+ *
+ * All corrections are weighted, considered only if they allow
+ * at least two shifts, and the cost of a correction increases if
+ * it allows shifting over only a part of the lookahead.
+ *
+ * Another error situation is that which occurs when an identifier "fails"
+ * a reduction because it is not the required "class".
+ * In this case, we also consider replacing this identifier, which has
+ * already been shifted over, with an identifier of the correct class.
+ *
+ * Another correction performed here is unique symbol insertion.
+ * If the current state admits only one input, and no other alternative
+ * correction presents itself, then that symbol will be inserted.
+ * There is a danger in this of looping, and it is handled
+ * by counting true shifts over input (see below).
+ *
+ *
+ * A final class of corrections, considered only when the error
+ * occurred immediately after a shift over a terminal, involves
+ * the three basic corrections above, but with the point of error
+ * considered to be before this terminal was shifted over, effectively
+ * "unreading" this terminal.  This is a feeble attempt at elimination
+ * of the left-right bias and because "if" has a low weight and some
+ * statements are quite simple i.e.
+ *
+ *     cse ch of ...
+ *
+ * we can get a small number of errors.  The major deficiency of
+ * this is that we back up only one token, and that the forward
+ * move is over a small number of tokens, often not enough to really
+ * tell what the input should be, e.g. in
+ *
+ *     a[i] > a[i - 1] ...
+ *
+ * In such cases a bad identifier (misspelled keyword) or omitted
+ * keyword will be change or inserted as "if" as it has the lowest cost.
+ * This is not terribly bad, as "if"s are most common.
+ * This also allows the correction of other errors.
+ *
+ * This recovery depends on the default reductions which delay
+ * noticing the error until the parse reaches a state where the
+ * relevant "alternatives" are visible.  Note that it does not
+ * consider tokens which will cause reductions before being
+ * shifted over.  This requires the grammar to be written in a
+ * certain way for the recovery to work correctly.
+ * In some sense, also, the recovery suffers because we have
+ * LALR(1) tables rather than LR(1) tables, e.g. in
+ *
+ *     if rec.field < rec2,field2 then
+ */
+\f
+/*
+ * Definitions of possible corrective actions
+ */
+#define        CPANIC          0
+#define        CDELETE         1
+#define        CREPLACE        2
+#define        CINSERT         3
+#define        CUNIQUE         4
+#define        CCHIDENT        5
+
+/*
+ * Multiplicative cost factors for corrective actions.
+ *
+ * When an error occurs we take YCSIZ - 1 look-ahead tokens.
+ * If a correction being considered will shift over only part of
+ * that look-ahead, it is not completely discarded, but rather
+ * "weighted", its cost being multiplied by a weighting factor.
+ * For a correction to be considered its weighted cost must be less
+ * than CLIMIT.
+ *
+ * Non-weighted costs are considered:
+ *
+ *     LOW     <= 3
+ *     MEDIUM  4,5
+ *     HIGH    >= 6
+ *
+ * CURRENT WEIGHTING STRATEGY: Aug 20, 1977
+ *
+ * For all kinds of corrections we demand shifts over two symbols.
+ * Corrections have high weight even after two symbol
+ * shifts because the costs for deleting and inserting symbols are actually
+ * quite low; we do not want to change weighty symbols 
+ * on inconclusive evidence.
+ *
+ * The weights are the same after the third look ahead.
+ * This prevents later, unrelated errors from causing "funny"
+ * biases of the weights toward one type of correction.
+ *
+ * Current look ahead is 5 symbols.
+ */
+
+/*** CLIMIT is defined in yy.h for yycosts ***/
+#define        CPRLIMIT        50
+#define        CCHIDCOST       3
+
+char   insmult[8]      = {INFINITY, INFINITY, INFINITY, 15, 8, 6, 3, 1};
+char   repmult[7]      = {INFINITY, INFINITY, INFINITY, 8, 6, 3, 1};
+char   delmult[6]      = {INFINITY, INFINITY, INFINITY, 6, 3, 1};
+\f
+#define        NOCHAR  -1
+
+#define        Eprintf if (errtrace) printf
+#define        Tprintf if (testtrace) printf
+
+/*
+ * Action arrays of the parser needed here
+ */
+int    yyact[], yypact[], *yypv;
+
+/*
+ * Yytips is the tip of the stack when using
+ * the function loccor to check for local
+ * syntactic correctness. As we don't want
+ * to copy the whole parser stack, but want
+ * to simulate parser moves, we "split"
+ * the parser stack and keep the tip here.
+ */
+#define        YYTIPSIZ 16
+int    yytips[YYTIPSIZ], yytipct;
+int    yytipv[YYTIPSIZ];
+
+/*
+ * The array YC saves the lookahead tokens for the
+ * forward moves.
+ * Yccnt is the number of tokens in the YC array.
+ */
+#define        YCSIZ   6
+
+int    yCcnt;
+struct yytok YC0[YCSIZ + 1];
+struct yytok *YC;
+
+/*
+ * YCps gives the top of stack at
+ * the point of error.
+ */
+
+char   yyunique =      1;
+
+STATIC unsigned yyTshifts;
+\f
+/*
+ * Cact is the corrective action we have decided on
+ * so far, ccost its cost, and cchar the associated token.
+ * Cflag tells if the correction is over the previous input token.
+ */
+int    cact, ccost, cchar, cflag;
+
+/*
+ * ACtok holds the token under
+ * consideration when examining
+ * the lookaheads in a state.
+ */
+struct yytok ACtok;
+
+#define acchar ACtok.Yychar
+#define aclval ACtok.Yylval
+
+/*
+ * Make a correction to the current stack which has
+ * top of stack pointer Ps.
+ */
+yyrecover(Ps0, idfail)
+       int *Ps0, idfail;
+{
+       register int c, i;
+       int yyrwant, yyrhave;
+
+#ifdef PI
+       Recovery = 1;
+#endif
+
+       YC = &YC0[1];
+#ifdef DEBUG
+       if (errtrace) {
+               setpfx('p');
+               yerror("Point of error");
+               printf("States %d %d ...", Ps0[0], Ps0[-1]);
+               if (idfail)
+                       printf(" [Idfail]");
+               putchar('\n');
+               printf("Input %s%s", tokname(&Y , 0)
+                                  , tokname(&Y , 1));
+       }
+
+#endif
+       /*
+        * We first save the current input token
+        * and its associated semantic information.
+        */
+       if (yychar < 0)
+               yychar = yylex();
+       copy(&YC[0], &Y, sizeof Y);
+
+       /*
+        * Set the default action and cost
+        */
+       cact = CPANIC, ccost = CLIMIT, cflag = 0;
+
+       /*
+        * Peek ahead
+        */
+       for (yCcnt = 1; yCcnt < YCSIZ; yCcnt++) {
+               yychar = yylex();
+               copy(&YC[yCcnt], &Y, sizeof YC[0]);
+#ifdef DEBUG
+               Eprintf(" | %s%s", tokname(&YC[yCcnt] , 0 )
+                                , tokname(&YC[yCcnt] , 1 ));
+#endif
+       }
+#ifdef DEBUG
+       Eprintf("\n");
+#endif
+
+       /*
+        * If we are here because a reduction failed, try
+        * correcting that.
+        */
+       if (idfail) {
+               /*
+                * Save the particulars about
+                * the kind of identifier we want/have.
+                */
+               yyrwant = yyidwant;
+               yyrhave = yyidhave;
+#ifdef DEBUG
+               Tprintf("  Try Replace %s identifier with %s identifier cost=%d\n",
+                   classes[yyidhave], classes[yyidwant], CCHIDCOST);
+#endif
+
+               /*
+                * Save the semantics of the ID on the
+                * stack, and null them out to free
+                * up the reduction in question.
+                */
+               i = yypv[0];
+               yypv[0] = nullsem(YID);
+               c = correct(NOCHAR, 0, CCHIDCOST, &repmult[2], Ps0, yypv);
+               yypv[0] = i;
+#ifdef DEBUG
+               if (c < CPRLIMIT || fulltrace)
+                       Eprintf("Cost %2d Replace %s identifier with %s identifier\n", c, classes[yyrhave], classes[yyrwant]);
+#endif
+               if (c < ccost)
+                       cact = CCHIDENT, ccost = c, cchar = YID;
+       }
+
+       /*
+        * First try correcting the state we are in
+        */
+       trystate(Ps0, yypv, 0, &insmult[1], &delmult[1], &repmult[1]);
+
+       /*
+        * Now, if we just shifted over a terminal, try
+        * correcting it.
+        */
+       if (OY.Yychar != -1 && OY.Yylval != nullsem(OY.Yychar)) {
+               YC--;
+               copy(&YC[0], &OY, sizeof YC[0]);
+               trystate(Ps0 - 1, yypv - 1, 1, insmult, delmult, repmult);
+               if (cflag == 0)
+                       YC++;
+               else {
+                       yypv--;
+#ifdef PXP
+                       yypw--;
+#endif
+                       Ps0--;
+                       yCcnt++;
+               }
+       }
+
+       /*
+        * Restoring the first look ahead into
+        * the scanner token allows the error message
+        * routine to print the error message with the text
+        * of the correct line.
+        */
+       copy(&Y, &YC[0], sizeof Y);
+
+       /*
+        * Unique symbol insertion.
+        *
+        * If there was no reasonable correction found,
+        * but only one input to the parser is acceptable
+        * we report that, and try it.
+        *
+        * Special precautions here to prevent looping.
+        * The number of true inputs shifted over at the point
+        * of the last unique insertion is recorded in the
+        * variable yyTshifts.  If this is not less than
+        * the current number in yytshifts, we do not insert.
+        * Thus, after one unique insertion, no more unique
+        * insertions will be made until an input is shifted
+        * over.  This guarantees termination.
+        */
+       if (cact == CPANIC && !idfail) {
+               register int *ap;
+
+               ap = &yyact[yypact[*Ps0 + 1]];
+               if (*ap == -ERROR)
+                       ap =+ 2;
+               if (ap[0] <= 0 && ap[2] > 0) {
+                       cchar = -ap[0];
+                       if (cchar == YEOF)
+                               yyexeof();
+                       if (cchar != ERROR && yyTshifts < yytshifts) {
+                               cact = CUNIQUE;
+#ifdef DEBUG
+                               Eprintf("Unique symbol %s%s\n", charname(cchar));
+#endif
+                               /*
+                                * Note that the inserted symbol
+                                * will not be counted as a true input
+                                * (i.e. the "yytshifts--" below)
+                                * so that a true shift will be needed
+                                * to make yytshifts > yyTshifts.
+                                */
+                               yyTshifts = yytshifts;
+                       }
+               }
+       }
+
+       /*
+        * Set up to perform the correction.
+        * Build a token appropriate for replacement
+        * or insertion in the yytok structure ACchar
+        * having the attributes of the input at the
+        * point of error.
+        */
+       copy(&ACtok, &YC[0], sizeof ACtok);
+       acchar = cchar;
+       aclval = nullsem(acchar);
+       if (aclval != NIL)
+               recovered();
+       switch (cact) {
+               /*
+                * Panic, just restore the
+                * lookahead and return.
+                */
+               case CPANIC:
+                       setpfx('E');
+                       if (idfail) {
+                               copy(&Y, &OY, sizeof Y);
+                               if (yyrhave == NIL) {
+#ifdef PI
+                                       if (yybaduse(yypv[0], yyeline, ISUNDEF) == NIL)
+#endif
+                                               yerror("Undefined identifier");
+                               } else {
+                                       yerror("Improper %s identifier", classes[yyrhave]);
+#ifdef PI
+                                       yybaduse(yypv[0], yyeline, NIL);
+#endif
+                               }
+                               /*
+                                * Suppress message from panic routine
+                                */
+                               yyshifts = 1;
+                       }
+                       i = 0;
+                       /* Note that on one path we dont touch yyshifts ! */
+                       break;
+               /*
+                * Delete the input.
+                * Mark this as a shift over true input.
+                * Restore the lookahead starting at
+                * the second token.
+                */
+               case CDELETE:
+                       if (ccost != 0)
+                               yerror("Deleted %s%s", tokname(&YC[0] , 0 )
+                                                    , tokname(&YC[0] , 1 ));
+                       yytshifts++;
+                       i = 1;
+                       yyshifts = 0;
+                       break;
+               /*
+                * Replace the input with a new token.
+                */
+               case CREPLACE:
+                       if (acchar == YEOF)
+                               yyexeof();
+                       if (acchar == YEND)
+                               aclval = NIL;
+                       yerror("Replaced %s%s with a %s%s",
+                           tokname(&YC[0] , 0 ),
+                           tokname(&YC[0] , 1 ),
+                           tokname(&ACtok , 0 ),
+                           tokname(&ACtok , 1 ));
+                       copy(&YC[0], &ACtok, sizeof YC[0]);
+                       i = 0;
+                       yyshifts = 0;
+                       break;
+               /*
+                * Insert a token.
+                * Don't count this token as a true input shift.
+                * For inserted "end"s pas.y is responsible
+                * for the error message later so suppress it.
+                * Restore all the lookahead.
+                */
+               case CINSERT:
+                       if (acchar == YEOF)
+                               yyexeof();
+                       if (acchar != YEND)
+                               yerror("Inserted %s%s",
+                                       tokname(&ACtok , 0 ),
+                                       tokname(&ACtok , 1 ));
+                       yytshifts--;
+                       i = 0;
+                       yyshifts = 0;
+                       break;
+               /*
+                * Make a unique symbol correction.
+                * Like an insertion but a different message.
+                */
+               case CUNIQUE:
+                       setpfx('E');
+                       yerror("Expected %s%s",
+                               tokname(&ACtok , 0 ),
+                               tokname(&ACtok , 1 ));
+                       yytshifts--;
+                       i = 0;
+                       if (ccost == 0 || yyunique)
+                               yyshifts = 0;
+                       else
+                               yyshifts = -1;
+                       break;
+               /*
+                * Change an identifier's type
+                * to make it work.
+                */
+               case CCHIDENT:
+                       copy(&Y, &OY, sizeof Y);
+#ifdef PI
+                       i = 1 << yyrwant;
+#endif
+                       if (yyrhave == NIL) {
+                               yerror("Undefined %s", classes[yyrwant]);
+#ifdef PI
+                               i =| ISUNDEF;
+#endif
+                       } else
+                               yerror("Replaced %s id with a %s id", classes[yyrhave], classes[yyrwant]);
+#ifdef PI
+                       yybaduse(yypv[0], yyeline, i);
+#endif
+                       yypv[0] = nullsem(YID);
+                       i = 0;
+                       yyshifts = 0;
+                       break;
+       }
+
+       /*
+        * Restore the desired portion of the lookahead,
+        * and possibly the inserted or unique inserted token.
+        */
+       for (yCcnt--; yCcnt >= i; yCcnt--)
+               unyylex(&YC[yCcnt]);
+       if (cact == CINSERT || cact == CUNIQUE)
+               unyylex(&ACtok);
+
+       /*
+        * Put the scanner back in sync.
+        */
+       yychar = yylex();
+
+       /*
+        * We succeeded if we didn't "panic".
+        */
+       Recovery = 0;
+       Ps = Ps0;
+       return (cact != CPANIC);
+}
+
+yyexeof()
+{
+
+       yerror("End-of-file expected - QUIT");
+       pexit(ERRS);
+}
+
+yyunexeof()
+{
+
+       yerror("Unexpected end-of-file - QUIT");
+       pexit(ERRS);
+}
+\f
+/*
+ * Try corrections with the state at Ps0.
+ * Flag is 0 if this is the top of stack state,
+ * 1 if it is the state below.
+ */
+trystate(Ps0, Pv0, flag, insmult, delmult, repmult)
+       int *Ps0, *Pv0, flag;
+       char *insmult, *delmult, *repmult;
+{
+       /*
+        * C is a working cost, ap a pointer into the action
+        * table for looking at feasible alternatives.
+        */
+       register int c, *ap;
+       int i, *actions;
+
+#ifdef DEBUG
+       Eprintf("Trying state %d\n", *Ps0);
+#endif
+       /*
+        * Try deletion.
+        * Correct returns a cost.
+        */
+#ifdef DEBUG
+       Tprintf("  Try Delete %s%s cost=%d\n",
+               tokname(&YC[0] , 0 ),
+               tokname(&YC[0] , 1 ),
+               delcost(YC[0].Yychar));
+#endif
+       c = delcost(YC[0].Yychar);
+#ifndef DEBUG
+       if (c < ccost) {
+#endif
+               c = correct(NOCHAR, 1, c, delmult, Ps0, Pv0);
+#ifdef DEBUG
+               if (c < CPRLIMIT || fulltrace)
+                       Eprintf("Cost %2d Delete %s%s\n", c,
+                               tokname(&YC[0] , 0 ),
+                               tokname(&YC[0] , 1 ));
+#endif
+               if (c < ccost)
+                       cact = CDELETE, ccost = c, cflag = flag;
+#ifndef DEBUG
+       }
+#endif
+
+       /*
+        * Look at the inputs to this state
+        * which will cause parse action shift.
+        */
+       aclval = NIL;
+       ap = &yyact[yypact[*Ps0 + 1]];
+
+       /*
+        * Skip action on error to
+        * detect true unique inputs.
+        * Error action is always first.
+        */
+       if (*ap == -ERROR) 
+               ap=+ 2;
+
+       /*
+        * Loop through the test actions
+        * for this state.
+        */
+       for (actions = ap; *ap <= 0; ap =+ 2) {
+               /*
+                * Extract the token of this action
+                */
+               acchar = -*ap;
+
+               /*
+                * Try insertion
+                */
+#ifdef DEBUG
+               Tprintf("  Try Insert %s%s cost=%d\n", charname(acchar), inscost(acchar));
+#endif
+               c = inscost(acchar, YC[0].Yychar);
+#ifndef DEBUG
+               if (c < ccost) {
+#endif
+                       if (c == 0) {
+                               c = correct(acchar, 0, 1, insmult + 1, Ps0, Pv0);
+#ifdef DEBUG
+                               Eprintf("Cost %2d Freebie %s%s\n", c, charname(acchar));
+#endif
+                               if (c < ccost)
+                                       cact = CUNIQUE, ccost = 0, cchar = acchar, cflag = flag;
+                       } else {
+                               c = correct(acchar, 0, c, insmult, Ps0, Pv0);
+#ifdef DEBUG
+                               if (c < CPRLIMIT || fulltrace)
+                                       Eprintf("Cost %2d Insert %s%s\n", c, charname(acchar));
+#endif
+                               if (c < ccost)
+                                       cact = CINSERT, ccost = c, cchar = acchar, cflag = flag;
+                       }
+#ifndef DEBUG
+               }
+#endif
+
+               /*
+                * Try replacement
+                */
+#ifdef DEBUG
+               Tprintf("  Try Replace %s%s with %s%s cost=%d\n",
+                   tokname(&YC[0] , 0 ),
+                   tokname(&YC[0] , 1 ),
+                   charname(acchar , 0 ),
+                   charname(acchar , 1 ),
+                   repcost(YC[0].Yychar, acchar));
+#endif
+               c = repcost(YC[0].Yychar, acchar);
+#ifndef DEBUG
+               if (c < ccost) {
+#endif
+                       c = correct(acchar, 1, repcost(YC[0].Yychar, acchar), repmult, Ps0, Pv0);
+#ifdef DEBUG
+                       if (c < CPRLIMIT || fulltrace)
+                               Eprintf("Cost %2d Replace %s%s with %s%s\n",
+                                       c,
+                                       tokname(&YC[0] , 0 ),
+                                       tokname(&YC[0] , 1 ),
+                                       tokname(&ACtok , 0 ),
+                                       tokname(&ACtok , 1 ));
+#endif
+                       if (c < ccost)
+                               cact = CREPLACE, ccost = c, cchar = acchar, cflag = flag;
+#ifndef DEBUG
+               }
+#endif
+       }
+}
+\f
+int    *yCpv;
+char   yyredfail;
+
+/*
+ * The ntok structure is used to build a
+ * scanner structure for tokens inserted
+ * from the argument "fchar" to "correct" below.
+ */
+static struct yytok ntok;
+
+/*
+ * Compute the cost of a correction
+ * C is the base cost for it.
+ * Fchar is the first input character from
+ * the current state, NOCHAR if none.
+ * The rest of the inputs come from the array
+ * YC, starting at origin and continuing to the
+ * last character there, YC[yCcnt - 1].Yychar.
+ *
+ * The cost returned is INFINITE if this correction
+ * allows no shifts, otherwise is weighted based
+ * on the number of shifts this allows against the
+ * maximum number possible with the available lookahead.
+ */
+correct(fchar, origin, c, multvec, Ps0, Pv0)
+       register int fchar, c;
+       int origin;
+       char *multvec;
+       int *Ps0, *Pv0;
+{
+       register char *mv;
+
+       /*
+        * Ps is the top of the parse stack after the most
+        * recent local correctness check.  Loccor returns
+        * NIL when we cannot shift.
+        */
+       register int *ps;
+
+       yyredfail = 0;
+       /*
+        * Initialize the tip parse and semantic stacks.
+        */
+       ps = Ps0;
+       yytips[0] = *ps;
+       ps--;
+       yytipv[0] = Pv0[0];
+       yCpv = Pv0 - 1;
+       yytipct = 1;
+
+       /*
+        * Shift while possible.
+        * Adjust cost as necessary.
+        */
+       mv = multvec;
+       do {
+               if (fchar != NOCHAR) {
+                       copy(&ntok, &YC[0], sizeof ntok);
+                       ntok.Yychar = fchar, ntok.Yylval = nullsem(fchar);
+                       fchar = NOCHAR;
+                       ps = loccor(ps, &ntok);
+               } else
+                       ps = loccor(ps, &YC[origin++]);
+               if (ps == NIL) {
+                       if (yyredfail && mv > multvec)
+                               mv--;
+                       c =* *mv;
+                       break;
+               }
+               mv++;
+       } while (*mv != 1);
+       return (c);
+}
+\f
+extern int yygo[], yypgo[], yyr1[], yyr2[];
+/*
+ * Local syntactic correctness check.
+ * The arguments to this routine are a
+ * top of stack pointer, ps, and an input
+ * token tok.  Also, implicitly, the contents
+ * of the yytips array which contains the tip
+ * of the stack, and into which the new top
+ * state on the stack will be placed if we shift.
+ *
+ * If we succeed, we return a new top of stack
+ * pointer, else we return NIL.
+ */
+loccor(ps, ntok)
+       int *ps;
+       struct yytok *ntok;
+{
+       register int *p, n;
+       register int nchar;
+       int i;
+
+       if (ps == NIL)
+               return (NIL);
+       nchar = ntok->Yychar;
+       yyeline = ntok->Yyeline;
+#ifdef DEBUG
+       Tprintf("    Stack ");
+       for (i = yytipct - 1; i >= 0; i--)
+               Tprintf("%d ", yytips[i]);
+       Tprintf("| %d, Input %s%s\n", *ps, charname(nchar));
+#endif
+       /*
+        * As in the yacc parser yyparse,
+        * p traces through the action list
+        * and "n" is the information associated
+        * with the action.
+        */
+newstate:
+       p = &yyact[ yypact[yytips[yytipct - 1]+1] ];
+
+actn:
+       /*
+        * Search the parse actions table
+        * for something useful to do.
+        * While n is non-positive, it is the
+        * arithmetic inverse of the token to be tested.
+        * This allows a fast check.
+        */
+       while ((n = *p++) <= 0)
+               if ((n =+ nchar) != 0)
+                       p++;
+       switch (n >> 12) {
+               /*
+                * SHIFT
+                */
+               case 2:
+                       n =& 07777;
+                       yyredfail = 0;
+                       if (nchar == YID)
+                               yyredfail++;
+                       if (yytipct == YYTIPSIZ) {
+tipover:
+#ifdef DEBUG
+                               Tprintf("\tTIP OVFLO\n");
+#endif
+                               return (NIL);
+                       }
+                       yytips[yytipct] = n;
+                       yytipv[yytipct] = ntok->Yylval;
+                       yytipct++;
+#ifdef DEBUG
+                       Tprintf("\tShift to state %d\n", n);
+#endif
+                       return (ps);
+               /*
+                * REDUCE
+                */
+               case 3:
+                       n =& 07777;
+                       if (yyEactr(n, yytipv[yytipct - 1]) == 0) {
+#ifdef DEBUG
+                               Tprintf("\tYyEactr objects: have %s id, want %s id\n", classes[yyidhave], classes[yyidwant]);
+#endif
+                               return (NIL);
+                       }
+                       yyredfail = 0;
+                       i = yyr2[n];
+#ifdef DEBUG
+                       Tprintf("\tReduce, length %d,", i);
+#endif
+                       if (i > yytipct) {
+                               i =- yytipct;
+                               yytipct = 0;
+                               ps =- i;
+                               yCpv =- i;
+                       } else
+                               yytipct =- i;
+                       if (yytipct >= YYTIPSIZ)
+                               goto tipover;
+                       /*
+                        * Use goto table to find next state
+                        */
+                       p = &yygo[yypgo[yyr1[n]]];
+                       i = yytipct ? yytips[yytipct - 1] : *ps;
+                       while (*p != i && *p >= 0)
+                               p =+ 2;
+#ifdef DEBUG
+                       Tprintf(" new state %d\n", p[1]);
+#endif
+                       yytips[yytipct] = p[1];
+                       yytipct++;
+                       goto newstate;
+               /*
+                * ACCEPT
+                */
+               case 4:
+#ifdef DEBUG
+                       Tprintf("\tAccept\n");
+#endif
+                       return (ps);
+               /*
+                * ERROR
+                */
+               case 1:
+#ifdef DEBUG
+                       Tprintf("\tError\n");
+#endif
+                       return (0);
+       }
+       panic("loccor");
+}