xref: /csrg-svn/usr.bin/pascal/pdx/sym/tree.c (revision 5783)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)tree.c 1.2 02/13/82";
4 
5 /*
6  * This module contains the interface between the SYM routines and
7  * the parse tree routines.  It would be nice if such a crude
8  * interface were not necessary, but some parts of tree building are
9  * language and hence SYM-representation dependent.  It's probably
10  * better to have tree-representation dependent code here than vice versa.
11  */
12 
13 #include "defs.h"
14 #include "tree.h"
15 #include "sym.h"
16 #include "btypes.h"
17 #include "classes.h"
18 #include "sym.rep"
19 #include "tree/tree.rep"
20 
21 typedef char *ARGLIST;
22 
23 #define nextarg(arglist, type)  ((type *) (arglist += sizeof(type)))[-1]
24 
25 LOCAL SYM *mkstring();
26 LOCAL SYM *namenode();
27 
28 /*
29  * Determine the type of a parse tree.  While we're at, check
30  * the parse tree out.
31  */
32 
33 SYM *treetype(p, ap)
34 register NODE *p;
35 register ARGLIST ap;
36 {
37     switch(p->op) {
38 	case O_NAME: {
39 	    SYM *s;
40 
41 	    s = nextarg(ap, SYM *);
42 	    s = which(s);
43 	    return namenode(p, s);
44 	    /* NOTREACHED */
45 	}
46 
47 	case O_WHICH:
48 	    p->nameval = nextarg(ap, SYM *);
49 	    p->nameval = which(p->nameval);
50 	    return NIL;
51 
52 	case O_LCON:
53 	    return t_int;
54 
55 	case O_FCON:
56 	    return t_real;
57 
58 	case O_SCON: {
59 	    char *cpy;
60 	    SYM *s;
61 
62 	    cpy = strdup(p->sconval);
63 	    p->sconval = cpy;
64 	    s = mkstring(p->sconval);
65 	    if (s == t_char) {
66 		p->op = O_LCON;
67 		p->lconval = p->sconval[0];
68 	    }
69 	    return s;
70 	}
71 
72 	case O_INDIR:
73 	    p->left = nextarg(ap, NODE *);
74 	    chkclass(p->left, PTR);
75 	    return rtype(p->left->nodetype)->type;
76 
77 	case O_RVAL: {
78 	    NODE *p1, *q;
79 
80 	    p1 = p->left;
81 	    p->nodetype = p1->nodetype;
82 	    if (p1->op == O_NAME) {
83 		if (p1->nodetype->class == FUNC) {
84 		    p->op = O_CALL;
85 		    p->right = NIL;
86 		} else if (p1->nameval->class == CONST) {
87 		    if (p1->nameval->type == t_real->type) {
88 			p->op = O_FCON;
89 			p->fconval = p1->nameval->symvalue.fconval;
90 			p->nodetype = t_real;
91 			dispose(p1);
92 		    } else {
93 			p->op = O_LCON;
94 			p->lconval = p1->nameval->symvalue.iconval;
95 			p->nodetype = p1->nameval->type;
96 			dispose(p1);
97 		    }
98 		}
99 	    }
100 	    return p->nodetype;
101 	    /* NOTREACHED */
102 	}
103 
104 	case O_CALL: {
105 	    SYM *s;
106 
107 	    p->left = nextarg(ap, NODE *);
108 	    p->right = nextarg(ap, NODE *);
109 	    s = p->left->nodetype;
110 	    if (isblock(s) && isbuiltin(s)) {
111 		p->op = (OP) s->symvalue.token.tokval;
112 		tfree(p->left);
113 		p->left = p->right;
114 		p->right = NIL;
115 	    }
116 	    return s->type;
117 	}
118 
119 	case O_ITOF:
120 	    return t_real;
121 
122 	case O_NEG: {
123 	    SYM *s;
124 
125 	    p->left = nextarg(ap, NODE *);
126 	    s = p->left->nodetype;
127 	    if (!compatible(s, t_int)) {
128 		if (!compatible(s, t_real)) {
129 		    trerror("%t is improper type", p->left);
130 		} else {
131 		    p->op = O_NEGF;
132 		}
133 	    }
134 	    return s;
135 	}
136 
137 	case O_ADD:
138 	case O_SUB:
139 	case O_MUL:
140 	case O_LT:
141 	case O_LE:
142 	case O_GT:
143 	case O_GE:
144 	case O_EQ:
145 	case O_NE:
146 	{
147 	    BOOLEAN t1real, t2real;
148 	    SYM *t1, *t2;
149 
150 	    p->left = nextarg(ap, NODE *);
151 	    p->right = nextarg(ap, NODE *);
152 	    t1 = rtype(p->left->nodetype);
153 	    t2 = rtype(p->right->nodetype);
154 	    t1real = (t1 == t_real);
155 	    t2real = (t2 == t_real);
156 	    if (t1real || t2real) {
157 		p->op++;
158 		if (!t1real) {
159 		    p->left = build(O_ITOF, p->left);
160 		} else if (!t2real) {
161 		    p->right = build(O_ITOF, p->right);
162 		}
163 	    } else {
164 		if (t1real) {
165 		    convert(&p->left, t_int, O_NOP);
166 		}
167 		if (t2real) {
168 		    convert(&p->right, t_int, O_NOP);
169 		}
170 	    }
171 	    if (p->op >= O_LT) {
172 		return t_boolean;
173 	    } else {
174 		if (t1real || t2real) {
175 		    return t_real;
176 		} else {
177 		    return t_int;
178 		}
179 	    }
180 	    /* NOTREACHED */
181 	}
182 
183 	case O_DIVF:
184 	    p->left = nextarg(ap, NODE *);
185 	    p->right = nextarg(ap, NODE *);
186 	    convert(&p->left, t_real, O_ITOF);
187 	    convert(&p->right, t_real, O_ITOF);
188 	    return t_real;
189 
190 	case O_DIV:
191 	case O_MOD:
192 	    p->left = nextarg(ap, NODE *);
193 	    p->right = nextarg(ap, NODE *);
194 	    convert(&p->left, t_int, O_NOP);
195 	    convert(&p->right, t_int, O_NOP);
196 	    return t_int;
197 
198 	case O_AND:
199 	case O_OR:
200 	    p->left = nextarg(ap, NODE *);
201 	    p->right = nextarg(ap, NODE *);
202 	    chkboolean(p->left);
203 	    chkboolean(p->right);
204 	    return t_boolean;
205 
206 	default:
207 	    return NIL;
208     }
209 }
210 
211 /*
212  * Create a node for a name.  The symbol for the name has already
213  * been chosen, either implicitly with "which" or explicitly from
214  * the dot routine.
215  */
216 
217 LOCAL SYM *namenode(p, s)
218 NODE *p;
219 SYM *s;
220 {
221     NODE *np;
222 
223     p->nameval = s;
224     if (s->class == REF) {
225 	np = alloc(1, NODE);
226 	*np = *p;
227 	p->op = O_INDIR;
228 	p->left = np;
229 	np->nodetype = s;
230     }
231     if (s->class == CONST || s->class == VAR || s->class == FVAR) {
232 	return s->type;
233     } else {
234 	return s;
235     }
236 }
237 
238 /*
239  * Convert a tree to a type via a conversion operator;
240  * if this isn't possible generate an error.
241  *
242  * Note the tree is call by address, hence the #define below.
243  */
244 
245 LOCAL convert(tp, typeto, op)
246 NODE **tp;
247 SYM *typeto;
248 OP op;
249 {
250 #define tree    (*tp)
251 
252     SYM *s;
253 
254     s = rtype(tree->nodetype);
255     typeto = rtype(typeto);
256     if (typeto == t_real && compatible(s, t_int)) {
257 	tree = build(op, tree);
258     } else if (!compatible(s, typeto)) {
259 	trerror("%t is improper type");
260     } else if (op != O_NOP && s != typeto) {
261 	tree = build(op, tree);
262     }
263 
264 #undef tree
265 }
266 
267 /*
268  * Construct a node for the Pascal dot operator.
269  *
270  * If the left operand is not a record, but rather a procedure
271  * or function, then we interpret the "." as referencing an
272  * "invisible" variable; i.e. a variable within a dynamically
273  * active block but not within the static scope of the current procedure.
274  */
275 
276 NODE *dot(record, field)
277 NODE *record;
278 SYM *field;
279 {
280     register NODE *p;
281     register SYM *s;
282 
283     if (isblock(record->nodetype)) {
284 	s = findsym(field, record->nodetype);
285 	if (s == NIL) {
286 	    error("\"%s\" is not defined in \"%s\"",
287 		field->symbol, record->nodetype->symbol);
288 	}
289 	p = alloc(1, NODE);
290 	p->op = O_NAME;
291 	p->nodetype = namenode(p, s);
292     } else {
293 	s = findclass(field, FIELD);
294 	if (s == NIL) {
295 	    error("\"%s\" is not a field", field->symbol);
296 	}
297 	field = s;
298 	chkfield(record, field);
299 	p = alloc(1, NODE);
300 	p->op = O_ADD;
301 	p->nodetype = field->type;
302 	p->left = record;
303 	p->right = build(O_LCON, (long) field->symvalue.offset);
304     }
305     return p;
306 }
307 
308 /*
309  * Return a tree corresponding to an array reference and do the
310  * error checking.
311  */
312 
313 NODE *subscript(a, slist)
314 NODE *a, *slist;
315 {
316     register SYM *t;
317     register NODE *p;
318     SYM *etype, *atype, *eltype;
319     NODE *esub, *olda;
320 
321     olda = a;
322     t = rtype(a->nodetype);
323     if (t->class != ARRAY) {
324 	trerror("%t is not an array");
325     }
326     eltype = t->type;
327     p = slist;
328     t = t->chain;
329     for (; p != NIL && t != NIL; p = p->right, t = t->chain) {
330 	esub = p->left;
331 	etype = rtype(esub->nodetype);
332 	atype = rtype(t);
333 	if (!compatible(atype, etype)) {
334 	    trerror("subscript %t is the wrong type", esub);
335 	}
336 	a = build(O_INDEX, a, esub);
337 	a->nodetype = eltype;
338     }
339     if (p != NIL) {
340 	trerror("too many subscripts for %t", olda);
341     } else if (t != NIL) {
342 	trerror("not enough subscripts for %t", olda);
343     }
344     return(a);
345 }
346 
347 /*
348  * Evaluate a subscript index.
349  */
350 
351 evalindex(arraytype, index)
352 SYM *arraytype;
353 long index;
354 {
355     long lb, ub;
356     SYM *indextype;
357 
358     indextype = arraytype->chain;
359     lb = indextype->symvalue.rangev.lower;
360     ub = indextype->symvalue.rangev.upper;
361     if (index < lb || index > ub) {
362 	error("subscript out of range");
363     }
364     return(index - lb);
365 }
366 
367 /*
368  * Check that a record.field usage is proper.
369  */
370 
371 LOCAL chkfield(r, f)
372 NODE *r;
373 SYM *f;
374 {
375     register SYM *s;
376 
377     chkclass(r, RECORD);
378 
379     /*
380      * Don't do this for compiled code.
381      */
382 #   if (!isvax)
383 	for (s = r->nodetype->chain; s != NIL; s = s->chain) {
384 	    if (s == f) {
385 		break;
386 	    }
387 	}
388 	if (s == NIL) {
389 	    error("\"%s\" is not a field in specified record", f->symbol);
390 	}
391 #   endif
392 }
393 
394 /*
395  * Check to see if a tree is boolean-valued, if not it's an error.
396  */
397 
398 chkboolean(p)
399 register NODE *p;
400 {
401     if (p->nodetype != t_boolean) {
402 	trerror("found %t, expected boolean expression");
403     }
404 }
405 
406 /*
407  * Check to make sure the given tree has a type of the given class.
408  */
409 
410 LOCAL chkclass(p, class)
411 NODE *p;
412 int class;
413 {
414     SYM tmpsym;
415 
416     tmpsym.class = class;
417     if (p->nodetype->class != class) {
418 	trerror("%t is not a %s", p, classname(&tmpsym));
419     }
420 }
421 
422 /*
423  * Construct a node for the type of a string.  While we're at it,
424  * scan the string for '' that collapse to ', and chop off the ends.
425  */
426 
427 LOCAL SYM *mkstring(str)
428 char *str;
429 {
430     register char *p, *q;
431     SYM *s, *t;
432     static SYM zerosym;
433 
434     p = str;
435     q = str + 1;
436     while (*q != '\0') {
437 	if (q[0] != '\'' || q[1] != '\'') {
438 	    *p = *q;
439 	    p++;
440 	}
441 	q++;
442     }
443     *--p = '\0';
444     if (p == str + 1) {
445 	return t_char;
446     }
447     s = alloc(1, SYM);
448     *s = zerosym;
449     s->class = ARRAY;
450     s->type = t_char;
451     s->chain = alloc(1, SYM);
452     t = s->chain;
453     *t = zerosym;
454     t->class = RANGE;
455     t->type = t_int;
456     t->symvalue.rangev.lower = 1;
457     t->symvalue.rangev.upper = p - str + 1;
458     return s;
459 }
460 
461 /*
462  * Free up the space allocated for a string type.
463  */
464 
465 unmkstring(s)
466 SYM *s;
467 {
468     dispose(s->chain);
469 }
470