xref: /csrg-svn/usr.bin/pascal/pdx/sym/tree.c (revision 30850)
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