xref: /csrg-svn/old/dbx/eval.c (revision 14445)
19662Slinton /* Copyright (c) 1982 Regents of the University of California */
29662Slinton 
3*14445Slinton static char sccsid[] = "@(#)eval.c 1.9 08/10/83";
49662Slinton 
59662Slinton /*
69662Slinton  * Tree evaluation.
79662Slinton  */
89662Slinton 
99662Slinton #include "defs.h"
109662Slinton #include "tree.h"
119662Slinton #include "operators.h"
129662Slinton #include "eval.h"
139662Slinton #include "events.h"
149662Slinton #include "symbols.h"
159662Slinton #include "scanner.h"
169662Slinton #include "source.h"
179662Slinton #include "object.h"
189662Slinton #include "mappings.h"
199662Slinton #include "process.h"
209662Slinton #include "machine.h"
219662Slinton #include <signal.h>
229662Slinton 
239662Slinton #ifndef public
249662Slinton 
259662Slinton #include "machine.h"
269662Slinton 
2712538Scsvaf #define STACKSIZE 20000
289662Slinton 
299662Slinton typedef Char Stack;
309662Slinton 
319662Slinton #define push(type, value) { \
329662Slinton     ((type *) (sp += sizeof(type)))[-1] = (value); \
339662Slinton }
349662Slinton 
359662Slinton #define pop(type) ( \
369662Slinton     (*((type *) (sp -= sizeof(type)))) \
379662Slinton )
389662Slinton 
399662Slinton #define alignstack() { \
409662Slinton     sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
419662Slinton }
429662Slinton 
439662Slinton #endif
449662Slinton 
459662Slinton public Stack stack[STACKSIZE];
469662Slinton public Stack *sp = &stack[0];
479662Slinton 
489662Slinton #define chksp() \
499662Slinton { \
509662Slinton     if (sp < &stack[0]) { \
519662Slinton 	panic("stack underflow"); \
529662Slinton     } \
539662Slinton }
549662Slinton 
559662Slinton #define poparg(n, r, fr) { \
569662Slinton     eval(p->value.arg[n]); \
579662Slinton     if (isreal(p->op)) { \
589662Slinton 	fr = pop(double); \
599662Slinton     } else if (isint(p->op)) { \
609662Slinton 	r = popsmall(p->value.arg[n]->nodetype); \
619662Slinton     } \
629662Slinton }
639662Slinton 
649662Slinton #define Boolrep char	/* underlying representation type for booleans */
659662Slinton 
669662Slinton /*
679662Slinton  * Evaluate a parse tree leaving the value on the top of the stack.
689662Slinton  */
699662Slinton 
709662Slinton public eval(p)
719662Slinton register Node p;
729662Slinton {
739662Slinton     long r0, r1;
749662Slinton     double fr0, fr1;
759662Slinton     Address addr;
769662Slinton     long i, n;
779662Slinton     int len;
789662Slinton     Symbol s, f;
799662Slinton     Node n1, n2;
809662Slinton     Boolean b;
819662Slinton     File file;
829662Slinton 
839662Slinton     checkref(p);
8413846Slinton     if (debug_flag[2]) {
8513846Slinton 	fprintf(stderr," evaluating %s \n",showoperator(p->op));
8612538Scsvaf     }
879662Slinton     switch (degree(p->op)) {
889662Slinton 	case BINARY:
899662Slinton 	    poparg(1, r1, fr1);
909662Slinton 	    poparg(0, r0, fr0);
919662Slinton 	    break;
929662Slinton 
939662Slinton 	case UNARY:
949662Slinton 	    poparg(0, r0, fr0);
959662Slinton 	    break;
969662Slinton 
979662Slinton 	default:
989662Slinton 	    /* do nothing */;
999662Slinton     }
1009662Slinton     switch (p->op) {
1019662Slinton 	case O_SYM:
1029662Slinton 	    s = p->value.sym;
1039662Slinton 	    if (s == retaddrsym) {
1049662Slinton 		push(long, return_addr());
1059662Slinton 	    } else {
1069662Slinton 		if (isvariable(s)) {
1079662Slinton 		    if (s != program and not isactive(container(s))) {
1089662Slinton 			error("\"%s\" is not active", symname(s));
1099662Slinton 		    }
1109662Slinton 		    push(long, address(s, nil));
1119662Slinton 		} else if (isblock(s)) {
1129662Slinton 		    push(Symbol, s);
1139662Slinton 		} else {
1149662Slinton 		    error("can't evaluate a %s", classname(s));
1159662Slinton 		}
1169662Slinton 	    }
1179662Slinton 	    break;
1189662Slinton 
1199662Slinton 	case O_LCON:
1209662Slinton 	    r0 = p->value.lcon;
1219662Slinton 	    pushsmall(p->nodetype, r0);
1229662Slinton 	    break;
1239662Slinton 
1249662Slinton 	case O_FCON:
1259662Slinton 	    push(double, p->value.fcon);
1269662Slinton 	    break;
1279662Slinton 
1289662Slinton 	case O_SCON:
1299662Slinton 	    len = size(p->nodetype);
1309662Slinton 	    mov(p->value.scon, sp, len);
1319662Slinton 	    sp += len;
1329662Slinton 	    break;
1339662Slinton 
1349662Slinton 	case O_INDEX:
1359662Slinton 	    n = pop(long);
1369662Slinton 	    i = evalindex(p->value.arg[0]->nodetype,
1379662Slinton 		popsmall(p->value.arg[1]->nodetype));
1389662Slinton 	    push(long, n + i*size(p->nodetype));
1399662Slinton 	    break;
1409662Slinton 
1419662Slinton 	case O_DOT:
1429662Slinton 	    s = p->value.arg[1]->value.sym;
1439662Slinton 	    n = lval(p->value.arg[0]);
1449662Slinton 	    push(long, n + (s->symvalue.field.offset div 8));
1459662Slinton 	    break;
1469662Slinton 
1479662Slinton 	/*
1489662Slinton 	 * Get the value of the expression addressed by the top of the stack.
1499662Slinton 	 * Push the result back on the stack.
1509662Slinton 	 */
1519662Slinton 
1529662Slinton 	case O_INDIR:
1539662Slinton 	case O_RVAL:
1549662Slinton 	    addr = pop(long);
1559662Slinton 	    if (addr == 0) {
1569662Slinton 		error("reference through nil pointer");
1579662Slinton 	    }
1589662Slinton 	    if (p->op == O_INDIR) {
1599662Slinton 		len = sizeof(long);
1609662Slinton 	    } else {
1619662Slinton 		len = size(p->nodetype);
1629662Slinton 	    }
1639662Slinton 	    rpush(addr, len);
16412538Scsvaf 	addr = pop(long);
16512538Scsvaf         push(long, addr);
1669662Slinton 	    break;
1679662Slinton 
16811175Slinton 	/*
16911175Slinton 	 * Effectively, we want to pop n bytes off for the evaluated subtree
17011175Slinton 	 * and push len bytes on for the new type of the same tree.
17111175Slinton 	 */
17211175Slinton 	case O_TYPERENAME:
17311175Slinton 	    n = size(p->value.arg[0]->nodetype);
17411175Slinton 	    len = size(p->nodetype);
17511175Slinton 	    sp = sp - n + len;
17611175Slinton 	    break;
17711175Slinton 
1789662Slinton 	case O_COMMA:
1799662Slinton 	    break;
1809662Slinton 
1819662Slinton 	case O_ITOF:
1829662Slinton 	    push(double, (double) r0);
1839662Slinton 	    break;
1849662Slinton 
1859662Slinton 	case O_ADD:
1869662Slinton 	    push(long, r0+r1);
1879662Slinton 	    break;
1889662Slinton 
1899662Slinton 	case O_ADDF:
1909662Slinton 	    push(double, fr0+fr1);
1919662Slinton 	    break;
1929662Slinton 
1939662Slinton 	case O_SUB:
1949662Slinton 	    push(long, r0-r1);
1959662Slinton 	    break;
1969662Slinton 
1979662Slinton 	case O_SUBF:
1989662Slinton 	    push(double, fr0-fr1);
1999662Slinton 	    break;
2009662Slinton 
2019662Slinton 	case O_NEG:
2029662Slinton 	    push(long, -r0);
2039662Slinton 	    break;
2049662Slinton 
2059662Slinton 	case O_NEGF:
2069662Slinton 	    push(double, -fr0);
2079662Slinton 	    break;
2089662Slinton 
2099662Slinton 	case O_MUL:
2109662Slinton 	    push(long, r0*r1);
2119662Slinton 	    break;
2129662Slinton 
2139662Slinton 	case O_MULF:
2149662Slinton 	    push(double, fr0*fr1);
2159662Slinton 	    break;
2169662Slinton 
2179662Slinton 	case O_DIVF:
2189662Slinton 	    if (fr1 == 0) {
2199662Slinton 		error("error: division by 0");
2209662Slinton 	    }
2219662Slinton 	    push(double, fr0 / fr1);
2229662Slinton 	    break;
2239662Slinton 
2249662Slinton 	case O_DIV:
2259662Slinton 	    if (r1 == 0) {
2269662Slinton 		error("error: div by 0");
2279662Slinton 	    }
2289662Slinton 	    push(long, r0 div r1);
2299662Slinton 	    break;
2309662Slinton 
2319662Slinton 	case O_MOD:
2329662Slinton 	    if (r1 == 0) {
2339662Slinton 		error("error: mod by 0");
2349662Slinton 	    }
2359662Slinton 	    push(long, r0 mod r1);
2369662Slinton 	    break;
2379662Slinton 
2389662Slinton 	case O_LT:
2399662Slinton 	    push(Boolrep, r0 < r1);
2409662Slinton 	    break;
2419662Slinton 
2429662Slinton 	case O_LTF:
2439662Slinton 	    push(Boolrep, fr0 < fr1);
2449662Slinton 	    break;
2459662Slinton 
2469662Slinton 	case O_LE:
2479662Slinton 	    push(Boolrep, r0 <= r1);
2489662Slinton 	    break;
2499662Slinton 
2509662Slinton 	case O_LEF:
2519662Slinton 	    push(Boolrep, fr0 <= fr1);
2529662Slinton 	    break;
2539662Slinton 
2549662Slinton 	case O_GT:
2559662Slinton 	    push(Boolrep, r0 > r1);
2569662Slinton 	    break;
2579662Slinton 
2589662Slinton 	case O_GTF:
2599662Slinton 	    push(Boolrep, fr0 > fr1);
2609662Slinton 	    break;
2619662Slinton 
2629662Slinton 	case O_EQ:
2639662Slinton 	    push(Boolrep, r0 == r1);
2649662Slinton 	    break;
2659662Slinton 
2669662Slinton 	case O_EQF:
2679662Slinton 	    push(Boolrep, fr0 == fr1);
2689662Slinton 	    break;
2699662Slinton 
2709662Slinton 	case O_NE:
2719662Slinton 	    push(Boolrep, r0 != r1);
2729662Slinton 	    break;
2739662Slinton 
2749662Slinton 	case O_NEF:
2759662Slinton 	    push(Boolrep, fr0 != fr1);
2769662Slinton 	    break;
2779662Slinton 
2789662Slinton 	case O_AND:
2799662Slinton 	    push(Boolrep, r0 and r1);
2809662Slinton 	    break;
2819662Slinton 
2829662Slinton 	case O_OR:
2839662Slinton 	    push(Boolrep, r0 or r1);
2849662Slinton 	    break;
2859662Slinton 
2869662Slinton 	case O_ASSIGN:
2879662Slinton 	    assign(p->value.arg[0], p->value.arg[1]);
2889662Slinton 	    break;
2899662Slinton 
2909662Slinton 	case O_CHFILE:
2919662Slinton 	    if (p->value.scon == nil) {
2929662Slinton 		printf("%s\n", cursource);
2939662Slinton 	    } else {
2949662Slinton 		file = opensource(p->value.scon);
2959662Slinton 		if (file == nil) {
2969662Slinton 		    error("can't read \"%s\"", p->value.scon);
2979662Slinton 		} else {
2989662Slinton 		    fclose(file);
2999662Slinton 		    setsource(p->value.scon);
3009662Slinton 		}
3019662Slinton 	    }
3029662Slinton 	    break;
3039662Slinton 
3049662Slinton 	case O_CONT:
30511871Slinton 	    cont(p->value.lcon);
3069662Slinton 	    printnews();
3079662Slinton 	    break;
3089662Slinton 
3099662Slinton 	case O_LIST:
3109662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
3119662Slinton 		f = p->value.arg[0]->value.sym;
3129662Slinton 		addr = firstline(f);
3139662Slinton 		if (addr == NOADDR) {
3149662Slinton 		    error("no source lines for \"%s\"", symname(f));
3159662Slinton 		}
3169662Slinton 		setsource(srcfilename(addr));
3179662Slinton 		r0 = srcline(addr) - 5;
3189662Slinton 		r1 = r0 + 10;
3199662Slinton 		if (r0 < 1) {
3209662Slinton 		    r0 = 1;
3219662Slinton 		}
3229662Slinton 	    } else {
3239662Slinton 		eval(p->value.arg[0]);
3249662Slinton 		r0 = pop(long);
3259662Slinton 		eval(p->value.arg[1]);
3269662Slinton 		r1 = pop(long);
3279662Slinton 	    }
3289662Slinton 	    printlines((Lineno) r0, (Lineno) r1);
3299662Slinton 	    break;
3309662Slinton 
3319662Slinton 	case O_FUNC:
3329662Slinton 	    if (p->value.arg[0] == nil) {
3339662Slinton 		printname(stdout, curfunc);
3349662Slinton 		putchar('\n');
3359662Slinton 	    } else {
33611871Slinton 		s = p->value.arg[0]->value.sym;
33711871Slinton 		find(f, s->name) where
33811871Slinton 		    f->class == FUNC or f->class == PROC
33911871Slinton 		endfind(f);
34011871Slinton 		if (f == nil) {
34111871Slinton 		    error("%s is not a procedure or function", symname(s));
34211771Slinton 		}
34311871Slinton 		curfunc = f;
3449662Slinton 		addr = codeloc(curfunc);
3459662Slinton 		if (addr != NOADDR) {
3469662Slinton 		    setsource(srcfilename(addr));
3479662Slinton 		    cursrcline = srcline(addr) - 5;
3489662Slinton 		    if (cursrcline < 1) {
3499662Slinton 			cursrcline = 1;
3509662Slinton 		    }
3519662Slinton 		}
3529662Slinton 	    }
3539662Slinton 	    break;
3549662Slinton 
3559662Slinton 	case O_EXAMINE:
3569662Slinton 	    eval(p->value.examine.beginaddr);
3579662Slinton 	    r0 = pop(long);
3589662Slinton 	    if (p->value.examine.endaddr == nil) {
3599662Slinton 		n = p->value.examine.count;
36011175Slinton 		if (n == 0) {
36111175Slinton 		    printvalue(r0, p->value.examine.mode);
36211175Slinton 		} else if (streq(p->value.examine.mode, "i")) {
3639662Slinton 		    printninst(n, (Address) r0);
3649662Slinton 		} else {
3659662Slinton 		    printndata(n, (Address) r0, p->value.examine.mode);
3669662Slinton 		}
3679662Slinton 	    } else {
3689662Slinton 		eval(p->value.examine.endaddr);
3699662Slinton 		r1 = pop(long);
3709662Slinton 		if (streq(p->value.examine.mode, "i")) {
3719662Slinton 		    printinst((Address)r0, (Address)r1);
3729662Slinton 		} else {
3739662Slinton 		    printdata((Address)r0, (Address)r1, p->value.examine.mode);
3749662Slinton 		}
3759662Slinton 	    }
3769662Slinton 	    break;
3779662Slinton 
3789662Slinton 	case O_PRINT:
3799662Slinton 	    for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) {
3809662Slinton 		eval(n1->value.arg[0]);
3819662Slinton 		printval(n1->value.arg[0]->nodetype);
3829662Slinton 		putchar(' ');
3839662Slinton 	    }
3849662Slinton 	    putchar('\n');
3859662Slinton 	    break;
3869662Slinton 
3879662Slinton 	case O_PSYM:
3889662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
3899662Slinton 		psym(p->value.arg[0]->value.sym);
3909662Slinton 	    } else {
3919662Slinton 		psym(p->value.arg[0]->nodetype);
3929662Slinton 	    }
3939662Slinton 	    break;
3949662Slinton 
3959662Slinton 	case O_QLINE:
3969662Slinton 	    eval(p->value.arg[1]);
3979662Slinton 	    break;
3989662Slinton 
3999662Slinton 	case O_STEP:
4009662Slinton 	    b = inst_tracing;
4019662Slinton 	    inst_tracing = (Boolean) (not p->value.step.source);
4029662Slinton 	    if (p->value.step.skipcalls) {
4039662Slinton 		next();
4049662Slinton 	    } else {
4059662Slinton 		stepc();
4069662Slinton 	    }
4079662Slinton 	    inst_tracing = b;
4089662Slinton 	    printnews();
4099662Slinton 	    break;
4109662Slinton 
4119662Slinton 	case O_WHATIS:
4129662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
4139662Slinton 		printdecl(p->value.arg[0]->value.sym);
4149662Slinton 	    } else {
4159662Slinton 		printdecl(p->value.arg[0]->nodetype);
4169662Slinton 	    }
4179662Slinton 	    break;
4189662Slinton 
4199662Slinton 	case O_WHERE:
4209662Slinton 	    wherecmd();
4219662Slinton 	    break;
4229662Slinton 
4239662Slinton 	case O_WHEREIS:
42412538Scsvaf 	    if (p->value.arg[0]->op == O_SYM) {
42512538Scsvaf 		printwhereis(stdout,p->value.arg[0]->value.sym);
42612538Scsvaf 	    } else {
42712538Scsvaf 		printwhereis(stdout,p->value.arg[0]->nodetype);
42812538Scsvaf 	    }
4299662Slinton 	    break;
4309662Slinton 
4319662Slinton 	case O_WHICH:
43212538Scsvaf 	    if (p->value.arg[0]->op == O_SYM) {
43312538Scsvaf 		printwhich(stdout,p->value.arg[0]->value.sym);
43412538Scsvaf 	    } else {
43512538Scsvaf 		printwhich(stdout,p->value.arg[0]->nodetype);
43612538Scsvaf 	    }
4379662Slinton 	    putchar('\n');
4389662Slinton 	    break;
4399662Slinton 
4409662Slinton 	case O_ALIAS:
4419662Slinton 	    n1 = p->value.arg[0];
4429662Slinton 	    n2 = p->value.arg[1];
4439662Slinton 	    if (n1 == nil) {
4449662Slinton 		print_alias(nil);
4459662Slinton 	    } else if (n2 == nil) {
4469662Slinton 		print_alias(n1->value.name);
4479662Slinton 	    } else {
4489662Slinton 		enter_alias(n1->value.name, n2->value.name);
4499662Slinton 	    }
4509662Slinton 	    break;
4519662Slinton 
4529662Slinton 	case O_CALL:
4539662Slinton 	    callproc(p->value.arg[0], p->value.arg[1]);
4549662Slinton 	    break;
4559662Slinton 
4569662Slinton 	case O_CATCH:
4579662Slinton 	    psigtrace(process, p->value.lcon, true);
4589662Slinton 	    break;
4599662Slinton 
4609662Slinton 	case O_EDIT:
4619662Slinton 	    edit(p->value.scon);
4629662Slinton 	    break;
4639662Slinton 
46412538Scsvaf         case O_DEBUG:
46512538Scsvaf             debug(p);
46612538Scsvaf 	    break;
46712538Scsvaf 
4689662Slinton 	case O_DUMP:
4699662Slinton 	    dump();
4709662Slinton 	    break;
4719662Slinton 
4729662Slinton 	case O_GRIPE:
4739662Slinton 	    gripe();
4749662Slinton 	    break;
4759662Slinton 
4769662Slinton 	case O_HELP:
4779662Slinton 	    help();
4789662Slinton 	    break;
4799662Slinton 
4809662Slinton 	case O_IGNORE:
4819662Slinton 	    psigtrace(process, p->value.lcon, false);
4829662Slinton 	    break;
4839662Slinton 
4849662Slinton 	case O_RUN:
4859662Slinton 	    run();
4869662Slinton 	    break;
4879662Slinton 
4889662Slinton 	case O_SOURCE:
4899662Slinton 	    setinput(p->value.scon);
4909662Slinton 	    break;
4919662Slinton 
4929662Slinton 	case O_STATUS:
4939662Slinton 	    status();
4949662Slinton 	    break;
4959662Slinton 
4969662Slinton 	case O_TRACE:
4979662Slinton 	case O_TRACEI:
4989662Slinton 	    trace(p);
4999662Slinton 	    break;
5009662Slinton 
5019662Slinton 	case O_STOP:
5029662Slinton 	case O_STOPI:
5039662Slinton 	    stop(p);
5049662Slinton 	    break;
5059662Slinton 
5069662Slinton 	case O_ADDEVENT:
5079662Slinton 	    addevent(p->value.event.cond, p->value.event.actions);
5089662Slinton 	    break;
5099662Slinton 
5109662Slinton 	case O_DELETE:
5119662Slinton 	    delevent((unsigned int) p->value.lcon);
5129662Slinton 	    break;
5139662Slinton 
5149662Slinton 	case O_ENDX:
5159662Slinton 	    endprogram();
5169662Slinton 	    break;
5179662Slinton 
5189662Slinton 	case O_IF:
5199662Slinton 	    if (cond(p->value.event.cond)) {
5209662Slinton 		evalcmdlist(p->value.event.actions);
5219662Slinton 	    }
5229662Slinton 	    break;
5239662Slinton 
5249662Slinton 	case O_ONCE:
5259662Slinton 	    event_once(p->value.event.cond, p->value.event.actions);
5269662Slinton 	    break;
5279662Slinton 
5289662Slinton 	case O_PRINTCALL:
5299662Slinton 	    printcall(p->value.sym, whatblock(return_addr()));
5309662Slinton 	    break;
5319662Slinton 
5329662Slinton 	case O_PRINTIFCHANGED:
5339662Slinton 	    printifchanged(p->value.arg[0]);
5349662Slinton 	    break;
5359662Slinton 
5369662Slinton 	case O_PRINTRTN:
5379662Slinton 	    printrtn(p->value.sym);
5389662Slinton 	    break;
5399662Slinton 
5409662Slinton 	case O_PRINTSRCPOS:
5419662Slinton 	    getsrcpos();
5429662Slinton 	    if (p->value.arg[0] == nil) {
5439662Slinton 		printsrcpos();
5449662Slinton 		putchar('\n');
5459662Slinton 		printlines(curline, curline);
5469662Slinton 	    } else if (p->value.arg[0]->op == O_QLINE) {
5479662Slinton 		if (p->value.arg[0]->value.arg[1]->value.lcon == 0) {
5489662Slinton 		    printf("tracei: ");
5499662Slinton 		    printinst(pc, pc);
5509662Slinton 		} else {
5519662Slinton 		    printf("trace:  ");
5529662Slinton 		    printlines(curline, curline);
5539662Slinton 		}
5549662Slinton 	    } else {
5559662Slinton 		printsrcpos();
5569662Slinton 		printf(": ");
5579662Slinton 		eval(p->value.arg[0]);
5589662Slinton 		prtree(stdout, p->value.arg[0]);
5599662Slinton 		printf(" = ");
5609662Slinton 		printval(p->value.arg[0]->nodetype);
5619662Slinton 		putchar('\n');
5629662Slinton 	    }
5639662Slinton 	    break;
5649662Slinton 
5659662Slinton 	case O_PROCRTN:
5669662Slinton 	    procreturn(p->value.sym);
5679662Slinton 	    break;
5689662Slinton 
5699662Slinton 	case O_STOPIFCHANGED:
5709662Slinton 	    stopifchanged(p->value.arg[0]);
5719662Slinton 	    break;
5729662Slinton 
5739662Slinton 	case O_STOPX:
5749662Slinton 	    isstopped = true;
5759662Slinton 	    break;
5769662Slinton 
5779662Slinton 	case O_TRACEON:
5789662Slinton 	    traceon(p->value.trace.inst, p->value.trace.event,
5799662Slinton 		p->value.trace.actions);
5809662Slinton 	    break;
5819662Slinton 
5829662Slinton 	case O_TRACEOFF:
5839662Slinton 	    traceoff(p->value.lcon);
5849662Slinton 	    break;
5859662Slinton 
5869662Slinton 	default:
5879662Slinton 	    panic("eval: bad op %d", p->op);
5889662Slinton     }
58912538Scsvaf  if(debug_flag[2]) {
59012538Scsvaf 	fprintf(stderr," evaluated %s \n",showoperator(p->op));
59112538Scsvaf  }
59212538Scsvaf 
5939662Slinton }
5949662Slinton 
5959662Slinton /*
5969662Slinton  * Evaluate a list of commands.
5979662Slinton  */
5989662Slinton 
5999662Slinton public evalcmdlist(cl)
6009662Slinton Cmdlist cl;
6019662Slinton {
6029662Slinton     Command c;
6039662Slinton 
6049662Slinton     foreach (Command, c, cl)
6059662Slinton 	evalcmd(c);
6069662Slinton     endfor
6079662Slinton }
6089662Slinton 
6099662Slinton /*
6109662Slinton  * Push "len" bytes onto the expression stack from address "addr"
6119662Slinton  * in the process.  If there isn't room on the stack, print an error message.
6129662Slinton  */
6139662Slinton 
6149662Slinton public rpush(addr, len)
6159662Slinton Address addr;
6169662Slinton int len;
6179662Slinton {
6189662Slinton     if (not canpush(len)) {
6199662Slinton 	error("expression too large to evaluate");
6209662Slinton     } else {
6219662Slinton 	chksp();
6229662Slinton 	dread(sp, addr, len);
6239662Slinton 	sp += len;
6249662Slinton     }
6259662Slinton }
6269662Slinton 
6279662Slinton /*
6289662Slinton  * Check if the stack has n bytes available.
6299662Slinton  */
6309662Slinton 
6319662Slinton public Boolean canpush(n)
6329662Slinton Integer n;
6339662Slinton {
6349662Slinton     return (Boolean) (sp + n < &stack[STACKSIZE]);
6359662Slinton }
6369662Slinton 
6379662Slinton /*
6389662Slinton  * Push a small scalar of the given type onto the stack.
6399662Slinton  */
6409662Slinton 
6419662Slinton public pushsmall(t, v)
6429662Slinton Symbol t;
6439662Slinton long v;
6449662Slinton {
6459662Slinton     register Integer s;
6469662Slinton 
6479662Slinton     s = size(t);
6489662Slinton     switch (s) {
6499662Slinton 	case sizeof(char):
6509662Slinton 	    push(char, v);
6519662Slinton 	    break;
6529662Slinton 
6539662Slinton 	case sizeof(short):
6549662Slinton 	    push(short, v);
6559662Slinton 	    break;
6569662Slinton 
6579662Slinton 	case sizeof(long):
6589662Slinton 	    push(long, v);
6599662Slinton 	    break;
6609662Slinton 
6619662Slinton 	default:
6629662Slinton 	    panic("bad size %d in popsmall", s);
6639662Slinton     }
6649662Slinton }
6659662Slinton 
6669662Slinton /*
6679662Slinton  * Pop an item of the given type which is assumed to be no larger
6689662Slinton  * than a long and return it expanded into a long.
6699662Slinton  */
6709662Slinton 
6719662Slinton public long popsmall(t)
6729662Slinton Symbol t;
6739662Slinton {
6749662Slinton     long r;
6759662Slinton 
6769662Slinton     switch (size(t)) {
6779662Slinton 	case sizeof(char):
6789662Slinton 	    r = (long) pop(char);
6799662Slinton 	    break;
6809662Slinton 
6819662Slinton 	case sizeof(short):
6829662Slinton 	    r = (long) pop(short);
6839662Slinton 	    break;
6849662Slinton 
6859662Slinton 	case sizeof(long):
6869662Slinton 	    r = pop(long);
6879662Slinton 	    break;
6889662Slinton 
6899662Slinton 	default:
6909662Slinton 	    panic("popsmall: size is %d", size(t));
6919662Slinton     }
6929662Slinton     return r;
6939662Slinton }
6949662Slinton 
6959662Slinton /*
6969662Slinton  * Evaluate a conditional expression.
6979662Slinton  */
6989662Slinton 
6999662Slinton public Boolean cond(p)
7009662Slinton Node p;
7019662Slinton {
7029662Slinton     register Boolean b;
7039662Slinton 
7049662Slinton     if (p == nil) {
7059662Slinton 	b = true;
7069662Slinton     } else {
7079662Slinton 	eval(p);
70813846Slinton 	b = (Boolean) pop(Boolrep);
7099662Slinton     }
7109662Slinton     return b;
7119662Slinton }
7129662Slinton 
7139662Slinton /*
7149662Slinton  * Return the address corresponding to a given tree.
7159662Slinton  */
7169662Slinton 
7179662Slinton public Address lval(p)
7189662Slinton Node p;
7199662Slinton {
7209662Slinton     if (p->op == O_RVAL) {
7219662Slinton 	eval(p->value.arg[0]);
7229662Slinton     } else {
7239662Slinton 	eval(p);
7249662Slinton     }
7259662Slinton     return (Address) (pop(long));
7269662Slinton }
7279662Slinton 
7289662Slinton /*
7299662Slinton  * Process a trace command, translating into the appropriate events
7309662Slinton  * and associated actions.
7319662Slinton  */
7329662Slinton 
7339662Slinton public trace(p)
7349662Slinton Node p;
7359662Slinton {
7369662Slinton     Node exp, place, cond;
7379662Slinton     Node left;
7389662Slinton 
7399662Slinton     exp = p->value.arg[0];
7409662Slinton     place = p->value.arg[1];
7419662Slinton     cond = p->value.arg[2];
7429662Slinton     if (exp == nil) {
7439662Slinton 	traceall(p->op, place, cond);
74411771Slinton     } else if (exp->op == O_QLINE or exp->op == O_LCON) {
7459662Slinton 	traceinst(p->op, exp, cond);
7469662Slinton     } else if (place != nil and place->op == O_QLINE) {
7479662Slinton 	traceat(p->op, exp, place, cond);
7489662Slinton     } else {
7499861Slinton 	left = exp;
7509861Slinton 	if (left->op == O_RVAL or left->op == O_CALL) {
7519861Slinton 	    left = left->value.arg[0];
7529861Slinton 	}
7539662Slinton 	if (left->op == O_SYM and isblock(left->value.sym)) {
7549662Slinton 	    traceproc(p->op, left->value.sym, place, cond);
7559662Slinton 	} else {
7569662Slinton 	    tracedata(p->op, exp, place, cond);
7579662Slinton 	}
7589662Slinton     }
7599662Slinton }
7609662Slinton 
7619662Slinton /*
7629662Slinton  * Set a breakpoint that will turn on tracing.
7639662Slinton  */
7649662Slinton 
7659662Slinton private traceall(op, place, cond)
7669662Slinton Operator op;
7679662Slinton Node place;
7689662Slinton Node cond;
7699662Slinton {
7709662Slinton     Symbol s;
7719662Slinton     Node event;
7729662Slinton     Command action;
7739662Slinton 
7749662Slinton     if (place == nil) {
7759662Slinton 	s = program;
7769662Slinton     } else {
7779662Slinton 	s = place->value.sym;
7789662Slinton     }
7799662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
7809662Slinton     action = build(O_PRINTSRCPOS,
7819662Slinton 	build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0)));
7829662Slinton     if (cond != nil) {
7839662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
7849662Slinton     }
7859662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
7869662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
78711871Slinton     if (isstdin()) {
78811871Slinton 	printevent(action->value.trace.event);
78911871Slinton     }
7909662Slinton }
7919662Slinton 
7929662Slinton /*
7939662Slinton  * Set up the appropriate breakpoint for tracing an instruction.
7949662Slinton  */
7959662Slinton 
7969662Slinton private traceinst(op, exp, cond)
7979662Slinton Operator op;
7989662Slinton Node exp;
7999662Slinton Node cond;
8009662Slinton {
80111771Slinton     Node event, wh;
8029662Slinton     Command action;
80311871Slinton     Event e;
8049662Slinton 
80511771Slinton     if (exp->op == O_LCON) {
80611771Slinton 	wh = build(O_QLINE, build(O_SCON, cursource), exp);
80711771Slinton     } else {
80811771Slinton 	wh = exp;
80911771Slinton     }
8109662Slinton     if (op == O_TRACEI) {
81111771Slinton 	event = build(O_EQ, build(O_SYM, pcsym), wh);
8129662Slinton     } else {
81311771Slinton 	event = build(O_EQ, build(O_SYM, linesym), wh);
8149662Slinton     }
81511771Slinton     action = build(O_PRINTSRCPOS, wh);
8169662Slinton     if (cond) {
8179662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
8189662Slinton     }
81911871Slinton     e = addevent(event, buildcmdlist(action));
82011871Slinton     if (isstdin()) {
82111871Slinton 	printevent(e);
82211871Slinton     }
8239662Slinton }
8249662Slinton 
8259662Slinton /*
8269662Slinton  * Set a breakpoint to print an expression at a given line or address.
8279662Slinton  */
8289662Slinton 
8299662Slinton private traceat(op, exp, place, cond)
8309662Slinton Operator op;
8319662Slinton Node exp;
8329662Slinton Node place;
8339662Slinton Node cond;
8349662Slinton {
8359662Slinton     Node event;
8369662Slinton     Command action;
83711871Slinton     Event e;
8389662Slinton 
8399662Slinton     if (op == O_TRACEI) {
8409662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
8419662Slinton     } else {
8429662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
8439662Slinton     }
8449662Slinton     action = build(O_PRINTSRCPOS, exp);
8459662Slinton     if (cond != nil) {
8469662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
8479662Slinton     }
84811871Slinton     e = addevent(event, buildcmdlist(action));
84911871Slinton     if (isstdin()) {
85011871Slinton 	printevent(e);
85111871Slinton     }
8529662Slinton }
8539662Slinton 
8549662Slinton /*
8559662Slinton  * Construct event for tracing a procedure.
8569662Slinton  *
8579662Slinton  * What we want here is
8589662Slinton  *
8599662Slinton  * 	when $proc = p do
8609662Slinton  *	    if <condition> then
8619662Slinton  *	        printcall;
8629662Slinton  *	        once $pc = $retaddr do
8639662Slinton  *	            printrtn;
8649662Slinton  *	        end;
8659662Slinton  *	    end if;
8669662Slinton  *	end;
8679662Slinton  *
8689662Slinton  * Note that "once" is like "when" except that the event
8699662Slinton  * deletes itself as part of its associated action.
8709662Slinton  */
8719662Slinton 
8729662Slinton private traceproc(op, p, place, cond)
8739662Slinton Operator op;
8749662Slinton Symbol p;
8759662Slinton Node place;
8769662Slinton Node cond;
8779662Slinton {
8789662Slinton     Node event;
8799662Slinton     Command action;
8809662Slinton     Cmdlist actionlist;
88111871Slinton     Event e;
8829662Slinton 
8839662Slinton     action = build(O_PRINTCALL, p);
8849662Slinton     actionlist = list_alloc();
8859662Slinton     cmdlist_append(action, actionlist);
8869662Slinton     event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym));
8879662Slinton     action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p)));
8889662Slinton     cmdlist_append(action, actionlist);
8899662Slinton     if (cond != nil) {
8909662Slinton 	actionlist = buildcmdlist(build(O_IF, cond, actionlist));
8919662Slinton     }
8929662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
89311871Slinton     e = addevent(event, actionlist);
89411871Slinton     if (isstdin()) {
89511871Slinton 	printevent(e);
89611871Slinton     }
8979662Slinton }
8989662Slinton 
8999662Slinton /*
9009662Slinton  * Set up breakpoint for tracing data.
9019662Slinton  */
9029662Slinton 
9039662Slinton private tracedata(op, exp, place, cond)
9049662Slinton Operator op;
9059662Slinton Node exp;
9069662Slinton Node place;
9079662Slinton Node cond;
9089662Slinton {
9099662Slinton     Symbol p;
9109662Slinton     Node event;
9119662Slinton     Command action;
9129662Slinton 
9139662Slinton     p = (place == nil) ? tcontainer(exp) : place->value.sym;
9149662Slinton     if (p == nil) {
9159662Slinton 	p = program;
9169662Slinton     }
9179662Slinton     action = build(O_PRINTIFCHANGED, exp);
9189662Slinton     if (cond != nil) {
9199662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
9209662Slinton     }
9219662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
9229662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
9239662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
92411871Slinton     if (isstdin()) {
92511871Slinton 	printevent(action->value.trace.event);
92611871Slinton     }
9279662Slinton }
9289662Slinton 
9299662Slinton /*
9309662Slinton  * Setting and unsetting of stops.
9319662Slinton  */
9329662Slinton 
9339662Slinton public stop(p)
9349662Slinton Node p;
9359662Slinton {
93613846Slinton     Node exp, place, cond, t;
9379662Slinton     Symbol s;
9389662Slinton     Command action;
93911871Slinton     Event e;
9409662Slinton 
9419662Slinton     exp = p->value.arg[0];
9429662Slinton     place = p->value.arg[1];
9439662Slinton     cond = p->value.arg[2];
9449662Slinton     if (exp != nil) {
9459662Slinton 	stopvar(p->op, exp, place, cond);
94613846Slinton     } else {
94713846Slinton 	action = build(O_STOPX);
94813846Slinton 	if (cond != nil) {
94913846Slinton 	    action = build(O_IF, cond, buildcmdlist(action));
95011871Slinton 	}
95113846Slinton 	if (place != nil and place->op == O_SYM) {
95213846Slinton 	    s = place->value.sym;
95313846Slinton 	    t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
95413846Slinton 	    if (cond != nil) {
95513846Slinton 		action = build(O_TRACEON, (p->op == O_STOPI),
95613846Slinton 		    buildcmdlist(action));
95713846Slinton 		e = addevent(t, buildcmdlist(action));
95813846Slinton 		action->value.trace.event = e;
95913846Slinton 	    } else {
96013846Slinton 		e = addevent(t, buildcmdlist(action));
96113846Slinton 	    }
96213846Slinton 	    if (isstdin()) {
96313846Slinton 		printevent(e);
96413846Slinton 	    }
96513846Slinton 	} else {
96613846Slinton 	    stopinst(p->op, place, cond, action);
96713846Slinton 	}
9689662Slinton     }
9699662Slinton }
9709662Slinton 
97113846Slinton private stopinst(op, place, cond, action)
9729662Slinton Operator op;
9739662Slinton Node place;
9749662Slinton Node cond;
97513846Slinton Command action;
9769662Slinton {
9779662Slinton     Node event;
97811871Slinton     Event e;
9799662Slinton 
9809662Slinton     if (op == O_STOP) {
9819662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
9829662Slinton     } else {
9839662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
9849662Slinton     }
98513846Slinton     e = addevent(event, buildcmdlist(action));
98611871Slinton     if (isstdin()) {
98711871Slinton 	printevent(e);
98811871Slinton     }
9899662Slinton }
9909662Slinton 
9919662Slinton /*
9929662Slinton  * Implement stopping on assignment to a variable by adding it to
9939662Slinton  * the variable list.
9949662Slinton  */
9959662Slinton 
9969662Slinton private stopvar(op, exp, place, cond)
9979662Slinton Operator op;
9989662Slinton Node exp;
9999662Slinton Node place;
10009662Slinton Node cond;
10019662Slinton {
10029662Slinton     Symbol p;
10039662Slinton     Node event;
10049662Slinton     Command action;
10059662Slinton 
1006*14445Slinton     if (place == nil) {
1007*14445Slinton 	if (exp->op == O_LCON) {
1008*14445Slinton 	    p = program;
1009*14445Slinton 	} else {
1010*14445Slinton 	    p = tcontainer(exp);
1011*14445Slinton 	    if (p == nil) {
1012*14445Slinton 		p = program;
1013*14445Slinton 	    }
1014*14445Slinton 	}
1015*14445Slinton     } else {
1016*14445Slinton 	p = place->value.sym;
10179662Slinton     }
1018*14445Slinton     action = build(O_STOPIFCHANGED, exp);
1019*14445Slinton     if (cond != nil) {
1020*14445Slinton 	action = build(O_IF, cond, buildcmdlist(action));
1021*14445Slinton     }
10229662Slinton     action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action));
10239662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
10249662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
102511871Slinton     if (isstdin()) {
102611871Slinton 	printevent(action->value.trace.event);
102711871Slinton     }
10289662Slinton }
10299662Slinton 
10309662Slinton /*
10319662Slinton  * Assign the value of an expression to a variable (or term).
10329662Slinton  */
10339662Slinton 
10349662Slinton public assign(var, exp)
10359662Slinton Node var;
10369662Slinton Node exp;
10379662Slinton {
10389662Slinton     Address addr;
10399662Slinton     int varsize;
10409662Slinton     char cvalue;
10419662Slinton     short svalue;
10429662Slinton     long lvalue;
10439662Slinton 
10449662Slinton     if (not compatible(var->nodetype, exp->nodetype)) {
10459662Slinton 	error("incompatible types");
10469662Slinton     }
10479662Slinton     addr = lval(var);
10489662Slinton     eval(exp);
10499662Slinton     varsize = size(var->nodetype);
10509662Slinton     if (varsize < sizeof(long)) {
10519662Slinton 	lvalue = pop(long);
10529662Slinton 	switch (varsize) {
10539662Slinton 	    case sizeof(char):
10549662Slinton 		cvalue = lvalue;
10559662Slinton 		dwrite(&cvalue, addr, varsize);
10569662Slinton 		break;
10579662Slinton 
10589662Slinton 	    case sizeof(short):
10599662Slinton 		svalue = lvalue;
10609662Slinton 		dwrite(&svalue, addr, varsize);
10619662Slinton 		break;
10629662Slinton 
10639662Slinton 	    default:
10649662Slinton 		panic("bad size %d", varsize);
10659662Slinton 	}
10669662Slinton     } else {
10679662Slinton 	sp -= varsize;
10689662Slinton 	dwrite(sp, addr, varsize);
10699662Slinton     }
10709662Slinton }
10719662Slinton 
10729662Slinton /*
10739662Slinton  * Send some nasty mail to the current support person.
10749662Slinton  */
10759662Slinton 
10769662Slinton public gripe()
10779662Slinton {
10789662Slinton     typedef Operation();
10799662Slinton     Operation *old;
1080*14445Slinton     int pid, status;
10819662Slinton 
1082*14445Slinton     char *maintainer = "linton@berkeley";
10839662Slinton 
10849662Slinton     puts("Type control-D to end your message.  Be sure to include");
10859662Slinton     puts("your name and the name of the file you are debugging.");
10869662Slinton     putchar('\n');
10879662Slinton     old = signal(SIGINT, SIG_DFL);
1088*14445Slinton     pid = back("Mail", stdin, stdout, "-s", "dbx gripe", maintainer, nil);
1089*14445Slinton     signal(SIGINT, SIG_IGN);
1090*14445Slinton     pwait(pid, &status);
10919662Slinton     signal(SIGINT, old);
1092*14445Slinton     if (status == 0) {
1093*14445Slinton 	puts("Thank you.");
1094*14445Slinton     } else {
1095*14445Slinton 	puts("\nMail not sent.");
1096*14445Slinton     }
10979662Slinton }
10989662Slinton 
10999662Slinton /*
11009662Slinton  * Give the user some help.
11019662Slinton  */
11029662Slinton 
11039662Slinton public help()
11049662Slinton {
11059662Slinton     puts("run                    - begin execution of the program");
11069662Slinton     puts("cont                   - continue execution");
11079662Slinton     puts("step                   - single step one line");
11089662Slinton     puts("next                   - step to next line (skip over calls)");
11099662Slinton     puts("trace <line#>          - trace execution of the line");
11109662Slinton     puts("trace <proc>           - trace calls to the procedure");
11119662Slinton     puts("trace <var>            - trace changes to the variable");
11129662Slinton     puts("trace <exp> at <line#> - print <exp> when <line> is reached");
11139662Slinton     puts("stop at <line>         - suspend execution at the line");
11149662Slinton     puts("stop in <proc>         - suspend execution when <proc> is called");
11159662Slinton     puts("status                 - print trace/stop's in effect");
11169662Slinton     puts("delete <number>        - remove trace or stop of given number");
11179662Slinton     puts("call <proc>            - call the procedure");
11189662Slinton     puts("where                  - print currently active procedures");
11199662Slinton     puts("print <exp>            - print the value of the expression");
11209662Slinton     puts("whatis <name>          - print the declaration of the name");
11219662Slinton     puts("list <line>, <line>    - list source lines");
11229662Slinton     puts("edit <proc>            - edit file containing <proc>");
11239662Slinton     puts("gripe                  - send mail to the person in charge of dbx");
11249662Slinton     puts("quit                   - exit dbx");
11259662Slinton }
11269662Slinton 
11279662Slinton /*
11289662Slinton  * Divert output to the given file name.
11299662Slinton  * Cannot redirect to an existing file.
11309662Slinton  */
11319662Slinton 
11329662Slinton private int so_fd;
11339662Slinton private Boolean notstdout;
11349662Slinton 
11359662Slinton public setout(filename)
11369662Slinton String filename;
11379662Slinton {
11389662Slinton     File f;
11399662Slinton 
11409662Slinton     f = fopen(filename, "r");
11419662Slinton     if (f != nil) {
11429662Slinton 	fclose(f);
11439662Slinton 	error("%s: file already exists", filename);
11449662Slinton     } else {
11459662Slinton 	so_fd = dup(1);
11469662Slinton 	close(1);
11479662Slinton 	if (creat(filename, 0666) == nil) {
11489662Slinton 	    unsetout();
11499662Slinton 	    error("can't create %s", filename);
11509662Slinton 	}
11519662Slinton 	notstdout = true;
11529662Slinton     }
11539662Slinton }
11549662Slinton 
11559662Slinton /*
11569662Slinton  * Revert output to standard output.
11579662Slinton  */
11589662Slinton 
11599662Slinton public unsetout()
11609662Slinton {
11619662Slinton     fflush(stdout);
11629662Slinton     close(1);
11639662Slinton     if (dup(so_fd) != 1) {
11649662Slinton 	panic("standard out dup failed");
11659662Slinton     }
11669662Slinton     close(so_fd);
11679662Slinton     notstdout = false;
11689662Slinton }
11699662Slinton 
11709662Slinton /*
11719662Slinton  * Determine is standard output is currently being redirected
11729662Slinton  * to a file (as far as we know).
11739662Slinton  */
11749662Slinton 
11759662Slinton public Boolean isredirected()
11769662Slinton {
11779662Slinton     return notstdout;
11789662Slinton }
1179