1*48093Sbostic /*- 2*48093Sbostic * Copyright (c) 1980 The Regents of the University of California. 3*48093Sbostic * All rights reserved. 4*48093Sbostic * 5*48093Sbostic * %sccs.include.redist.c% 622528Sdist */ 75531Slinton 822528Sdist #ifndef lint 9*48093Sbostic static char sccsid[] = "@(#)tree.c 5.3 (Berkeley) 04/16/91"; 10*48093Sbostic #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 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 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 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 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 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 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 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 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 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 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 4915531Slinton unmkstring(s) 4925531Slinton SYM *s; 4935531Slinton { 4945783Slinton dispose(s->chain); 4955531Slinton } 496