xref: /csrg-svn/old/dbx/eval.c (revision 42683)
121601Sdist /*
238105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
338105Sbostic  * All rights reserved.
438105Sbostic  *
5*42683Sbostic  * %sccs.include.redist.c%
621601Sdist  */
79662Slinton 
821601Sdist #ifndef lint
9*42683Sbostic static char sccsid[] = "@(#)eval.c	5.7 (Berkeley) 06/01/90";
1038105Sbostic #endif /* not lint */
119662Slinton 
129662Slinton /*
139662Slinton  * Tree evaluation.
149662Slinton  */
159662Slinton 
169662Slinton #include "defs.h"
179662Slinton #include "tree.h"
189662Slinton #include "operators.h"
1918217Slinton #include "debug.h"
209662Slinton #include "eval.h"
219662Slinton #include "events.h"
229662Slinton #include "symbols.h"
239662Slinton #include "scanner.h"
249662Slinton #include "source.h"
259662Slinton #include "object.h"
269662Slinton #include "mappings.h"
279662Slinton #include "process.h"
2816608Ssam #include "runtime.h"
299662Slinton #include "machine.h"
309662Slinton #include <signal.h>
319662Slinton 
329662Slinton #ifndef public
339662Slinton 
349662Slinton #include "machine.h"
359662Slinton 
3612538Scsvaf #define STACKSIZE 20000
379662Slinton 
389662Slinton typedef Char Stack;
399662Slinton 
409662Slinton #define push(type, value) { \
419662Slinton     ((type *) (sp += sizeof(type)))[-1] = (value); \
429662Slinton }
439662Slinton 
449662Slinton #define pop(type) ( \
459662Slinton     (*((type *) (sp -= sizeof(type)))) \
469662Slinton )
479662Slinton 
4816608Ssam #define popn(n, dest) { \
4916608Ssam     sp -= n; \
5016608Ssam     bcopy(sp, dest, n); \
5116608Ssam }
5216608Ssam 
539662Slinton #define alignstack() { \
549662Slinton     sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
559662Slinton }
569662Slinton 
579662Slinton #endif
589662Slinton 
599662Slinton public Stack stack[STACKSIZE];
609662Slinton public Stack *sp = &stack[0];
6114674Slinton public Boolean useInstLoc = false;
629662Slinton 
639662Slinton #define chksp() \
649662Slinton { \
659662Slinton     if (sp < &stack[0]) { \
669662Slinton 	panic("stack underflow"); \
679662Slinton     } \
689662Slinton }
699662Slinton 
709662Slinton #define poparg(n, r, fr) { \
719662Slinton     eval(p->value.arg[n]); \
729662Slinton     if (isreal(p->op)) { \
7316608Ssam 	if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \
7416608Ssam 	    fr = pop(float); \
7516608Ssam 	} else { \
7616608Ssam 	    fr = pop(double); \
7716608Ssam 	} \
789662Slinton     } else if (isint(p->op)) { \
799662Slinton 	r = popsmall(p->value.arg[n]->nodetype); \
809662Slinton     } \
819662Slinton }
829662Slinton 
839662Slinton #define Boolrep char	/* underlying representation type for booleans */
849662Slinton 
859662Slinton /*
8618217Slinton  * Command-level evaluation.
8718217Slinton  */
8818217Slinton 
8918217Slinton public Node topnode;
9018217Slinton 
topeval(p)9118217Slinton public topeval (p)
9218217Slinton Node p;
9318217Slinton {
9418217Slinton     if (traceeval) {
9518217Slinton 	fprintf(stderr, "topeval(");
9618217Slinton 	prtree(stderr, p);
9718217Slinton 	fprintf(stderr, ")\n");
9818217Slinton 	fflush(stderr);
9918217Slinton     }
10018217Slinton     topnode = p;
10118217Slinton     eval(p);
10218217Slinton }
10318217Slinton 
10418217Slinton /*
1059662Slinton  * Evaluate a parse tree leaving the value on the top of the stack.
1069662Slinton  */
1079662Slinton 
eval(p)1089662Slinton public eval(p)
1099662Slinton register Node p;
1109662Slinton {
1119662Slinton     long r0, r1;
1129662Slinton     double fr0, fr1;
1139662Slinton     Address addr;
1149662Slinton     long i, n;
1159662Slinton     int len;
11618217Slinton     Symbol s;
1179662Slinton     Node n1, n2;
11818217Slinton     boolean b;
1199662Slinton     File file;
12018217Slinton     String str;
1219662Slinton 
1229662Slinton     checkref(p);
12318217Slinton     if (traceeval) {
12418217Slinton 	fprintf(stderr, "begin eval %s\n", opname(p->op));
12512538Scsvaf     }
1269662Slinton     switch (degree(p->op)) {
1279662Slinton 	case BINARY:
1289662Slinton 	    poparg(1, r1, fr1);
1299662Slinton 	    poparg(0, r0, fr0);
1309662Slinton 	    break;
1319662Slinton 
1329662Slinton 	case UNARY:
1339662Slinton 	    poparg(0, r0, fr0);
1349662Slinton 	    break;
1359662Slinton 
1369662Slinton 	default:
1379662Slinton 	    /* do nothing */;
1389662Slinton     }
1399662Slinton     switch (p->op) {
1409662Slinton 	case O_SYM:
1419662Slinton 	    s = p->value.sym;
1429662Slinton 	    if (s == retaddrsym) {
1439662Slinton 		push(long, return_addr());
14418217Slinton 	    } else if (isvariable(s)) {
14518217Slinton 		if (s != program and not isactive(container(s))) {
14618217Slinton 		    error("\"%s\" is not active", symname(s));
14718217Slinton 		}
14818217Slinton 		if (isvarparam(s) and not isopenarray(s)) {
14918217Slinton 		    rpush(address(s, nil), sizeof(Address));
1509662Slinton 		} else {
15118217Slinton 		    push(Address, address(s, nil));
1529662Slinton 		}
15318217Slinton 	    } else if (isblock(s)) {
15418217Slinton 		push(Symbol, s);
15518217Slinton 	    } else if (isconst(s)) {
15618217Slinton 		eval(constval(s));
15718217Slinton 	    } else {
15818217Slinton 		error("can't evaluate a %s", classname(s));
1599662Slinton 	    }
1609662Slinton 	    break;
1619662Slinton 
1629662Slinton 	case O_LCON:
16318217Slinton 	case O_CCON:
1649662Slinton 	    r0 = p->value.lcon;
1659662Slinton 	    pushsmall(p->nodetype, r0);
1669662Slinton 	    break;
1679662Slinton 
1689662Slinton 	case O_FCON:
1699662Slinton 	    push(double, p->value.fcon);
1709662Slinton 	    break;
1719662Slinton 
1729662Slinton 	case O_SCON:
1739662Slinton 	    len = size(p->nodetype);
1749662Slinton 	    mov(p->value.scon, sp, len);
1759662Slinton 	    sp += len;
1769662Slinton 	    break;
1779662Slinton 
1789662Slinton 	case O_INDEX:
17918217Slinton 	    s = p->value.arg[0]->nodetype;
18018217Slinton 	    p->value.arg[0]->nodetype = t_addr;
18118217Slinton 	    eval(p->value.arg[0]);
18218217Slinton 	    p->value.arg[0]->nodetype = s;
18318217Slinton 	    n = pop(Address);
18418217Slinton 	    eval(p->value.arg[1]);
18518217Slinton 	    evalindex(s, n, popsmall(p->value.arg[1]->nodetype));
1869662Slinton 	    break;
1879662Slinton 
1889662Slinton 	case O_DOT:
1899662Slinton 	    s = p->value.arg[1]->value.sym;
19018217Slinton 	    eval(p->value.arg[0]);
19118217Slinton 	    n = pop(long);
1929662Slinton 	    push(long, n + (s->symvalue.field.offset div 8));
1939662Slinton 	    break;
1949662Slinton 
1959662Slinton 	/*
1969662Slinton 	 * Get the value of the expression addressed by the top of the stack.
1979662Slinton 	 * Push the result back on the stack.
1989662Slinton 	 */
1999662Slinton 
2009662Slinton 	case O_INDIR:
2019662Slinton 	case O_RVAL:
2029662Slinton 	    addr = pop(long);
2039662Slinton 	    if (addr == 0) {
2049662Slinton 		error("reference through nil pointer");
2059662Slinton 	    }
20618217Slinton 	    len = size(p->nodetype);
2079662Slinton 	    rpush(addr, len);
2089662Slinton 	    break;
2099662Slinton 
21011175Slinton 	case O_TYPERENAME:
21133315Sdonn 	    loophole(size(p->value.arg[0]->nodetype), size(p->nodetype));
21211175Slinton 	    break;
21311175Slinton 
2149662Slinton 	case O_COMMA:
21518217Slinton 	    eval(p->value.arg[0]);
21618217Slinton 	    if (p->value.arg[1] != nil) {
21718217Slinton 		eval(p->value.arg[1]);
21818217Slinton 	    }
2199662Slinton 	    break;
2209662Slinton 
2219662Slinton 	case O_ITOF:
2229662Slinton 	    push(double, (double) r0);
2239662Slinton 	    break;
2249662Slinton 
2259662Slinton 	case O_ADD:
2269662Slinton 	    push(long, r0+r1);
2279662Slinton 	    break;
2289662Slinton 
2299662Slinton 	case O_ADDF:
2309662Slinton 	    push(double, fr0+fr1);
2319662Slinton 	    break;
2329662Slinton 
2339662Slinton 	case O_SUB:
2349662Slinton 	    push(long, r0-r1);
2359662Slinton 	    break;
2369662Slinton 
2379662Slinton 	case O_SUBF:
2389662Slinton 	    push(double, fr0-fr1);
2399662Slinton 	    break;
2409662Slinton 
2419662Slinton 	case O_NEG:
2429662Slinton 	    push(long, -r0);
2439662Slinton 	    break;
2449662Slinton 
2459662Slinton 	case O_NEGF:
2469662Slinton 	    push(double, -fr0);
2479662Slinton 	    break;
2489662Slinton 
2499662Slinton 	case O_MUL:
2509662Slinton 	    push(long, r0*r1);
2519662Slinton 	    break;
2529662Slinton 
2539662Slinton 	case O_MULF:
2549662Slinton 	    push(double, fr0*fr1);
2559662Slinton 	    break;
2569662Slinton 
2579662Slinton 	case O_DIVF:
2589662Slinton 	    if (fr1 == 0) {
2599662Slinton 		error("error: division by 0");
2609662Slinton 	    }
2619662Slinton 	    push(double, fr0 / fr1);
2629662Slinton 	    break;
2639662Slinton 
2649662Slinton 	case O_DIV:
2659662Slinton 	    if (r1 == 0) {
2669662Slinton 		error("error: div by 0");
2679662Slinton 	    }
2689662Slinton 	    push(long, r0 div r1);
2699662Slinton 	    break;
2709662Slinton 
2719662Slinton 	case O_MOD:
2729662Slinton 	    if (r1 == 0) {
2739662Slinton 		error("error: mod by 0");
2749662Slinton 	    }
2759662Slinton 	    push(long, r0 mod r1);
2769662Slinton 	    break;
2779662Slinton 
2789662Slinton 	case O_LT:
2799662Slinton 	    push(Boolrep, r0 < r1);
2809662Slinton 	    break;
2819662Slinton 
2829662Slinton 	case O_LTF:
2839662Slinton 	    push(Boolrep, fr0 < fr1);
2849662Slinton 	    break;
2859662Slinton 
2869662Slinton 	case O_LE:
2879662Slinton 	    push(Boolrep, r0 <= r1);
2889662Slinton 	    break;
2899662Slinton 
2909662Slinton 	case O_LEF:
2919662Slinton 	    push(Boolrep, fr0 <= fr1);
2929662Slinton 	    break;
2939662Slinton 
2949662Slinton 	case O_GT:
2959662Slinton 	    push(Boolrep, r0 > r1);
2969662Slinton 	    break;
2979662Slinton 
2989662Slinton 	case O_GTF:
2999662Slinton 	    push(Boolrep, fr0 > fr1);
3009662Slinton 	    break;
3019662Slinton 
3029662Slinton 	case O_EQ:
3039662Slinton 	    push(Boolrep, r0 == r1);
3049662Slinton 	    break;
3059662Slinton 
3069662Slinton 	case O_EQF:
3079662Slinton 	    push(Boolrep, fr0 == fr1);
3089662Slinton 	    break;
3099662Slinton 
3109662Slinton 	case O_NE:
3119662Slinton 	    push(Boolrep, r0 != r1);
3129662Slinton 	    break;
3139662Slinton 
3149662Slinton 	case O_NEF:
3159662Slinton 	    push(Boolrep, fr0 != fr1);
3169662Slinton 	    break;
3179662Slinton 
3189662Slinton 	case O_AND:
3199662Slinton 	    push(Boolrep, r0 and r1);
3209662Slinton 	    break;
3219662Slinton 
3229662Slinton 	case O_OR:
3239662Slinton 	    push(Boolrep, r0 or r1);
3249662Slinton 	    break;
3259662Slinton 
3269662Slinton 	case O_ASSIGN:
3279662Slinton 	    assign(p->value.arg[0], p->value.arg[1]);
3289662Slinton 	    break;
3299662Slinton 
3309662Slinton 	case O_CHFILE:
3319662Slinton 	    if (p->value.scon == nil) {
3329662Slinton 		printf("%s\n", cursource);
3339662Slinton 	    } else {
3349662Slinton 		file = opensource(p->value.scon);
3359662Slinton 		if (file == nil) {
3369662Slinton 		    error("can't read \"%s\"", p->value.scon);
3379662Slinton 		} else {
3389662Slinton 		    fclose(file);
3399662Slinton 		    setsource(p->value.scon);
3409662Slinton 		}
3419662Slinton 	    }
3429662Slinton 	    break;
3439662Slinton 
3449662Slinton 	case O_CONT:
34511871Slinton 	    cont(p->value.lcon);
3469662Slinton 	    printnews();
3479662Slinton 	    break;
3489662Slinton 
3499662Slinton 	case O_LIST:
35018217Slinton 	    list(p);
3519662Slinton 	    break;
3529662Slinton 
3539662Slinton 	case O_FUNC:
35418217Slinton 	    func(p->value.arg[0]);
3559662Slinton 	    break;
3569662Slinton 
3579662Slinton 	case O_EXAMINE:
3589662Slinton 	    eval(p->value.examine.beginaddr);
3599662Slinton 	    r0 = pop(long);
3609662Slinton 	    if (p->value.examine.endaddr == nil) {
3619662Slinton 		n = p->value.examine.count;
36211175Slinton 		if (n == 0) {
36311175Slinton 		    printvalue(r0, p->value.examine.mode);
36411175Slinton 		} else if (streq(p->value.examine.mode, "i")) {
3659662Slinton 		    printninst(n, (Address) r0);
3669662Slinton 		} else {
3679662Slinton 		    printndata(n, (Address) r0, p->value.examine.mode);
3689662Slinton 		}
3699662Slinton 	    } else {
3709662Slinton 		eval(p->value.examine.endaddr);
3719662Slinton 		r1 = pop(long);
3729662Slinton 		if (streq(p->value.examine.mode, "i")) {
3739662Slinton 		    printinst((Address)r0, (Address)r1);
3749662Slinton 		} else {
3759662Slinton 		    printdata((Address)r0, (Address)r1, p->value.examine.mode);
3769662Slinton 		}
3779662Slinton 	    }
3789662Slinton 	    break;
3799662Slinton 
3809662Slinton 	case O_PRINT:
3819662Slinton 	    for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) {
3829662Slinton 		eval(n1->value.arg[0]);
3839662Slinton 		printval(n1->value.arg[0]->nodetype);
3849662Slinton 		putchar(' ');
3859662Slinton 	    }
3869662Slinton 	    putchar('\n');
3879662Slinton 	    break;
3889662Slinton 
3899662Slinton 	case O_PSYM:
3909662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
3919662Slinton 		psym(p->value.arg[0]->value.sym);
3929662Slinton 	    } else {
3939662Slinton 		psym(p->value.arg[0]->nodetype);
3949662Slinton 	    }
3959662Slinton 	    break;
3969662Slinton 
3979662Slinton 	case O_QLINE:
3989662Slinton 	    eval(p->value.arg[1]);
3999662Slinton 	    break;
4009662Slinton 
4019662Slinton 	case O_STEP:
4029662Slinton 	    b = inst_tracing;
4039662Slinton 	    inst_tracing = (Boolean) (not p->value.step.source);
4049662Slinton 	    if (p->value.step.skipcalls) {
4059662Slinton 		next();
4069662Slinton 	    } else {
4079662Slinton 		stepc();
4089662Slinton 	    }
4099662Slinton 	    inst_tracing = b;
41014674Slinton 	    useInstLoc = (Boolean) (not p->value.step.source);
4119662Slinton 	    printnews();
4129662Slinton 	    break;
4139662Slinton 
4149662Slinton 	case O_WHATIS:
4159662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
4169662Slinton 		printdecl(p->value.arg[0]->value.sym);
4179662Slinton 	    } else {
4189662Slinton 		printdecl(p->value.arg[0]->nodetype);
4199662Slinton 	    }
4209662Slinton 	    break;
4219662Slinton 
4229662Slinton 	case O_WHERE:
4239662Slinton 	    wherecmd();
4249662Slinton 	    break;
4259662Slinton 
4269662Slinton 	case O_WHEREIS:
42712538Scsvaf 	    if (p->value.arg[0]->op == O_SYM) {
42818217Slinton 		printwhereis(stdout, p->value.arg[0]->value.sym);
42912538Scsvaf 	    } else {
43018217Slinton 		printwhereis(stdout, p->value.arg[0]->nodetype);
43112538Scsvaf 	    }
4329662Slinton 	    break;
4339662Slinton 
4349662Slinton 	case O_WHICH:
43512538Scsvaf 	    if (p->value.arg[0]->op == O_SYM) {
43618217Slinton 		printwhich(stdout, p->value.arg[0]->value.sym);
43712538Scsvaf 	    } else {
43818217Slinton 		printwhich(stdout, p->value.arg[0]->nodetype);
43912538Scsvaf 	    }
4409662Slinton 	    putchar('\n');
4419662Slinton 	    break;
4429662Slinton 
4439662Slinton 	case O_ALIAS:
4449662Slinton 	    n1 = p->value.arg[0];
4459662Slinton 	    n2 = p->value.arg[1];
44618217Slinton 	    if (n2 == nil) {
44718217Slinton 		if (n1 == nil) {
44818217Slinton 		    alias(nil, nil, nil);
44918217Slinton 		} else {
45018217Slinton 		    alias(n1->value.name, nil, nil);
45118217Slinton 		}
45218217Slinton 	    } else if (n2->op == O_NAME) {
45318217Slinton 		str = ident(n2->value.name);
45418217Slinton 		alias(n1->value.name, nil, strdup(str));
4559662Slinton 	    } else {
45618217Slinton 		if (n1->op == O_COMMA) {
45718217Slinton 		    alias(
45818217Slinton 			n1->value.arg[0]->value.name,
45918217Slinton 			(List) n1->value.arg[1],
46018217Slinton 			n2->value.scon
46118217Slinton 		    );
46218217Slinton 		} else {
46318217Slinton 		    alias(n1->value.name, nil, n2->value.scon);
46418217Slinton 		}
4659662Slinton 	    }
4669662Slinton 	    break;
4679662Slinton 
46818217Slinton 	case O_UNALIAS:
46918217Slinton 	    unalias(p->value.arg[0]->value.name);
47018217Slinton 	    break;
47118217Slinton 
47218217Slinton 	case O_CALLPROC:
47318217Slinton 	    callproc(p, false);
47418217Slinton 	    break;
47518217Slinton 
4769662Slinton 	case O_CALL:
47718217Slinton 	    callproc(p, true);
4789662Slinton 	    break;
4799662Slinton 
4809662Slinton 	case O_CATCH:
48118217Slinton 	    if (p->value.lcon == 0) {
48218217Slinton 		printsigscaught(process);
48318217Slinton 	    } else {
48418217Slinton 		psigtrace(process, p->value.lcon, true);
48518217Slinton 	    }
4869662Slinton 	    break;
4879662Slinton 
4889662Slinton 	case O_EDIT:
4899662Slinton 	    edit(p->value.scon);
4909662Slinton 	    break;
4919662Slinton 
49212538Scsvaf         case O_DEBUG:
49312538Scsvaf             debug(p);
49412538Scsvaf 	    break;
49512538Scsvaf 
49616608Ssam 	case O_DOWN:
49716608Ssam 	    checkref(p->value.arg[0]);
49816608Ssam 	    assert(p->value.arg[0]->op == O_LCON);
49916608Ssam 	    down(p->value.arg[0]->value.lcon);
50016608Ssam 	    break;
50116608Ssam 
5029662Slinton 	case O_DUMP:
50318217Slinton 	    if (p->value.arg[0] == nil) {
50418217Slinton 		dumpall();
50518217Slinton 	    } else {
50618217Slinton 		s = p->value.arg[0]->value.sym;
50718217Slinton 		if (s == curfunc) {
50818217Slinton 		    dump(nil);
50918217Slinton 		} else {
51018217Slinton 		    dump(s);
51118217Slinton 		}
51218217Slinton 	    }
5139662Slinton 	    break;
5149662Slinton 
5159662Slinton 	case O_GRIPE:
5169662Slinton 	    gripe();
5179662Slinton 	    break;
5189662Slinton 
5199662Slinton 	case O_HELP:
5209662Slinton 	    help();
5219662Slinton 	    break;
5229662Slinton 
5239662Slinton 	case O_IGNORE:
52418217Slinton 	    if (p->value.lcon == 0) {
52518217Slinton 		printsigsignored(process);
52618217Slinton 	    } else {
52718217Slinton 		psigtrace(process, p->value.lcon, false);
52818217Slinton 	    }
5299662Slinton 	    break;
5309662Slinton 
53116608Ssam 	case O_RETURN:
53216608Ssam 	    if (p->value.arg[0] == nil) {
53316608Ssam 		rtnfunc(nil);
53416608Ssam 	    } else {
53516608Ssam 		assert(p->value.arg[0]->op == O_SYM);
53616608Ssam 		rtnfunc(p->value.arg[0]->value.sym);
53716608Ssam 	    }
53816608Ssam 	    break;
53916608Ssam 
5409662Slinton 	case O_RUN:
5419662Slinton 	    run();
5429662Slinton 	    break;
5439662Slinton 
54418217Slinton 	case O_SET:
54518217Slinton 	    set(p->value.arg[0], p->value.arg[1]);
54618217Slinton 	    break;
54718217Slinton 
54818217Slinton 	case O_SEARCH:
54918217Slinton 	    search(p->value.arg[0]->value.lcon, p->value.arg[1]->value.scon);
55018217Slinton 	    break;
55118217Slinton 
5529662Slinton 	case O_SOURCE:
5539662Slinton 	    setinput(p->value.scon);
5549662Slinton 	    break;
5559662Slinton 
5569662Slinton 	case O_STATUS:
5579662Slinton 	    status();
5589662Slinton 	    break;
5599662Slinton 
5609662Slinton 	case O_TRACE:
5619662Slinton 	case O_TRACEI:
5629662Slinton 	    trace(p);
5639662Slinton 	    break;
5649662Slinton 
5659662Slinton 	case O_STOP:
5669662Slinton 	case O_STOPI:
5679662Slinton 	    stop(p);
5689662Slinton 	    break;
5699662Slinton 
57018217Slinton 	case O_UNSET:
57118217Slinton 	    undefvar(p->value.arg[0]->value.name);
57218217Slinton 	    break;
57318217Slinton 
57416608Ssam 	case O_UP:
57516608Ssam 	    checkref(p->value.arg[0]);
57616608Ssam 	    assert(p->value.arg[0]->op == O_LCON);
57716608Ssam 	    up(p->value.arg[0]->value.lcon);
57816608Ssam 	    break;
57916608Ssam 
5809662Slinton 	case O_ADDEVENT:
5819662Slinton 	    addevent(p->value.event.cond, p->value.event.actions);
5829662Slinton 	    break;
5839662Slinton 
5849662Slinton 	case O_DELETE:
58516608Ssam 	    n1 = p->value.arg[0];
58616608Ssam 	    while (n1->op == O_COMMA) {
58716608Ssam 		n2 = n1->value.arg[0];
58816608Ssam 		assert(n2->op == O_LCON);
58916608Ssam 		if (not delevent((unsigned int) n2->value.lcon)) {
59016608Ssam 		    error("unknown event %ld", n2->value.lcon);
59116608Ssam 		}
59216608Ssam 		n1 = n1->value.arg[1];
59316608Ssam 	    }
59416608Ssam 	    assert(n1->op == O_LCON);
59516608Ssam 	    if (not delevent((unsigned int) n1->value.lcon)) {
59616608Ssam 		error("unknown event %ld", n1->value.lcon);
59716608Ssam 	    }
5989662Slinton 	    break;
5999662Slinton 
6009662Slinton 	case O_ENDX:
6019662Slinton 	    endprogram();
6029662Slinton 	    break;
6039662Slinton 
6049662Slinton 	case O_IF:
6059662Slinton 	    if (cond(p->value.event.cond)) {
6069662Slinton 		evalcmdlist(p->value.event.actions);
6079662Slinton 	    }
6089662Slinton 	    break;
6099662Slinton 
6109662Slinton 	case O_ONCE:
6119662Slinton 	    event_once(p->value.event.cond, p->value.event.actions);
6129662Slinton 	    break;
6139662Slinton 
6149662Slinton 	case O_PRINTCALL:
6159662Slinton 	    printcall(p->value.sym, whatblock(return_addr()));
6169662Slinton 	    break;
6179662Slinton 
6189662Slinton 	case O_PRINTIFCHANGED:
6199662Slinton 	    printifchanged(p->value.arg[0]);
6209662Slinton 	    break;
6219662Slinton 
6229662Slinton 	case O_PRINTRTN:
6239662Slinton 	    printrtn(p->value.sym);
6249662Slinton 	    break;
6259662Slinton 
6269662Slinton 	case O_PRINTSRCPOS:
6279662Slinton 	    getsrcpos();
6289662Slinton 	    if (p->value.arg[0] == nil) {
6299662Slinton 		printsrcpos();
6309662Slinton 		putchar('\n');
6319662Slinton 		printlines(curline, curline);
6329662Slinton 	    } else if (p->value.arg[0]->op == O_QLINE) {
6339662Slinton 		if (p->value.arg[0]->value.arg[1]->value.lcon == 0) {
6349662Slinton 		    printf("tracei: ");
6359662Slinton 		    printinst(pc, pc);
6369662Slinton 		} else {
63718217Slinton 		    if (canReadSource()) {
63818217Slinton 			printf("trace:  ");
63918217Slinton 			printlines(curline, curline);
64018217Slinton 		    }
6419662Slinton 		}
6429662Slinton 	    } else {
6439662Slinton 		printsrcpos();
6449662Slinton 		printf(": ");
6459662Slinton 		eval(p->value.arg[0]);
6469662Slinton 		prtree(stdout, p->value.arg[0]);
6479662Slinton 		printf(" = ");
6489662Slinton 		printval(p->value.arg[0]->nodetype);
6499662Slinton 		putchar('\n');
6509662Slinton 	    }
6519662Slinton 	    break;
6529662Slinton 
6539662Slinton 	case O_PROCRTN:
6549662Slinton 	    procreturn(p->value.sym);
6559662Slinton 	    break;
6569662Slinton 
6579662Slinton 	case O_STOPIFCHANGED:
6589662Slinton 	    stopifchanged(p->value.arg[0]);
6599662Slinton 	    break;
6609662Slinton 
6619662Slinton 	case O_STOPX:
6629662Slinton 	    isstopped = true;
6639662Slinton 	    break;
6649662Slinton 
6659662Slinton 	case O_TRACEON:
6669662Slinton 	    traceon(p->value.trace.inst, p->value.trace.event,
6679662Slinton 		p->value.trace.actions);
6689662Slinton 	    break;
6699662Slinton 
6709662Slinton 	case O_TRACEOFF:
6719662Slinton 	    traceoff(p->value.lcon);
6729662Slinton 	    break;
6739662Slinton 
6749662Slinton 	default:
6759662Slinton 	    panic("eval: bad op %d", p->op);
6769662Slinton     }
67718217Slinton     if (traceeval) {
67818217Slinton 	fprintf(stderr, "end eval %s\n", opname(p->op));
67918217Slinton     }
6809662Slinton }
6819662Slinton 
6829662Slinton /*
6839662Slinton  * Evaluate a list of commands.
6849662Slinton  */
6859662Slinton 
evalcmdlist(cl)6869662Slinton public evalcmdlist(cl)
6879662Slinton Cmdlist cl;
6889662Slinton {
6899662Slinton     Command c;
6909662Slinton 
6919662Slinton     foreach (Command, c, cl)
6929662Slinton 	evalcmd(c);
6939662Slinton     endfor
6949662Slinton }
6959662Slinton 
6969662Slinton /*
6979662Slinton  * Push "len" bytes onto the expression stack from address "addr"
6989662Slinton  * in the process.  If there isn't room on the stack, print an error message.
6999662Slinton  */
7009662Slinton 
rpush(addr,len)7019662Slinton public rpush(addr, len)
7029662Slinton Address addr;
7039662Slinton int len;
7049662Slinton {
7059662Slinton     if (not canpush(len)) {
7069662Slinton 	error("expression too large to evaluate");
7079662Slinton     } else {
7089662Slinton 	chksp();
7099662Slinton 	dread(sp, addr, len);
7109662Slinton 	sp += len;
7119662Slinton     }
7129662Slinton }
7139662Slinton 
7149662Slinton /*
7159662Slinton  * Check if the stack has n bytes available.
7169662Slinton  */
7179662Slinton 
canpush(n)7189662Slinton public Boolean canpush(n)
7199662Slinton Integer n;
7209662Slinton {
7219662Slinton     return (Boolean) (sp + n < &stack[STACKSIZE]);
7229662Slinton }
7239662Slinton 
7249662Slinton /*
7259662Slinton  * Push a small scalar of the given type onto the stack.
7269662Slinton  */
7279662Slinton 
pushsmall(t,v)7289662Slinton public pushsmall(t, v)
7299662Slinton Symbol t;
7309662Slinton long v;
7319662Slinton {
7329662Slinton     register Integer s;
7339662Slinton 
7349662Slinton     s = size(t);
7359662Slinton     switch (s) {
7369662Slinton 	case sizeof(char):
7379662Slinton 	    push(char, v);
7389662Slinton 	    break;
7399662Slinton 
7409662Slinton 	case sizeof(short):
7419662Slinton 	    push(short, v);
7429662Slinton 	    break;
7439662Slinton 
7449662Slinton 	case sizeof(long):
7459662Slinton 	    push(long, v);
7469662Slinton 	    break;
7479662Slinton 
7489662Slinton 	default:
7499662Slinton 	    panic("bad size %d in popsmall", s);
7509662Slinton     }
7519662Slinton }
7529662Slinton 
7539662Slinton /*
7549662Slinton  * Pop an item of the given type which is assumed to be no larger
7559662Slinton  * than a long and return it expanded into a long.
7569662Slinton  */
7579662Slinton 
popsmall(t)7589662Slinton public long popsmall(t)
7599662Slinton Symbol t;
7609662Slinton {
76118217Slinton     register integer n;
7629662Slinton     long r;
7639662Slinton 
76418217Slinton     n = size(t);
76518217Slinton     if (n == sizeof(char)) {
76618217Slinton 	if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
76718217Slinton 	    r = (long) pop(unsigned char);
76818217Slinton 	} else {
7699662Slinton 	    r = (long) pop(char);
77018217Slinton 	}
77118217Slinton     } else if (n == sizeof(short)) {
77218217Slinton 	if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
77318217Slinton 	    r = (long) pop(unsigned short);
77418217Slinton 	} else {
7759662Slinton 	    r = (long) pop(short);
77618217Slinton 	}
77718217Slinton     } else if (n == sizeof(long)) {
77818217Slinton 	r = pop(long);
77918217Slinton     } else {
78018217Slinton 	error("[internal error: size %d in popsmall]", n);
7819662Slinton     }
7829662Slinton     return r;
7839662Slinton }
7849662Slinton 
7859662Slinton /*
7869662Slinton  * Evaluate a conditional expression.
7879662Slinton  */
7889662Slinton 
cond(p)7899662Slinton public Boolean cond(p)
7909662Slinton Node p;
7919662Slinton {
79233315Sdonn     Boolean b;
79333315Sdonn     int i;
7949662Slinton 
7959662Slinton     if (p == nil) {
7969662Slinton 	b = true;
7979662Slinton     } else {
7989662Slinton 	eval(p);
79933315Sdonn 	i = pop(Boolrep);
80033315Sdonn 	b = (Boolean) i;
8019662Slinton     }
8029662Slinton     return b;
8039662Slinton }
8049662Slinton 
8059662Slinton /*
8069662Slinton  * Return the address corresponding to a given tree.
8079662Slinton  */
8089662Slinton 
lval(p)8099662Slinton public Address lval(p)
8109662Slinton Node p;
8119662Slinton {
8129662Slinton     if (p->op == O_RVAL) {
8139662Slinton 	eval(p->value.arg[0]);
8149662Slinton     } else {
8159662Slinton 	eval(p);
8169662Slinton     }
8179662Slinton     return (Address) (pop(long));
8189662Slinton }
8199662Slinton 
8209662Slinton /*
8219662Slinton  * Process a trace command, translating into the appropriate events
8229662Slinton  * and associated actions.
8239662Slinton  */
8249662Slinton 
trace(p)8259662Slinton public trace(p)
8269662Slinton Node p;
8279662Slinton {
8289662Slinton     Node exp, place, cond;
8299662Slinton     Node left;
8309662Slinton 
8319662Slinton     exp = p->value.arg[0];
8329662Slinton     place = p->value.arg[1];
8339662Slinton     cond = p->value.arg[2];
8349662Slinton     if (exp == nil) {
8359662Slinton 	traceall(p->op, place, cond);
83611771Slinton     } else if (exp->op == O_QLINE or exp->op == O_LCON) {
8379662Slinton 	traceinst(p->op, exp, cond);
8389662Slinton     } else if (place != nil and place->op == O_QLINE) {
8399662Slinton 	traceat(p->op, exp, place, cond);
8409662Slinton     } else {
8419861Slinton 	left = exp;
8429861Slinton 	if (left->op == O_RVAL or left->op == O_CALL) {
8439861Slinton 	    left = left->value.arg[0];
8449861Slinton 	}
8459662Slinton 	if (left->op == O_SYM and isblock(left->value.sym)) {
8469662Slinton 	    traceproc(p->op, left->value.sym, place, cond);
8479662Slinton 	} else {
8489662Slinton 	    tracedata(p->op, exp, place, cond);
8499662Slinton 	}
8509662Slinton     }
8519662Slinton }
8529662Slinton 
8539662Slinton /*
8549662Slinton  * Set a breakpoint that will turn on tracing.
8559662Slinton  */
8569662Slinton 
traceall(op,place,cond)8579662Slinton private traceall(op, place, cond)
8589662Slinton Operator op;
8599662Slinton Node place;
8609662Slinton Node cond;
8619662Slinton {
8629662Slinton     Symbol s;
8639662Slinton     Node event;
8649662Slinton     Command action;
8659662Slinton 
8669662Slinton     if (place == nil) {
8679662Slinton 	s = program;
8689662Slinton     } else {
8699662Slinton 	s = place->value.sym;
8709662Slinton     }
8719662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
8729662Slinton     action = build(O_PRINTSRCPOS,
8739662Slinton 	build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0)));
8749662Slinton     if (cond != nil) {
8759662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
8769662Slinton     }
8779662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
8789662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
87911871Slinton     if (isstdin()) {
88011871Slinton 	printevent(action->value.trace.event);
88111871Slinton     }
8829662Slinton }
8839662Slinton 
8849662Slinton /*
8859662Slinton  * Set up the appropriate breakpoint for tracing an instruction.
8869662Slinton  */
8879662Slinton 
traceinst(op,exp,cond)8889662Slinton private traceinst(op, exp, cond)
8899662Slinton Operator op;
8909662Slinton Node exp;
8919662Slinton Node cond;
8929662Slinton {
89311771Slinton     Node event, wh;
8949662Slinton     Command action;
89511871Slinton     Event e;
8969662Slinton 
89711771Slinton     if (exp->op == O_LCON) {
89818217Slinton 	wh = build(O_QLINE, build(O_SCON, strdup(cursource)), exp);
89911771Slinton     } else {
90011771Slinton 	wh = exp;
90111771Slinton     }
9029662Slinton     if (op == O_TRACEI) {
90311771Slinton 	event = build(O_EQ, build(O_SYM, pcsym), wh);
9049662Slinton     } else {
90511771Slinton 	event = build(O_EQ, build(O_SYM, linesym), wh);
9069662Slinton     }
90711771Slinton     action = build(O_PRINTSRCPOS, wh);
9089662Slinton     if (cond) {
9099662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
9109662Slinton     }
91111871Slinton     e = addevent(event, buildcmdlist(action));
91211871Slinton     if (isstdin()) {
91311871Slinton 	printevent(e);
91411871Slinton     }
9159662Slinton }
9169662Slinton 
9179662Slinton /*
9189662Slinton  * Set a breakpoint to print an expression at a given line or address.
9199662Slinton  */
9209662Slinton 
traceat(op,exp,place,cond)9219662Slinton private traceat(op, exp, place, cond)
9229662Slinton Operator op;
9239662Slinton Node exp;
9249662Slinton Node place;
9259662Slinton Node cond;
9269662Slinton {
9279662Slinton     Node event;
9289662Slinton     Command action;
92911871Slinton     Event e;
9309662Slinton 
9319662Slinton     if (op == O_TRACEI) {
9329662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
9339662Slinton     } else {
9349662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
9359662Slinton     }
9369662Slinton     action = build(O_PRINTSRCPOS, exp);
9379662Slinton     if (cond != nil) {
9389662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
9399662Slinton     }
94011871Slinton     e = addevent(event, buildcmdlist(action));
94111871Slinton     if (isstdin()) {
94211871Slinton 	printevent(e);
94311871Slinton     }
9449662Slinton }
9459662Slinton 
9469662Slinton /*
9479662Slinton  * Construct event for tracing a procedure.
9489662Slinton  *
9499662Slinton  * What we want here is
9509662Slinton  *
9519662Slinton  * 	when $proc = p do
9529662Slinton  *	    if <condition> then
9539662Slinton  *	        printcall;
9549662Slinton  *	        once $pc = $retaddr do
9559662Slinton  *	            printrtn;
9569662Slinton  *	        end;
9579662Slinton  *	    end if;
9589662Slinton  *	end;
9599662Slinton  *
9609662Slinton  * Note that "once" is like "when" except that the event
9619662Slinton  * deletes itself as part of its associated action.
9629662Slinton  */
9639662Slinton 
traceproc(op,p,place,cond)9649662Slinton private traceproc(op, p, place, cond)
9659662Slinton Operator op;
9669662Slinton Symbol p;
9679662Slinton Node place;
9689662Slinton Node cond;
9699662Slinton {
9709662Slinton     Node event;
9719662Slinton     Command action;
9729662Slinton     Cmdlist actionlist;
97311871Slinton     Event e;
9749662Slinton 
9759662Slinton     action = build(O_PRINTCALL, p);
9769662Slinton     actionlist = list_alloc();
9779662Slinton     cmdlist_append(action, actionlist);
9789662Slinton     event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym));
9799662Slinton     action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p)));
9809662Slinton     cmdlist_append(action, actionlist);
9819662Slinton     if (cond != nil) {
9829662Slinton 	actionlist = buildcmdlist(build(O_IF, cond, actionlist));
9839662Slinton     }
9849662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
98511871Slinton     e = addevent(event, actionlist);
98611871Slinton     if (isstdin()) {
98711871Slinton 	printevent(e);
98811871Slinton     }
9899662Slinton }
9909662Slinton 
9919662Slinton /*
9929662Slinton  * Set up breakpoint for tracing data.
9939662Slinton  */
9949662Slinton 
tracedata(op,exp,place,cond)9959662Slinton private tracedata(op, exp, place, cond)
9969662Slinton Operator op;
9979662Slinton Node exp;
9989662Slinton Node place;
9999662Slinton Node cond;
10009662Slinton {
10019662Slinton     Symbol p;
10029662Slinton     Node event;
10039662Slinton     Command action;
10049662Slinton 
100533315Sdonn     if (size(exp->nodetype) > MAXTRSIZE) {
100633315Sdonn 	error("expression too large to trace (limit is %d bytes)", MAXTRSIZE);
100733315Sdonn     }
10089662Slinton     p = (place == nil) ? tcontainer(exp) : place->value.sym;
10099662Slinton     if (p == nil) {
10109662Slinton 	p = program;
10119662Slinton     }
10129662Slinton     action = build(O_PRINTIFCHANGED, exp);
10139662Slinton     if (cond != nil) {
10149662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
10159662Slinton     }
10169662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
10179662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
10189662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
101911871Slinton     if (isstdin()) {
102011871Slinton 	printevent(action->value.trace.event);
102111871Slinton     }
10229662Slinton }
10239662Slinton 
10249662Slinton /*
10259662Slinton  * Setting and unsetting of stops.
10269662Slinton  */
10279662Slinton 
stop(p)10289662Slinton public stop(p)
10299662Slinton Node p;
10309662Slinton {
103113846Slinton     Node exp, place, cond, t;
10329662Slinton     Symbol s;
10339662Slinton     Command action;
103411871Slinton     Event e;
10359662Slinton 
10369662Slinton     exp = p->value.arg[0];
10379662Slinton     place = p->value.arg[1];
10389662Slinton     cond = p->value.arg[2];
10399662Slinton     if (exp != nil) {
10409662Slinton 	stopvar(p->op, exp, place, cond);
104113846Slinton     } else {
104213846Slinton 	action = build(O_STOPX);
104313846Slinton 	if (cond != nil) {
104413846Slinton 	    action = build(O_IF, cond, buildcmdlist(action));
104511871Slinton 	}
104616608Ssam 	if (place == nil or place->op == O_SYM) {
104716608Ssam 	    if (place == nil) {
104816608Ssam 		s = program;
104916608Ssam 	    } else {
105016608Ssam 		s = place->value.sym;
105116608Ssam 	    }
105213846Slinton 	    t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
105313846Slinton 	    if (cond != nil) {
105413846Slinton 		action = build(O_TRACEON, (p->op == O_STOPI),
105513846Slinton 		    buildcmdlist(action));
105613846Slinton 		e = addevent(t, buildcmdlist(action));
105713846Slinton 		action->value.trace.event = e;
105813846Slinton 	    } else {
105913846Slinton 		e = addevent(t, buildcmdlist(action));
106013846Slinton 	    }
106113846Slinton 	    if (isstdin()) {
106213846Slinton 		printevent(e);
106313846Slinton 	    }
106413846Slinton 	} else {
106513846Slinton 	    stopinst(p->op, place, cond, action);
106613846Slinton 	}
10679662Slinton     }
10689662Slinton }
10699662Slinton 
stopinst(op,place,cond,action)107013846Slinton private stopinst(op, place, cond, action)
10719662Slinton Operator op;
10729662Slinton Node place;
10739662Slinton Node cond;
107413846Slinton Command action;
10759662Slinton {
10769662Slinton     Node event;
107711871Slinton     Event e;
10789662Slinton 
10799662Slinton     if (op == O_STOP) {
10809662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
10819662Slinton     } else {
10829662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
10839662Slinton     }
108413846Slinton     e = addevent(event, buildcmdlist(action));
108511871Slinton     if (isstdin()) {
108611871Slinton 	printevent(e);
108711871Slinton     }
10889662Slinton }
10899662Slinton 
10909662Slinton /*
10919662Slinton  * Implement stopping on assignment to a variable by adding it to
10929662Slinton  * the variable list.
10939662Slinton  */
10949662Slinton 
stopvar(op,exp,place,cond)10959662Slinton private stopvar(op, exp, place, cond)
10969662Slinton Operator op;
10979662Slinton Node exp;
10989662Slinton Node place;
10999662Slinton Node cond;
11009662Slinton {
11019662Slinton     Symbol p;
11029662Slinton     Node event;
11039662Slinton     Command action;
11049662Slinton 
110533315Sdonn     if (size(exp->nodetype) > MAXTRSIZE) {
110633315Sdonn 	error("expression too large to trace (limit is %d bytes)", MAXTRSIZE);
110733315Sdonn     }
110814445Slinton     if (place == nil) {
110914445Slinton 	if (exp->op == O_LCON) {
111014445Slinton 	    p = program;
111114445Slinton 	} else {
111214445Slinton 	    p = tcontainer(exp);
111314445Slinton 	    if (p == nil) {
111414445Slinton 		p = program;
111514445Slinton 	    }
111614445Slinton 	}
111714445Slinton     } else {
111814445Slinton 	p = place->value.sym;
11199662Slinton     }
112014445Slinton     action = build(O_STOPIFCHANGED, exp);
112114445Slinton     if (cond != nil) {
112214445Slinton 	action = build(O_IF, cond, buildcmdlist(action));
112314445Slinton     }
11249662Slinton     action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action));
11259662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
11269662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
112711871Slinton     if (isstdin()) {
112811871Slinton 	printevent(action->value.trace.event);
112911871Slinton     }
11309662Slinton }
11319662Slinton 
11329662Slinton /*
11339662Slinton  * Assign the value of an expression to a variable (or term).
11349662Slinton  */
11359662Slinton 
assign(var,exp)11369662Slinton public assign(var, exp)
11379662Slinton Node var;
11389662Slinton Node exp;
11399662Slinton {
11409662Slinton     Address addr;
114116608Ssam     integer varsize, expsize;
11429662Slinton     char cvalue;
11439662Slinton     short svalue;
11449662Slinton     long lvalue;
114516608Ssam     float fvalue;
11469662Slinton 
114718217Slinton     if (var->op == O_SYM and regnum(var->value.sym) != -1) {
114818217Slinton 	eval(exp);
114918217Slinton 	setreg(regnum(var->value.sym), pop(Address));
115016608Ssam     } else {
115118217Slinton 	addr = lval(var);
115218217Slinton 	varsize = size(var->nodetype);
115318217Slinton 	expsize = size(exp->nodetype);
115418217Slinton 	eval(exp);
115518217Slinton 	if (varsize == sizeof(float) and expsize == sizeof(double)) {
115618217Slinton 	    fvalue = (float) pop(double);
115718217Slinton 	    dwrite(&fvalue, addr, sizeof(fvalue));
115818217Slinton 	} else {
115918217Slinton 	    if (varsize < sizeof(long)) {
116018217Slinton 		lvalue = 0;
116118217Slinton 		popn(expsize, &lvalue);
116218217Slinton 		if (varsize == sizeof(char)) {
116316608Ssam 		    cvalue = lvalue;
116416608Ssam 		    dwrite(&cvalue, addr, sizeof(cvalue));
116518217Slinton 		} else if (varsize == sizeof(short)) {
116616608Ssam 		    svalue = lvalue;
116716608Ssam 		    dwrite(&svalue, addr, sizeof(svalue));
116818217Slinton 		} else {
116918217Slinton 		    error("[internal error: bad size %d in assign]", varsize);
117018217Slinton 		}
117118217Slinton 	    } else {
117218217Slinton 		if (expsize <= varsize) {
117318217Slinton 		    sp -= expsize;
117418217Slinton 		    dwrite(sp, addr, expsize);
117518217Slinton 		} else {
117618217Slinton 		    sp -= expsize;
117718217Slinton 		    dwrite(sp, addr, varsize);
117818217Slinton 		}
117918217Slinton 	    }
118018217Slinton 	}
118118217Slinton     }
118218217Slinton }
11839662Slinton 
118418217Slinton /*
118518217Slinton  * Set a debugger variable.
118618217Slinton  */
118718217Slinton 
set(var,exp)118818217Slinton private set (var, exp)
118918217Slinton Node var, exp;
119018217Slinton {
119118217Slinton     Symbol t;
119218217Slinton 
119318217Slinton     if (var == nil) {
119418217Slinton 	defvar(nil, nil);
119518217Slinton     } else if (exp == nil) {
119618217Slinton 	defvar(var->value.name, nil);
119718217Slinton     } else if (var->value.name == identname("$frame", true)) {
119818217Slinton 	t = exp->nodetype;
119918217Slinton 	if (not compatible(t, t_int) and not compatible(t, t_addr)) {
120018217Slinton 	    error("$frame must be an address");
120118217Slinton 	}
120218217Slinton 	eval(exp);
120318217Slinton 	getnewregs(pop(Address));
120418217Slinton     } else {
120518217Slinton 	defvar(var->value.name, unrval(exp));
120618217Slinton     }
120718217Slinton }
120818217Slinton 
120918217Slinton /*
121018217Slinton  * Execute a list command.
121118217Slinton  */
121218217Slinton 
list(p)121318217Slinton private list (p)
121418217Slinton Node p;
121518217Slinton {
121618217Slinton     Symbol f;
121718217Slinton     Address addr;
121818217Slinton     Lineno line, l1, l2;
121918217Slinton 
122018217Slinton     if (p->value.arg[0]->op == O_SYM) {
122118217Slinton 	f = p->value.arg[0]->value.sym;
122218217Slinton 	addr = firstline(f);
122318217Slinton 	if (addr == NOADDR) {
122418217Slinton 	    error("no source lines for \"%s\"", symname(f));
122518217Slinton 	}
122618217Slinton 	setsource(srcfilename(addr));
122718217Slinton 	line = srcline(addr);
122818217Slinton 	getsrcwindow(line, &l1, &l2);
122918217Slinton     } else {
123018217Slinton 	eval(p->value.arg[0]);
123118217Slinton 	l1 = (Lineno) (pop(long));
123218217Slinton 	eval(p->value.arg[1]);
123318217Slinton 	l2 = (Lineno) (pop(long));
123418217Slinton     }
123518217Slinton     printlines(l1, l2);
123618217Slinton }
123718217Slinton 
123818217Slinton /*
123918217Slinton  * Execute a func command.
124018217Slinton  */
124118217Slinton 
func(p)124218217Slinton private func (p)
124318217Slinton Node p;
124418217Slinton {
124518217Slinton     Symbol s, f;
124618217Slinton     Address addr;
124718217Slinton 
124818217Slinton     if (p == nil) {
124918217Slinton 	printname(stdout, curfunc);
125018217Slinton 	putchar('\n');
125118217Slinton     } else {
125218217Slinton 	s = p->value.sym;
125318217Slinton 	if (isroutine(s)) {
125418217Slinton 	    setcurfunc(s);
125516608Ssam 	} else {
125618217Slinton 	    find(f, s->name) where isroutine(f) endfind(f);
125718217Slinton 	    if (f == nil) {
125818217Slinton 		error("%s is not a procedure or function", symname(s));
125916608Ssam 	    }
126018217Slinton 	    setcurfunc(f);
12619662Slinton 	}
126218217Slinton 	addr = codeloc(curfunc);
126318217Slinton 	if (addr != NOADDR) {
126418217Slinton 	    setsource(srcfilename(addr));
126518217Slinton 	    cursrcline = srcline(addr);
126618217Slinton 	}
12679662Slinton     }
12689662Slinton }
12699662Slinton 
12709662Slinton /*
127118217Slinton  * Send a message to the current support person.
12729662Slinton  */
12739662Slinton 
gripe()12749662Slinton public gripe()
12759662Slinton {
12769662Slinton     typedef Operation();
12779662Slinton     Operation *old;
127814445Slinton     int pid, status;
127916608Ssam     extern int versionNumber;
128016608Ssam     char subject[100];
12819662Slinton 
128233315Sdonn #   ifdef MAINTAINER
128333315Sdonn 	puts("Type control-D to end your message.  Be sure to include");
128433315Sdonn 	puts("your name and the name of the file you are debugging.");
128533315Sdonn 	putchar('\n');
128633315Sdonn 	old = signal(SIGINT, SIG_DFL);
128733315Sdonn 	sprintf(subject, "dbx (version 3.%d) gripe", versionNumber);
128833315Sdonn 	pid = back("Mail", stdin, stdout, "-s", subject, MAINTAINER, nil);
128933315Sdonn 	signal(SIGINT, SIG_IGN);
129033315Sdonn 	pwait(pid, &status);
129133315Sdonn 	signal(SIGINT, old);
129233315Sdonn 	if (status == 0) {
129333315Sdonn 	    puts("Thank you.");
129433315Sdonn 	} else {
129533315Sdonn 	    puts("\nMail not sent.");
129633315Sdonn 	}
129733315Sdonn #   else
129833315Sdonn 	puts("Sorry, no dbx maintainer available to gripe to.");
129933315Sdonn 	puts("Try contacting your system manager.");
130033315Sdonn #   endif
13019662Slinton }
13029662Slinton 
13039662Slinton /*
13049662Slinton  * Give the user some help.
13059662Slinton  */
13069662Slinton 
help()13079662Slinton public help()
13089662Slinton {
13099662Slinton     puts("run                    - begin execution of the program");
131016608Ssam     puts("print <exp>            - print the value of the expression");
131116608Ssam     puts("where                  - print currently active procedures");
131216608Ssam     puts("stop at <line>         - suspend execution at the line");
131316608Ssam     puts("stop in <proc>         - suspend execution when <proc> is called");
13149662Slinton     puts("cont                   - continue execution");
13159662Slinton     puts("step                   - single step one line");
13169662Slinton     puts("next                   - step to next line (skip over calls)");
13179662Slinton     puts("trace <line#>          - trace execution of the line");
13189662Slinton     puts("trace <proc>           - trace calls to the procedure");
13199662Slinton     puts("trace <var>            - trace changes to the variable");
13209662Slinton     puts("trace <exp> at <line#> - print <exp> when <line> is reached");
13219662Slinton     puts("status                 - print trace/stop's in effect");
13229662Slinton     puts("delete <number>        - remove trace or stop of given number");
132316608Ssam     puts("call <proc>            - call a procedure in program");
13249662Slinton     puts("whatis <name>          - print the declaration of the name");
13259662Slinton     puts("list <line>, <line>    - list source lines");
13269662Slinton     puts("gripe                  - send mail to the person in charge of dbx");
13279662Slinton     puts("quit                   - exit dbx");
13289662Slinton }
13299662Slinton 
13309662Slinton /*
13319662Slinton  * Divert output to the given file name.
13329662Slinton  * Cannot redirect to an existing file.
13339662Slinton  */
13349662Slinton 
13359662Slinton private int so_fd;
13369662Slinton private Boolean notstdout;
13379662Slinton 
setout(filename)13389662Slinton public setout(filename)
13399662Slinton String filename;
13409662Slinton {
13419662Slinton     File f;
13429662Slinton 
13439662Slinton     f = fopen(filename, "r");
13449662Slinton     if (f != nil) {
13459662Slinton 	fclose(f);
13469662Slinton 	error("%s: file already exists", filename);
13479662Slinton     } else {
13489662Slinton 	so_fd = dup(1);
13499662Slinton 	close(1);
13509662Slinton 	if (creat(filename, 0666) == nil) {
13519662Slinton 	    unsetout();
13529662Slinton 	    error("can't create %s", filename);
13539662Slinton 	}
13549662Slinton 	notstdout = true;
13559662Slinton     }
13569662Slinton }
13579662Slinton 
13589662Slinton /*
13599662Slinton  * Revert output to standard output.
13609662Slinton  */
13619662Slinton 
unsetout()13629662Slinton public unsetout()
13639662Slinton {
13649662Slinton     fflush(stdout);
13659662Slinton     close(1);
13669662Slinton     if (dup(so_fd) != 1) {
13679662Slinton 	panic("standard out dup failed");
13689662Slinton     }
13699662Slinton     close(so_fd);
13709662Slinton     notstdout = false;
13719662Slinton }
13729662Slinton 
13739662Slinton /*
13749662Slinton  * Determine is standard output is currently being redirected
13759662Slinton  * to a file (as far as we know).
13769662Slinton  */
13779662Slinton 
isredirected()13789662Slinton public Boolean isredirected()
13799662Slinton {
13809662Slinton     return notstdout;
13819662Slinton }
1382