xref: /original-bsd/usr.bin/pascal/pdx/tree/eval.c (revision c3e32dec)
1 /*-
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)eval.c	8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11 
12 /*
13  * Parse tree evaluation.
14  */
15 
16 #include "defs.h"
17 #include "tree.h"
18 #include "sym.h"
19 #include "process.h"
20 #include "source.h"
21 #include "mappings.h"
22 #include "breakpoint.h"
23 #include "machine.h"
24 #include "tree.rep"
25 #include "process/process.rep"
26 #include "process/pxinfo.h"
27 
28 #define Boolean char	/* underlying representation type for booleans */
29 
30 /*
31  * Evaluate a parse tree using a stack; value is left at top.
32  */
33 
34 #define STACKSIZE 2000
35 
36 STACK stack[STACKSIZE];
37 STACK *sp = &stack[0];
38 
39 eval(p)
40 register NODE *p;
41 {
42     long r0, r1;
43     double fr0, fr1;
44     FILE *fp;
45 
46     if (p == NULL) {
47 	return;
48     }
49     switch(degree(p->op)) {
50 	case BINARY:
51 	    eval(p->right);
52 	    if (isreal(p->op)) {
53 		fr1 = pop(double);
54 	    } else if (isint(p->op)) {
55 		r1 = popsmall(p->right->nodetype);
56 	    }
57 	    /* fall through */
58 	case UNARY:
59 	    eval(p->left);
60 	    if (isreal(p->op)) {
61 		fr0 = pop(double);
62 	    } else if (isint(p->op)) {
63 		r0 = popsmall(p->left->nodetype);
64 	    }
65 	    break;
66 
67 	default:
68 	    /* do nothing */;
69 	}
70     switch(p->op) {
71 	case O_NAME: {
72 	    SYM *s, *f;
73 
74 	    s = p->nameval;
75 	    if (!isvariable(s)) {
76 		error("cannot evaluate a %s", classname(s));
77 	    } else {
78 		f = container(s);
79 		if (!isactive(f)) {
80 		    error("\"%s\" is not active", name(f));
81 		}
82 		push(long, address(s, NIL));
83 	    }
84 	    break;
85 	}
86 
87 	case O_LCON:
88 	    switch (size(p->nodetype)) {
89 		case sizeof(char):
90 		    push(char, p->lconval);
91 		    break;
92 
93 		case sizeof(short):
94 		    push(short, p->lconval);
95 		    break;
96 
97 		case sizeof(long):
98 		    push(long, p->lconval);
99 		    break;
100 
101 		default:
102 		    panic("bad size %d for LCON", size(p->nodetype));
103 	    }
104 	    break;
105 
106 	case O_FCON:
107 	    push(double, p->fconval);
108 	    break;
109 
110 	case O_SCON: {
111 	    int len;
112 
113 	    len = size(p->nodetype);
114 	    mov(p->sconval, sp, len);
115 	    sp += len;
116 #ifdef tahoe
117 	    alignstack();
118 #endif tahoe
119 	    break;
120 	}
121 
122 	case O_INDEX: {
123 	    long n;	/* base address for array */
124 	    long i;	/* index - lower bound */
125 	    long evalindex();
126 
127 	    n = pop(long);
128 	    i = evalindex(p->left->nodetype, p->right);
129 	    push(long, n + i*size(p->nodetype));
130 	    break;
131 	}
132 
133 	case O_INDIR: {
134 	    ADDRESS a;
135 
136 	    a = pop(ADDRESS);
137 	    if (a == 0) {
138 		error("reference through nil pointer");
139 	    }
140 	    dread(sp, a, sizeof(ADDRESS));
141 	    sp += sizeof(ADDRESS);
142 	    break;
143 	}
144 
145 	/*
146 	 * Get the value of the expression addressed by the top of the stack.
147 	 * Push the result back on the stack.
148 	 */
149 
150 	case O_RVAL: {
151 	    ADDRESS addr, len;
152 
153 	    addr = pop(long);
154 	    if (addr == 0) {
155 		error("reference through nil pointer");
156 	    }
157 	    len = size(p->nodetype);
158 	    if (!rpush(addr, len)) {
159 		error("expression too large to evaluate");
160 	    }
161 	    break;
162 	}
163 
164 	case O_COMMA:
165 	    break;
166 
167 	case O_ITOF:
168 	    push(double, (double) r0);
169 	    break;
170 
171 	case O_ADD:
172 	    push(long, r0+r1);
173 	    break;
174 
175 	case O_ADDF:
176 	    push(double, fr0+fr1);
177 	    break;
178 
179 	case O_SUB:
180 	    push(long, r0-r1);
181 	    break;
182 
183 	case O_SUBF:
184 	    push(double, fr0-fr1);
185 	    break;
186 
187 	case O_NEG:
188 	    push(long, -r0);
189 	    break;
190 
191 	case O_NEGF:
192 	    push(double, -fr0);
193 	    break;
194 
195 	case O_MUL:
196 	    push(long, r0*r1);
197 	    break;
198 
199 	case O_MULF:
200 	    push(double, fr0*fr1);
201 	    break;
202 
203 	case O_DIVF:
204 	    if (fr1 == 0) {
205 		error("error: division by 0");
206 	    }
207 	    push(double, fr0/fr1);
208 	    break;
209 
210 	case O_DIV:
211 	    if (r1 == 0) {
212 		error("error: div by 0");
213 	    }
214 	    push(long, r0/r1);
215 	    break;
216 
217 	case O_MOD:
218 	    if (r1 == 0) {
219 		error("error: mod by 0");
220 	    }
221 	    push(long, r0%r1);
222 	    break;
223 
224 	case O_LT:
225 	    push(Boolean, r0 < r1);
226 	    break;
227 
228 	case O_LTF:
229 	    push(Boolean, fr0 < fr1);
230 	    break;
231 
232 	case O_LE:
233 	    push(Boolean, r0 <= r1);
234 	    break;
235 
236 	case O_LEF:
237 	    push(Boolean, fr0 <= fr1);
238 	    break;
239 
240 	case O_GT:
241 	    push(Boolean, r0 > r1);
242 	    break;
243 
244 	case O_GTF:
245 	    push(Boolean, fr0 > fr1);
246 	    break;
247 
248 	case O_EQ:
249 	    push(Boolean, r0 == r1);
250 	    break;
251 
252 	case O_EQF:
253 	    push(Boolean, fr0 == fr1);
254 	    break;
255 
256 	case O_NE:
257 	    push(Boolean, r0 != r1);
258 	    break;
259 
260 	case O_NEF:
261 	    push(Boolean, fr0 != fr1);
262 	    break;
263 
264 	case O_AND:
265 	    push(Boolean, r0 && r1);
266 	    break;
267 
268 	case O_OR:
269 	    push(Boolean, r0 || r1);
270 	    break;
271 
272 	case O_ASSIGN:
273 	    assign(p->left, p->right);
274 	    break;
275 
276 	case O_CHFILE:
277 	    if (p->sconval == NIL) {
278 		printf("%s\n", cursource);
279 	    } else {
280 		fp = fopen(p->sconval, "r");
281 		if (fp == NIL) {
282 		    error("can't read \"%s\"", p->sconval);
283 		} else {
284 		    fclose(fp);
285 		    skimsource(p->sconval);
286 		}
287 	    }
288 	    break;
289 
290 	case O_CONT:
291 	    cont();
292 	    printnews();
293 	    break;
294 
295 	case O_LIST: {
296 	    SYM *b;
297 	    ADDRESS addr;
298 
299 	    if (p->left->op == O_NAME) {
300 		b = p->left->nameval;
301 		if (!isblock(b)) {
302 		    error("\"%s\" is not a procedure or function", name(b));
303 		}
304 		addr = firstline(b);
305 		if ((int)addr == -1) {
306 		    error("\"%s\" is empty", name(b));
307 		}
308 		skimsource(srcfilename(addr));
309 		r0 = srcline(addr);
310 		r1 = r0 + 5;
311 		if (r1 > lastlinenum) {
312 		    r1 = lastlinenum;
313 		}
314 		r0 = r0 - 5;
315 		if (r0 < 1) {
316 		    r0 = 1;
317 		}
318 	    } else {
319 		eval(p->left->right);
320 		eval(p->left->left);
321 		r0 = pop(long);
322 		r1 = pop(long);
323 	    }
324 	    printlines((LINENO) r0, (LINENO) r1);
325 	    break;
326 	}
327 
328 	case O_XI:
329 	case O_XD:
330 	{
331 	    SYM *b;
332 
333 	    if (p->left->op == O_CALL) {
334 		b = p->left->left->nameval;
335 		r0 = codeloc(b);
336 		r1 = firstline(b);
337 	    } else {
338 		eval(p->left->right);
339 		eval(p->left->left);
340 		r0 = pop(long);
341 		r1 = pop(long);
342 	    }
343 	    if (p->op == O_XI)  {
344 		printinst((ADDRESS) r0, (ADDRESS) r1);
345 	    } else {
346 		printdata((ADDRESS) r0, (ADDRESS) r1);
347 	    }
348 	    break;
349 	}
350 
351 	case O_NEXT:
352 	    next();
353 	    printnews();
354 	    break;
355 
356 	case O_PRINT: {
357 	    NODE *o;
358 
359 	    for (o = p->left; o != NIL; o = o->right) {
360 		eval(o->left);
361 		printval(o->left->nodetype);
362 		putchar(' ');
363 	    }
364 	    putchar('\n');
365 	    break;
366 	}
367 
368 	case O_STEP:
369 	    stepc();
370 	    printnews();
371 	    break;
372 
373 	case O_WHATIS:
374 	    if (p->left->op == O_NAME) {
375 		printdecl(p->left->nameval);
376 	    } else {
377 		printdecl(p->left->nodetype);
378 	    }
379 	    break;
380 
381 	case O_WHICH:
382 	    printwhich(p->nameval);
383 	    putchar('\n');
384 	    break;
385 
386 	case O_WHERE:
387 	    where();
388 	    break;
389 
390 	case O_ALIAS:
391 	    alias(p->left->sconval, p->right->sconval);
392 	    break;
393 
394 	case O_CALL:
395 	    callproc(p->left, p->right);
396 	    break;
397 
398 	case O_EDIT:
399 	    edit(p->sconval);
400 	    break;
401 
402 	case O_DUMP:
403 	    dump();
404 	    break;
405 
406 	case O_GRIPE:
407 	    gripe();
408 	    break;
409 
410 	case O_HELP:
411 	    help();
412 	    break;
413 
414 	case O_REMAKE:
415 	    remake();
416 	    break;
417 
418 	case O_RUN:
419 	    run();
420 	    break;
421 
422 	case O_SOURCE:
423 	    setinput(p->sconval);
424 	    break;
425 
426 	case O_STATUS:
427 	    status();
428 	    break;
429 
430 	case O_TRACE:
431 	case O_TRACEI:
432 	    trace(p->op, p->what, p->where, p->cond);
433 	    if (isstdin()) {
434 		status();
435 	    }
436 	    break;
437 
438 	case O_STOP:
439 	case O_STOPI:
440 	    stop(p->op, p->what, p->where, p->cond);
441 	    if (isstdin()) {
442 		status();
443 	    }
444 	    break;
445 
446 	case O_DELETE:
447 	    eval(p->left);
448 	    delbp((unsigned int) pop(long));
449 	    break;
450 
451 	default:
452 	    panic("eval: bad op %d", p->op);
453     }
454 }
455 
456 /*
457  * Push "len" bytes onto the expression stack from address "addr"
458  * in the process.  Normally TRUE is returned, however if there
459  * isn't enough room on the stack, rpush returns FALSE.
460  */
461 
462 BOOLEAN rpush(addr, len)
463 ADDRESS addr;
464 int len;
465 {
466     BOOLEAN success;
467 #ifdef tahoe
468     register char *savesp = sp;
469 #endif
470 
471     if (sp + len >= &stack[STACKSIZE]) {
472 	success = FALSE;
473     } else {
474 	dread(sp, addr, len);
475 	sp += len;
476 #ifdef tahoe
477         alignstack();
478 	if (sp >= &stack[STACKSIZE]) {
479 		success = FALSE;
480 		sp = savesp;
481 	} else
482 #endif
483 	    success = TRUE;
484     }
485     return success;
486 }
487 
488 /*
489  * Pop an item of the given type which is assumed to be no larger
490  * than a long and return it expanded into a long.
491  */
492 
493 long popsmall(t)
494 SYM *t;
495 {
496     long r;
497 
498     switch (size(t)) {
499 	case sizeof(char):
500 	    r = (long) pop(char);
501 	    break;
502 
503 	case sizeof(short):
504 	    r = (long) pop(short);
505 	    break;
506 
507 	case sizeof(long):
508 	    r = pop(long);
509 	    break;
510 
511 	/*
512 	 * A bit of a kludge here.  If an array element is a record,
513 	 * the dot operation will be converted into an addition with
514 	 * the record operand having a type whose size may be larger
515 	 * than a word.  Now actually this is a pointer, but the subscript
516 	 * operation isn't aware of this, so it's just hacked here.
517 	 *
518 	 * The right thing to do is to make dot directly evaluated
519 	 * instead of changing it into addition.
520 	 */
521 	default:
522 	    r = pop(ADDRESS);
523 	    break;
524     }
525     return r;
526 }
527 
528 /*
529  * evaluate a conditional expression
530  */
531 
532 BOOLEAN cond(p)
533 NODE *p;
534 {
535     if (p == NIL) {
536 	return(TRUE);
537     }
538     eval(p);
539     return(pop(BOOLEAN));
540 }
541 
542 /*
543  * Return the address corresponding to a given tree.
544  */
545 
546 ADDRESS lval(p)
547 NODE *p;
548 {
549     eval(p);
550     return(pop(ADDRESS));
551 }
552