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