148093Sbostic /*-
2*62149Sbostic * Copyright (c) 1980, 1993
3*62149Sbostic * The Regents of the University of California. All rights reserved.
448093Sbostic *
548093Sbostic * %sccs.include.redist.c%
622528Sdist */
75531Slinton
822528Sdist #ifndef lint
9*62149Sbostic static char sccsid[] = "@(#)tree.c 8.1 (Berkeley) 06/06/93";
1048093Sbostic #endif /* not lint */
115531Slinton
125531Slinton /*
135531Slinton * This module contains the interface between the SYM routines and
145531Slinton * the parse tree routines. It would be nice if such a crude
155531Slinton * interface were not necessary, but some parts of tree building are
165531Slinton * language and hence SYM-representation dependent. It's probably
175531Slinton * better to have tree-representation dependent code here than vice versa.
185531Slinton */
195531Slinton
205531Slinton #include "defs.h"
215531Slinton #include "tree.h"
225531Slinton #include "sym.h"
235531Slinton #include "btypes.h"
245531Slinton #include "classes.h"
255531Slinton #include "sym.rep"
265531Slinton #include "tree/tree.rep"
275531Slinton
285531Slinton typedef char *ARGLIST;
295531Slinton
305783Slinton #define nextarg(arglist, type) ((type *) (arglist += sizeof(type)))[-1]
315531Slinton
325531Slinton LOCAL SYM *mkstring();
335531Slinton LOCAL SYM *namenode();
345531Slinton
355531Slinton /*
365531Slinton * Determine the type of a parse tree. While we're at, check
375531Slinton * the parse tree out.
385531Slinton */
395531Slinton
treetype(p,ap)405531Slinton SYM *treetype(p, ap)
415531Slinton register NODE *p;
425531Slinton register ARGLIST ap;
435531Slinton {
445783Slinton switch(p->op) {
455783Slinton case O_NAME: {
465783Slinton SYM *s;
475531Slinton
485783Slinton s = nextarg(ap, SYM *);
495783Slinton s = which(s);
505783Slinton return namenode(p, s);
515783Slinton /* NOTREACHED */
525783Slinton }
535531Slinton
545783Slinton case O_WHICH:
555783Slinton p->nameval = nextarg(ap, SYM *);
565783Slinton p->nameval = which(p->nameval);
575783Slinton return NIL;
585531Slinton
595783Slinton case O_LCON:
605783Slinton return t_int;
615531Slinton
625783Slinton case O_FCON:
635783Slinton return t_real;
645531Slinton
655783Slinton case O_SCON: {
665783Slinton char *cpy;
675783Slinton SYM *s;
685531Slinton
695783Slinton cpy = strdup(p->sconval);
705783Slinton p->sconval = cpy;
715783Slinton s = mkstring(p->sconval);
725783Slinton if (s == t_char) {
735783Slinton p->op = O_LCON;
745783Slinton p->lconval = p->sconval[0];
755783Slinton }
765783Slinton return s;
775783Slinton }
785531Slinton
795783Slinton case O_INDIR:
805783Slinton p->left = nextarg(ap, NODE *);
815783Slinton chkclass(p->left, PTR);
825783Slinton return rtype(p->left->nodetype)->type;
835531Slinton
845783Slinton case O_RVAL: {
8530850Smckusick NODE *p1;
865531Slinton
875783Slinton p1 = p->left;
885783Slinton p->nodetype = p1->nodetype;
895783Slinton if (p1->op == O_NAME) {
905783Slinton if (p1->nodetype->class == FUNC) {
915783Slinton p->op = O_CALL;
925783Slinton p->right = NIL;
935783Slinton } else if (p1->nameval->class == CONST) {
945783Slinton if (p1->nameval->type == t_real->type) {
955783Slinton p->op = O_FCON;
965783Slinton p->fconval = p1->nameval->symvalue.fconval;
975783Slinton p->nodetype = t_real;
985783Slinton dispose(p1);
995783Slinton } else {
1005783Slinton p->op = O_LCON;
1015783Slinton p->lconval = p1->nameval->symvalue.iconval;
1025783Slinton p->nodetype = p1->nameval->type;
1035783Slinton dispose(p1);
1045783Slinton }
1055531Slinton }
1065783Slinton }
1075783Slinton return p->nodetype;
1085783Slinton /* NOTREACHED */
1095783Slinton }
1105531Slinton
1115783Slinton case O_CALL: {
1125783Slinton SYM *s;
1135531Slinton
1145783Slinton p->left = nextarg(ap, NODE *);
1155783Slinton p->right = nextarg(ap, NODE *);
1165783Slinton s = p->left->nodetype;
1175783Slinton if (isblock(s) && isbuiltin(s)) {
1185783Slinton p->op = (OP) s->symvalue.token.tokval;
1195783Slinton tfree(p->left);
1205783Slinton p->left = p->right;
1215783Slinton p->right = NIL;
1225783Slinton }
1235783Slinton return s->type;
1245783Slinton }
1255531Slinton
1265783Slinton case O_ITOF:
1275783Slinton return t_real;
1285531Slinton
1295783Slinton case O_NEG: {
1305783Slinton SYM *s;
1315531Slinton
1325783Slinton p->left = nextarg(ap, NODE *);
1335783Slinton s = p->left->nodetype;
1345783Slinton if (!compatible(s, t_int)) {
1355783Slinton if (!compatible(s, t_real)) {
1365783Slinton trerror("%t is improper type", p->left);
1375783Slinton } else {
1385783Slinton p->op = O_NEGF;
1395531Slinton }
1405783Slinton }
1415783Slinton return s;
1425783Slinton }
1435531Slinton
1445783Slinton case O_ADD:
1455783Slinton case O_SUB:
1465783Slinton case O_MUL:
1475783Slinton case O_LT:
1485783Slinton case O_LE:
1495783Slinton case O_GT:
1505783Slinton case O_GE:
1515783Slinton case O_EQ:
1525783Slinton case O_NE:
1535783Slinton {
1545783Slinton BOOLEAN t1real, t2real;
1555783Slinton SYM *t1, *t2;
1565531Slinton
1575783Slinton p->left = nextarg(ap, NODE *);
1585783Slinton p->right = nextarg(ap, NODE *);
1595783Slinton t1 = rtype(p->left->nodetype);
1605783Slinton t2 = rtype(p->right->nodetype);
1615783Slinton t1real = (t1 == t_real);
1625783Slinton t2real = (t2 == t_real);
1635783Slinton if (t1real || t2real) {
1645783Slinton p->op++;
1655783Slinton if (!t1real) {
1665783Slinton p->left = build(O_ITOF, p->left);
1675783Slinton } else if (!t2real) {
1685783Slinton p->right = build(O_ITOF, p->right);
1695531Slinton }
1705783Slinton } else {
1715783Slinton if (t1real) {
1725783Slinton convert(&p->left, t_int, O_NOP);
1735783Slinton }
1745783Slinton if (t2real) {
1755783Slinton convert(&p->right, t_int, O_NOP);
1765783Slinton }
1775783Slinton }
1785783Slinton if (p->op >= O_LT) {
1795783Slinton return t_boolean;
1805783Slinton } else {
1815783Slinton if (t1real || t2real) {
1825783Slinton return t_real;
1835783Slinton } else {
1845783Slinton return t_int;
1855783Slinton }
1865783Slinton }
1875783Slinton /* NOTREACHED */
1885783Slinton }
1895531Slinton
1905783Slinton case O_DIVF:
1915783Slinton p->left = nextarg(ap, NODE *);
1925783Slinton p->right = nextarg(ap, NODE *);
1935783Slinton convert(&p->left, t_real, O_ITOF);
1945783Slinton convert(&p->right, t_real, O_ITOF);
1955783Slinton return t_real;
1965531Slinton
1975783Slinton case O_DIV:
1985783Slinton case O_MOD:
1995783Slinton p->left = nextarg(ap, NODE *);
2005783Slinton p->right = nextarg(ap, NODE *);
2015783Slinton convert(&p->left, t_int, O_NOP);
2025783Slinton convert(&p->right, t_int, O_NOP);
2035783Slinton return t_int;
2045531Slinton
2055783Slinton case O_AND:
2065783Slinton case O_OR:
2075783Slinton p->left = nextarg(ap, NODE *);
2085783Slinton p->right = nextarg(ap, NODE *);
2095783Slinton chkboolean(p->left);
2105783Slinton chkboolean(p->right);
2115783Slinton return t_boolean;
2125531Slinton
2135783Slinton default:
2145783Slinton return NIL;
2155783Slinton }
2165531Slinton }
2175531Slinton
2185531Slinton /*
2195531Slinton * Create a node for a name. The symbol for the name has already
2205531Slinton * been chosen, either implicitly with "which" or explicitly from
2215531Slinton * the dot routine.
2225531Slinton */
2235531Slinton
namenode(p,s)2245531Slinton LOCAL SYM *namenode(p, s)
2255531Slinton NODE *p;
2265531Slinton SYM *s;
2275531Slinton {
2285783Slinton NODE *np;
2295531Slinton
2305783Slinton p->nameval = s;
2315783Slinton if (s->class == REF) {
2325783Slinton np = alloc(1, NODE);
2335783Slinton *np = *p;
2345783Slinton p->op = O_INDIR;
2355783Slinton p->left = np;
2365783Slinton np->nodetype = s;
2375783Slinton }
2385783Slinton if (s->class == CONST || s->class == VAR || s->class == FVAR) {
2395783Slinton return s->type;
2405783Slinton } else {
2415783Slinton return s;
2425783Slinton }
2435531Slinton }
2445531Slinton
2455531Slinton /*
2465531Slinton * Convert a tree to a type via a conversion operator;
2475531Slinton * if this isn't possible generate an error.
2485531Slinton *
2495531Slinton * Note the tree is call by address, hence the #define below.
2505531Slinton */
2515531Slinton
convert(tp,typeto,op)2525531Slinton LOCAL convert(tp, typeto, op)
2535531Slinton NODE **tp;
2545531Slinton SYM *typeto;
2555531Slinton OP op;
2565531Slinton {
2575783Slinton #define tree (*tp)
2585531Slinton
2595783Slinton SYM *s;
2605531Slinton
2615783Slinton s = rtype(tree->nodetype);
2625783Slinton typeto = rtype(typeto);
2635783Slinton if (typeto == t_real && compatible(s, t_int)) {
2645783Slinton tree = build(op, tree);
2655783Slinton } else if (!compatible(s, typeto)) {
2665783Slinton trerror("%t is improper type");
2675783Slinton } else if (op != O_NOP && s != typeto) {
2685783Slinton tree = build(op, tree);
2695783Slinton }
2705531Slinton
2715531Slinton #undef tree
2725531Slinton }
2735531Slinton
2745531Slinton /*
2755531Slinton * Construct a node for the Pascal dot operator.
2765531Slinton *
2775531Slinton * If the left operand is not a record, but rather a procedure
2785531Slinton * or function, then we interpret the "." as referencing an
2795531Slinton * "invisible" variable; i.e. a variable within a dynamically
2805531Slinton * active block but not within the static scope of the current procedure.
2815531Slinton */
2825531Slinton
dot(record,field)2835531Slinton NODE *dot(record, field)
2845531Slinton NODE *record;
2855531Slinton SYM *field;
2865531Slinton {
2875783Slinton register NODE *p;
2885783Slinton register SYM *s;
2895531Slinton
2905783Slinton if (isblock(record->nodetype)) {
2915783Slinton s = findsym(field, record->nodetype);
2925783Slinton if (s == NIL) {
2935783Slinton error("\"%s\" is not defined in \"%s\"",
2945783Slinton field->symbol, record->nodetype->symbol);
2955531Slinton }
2965783Slinton p = alloc(1, NODE);
2975783Slinton p->op = O_NAME;
2985783Slinton p->nodetype = namenode(p, s);
2995783Slinton } else {
3005783Slinton s = findclass(field, FIELD);
3015783Slinton if (s == NIL) {
3025783Slinton error("\"%s\" is not a field", field->symbol);
3035783Slinton }
3045783Slinton field = s;
3055783Slinton chkfield(record, field);
3065783Slinton p = alloc(1, NODE);
3075783Slinton p->op = O_ADD;
3085783Slinton p->nodetype = field->type;
3095783Slinton p->left = record;
3105783Slinton p->right = build(O_LCON, (long) field->symvalue.offset);
3115783Slinton }
3125783Slinton return p;
3135531Slinton }
3145531Slinton
3155531Slinton /*
3165531Slinton * Return a tree corresponding to an array reference and do the
3175531Slinton * error checking.
3185531Slinton */
3195531Slinton
subscript(a,slist)3205531Slinton NODE *subscript(a, slist)
3215531Slinton NODE *a, *slist;
3225531Slinton {
3235783Slinton register SYM *t;
3245783Slinton register NODE *p;
3255783Slinton SYM *etype, *atype, *eltype;
32611064Slinton NODE *esub;
3275531Slinton
3285783Slinton t = rtype(a->nodetype);
3295783Slinton if (t->class != ARRAY) {
33011064Slinton trerror("%t is not an array", a);
3315783Slinton }
3325783Slinton eltype = t->type;
3335783Slinton p = slist;
3345783Slinton t = t->chain;
3355783Slinton for (; p != NIL && t != NIL; p = p->right, t = t->chain) {
3365783Slinton esub = p->left;
3375783Slinton etype = rtype(esub->nodetype);
3385783Slinton atype = rtype(t);
3395783Slinton if (!compatible(atype, etype)) {
3405783Slinton trerror("subscript %t is the wrong type", esub);
3415531Slinton }
34211064Slinton esub->nodetype = atype;
3435783Slinton }
3445783Slinton if (p != NIL) {
34511064Slinton trerror("too many subscripts for %t", a);
3465783Slinton } else if (t != NIL) {
34711064Slinton trerror("not enough subscripts for %t", a);
3485783Slinton }
34911064Slinton p = alloc(1, NODE);
35011064Slinton p->op = O_INDEX;
35111064Slinton p->left = a;
35211064Slinton p->right = slist;
35311064Slinton p->nodetype = eltype;
35411064Slinton return p;
3555531Slinton }
3565531Slinton
3575531Slinton /*
35811064Slinton * Evaluate a subscript (possibly more than one index).
3595531Slinton */
3605531Slinton
evalindex(arraytype,subs)36111064Slinton long evalindex(arraytype, subs)
3625783Slinton SYM *arraytype;
36311064Slinton NODE *subs;
3645531Slinton {
36511064Slinton long lb, ub, index, i;
36611064Slinton SYM *t, *indextype;
36711064Slinton NODE *p;
3685531Slinton
36911064Slinton t = rtype(arraytype);
37011064Slinton if (t->class != ARRAY) {
37111064Slinton panic("unexpected class %d in evalindex", t->class);
3725783Slinton }
37311064Slinton i = 0;
37411064Slinton t = t->chain;
37511064Slinton p = subs;
37611064Slinton while (t != NIL) {
37711064Slinton if (p == NIL) {
37811064Slinton panic("unexpected end of subscript list in evalindex");
37911064Slinton }
38011064Slinton indextype = rtype(t);
38111064Slinton lb = indextype->symvalue.rangev.lower;
38211064Slinton ub = indextype->symvalue.rangev.upper;
38311064Slinton eval(p->left);
38411064Slinton index = popsmall(p->left->nodetype);
38511064Slinton if (index < lb || index > ub) {
38611064Slinton error("subscript value %d out of range %d..%d", index, lb, ub);
38711064Slinton }
38811067Slinton i = (ub-lb+1)*i + (index-lb);
38911064Slinton t = t->chain;
39011064Slinton p = p->right;
39111064Slinton }
39211064Slinton return i;
3935531Slinton }
3945531Slinton
3955531Slinton /*
3965531Slinton * Check that a record.field usage is proper.
3975531Slinton */
3985531Slinton
chkfield(r,f)3995531Slinton LOCAL chkfield(r, f)
4005531Slinton NODE *r;
4015531Slinton SYM *f;
4025531Slinton {
4035783Slinton register SYM *s;
4045531Slinton
4055783Slinton chkclass(r, RECORD);
4065531Slinton
4075783Slinton /*
4085783Slinton * Don't do this for compiled code.
4095783Slinton */
41030850Smckusick for (s = r->nodetype->chain; s != NIL; s = s->chain) {
41130850Smckusick if (s == f) {
41230850Smckusick break;
4135783Slinton }
41430850Smckusick }
41530850Smckusick if (s == NIL) {
41630850Smckusick error("\"%s\" is not a field in specified record", f->symbol);
41730850Smckusick }
4185531Slinton }
4195531Slinton
4205531Slinton /*
4215531Slinton * Check to see if a tree is boolean-valued, if not it's an error.
4225531Slinton */
4235531Slinton
chkboolean(p)4245531Slinton chkboolean(p)
4255531Slinton register NODE *p;
4265531Slinton {
4275783Slinton if (p->nodetype != t_boolean) {
4285783Slinton trerror("found %t, expected boolean expression");
4295783Slinton }
4305531Slinton }
4315531Slinton
4325531Slinton /*
4335531Slinton * Check to make sure the given tree has a type of the given class.
4345531Slinton */
4355531Slinton
chkclass(p,class)4365531Slinton LOCAL chkclass(p, class)
4375531Slinton NODE *p;
4385531Slinton int class;
4395531Slinton {
4405783Slinton SYM tmpsym;
4415531Slinton
4425783Slinton tmpsym.class = class;
4435783Slinton if (p->nodetype->class != class) {
4445783Slinton trerror("%t is not a %s", p, classname(&tmpsym));
4455783Slinton }
4465531Slinton }
4475531Slinton
4485531Slinton /*
4495531Slinton * Construct a node for the type of a string. While we're at it,
4505531Slinton * scan the string for '' that collapse to ', and chop off the ends.
4515531Slinton */
4525531Slinton
mkstring(str)4535531Slinton LOCAL SYM *mkstring(str)
4545531Slinton char *str;
4555531Slinton {
4565783Slinton register char *p, *q;
4575783Slinton SYM *s, *t;
4585783Slinton static SYM zerosym;
4595531Slinton
4605783Slinton p = str;
4615783Slinton q = str + 1;
4625783Slinton while (*q != '\0') {
4635783Slinton if (q[0] != '\'' || q[1] != '\'') {
4645783Slinton *p = *q;
4655783Slinton p++;
4665531Slinton }
4675783Slinton q++;
4685783Slinton }
4695783Slinton *--p = '\0';
4705783Slinton if (p == str + 1) {
4715783Slinton return t_char;
4725783Slinton }
4735783Slinton s = alloc(1, SYM);
4745783Slinton *s = zerosym;
4755783Slinton s->class = ARRAY;
4765783Slinton s->type = t_char;
4775783Slinton s->chain = alloc(1, SYM);
4785783Slinton t = s->chain;
4795783Slinton *t = zerosym;
4805783Slinton t->class = RANGE;
4815783Slinton t->type = t_int;
4825783Slinton t->symvalue.rangev.lower = 1;
4835783Slinton t->symvalue.rangev.upper = p - str + 1;
4845783Slinton return s;
4855531Slinton }
4865531Slinton
4875531Slinton /*
4885531Slinton * Free up the space allocated for a string type.
4895531Slinton */
4905531Slinton
unmkstring(s)4915531Slinton unmkstring(s)
4925531Slinton SYM *s;
4935531Slinton {
4945783Slinton dispose(s->chain);
4955531Slinton }
496