15531Slinton /* Copyright (c) 1982 Regents of the University of California */ 25531Slinton 3*11064Slinton static char sccsid[] = "@(#)tree.c 1.5 02/14/83"; 45531Slinton 55531Slinton /* 65531Slinton * This module contains the interface between the SYM routines and 75531Slinton * the parse tree routines. It would be nice if such a crude 85531Slinton * interface were not necessary, but some parts of tree building are 95531Slinton * language and hence SYM-representation dependent. It's probably 105531Slinton * better to have tree-representation dependent code here than vice versa. 115531Slinton */ 125531Slinton 135531Slinton #include "defs.h" 145531Slinton #include "tree.h" 155531Slinton #include "sym.h" 165531Slinton #include "btypes.h" 175531Slinton #include "classes.h" 185531Slinton #include "sym.rep" 195531Slinton #include "tree/tree.rep" 205531Slinton 215531Slinton typedef char *ARGLIST; 225531Slinton 235783Slinton #define nextarg(arglist, type) ((type *) (arglist += sizeof(type)))[-1] 245531Slinton 255531Slinton LOCAL SYM *mkstring(); 265531Slinton LOCAL SYM *namenode(); 275531Slinton 285531Slinton /* 295531Slinton * Determine the type of a parse tree. While we're at, check 305531Slinton * the parse tree out. 315531Slinton */ 325531Slinton 335531Slinton SYM *treetype(p, ap) 345531Slinton register NODE *p; 355531Slinton register ARGLIST ap; 365531Slinton { 375783Slinton switch(p->op) { 385783Slinton case O_NAME: { 395783Slinton SYM *s; 405531Slinton 415783Slinton s = nextarg(ap, SYM *); 425783Slinton s = which(s); 435783Slinton return namenode(p, s); 445783Slinton /* NOTREACHED */ 455783Slinton } 465531Slinton 475783Slinton case O_WHICH: 485783Slinton p->nameval = nextarg(ap, SYM *); 495783Slinton p->nameval = which(p->nameval); 505783Slinton return NIL; 515531Slinton 525783Slinton case O_LCON: 535783Slinton return t_int; 545531Slinton 555783Slinton case O_FCON: 565783Slinton return t_real; 575531Slinton 585783Slinton case O_SCON: { 595783Slinton char *cpy; 605783Slinton SYM *s; 615531Slinton 625783Slinton cpy = strdup(p->sconval); 635783Slinton p->sconval = cpy; 645783Slinton s = mkstring(p->sconval); 655783Slinton if (s == t_char) { 665783Slinton p->op = O_LCON; 675783Slinton p->lconval = p->sconval[0]; 685783Slinton } 695783Slinton return s; 705783Slinton } 715531Slinton 725783Slinton case O_INDIR: 735783Slinton p->left = nextarg(ap, NODE *); 745783Slinton chkclass(p->left, PTR); 755783Slinton return rtype(p->left->nodetype)->type; 765531Slinton 775783Slinton case O_RVAL: { 785783Slinton NODE *p1, *q; 795531Slinton 805783Slinton p1 = p->left; 815783Slinton p->nodetype = p1->nodetype; 825783Slinton if (p1->op == O_NAME) { 835783Slinton if (p1->nodetype->class == FUNC) { 845783Slinton p->op = O_CALL; 855783Slinton p->right = NIL; 865783Slinton } else if (p1->nameval->class == CONST) { 875783Slinton if (p1->nameval->type == t_real->type) { 885783Slinton p->op = O_FCON; 895783Slinton p->fconval = p1->nameval->symvalue.fconval; 905783Slinton p->nodetype = t_real; 915783Slinton dispose(p1); 925783Slinton } else { 935783Slinton p->op = O_LCON; 945783Slinton p->lconval = p1->nameval->symvalue.iconval; 955783Slinton p->nodetype = p1->nameval->type; 965783Slinton dispose(p1); 975783Slinton } 985531Slinton } 995783Slinton } 1005783Slinton return p->nodetype; 1015783Slinton /* NOTREACHED */ 1025783Slinton } 1035531Slinton 1045783Slinton case O_CALL: { 1055783Slinton SYM *s; 1065531Slinton 1075783Slinton p->left = nextarg(ap, NODE *); 1085783Slinton p->right = nextarg(ap, NODE *); 1095783Slinton s = p->left->nodetype; 1105783Slinton if (isblock(s) && isbuiltin(s)) { 1115783Slinton p->op = (OP) s->symvalue.token.tokval; 1125783Slinton tfree(p->left); 1135783Slinton p->left = p->right; 1145783Slinton p->right = NIL; 1155783Slinton } 1165783Slinton return s->type; 1175783Slinton } 1185531Slinton 1195783Slinton case O_ITOF: 1205783Slinton return t_real; 1215531Slinton 1225783Slinton case O_NEG: { 1235783Slinton SYM *s; 1245531Slinton 1255783Slinton p->left = nextarg(ap, NODE *); 1265783Slinton s = p->left->nodetype; 1275783Slinton if (!compatible(s, t_int)) { 1285783Slinton if (!compatible(s, t_real)) { 1295783Slinton trerror("%t is improper type", p->left); 1305783Slinton } else { 1315783Slinton p->op = O_NEGF; 1325531Slinton } 1335783Slinton } 1345783Slinton return s; 1355783Slinton } 1365531Slinton 1375783Slinton case O_ADD: 1385783Slinton case O_SUB: 1395783Slinton case O_MUL: 1405783Slinton case O_LT: 1415783Slinton case O_LE: 1425783Slinton case O_GT: 1435783Slinton case O_GE: 1445783Slinton case O_EQ: 1455783Slinton case O_NE: 1465783Slinton { 1475783Slinton BOOLEAN t1real, t2real; 1485783Slinton SYM *t1, *t2; 1495531Slinton 1505783Slinton p->left = nextarg(ap, NODE *); 1515783Slinton p->right = nextarg(ap, NODE *); 1525783Slinton t1 = rtype(p->left->nodetype); 1535783Slinton t2 = rtype(p->right->nodetype); 1545783Slinton t1real = (t1 == t_real); 1555783Slinton t2real = (t2 == t_real); 1565783Slinton if (t1real || t2real) { 1575783Slinton p->op++; 1585783Slinton if (!t1real) { 1595783Slinton p->left = build(O_ITOF, p->left); 1605783Slinton } else if (!t2real) { 1615783Slinton p->right = build(O_ITOF, p->right); 1625531Slinton } 1635783Slinton } else { 1645783Slinton if (t1real) { 1655783Slinton convert(&p->left, t_int, O_NOP); 1665783Slinton } 1675783Slinton if (t2real) { 1685783Slinton convert(&p->right, t_int, O_NOP); 1695783Slinton } 1705783Slinton } 1715783Slinton if (p->op >= O_LT) { 1725783Slinton return t_boolean; 1735783Slinton } else { 1745783Slinton if (t1real || t2real) { 1755783Slinton return t_real; 1765783Slinton } else { 1775783Slinton return t_int; 1785783Slinton } 1795783Slinton } 1805783Slinton /* NOTREACHED */ 1815783Slinton } 1825531Slinton 1835783Slinton case O_DIVF: 1845783Slinton p->left = nextarg(ap, NODE *); 1855783Slinton p->right = nextarg(ap, NODE *); 1865783Slinton convert(&p->left, t_real, O_ITOF); 1875783Slinton convert(&p->right, t_real, O_ITOF); 1885783Slinton return t_real; 1895531Slinton 1905783Slinton case O_DIV: 1915783Slinton case O_MOD: 1925783Slinton p->left = nextarg(ap, NODE *); 1935783Slinton p->right = nextarg(ap, NODE *); 1945783Slinton convert(&p->left, t_int, O_NOP); 1955783Slinton convert(&p->right, t_int, O_NOP); 1965783Slinton return t_int; 1975531Slinton 1985783Slinton case O_AND: 1995783Slinton case O_OR: 2005783Slinton p->left = nextarg(ap, NODE *); 2015783Slinton p->right = nextarg(ap, NODE *); 2025783Slinton chkboolean(p->left); 2035783Slinton chkboolean(p->right); 2045783Slinton return t_boolean; 2055531Slinton 2065783Slinton default: 2075783Slinton return NIL; 2085783Slinton } 2095531Slinton } 2105531Slinton 2115531Slinton /* 2125531Slinton * Create a node for a name. The symbol for the name has already 2135531Slinton * been chosen, either implicitly with "which" or explicitly from 2145531Slinton * the dot routine. 2155531Slinton */ 2165531Slinton 2175531Slinton LOCAL SYM *namenode(p, s) 2185531Slinton NODE *p; 2195531Slinton SYM *s; 2205531Slinton { 2215783Slinton NODE *np; 2225531Slinton 2235783Slinton p->nameval = s; 2245783Slinton if (s->class == REF) { 2255783Slinton np = alloc(1, NODE); 2265783Slinton *np = *p; 2275783Slinton p->op = O_INDIR; 2285783Slinton p->left = np; 2295783Slinton np->nodetype = s; 2305783Slinton } 2315783Slinton if (s->class == CONST || s->class == VAR || s->class == FVAR) { 2325783Slinton return s->type; 2335783Slinton } else { 2345783Slinton return s; 2355783Slinton } 2365531Slinton } 2375531Slinton 2385531Slinton /* 2395531Slinton * Convert a tree to a type via a conversion operator; 2405531Slinton * if this isn't possible generate an error. 2415531Slinton * 2425531Slinton * Note the tree is call by address, hence the #define below. 2435531Slinton */ 2445531Slinton 2455531Slinton LOCAL convert(tp, typeto, op) 2465531Slinton NODE **tp; 2475531Slinton SYM *typeto; 2485531Slinton OP op; 2495531Slinton { 2505783Slinton #define tree (*tp) 2515531Slinton 2525783Slinton SYM *s; 2535531Slinton 2545783Slinton s = rtype(tree->nodetype); 2555783Slinton typeto = rtype(typeto); 2565783Slinton if (typeto == t_real && compatible(s, t_int)) { 2575783Slinton tree = build(op, tree); 2585783Slinton } else if (!compatible(s, typeto)) { 2595783Slinton trerror("%t is improper type"); 2605783Slinton } else if (op != O_NOP && s != typeto) { 2615783Slinton tree = build(op, tree); 2625783Slinton } 2635531Slinton 2645531Slinton #undef tree 2655531Slinton } 2665531Slinton 2675531Slinton /* 2685531Slinton * Construct a node for the Pascal dot operator. 2695531Slinton * 2705531Slinton * If the left operand is not a record, but rather a procedure 2715531Slinton * or function, then we interpret the "." as referencing an 2725531Slinton * "invisible" variable; i.e. a variable within a dynamically 2735531Slinton * active block but not within the static scope of the current procedure. 2745531Slinton */ 2755531Slinton 2765531Slinton NODE *dot(record, field) 2775531Slinton NODE *record; 2785531Slinton SYM *field; 2795531Slinton { 2805783Slinton register NODE *p; 2815783Slinton register SYM *s; 2825531Slinton 2835783Slinton if (isblock(record->nodetype)) { 2845783Slinton s = findsym(field, record->nodetype); 2855783Slinton if (s == NIL) { 2865783Slinton error("\"%s\" is not defined in \"%s\"", 2875783Slinton field->symbol, record->nodetype->symbol); 2885531Slinton } 2895783Slinton p = alloc(1, NODE); 2905783Slinton p->op = O_NAME; 2915783Slinton p->nodetype = namenode(p, s); 2925783Slinton } else { 2935783Slinton s = findclass(field, FIELD); 2945783Slinton if (s == NIL) { 2955783Slinton error("\"%s\" is not a field", field->symbol); 2965783Slinton } 2975783Slinton field = s; 2985783Slinton chkfield(record, field); 2995783Slinton p = alloc(1, NODE); 3005783Slinton p->op = O_ADD; 3015783Slinton p->nodetype = field->type; 3025783Slinton p->left = record; 3035783Slinton p->right = build(O_LCON, (long) field->symvalue.offset); 3045783Slinton } 3055783Slinton return p; 3065531Slinton } 3075531Slinton 3085531Slinton /* 3095531Slinton * Return a tree corresponding to an array reference and do the 3105531Slinton * error checking. 3115531Slinton */ 3125531Slinton 3135531Slinton NODE *subscript(a, slist) 3145531Slinton NODE *a, *slist; 3155531Slinton { 3165783Slinton register SYM *t; 3175783Slinton register NODE *p; 3185783Slinton SYM *etype, *atype, *eltype; 319*11064Slinton NODE *esub; 3205531Slinton 3215783Slinton t = rtype(a->nodetype); 3225783Slinton if (t->class != ARRAY) { 323*11064Slinton trerror("%t is not an array", a); 3245783Slinton } 3255783Slinton eltype = t->type; 3265783Slinton p = slist; 3275783Slinton t = t->chain; 3285783Slinton for (; p != NIL && t != NIL; p = p->right, t = t->chain) { 3295783Slinton esub = p->left; 3305783Slinton etype = rtype(esub->nodetype); 3315783Slinton atype = rtype(t); 3325783Slinton if (!compatible(atype, etype)) { 3335783Slinton trerror("subscript %t is the wrong type", esub); 3345531Slinton } 335*11064Slinton esub->nodetype = atype; 3365783Slinton } 3375783Slinton if (p != NIL) { 338*11064Slinton trerror("too many subscripts for %t", a); 3395783Slinton } else if (t != NIL) { 340*11064Slinton trerror("not enough subscripts for %t", a); 3415783Slinton } 342*11064Slinton p = alloc(1, NODE); 343*11064Slinton p->op = O_INDEX; 344*11064Slinton p->left = a; 345*11064Slinton p->right = slist; 346*11064Slinton p->nodetype = eltype; 347*11064Slinton return p; 3485531Slinton } 3495531Slinton 3505531Slinton /* 351*11064Slinton * Evaluate a subscript (possibly more than one index). 3525531Slinton */ 3535531Slinton 354*11064Slinton long evalindex(arraytype, subs) 3555783Slinton SYM *arraytype; 356*11064Slinton NODE *subs; 3575531Slinton { 358*11064Slinton long lb, ub, index, i; 359*11064Slinton SYM *t, *indextype; 360*11064Slinton NODE *p; 3615531Slinton 362*11064Slinton t = rtype(arraytype); 363*11064Slinton if (t->class != ARRAY) { 364*11064Slinton panic("unexpected class %d in evalindex", t->class); 3655783Slinton } 366*11064Slinton i = 0; 367*11064Slinton t = t->chain; 368*11064Slinton p = subs; 369*11064Slinton while (t != NIL) { 370*11064Slinton if (p == NIL) { 371*11064Slinton panic("unexpected end of subscript list in evalindex"); 372*11064Slinton } 373*11064Slinton indextype = rtype(t); 374*11064Slinton lb = indextype->symvalue.rangev.lower; 375*11064Slinton ub = indextype->symvalue.rangev.upper; 376*11064Slinton eval(p->left); 377*11064Slinton index = popsmall(p->left->nodetype); 378*11064Slinton if (index < lb || index > ub) { 379*11064Slinton error("subscript value %d out of range %d..%d", index, lb, ub); 380*11064Slinton } 381*11064Slinton i = i + (index - lb); 382*11064Slinton t = t->chain; 383*11064Slinton p = p->right; 384*11064Slinton } 385*11064Slinton return i; 3865531Slinton } 3875531Slinton 3885531Slinton /* 3895531Slinton * Check that a record.field usage is proper. 3905531Slinton */ 3915531Slinton 3925531Slinton LOCAL chkfield(r, f) 3935531Slinton NODE *r; 3945531Slinton SYM *f; 3955531Slinton { 3965783Slinton register SYM *s; 3975531Slinton 3985783Slinton chkclass(r, RECORD); 3995531Slinton 4005783Slinton /* 4015783Slinton * Don't do this for compiled code. 4025783Slinton */ 4035783Slinton # if (!isvax) 4045783Slinton for (s = r->nodetype->chain; s != NIL; s = s->chain) { 4055783Slinton if (s == f) { 4065783Slinton break; 4075783Slinton } 4085783Slinton } 4095783Slinton if (s == NIL) { 4105783Slinton error("\"%s\" is not a field in specified record", f->symbol); 4115783Slinton } 4125783Slinton # endif 4135531Slinton } 4145531Slinton 4155531Slinton /* 4165531Slinton * Check to see if a tree is boolean-valued, if not it's an error. 4175531Slinton */ 4185531Slinton 4195531Slinton chkboolean(p) 4205531Slinton register NODE *p; 4215531Slinton { 4225783Slinton if (p->nodetype != t_boolean) { 4235783Slinton trerror("found %t, expected boolean expression"); 4245783Slinton } 4255531Slinton } 4265531Slinton 4275531Slinton /* 4285531Slinton * Check to make sure the given tree has a type of the given class. 4295531Slinton */ 4305531Slinton 4315531Slinton LOCAL chkclass(p, class) 4325531Slinton NODE *p; 4335531Slinton int class; 4345531Slinton { 4355783Slinton SYM tmpsym; 4365531Slinton 4375783Slinton tmpsym.class = class; 4385783Slinton if (p->nodetype->class != class) { 4395783Slinton trerror("%t is not a %s", p, classname(&tmpsym)); 4405783Slinton } 4415531Slinton } 4425531Slinton 4435531Slinton /* 4445531Slinton * Construct a node for the type of a string. While we're at it, 4455531Slinton * scan the string for '' that collapse to ', and chop off the ends. 4465531Slinton */ 4475531Slinton 4485531Slinton LOCAL SYM *mkstring(str) 4495531Slinton char *str; 4505531Slinton { 4515783Slinton register char *p, *q; 4525783Slinton SYM *s, *t; 4535783Slinton static SYM zerosym; 4545531Slinton 4555783Slinton p = str; 4565783Slinton q = str + 1; 4575783Slinton while (*q != '\0') { 4585783Slinton if (q[0] != '\'' || q[1] != '\'') { 4595783Slinton *p = *q; 4605783Slinton p++; 4615531Slinton } 4625783Slinton q++; 4635783Slinton } 4645783Slinton *--p = '\0'; 4655783Slinton if (p == str + 1) { 4665783Slinton return t_char; 4675783Slinton } 4685783Slinton s = alloc(1, SYM); 4695783Slinton *s = zerosym; 4705783Slinton s->class = ARRAY; 4715783Slinton s->type = t_char; 4725783Slinton s->chain = alloc(1, SYM); 4735783Slinton t = s->chain; 4745783Slinton *t = zerosym; 4755783Slinton t->class = RANGE; 4765783Slinton t->type = t_int; 4775783Slinton t->symvalue.rangev.lower = 1; 4785783Slinton t->symvalue.rangev.upper = p - str + 1; 4795783Slinton return s; 4805531Slinton } 4815531Slinton 4825531Slinton /* 4835531Slinton * Free up the space allocated for a string type. 4845531Slinton */ 4855531Slinton 4865531Slinton unmkstring(s) 4875531Slinton SYM *s; 4885531Slinton { 4895783Slinton dispose(s->chain); 4905531Slinton } 491