xref: /csrg-svn/usr.bin/pascal/pdx/tree/eval.c (revision 22559)
1*22559Sdist /*
2*22559Sdist  * Copyright (c) 1980 Regents of the University of California.
3*22559Sdist  * All rights reserved.  The Berkeley software License Agreement
4*22559Sdist  * specifies the terms and conditions for redistribution.
5*22559Sdist  */
65543Slinton 
7*22559Sdist #ifndef lint
8*22559Sdist static char sccsid[] = "@(#)eval.c	5.1 (Berkeley) 06/06/85";
9*22559Sdist #endif not lint
105543Slinton 
115543Slinton /*
125562Slinton  * Parse tree evaluation.
135543Slinton  */
145543Slinton 
155543Slinton #include "defs.h"
165543Slinton #include "tree.h"
175543Slinton #include "sym.h"
185543Slinton #include "process.h"
195543Slinton #include "source.h"
205543Slinton #include "mappings.h"
215543Slinton #include "breakpoint.h"
225543Slinton #include "machine.h"
235543Slinton #include "tree.rep"
245543Slinton 
256086Slinton #define Boolean char	/* underlying representation type for booleans */
266086Slinton 
275543Slinton /*
285543Slinton  * Evaluate a parse tree using a stack; value is left at top.
295543Slinton  */
305543Slinton 
315562Slinton #define STACKSIZE 2000
325562Slinton 
335562Slinton STACK stack[STACKSIZE];
345543Slinton STACK *sp = &stack[0];
355543Slinton 
365543Slinton eval(p)
375543Slinton register NODE *p;
385543Slinton {
395782Slinton     long r0, r1;
405782Slinton     double fr0, fr1;
416874Slinton     FILE *fp;
425543Slinton 
435782Slinton     if (p == NULL) {
445782Slinton 	return;
455782Slinton     }
465782Slinton     switch(degree(p->op)) {
475782Slinton 	case BINARY:
485782Slinton 	    eval(p->right);
495782Slinton 	    if (isreal(p->op)) {
505782Slinton 		fr1 = pop(double);
515782Slinton 	    } else if (isint(p->op)) {
526076Slinton 		r1 = popsmall(p->right->nodetype);
535782Slinton 	    }
545782Slinton 	    /* fall through */
555782Slinton 	case UNARY:
565782Slinton 	    eval(p->left);
575782Slinton 	    if (isreal(p->op)) {
585782Slinton 		fr0 = pop(double);
595782Slinton 	    } else if (isint(p->op)) {
606076Slinton 		r0 = popsmall(p->left->nodetype);
615782Slinton 	    }
625782Slinton 	    break;
635782Slinton 
645782Slinton 	default:
655782Slinton 	    /* do nothing */;
665543Slinton 	}
675782Slinton     switch(p->op) {
685782Slinton 	case O_NAME: {
695782Slinton 	    SYM *s, *f;
705543Slinton 
715782Slinton 	    s = p->nameval;
725886Slinton 	    if (!isvariable(s)) {
735886Slinton 		error("cannot evaluate a %s", classname(s));
745886Slinton 	    } else {
755886Slinton 		f = container(s);
765886Slinton 		if (!isactive(f)) {
775886Slinton 		    error("\"%s\" is not active", name(f));
785886Slinton 		}
796086Slinton 		push(long, address(s, NIL));
805782Slinton 	    }
815782Slinton 	    break;
825782Slinton 	}
835543Slinton 
845782Slinton 	case O_LCON:
855782Slinton 	    switch (size(p->nodetype)) {
865782Slinton 		case sizeof(char):
875782Slinton 		    push(char, p->lconval);
885782Slinton 		    break;
895543Slinton 
905782Slinton 		case sizeof(short):
915782Slinton 		    push(short, p->lconval);
925782Slinton 		    break;
935543Slinton 
945782Slinton 		case sizeof(long):
955782Slinton 		    push(long, p->lconval);
965782Slinton 		    break;
975543Slinton 
985782Slinton 		default:
995782Slinton 		    panic("bad size %d for LCON", size(p->nodetype));
1005782Slinton 	    }
1015782Slinton 	    break;
1025543Slinton 
1035782Slinton 	case O_FCON:
1045782Slinton 	    push(double, p->fconval);
1055782Slinton 	    break;
1065543Slinton 
1075782Slinton 	case O_SCON: {
1085782Slinton 	    int len;
1095543Slinton 
1105782Slinton 	    len = size(p->nodetype);
1115782Slinton 	    mov(p->sconval, sp, len);
1125782Slinton 	    sp += len;
1135782Slinton 	    break;
1145782Slinton 	}
1155543Slinton 
1165782Slinton 	case O_INDEX: {
11711063Slinton 	    long n;	/* base address for array */
11811063Slinton 	    long i;	/* index - lower bound */
1195543Slinton 
1206086Slinton 	    n = pop(long);
12111063Slinton 	    i = evalindex(p->left->nodetype, p->right);
1226086Slinton 	    push(long, n + i*size(p->nodetype));
1235782Slinton 	    break;
1245782Slinton 	}
1255543Slinton 
1265782Slinton 	case O_INDIR: {
1275782Slinton 	    ADDRESS a;
1285543Slinton 
1295782Slinton 	    a = pop(ADDRESS);
1305782Slinton 	    if (a == 0) {
1315782Slinton 		error("reference through nil pointer");
1325782Slinton 	    }
1335782Slinton 	    dread(sp, a, sizeof(ADDRESS));
1345782Slinton 	    sp += sizeof(ADDRESS);
1355782Slinton 	    break;
1365782Slinton 	}
1375543Slinton 
1385782Slinton 	/*
1395782Slinton 	 * Get the value of the expression addressed by the top of the stack.
1406076Slinton 	 * Push the result back on the stack.
1415782Slinton 	 */
1425543Slinton 
1435782Slinton 	case O_RVAL: {
1445782Slinton 	    ADDRESS addr, len;
1455782Slinton 	    long i;
1465543Slinton 
1476086Slinton 	    addr = pop(long);
1485782Slinton 	    if (addr == 0) {
1495782Slinton 		error("reference through nil pointer");
1505782Slinton 	    }
1515782Slinton 	    len = size(p->nodetype);
1525782Slinton 	    if (!rpush(addr, len)) {
1535782Slinton 		error("expression too large to evaluate");
1545782Slinton 	    }
1555782Slinton 	    break;
1565782Slinton 	}
1575543Slinton 
1585782Slinton 	case O_COMMA:
1595782Slinton 	    break;
1605543Slinton 
1615782Slinton 	case O_ITOF:
1625782Slinton 	    push(double, (double) r0);
1635782Slinton 	    break;
1645543Slinton 
1655782Slinton 	case O_ADD:
1665782Slinton 	    push(long, r0+r1);
1675782Slinton 	    break;
1685543Slinton 
1695782Slinton 	case O_ADDF:
1705782Slinton 	    push(double, fr0+fr1);
1715782Slinton 	    break;
1725543Slinton 
1735782Slinton 	case O_SUB:
1745782Slinton 	    push(long, r0-r1);
1755782Slinton 	    break;
1765543Slinton 
1775782Slinton 	case O_SUBF:
1785782Slinton 	    push(double, fr0-fr1);
1795782Slinton 	    break;
1805543Slinton 
1815782Slinton 	case O_NEG:
1825782Slinton 	    push(long, -r0);
1835782Slinton 	    break;
1845543Slinton 
1855782Slinton 	case O_NEGF:
1865782Slinton 	    push(double, -fr0);
1875782Slinton 	    break;
1885543Slinton 
1895782Slinton 	case O_MUL:
1905782Slinton 	    push(long, r0*r1);
1915782Slinton 	    break;
1925543Slinton 
1935782Slinton 	case O_MULF:
1945782Slinton 	    push(double, fr0*fr1);
1955782Slinton 	    break;
1965543Slinton 
1975782Slinton 	case O_DIVF:
1985782Slinton 	    if (fr1 == 0) {
1995782Slinton 		error("error: division by 0");
2005782Slinton 	    }
2015782Slinton 	    push(double, fr0/fr1);
2025782Slinton 	    break;
2035543Slinton 
2045782Slinton 	case O_DIV:
2055782Slinton 	    if (r1 == 0) {
2065782Slinton 		error("error: div by 0");
2075782Slinton 	    }
2085782Slinton 	    push(long, r0/r1);
2095782Slinton 	    break;
2105543Slinton 
2115782Slinton 	case O_MOD:
2125782Slinton 	    if (r1 == 0) {
2135782Slinton 		error("error: mod by 0");
2145782Slinton 	    }
2155782Slinton 	    push(long, r0%r1);
2165782Slinton 	    break;
2175543Slinton 
2185782Slinton 	case O_LT:
2196086Slinton 	    push(Boolean, r0 < r1);
2205782Slinton 	    break;
2215543Slinton 
2225782Slinton 	case O_LTF:
2236086Slinton 	    push(Boolean, fr0 < fr1);
2245782Slinton 	    break;
2255543Slinton 
2265782Slinton 	case O_LE:
2276086Slinton 	    push(Boolean, r0 <= r1);
2285782Slinton 	    break;
2295543Slinton 
2305782Slinton 	case O_LEF:
2316086Slinton 	    push(Boolean, fr0 <= fr1);
2325782Slinton 	    break;
2335543Slinton 
2345782Slinton 	case O_GT:
2356086Slinton 	    push(Boolean, r0 > r1);
2365782Slinton 	    break;
2375543Slinton 
2385782Slinton 	case O_GTF:
2396086Slinton 	    push(Boolean, fr0 > fr1);
2405782Slinton 	    break;
2415543Slinton 
2425782Slinton 	case O_EQ:
2436086Slinton 	    push(Boolean, r0 == r1);
2445782Slinton 	    break;
2455543Slinton 
2465782Slinton 	case O_EQF:
2476086Slinton 	    push(Boolean, fr0 == fr1);
2485782Slinton 	    break;
2495543Slinton 
2505782Slinton 	case O_NE:
2516086Slinton 	    push(Boolean, r0 != r1);
2525782Slinton 	    break;
2535543Slinton 
2545782Slinton 	case O_NEF:
2556086Slinton 	    push(Boolean, fr0 != fr1);
2565782Slinton 	    break;
2575543Slinton 
2585782Slinton 	case O_AND:
2596086Slinton 	    push(Boolean, r0 && r1);
2605782Slinton 	    break;
2615543Slinton 
2625782Slinton 	case O_OR:
2636086Slinton 	    push(Boolean, r0 || r1);
2645782Slinton 	    break;
2655543Slinton 
2665782Slinton 	case O_ASSIGN:
2675782Slinton 	    assign(p->left, p->right);
2685782Slinton 	    break;
2695543Slinton 
2705782Slinton 	case O_CHFILE:
2715782Slinton 	    if (p->sconval == NIL) {
2725782Slinton 		printf("%s\n", cursource);
2735782Slinton 	    } else {
2746874Slinton 		fp = fopen(p->sconval, "r");
2756874Slinton 		if (fp == NIL) {
2766874Slinton 		    error("can't read \"%s\"", p->sconval);
2776874Slinton 		} else {
2786874Slinton 		    fclose(fp);
2796874Slinton 		    skimsource(p->sconval);
2806874Slinton 		}
2815782Slinton 	    }
2825782Slinton 	    break;
2835543Slinton 
2845782Slinton 	case O_CONT:
2855782Slinton 	    cont();
2865782Slinton 	    printnews();
2875782Slinton 	    break;
2885543Slinton 
2895782Slinton 	case O_LIST: {
2905782Slinton 	    SYM *b;
2916083Slinton 	    ADDRESS addr;
2925543Slinton 
2935782Slinton 	    if (p->left->op == O_NAME) {
2945782Slinton 		b = p->left->nameval;
2955782Slinton 		if (!isblock(b)) {
2965782Slinton 		    error("\"%s\" is not a procedure or function", name(b));
2975543Slinton 		}
2986083Slinton 		addr = firstline(b);
2996083Slinton 		if (addr == -1) {
3006083Slinton 		    error("\"%s\" is empty", name(b));
3016083Slinton 		}
3026083Slinton 		skimsource(srcfilename(addr));
3036083Slinton 		r0 = srcline(addr);
3045782Slinton 		r1 = r0 + 5;
3055782Slinton 		if (r1 > lastlinenum) {
3065782Slinton 		    r1 = lastlinenum;
3075782Slinton 		}
3085782Slinton 		r0 = r0 - 5;
3095782Slinton 		if (r0 < 1) {
3105782Slinton 		    r0 = 1;
3115782Slinton 		}
3125782Slinton 	    } else {
3135782Slinton 		eval(p->left->right);
3145782Slinton 		eval(p->left->left);
3155782Slinton 		r0 = pop(long);
3165782Slinton 		r1 = pop(long);
3175782Slinton 	    }
3185782Slinton 	    printlines((LINENO) r0, (LINENO) r1);
3195782Slinton 	    break;
3205782Slinton 	}
3215543Slinton 
3225782Slinton 	case O_XI:
3235782Slinton 	case O_XD:
3245782Slinton 	{
3255782Slinton 	    SYM *b;
3265543Slinton 
3275782Slinton 	    if (p->left->op == O_CALL) {
3285782Slinton 		b = p->left->left->nameval;
3295782Slinton 		r0 = codeloc(b);
3305782Slinton 		r1 = firstline(b);
3315782Slinton 	    } else {
3325782Slinton 		eval(p->left->right);
3335782Slinton 		eval(p->left->left);
3345782Slinton 		r0 = pop(long);
3355782Slinton 		r1 = pop(long);
3365782Slinton 	    }
3375782Slinton 	    if (p->op == O_XI)  {
3385782Slinton 		printinst((ADDRESS) r0, (ADDRESS) r1);
3395782Slinton 	    } else {
3405782Slinton 		printdata((ADDRESS) r0, (ADDRESS) r1);
3415782Slinton 	    }
3425782Slinton 	    break;
3435782Slinton 	}
3445543Slinton 
3455782Slinton 	case O_NEXT:
3465782Slinton 	    next();
3475782Slinton 	    printnews();
3485782Slinton 	    break;
3495543Slinton 
3505782Slinton 	case O_PRINT: {
3515782Slinton 	    NODE *o;
3525543Slinton 
3535782Slinton 	    for (o = p->left; o != NIL; o = o->right) {
3545782Slinton 		eval(o->left);
3555782Slinton 		printval(o->left->nodetype);
3565782Slinton 		putchar(' ');
3575782Slinton 	    }
3585782Slinton 	    putchar('\n');
3595782Slinton 	    break;
3605782Slinton 	}
3615543Slinton 
3625782Slinton 	case O_STEP:
3635782Slinton 	    stepc();
3645782Slinton 	    printnews();
3655782Slinton 	    break;
3665543Slinton 
3675782Slinton 	case O_WHATIS:
3685782Slinton 	    if (p->left->op == O_NAME) {
3695782Slinton 		printdecl(p->left->nameval);
3705782Slinton 	    } else {
3715782Slinton 		printdecl(p->left->nodetype);
3725782Slinton 	    }
3735782Slinton 	    break;
3745543Slinton 
3755782Slinton 	case O_WHICH:
3765782Slinton 	    printwhich(p->nameval);
3775782Slinton 	    putchar('\n');
3785782Slinton 	    break;
3795543Slinton 
3805782Slinton 	case O_WHERE:
3815782Slinton 	    where();
3825782Slinton 	    break;
3835543Slinton 
3845782Slinton 	case O_ALIAS:
3855782Slinton 	    alias(p->left->sconval, p->right->sconval);
3865782Slinton 	    break;
3875543Slinton 
3885782Slinton 	case O_CALL:
3895782Slinton 	    callproc(p->left, p->right);
3905782Slinton 	    break;
3915543Slinton 
3925782Slinton 	case O_EDIT:
3935782Slinton 	    edit(p->sconval);
3945782Slinton 	    break;
3955543Slinton 
3965782Slinton 	case O_DUMP:
3975782Slinton 	    dump();
3985782Slinton 	    break;
3995543Slinton 
4005782Slinton 	case O_GRIPE:
4015782Slinton 	    gripe();
4025782Slinton 	    break;
4035562Slinton 
4045782Slinton 	case O_HELP:
4055782Slinton 	    help();
4065782Slinton 	    break;
4075543Slinton 
4085782Slinton 	case O_REMAKE:
4095782Slinton 	    remake();
4105782Slinton 	    break;
4115543Slinton 
4125782Slinton 	case O_RUN:
4135782Slinton 	    run();
4145782Slinton 	    break;
4155543Slinton 
4165782Slinton 	case O_SOURCE:
4175782Slinton 	    setinput(p->sconval);
4185782Slinton 	    break;
4195543Slinton 
4205782Slinton 	case O_STATUS:
4215782Slinton 	    status();
4225782Slinton 	    break;
4235543Slinton 
4245782Slinton 	case O_TRACE:
4255782Slinton 	case O_TRACEI:
4265782Slinton 	    trace(p->op, p->what, p->where, p->cond);
4275782Slinton 	    if (isstdin()) {
4285782Slinton 		status();
4295782Slinton 	    }
4305782Slinton 	    break;
4315543Slinton 
4325782Slinton 	case O_STOP:
4335782Slinton 	case O_STOPI:
4345782Slinton 	    stop(p->op, p->what, p->where, p->cond);
4355782Slinton 	    if (isstdin()) {
4365782Slinton 		status();
4375782Slinton 	    }
4385782Slinton 	    break;
4395543Slinton 
4405782Slinton 	case O_DELETE:
4415782Slinton 	    eval(p->left);
4425782Slinton 	    delbp((unsigned int) pop(long));
4435782Slinton 	    break;
4445543Slinton 
4455782Slinton 	default:
4465782Slinton 	    panic("eval: bad op %d", p->op);
4475782Slinton     }
4485543Slinton }
4495543Slinton 
4505543Slinton /*
4515562Slinton  * Push "len" bytes onto the expression stack from address "addr"
4525562Slinton  * in the process.  Normally TRUE is returned, however if there
4535562Slinton  * isn't enough room on the stack, rpush returns FALSE.
4545562Slinton  */
4555562Slinton 
4565562Slinton BOOLEAN rpush(addr, len)
4575562Slinton ADDRESS addr;
4585562Slinton int len;
4595562Slinton {
4605782Slinton     BOOLEAN success;
4615562Slinton 
4625782Slinton     if (sp + len >= &stack[STACKSIZE]) {
4635782Slinton 	success = FALSE;
4645782Slinton     } else {
4655782Slinton 	dread(sp, addr, len);
4665782Slinton 	sp += len;
4675782Slinton 	success = TRUE;
4685782Slinton     }
4695782Slinton     return success;
4705562Slinton }
4715562Slinton 
4725562Slinton /*
4735782Slinton  * Pop an item of the given type which is assumed to be no larger
4745782Slinton  * than a long and return it expanded into a long.
4755782Slinton  */
4765782Slinton 
4775782Slinton long popsmall(t)
4785782Slinton SYM *t;
4795782Slinton {
4805782Slinton     long r;
4815782Slinton 
4825782Slinton     switch (size(t)) {
4835782Slinton 	case sizeof(char):
4845782Slinton 	    r = (long) pop(char);
4855782Slinton 	    break;
4865782Slinton 
4875782Slinton 	case sizeof(short):
4885782Slinton 	    r = (long) pop(short);
4895782Slinton 	    break;
4905782Slinton 
4915782Slinton 	case sizeof(long):
4925782Slinton 	    r = pop(long);
4935782Slinton 	    break;
4945782Slinton 
49510765Slinton 	/*
49610765Slinton 	 * A bit of a kludge here.  If an array element is a record,
49710765Slinton 	 * the dot operation will be converted into an addition with
49810765Slinton 	 * the record operand having a type whose size may be larger
49910765Slinton 	 * than a word.  Now actually this is a pointer, but the subscript
50010765Slinton 	 * operation isn't aware of this, so it's just hacked here.
50110765Slinton 	 *
50210765Slinton 	 * The right thing to do is to make dot directly evaluated
50310765Slinton 	 * instead of changing it into addition.
50410765Slinton 	 */
5055782Slinton 	default:
50610765Slinton 	    r = pop(ADDRESS);
50710765Slinton 	    break;
5085782Slinton     }
5095782Slinton     return r;
5105782Slinton }
5115782Slinton 
5125782Slinton /*
5135543Slinton  * evaluate a conditional expression
5145543Slinton  */
5155543Slinton 
5165543Slinton BOOLEAN cond(p)
5175543Slinton NODE *p;
5185543Slinton {
5195782Slinton     if (p == NIL) {
5205782Slinton 	return(TRUE);
5215782Slinton     }
5225782Slinton     eval(p);
5235782Slinton     return(pop(BOOLEAN));
5245543Slinton }
5255543Slinton 
5265543Slinton /*
5275543Slinton  * Return the address corresponding to a given tree.
5285543Slinton  */
5295543Slinton 
5305543Slinton ADDRESS lval(p)
5315543Slinton NODE *p;
5325543Slinton {
5335782Slinton     eval(p);
5345782Slinton     return(pop(ADDRESS));
5355543Slinton }
536