122528Sdist /* 222528Sdist * Copyright (c) 1980 Regents of the University of California. 322528Sdist * All rights reserved. The Berkeley software License Agreement 422528Sdist * specifies the terms and conditions for redistribution. 522528Sdist */ 65531Slinton 722528Sdist #ifndef lint 8*30850Smckusick static char sccsid[] = "@(#)tree.c 5.2 (Berkeley) 04/07/87"; 922528Sdist #endif not lint 105531Slinton 115531Slinton /* 125531Slinton * This module contains the interface between the SYM routines and 135531Slinton * the parse tree routines. It would be nice if such a crude 145531Slinton * interface were not necessary, but some parts of tree building are 155531Slinton * language and hence SYM-representation dependent. It's probably 165531Slinton * better to have tree-representation dependent code here than vice versa. 175531Slinton */ 185531Slinton 195531Slinton #include "defs.h" 205531Slinton #include "tree.h" 215531Slinton #include "sym.h" 225531Slinton #include "btypes.h" 235531Slinton #include "classes.h" 245531Slinton #include "sym.rep" 255531Slinton #include "tree/tree.rep" 265531Slinton 275531Slinton typedef char *ARGLIST; 285531Slinton 295783Slinton #define nextarg(arglist, type) ((type *) (arglist += sizeof(type)))[-1] 305531Slinton 315531Slinton LOCAL SYM *mkstring(); 325531Slinton LOCAL SYM *namenode(); 335531Slinton 345531Slinton /* 355531Slinton * Determine the type of a parse tree. While we're at, check 365531Slinton * the parse tree out. 375531Slinton */ 385531Slinton 395531Slinton SYM *treetype(p, ap) 405531Slinton register NODE *p; 415531Slinton register ARGLIST ap; 425531Slinton { 435783Slinton switch(p->op) { 445783Slinton case O_NAME: { 455783Slinton SYM *s; 465531Slinton 475783Slinton s = nextarg(ap, SYM *); 485783Slinton s = which(s); 495783Slinton return namenode(p, s); 505783Slinton /* NOTREACHED */ 515783Slinton } 525531Slinton 535783Slinton case O_WHICH: 545783Slinton p->nameval = nextarg(ap, SYM *); 555783Slinton p->nameval = which(p->nameval); 565783Slinton return NIL; 575531Slinton 585783Slinton case O_LCON: 595783Slinton return t_int; 605531Slinton 615783Slinton case O_FCON: 625783Slinton return t_real; 635531Slinton 645783Slinton case O_SCON: { 655783Slinton char *cpy; 665783Slinton SYM *s; 675531Slinton 685783Slinton cpy = strdup(p->sconval); 695783Slinton p->sconval = cpy; 705783Slinton s = mkstring(p->sconval); 715783Slinton if (s == t_char) { 725783Slinton p->op = O_LCON; 735783Slinton p->lconval = p->sconval[0]; 745783Slinton } 755783Slinton return s; 765783Slinton } 775531Slinton 785783Slinton case O_INDIR: 795783Slinton p->left = nextarg(ap, NODE *); 805783Slinton chkclass(p->left, PTR); 815783Slinton return rtype(p->left->nodetype)->type; 825531Slinton 835783Slinton case O_RVAL: { 84*30850Smckusick NODE *p1; 855531Slinton 865783Slinton p1 = p->left; 875783Slinton p->nodetype = p1->nodetype; 885783Slinton if (p1->op == O_NAME) { 895783Slinton if (p1->nodetype->class == FUNC) { 905783Slinton p->op = O_CALL; 915783Slinton p->right = NIL; 925783Slinton } else if (p1->nameval->class == CONST) { 935783Slinton if (p1->nameval->type == t_real->type) { 945783Slinton p->op = O_FCON; 955783Slinton p->fconval = p1->nameval->symvalue.fconval; 965783Slinton p->nodetype = t_real; 975783Slinton dispose(p1); 985783Slinton } else { 995783Slinton p->op = O_LCON; 1005783Slinton p->lconval = p1->nameval->symvalue.iconval; 1015783Slinton p->nodetype = p1->nameval->type; 1025783Slinton dispose(p1); 1035783Slinton } 1045531Slinton } 1055783Slinton } 1065783Slinton return p->nodetype; 1075783Slinton /* NOTREACHED */ 1085783Slinton } 1095531Slinton 1105783Slinton case O_CALL: { 1115783Slinton SYM *s; 1125531Slinton 1135783Slinton p->left = nextarg(ap, NODE *); 1145783Slinton p->right = nextarg(ap, NODE *); 1155783Slinton s = p->left->nodetype; 1165783Slinton if (isblock(s) && isbuiltin(s)) { 1175783Slinton p->op = (OP) s->symvalue.token.tokval; 1185783Slinton tfree(p->left); 1195783Slinton p->left = p->right; 1205783Slinton p->right = NIL; 1215783Slinton } 1225783Slinton return s->type; 1235783Slinton } 1245531Slinton 1255783Slinton case O_ITOF: 1265783Slinton return t_real; 1275531Slinton 1285783Slinton case O_NEG: { 1295783Slinton SYM *s; 1305531Slinton 1315783Slinton p->left = nextarg(ap, NODE *); 1325783Slinton s = p->left->nodetype; 1335783Slinton if (!compatible(s, t_int)) { 1345783Slinton if (!compatible(s, t_real)) { 1355783Slinton trerror("%t is improper type", p->left); 1365783Slinton } else { 1375783Slinton p->op = O_NEGF; 1385531Slinton } 1395783Slinton } 1405783Slinton return s; 1415783Slinton } 1425531Slinton 1435783Slinton case O_ADD: 1445783Slinton case O_SUB: 1455783Slinton case O_MUL: 1465783Slinton case O_LT: 1475783Slinton case O_LE: 1485783Slinton case O_GT: 1495783Slinton case O_GE: 1505783Slinton case O_EQ: 1515783Slinton case O_NE: 1525783Slinton { 1535783Slinton BOOLEAN t1real, t2real; 1545783Slinton SYM *t1, *t2; 1555531Slinton 1565783Slinton p->left = nextarg(ap, NODE *); 1575783Slinton p->right = nextarg(ap, NODE *); 1585783Slinton t1 = rtype(p->left->nodetype); 1595783Slinton t2 = rtype(p->right->nodetype); 1605783Slinton t1real = (t1 == t_real); 1615783Slinton t2real = (t2 == t_real); 1625783Slinton if (t1real || t2real) { 1635783Slinton p->op++; 1645783Slinton if (!t1real) { 1655783Slinton p->left = build(O_ITOF, p->left); 1665783Slinton } else if (!t2real) { 1675783Slinton p->right = build(O_ITOF, p->right); 1685531Slinton } 1695783Slinton } else { 1705783Slinton if (t1real) { 1715783Slinton convert(&p->left, t_int, O_NOP); 1725783Slinton } 1735783Slinton if (t2real) { 1745783Slinton convert(&p->right, t_int, O_NOP); 1755783Slinton } 1765783Slinton } 1775783Slinton if (p->op >= O_LT) { 1785783Slinton return t_boolean; 1795783Slinton } else { 1805783Slinton if (t1real || t2real) { 1815783Slinton return t_real; 1825783Slinton } else { 1835783Slinton return t_int; 1845783Slinton } 1855783Slinton } 1865783Slinton /* NOTREACHED */ 1875783Slinton } 1885531Slinton 1895783Slinton case O_DIVF: 1905783Slinton p->left = nextarg(ap, NODE *); 1915783Slinton p->right = nextarg(ap, NODE *); 1925783Slinton convert(&p->left, t_real, O_ITOF); 1935783Slinton convert(&p->right, t_real, O_ITOF); 1945783Slinton return t_real; 1955531Slinton 1965783Slinton case O_DIV: 1975783Slinton case O_MOD: 1985783Slinton p->left = nextarg(ap, NODE *); 1995783Slinton p->right = nextarg(ap, NODE *); 2005783Slinton convert(&p->left, t_int, O_NOP); 2015783Slinton convert(&p->right, t_int, O_NOP); 2025783Slinton return t_int; 2035531Slinton 2045783Slinton case O_AND: 2055783Slinton case O_OR: 2065783Slinton p->left = nextarg(ap, NODE *); 2075783Slinton p->right = nextarg(ap, NODE *); 2085783Slinton chkboolean(p->left); 2095783Slinton chkboolean(p->right); 2105783Slinton return t_boolean; 2115531Slinton 2125783Slinton default: 2135783Slinton return NIL; 2145783Slinton } 2155531Slinton } 2165531Slinton 2175531Slinton /* 2185531Slinton * Create a node for a name. The symbol for the name has already 2195531Slinton * been chosen, either implicitly with "which" or explicitly from 2205531Slinton * the dot routine. 2215531Slinton */ 2225531Slinton 2235531Slinton LOCAL SYM *namenode(p, s) 2245531Slinton NODE *p; 2255531Slinton SYM *s; 2265531Slinton { 2275783Slinton NODE *np; 2285531Slinton 2295783Slinton p->nameval = s; 2305783Slinton if (s->class == REF) { 2315783Slinton np = alloc(1, NODE); 2325783Slinton *np = *p; 2335783Slinton p->op = O_INDIR; 2345783Slinton p->left = np; 2355783Slinton np->nodetype = s; 2365783Slinton } 2375783Slinton if (s->class == CONST || s->class == VAR || s->class == FVAR) { 2385783Slinton return s->type; 2395783Slinton } else { 2405783Slinton return s; 2415783Slinton } 2425531Slinton } 2435531Slinton 2445531Slinton /* 2455531Slinton * Convert a tree to a type via a conversion operator; 2465531Slinton * if this isn't possible generate an error. 2475531Slinton * 2485531Slinton * Note the tree is call by address, hence the #define below. 2495531Slinton */ 2505531Slinton 2515531Slinton LOCAL convert(tp, typeto, op) 2525531Slinton NODE **tp; 2535531Slinton SYM *typeto; 2545531Slinton OP op; 2555531Slinton { 2565783Slinton #define tree (*tp) 2575531Slinton 2585783Slinton SYM *s; 2595531Slinton 2605783Slinton s = rtype(tree->nodetype); 2615783Slinton typeto = rtype(typeto); 2625783Slinton if (typeto == t_real && compatible(s, t_int)) { 2635783Slinton tree = build(op, tree); 2645783Slinton } else if (!compatible(s, typeto)) { 2655783Slinton trerror("%t is improper type"); 2665783Slinton } else if (op != O_NOP && s != typeto) { 2675783Slinton tree = build(op, tree); 2685783Slinton } 2695531Slinton 2705531Slinton #undef tree 2715531Slinton } 2725531Slinton 2735531Slinton /* 2745531Slinton * Construct a node for the Pascal dot operator. 2755531Slinton * 2765531Slinton * If the left operand is not a record, but rather a procedure 2775531Slinton * or function, then we interpret the "." as referencing an 2785531Slinton * "invisible" variable; i.e. a variable within a dynamically 2795531Slinton * active block but not within the static scope of the current procedure. 2805531Slinton */ 2815531Slinton 2825531Slinton NODE *dot(record, field) 2835531Slinton NODE *record; 2845531Slinton SYM *field; 2855531Slinton { 2865783Slinton register NODE *p; 2875783Slinton register SYM *s; 2885531Slinton 2895783Slinton if (isblock(record->nodetype)) { 2905783Slinton s = findsym(field, record->nodetype); 2915783Slinton if (s == NIL) { 2925783Slinton error("\"%s\" is not defined in \"%s\"", 2935783Slinton field->symbol, record->nodetype->symbol); 2945531Slinton } 2955783Slinton p = alloc(1, NODE); 2965783Slinton p->op = O_NAME; 2975783Slinton p->nodetype = namenode(p, s); 2985783Slinton } else { 2995783Slinton s = findclass(field, FIELD); 3005783Slinton if (s == NIL) { 3015783Slinton error("\"%s\" is not a field", field->symbol); 3025783Slinton } 3035783Slinton field = s; 3045783Slinton chkfield(record, field); 3055783Slinton p = alloc(1, NODE); 3065783Slinton p->op = O_ADD; 3075783Slinton p->nodetype = field->type; 3085783Slinton p->left = record; 3095783Slinton p->right = build(O_LCON, (long) field->symvalue.offset); 3105783Slinton } 3115783Slinton return p; 3125531Slinton } 3135531Slinton 3145531Slinton /* 3155531Slinton * Return a tree corresponding to an array reference and do the 3165531Slinton * error checking. 3175531Slinton */ 3185531Slinton 3195531Slinton NODE *subscript(a, slist) 3205531Slinton NODE *a, *slist; 3215531Slinton { 3225783Slinton register SYM *t; 3235783Slinton register NODE *p; 3245783Slinton SYM *etype, *atype, *eltype; 32511064Slinton NODE *esub; 3265531Slinton 3275783Slinton t = rtype(a->nodetype); 3285783Slinton if (t->class != ARRAY) { 32911064Slinton trerror("%t is not an array", a); 3305783Slinton } 3315783Slinton eltype = t->type; 3325783Slinton p = slist; 3335783Slinton t = t->chain; 3345783Slinton for (; p != NIL && t != NIL; p = p->right, t = t->chain) { 3355783Slinton esub = p->left; 3365783Slinton etype = rtype(esub->nodetype); 3375783Slinton atype = rtype(t); 3385783Slinton if (!compatible(atype, etype)) { 3395783Slinton trerror("subscript %t is the wrong type", esub); 3405531Slinton } 34111064Slinton esub->nodetype = atype; 3425783Slinton } 3435783Slinton if (p != NIL) { 34411064Slinton trerror("too many subscripts for %t", a); 3455783Slinton } else if (t != NIL) { 34611064Slinton trerror("not enough subscripts for %t", a); 3475783Slinton } 34811064Slinton p = alloc(1, NODE); 34911064Slinton p->op = O_INDEX; 35011064Slinton p->left = a; 35111064Slinton p->right = slist; 35211064Slinton p->nodetype = eltype; 35311064Slinton return p; 3545531Slinton } 3555531Slinton 3565531Slinton /* 35711064Slinton * Evaluate a subscript (possibly more than one index). 3585531Slinton */ 3595531Slinton 36011064Slinton long evalindex(arraytype, subs) 3615783Slinton SYM *arraytype; 36211064Slinton NODE *subs; 3635531Slinton { 36411064Slinton long lb, ub, index, i; 36511064Slinton SYM *t, *indextype; 36611064Slinton NODE *p; 3675531Slinton 36811064Slinton t = rtype(arraytype); 36911064Slinton if (t->class != ARRAY) { 37011064Slinton panic("unexpected class %d in evalindex", t->class); 3715783Slinton } 37211064Slinton i = 0; 37311064Slinton t = t->chain; 37411064Slinton p = subs; 37511064Slinton while (t != NIL) { 37611064Slinton if (p == NIL) { 37711064Slinton panic("unexpected end of subscript list in evalindex"); 37811064Slinton } 37911064Slinton indextype = rtype(t); 38011064Slinton lb = indextype->symvalue.rangev.lower; 38111064Slinton ub = indextype->symvalue.rangev.upper; 38211064Slinton eval(p->left); 38311064Slinton index = popsmall(p->left->nodetype); 38411064Slinton if (index < lb || index > ub) { 38511064Slinton error("subscript value %d out of range %d..%d", index, lb, ub); 38611064Slinton } 38711067Slinton i = (ub-lb+1)*i + (index-lb); 38811064Slinton t = t->chain; 38911064Slinton p = p->right; 39011064Slinton } 39111064Slinton return i; 3925531Slinton } 3935531Slinton 3945531Slinton /* 3955531Slinton * Check that a record.field usage is proper. 3965531Slinton */ 3975531Slinton 3985531Slinton LOCAL chkfield(r, f) 3995531Slinton NODE *r; 4005531Slinton SYM *f; 4015531Slinton { 4025783Slinton register SYM *s; 4035531Slinton 4045783Slinton chkclass(r, RECORD); 4055531Slinton 4065783Slinton /* 4075783Slinton * Don't do this for compiled code. 4085783Slinton */ 409*30850Smckusick for (s = r->nodetype->chain; s != NIL; s = s->chain) { 410*30850Smckusick if (s == f) { 411*30850Smckusick break; 4125783Slinton } 413*30850Smckusick } 414*30850Smckusick if (s == NIL) { 415*30850Smckusick error("\"%s\" is not a field in specified record", f->symbol); 416*30850Smckusick } 4175531Slinton } 4185531Slinton 4195531Slinton /* 4205531Slinton * Check to see if a tree is boolean-valued, if not it's an error. 4215531Slinton */ 4225531Slinton 4235531Slinton chkboolean(p) 4245531Slinton register NODE *p; 4255531Slinton { 4265783Slinton if (p->nodetype != t_boolean) { 4275783Slinton trerror("found %t, expected boolean expression"); 4285783Slinton } 4295531Slinton } 4305531Slinton 4315531Slinton /* 4325531Slinton * Check to make sure the given tree has a type of the given class. 4335531Slinton */ 4345531Slinton 4355531Slinton LOCAL chkclass(p, class) 4365531Slinton NODE *p; 4375531Slinton int class; 4385531Slinton { 4395783Slinton SYM tmpsym; 4405531Slinton 4415783Slinton tmpsym.class = class; 4425783Slinton if (p->nodetype->class != class) { 4435783Slinton trerror("%t is not a %s", p, classname(&tmpsym)); 4445783Slinton } 4455531Slinton } 4465531Slinton 4475531Slinton /* 4485531Slinton * Construct a node for the type of a string. While we're at it, 4495531Slinton * scan the string for '' that collapse to ', and chop off the ends. 4505531Slinton */ 4515531Slinton 4525531Slinton LOCAL SYM *mkstring(str) 4535531Slinton char *str; 4545531Slinton { 4555783Slinton register char *p, *q; 4565783Slinton SYM *s, *t; 4575783Slinton static SYM zerosym; 4585531Slinton 4595783Slinton p = str; 4605783Slinton q = str + 1; 4615783Slinton while (*q != '\0') { 4625783Slinton if (q[0] != '\'' || q[1] != '\'') { 4635783Slinton *p = *q; 4645783Slinton p++; 4655531Slinton } 4665783Slinton q++; 4675783Slinton } 4685783Slinton *--p = '\0'; 4695783Slinton if (p == str + 1) { 4705783Slinton return t_char; 4715783Slinton } 4725783Slinton s = alloc(1, SYM); 4735783Slinton *s = zerosym; 4745783Slinton s->class = ARRAY; 4755783Slinton s->type = t_char; 4765783Slinton s->chain = alloc(1, SYM); 4775783Slinton t = s->chain; 4785783Slinton *t = zerosym; 4795783Slinton t->class = RANGE; 4805783Slinton t->type = t_int; 4815783Slinton t->symvalue.rangev.lower = 1; 4825783Slinton t->symvalue.rangev.upper = p - str + 1; 4835783Slinton return s; 4845531Slinton } 4855531Slinton 4865531Slinton /* 4875531Slinton * Free up the space allocated for a string type. 4885531Slinton */ 4895531Slinton 4905531Slinton unmkstring(s) 4915531Slinton SYM *s; 4925531Slinton { 4935783Slinton dispose(s->chain); 4945531Slinton } 495