xref: /csrg-svn/old/dbx/eval.c (revision 18217)
19662Slinton /* Copyright (c) 1982 Regents of the University of California */
29662Slinton 
3*18217Slinton static	char sccsid[] = "@(#)eval.c	1.15 (Berkeley) 03/01/85";
49662Slinton 
5*18217Slinton static char rcsid[] = "$Header: eval.c,v 1.5 84/12/26 10:39:08 linton Exp $";
6*18217Slinton 
79662Slinton /*
89662Slinton  * Tree evaluation.
99662Slinton  */
109662Slinton 
119662Slinton #include "defs.h"
129662Slinton #include "tree.h"
139662Slinton #include "operators.h"
14*18217Slinton #include "debug.h"
159662Slinton #include "eval.h"
169662Slinton #include "events.h"
179662Slinton #include "symbols.h"
189662Slinton #include "scanner.h"
199662Slinton #include "source.h"
209662Slinton #include "object.h"
219662Slinton #include "mappings.h"
229662Slinton #include "process.h"
2316608Ssam #include "runtime.h"
249662Slinton #include "machine.h"
259662Slinton #include <signal.h>
269662Slinton 
279662Slinton #ifndef public
289662Slinton 
299662Slinton #include "machine.h"
309662Slinton 
3112538Scsvaf #define STACKSIZE 20000
329662Slinton 
339662Slinton typedef Char Stack;
349662Slinton 
359662Slinton #define push(type, value) { \
369662Slinton     ((type *) (sp += sizeof(type)))[-1] = (value); \
379662Slinton }
389662Slinton 
399662Slinton #define pop(type) ( \
409662Slinton     (*((type *) (sp -= sizeof(type)))) \
419662Slinton )
429662Slinton 
4316608Ssam #define popn(n, dest) { \
4416608Ssam     sp -= n; \
4516608Ssam     bcopy(sp, dest, n); \
4616608Ssam }
4716608Ssam 
489662Slinton #define alignstack() { \
499662Slinton     sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
509662Slinton }
519662Slinton 
529662Slinton #endif
539662Slinton 
549662Slinton public Stack stack[STACKSIZE];
559662Slinton public Stack *sp = &stack[0];
5614674Slinton public Boolean useInstLoc = false;
579662Slinton 
589662Slinton #define chksp() \
599662Slinton { \
609662Slinton     if (sp < &stack[0]) { \
619662Slinton 	panic("stack underflow"); \
629662Slinton     } \
639662Slinton }
649662Slinton 
659662Slinton #define poparg(n, r, fr) { \
669662Slinton     eval(p->value.arg[n]); \
679662Slinton     if (isreal(p->op)) { \
6816608Ssam 	if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \
6916608Ssam 	    fr = pop(float); \
7016608Ssam 	} else { \
7116608Ssam 	    fr = pop(double); \
7216608Ssam 	} \
739662Slinton     } else if (isint(p->op)) { \
749662Slinton 	r = popsmall(p->value.arg[n]->nodetype); \
759662Slinton     } \
769662Slinton }
779662Slinton 
789662Slinton #define Boolrep char	/* underlying representation type for booleans */
799662Slinton 
809662Slinton /*
81*18217Slinton  * Command-level evaluation.
82*18217Slinton  */
83*18217Slinton 
84*18217Slinton public Node topnode;
85*18217Slinton 
86*18217Slinton public topeval (p)
87*18217Slinton Node p;
88*18217Slinton {
89*18217Slinton     if (traceeval) {
90*18217Slinton 	fprintf(stderr, "topeval(");
91*18217Slinton 	prtree(stderr, p);
92*18217Slinton 	fprintf(stderr, ")\n");
93*18217Slinton 	fflush(stderr);
94*18217Slinton     }
95*18217Slinton     topnode = p;
96*18217Slinton     eval(p);
97*18217Slinton }
98*18217Slinton 
99*18217Slinton /*
1009662Slinton  * Evaluate a parse tree leaving the value on the top of the stack.
1019662Slinton  */
1029662Slinton 
1039662Slinton public eval(p)
1049662Slinton register Node p;
1059662Slinton {
1069662Slinton     long r0, r1;
1079662Slinton     double fr0, fr1;
1089662Slinton     Address addr;
1099662Slinton     long i, n;
1109662Slinton     int len;
111*18217Slinton     Symbol s;
1129662Slinton     Node n1, n2;
113*18217Slinton     boolean b;
1149662Slinton     File file;
115*18217Slinton     String str;
1169662Slinton 
1179662Slinton     checkref(p);
118*18217Slinton     if (traceeval) {
119*18217Slinton 	fprintf(stderr, "begin eval %s\n", opname(p->op));
12012538Scsvaf     }
1219662Slinton     switch (degree(p->op)) {
1229662Slinton 	case BINARY:
1239662Slinton 	    poparg(1, r1, fr1);
1249662Slinton 	    poparg(0, r0, fr0);
1259662Slinton 	    break;
1269662Slinton 
1279662Slinton 	case UNARY:
1289662Slinton 	    poparg(0, r0, fr0);
1299662Slinton 	    break;
1309662Slinton 
1319662Slinton 	default:
1329662Slinton 	    /* do nothing */;
1339662Slinton     }
1349662Slinton     switch (p->op) {
1359662Slinton 	case O_SYM:
1369662Slinton 	    s = p->value.sym;
1379662Slinton 	    if (s == retaddrsym) {
1389662Slinton 		push(long, return_addr());
139*18217Slinton 	    } else if (isvariable(s)) {
140*18217Slinton 		if (s != program and not isactive(container(s))) {
141*18217Slinton 		    error("\"%s\" is not active", symname(s));
142*18217Slinton 		}
143*18217Slinton 		if (isvarparam(s) and not isopenarray(s)) {
144*18217Slinton 		    rpush(address(s, nil), sizeof(Address));
1459662Slinton 		} else {
146*18217Slinton 		    push(Address, address(s, nil));
1479662Slinton 		}
148*18217Slinton 	    } else if (isblock(s)) {
149*18217Slinton 		push(Symbol, s);
150*18217Slinton 	    } else if (isconst(s)) {
151*18217Slinton 		eval(constval(s));
152*18217Slinton 	    } else {
153*18217Slinton 		error("can't evaluate a %s", classname(s));
1549662Slinton 	    }
1559662Slinton 	    break;
1569662Slinton 
1579662Slinton 	case O_LCON:
158*18217Slinton 	case O_CCON:
1599662Slinton 	    r0 = p->value.lcon;
1609662Slinton 	    pushsmall(p->nodetype, r0);
1619662Slinton 	    break;
1629662Slinton 
1639662Slinton 	case O_FCON:
1649662Slinton 	    push(double, p->value.fcon);
1659662Slinton 	    break;
1669662Slinton 
1679662Slinton 	case O_SCON:
1689662Slinton 	    len = size(p->nodetype);
1699662Slinton 	    mov(p->value.scon, sp, len);
1709662Slinton 	    sp += len;
1719662Slinton 	    break;
1729662Slinton 
1739662Slinton 	case O_INDEX:
174*18217Slinton 	    s = p->value.arg[0]->nodetype;
175*18217Slinton 	    p->value.arg[0]->nodetype = t_addr;
176*18217Slinton 	    eval(p->value.arg[0]);
177*18217Slinton 	    p->value.arg[0]->nodetype = s;
178*18217Slinton 	    n = pop(Address);
179*18217Slinton 	    eval(p->value.arg[1]);
180*18217Slinton 	    evalindex(s, n, popsmall(p->value.arg[1]->nodetype));
1819662Slinton 	    break;
1829662Slinton 
1839662Slinton 	case O_DOT:
1849662Slinton 	    s = p->value.arg[1]->value.sym;
185*18217Slinton 	    eval(p->value.arg[0]);
186*18217Slinton 	    n = pop(long);
1879662Slinton 	    push(long, n + (s->symvalue.field.offset div 8));
1889662Slinton 	    break;
1899662Slinton 
1909662Slinton 	/*
1919662Slinton 	 * Get the value of the expression addressed by the top of the stack.
1929662Slinton 	 * Push the result back on the stack.
1939662Slinton 	 */
1949662Slinton 
1959662Slinton 	case O_INDIR:
1969662Slinton 	case O_RVAL:
1979662Slinton 	    addr = pop(long);
1989662Slinton 	    if (addr == 0) {
1999662Slinton 		error("reference through nil pointer");
2009662Slinton 	    }
201*18217Slinton 	    len = size(p->nodetype);
2029662Slinton 	    rpush(addr, len);
2039662Slinton 	    break;
2049662Slinton 
20511175Slinton 	/*
206*18217Slinton 	 * Move the stack pointer so that the top of the stack has
207*18217Slinton 	 * something corresponding to the size of the current node type.
208*18217Slinton 	 * If this new type is bigger than the subtree (len > 0),
209*18217Slinton 	 * then the stack is padded with nulls.  If it's smaller,
210*18217Slinton 	 * the stack is just dropped by the appropriate amount.
21111175Slinton 	 */
21211175Slinton 	case O_TYPERENAME:
213*18217Slinton 	    len = size(p->nodetype) - size(p->value.arg[0]->nodetype);
214*18217Slinton 	    if (len > 0) {
215*18217Slinton 		for (n = 0; n < len; n++) {
216*18217Slinton 		    *sp++ = '\0';
217*18217Slinton 		}
218*18217Slinton 	    } else if (len < 0) {
219*18217Slinton 		sp += len;
220*18217Slinton 	    }
22111175Slinton 	    break;
22211175Slinton 
2239662Slinton 	case O_COMMA:
224*18217Slinton 	    eval(p->value.arg[0]);
225*18217Slinton 	    if (p->value.arg[1] != nil) {
226*18217Slinton 		eval(p->value.arg[1]);
227*18217Slinton 	    }
2289662Slinton 	    break;
2299662Slinton 
2309662Slinton 	case O_ITOF:
2319662Slinton 	    push(double, (double) r0);
2329662Slinton 	    break;
2339662Slinton 
2349662Slinton 	case O_ADD:
2359662Slinton 	    push(long, r0+r1);
2369662Slinton 	    break;
2379662Slinton 
2389662Slinton 	case O_ADDF:
2399662Slinton 	    push(double, fr0+fr1);
2409662Slinton 	    break;
2419662Slinton 
2429662Slinton 	case O_SUB:
2439662Slinton 	    push(long, r0-r1);
2449662Slinton 	    break;
2459662Slinton 
2469662Slinton 	case O_SUBF:
2479662Slinton 	    push(double, fr0-fr1);
2489662Slinton 	    break;
2499662Slinton 
2509662Slinton 	case O_NEG:
2519662Slinton 	    push(long, -r0);
2529662Slinton 	    break;
2539662Slinton 
2549662Slinton 	case O_NEGF:
2559662Slinton 	    push(double, -fr0);
2569662Slinton 	    break;
2579662Slinton 
2589662Slinton 	case O_MUL:
2599662Slinton 	    push(long, r0*r1);
2609662Slinton 	    break;
2619662Slinton 
2629662Slinton 	case O_MULF:
2639662Slinton 	    push(double, fr0*fr1);
2649662Slinton 	    break;
2659662Slinton 
2669662Slinton 	case O_DIVF:
2679662Slinton 	    if (fr1 == 0) {
2689662Slinton 		error("error: division by 0");
2699662Slinton 	    }
2709662Slinton 	    push(double, fr0 / fr1);
2719662Slinton 	    break;
2729662Slinton 
2739662Slinton 	case O_DIV:
2749662Slinton 	    if (r1 == 0) {
2759662Slinton 		error("error: div by 0");
2769662Slinton 	    }
2779662Slinton 	    push(long, r0 div r1);
2789662Slinton 	    break;
2799662Slinton 
2809662Slinton 	case O_MOD:
2819662Slinton 	    if (r1 == 0) {
2829662Slinton 		error("error: mod by 0");
2839662Slinton 	    }
2849662Slinton 	    push(long, r0 mod r1);
2859662Slinton 	    break;
2869662Slinton 
2879662Slinton 	case O_LT:
2889662Slinton 	    push(Boolrep, r0 < r1);
2899662Slinton 	    break;
2909662Slinton 
2919662Slinton 	case O_LTF:
2929662Slinton 	    push(Boolrep, fr0 < fr1);
2939662Slinton 	    break;
2949662Slinton 
2959662Slinton 	case O_LE:
2969662Slinton 	    push(Boolrep, r0 <= r1);
2979662Slinton 	    break;
2989662Slinton 
2999662Slinton 	case O_LEF:
3009662Slinton 	    push(Boolrep, fr0 <= fr1);
3019662Slinton 	    break;
3029662Slinton 
3039662Slinton 	case O_GT:
3049662Slinton 	    push(Boolrep, r0 > r1);
3059662Slinton 	    break;
3069662Slinton 
3079662Slinton 	case O_GTF:
3089662Slinton 	    push(Boolrep, fr0 > fr1);
3099662Slinton 	    break;
3109662Slinton 
3119662Slinton 	case O_EQ:
3129662Slinton 	    push(Boolrep, r0 == r1);
3139662Slinton 	    break;
3149662Slinton 
3159662Slinton 	case O_EQF:
3169662Slinton 	    push(Boolrep, fr0 == fr1);
3179662Slinton 	    break;
3189662Slinton 
3199662Slinton 	case O_NE:
3209662Slinton 	    push(Boolrep, r0 != r1);
3219662Slinton 	    break;
3229662Slinton 
3239662Slinton 	case O_NEF:
3249662Slinton 	    push(Boolrep, fr0 != fr1);
3259662Slinton 	    break;
3269662Slinton 
3279662Slinton 	case O_AND:
3289662Slinton 	    push(Boolrep, r0 and r1);
3299662Slinton 	    break;
3309662Slinton 
3319662Slinton 	case O_OR:
3329662Slinton 	    push(Boolrep, r0 or r1);
3339662Slinton 	    break;
3349662Slinton 
3359662Slinton 	case O_ASSIGN:
3369662Slinton 	    assign(p->value.arg[0], p->value.arg[1]);
3379662Slinton 	    break;
3389662Slinton 
3399662Slinton 	case O_CHFILE:
3409662Slinton 	    if (p->value.scon == nil) {
3419662Slinton 		printf("%s\n", cursource);
3429662Slinton 	    } else {
3439662Slinton 		file = opensource(p->value.scon);
3449662Slinton 		if (file == nil) {
3459662Slinton 		    error("can't read \"%s\"", p->value.scon);
3469662Slinton 		} else {
3479662Slinton 		    fclose(file);
3489662Slinton 		    setsource(p->value.scon);
3499662Slinton 		}
3509662Slinton 	    }
3519662Slinton 	    break;
3529662Slinton 
3539662Slinton 	case O_CONT:
35411871Slinton 	    cont(p->value.lcon);
3559662Slinton 	    printnews();
3569662Slinton 	    break;
3579662Slinton 
3589662Slinton 	case O_LIST:
359*18217Slinton 	    list(p);
3609662Slinton 	    break;
3619662Slinton 
3629662Slinton 	case O_FUNC:
363*18217Slinton 	    func(p->value.arg[0]);
3649662Slinton 	    break;
3659662Slinton 
3669662Slinton 	case O_EXAMINE:
3679662Slinton 	    eval(p->value.examine.beginaddr);
3689662Slinton 	    r0 = pop(long);
3699662Slinton 	    if (p->value.examine.endaddr == nil) {
3709662Slinton 		n = p->value.examine.count;
37111175Slinton 		if (n == 0) {
37211175Slinton 		    printvalue(r0, p->value.examine.mode);
37311175Slinton 		} else if (streq(p->value.examine.mode, "i")) {
3749662Slinton 		    printninst(n, (Address) r0);
3759662Slinton 		} else {
3769662Slinton 		    printndata(n, (Address) r0, p->value.examine.mode);
3779662Slinton 		}
3789662Slinton 	    } else {
3799662Slinton 		eval(p->value.examine.endaddr);
3809662Slinton 		r1 = pop(long);
3819662Slinton 		if (streq(p->value.examine.mode, "i")) {
3829662Slinton 		    printinst((Address)r0, (Address)r1);
3839662Slinton 		} else {
3849662Slinton 		    printdata((Address)r0, (Address)r1, p->value.examine.mode);
3859662Slinton 		}
3869662Slinton 	    }
3879662Slinton 	    break;
3889662Slinton 
3899662Slinton 	case O_PRINT:
3909662Slinton 	    for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) {
3919662Slinton 		eval(n1->value.arg[0]);
3929662Slinton 		printval(n1->value.arg[0]->nodetype);
3939662Slinton 		putchar(' ');
3949662Slinton 	    }
3959662Slinton 	    putchar('\n');
3969662Slinton 	    break;
3979662Slinton 
3989662Slinton 	case O_PSYM:
3999662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
4009662Slinton 		psym(p->value.arg[0]->value.sym);
4019662Slinton 	    } else {
4029662Slinton 		psym(p->value.arg[0]->nodetype);
4039662Slinton 	    }
4049662Slinton 	    break;
4059662Slinton 
4069662Slinton 	case O_QLINE:
4079662Slinton 	    eval(p->value.arg[1]);
4089662Slinton 	    break;
4099662Slinton 
4109662Slinton 	case O_STEP:
4119662Slinton 	    b = inst_tracing;
4129662Slinton 	    inst_tracing = (Boolean) (not p->value.step.source);
4139662Slinton 	    if (p->value.step.skipcalls) {
4149662Slinton 		next();
4159662Slinton 	    } else {
4169662Slinton 		stepc();
4179662Slinton 	    }
4189662Slinton 	    inst_tracing = b;
41914674Slinton 	    useInstLoc = (Boolean) (not p->value.step.source);
4209662Slinton 	    printnews();
4219662Slinton 	    break;
4229662Slinton 
4239662Slinton 	case O_WHATIS:
4249662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
4259662Slinton 		printdecl(p->value.arg[0]->value.sym);
4269662Slinton 	    } else {
4279662Slinton 		printdecl(p->value.arg[0]->nodetype);
4289662Slinton 	    }
4299662Slinton 	    break;
4309662Slinton 
4319662Slinton 	case O_WHERE:
4329662Slinton 	    wherecmd();
4339662Slinton 	    break;
4349662Slinton 
4359662Slinton 	case O_WHEREIS:
43612538Scsvaf 	    if (p->value.arg[0]->op == O_SYM) {
437*18217Slinton 		printwhereis(stdout, p->value.arg[0]->value.sym);
43812538Scsvaf 	    } else {
439*18217Slinton 		printwhereis(stdout, p->value.arg[0]->nodetype);
44012538Scsvaf 	    }
4419662Slinton 	    break;
4429662Slinton 
4439662Slinton 	case O_WHICH:
44412538Scsvaf 	    if (p->value.arg[0]->op == O_SYM) {
445*18217Slinton 		printwhich(stdout, p->value.arg[0]->value.sym);
44612538Scsvaf 	    } else {
447*18217Slinton 		printwhich(stdout, p->value.arg[0]->nodetype);
44812538Scsvaf 	    }
4499662Slinton 	    putchar('\n');
4509662Slinton 	    break;
4519662Slinton 
4529662Slinton 	case O_ALIAS:
4539662Slinton 	    n1 = p->value.arg[0];
4549662Slinton 	    n2 = p->value.arg[1];
455*18217Slinton 	    if (n2 == nil) {
456*18217Slinton 		if (n1 == nil) {
457*18217Slinton 		    alias(nil, nil, nil);
458*18217Slinton 		} else {
459*18217Slinton 		    alias(n1->value.name, nil, nil);
460*18217Slinton 		}
461*18217Slinton 	    } else if (n2->op == O_NAME) {
462*18217Slinton 		str = ident(n2->value.name);
463*18217Slinton 		alias(n1->value.name, nil, strdup(str));
4649662Slinton 	    } else {
465*18217Slinton 		if (n1->op == O_COMMA) {
466*18217Slinton 		    alias(
467*18217Slinton 			n1->value.arg[0]->value.name,
468*18217Slinton 			(List) n1->value.arg[1],
469*18217Slinton 			n2->value.scon
470*18217Slinton 		    );
471*18217Slinton 		} else {
472*18217Slinton 		    alias(n1->value.name, nil, n2->value.scon);
473*18217Slinton 		}
4749662Slinton 	    }
4759662Slinton 	    break;
4769662Slinton 
477*18217Slinton 	case O_UNALIAS:
478*18217Slinton 	    unalias(p->value.arg[0]->value.name);
479*18217Slinton 	    break;
480*18217Slinton 
481*18217Slinton 	case O_CALLPROC:
482*18217Slinton 	    callproc(p, false);
483*18217Slinton 	    break;
484*18217Slinton 
4859662Slinton 	case O_CALL:
486*18217Slinton 	    callproc(p, true);
4879662Slinton 	    break;
4889662Slinton 
4899662Slinton 	case O_CATCH:
490*18217Slinton 	    if (p->value.lcon == 0) {
491*18217Slinton 		printsigscaught(process);
492*18217Slinton 	    } else {
493*18217Slinton 		psigtrace(process, p->value.lcon, true);
494*18217Slinton 	    }
4959662Slinton 	    break;
4969662Slinton 
4979662Slinton 	case O_EDIT:
4989662Slinton 	    edit(p->value.scon);
4999662Slinton 	    break;
5009662Slinton 
50112538Scsvaf         case O_DEBUG:
50212538Scsvaf             debug(p);
50312538Scsvaf 	    break;
50412538Scsvaf 
50516608Ssam 	case O_DOWN:
50616608Ssam 	    checkref(p->value.arg[0]);
50716608Ssam 	    assert(p->value.arg[0]->op == O_LCON);
50816608Ssam 	    down(p->value.arg[0]->value.lcon);
50916608Ssam 	    break;
51016608Ssam 
5119662Slinton 	case O_DUMP:
512*18217Slinton 	    if (p->value.arg[0] == nil) {
513*18217Slinton 		dumpall();
514*18217Slinton 	    } else {
515*18217Slinton 		s = p->value.arg[0]->value.sym;
516*18217Slinton 		if (s == curfunc) {
517*18217Slinton 		    dump(nil);
518*18217Slinton 		} else {
519*18217Slinton 		    dump(s);
520*18217Slinton 		}
521*18217Slinton 	    }
5229662Slinton 	    break;
5239662Slinton 
5249662Slinton 	case O_GRIPE:
5259662Slinton 	    gripe();
5269662Slinton 	    break;
5279662Slinton 
5289662Slinton 	case O_HELP:
5299662Slinton 	    help();
5309662Slinton 	    break;
5319662Slinton 
5329662Slinton 	case O_IGNORE:
533*18217Slinton 	    if (p->value.lcon == 0) {
534*18217Slinton 		printsigsignored(process);
535*18217Slinton 	    } else {
536*18217Slinton 		psigtrace(process, p->value.lcon, false);
537*18217Slinton 	    }
5389662Slinton 	    break;
5399662Slinton 
54016608Ssam 	case O_RETURN:
54116608Ssam 	    if (p->value.arg[0] == nil) {
54216608Ssam 		rtnfunc(nil);
54316608Ssam 	    } else {
54416608Ssam 		assert(p->value.arg[0]->op == O_SYM);
54516608Ssam 		rtnfunc(p->value.arg[0]->value.sym);
54616608Ssam 	    }
54716608Ssam 	    break;
54816608Ssam 
5499662Slinton 	case O_RUN:
5509662Slinton 	    run();
5519662Slinton 	    break;
5529662Slinton 
553*18217Slinton 	case O_SET:
554*18217Slinton 	    set(p->value.arg[0], p->value.arg[1]);
555*18217Slinton 	    break;
556*18217Slinton 
557*18217Slinton 	case O_SEARCH:
558*18217Slinton 	    search(p->value.arg[0]->value.lcon, p->value.arg[1]->value.scon);
559*18217Slinton 	    break;
560*18217Slinton 
5619662Slinton 	case O_SOURCE:
5629662Slinton 	    setinput(p->value.scon);
5639662Slinton 	    break;
5649662Slinton 
5659662Slinton 	case O_STATUS:
5669662Slinton 	    status();
5679662Slinton 	    break;
5689662Slinton 
5699662Slinton 	case O_TRACE:
5709662Slinton 	case O_TRACEI:
5719662Slinton 	    trace(p);
5729662Slinton 	    break;
5739662Slinton 
5749662Slinton 	case O_STOP:
5759662Slinton 	case O_STOPI:
5769662Slinton 	    stop(p);
5779662Slinton 	    break;
5789662Slinton 
579*18217Slinton 	case O_UNSET:
580*18217Slinton 	    undefvar(p->value.arg[0]->value.name);
581*18217Slinton 	    break;
582*18217Slinton 
58316608Ssam 	case O_UP:
58416608Ssam 	    checkref(p->value.arg[0]);
58516608Ssam 	    assert(p->value.arg[0]->op == O_LCON);
58616608Ssam 	    up(p->value.arg[0]->value.lcon);
58716608Ssam 	    break;
58816608Ssam 
5899662Slinton 	case O_ADDEVENT:
5909662Slinton 	    addevent(p->value.event.cond, p->value.event.actions);
5919662Slinton 	    break;
5929662Slinton 
5939662Slinton 	case O_DELETE:
59416608Ssam 	    n1 = p->value.arg[0];
59516608Ssam 	    while (n1->op == O_COMMA) {
59616608Ssam 		n2 = n1->value.arg[0];
59716608Ssam 		assert(n2->op == O_LCON);
59816608Ssam 		if (not delevent((unsigned int) n2->value.lcon)) {
59916608Ssam 		    error("unknown event %ld", n2->value.lcon);
60016608Ssam 		}
60116608Ssam 		n1 = n1->value.arg[1];
60216608Ssam 	    }
60316608Ssam 	    assert(n1->op == O_LCON);
60416608Ssam 	    if (not delevent((unsigned int) n1->value.lcon)) {
60516608Ssam 		error("unknown event %ld", n1->value.lcon);
60616608Ssam 	    }
6079662Slinton 	    break;
6089662Slinton 
6099662Slinton 	case O_ENDX:
6109662Slinton 	    endprogram();
6119662Slinton 	    break;
6129662Slinton 
6139662Slinton 	case O_IF:
6149662Slinton 	    if (cond(p->value.event.cond)) {
6159662Slinton 		evalcmdlist(p->value.event.actions);
6169662Slinton 	    }
6179662Slinton 	    break;
6189662Slinton 
6199662Slinton 	case O_ONCE:
6209662Slinton 	    event_once(p->value.event.cond, p->value.event.actions);
6219662Slinton 	    break;
6229662Slinton 
6239662Slinton 	case O_PRINTCALL:
6249662Slinton 	    printcall(p->value.sym, whatblock(return_addr()));
6259662Slinton 	    break;
6269662Slinton 
6279662Slinton 	case O_PRINTIFCHANGED:
6289662Slinton 	    printifchanged(p->value.arg[0]);
6299662Slinton 	    break;
6309662Slinton 
6319662Slinton 	case O_PRINTRTN:
6329662Slinton 	    printrtn(p->value.sym);
6339662Slinton 	    break;
6349662Slinton 
6359662Slinton 	case O_PRINTSRCPOS:
6369662Slinton 	    getsrcpos();
6379662Slinton 	    if (p->value.arg[0] == nil) {
6389662Slinton 		printsrcpos();
6399662Slinton 		putchar('\n');
6409662Slinton 		printlines(curline, curline);
6419662Slinton 	    } else if (p->value.arg[0]->op == O_QLINE) {
6429662Slinton 		if (p->value.arg[0]->value.arg[1]->value.lcon == 0) {
6439662Slinton 		    printf("tracei: ");
6449662Slinton 		    printinst(pc, pc);
6459662Slinton 		} else {
646*18217Slinton 		    if (canReadSource()) {
647*18217Slinton 			printf("trace:  ");
648*18217Slinton 			printlines(curline, curline);
649*18217Slinton 		    }
6509662Slinton 		}
6519662Slinton 	    } else {
6529662Slinton 		printsrcpos();
6539662Slinton 		printf(": ");
6549662Slinton 		eval(p->value.arg[0]);
6559662Slinton 		prtree(stdout, p->value.arg[0]);
6569662Slinton 		printf(" = ");
6579662Slinton 		printval(p->value.arg[0]->nodetype);
6589662Slinton 		putchar('\n');
6599662Slinton 	    }
6609662Slinton 	    break;
6619662Slinton 
6629662Slinton 	case O_PROCRTN:
6639662Slinton 	    procreturn(p->value.sym);
6649662Slinton 	    break;
6659662Slinton 
6669662Slinton 	case O_STOPIFCHANGED:
6679662Slinton 	    stopifchanged(p->value.arg[0]);
6689662Slinton 	    break;
6699662Slinton 
6709662Slinton 	case O_STOPX:
6719662Slinton 	    isstopped = true;
6729662Slinton 	    break;
6739662Slinton 
6749662Slinton 	case O_TRACEON:
6759662Slinton 	    traceon(p->value.trace.inst, p->value.trace.event,
6769662Slinton 		p->value.trace.actions);
6779662Slinton 	    break;
6789662Slinton 
6799662Slinton 	case O_TRACEOFF:
6809662Slinton 	    traceoff(p->value.lcon);
6819662Slinton 	    break;
6829662Slinton 
6839662Slinton 	default:
6849662Slinton 	    panic("eval: bad op %d", p->op);
6859662Slinton     }
686*18217Slinton     if (traceeval) {
687*18217Slinton 	fprintf(stderr, "end eval %s\n", opname(p->op));
688*18217Slinton     }
6899662Slinton }
6909662Slinton 
6919662Slinton /*
6929662Slinton  * Evaluate a list of commands.
6939662Slinton  */
6949662Slinton 
6959662Slinton public evalcmdlist(cl)
6969662Slinton Cmdlist cl;
6979662Slinton {
6989662Slinton     Command c;
6999662Slinton 
7009662Slinton     foreach (Command, c, cl)
7019662Slinton 	evalcmd(c);
7029662Slinton     endfor
7039662Slinton }
7049662Slinton 
7059662Slinton /*
7069662Slinton  * Push "len" bytes onto the expression stack from address "addr"
7079662Slinton  * in the process.  If there isn't room on the stack, print an error message.
7089662Slinton  */
7099662Slinton 
7109662Slinton public rpush(addr, len)
7119662Slinton Address addr;
7129662Slinton int len;
7139662Slinton {
7149662Slinton     if (not canpush(len)) {
7159662Slinton 	error("expression too large to evaluate");
7169662Slinton     } else {
7179662Slinton 	chksp();
7189662Slinton 	dread(sp, addr, len);
7199662Slinton 	sp += len;
7209662Slinton     }
7219662Slinton }
7229662Slinton 
7239662Slinton /*
7249662Slinton  * Check if the stack has n bytes available.
7259662Slinton  */
7269662Slinton 
7279662Slinton public Boolean canpush(n)
7289662Slinton Integer n;
7299662Slinton {
7309662Slinton     return (Boolean) (sp + n < &stack[STACKSIZE]);
7319662Slinton }
7329662Slinton 
7339662Slinton /*
7349662Slinton  * Push a small scalar of the given type onto the stack.
7359662Slinton  */
7369662Slinton 
7379662Slinton public pushsmall(t, v)
7389662Slinton Symbol t;
7399662Slinton long v;
7409662Slinton {
7419662Slinton     register Integer s;
7429662Slinton 
7439662Slinton     s = size(t);
7449662Slinton     switch (s) {
7459662Slinton 	case sizeof(char):
7469662Slinton 	    push(char, v);
7479662Slinton 	    break;
7489662Slinton 
7499662Slinton 	case sizeof(short):
7509662Slinton 	    push(short, v);
7519662Slinton 	    break;
7529662Slinton 
7539662Slinton 	case sizeof(long):
7549662Slinton 	    push(long, v);
7559662Slinton 	    break;
7569662Slinton 
7579662Slinton 	default:
7589662Slinton 	    panic("bad size %d in popsmall", s);
7599662Slinton     }
7609662Slinton }
7619662Slinton 
7629662Slinton /*
7639662Slinton  * Pop an item of the given type which is assumed to be no larger
7649662Slinton  * than a long and return it expanded into a long.
7659662Slinton  */
7669662Slinton 
7679662Slinton public long popsmall(t)
7689662Slinton Symbol t;
7699662Slinton {
770*18217Slinton     register integer n;
7719662Slinton     long r;
7729662Slinton 
773*18217Slinton     n = size(t);
774*18217Slinton     if (n == sizeof(char)) {
775*18217Slinton 	if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
776*18217Slinton 	    r = (long) pop(unsigned char);
777*18217Slinton 	} else {
7789662Slinton 	    r = (long) pop(char);
779*18217Slinton 	}
780*18217Slinton     } else if (n == sizeof(short)) {
781*18217Slinton 	if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
782*18217Slinton 	    r = (long) pop(unsigned short);
783*18217Slinton 	} else {
7849662Slinton 	    r = (long) pop(short);
785*18217Slinton 	}
786*18217Slinton     } else if (n == sizeof(long)) {
787*18217Slinton 	r = pop(long);
788*18217Slinton     } else {
789*18217Slinton 	error("[internal error: size %d in popsmall]", n);
7909662Slinton     }
7919662Slinton     return r;
7929662Slinton }
7939662Slinton 
7949662Slinton /*
7959662Slinton  * Evaluate a conditional expression.
7969662Slinton  */
7979662Slinton 
7989662Slinton public Boolean cond(p)
7999662Slinton Node p;
8009662Slinton {
8019662Slinton     register Boolean b;
8029662Slinton 
8039662Slinton     if (p == nil) {
8049662Slinton 	b = true;
8059662Slinton     } else {
8069662Slinton 	eval(p);
80713846Slinton 	b = (Boolean) pop(Boolrep);
8089662Slinton     }
8099662Slinton     return b;
8109662Slinton }
8119662Slinton 
8129662Slinton /*
8139662Slinton  * Return the address corresponding to a given tree.
8149662Slinton  */
8159662Slinton 
8169662Slinton public Address lval(p)
8179662Slinton Node p;
8189662Slinton {
8199662Slinton     if (p->op == O_RVAL) {
8209662Slinton 	eval(p->value.arg[0]);
8219662Slinton     } else {
8229662Slinton 	eval(p);
8239662Slinton     }
8249662Slinton     return (Address) (pop(long));
8259662Slinton }
8269662Slinton 
8279662Slinton /*
8289662Slinton  * Process a trace command, translating into the appropriate events
8299662Slinton  * and associated actions.
8309662Slinton  */
8319662Slinton 
8329662Slinton public trace(p)
8339662Slinton Node p;
8349662Slinton {
8359662Slinton     Node exp, place, cond;
8369662Slinton     Node left;
8379662Slinton 
8389662Slinton     exp = p->value.arg[0];
8399662Slinton     place = p->value.arg[1];
8409662Slinton     cond = p->value.arg[2];
8419662Slinton     if (exp == nil) {
8429662Slinton 	traceall(p->op, place, cond);
84311771Slinton     } else if (exp->op == O_QLINE or exp->op == O_LCON) {
8449662Slinton 	traceinst(p->op, exp, cond);
8459662Slinton     } else if (place != nil and place->op == O_QLINE) {
8469662Slinton 	traceat(p->op, exp, place, cond);
8479662Slinton     } else {
8489861Slinton 	left = exp;
8499861Slinton 	if (left->op == O_RVAL or left->op == O_CALL) {
8509861Slinton 	    left = left->value.arg[0];
8519861Slinton 	}
8529662Slinton 	if (left->op == O_SYM and isblock(left->value.sym)) {
8539662Slinton 	    traceproc(p->op, left->value.sym, place, cond);
8549662Slinton 	} else {
8559662Slinton 	    tracedata(p->op, exp, place, cond);
8569662Slinton 	}
8579662Slinton     }
8589662Slinton }
8599662Slinton 
8609662Slinton /*
8619662Slinton  * Set a breakpoint that will turn on tracing.
8629662Slinton  */
8639662Slinton 
8649662Slinton private traceall(op, place, cond)
8659662Slinton Operator op;
8669662Slinton Node place;
8679662Slinton Node cond;
8689662Slinton {
8699662Slinton     Symbol s;
8709662Slinton     Node event;
8719662Slinton     Command action;
8729662Slinton 
8739662Slinton     if (place == nil) {
8749662Slinton 	s = program;
8759662Slinton     } else {
8769662Slinton 	s = place->value.sym;
8779662Slinton     }
8789662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
8799662Slinton     action = build(O_PRINTSRCPOS,
8809662Slinton 	build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0)));
8819662Slinton     if (cond != nil) {
8829662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
8839662Slinton     }
8849662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
8859662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
88611871Slinton     if (isstdin()) {
88711871Slinton 	printevent(action->value.trace.event);
88811871Slinton     }
8899662Slinton }
8909662Slinton 
8919662Slinton /*
8929662Slinton  * Set up the appropriate breakpoint for tracing an instruction.
8939662Slinton  */
8949662Slinton 
8959662Slinton private traceinst(op, exp, cond)
8969662Slinton Operator op;
8979662Slinton Node exp;
8989662Slinton Node cond;
8999662Slinton {
90011771Slinton     Node event, wh;
9019662Slinton     Command action;
90211871Slinton     Event e;
9039662Slinton 
90411771Slinton     if (exp->op == O_LCON) {
905*18217Slinton 	wh = build(O_QLINE, build(O_SCON, strdup(cursource)), exp);
90611771Slinton     } else {
90711771Slinton 	wh = exp;
90811771Slinton     }
9099662Slinton     if (op == O_TRACEI) {
91011771Slinton 	event = build(O_EQ, build(O_SYM, pcsym), wh);
9119662Slinton     } else {
91211771Slinton 	event = build(O_EQ, build(O_SYM, linesym), wh);
9139662Slinton     }
91411771Slinton     action = build(O_PRINTSRCPOS, wh);
9159662Slinton     if (cond) {
9169662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
9179662Slinton     }
91811871Slinton     e = addevent(event, buildcmdlist(action));
91911871Slinton     if (isstdin()) {
92011871Slinton 	printevent(e);
92111871Slinton     }
9229662Slinton }
9239662Slinton 
9249662Slinton /*
9259662Slinton  * Set a breakpoint to print an expression at a given line or address.
9269662Slinton  */
9279662Slinton 
9289662Slinton private traceat(op, exp, place, cond)
9299662Slinton Operator op;
9309662Slinton Node exp;
9319662Slinton Node place;
9329662Slinton Node cond;
9339662Slinton {
9349662Slinton     Node event;
9359662Slinton     Command action;
93611871Slinton     Event e;
9379662Slinton 
9389662Slinton     if (op == O_TRACEI) {
9399662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
9409662Slinton     } else {
9419662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
9429662Slinton     }
9439662Slinton     action = build(O_PRINTSRCPOS, exp);
9449662Slinton     if (cond != nil) {
9459662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
9469662Slinton     }
94711871Slinton     e = addevent(event, buildcmdlist(action));
94811871Slinton     if (isstdin()) {
94911871Slinton 	printevent(e);
95011871Slinton     }
9519662Slinton }
9529662Slinton 
9539662Slinton /*
9549662Slinton  * Construct event for tracing a procedure.
9559662Slinton  *
9569662Slinton  * What we want here is
9579662Slinton  *
9589662Slinton  * 	when $proc = p do
9599662Slinton  *	    if <condition> then
9609662Slinton  *	        printcall;
9619662Slinton  *	        once $pc = $retaddr do
9629662Slinton  *	            printrtn;
9639662Slinton  *	        end;
9649662Slinton  *	    end if;
9659662Slinton  *	end;
9669662Slinton  *
9679662Slinton  * Note that "once" is like "when" except that the event
9689662Slinton  * deletes itself as part of its associated action.
9699662Slinton  */
9709662Slinton 
9719662Slinton private traceproc(op, p, place, cond)
9729662Slinton Operator op;
9739662Slinton Symbol p;
9749662Slinton Node place;
9759662Slinton Node cond;
9769662Slinton {
9779662Slinton     Node event;
9789662Slinton     Command action;
9799662Slinton     Cmdlist actionlist;
98011871Slinton     Event e;
9819662Slinton 
9829662Slinton     action = build(O_PRINTCALL, p);
9839662Slinton     actionlist = list_alloc();
9849662Slinton     cmdlist_append(action, actionlist);
9859662Slinton     event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym));
9869662Slinton     action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p)));
9879662Slinton     cmdlist_append(action, actionlist);
9889662Slinton     if (cond != nil) {
9899662Slinton 	actionlist = buildcmdlist(build(O_IF, cond, actionlist));
9909662Slinton     }
9919662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
99211871Slinton     e = addevent(event, actionlist);
99311871Slinton     if (isstdin()) {
99411871Slinton 	printevent(e);
99511871Slinton     }
9969662Slinton }
9979662Slinton 
9989662Slinton /*
9999662Slinton  * Set up breakpoint for tracing data.
10009662Slinton  */
10019662Slinton 
10029662Slinton private tracedata(op, exp, place, cond)
10039662Slinton Operator op;
10049662Slinton Node exp;
10059662Slinton Node place;
10069662Slinton Node cond;
10079662Slinton {
10089662Slinton     Symbol p;
10099662Slinton     Node event;
10109662Slinton     Command action;
10119662Slinton 
10129662Slinton     p = (place == nil) ? tcontainer(exp) : place->value.sym;
10139662Slinton     if (p == nil) {
10149662Slinton 	p = program;
10159662Slinton     }
10169662Slinton     action = build(O_PRINTIFCHANGED, exp);
10179662Slinton     if (cond != nil) {
10189662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
10199662Slinton     }
10209662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
10219662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
10229662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
102311871Slinton     if (isstdin()) {
102411871Slinton 	printevent(action->value.trace.event);
102511871Slinton     }
10269662Slinton }
10279662Slinton 
10289662Slinton /*
10299662Slinton  * Setting and unsetting of stops.
10309662Slinton  */
10319662Slinton 
10329662Slinton public stop(p)
10339662Slinton Node p;
10349662Slinton {
103513846Slinton     Node exp, place, cond, t;
10369662Slinton     Symbol s;
10379662Slinton     Command action;
103811871Slinton     Event e;
10399662Slinton 
10409662Slinton     exp = p->value.arg[0];
10419662Slinton     place = p->value.arg[1];
10429662Slinton     cond = p->value.arg[2];
10439662Slinton     if (exp != nil) {
10449662Slinton 	stopvar(p->op, exp, place, cond);
104513846Slinton     } else {
104613846Slinton 	action = build(O_STOPX);
104713846Slinton 	if (cond != nil) {
104813846Slinton 	    action = build(O_IF, cond, buildcmdlist(action));
104911871Slinton 	}
105016608Ssam 	if (place == nil or place->op == O_SYM) {
105116608Ssam 	    if (place == nil) {
105216608Ssam 		s = program;
105316608Ssam 	    } else {
105416608Ssam 		s = place->value.sym;
105516608Ssam 	    }
105613846Slinton 	    t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
105713846Slinton 	    if (cond != nil) {
105813846Slinton 		action = build(O_TRACEON, (p->op == O_STOPI),
105913846Slinton 		    buildcmdlist(action));
106013846Slinton 		e = addevent(t, buildcmdlist(action));
106113846Slinton 		action->value.trace.event = e;
106213846Slinton 	    } else {
106313846Slinton 		e = addevent(t, buildcmdlist(action));
106413846Slinton 	    }
106513846Slinton 	    if (isstdin()) {
106613846Slinton 		printevent(e);
106713846Slinton 	    }
106813846Slinton 	} else {
106913846Slinton 	    stopinst(p->op, place, cond, action);
107013846Slinton 	}
10719662Slinton     }
10729662Slinton }
10739662Slinton 
107413846Slinton private stopinst(op, place, cond, action)
10759662Slinton Operator op;
10769662Slinton Node place;
10779662Slinton Node cond;
107813846Slinton Command action;
10799662Slinton {
10809662Slinton     Node event;
108111871Slinton     Event e;
10829662Slinton 
10839662Slinton     if (op == O_STOP) {
10849662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
10859662Slinton     } else {
10869662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
10879662Slinton     }
108813846Slinton     e = addevent(event, buildcmdlist(action));
108911871Slinton     if (isstdin()) {
109011871Slinton 	printevent(e);
109111871Slinton     }
10929662Slinton }
10939662Slinton 
10949662Slinton /*
10959662Slinton  * Implement stopping on assignment to a variable by adding it to
10969662Slinton  * the variable list.
10979662Slinton  */
10989662Slinton 
10999662Slinton private stopvar(op, exp, place, cond)
11009662Slinton Operator op;
11019662Slinton Node exp;
11029662Slinton Node place;
11039662Slinton Node cond;
11049662Slinton {
11059662Slinton     Symbol p;
11069662Slinton     Node event;
11079662Slinton     Command action;
11089662Slinton 
110914445Slinton     if (place == nil) {
111014445Slinton 	if (exp->op == O_LCON) {
111114445Slinton 	    p = program;
111214445Slinton 	} else {
111314445Slinton 	    p = tcontainer(exp);
111414445Slinton 	    if (p == nil) {
111514445Slinton 		p = program;
111614445Slinton 	    }
111714445Slinton 	}
111814445Slinton     } else {
111914445Slinton 	p = place->value.sym;
11209662Slinton     }
112114445Slinton     action = build(O_STOPIFCHANGED, exp);
112214445Slinton     if (cond != nil) {
112314445Slinton 	action = build(O_IF, cond, buildcmdlist(action));
112414445Slinton     }
11259662Slinton     action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action));
11269662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
11279662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
112811871Slinton     if (isstdin()) {
112911871Slinton 	printevent(action->value.trace.event);
113011871Slinton     }
11319662Slinton }
11329662Slinton 
11339662Slinton /*
11349662Slinton  * Assign the value of an expression to a variable (or term).
11359662Slinton  */
11369662Slinton 
11379662Slinton public assign(var, exp)
11389662Slinton Node var;
11399662Slinton Node exp;
11409662Slinton {
11419662Slinton     Address addr;
114216608Ssam     integer varsize, expsize;
11439662Slinton     char cvalue;
11449662Slinton     short svalue;
11459662Slinton     long lvalue;
114616608Ssam     float fvalue;
11479662Slinton 
1148*18217Slinton     if (var->op == O_SYM and regnum(var->value.sym) != -1) {
1149*18217Slinton 	eval(exp);
1150*18217Slinton 	setreg(regnum(var->value.sym), pop(Address));
115116608Ssam     } else {
1152*18217Slinton 	addr = lval(var);
1153*18217Slinton 	varsize = size(var->nodetype);
1154*18217Slinton 	expsize = size(exp->nodetype);
1155*18217Slinton 	eval(exp);
1156*18217Slinton 	if (varsize == sizeof(float) and expsize == sizeof(double)) {
1157*18217Slinton 	    fvalue = (float) pop(double);
1158*18217Slinton 	    dwrite(&fvalue, addr, sizeof(fvalue));
1159*18217Slinton 	} else {
1160*18217Slinton 	    if (varsize < sizeof(long)) {
1161*18217Slinton 		lvalue = 0;
1162*18217Slinton 		popn(expsize, &lvalue);
1163*18217Slinton 		if (varsize == sizeof(char)) {
116416608Ssam 		    cvalue = lvalue;
116516608Ssam 		    dwrite(&cvalue, addr, sizeof(cvalue));
1166*18217Slinton 		} else if (varsize == sizeof(short)) {
116716608Ssam 		    svalue = lvalue;
116816608Ssam 		    dwrite(&svalue, addr, sizeof(svalue));
1169*18217Slinton 		} else {
1170*18217Slinton 		    error("[internal error: bad size %d in assign]", varsize);
1171*18217Slinton 		}
1172*18217Slinton 	    } else {
1173*18217Slinton 		if (expsize <= varsize) {
1174*18217Slinton 		    sp -= expsize;
1175*18217Slinton 		    dwrite(sp, addr, expsize);
1176*18217Slinton 		} else {
1177*18217Slinton 		    sp -= expsize;
1178*18217Slinton 		    dwrite(sp, addr, varsize);
1179*18217Slinton 		}
1180*18217Slinton 	    }
1181*18217Slinton 	}
1182*18217Slinton     }
1183*18217Slinton }
11849662Slinton 
1185*18217Slinton /*
1186*18217Slinton  * Set a debugger variable.
1187*18217Slinton  */
1188*18217Slinton 
1189*18217Slinton private set (var, exp)
1190*18217Slinton Node var, exp;
1191*18217Slinton {
1192*18217Slinton     Symbol t;
1193*18217Slinton 
1194*18217Slinton     if (var == nil) {
1195*18217Slinton 	defvar(nil, nil);
1196*18217Slinton     } else if (exp == nil) {
1197*18217Slinton 	defvar(var->value.name, nil);
1198*18217Slinton     } else if (var->value.name == identname("$frame", true)) {
1199*18217Slinton 	t = exp->nodetype;
1200*18217Slinton 	if (not compatible(t, t_int) and not compatible(t, t_addr)) {
1201*18217Slinton 	    error("$frame must be an address");
1202*18217Slinton 	}
1203*18217Slinton 	eval(exp);
1204*18217Slinton 	getnewregs(pop(Address));
1205*18217Slinton     } else {
1206*18217Slinton 	defvar(var->value.name, unrval(exp));
1207*18217Slinton     }
1208*18217Slinton }
1209*18217Slinton 
1210*18217Slinton /*
1211*18217Slinton  * Execute a list command.
1212*18217Slinton  */
1213*18217Slinton 
1214*18217Slinton private list (p)
1215*18217Slinton Node p;
1216*18217Slinton {
1217*18217Slinton     Symbol f;
1218*18217Slinton     Address addr;
1219*18217Slinton     Lineno line, l1, l2;
1220*18217Slinton 
1221*18217Slinton     if (p->value.arg[0]->op == O_SYM) {
1222*18217Slinton 	f = p->value.arg[0]->value.sym;
1223*18217Slinton 	addr = firstline(f);
1224*18217Slinton 	if (addr == NOADDR) {
1225*18217Slinton 	    error("no source lines for \"%s\"", symname(f));
1226*18217Slinton 	}
1227*18217Slinton 	setsource(srcfilename(addr));
1228*18217Slinton 	line = srcline(addr);
1229*18217Slinton 	getsrcwindow(line, &l1, &l2);
1230*18217Slinton     } else {
1231*18217Slinton 	eval(p->value.arg[0]);
1232*18217Slinton 	l1 = (Lineno) (pop(long));
1233*18217Slinton 	eval(p->value.arg[1]);
1234*18217Slinton 	l2 = (Lineno) (pop(long));
1235*18217Slinton     }
1236*18217Slinton     printlines(l1, l2);
1237*18217Slinton }
1238*18217Slinton 
1239*18217Slinton /*
1240*18217Slinton  * Execute a func command.
1241*18217Slinton  */
1242*18217Slinton 
1243*18217Slinton private func (p)
1244*18217Slinton Node p;
1245*18217Slinton {
1246*18217Slinton     Symbol s, f;
1247*18217Slinton     Address addr;
1248*18217Slinton 
1249*18217Slinton     if (p == nil) {
1250*18217Slinton 	printname(stdout, curfunc);
1251*18217Slinton 	putchar('\n');
1252*18217Slinton     } else {
1253*18217Slinton 	s = p->value.sym;
1254*18217Slinton 	if (isroutine(s)) {
1255*18217Slinton 	    setcurfunc(s);
125616608Ssam 	} else {
1257*18217Slinton 	    find(f, s->name) where isroutine(f) endfind(f);
1258*18217Slinton 	    if (f == nil) {
1259*18217Slinton 		error("%s is not a procedure or function", symname(s));
126016608Ssam 	    }
1261*18217Slinton 	    setcurfunc(f);
12629662Slinton 	}
1263*18217Slinton 	addr = codeloc(curfunc);
1264*18217Slinton 	if (addr != NOADDR) {
1265*18217Slinton 	    setsource(srcfilename(addr));
1266*18217Slinton 	    cursrcline = srcline(addr);
1267*18217Slinton 	}
12689662Slinton     }
12699662Slinton }
12709662Slinton 
12719662Slinton /*
1272*18217Slinton  * Send a message to the current support person.
12739662Slinton  */
12749662Slinton 
12759662Slinton public gripe()
12769662Slinton {
12779662Slinton     typedef Operation();
12789662Slinton     Operation *old;
127914445Slinton     int pid, status;
128016608Ssam     extern int versionNumber;
128116608Ssam     char subject[100];
12829662Slinton 
12839662Slinton     puts("Type control-D to end your message.  Be sure to include");
12849662Slinton     puts("your name and the name of the file you are debugging.");
12859662Slinton     putchar('\n');
12869662Slinton     old = signal(SIGINT, SIG_DFL);
1287*18217Slinton     sprintf(subject, "dbx (version 3.%d) gripe", versionNumber);
1288*18217Slinton     pid = back("Mail", stdin, stdout, "-s", subject, MAINTAINER, nil);
128914445Slinton     signal(SIGINT, SIG_IGN);
129014445Slinton     pwait(pid, &status);
12919662Slinton     signal(SIGINT, old);
129214445Slinton     if (status == 0) {
129314445Slinton 	puts("Thank you.");
129414445Slinton     } else {
129514445Slinton 	puts("\nMail not sent.");
129614445Slinton     }
12979662Slinton }
12989662Slinton 
12999662Slinton /*
13009662Slinton  * Give the user some help.
13019662Slinton  */
13029662Slinton 
13039662Slinton public help()
13049662Slinton {
13059662Slinton     puts("run                    - begin execution of the program");
130616608Ssam     puts("print <exp>            - print the value of the expression");
130716608Ssam     puts("where                  - print currently active procedures");
130816608Ssam     puts("stop at <line>         - suspend execution at the line");
130916608Ssam     puts("stop in <proc>         - suspend execution when <proc> is called");
13109662Slinton     puts("cont                   - continue execution");
13119662Slinton     puts("step                   - single step one line");
13129662Slinton     puts("next                   - step to next line (skip over calls)");
13139662Slinton     puts("trace <line#>          - trace execution of the line");
13149662Slinton     puts("trace <proc>           - trace calls to the procedure");
13159662Slinton     puts("trace <var>            - trace changes to the variable");
13169662Slinton     puts("trace <exp> at <line#> - print <exp> when <line> is reached");
13179662Slinton     puts("status                 - print trace/stop's in effect");
13189662Slinton     puts("delete <number>        - remove trace or stop of given number");
131916608Ssam     puts("call <proc>            - call a procedure in program");
13209662Slinton     puts("whatis <name>          - print the declaration of the name");
13219662Slinton     puts("list <line>, <line>    - list source lines");
13229662Slinton     puts("gripe                  - send mail to the person in charge of dbx");
13239662Slinton     puts("quit                   - exit dbx");
13249662Slinton }
13259662Slinton 
13269662Slinton /*
13279662Slinton  * Divert output to the given file name.
13289662Slinton  * Cannot redirect to an existing file.
13299662Slinton  */
13309662Slinton 
13319662Slinton private int so_fd;
13329662Slinton private Boolean notstdout;
13339662Slinton 
13349662Slinton public setout(filename)
13359662Slinton String filename;
13369662Slinton {
13379662Slinton     File f;
13389662Slinton 
13399662Slinton     f = fopen(filename, "r");
13409662Slinton     if (f != nil) {
13419662Slinton 	fclose(f);
13429662Slinton 	error("%s: file already exists", filename);
13439662Slinton     } else {
13449662Slinton 	so_fd = dup(1);
13459662Slinton 	close(1);
13469662Slinton 	if (creat(filename, 0666) == nil) {
13479662Slinton 	    unsetout();
13489662Slinton 	    error("can't create %s", filename);
13499662Slinton 	}
13509662Slinton 	notstdout = true;
13519662Slinton     }
13529662Slinton }
13539662Slinton 
13549662Slinton /*
13559662Slinton  * Revert output to standard output.
13569662Slinton  */
13579662Slinton 
13589662Slinton public unsetout()
13599662Slinton {
13609662Slinton     fflush(stdout);
13619662Slinton     close(1);
13629662Slinton     if (dup(so_fd) != 1) {
13639662Slinton 	panic("standard out dup failed");
13649662Slinton     }
13659662Slinton     close(so_fd);
13669662Slinton     notstdout = false;
13679662Slinton }
13689662Slinton 
13699662Slinton /*
13709662Slinton  * Determine is standard output is currently being redirected
13719662Slinton  * to a file (as far as we know).
13729662Slinton  */
13739662Slinton 
13749662Slinton public Boolean isredirected()
13759662Slinton {
13769662Slinton     return notstdout;
13779662Slinton }
1378