BSD 3 development
authorCharles B. Haley <cbh@research.uucp>
Thu, 1 Nov 1979 04:28:34 +0000 (20:28 -0800)
committerCharles B. Haley <cbh@research.uucp>
Thu, 1 Nov 1979 04:28:34 +0000 (20:28 -0800)
Work on file usr/src/cmd/pi/rec.c
Work on file usr/src/cmd/pi/rval.c
Work on file usr/src/cmd/pi/stat.c
Work on file usr/src/cmd/pi/string.c
Work on file usr/src/cmd/pi/subr.c
Work on file usr/src/cmd/pi/tCopy.c
Work on file usr/src/cmd/pi/tree.c
Work on file usr/src/cmd/pi/tree.h
Work on file usr/src/cmd/pi/treen.c

Co-Authored-By: Bill Joy <wnj@ucbvax.Berkeley.EDU>
Co-Authored-By: Ken Thompson <ken@research.uucp>
Synthesized-from: 3bsd

usr/src/cmd/pi/rec.c [new file with mode: 0644]
usr/src/cmd/pi/rval.c [new file with mode: 0644]
usr/src/cmd/pi/stat.c [new file with mode: 0644]
usr/src/cmd/pi/string.c [new file with mode: 0644]
usr/src/cmd/pi/subr.c [new file with mode: 0644]
usr/src/cmd/pi/tCopy.c [new file with mode: 0644]
usr/src/cmd/pi/tree.c [new file with mode: 0644]
usr/src/cmd/pi/tree.h [new file with mode: 0644]
usr/src/cmd/pi/treen.c [new file with mode: 0644]

diff --git a/usr/src/cmd/pi/rec.c b/usr/src/cmd/pi/rec.c
new file mode 100644 (file)
index 0000000..a281f63
--- /dev/null
@@ -0,0 +1,248 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+/*
+ * pi - Pascal interpreter code translator
+ *
+ * Charles Haley, Bill Joy UCB
+ * Version 1.2 Novmeber 1978
+ */
+
+#include "whoami"
+#include "0.h"
+#include "tree.h"
+#include "opcode.h"
+
+/*
+ * Build a record namelist entry.
+ * Some of the processing here is somewhat involved.
+ * The basic structure we are building is as follows.
+ *
+ * Each record has a main RECORD entry, with an attached
+ * chain of fields as ->chain;  these include all the fields in all
+ * the variants of this record.
+ *
+ * Attached to NL_VARNT is a chain of VARNT structures
+ * describing each of the variants.  These are further linked
+ * through ->chain.  Each VARNT has, in ->range[0] the value of
+ * the associated constant, and each points at a RECORD describing
+ * the subrecord through NL_VTOREC.  These pointers are not unique,
+ * more than one VARNT may reference the same RECORD.
+ *
+ * The involved processing here is in computing the NL_OFFS entry
+ * by maxing over the variants.  This works as follows.
+ *
+ * Each RECORD has two size counters.  NL_OFFS is the maximum size
+ * so far of any variant of this record;  NL_FLDSZ gives the size
+ * of just the FIELDs to this point as a base for further variants.
+ *
+ * As we process each variant record, we start its size with the
+ * NL_FLDSZ we have so far.  After processing it, if its NL_OFFS
+ * is the largest so far, we update the NL_OFFS of this subrecord.
+ * This will eventually propagate back and update the NL_OFFS of the
+ * entire record.
+ */
+
+/*
+ * P0 points to the outermost RECORD for name searches.
+ */
+struct nl *P0;
+
+tyrec(r, off)
+       int *r, off;
+{
+
+           return tyrec1(r, off, 1);
+}
+
+/*
+ * Define a record namelist entry.
+ * R is the tree for the record to be built.
+ * Off is the offset for the first item in this (sub)record.
+ */
+struct nl *
+tyrec1(r, off, first)
+       register int *r;
+       int off;
+       char first;
+{
+       register struct nl *p, *P0was;
+
+       p = defnl(0, RECORD, 0, 0);
+       P0was = P0;
+       if (first)
+               P0 = p;
+#ifndef PI0
+       p->value[NL_FLDSZ] = p->value[NL_OFFS] = off;
+#endif
+       if (r != NIL) {
+               fields(p, r[2]);
+               variants(p, r[3]);
+       }
+       P0 = P0was;
+       return (p);
+}
+
+/*
+ * Define the fixed part fields for p.
+ */
+struct nl *
+fields(p, r)
+       struct nl *p;
+       int *r;
+{
+       register int *fp, *tp, *ip;
+       struct nl *jp;
+
+       for (fp = r; fp != NIL; fp = fp[2]) {
+               tp = fp[1];
+               if (tp == NIL)
+                       continue;
+               jp = gtype(tp[3]);
+               line = tp[1];
+               for (ip = tp[2]; ip != NIL; ip = ip[2])
+                       deffld(p, ip[1], jp);
+       }
+}
+
+/*
+ * Define the variants for RECORD p.
+ */
+struct nl *
+variants(p, r)
+       struct nl *p;
+       register int *r;
+{
+       register int *vc, *v;
+       int *vr;
+       struct nl *ct;
+
+       if (r == NIL)
+               return;
+       ct = gtype(r[3]);
+       line = r[1];
+       /*
+        * Want it even if r[2] is NIL so
+        * we check its type in "new" and "dispose"
+        * calls -- link it to NL_TAG.
+        */
+       p->ptr[NL_TAG] = deffld(p, r[2], ct);
+       for (vc = r[4]; vc != NIL; vc = vc[2]) {
+               v = vc[1];
+               if (v == NIL)
+                       continue;
+               vr = tyrec1(v[3], p->value[NL_FLDSZ], 0);
+#ifndef PI0
+               if (vr->value[NL_OFFS] > p->value[NL_OFFS])
+                       p->value[NL_OFFS] = vr->value[NL_OFFS];
+#endif
+               line = v[1];
+               for (v = v[2]; v != NIL; v = v[2])
+                       defvnt(p, v[1], vr, ct);
+       }
+}
+
+/*
+ * Define a field in subrecord p of record P0
+ * with name s and type t.
+ */
+struct nl *
+deffld(p, s, t)
+       struct nl *p;
+       register char *s;
+       register struct nl *t;
+{
+       register struct nl *fp;
+
+       if (reclook(P0, s) != NIL) {
+#ifndef PI1
+               error("%s is a duplicate field name in this record", s);
+#endif
+               s = NIL;
+       }
+#ifndef PI0
+       fp = enter(defnl(s, FIELD, t, p->value[NL_OFFS]));
+#else
+       fp = enter(defnl(s, FIELD, t, 0));
+#endif
+       if (s != NIL) {
+               fp->chain = P0->chain;
+               P0->chain = fp;
+#ifndef PI0
+               p->value[NL_FLDSZ] = p->value[NL_OFFS] += even(width(t));
+#endif
+               if (t != NIL) {
+                       P0->nl_flags |= t->nl_flags & NFILES;
+                       p->nl_flags |= t->nl_flags & NFILES;
+               }
+       }
+       return (fp);
+}
+
+/*
+ * Define a variant from the constant tree of t
+ * in subrecord p of record P0 where the casetype
+ * is ct and the variant record to be associated is vr.
+ */
+struct nl *
+defvnt(p, t, vr, ct)
+       struct nl *p, *vr;
+       int *t;
+       register struct nl *ct;
+{
+       register struct nl *av;
+
+       gconst(t);
+       if (ct != NIL && incompat(con.ctype, ct)) {
+#ifndef PI1
+               cerror("Variant label type incompatible with selector type");
+#endif
+               ct = NIL;
+       }
+       av = defnl(0, VARNT, ct, 0);
+#ifndef PI1
+       if (ct != NIL)
+               uniqv(p);
+#endif
+       av->chain = p->ptr[NL_VARNT];
+       p->ptr[NL_VARNT] = av;
+       av->ptr[NL_VTOREC] = vr;
+       av->range[0] = con.crval;
+       return (av);
+}
+
+#ifndef PI1
+/*
+ * Check that the constant label value
+ * is unique among the labels in this variant.
+ */
+uniqv(p)
+       struct nl *p;
+{
+       register struct nl *vt;
+
+       for (vt = p->ptr[NL_VARNT]; vt != NIL; vt = vt->chain)
+               if (vt->range[0] == con.crval) {
+                       error("Duplicate variant case label in record");
+                       return;
+               }
+}
+#endif
+
+/*
+ * See if the field name s is defined
+ * in the record p, returning a pointer
+ * to it namelist entry if it is.
+ */
+struct nl *
+reclook(p, s)
+       register struct nl *p;
+       char *s;
+{
+
+       if (p == NIL || s == NIL)
+               return (NIL);
+       for (p = p->chain; p != NIL; p = p->chain)
+               if (p->symbol == s)
+                       return (p);
+       return (NIL);
+}
diff --git a/usr/src/cmd/pi/rval.c b/usr/src/cmd/pi/rval.c
new file mode 100644 (file)
index 0000000..fb51694
--- /dev/null
@@ -0,0 +1,554 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+/*
+ * pi - Pascal interpreter code translator
+ *
+ * Charles Haley, Bill Joy UCB
+ * Version 1.2 Novmeber 1978
+ */
+
+#include "whoami"
+#include "0.h"
+#include "tree.h"
+#include "opcode.h"
+
+extern char *opnames[];
+/*
+ * Rvalue - an expression.
+ *
+ * Contype is the type that the caller would prefer, nand is important
+ * if constant sets or constant strings are involved, the latter
+ * because of string padding.
+ */
+struct nl *
+rvalue(r, contype)
+       int *r;
+       struct nl *contype;
+{
+       register struct nl *p, *p1;
+       register struct nl *q;
+       int c, c1, *rt, w, g;
+       char *cp, *cp1, *opname;
+       long l;
+       double f;
+
+       if (r == NIL)
+               return (NIL);
+       if (nowexp(r))
+               return (NIL);
+       /*
+        * Pick up the name of the operation
+        * for future error messages.
+        */
+       if (r[0] <= T_IN)
+               opname = opnames[r[0]];
+
+       /*
+        * The root of the tree tells us what sort of expression we have.
+        */
+       switch (r[0]) {
+
+       /*
+        * The constant nil
+        */
+       case T_NIL:
+               put2(O_CON2, 0);
+               return (nl+TNIL);
+
+       /*
+        * Function call with arguments.
+        */
+       case T_FCALL:
+               return (funccod(r));
+
+       case T_VAR:
+               p = lookup(r[2]);
+               if (p == NIL || p->class == BADUSE)
+                       return (NIL);
+               switch (p->class) {
+                   case VAR:
+                           /*
+                            * If a variable is
+                            * qualified then get
+                            * the rvalue by a
+                            * lvalue and an ind.
+                            */
+                           if (r[3] != NIL)
+                                   goto ind;
+                           q = p->type;
+                           if (q == NIL)
+                                   return (NIL);
+                           w = width(q);
+                           switch (w) {
+                               case 8:
+                                   w = 6;
+                               case 4:
+                               case 2:
+                               case 1:
+                                   put2(O_RV1 + (w >> 1) | bn << 9
+                                       , p->value[0]);
+                                   break;
+                               default:
+                                   put3(O_RV | bn << 9, p->value[0], w);
+                           }
+                           return (q);
+
+                   case WITHPTR:
+                   case REF:
+                           /*
+                            * A lvalue for these
+                            * is actually what one
+                            * might consider a rvalue.
+                            */
+ind:
+                           q = lvalue(r, NOMOD);
+                           if (q == NIL)
+                                   return (NIL);
+                           w = width(q);
+                           switch (w) {
+                               case 8:
+                                       w = 6;
+                               case 4:
+                               case 2:
+                               case 1:
+                                       put1(O_IND1 + (w >> 1));
+                                       break;
+                               default:
+                                       put2(O_IND, w);
+                           }
+                           return (q);
+
+                   case CONST:
+                           if (r[3] != NIL) {
+                                   error("%s is a constant and cannot be qualified", r[2]);
+                                   return (NIL);
+                           }
+                           q = p->type;
+                           if (q == NIL)
+                                   return (NIL);
+                           if (q == nl+TSTR) {
+                                   /*
+                                    * Find the size of the string
+                                    * constant if needed.
+                                    */
+                                   cp = p->ptr[0];
+cstrng:
+                                   cp1 = cp;
+                                   for (c = 0; *cp++; c++)
+                                           continue;
+                                   if (contype != NIL && !opt('s')) {
+                                           if (width(contype) < c && classify(contype) == TSTR) {
+                                                   error("Constant string too long");
+                                                   return (NIL);
+                                           }
+                                           c = width(contype);
+                                   }
+                                   put( 2 + (sizeof ( char * )/sizeof ( short )) , O_CONG, c, cp1);
+                                   /*
+                                    * Define the string temporarily
+                                    * so later people can know its
+                                    * width.
+                                    * cleaned out by stat.
+                                    */
+                                   q = defnl(0, STR, 0, c);
+                                   q->type = q;
+                                   return (q);
+                           }
+                           if (q == nl+T1CHAR) {
+                                   put2(O_CONC, p->value[0]);
+                                   return (q);
+                           }
+                           /*
+                            * Every other kind of constant here
+                            */
+                           switch (width(q)) {
+                           case 8:
+#ifndef DEBUG
+                                   put(5, O_CON8, p->real);
+#else
+                                   if (hp21mx) {
+                                           f = p->real;
+                                           conv(&f);
+                                           l = f.plong;
+                                           put( 3 , O_CON4, l);
+                                   } else
+                                           put(5, O_CON8, p->real);
+#endif
+                                   break;
+                           case 4:
+                                   put( 3 , O_CON4, p->range[0]);
+                                   break;
+                           case 2:
+                                   put2(O_CON2, ( short ) p->range[0]);
+                                   break;
+                           case 1:
+                                   put2(O_CON1, p->value[0]);
+                                   break;
+                           default:
+                                   panic("rval");
+                           }
+                           return (q);
+
+                   case FUNC:
+                           /*
+                            * Function call with no arguments.
+                            */
+                           if (r[3]) {
+                                   error("Can't qualify a function result value");
+                                   return (NIL);
+                           }
+                           return (funccod((int *) r));
+
+                   case TYPE:
+                           error("Type names (e.g. %s) allowed only in declarations", p->symbol);
+                           return (NIL);
+
+                   case PROC:
+                           error("Procedure %s found where expression required", p->symbol);
+                           return (NIL);
+                   default:
+                           panic("rvid");
+               }
+       /*
+        * Constant sets
+        */
+       case T_CSET:
+               return (cset(r, contype, NIL));
+
+       /*
+        * Unary plus and minus
+        */
+       case T_PLUS:
+       case T_MINUS:
+               q = rvalue(r[2], NIL);
+               if (q == NIL)
+                       return (NIL);
+               if (isnta(q, "id")) {
+                       error("Operand of %s must be integer or real, not %s", opname, nameof(q));
+                       return (NIL);
+               }
+               if (r[0] == T_MINUS) {
+                       put1(O_NEG2 + (width(q) >> 2));
+                       return (isa(q, "d") ? q : nl+T4INT);
+               }
+               return (q);
+
+       case T_NOT:
+               q = rvalue(r[2], NIL);
+               if (q == NIL)
+                       return (NIL);
+               if (isnta(q, "b")) {
+                       error("not must operate on a Boolean, not %s", nameof(q));
+                       return (NIL);
+               }
+               put1(O_NOT);
+               return (nl+T1BOOL);
+
+       case T_AND:
+       case T_OR:
+               p = rvalue(r[2], NIL);
+               p1 = rvalue(r[3], NIL);
+               if (p == NIL || p1 == NIL)
+                       return (NIL);
+               if (isnta(p, "b")) {
+                       error("Left operand of %s must be Boolean, not %s", opname, nameof(p));
+                       return (NIL);
+               }
+               if (isnta(p1, "b")) {
+                       error("Right operand of %s must be Boolean, not %s", opname, nameof(p1));
+                       return (NIL);
+               }
+               put1(r[0] == T_AND ? O_AND : O_OR);
+               return (nl+T1BOOL);
+
+       case T_DIVD:
+               p = rvalue(r[2], NIL);
+               p1 = rvalue(r[3], NIL);
+               if (p == NIL || p1 == NIL)
+                       return (NIL);
+               if (isnta(p, "id")) {
+                       error("Left operand of / must be integer or real, not %s", nameof(p));
+                       return (NIL);
+               }
+               if (isnta(p1, "id")) {
+                       error("Right operand of / must be integer or real, not %s", nameof(p1));
+                       return (NIL);
+               }
+               return (gen(NIL, r[0], width(p), width(p1)));
+
+       case T_MULT:
+       case T_SUB:
+       case T_ADD:
+               /*
+                * If the context hasn't told us
+                * the type and a constant set is
+                * present on the left we need to infer
+                * the type from the right if possible
+                * before generating left side code.
+                */
+               if (contype == NIL && (rt = r[2]) != NIL && rt[1] == SAWCON) {
+                       codeoff();
+                       contype = rvalue(r[3], NIL);
+                       codeon();
+                       if (contype == NIL)
+                               return (NIL);
+               }
+               p = rvalue(r[2], contype);
+               p1 = rvalue(r[3], p);
+               if (p == NIL || p1 == NIL)
+                       return (NIL);
+               if (isa(p, "id") && isa(p1, "id"))
+                       return (gen(NIL, r[0], width(p), width(p1)));
+               if (isa(p, "t") && isa(p1, "t")) {
+                       if (p != p1) {
+                               error("Set types of operands of %s must be identical", opname);
+                               return (NIL);
+                       }
+                       gen(TSET, r[0], width(p), 0);
+                       /*
+                        * Note that set was filled in by the call
+                        * to width above.
+                        */
+                       if (r[0] == T_SUB)
+                               put2(NIL, 0177777 << ((set.uprbp & 017) + 1));
+                       return (p);
+               }
+               if (isnta(p, "idt")) {
+                       error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p));
+                       return (NIL);
+               }
+               if (isnta(p1, "idt")) {
+                       error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1));
+                       return (NIL);
+               }
+               error("Cannot mix sets with integers and reals as operands of %s", opname);
+               return (NIL);
+
+       case T_MOD:
+       case T_DIV:
+               p = rvalue(r[2], NIL);
+               p1 = rvalue(r[3], NIL);
+               if (p == NIL || p1 == NIL)
+                       return (NIL);
+               if (isnta(p, "i")) {
+                       error("Left operand of %s must be integer, not %s", opname, nameof(p));
+                       return (NIL);
+               }
+               if (isnta(p1, "i")) {
+                       error("Right operand of %s must be integer, not %s", opname, nameof(p1));
+                       return (NIL);
+               }
+               return (gen(NIL, r[0], width(p), width(p1)));
+
+       case T_EQ:
+       case T_NE:
+       case T_GE:
+       case T_LE:
+       case T_GT:
+       case T_LT:
+               /*
+                * Since there can be no, a priori, knowledge
+                * of the context type should a constant string
+                * or set arise, we must poke around to find such
+                * a type if possible.  Since constant strings can
+                * always masquerade as identifiers, this is always
+                * necessary.
+                */
+               codeoff();
+               p1 = rvalue(r[3], NIL);
+               codeon();
+               if (p1 == NIL)
+                       return (NIL);
+               contype = p1;
+               if (p1 == nl+TSET || p1->class == STR) {
+                       /*
+                        * For constant strings we want
+                        * the longest type so as to be
+                        * able to do padding (more importantly
+                        * avoiding truncation). For clarity,
+                        * we get this length here.
+                        */
+                       codeoff();
+                       p = rvalue(r[2], NIL);
+                       codeon();
+                       if (p == NIL)
+                               return (NIL);
+                       if (p1 == nl+TSET || width(p) > width(p1))
+                               contype = p;
+               }
+               /*
+                * Now we generate code for
+                * the operands of the relational
+                * operation.
+                */
+               p = rvalue(r[2], contype);
+               if (p == NIL)
+                       return (NIL);
+               p1 = rvalue(r[3], p);
+               if (p1 == NIL)
+                       return (NIL);
+               c = classify(p);
+               c1 = classify(p1);
+               if (nocomp(c) || nocomp(c1))
+                       return (NIL);
+               g = NIL;
+               switch (c) {
+                       case TBOOL:
+                       case TCHAR:
+                               if (c != c1)
+                                       goto clash;
+                               break;
+                       case TINT:
+                       case TDOUBLE:
+                               if (c1 != TINT && c1 != TDOUBLE)
+                                       goto clash;
+                               break;
+                       case TSCAL:
+                               if (c1 != TSCAL)
+                                       goto clash;
+                               if (scalar(p) != scalar(p1))
+                                       goto nonident;
+                               break;
+                       case TSET:
+                               if (c1 != TSET)
+                                       goto clash;
+                               if (p != p1)
+                                       goto nonident;
+                               g = TSET;
+                               break;
+                       case TPTR:
+                       case TNIL:
+                               if (c1 != TPTR && c1 != TNIL)
+                                       goto clash;
+                               if (r[0] != T_EQ && r[0] != T_NE) {
+                                       error("%s not allowed on pointers - only allow = and <>");
+                                       return (NIL);
+                               }
+                               break;
+                       case TSTR:
+                               if (c1 != TSTR)
+                                       goto clash;
+                               if (width(p) != width(p1)) {
+                                       error("Strings not same length in %s comparison", opname);
+                                       return (NIL);
+                               }
+                               g = TSTR;
+                               break;
+                       default:
+                               panic("rval2");
+               }
+               return (gen(g, r[0], width(p), width(p1)));
+clash:
+               error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname);
+               return (NIL);
+nonident:
+               error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname);
+               return (NIL);
+
+       case T_IN:
+               rt = r[3];
+               if (rt != NIL && rt[0] == T_CSET)
+                       p1 = cset(rt, NLNIL, 1);
+               else {
+                       p1 = rvalue(r[3], NIL);
+                       rt = NIL;
+               }
+               if (p1 == nl+TSET) {
+                       warning();
+                       error("... in [] makes little sense, since it is always false!");
+                       put1(O_CON1, 0);
+                       return (nl+T1BOOL);
+               }
+               p = rvalue(r[2], NIL);
+               if (p == NIL || p1 == NIL)
+                       return (NIL);
+               if (p1->class != SET) {
+                       error("Right operand of 'in' must be a set, not %s", nameof(p1));
+                       return (NIL);
+               }
+               if (incompat(p, p1->type, r[2])) {
+                       cerror("Index type clashed with set component type for 'in'");
+                       return (NIL);
+               }
+               convert(p, nl+T2INT);
+               setran(p1->type);
+               if (rt == NIL)
+                       put4(O_IN, width(p1), set.lwrb, set.uprbp);
+               else
+                       put1(O_INCT);
+               return (nl+T1BOOL);
+
+       default:
+               if (r[2] == NIL)
+                       return (NIL);
+               switch (r[0]) {
+               default:
+                       panic("rval3");
+
+
+               /*
+                * An octal number
+                */
+               case T_BINT:
+                       f = a8tol(r[2]);
+                       goto conint;
+       
+               /*
+                * A decimal number
+                */
+               case T_INT:
+                       f = atof(r[2]);
+conint:
+                       if (f > MAXINT || f < MININT) {
+                               error("Constant too large for this implementation");
+                               return (NIL);
+                       }
+                       l = f;
+                       if (bytes(l, l) <= 2) {
+                               put2(O_CON2, ( short ) l);
+                               return (nl+T2INT);
+                       }
+                       put( 3 , O_CON4, l); 
+                       return (nl+T4INT);
+       
+               /*
+                * A floating point number
+                */
+               case T_FINT:
+                       put(5, O_CON8, atof(r[2]));
+                       return (nl+TDOUBLE);
+       
+               /*
+                * Constant strings.  Note that constant characters
+                * are constant strings of length one; there is
+                * no constant string of length one.
+                */
+               case T_STRNG:
+                       cp = r[2];
+                       if (cp[1] == 0) {
+                               put2(O_CONC, cp[0]);
+                               return (nl+T1CHAR);
+                       }
+                       goto cstrng;
+               }
+       
+       }
+}
+
+/*
+ * Can a class appear
+ * in a comparison ?
+ */
+nocomp(c)
+       int c;
+{
+
+       switch (c) {
+               case TFILE:
+               case TARY:
+               case TREC:
+                       error("%ss may not participate in comparisons", clnames[c]);
+                       return (1);
+       }
+       return (NIL);
+}
diff --git a/usr/src/cmd/pi/stat.c b/usr/src/cmd/pi/stat.c
new file mode 100644 (file)
index 0000000..9e31804
--- /dev/null
@@ -0,0 +1,571 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#
+/*
+ * pi - Pascal interpreter code translator
+ *
+ * Charles Haley, Bill Joy UCB
+ * Version 1.2 November 1978
+ */
+
+#include "whoami"
+#include "0.h"
+#include "tree.h"
+
+int cntstat;
+short cnts = 2;
+#include "opcode.h"
+
+/*
+ * Statement list
+ */
+statlist(r)
+       int *r;
+{
+       register *sl;
+
+       for (sl=r; sl != NIL; sl=sl[2])
+               statement(sl[1]);
+}
+
+/*
+ * Statement
+ */
+statement(r)
+       int *r;
+{
+       register *s;
+       register struct nl *snlp;
+
+       s = r;
+       snlp = nlp;
+top:
+       if (cntstat) {
+               cntstat = 0;
+               putcnt();
+       }
+       if (s == NIL)
+               return;
+       line = s[1];
+       if (s[0] == T_LABEL) {
+               labeled(s[2]);
+               s = s[3];
+               noreach = 0;
+               cntstat = 1;
+               goto top;
+       }
+       if (noreach) {
+               noreach = 0;
+               warning();
+               error("Unreachable statement");
+       }
+       switch (s[0]) {
+               case T_PCALL:
+                       putline();
+                       proc(s);
+                       break;
+               case T_ASGN:
+                       putline();
+                       asgnop(s);
+                       break;
+               case T_GOTO:
+                       putline();
+                       gotoop(s[2]);
+                       noreach = 1;
+                       cntstat = 1;
+                       break;
+               default:
+                       level++;
+                       switch (s[0]) {
+                               default:
+                                       panic("stat");
+                               case T_IF:
+                               case T_IFEL:
+                                       ifop(s);
+                                       break;
+                               case T_WHILE:
+                                       whilop(s);
+                                       noreach = 0;
+                                       break;
+                               case T_REPEAT:
+                                       repop(s);
+                                       break;
+                               case T_FORU:
+                               case T_FORD:
+                                       forop(s);
+                                       noreach = 0;
+                                       break;
+                               case T_BLOCK:
+                                       statlist(s[2]);
+                                       break;
+                               case T_CASE:
+                                       putline();
+                                       caseop(s);
+                                       break;
+                               case T_WITH:
+                                       withop(s);
+                                       break;
+                               case T_ASRT:
+                                       putline();
+                                       asrtop(s);
+                                       break;
+                       }
+                       --level;
+                       if (gotos[cbn])
+                               ungoto();
+                       break;
+       }
+       /*
+        * Free the temporary name list entries defined in
+        * expressions, e.g. STRs, and WITHPTRs from withs.
+        */
+       nlfree(snlp);
+}
+
+ungoto()
+{
+       register struct nl *p;
+
+       for (p = gotos[cbn]; p != NIL; p = p->chain)
+               if ((p->nl_flags & NFORWD) != 0) {
+                       if (p->value[NL_GOLEV] != NOTYET)
+                               if (p->value[NL_GOLEV] > level)
+                                       p->value[NL_GOLEV] = level;
+               } else
+                       if (p->value[NL_GOLEV] != DEAD)
+                               if (p->value[NL_GOLEV] > level)
+                                       p->value[NL_GOLEV] = DEAD;
+}
+
+putcnt()
+{
+
+       if (monflg == 0)
+               return;
+       cnts++;
+       put2(O_COUNT, cnts);
+}
+
+putline()
+{
+
+#      ifdef OBJ
+           if (opt('p') != 0)
+                   put2(O_LINO, line);
+#      endif
+}
+
+/*
+ * With varlist do stat
+ *
+ * With statement requires an extra word
+ * in automatic storage for each level of withing.
+ * These indirect pointers are initialized here, and
+ * the scoping effect of the with statement occurs
+ * because lookup examines the field names of the records
+ * associated with the WITHPTRs on the withlist.
+ */
+withop(s)
+       int *s;
+{
+       register *p;
+       register struct nl *r;
+       int i;
+       int *swl;
+       long soffset;
+
+       putline();
+       swl = withlist;
+       soffset = sizes[cbn].om_off;
+       for (p = s[2]; p != NIL; p = p[2]) {
+               sizes[cbn].om_off -= sizeof ( int * );
+#              ifdef PPC
+                   putlbracket();
+#              endif
+               put2(O_LV | cbn <<9, i = sizes[cbn].om_off);
+               r = lvalue(p[1], MOD);
+               if (r == NIL)
+                       continue;
+               if (r->class != RECORD) {
+                       error("Variable in with statement refers to %s, not to a record", nameof(r));
+                       continue;
+               }
+               r = defnl(0, WITHPTR, r, i);
+               r->nl_next = withlist;
+               withlist = r;
+#              ifdef   VAX
+                   put1 ( O_AS4 );
+#              endif
+#              ifdef PDP11
+                   put1(O_AS2);
+#              endif
+       }
+       if (sizes[cbn].om_off < sizes[cbn].om_max)
+               sizes[cbn].om_max = sizes[cbn].om_off;
+       statement(s[3]);
+       sizes[cbn].om_off = soffset;
+#      ifdef PPC
+           putlbracket();
+#      endif
+       withlist = swl;
+}
+
+extern flagwas;
+/*
+ * var := expr
+ */
+asgnop(r)
+       int *r;
+{
+       register struct nl *p;
+       register *av;
+
+       if (r == NIL)
+               return (NIL);
+       /*
+        * Asgnop's only function is
+        * to handle function variable
+        * assignments.  All other assignment
+        * stuff is handled by asgnop1.
+        */
+       av = r[2];
+       if (av != NIL && av[0] == T_VAR && av[3] == NIL) {
+               p = lookup1(av[2]);
+               if (p != NIL)
+                       p->nl_flags = flagwas;
+               if (p != NIL && p->class == FVAR) {
+                       /*
+                        * Give asgnop1 the func
+                        * which is the chain of
+                        * the FVAR.
+                        */
+                       p->nl_flags |= NUSED|NMOD;
+                       p = p->chain;
+                       if (p == NIL) {
+                               rvalue(r[3], NIL);
+                               return;
+                       }
+                       put2(O_LV | bn << 9, p->value[NL_OFFS]);
+                       if (isa(p->type, "i") && width(p->type) == 1)
+                               asgnop1(r, nl+T2INT);
+                       else
+                               asgnop1(r, p->type);
+                       return;
+               }
+       }
+       asgnop1(r, NIL);
+}
+
+/*
+ * Asgnop1 handles all assignments.
+ * If p is not nil then we are assigning
+ * to a function variable, otherwise
+ * we look the variable up ourselves.
+ */
+struct nl *
+asgnop1(r, p)
+       int *r;
+       register struct nl *p;
+{
+       register struct nl *p1;
+
+       if (r == NIL)
+               return (NIL);
+       if (p == NIL) {
+               p = lvalue(r[2], MOD|ASGN|NOUSE);
+               if (p == NIL) {
+                       rvalue(r[3], NIL);
+                       return (NIL);
+               }
+       }
+       p1 = rvalue(r[3], p);
+       if (p1 == NIL)
+               return (NIL);
+       if (incompat(p1, p, r[3])) {
+               cerror("Type of expression clashed with type of variable in assignment");
+               return (NIL);
+       }
+       switch (classify(p)) {
+               case TBOOL:
+               case TCHAR:
+               case TINT:
+               case TSCAL:
+                       rangechk(p, p1);
+               case TDOUBLE:
+               case TPTR:
+                       gen(O_AS2, O_AS2, width(p), width(p1));
+                       break;
+               default:
+                       put2(O_AS, width(p));
+       }
+#      ifdef PPC
+           putexpr();
+#      endif
+       return (p);     /* Used by for statement */
+}
+
+/*
+ * for var := expr [down]to expr do stat
+ */
+forop(r)
+       int *r;
+{
+       register struct nl *t1, *t2;
+       int l1, l2, l3;
+       long soffset;
+       register op;
+       struct nl *p;
+       int *rr, goc, i;
+
+       p = NIL;
+       goc = gocnt;
+       if (r == NIL)
+               goto aloha;
+       putline();
+       /*
+        * Start with assignment
+        * of initial value to for variable
+        */
+       t1 = asgnop1(r[2], NIL);
+       if (t1 == NIL) {
+               rvalue(r[3], NIL);
+               statement(r[4]);
+               goto aloha;
+       }
+       rr = r[2];              /* Assignment */
+       rr = rr[2];             /* Lhs variable */
+       if (rr[3] != NIL) {
+               error("For variable must be unqualified");
+               rvalue(r[3], NIL);
+               statement(r[4]);
+               goto aloha;
+       }
+       p = lookup(rr[2]);
+       p->value[NL_FORV] = 1;
+       if (isnta(t1, "bcis")) {
+               error("For variables cannot be %ss", nameof(t1));
+               statement(r[4]);
+               goto aloha;
+       }
+       /*
+        * Allocate automatic
+        * space for limit variable
+        */
+       sizes[cbn].om_off -= 4;
+#      ifdef PPC
+           putlbracket();
+#      endif
+       if (sizes[cbn].om_off < sizes[cbn].om_max)
+               sizes[cbn].om_max = sizes[cbn].om_off;
+       i = sizes[cbn].om_off;
+       /*
+        * Initialize the limit variable
+        */
+       put2(O_LV | cbn<<9, i);
+       t2 = rvalue(r[3], NIL);
+       if (incompat(t2, t1, r[3])) {
+               cerror("Limit type clashed with index type in 'for' statement");
+               statement(r[4]);
+               goto aloha;
+       }
+       put1(width(t2) <= 2 ? O_AS24 : O_AS4);
+#      ifdef PPC
+           putexpr();
+#      endif
+       /*
+        * See if we can skip the loop altogether
+        */
+       rr = r[2];
+       if (rr != NIL)
+               rvalue(rr[2], NIL);
+       put2(O_RV4 | cbn<<9, i);
+       gen(NIL, r[0] == T_FORU ? T_LE : T_GE, width(t1), 4);
+       /*
+        * L1 will be patched to skip the body of the loop.
+        * L2 marks the top of the loop when we go around.
+        */
+       put2(O_IF, (l1 = getlab()));
+       putlab(l2 = getlab());
+       putcnt();
+       statement(r[4]);
+       /*
+        * now we see if we get to go again
+        */
+       if (opt('t') == 0) {
+               /*
+                * Easy if we dont have to test
+                */
+               put2(O_RV4 | cbn<<9, i);
+               if (rr != NIL)
+                       lvalue(rr[2], MOD);
+               put2((r[0] == T_FORU ? O_FOR1U : O_FOR1D) + (width(t1) >> 1), l2);
+       } else {
+               line = r[1];
+               putline();
+               if (rr != NIL)
+                       rvalue(rr[2], NIL);
+               put2(O_RV4 | cbn << 9, i);
+               gen(NIL, (r[0] == T_FORU ? T_LT : T_GT), width(t1), 4);
+               l3 = put2(O_IF, getlab());
+               lvalue((int *) rr[2], MOD);
+               rvalue(rr[2], NIL);
+               put2(O_CON2, 1);
+               t2 = gen(NIL, r[0] == T_FORU ? T_ADD: T_SUB, width(t1), 2);
+               rangechk(t1, t2);       /* The point of all this */
+               gen(O_AS2, O_AS2, width(t1), width(t2));
+               put2(O_TRA, l2);
+               patch(l3);
+       }
+       sizes[cbn].om_off += 4;
+#      ifdef PPC
+           putlbracket();
+#      endif
+       patch(l1);
+aloha:
+       noreach = 0;
+       if (p != NIL)
+               p->value[NL_FORV] = 0;
+       if (goc != gocnt)
+               putcnt();
+}
+
+/*
+ * if expr then stat [ else stat ]
+ */
+ifop(r)
+       int *r;
+{
+       register struct nl *p;
+       register l1, l2;
+       int nr, goc;
+
+       goc = gocnt;
+       if (r == NIL)
+               return;
+       putline();
+       p = rvalue(r[2], NIL);
+       if (p == NIL) {
+               statement(r[3]);
+               noreach = 0;
+               statement(r[4]);
+               noreach = 0;
+               return;
+       }
+       if (isnta(p, "b")) {
+               error("Type of expression in if statement must be Boolean, not %s", nameof(p));
+               statement(r[3]);
+               noreach = 0;
+               statement(r[4]);
+               noreach = 0;
+               return;
+       }
+       l1 = put2(O_IF, getlab());
+       putcnt();
+       statement(r[3]);
+       nr = noreach;
+       if (r[4] != NIL) {
+               /*
+                * else stat
+                */
+               --level;
+               ungoto();
+               ++level;
+               l2 = put2(O_TRA, getlab());
+               patch(l1);
+               noreach = 0;
+               statement(r[4]);
+               noreach &= nr;
+               l1 = l2;
+       } else
+               noreach = 0;
+       patch(l1);
+       if (goc != gocnt)
+               putcnt();
+}
+
+/*
+ * while expr do stat
+ */
+whilop(r)
+       int *r;
+{
+       register struct nl *p;
+       register l1, l2;
+       int goc;
+
+       goc = gocnt;
+       if (r == NIL)
+               return;
+       putlab(l1 = getlab());
+       putline();
+       p = rvalue(r[2], NIL);
+       if (p == NIL) {
+               statement(r[3]);
+               noreach = 0;
+               return;
+       }
+       if (isnta(p, "b")) {
+               error("Type of expression in while statement must be Boolean, not %s", nameof(p));
+               statement(r[3]);
+               noreach = 0;
+               return;
+       }
+       put2(O_IF, (l2 = getlab()));
+       putcnt();
+       statement(r[3]);
+       put2(O_TRA, l1);
+       patch(l2);
+       if (goc != gocnt)
+               putcnt();
+}
+
+/*
+ * repeat stat* until expr
+ */
+repop(r)
+       int *r;
+{
+       register struct nl *p;
+       register l;
+       int goc;
+
+       goc = gocnt;
+       if (r == NIL)
+               return;
+       l = putlab(getlab());
+       putcnt();
+       statlist(r[2]);
+       line = r[1];
+       p = rvalue(r[3], NIL);
+       if (p == NIL)
+               return;
+       if (isnta(p,"b")) {
+               error("Until expression type must be Boolean, not %s, in repeat statement", nameof(p));
+               return;
+       }
+       put2(O_IF, l);
+       if (goc != gocnt)
+               putcnt();
+}
+
+/*
+ * assert expr
+ */
+asrtop(r)
+       register int *r;
+{
+       register struct nl *q;
+
+       if (opt('s')) {
+               standard();
+               error("Assert statement is non-standard");
+       }
+       if (!opt('t'))
+               return;
+       r = r[2];
+       q = rvalue((int *) r, NLNIL);
+       if (q == NIL)
+               return;
+       if (isnta(q, "b"))
+               error("Assert expression must be Boolean, not %ss", nameof(q));
+       put1(O_ASRT);
+}
diff --git a/usr/src/cmd/pi/string.c b/usr/src/cmd/pi/string.c
new file mode 100644 (file)
index 0000000..31f05c7
--- /dev/null
@@ -0,0 +1,160 @@
+/* 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 "whoami"
+#include "0.h"
+#ifndef PI01
+#ifndef PXP
+#include "send.h"
+#endif
+#endif
+
+/*
+ * STRING SPACE DECLARATIONS
+ *
+ * Strng is the base of the current
+ * string space and strngp the
+ * base of the free area therein.
+ * Strp is the array of descriptors.
+ */
+#ifndef PI0
+STATIC char strings[STRINC];
+STATIC char *strng = strings;
+STATIC char *strngp = strings;
+#else
+char   *strng, *strngp;
+#endif
+#ifndef PI01
+#ifndef PXP
+STATIC char *strp[20];
+STATIC char **stract strp;
+int    strmax;
+#endif
+#endif
+
+#ifndef PI01
+#ifndef PXP
+#ifndef PI0
+initstring()
+#else
+initstring(strings)
+       char *strings;
+#endif
+{
+
+       *stract++ = strings;
+#ifdef PI0
+       strng = strngp = strings;
+#endif
+       strmax = STRINC * 2;
+}
+#endif
+#endif
+
+/*
+ * Copy a string into the string area.
+ */
+char *
+savestr(cp)
+       register char *cp;
+{
+       register int i;
+
+       i = strlen(cp) + 1;
+       if (strngp + i >= strng + STRINC) {
+               strngp = malloc(STRINC);
+               if (strngp == -1) {
+                       yerror("Ran out of memory (string)");
+                       pexit(DIED);
+               }
+#ifndef PI01
+#ifndef PXP
+               *stract++ = strngp;
+               strmax =+ STRINC;
+#endif
+#endif
+               strng = strngp;
+       }
+       strcpy(strngp, cp);
+       cp = strngp;
+       strngp = cp + i;
+#ifdef PI0
+       send(RSTRING, cp);
+#endif
+       return (cp);
+}
+
+#ifndef PI1
+#ifndef PXP
+esavestr(cp)
+       char *cp;
+{
+
+#ifdef PI0
+       send(REVENIT);
+#endif
+       strngp = ( (char *) ( ( (int) (strngp + 1) ) &~ 1 ) );
+       return (savestr(cp));
+}
+#endif
+#endif
+
+#ifndef PI01
+#ifndef PXP
+soffset(cp)
+       register char *cp;
+{
+       register char **sp;
+       register int i;
+
+       if (cp == NIL || cp == OCT || cp == HEX)
+               return (-cp);
+       for (i = STRINC, sp = strp; sp < stract; sp++) {
+               if (cp >= *sp && cp < (*sp + STRINC))
+                       return (i + (cp - *sp));
+               i =+ STRINC;
+       }
+       i = nlfund(cp);
+       if (i != 0)
+               return (i);
+       panic("soffset");
+}
+#ifdef PI1
+sreloc(i)
+       register int i;
+{
+
+       if (i == 0 || i == -OCT || i == -HEX)
+               return (-i);
+       if (i < STRINC) {
+               if (i >= INL)
+                       panic("sreloc INL");
+               i = nl[i].symbol;
+               if (i == 0)
+                       panic("sreloc nl[i]");
+               return (i);
+       }
+       if (i > strmax || i < 0)
+               panic("sreloc");
+       return (strp[(i / STRINC) - 1] + (i % STRINC));
+}
+
+evenit()
+{
+
+       strngp = (strngp + 1) &~ 1;
+}
+#endif
+#endif
+#endif
diff --git a/usr/src/cmd/pi/subr.c b/usr/src/cmd/pi/subr.c
new file mode 100644 (file)
index 0000000..4aa269f
--- /dev/null
@@ -0,0 +1,221 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#include "whoami"
+/*
+ * 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"
+
+#ifndef PI1
+/*
+ * Does the string fp end in '.' and the character c ?
+ */
+dotted(fp, c)
+       register char *fp;
+       char c;
+{
+       register int i;
+
+       i = strlen(fp);
+       return (i > 1 && fp[i - 2] == '.' && fp[i - 1] == c);
+}
+
+/*
+ * Toggle the option c.
+ */
+togopt(c)
+       char c;
+{
+       register char *tp;
+
+       tp = &opts[c-'a'];
+       *tp = 1 - *tp;
+}
+
+/*
+ * Set the time vector "tvec" to the
+ * modification time stamp of a file.
+ */
+gettime( filename )
+    char *filename;
+{
+#include <stat.h>
+       struct stat stb;
+
+       stat(filename, &stb);
+       tvec = stb.st_mtime;
+}
+
+/*
+ * Convert a "ctime" into a Pascal styple time line
+ */
+char *
+myctime(tv)
+       int *tv;
+{
+       register char *cp, *dp;
+       char *cpp;
+       register i;
+       static char mycbuf[26];
+
+       cpp = ctime(tv);
+       dp = mycbuf;
+       cp = cpp;
+       cpp[16] = 0;
+       while (*dp++ = *cp++);
+       dp--;
+       cp = cpp+19;
+       cpp[24] = 0;
+       while (*dp++ = *cp++);
+       return (mycbuf);
+}
+
+/*
+ * Is "fp" in the command line list of names ?
+ */
+inpflist(fp)
+       char *fp;
+{
+       register i, *pfp;
+
+       pfp = pflist;
+       for (i = pflstc; i > 0; i--)
+               if (strcmp(fp, *pfp++) == 0)
+                       return (1);
+       return (0);
+}
+#endif
+
+extern int errno;
+extern char *sys_errlist[];
+
+/*
+ * Boom!
+ */
+Perror(file, error)
+       char *file, *error;
+{
+
+       errno = 0;
+       sys_errlist[0] = error;
+       perror(file);
+}
+
+int *
+calloc(num, size)
+       int num, size;
+{
+       register int p1, *p2, nbyte;
+
+       nbyte = (num*size+( ( sizeof ( int ) ) - 1 ) ) & ~( ( sizeof ( int ) ) - 1 );
+       if ((p1 = malloc(nbyte)) == -1 || p1==0)
+               return (-1);
+       p2 = p1;
+       nbyte /= sizeof ( int );
+       do {
+               *p2++ = 0;
+       } while (--nbyte);
+       return (p1);
+}
+
+/*
+ * Compare strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
+ */
+strcmp(s1, s2)
+       register char *s1, *s2;
+{
+
+       while (*s1 == *s2++)
+               if (*s1++=='\0')
+                       return (0);
+       return (*s1 - *--s2);
+}
+
+/*
+ * Copy string s2 to s1.
+ * S1 must be large enough.
+ * Return s1.
+ */
+strcpy(s1, s2)
+       register char *s1, *s2;
+{
+       register os1;
+
+       os1 = s1;
+       while (*s1++ = *s2++)
+               continue;
+       return (os1);
+}
+
+/*
+ * Strlen is currently a freebie of perror
+ * Take the length of a string.
+ * Note that this does not include the trailing null!
+strlen(cp)
+       register char *cp;
+{
+       register int i;
+
+       for (i = 0; *cp != 0; cp++)
+               i++;
+       return (i);
+}
+ */
+copy(to, from, bytes)
+       register char *to, *from;
+       register int bytes;
+{
+
+       if (bytes != 0)
+               do
+                       *to++ = *from++;
+               while (--bytes);
+}
+
+/*
+ * Is ch one of the characters in the string cp ?
+ */
+any(cp, ch)
+       register char *cp;
+       char ch;
+{
+
+       while (*cp)
+               if (*cp++ == ch)
+                       return (1);
+       return (0);
+}
+
+opush(c)
+       register CHAR c;
+{
+
+       c -= 'a';
+       optstk[c] <<= 1;
+       optstk[c] |= opts[c];
+       opts[c] = 1;
+#ifdef PI0
+       send(ROPUSH, c);
+#endif
+}
+
+opop(c)
+       register CHAR c;
+{
+
+       c -= 'a';
+       opts[c] = optstk[c] & 1;
+       optstk[c] >>= 1;
+#ifdef PI0
+       send(ROPOP, c);
+#endif
+}
diff --git a/usr/src/cmd/pi/tCopy.c b/usr/src/cmd/pi/tCopy.c
new file mode 100644 (file)
index 0000000..8199999
--- /dev/null
@@ -0,0 +1,298 @@
+    /*
+     * tCopy.c
+     *
+     * functions to copy pi trees to pTrees
+     */
+
+#include       "whoami"
+
+#ifdef PTREE
+
+#include       "0.h"
+
+#include       "tree.h"
+
+    /*
+     * tCopy
+     * a mongo switch statement to farm out the actual copying 
+     * to the appropriate routines.
+     * given a pointer to a pi tree branch, it returns a pPointer to
+     * a pTree copy of that branch.
+     */
+pPointer
+tCopy( node )
+    int        *node;
+    {
+
+       if ( node == NIL )
+           return pNIL;
+       switch ( node[ 0 ] ) {
+           case T_PROG:        
+           case T_PDEC:
+           case T_FDEC:        
+               return PorFCopy( node );
+           case T_TYPTR:
+               return PtrTCopy( node );
+           case T_TYPACK:
+               return PackTCopy( node );
+           case T_TYSCAL:
+               return EnumTCopy( node );
+           case T_TYRANG:
+               return RangeTCopy( node );
+           case T_TYARY:
+               return ArrayTCopy( node );
+           case T_TYFILE:
+               return FileTCopy( node );
+           case T_TYSET:
+               return SetTCopy( node );
+           case T_TYREC:
+               return RecTCopy( node );
+           case T_FLDLST:
+               return FldlstCopy( node );
+           case T_RFIELD:
+               return FieldCopy( node );
+           case T_TYVARPT:
+               return VarntCopy( node );
+           case T_TYVARNT:
+               return VCaseCopy( node );
+           case T_CSTAT:
+               return CasedCopy( node );
+           case T_PVAL:
+           case T_PVAR:
+               return ParamCopy( node );
+           case T_CSTRNG:
+               return sCopy( node[1] );
+           case T_STRNG:
+               return sCopy( node[2] );
+           case T_PLUSC:
+           case T_PLUS:
+           case T_MINUSC:
+           case T_MINUS:
+           case T_NOT:
+               return UnOpCopy( node );
+           case T_ID:
+               return ThreadSymbol( node[1] );
+           case T_TYID:
+               return ThreadSymbol( node[2] );
+           case T_CINT:
+           case T_CBINT:
+               return iCopy( node[1] );
+           case T_INT:
+           case T_BINT:
+               return iCopy( node[2] );
+           case T_CFINT:
+               return fCopy( node[1] );
+           case T_FINT:
+               return fCopy( node[2] );
+           case T_LISTPP:
+               return ListCopy( node );
+           case T_PCALL:
+               return PCallCopy( node );
+           case T_BLOCK:
+           case T_BSTL:
+               return ListCopy( node[2] );
+           case T_CASE:
+               return CaseSCopy( node );
+           case T_WITH:
+               return WithCopy( node );
+           case T_WHILE:
+               return WhileCopy( node );
+           case T_REPEAT:
+               return RepeatCopy( node );
+           case T_FORU:
+           case T_FORD:
+               return ForCopy( node );
+           case T_IF:
+           case T_IFEL:
+               return IfCopy( node );
+           case T_GOTO:
+               return GotoCopy( node );
+           case T_LABEL:
+               return LabelCopy( node );
+           case T_ASRT:
+               return AssertCopy( node );
+           case T_ASGN:
+               return AssignCopy( node );
+           case T_NIL:
+               return NilCopy( node );
+           case T_FCALL:
+               return FCallCopy( node );
+           case T_CSET:
+               return SetCopy( node );
+           case T_RANG:
+               return RangeCopy( node );
+           case T_VAR:
+               return VarCopy( node );
+           case T_ARY:
+               return SubscCopy( node );
+           case T_FIELD:
+               return SelCopy( node );
+           case T_PTR:
+               return PtrCopy( node );
+           case T_EQ:
+           case T_LT:
+           case T_GT:
+           case T_LE:
+           case T_GE:
+           case T_NE:
+           case T_IN:
+           case T_ADD:
+           case T_SUB:
+           case T_MULT:
+           case T_DIVD:
+           case T_DIV:
+           case T_MOD:
+           case T_OR:
+           case T_AND:
+               return BinOpCopy( node );
+           case T_WEXP:
+               return WidthCopy( node );
+           default:
+               panic("tCopy");
+       }
+    }
+
+\f
+    /*
+     * copy a list of nodes into ListNodes
+     * (with a hack for appending one list to another
+     *     for example: labelled statements)
+     * listnode[0]     T_LISTPP
+     *         [1]     "list_element"
+     *         [2]     "list_next"
+     */
+pPointer
+ListCopy( listnode )
+    int        *listnode;
+    {
+       pPointer        First;
+       pPointer        After;
+       int             *listp;
+       pPointer        Item;
+       pPointer        List;
+       pPointer        Furthur;
+
+       First = pNIL;
+       After = pNIL;
+       for ( listp = listnode ; listp != NIL ; listp = (int *) listp[2] ) {
+           List = pNewNode( ListTAG , sizeof( struct ListNode ) );
+           if ( First == pNIL )
+               First = List;
+           Item = tCopy( listp[1] );
+           pDEF( List ).ListItem = Item;
+           pDEF( List ).ListDown = pNIL;
+           pDEF( List ).ListUp = After;
+           if ( After != pNIL )
+               pDEF( After ).ListDown = List;
+           After = List;
+           /*
+            *  if ListItem is a ListNode whose ListUp is non-pNIL
+            *  append that list to this list, using that ListUp
+            *  as an additional ListItem.
+            */
+           Furthur = Item;
+           if (  Furthur != pNIL
+              && pTAG( Furthur ) == ListTAG
+              && pUSE( Furthur ).ListUp != pNIL ) {
+               Item = pUSE( Furthur ).ListUp;
+               pDEF( List ).ListItem = Item;
+               pDEF( Furthur ).ListUp = List;
+               pDEF( List ).ListDown = Furthur;
+               do {
+                   After = Furthur;
+                   Furthur = pUSE( After ).ListDown;
+               } while ( Furthur != pNIL );
+           }
+       }
+       return First;
+    }
+
+    /*
+     * ListAppend
+     * append a random item to the end of a list
+     * (with a hack for appending one list to another
+     *  e.g. labelled statments)
+     */
+pPointer
+ListAppend( list , item )
+    pPointer   list;
+    pPointer   item;
+    {
+       pPointer        List = pNewNode( ListTAG , sizeof( struct ListNode ) );
+       pPointer        First;
+       pPointer        After;
+       pPointer        Furthur;
+
+       pDEF( List ).ListItem = item;
+       pDEF( List ).ListDown = pNIL;
+       First = After = list;
+       if ( First == pNIL ) {
+               First = List;
+       } else {
+               while ( ( Furthur = pUSE( After ).ListDown ) != pNIL )
+                   After = Furthur;
+               pDEF( After ).ListDown = List;
+       }
+       pDEF( List ).ListUp = After;
+       /*
+        *      if item is a ListNode whose ListUp is non-pNIL
+        *      append that list to this list, using that ListUp
+        *      as an additional ListItem.
+        */
+       Furthur = item;
+       if (  Furthur != pNIL
+          && pTAG( Furthur ) == ListTAG
+          && pUSE( Furthur ).ListUp != pNIL ) {
+           pDEF( List ).ListDown = Furthur;
+           pDEF( List ).ListItem = pUSE( Furthur ).ListUp;
+           pDEF( Furthur ).ListUp = List;
+       }
+       return First;
+    }
+
+    /*
+     * iCopy
+     * copy an integer (string) to an IntNode
+     */
+pPointer
+iCopy( intstring )
+    char *intstring;
+    {
+       pPointer        Int = pNewNode( IntTAG , sizeof( struct IntNode ) );
+
+       pDEF( Int ).IntValue = atol( intstring );
+       return Int;
+    }
+
+    /*
+     * fCopy
+     * copy a float (string) to a RealNode
+     */
+pPointer
+fCopy( realstring )
+    char *realstring;
+    {
+       pPointer        Real = pNewNode( RealTAG , sizeof( struct RealNode ) );
+
+       pDEF( Real ).RealValue = atof( realstring );
+       return Real;
+    }
+
+    /*
+     * sCopy
+     * copy a string to a StringNode
+     */
+pPointer
+sCopy( string )
+    char *string;
+    {
+       pPointer        String;
+
+       if ( string == NIL )
+           return pNIL;
+       String = pNewNode( StringTAG , strlen( string ) + 1 );
+       strcpy( pDEF( String ).StringValue , string );
+       return String;
+    }
+
+#endif PTREE
diff --git a/usr/src/cmd/pi/tree.c b/usr/src/cmd/pi/tree.c
new file mode 100644 (file)
index 0000000..16f90c3
--- /dev/null
@@ -0,0 +1,190 @@
+/* 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 "whoami"
+#include "0.h"
+
+/*
+ * TREE SPACE DECLARATIONS
+ */
+struct tr {
+       int     *tr_low;
+       int     *tr_high;
+} ttab[MAXTREE], *tract;
+
+/*
+ * The variable space is the
+ * absolute base of the tree segments.
+ * (exactly the same as ttab[0].tr_low)
+ * Spacep is maintained to point at the
+ * beginning of the next tree slot to
+ * be allocated for use by the grammar.
+ * Spacep is used "extern" by the semantic
+ * actions in pas.y.
+ * The variable tract is maintained to point
+ * at the tree segment out of which we are
+ * allocating (the active segment).
+ */
+int    *space, *spacep;
+
+/*
+ * TREENMAX is the maximum width
+ * in words that any tree node 
+ * due to the way in which the parser uses
+ * the pointer spacep.
+ */
+#define        TREENMAX        6
+
+int    trspace[ITREE];
+int    *space  = trspace;
+int    *spacep = trspace;
+struct tr *tract       = ttab;
+
+/*
+ * Inittree allocates the first tree slot
+ * and sets up the first segment descriptor.
+ * A lot of this work is actually done statically
+ * above.
+ */
+inittree()
+{
+
+       ttab[0].tr_low = space;
+       ttab[0].tr_high = &space[ITREE];
+}
+
+/*
+ * Tree builds the nodes in the
+ * parse tree. It is rarely called
+ * directly, rather calls are made
+ * to tree[12345] which supplies the
+ * first argument to save space in
+ * the code. Tree also guarantees
+ * that spacep points to the beginning
+ * of the next slot it will return,
+ * a property required by the parser
+ * which was always true before we
+ * segmented the tree space.
+ */
+int *tree(cnt, a)
+       int cnt;
+{
+       register int *p, *q;
+       register int i;
+
+       i = cnt;
+       p = spacep;
+       q = &a;
+       do
+               *p++ = *q++;
+       while (--i);
+       q = spacep;
+       spacep = p;
+       if (p+TREENMAX >= tract->tr_high)
+               /*
+                * this peek-ahead should
+                * save a great number of calls
+                * to tralloc.
+                */
+               tralloc(TREENMAX);
+       return (q);
+}
+
+/*
+ * Tralloc preallocates enough
+ * space in the tree to allow
+ * the grammar to use the variable
+ * spacep, as it did before the
+ * tree was segmented.
+ */
+tralloc(howmuch)
+{
+       register char *cp;
+       register i;
+
+       if (spacep + howmuch >= tract->tr_high) {
+               i = TRINC;
+               cp = malloc(i * sizeof ( int ));
+               if (cp == -1) {
+                       yerror("Ran out of memory (tralloc)");
+                       pexit(DIED);
+               }
+               spacep = cp;
+               tract++;
+               if (tract >= &ttab[MAXTREE]) {
+                       yerror("Ran out of tree tables");
+                       pexit(DIED);
+               }
+               tract->tr_low = cp;
+               tract->tr_high = tract->tr_low+i;
+       }
+}
+
+extern int yylacnt;
+extern bottled;
+#ifdef PXP
+#endif
+/*
+ * Free up the tree segments
+ * at the end of a block.
+ * If there is scanner lookahead,
+ * i.e. if yylacnt != 0 or there is bottled output, then we
+ * cannot free the tree space.
+ * This happens only when errors
+ * occur and the forward move extends
+ * across "units".
+ */
+trfree()
+{
+
+       if (yylacnt != 0 || bottled != NIL)
+               return;
+#ifdef PXP
+       if (needtree())
+               return;
+#endif
+       spacep = space;
+       while (tract->tr_low > spacep || tract->tr_high <= spacep) {
+               free(tract->tr_low);
+               tract->tr_low = NIL;
+               tract->tr_high = NIL;
+               tract--;
+               if (tract < ttab)
+                       panic("ttab");
+       }
+#ifdef PXP
+       packtree();
+#endif
+}
+
+/*
+ * Copystr copies a token from
+ * the "token" buffer into the
+ * tree space.
+ */
+copystr(token)
+       register char *token;
+{
+       register char *cp;
+       register int i;
+
+       i = (strlen(token) + sizeof ( int )) & ~( ( sizeof ( int ) ) - 1 );
+       tralloc(i / sizeof ( int ));
+       strcpy(spacep, token);
+       cp = spacep;
+       spacep = cp + i;
+       tralloc(TREENMAX);
+       return (cp);
+}
diff --git a/usr/src/cmd/pi/tree.h b/usr/src/cmd/pi/tree.h
new file mode 100644 (file)
index 0000000..4e636ac
--- /dev/null
@@ -0,0 +1,81 @@
+#define T_MINUS 1
+#define T_MOD 2
+#define T_DIV 3
+#define T_DIVD 4
+#define T_MULT 5
+#define T_ADD 6
+#define T_SUB 7
+#define T_EQ 8
+#define T_NE 9
+#define T_LT 10
+#define T_GT 11
+#define T_LE 12
+#define T_GE 13
+#define T_NOT 14
+#define T_AND 15
+#define T_OR 16
+#define T_ASGN 17
+#define T_PLUS 18
+#define T_IN 19
+#define T_LISTPP 20
+#define T_PDEC 21
+#define T_FDEC 22
+#define T_PVAL 23
+#define T_PVAR 24
+#define T_PFUNC 25
+#define T_PPROC 26
+#define T_NIL 27
+#define T_STRNG 28
+#define T_CSTRNG 29
+#define T_PLUSC 30
+#define T_MINUSC 31
+#define T_ID 32
+#define T_INT 33
+#define T_FINT 34
+#define T_CINT 35
+#define T_CFINT 36
+#define T_TYPTR 37
+#define T_TYPACK 38
+#define T_TYSCAL 39
+#define T_TYRANG 40
+#define T_TYARY 41
+#define T_TYFILE 42
+#define T_TYSET 43
+#define T_TYREC 44
+#define T_TYFIELD 45
+#define T_TYVARPT 46
+#define T_TYVARNT 47
+#define T_CSTAT 48
+#define T_BLOCK 49
+#define T_BSTL 50
+#define T_LABEL 51
+#define T_PCALL 52
+#define T_FCALL 53
+#define T_CASE 54
+#define T_WITH 55
+#define T_WHILE 56
+#define T_REPEAT 57
+#define T_FORU 58
+#define T_FORD 59
+#define T_GOTO 60
+#define T_IF 61
+#define T_ASRT 62
+#define T_CSET 63
+#define T_RANG 64
+#define T_VAR 65
+#define T_ARGL 66
+#define T_ARY 67
+#define T_FIELD 68
+#define T_PTR 69
+#define T_WEXP 70
+#define T_PROG 71
+#define T_BINT 72
+#define T_CBINT 73
+#define T_IFEL 74
+#define T_IFX 75
+#define T_TYID 76
+#define T_COPSTR 77
+#define T_BOTTLE 78
+#define T_RFIELD 79
+#define T_FLDLST 80
+#define T_LAST 81
diff --git a/usr/src/cmd/pi/treen.c b/usr/src/cmd/pi/treen.c
new file mode 100644 (file)
index 0000000..8649ed3
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (c) 1979 Regents of the University of California */
+    /*
+     * is there some reason why these aren't #defined?
+     */
+
+tree1 ( arg1 )
+    int                arg1;
+    {
+       tree ( 1 , arg1 );
+    }
+
+tree2 ( arg1 , arg2 )
+    int                arg1 , arg2;
+    {
+       tree ( 2 , arg1 , arg2 );
+    }
+
+tree3 ( arg1 , arg2 , arg3 )
+    int                arg1 , arg2 , arg3;
+    {
+       tree ( 3 , arg1 , arg2 , arg3 );
+    }
+
+tree4 ( arg1 , arg2 , arg3 , arg4 )
+    int                arg1 , arg2 , arg3 , arg4;
+    {
+       tree ( 4 , arg1 , arg2 , arg3 , arg4 );
+    }
+
+tree5 ( arg1 , arg2 , arg3 , arg4 , arg5 )
+    int                arg1 , arg2 , arg3 , arg4 , arg5;
+    {
+       tree ( 5 , arg1 , arg2 , arg3 , arg4 , arg5 );
+    }
+