From: Bill Joy Date: Sat, 20 Oct 1979 11:16:11 +0000 (-0800) Subject: BSD 3 development X-Git-Tag: BSD-3~817 X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/commitdiff_plain/eb8dd88eb14b837e6303833191236a128ad99682?hp=391b70cbba8f9cd2a910748333244b101a686579 BSD 3 development 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 --- diff --git a/usr/src/cmd/pxp/error.c b/usr/src/cmd/pxp/error.c new file mode 100644 index 0000000000..9b8eb80f07 --- /dev/null +++ b/usr/src/cmd/pxp/error.c @@ -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 index 0000000000..4f632dfb1b --- /dev/null +++ b/usr/src/cmd/pxp/nl.c @@ -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 +}; + +/* + * 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 + +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 + + +/* + * 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); +} + +/* + * 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 index 0000000000..f68de0df61 --- /dev/null +++ b/usr/src/cmd/pxp/pp.c @@ -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 index 0000000000..f9de40ee6c --- /dev/null +++ b/usr/src/cmd/pxp/printf.c @@ -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 index 0000000000..c412c100d1 --- /dev/null +++ b/usr/src/cmd/pxp/yymain.c @@ -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 index 0000000000..cdd921d814 --- /dev/null +++ b/usr/src/cmd/pxp/yyput.c @@ -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; + +/* + * 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; + } +} + +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); +} + +/* + * 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); + } +} + +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 index 0000000000..a322b097c7 --- /dev/null +++ b/usr/src/cmd/pxp/yyrecover.c @@ -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 + */ + +/* + * 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}; + +#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; + +/* + * 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); +} + +/* + * 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 + } +} + +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); +} + +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"); +}