home *** CD-ROM | disk | FTP | other *** search
- /* 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 "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.
- */
- 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->value[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);
- }
- put3(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;
- put3(O_CON4, l);
- } else
- put(5, O_CON8, p->real);
- #endif
- break;
- case 4:
- put3(O_CON4, p->range[0]);
- break;
- case 2:
- put2(O_CON2, p->value[1]);
- 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(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, NIL, 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, c=l);
- return (nl+T2INT);
- }
- put3(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);
- }
-