xref: /csrg-svn/usr.bin/pascal/pdx/tree/eval.c (revision 10765)
15543Slinton /* Copyright (c) 1982 Regents of the University of California */
25543Slinton 
3*10765Slinton static char sccsid[] = "@(#)eval.c 1.9 02/08/83";
45543Slinton 
55543Slinton /*
65562Slinton  * Parse tree evaluation.
75543Slinton  */
85543Slinton 
95543Slinton #include "defs.h"
105543Slinton #include "tree.h"
115543Slinton #include "sym.h"
125543Slinton #include "process.h"
135543Slinton #include "source.h"
145543Slinton #include "mappings.h"
155543Slinton #include "breakpoint.h"
165543Slinton #include "machine.h"
175543Slinton #include "tree.rep"
185543Slinton 
196086Slinton #define Boolean char	/* underlying representation type for booleans */
206086Slinton 
215543Slinton /*
225543Slinton  * Evaluate a parse tree using a stack; value is left at top.
235543Slinton  */
245543Slinton 
255562Slinton #define STACKSIZE 2000
265562Slinton 
275562Slinton STACK stack[STACKSIZE];
285543Slinton STACK *sp = &stack[0];
295543Slinton 
305543Slinton eval(p)
315543Slinton register NODE *p;
325543Slinton {
335782Slinton     long r0, r1;
345782Slinton     double fr0, fr1;
356874Slinton     FILE *fp;
365543Slinton 
375782Slinton     if (p == NULL) {
385782Slinton 	return;
395782Slinton     }
405782Slinton     switch(degree(p->op)) {
415782Slinton 	case BINARY:
425782Slinton 	    eval(p->right);
435782Slinton 	    if (isreal(p->op)) {
445782Slinton 		fr1 = pop(double);
455782Slinton 	    } else if (isint(p->op)) {
466076Slinton 		r1 = popsmall(p->right->nodetype);
475782Slinton 	    }
485782Slinton 	    /* fall through */
495782Slinton 	case UNARY:
505782Slinton 	    eval(p->left);
515782Slinton 	    if (isreal(p->op)) {
525782Slinton 		fr0 = pop(double);
535782Slinton 	    } else if (isint(p->op)) {
546076Slinton 		r0 = popsmall(p->left->nodetype);
555782Slinton 	    }
565782Slinton 	    break;
575782Slinton 
585782Slinton 	default:
595782Slinton 	    /* do nothing */;
605543Slinton 	}
615782Slinton     switch(p->op) {
625782Slinton 	case O_NAME: {
635782Slinton 	    SYM *s, *f;
645543Slinton 
655782Slinton 	    s = p->nameval;
665886Slinton 	    if (!isvariable(s)) {
675886Slinton 		error("cannot evaluate a %s", classname(s));
685886Slinton 	    } else {
695886Slinton 		f = container(s);
705886Slinton 		if (!isactive(f)) {
715886Slinton 		    error("\"%s\" is not active", name(f));
725886Slinton 		}
736086Slinton 		push(long, address(s, NIL));
745782Slinton 	    }
755782Slinton 	    break;
765782Slinton 	}
775543Slinton 
785782Slinton 	case O_LCON:
795782Slinton 	    switch (size(p->nodetype)) {
805782Slinton 		case sizeof(char):
815782Slinton 		    push(char, p->lconval);
825782Slinton 		    break;
835543Slinton 
845782Slinton 		case sizeof(short):
855782Slinton 		    push(short, p->lconval);
865782Slinton 		    break;
875543Slinton 
885782Slinton 		case sizeof(long):
895782Slinton 		    push(long, p->lconval);
905782Slinton 		    break;
915543Slinton 
925782Slinton 		default:
935782Slinton 		    panic("bad size %d for LCON", size(p->nodetype));
945782Slinton 	    }
955782Slinton 	    break;
965543Slinton 
975782Slinton 	case O_FCON:
985782Slinton 	    push(double, p->fconval);
995782Slinton 	    break;
1005543Slinton 
1015782Slinton 	case O_SCON: {
1025782Slinton 	    int len;
1035543Slinton 
1045782Slinton 	    len = size(p->nodetype);
1055782Slinton 	    mov(p->sconval, sp, len);
1065782Slinton 	    sp += len;
1075782Slinton 	    break;
1085782Slinton 	}
1095543Slinton 
1105782Slinton 	case O_INDEX: {
1115782Slinton 	    int n;
1125782Slinton 	    long i;
1135543Slinton 
1146086Slinton 	    n = pop(long);
1155782Slinton 	    i = evalindex(p->left->nodetype, popsmall(p->right->nodetype));
1166086Slinton 	    push(long, n + i*size(p->nodetype));
1175782Slinton 	    break;
1185782Slinton 	}
1195543Slinton 
1205782Slinton 	case O_INDIR: {
1215782Slinton 	    ADDRESS a;
1225543Slinton 
1235782Slinton 	    a = pop(ADDRESS);
1245782Slinton 	    if (a == 0) {
1255782Slinton 		error("reference through nil pointer");
1265782Slinton 	    }
1275782Slinton 	    dread(sp, a, sizeof(ADDRESS));
1285782Slinton 	    sp += sizeof(ADDRESS);
1295782Slinton 	    break;
1305782Slinton 	}
1315543Slinton 
1325782Slinton 	/*
1335782Slinton 	 * Get the value of the expression addressed by the top of the stack.
1346076Slinton 	 * Push the result back on the stack.
1355782Slinton 	 */
1365543Slinton 
1375782Slinton 	case O_RVAL: {
1385782Slinton 	    ADDRESS addr, len;
1395782Slinton 	    long i;
1405543Slinton 
1416086Slinton 	    addr = pop(long);
1425782Slinton 	    if (addr == 0) {
1435782Slinton 		error("reference through nil pointer");
1445782Slinton 	    }
1455782Slinton 	    len = size(p->nodetype);
1465782Slinton 	    if (!rpush(addr, len)) {
1475782Slinton 		error("expression too large to evaluate");
1485782Slinton 	    }
1495782Slinton 	    break;
1505782Slinton 	}
1515543Slinton 
1525782Slinton 	case O_COMMA:
1535782Slinton 	    break;
1545543Slinton 
1555782Slinton 	case O_ITOF:
1565782Slinton 	    push(double, (double) r0);
1575782Slinton 	    break;
1585543Slinton 
1595782Slinton 	case O_ADD:
1605782Slinton 	    push(long, r0+r1);
1615782Slinton 	    break;
1625543Slinton 
1635782Slinton 	case O_ADDF:
1645782Slinton 	    push(double, fr0+fr1);
1655782Slinton 	    break;
1665543Slinton 
1675782Slinton 	case O_SUB:
1685782Slinton 	    push(long, r0-r1);
1695782Slinton 	    break;
1705543Slinton 
1715782Slinton 	case O_SUBF:
1725782Slinton 	    push(double, fr0-fr1);
1735782Slinton 	    break;
1745543Slinton 
1755782Slinton 	case O_NEG:
1765782Slinton 	    push(long, -r0);
1775782Slinton 	    break;
1785543Slinton 
1795782Slinton 	case O_NEGF:
1805782Slinton 	    push(double, -fr0);
1815782Slinton 	    break;
1825543Slinton 
1835782Slinton 	case O_MUL:
1845782Slinton 	    push(long, r0*r1);
1855782Slinton 	    break;
1865543Slinton 
1875782Slinton 	case O_MULF:
1885782Slinton 	    push(double, fr0*fr1);
1895782Slinton 	    break;
1905543Slinton 
1915782Slinton 	case O_DIVF:
1925782Slinton 	    if (fr1 == 0) {
1935782Slinton 		error("error: division by 0");
1945782Slinton 	    }
1955782Slinton 	    push(double, fr0/fr1);
1965782Slinton 	    break;
1975543Slinton 
1985782Slinton 	case O_DIV:
1995782Slinton 	    if (r1 == 0) {
2005782Slinton 		error("error: div by 0");
2015782Slinton 	    }
2025782Slinton 	    push(long, r0/r1);
2035782Slinton 	    break;
2045543Slinton 
2055782Slinton 	case O_MOD:
2065782Slinton 	    if (r1 == 0) {
2075782Slinton 		error("error: mod by 0");
2085782Slinton 	    }
2095782Slinton 	    push(long, r0%r1);
2105782Slinton 	    break;
2115543Slinton 
2125782Slinton 	case O_LT:
2136086Slinton 	    push(Boolean, r0 < r1);
2145782Slinton 	    break;
2155543Slinton 
2165782Slinton 	case O_LTF:
2176086Slinton 	    push(Boolean, fr0 < fr1);
2185782Slinton 	    break;
2195543Slinton 
2205782Slinton 	case O_LE:
2216086Slinton 	    push(Boolean, r0 <= r1);
2225782Slinton 	    break;
2235543Slinton 
2245782Slinton 	case O_LEF:
2256086Slinton 	    push(Boolean, fr0 <= fr1);
2265782Slinton 	    break;
2275543Slinton 
2285782Slinton 	case O_GT:
2296086Slinton 	    push(Boolean, r0 > r1);
2305782Slinton 	    break;
2315543Slinton 
2325782Slinton 	case O_GTF:
2336086Slinton 	    push(Boolean, fr0 > fr1);
2345782Slinton 	    break;
2355543Slinton 
2365782Slinton 	case O_EQ:
2376086Slinton 	    push(Boolean, r0 == r1);
2385782Slinton 	    break;
2395543Slinton 
2405782Slinton 	case O_EQF:
2416086Slinton 	    push(Boolean, fr0 == fr1);
2425782Slinton 	    break;
2435543Slinton 
2445782Slinton 	case O_NE:
2456086Slinton 	    push(Boolean, r0 != r1);
2465782Slinton 	    break;
2475543Slinton 
2485782Slinton 	case O_NEF:
2496086Slinton 	    push(Boolean, fr0 != fr1);
2505782Slinton 	    break;
2515543Slinton 
2525782Slinton 	case O_AND:
2536086Slinton 	    push(Boolean, r0 && r1);
2545782Slinton 	    break;
2555543Slinton 
2565782Slinton 	case O_OR:
2576086Slinton 	    push(Boolean, r0 || r1);
2585782Slinton 	    break;
2595543Slinton 
2605782Slinton 	case O_ASSIGN:
2615782Slinton 	    assign(p->left, p->right);
2625782Slinton 	    break;
2635543Slinton 
2645782Slinton 	case O_CHFILE:
2655782Slinton 	    if (p->sconval == NIL) {
2665782Slinton 		printf("%s\n", cursource);
2675782Slinton 	    } else {
2686874Slinton 		fp = fopen(p->sconval, "r");
2696874Slinton 		if (fp == NIL) {
2706874Slinton 		    error("can't read \"%s\"", p->sconval);
2716874Slinton 		} else {
2726874Slinton 		    fclose(fp);
2736874Slinton 		    skimsource(p->sconval);
2746874Slinton 		}
2755782Slinton 	    }
2765782Slinton 	    break;
2775543Slinton 
2785782Slinton 	case O_CONT:
2795782Slinton 	    cont();
2805782Slinton 	    printnews();
2815782Slinton 	    break;
2825543Slinton 
2835782Slinton 	case O_LIST: {
2845782Slinton 	    SYM *b;
2856083Slinton 	    ADDRESS addr;
2865543Slinton 
2875782Slinton 	    if (p->left->op == O_NAME) {
2885782Slinton 		b = p->left->nameval;
2895782Slinton 		if (!isblock(b)) {
2905782Slinton 		    error("\"%s\" is not a procedure or function", name(b));
2915543Slinton 		}
2926083Slinton 		addr = firstline(b);
2936083Slinton 		if (addr == -1) {
2946083Slinton 		    error("\"%s\" is empty", name(b));
2956083Slinton 		}
2966083Slinton 		skimsource(srcfilename(addr));
2976083Slinton 		r0 = srcline(addr);
2985782Slinton 		r1 = r0 + 5;
2995782Slinton 		if (r1 > lastlinenum) {
3005782Slinton 		    r1 = lastlinenum;
3015782Slinton 		}
3025782Slinton 		r0 = r0 - 5;
3035782Slinton 		if (r0 < 1) {
3045782Slinton 		    r0 = 1;
3055782Slinton 		}
3065782Slinton 	    } else {
3075782Slinton 		eval(p->left->right);
3085782Slinton 		eval(p->left->left);
3095782Slinton 		r0 = pop(long);
3105782Slinton 		r1 = pop(long);
3115782Slinton 	    }
3125782Slinton 	    printlines((LINENO) r0, (LINENO) r1);
3135782Slinton 	    break;
3145782Slinton 	}
3155543Slinton 
3165782Slinton 	case O_XI:
3175782Slinton 	case O_XD:
3185782Slinton 	{
3195782Slinton 	    SYM *b;
3205543Slinton 
3215782Slinton 	    if (p->left->op == O_CALL) {
3225782Slinton 		b = p->left->left->nameval;
3235782Slinton 		r0 = codeloc(b);
3245782Slinton 		r1 = firstline(b);
3255782Slinton 	    } else {
3265782Slinton 		eval(p->left->right);
3275782Slinton 		eval(p->left->left);
3285782Slinton 		r0 = pop(long);
3295782Slinton 		r1 = pop(long);
3305782Slinton 	    }
3315782Slinton 	    if (p->op == O_XI)  {
3325782Slinton 		printinst((ADDRESS) r0, (ADDRESS) r1);
3335782Slinton 	    } else {
3345782Slinton 		printdata((ADDRESS) r0, (ADDRESS) r1);
3355782Slinton 	    }
3365782Slinton 	    break;
3375782Slinton 	}
3385543Slinton 
3395782Slinton 	case O_NEXT:
3405782Slinton 	    next();
3415782Slinton 	    printnews();
3425782Slinton 	    break;
3435543Slinton 
3445782Slinton 	case O_PRINT: {
3455782Slinton 	    NODE *o;
3465543Slinton 
3475782Slinton 	    for (o = p->left; o != NIL; o = o->right) {
3485782Slinton 		eval(o->left);
3495782Slinton 		printval(o->left->nodetype);
3505782Slinton 		putchar(' ');
3515782Slinton 	    }
3525782Slinton 	    putchar('\n');
3535782Slinton 	    break;
3545782Slinton 	}
3555543Slinton 
3565782Slinton 	case O_STEP:
3575782Slinton 	    stepc();
3585782Slinton 	    printnews();
3595782Slinton 	    break;
3605543Slinton 
3615782Slinton 	case O_WHATIS:
3625782Slinton 	    if (p->left->op == O_NAME) {
3635782Slinton 		printdecl(p->left->nameval);
3645782Slinton 	    } else {
3655782Slinton 		printdecl(p->left->nodetype);
3665782Slinton 	    }
3675782Slinton 	    break;
3685543Slinton 
3695782Slinton 	case O_WHICH:
3705782Slinton 	    printwhich(p->nameval);
3715782Slinton 	    putchar('\n');
3725782Slinton 	    break;
3735543Slinton 
3745782Slinton 	case O_WHERE:
3755782Slinton 	    where();
3765782Slinton 	    break;
3775543Slinton 
3785782Slinton 	case O_ALIAS:
3795782Slinton 	    alias(p->left->sconval, p->right->sconval);
3805782Slinton 	    break;
3815543Slinton 
3825782Slinton 	case O_CALL:
3835782Slinton 	    callproc(p->left, p->right);
3845782Slinton 	    break;
3855543Slinton 
3865782Slinton 	case O_EDIT:
3875782Slinton 	    edit(p->sconval);
3885782Slinton 	    break;
3895543Slinton 
3905782Slinton 	case O_DUMP:
3915782Slinton 	    dump();
3925782Slinton 	    break;
3935543Slinton 
3945782Slinton 	case O_GRIPE:
3955782Slinton 	    gripe();
3965782Slinton 	    break;
3975562Slinton 
3985782Slinton 	case O_HELP:
3995782Slinton 	    help();
4005782Slinton 	    break;
4015543Slinton 
4025782Slinton 	case O_REMAKE:
4035782Slinton 	    remake();
4045782Slinton 	    break;
4055543Slinton 
4065782Slinton 	case O_RUN:
4075782Slinton 	    run();
4085782Slinton 	    break;
4095543Slinton 
4105782Slinton 	case O_SOURCE:
4115782Slinton 	    setinput(p->sconval);
4125782Slinton 	    break;
4135543Slinton 
4145782Slinton 	case O_STATUS:
4155782Slinton 	    status();
4165782Slinton 	    break;
4175543Slinton 
4185782Slinton 	case O_TRACE:
4195782Slinton 	case O_TRACEI:
4205782Slinton 	    trace(p->op, p->what, p->where, p->cond);
4215782Slinton 	    if (isstdin()) {
4225782Slinton 		status();
4235782Slinton 	    }
4245782Slinton 	    break;
4255543Slinton 
4265782Slinton 	case O_STOP:
4275782Slinton 	case O_STOPI:
4285782Slinton 	    stop(p->op, p->what, p->where, p->cond);
4295782Slinton 	    if (isstdin()) {
4305782Slinton 		status();
4315782Slinton 	    }
4325782Slinton 	    break;
4335543Slinton 
4345782Slinton 	case O_DELETE:
4355782Slinton 	    eval(p->left);
4365782Slinton 	    delbp((unsigned int) pop(long));
4375782Slinton 	    break;
4385543Slinton 
4395782Slinton 	default:
4405782Slinton 	    panic("eval: bad op %d", p->op);
4415782Slinton     }
4425543Slinton }
4435543Slinton 
4445543Slinton /*
4455562Slinton  * Push "len" bytes onto the expression stack from address "addr"
4465562Slinton  * in the process.  Normally TRUE is returned, however if there
4475562Slinton  * isn't enough room on the stack, rpush returns FALSE.
4485562Slinton  */
4495562Slinton 
4505562Slinton BOOLEAN rpush(addr, len)
4515562Slinton ADDRESS addr;
4525562Slinton int len;
4535562Slinton {
4545782Slinton     BOOLEAN success;
4555562Slinton 
4565782Slinton     if (sp + len >= &stack[STACKSIZE]) {
4575782Slinton 	success = FALSE;
4585782Slinton     } else {
4595782Slinton 	dread(sp, addr, len);
4605782Slinton 	sp += len;
4615782Slinton 	success = TRUE;
4625782Slinton     }
4635782Slinton     return success;
4645562Slinton }
4655562Slinton 
4665562Slinton /*
4675782Slinton  * Pop an item of the given type which is assumed to be no larger
4685782Slinton  * than a long and return it expanded into a long.
4695782Slinton  */
4705782Slinton 
4715782Slinton long popsmall(t)
4725782Slinton SYM *t;
4735782Slinton {
4745782Slinton     long r;
4755782Slinton 
4765782Slinton     switch (size(t)) {
4775782Slinton 	case sizeof(char):
4785782Slinton 	    r = (long) pop(char);
4795782Slinton 	    break;
4805782Slinton 
4815782Slinton 	case sizeof(short):
4825782Slinton 	    r = (long) pop(short);
4835782Slinton 	    break;
4845782Slinton 
4855782Slinton 	case sizeof(long):
4865782Slinton 	    r = pop(long);
4875782Slinton 	    break;
4885782Slinton 
489*10765Slinton 	/*
490*10765Slinton 	 * A bit of a kludge here.  If an array element is a record,
491*10765Slinton 	 * the dot operation will be converted into an addition with
492*10765Slinton 	 * the record operand having a type whose size may be larger
493*10765Slinton 	 * than a word.  Now actually this is a pointer, but the subscript
494*10765Slinton 	 * operation isn't aware of this, so it's just hacked here.
495*10765Slinton 	 *
496*10765Slinton 	 * The right thing to do is to make dot directly evaluated
497*10765Slinton 	 * instead of changing it into addition.
498*10765Slinton 	 */
4995782Slinton 	default:
500*10765Slinton 	    r = pop(ADDRESS);
501*10765Slinton 	    break;
5025782Slinton     }
5035782Slinton     return r;
5045782Slinton }
5055782Slinton 
5065782Slinton /*
5075543Slinton  * evaluate a conditional expression
5085543Slinton  */
5095543Slinton 
5105543Slinton BOOLEAN cond(p)
5115543Slinton NODE *p;
5125543Slinton {
5135782Slinton     if (p == NIL) {
5145782Slinton 	return(TRUE);
5155782Slinton     }
5165782Slinton     eval(p);
5175782Slinton     return(pop(BOOLEAN));
5185543Slinton }
5195543Slinton 
5205543Slinton /*
5215543Slinton  * Return the address corresponding to a given tree.
5225543Slinton  */
5235543Slinton 
5245543Slinton ADDRESS lval(p)
5255543Slinton NODE *p;
5265543Slinton {
5275782Slinton     eval(p);
5285782Slinton     return(pop(ADDRESS));
5295543Slinton }
530