xref: /csrg-svn/old/dbx/eval.c (revision 21601)
1*21601Sdist /*
2*21601Sdist  * Copyright (c) 1983 Regents of the University of California.
3*21601Sdist  * All rights reserved.  The Berkeley software License Agreement
4*21601Sdist  * specifies the terms and conditions for redistribution.
5*21601Sdist  */
69662Slinton 
7*21601Sdist #ifndef lint
8*21601Sdist static char sccsid[] = "@(#)eval.c	5.1 (Berkeley) 05/31/85";
9*21601Sdist #endif not lint
109662Slinton 
1118217Slinton static char rcsid[] = "$Header: eval.c,v 1.5 84/12/26 10:39:08 linton Exp $";
1218217Slinton 
139662Slinton /*
149662Slinton  * Tree evaluation.
159662Slinton  */
169662Slinton 
179662Slinton #include "defs.h"
189662Slinton #include "tree.h"
199662Slinton #include "operators.h"
2018217Slinton #include "debug.h"
219662Slinton #include "eval.h"
229662Slinton #include "events.h"
239662Slinton #include "symbols.h"
249662Slinton #include "scanner.h"
259662Slinton #include "source.h"
269662Slinton #include "object.h"
279662Slinton #include "mappings.h"
289662Slinton #include "process.h"
2916608Ssam #include "runtime.h"
309662Slinton #include "machine.h"
319662Slinton #include <signal.h>
329662Slinton 
339662Slinton #ifndef public
349662Slinton 
359662Slinton #include "machine.h"
369662Slinton 
3712538Scsvaf #define STACKSIZE 20000
389662Slinton 
399662Slinton typedef Char Stack;
409662Slinton 
419662Slinton #define push(type, value) { \
429662Slinton     ((type *) (sp += sizeof(type)))[-1] = (value); \
439662Slinton }
449662Slinton 
459662Slinton #define pop(type) ( \
469662Slinton     (*((type *) (sp -= sizeof(type)))) \
479662Slinton )
489662Slinton 
4916608Ssam #define popn(n, dest) { \
5016608Ssam     sp -= n; \
5116608Ssam     bcopy(sp, dest, n); \
5216608Ssam }
5316608Ssam 
549662Slinton #define alignstack() { \
559662Slinton     sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
569662Slinton }
579662Slinton 
589662Slinton #endif
599662Slinton 
609662Slinton public Stack stack[STACKSIZE];
619662Slinton public Stack *sp = &stack[0];
6214674Slinton public Boolean useInstLoc = false;
639662Slinton 
649662Slinton #define chksp() \
659662Slinton { \
669662Slinton     if (sp < &stack[0]) { \
679662Slinton 	panic("stack underflow"); \
689662Slinton     } \
699662Slinton }
709662Slinton 
719662Slinton #define poparg(n, r, fr) { \
729662Slinton     eval(p->value.arg[n]); \
739662Slinton     if (isreal(p->op)) { \
7416608Ssam 	if (size(p->value.arg[n]->nodetype) == sizeof(float)) { \
7516608Ssam 	    fr = pop(float); \
7616608Ssam 	} else { \
7716608Ssam 	    fr = pop(double); \
7816608Ssam 	} \
799662Slinton     } else if (isint(p->op)) { \
809662Slinton 	r = popsmall(p->value.arg[n]->nodetype); \
819662Slinton     } \
829662Slinton }
839662Slinton 
849662Slinton #define Boolrep char	/* underlying representation type for booleans */
859662Slinton 
869662Slinton /*
8718217Slinton  * Command-level evaluation.
8818217Slinton  */
8918217Slinton 
9018217Slinton public Node topnode;
9118217Slinton 
9218217Slinton public topeval (p)
9318217Slinton Node p;
9418217Slinton {
9518217Slinton     if (traceeval) {
9618217Slinton 	fprintf(stderr, "topeval(");
9718217Slinton 	prtree(stderr, p);
9818217Slinton 	fprintf(stderr, ")\n");
9918217Slinton 	fflush(stderr);
10018217Slinton     }
10118217Slinton     topnode = p;
10218217Slinton     eval(p);
10318217Slinton }
10418217Slinton 
10518217Slinton /*
1069662Slinton  * Evaluate a parse tree leaving the value on the top of the stack.
1079662Slinton  */
1089662Slinton 
1099662Slinton public eval(p)
1109662Slinton register Node p;
1119662Slinton {
1129662Slinton     long r0, r1;
1139662Slinton     double fr0, fr1;
1149662Slinton     Address addr;
1159662Slinton     long i, n;
1169662Slinton     int len;
11718217Slinton     Symbol s;
1189662Slinton     Node n1, n2;
11918217Slinton     boolean b;
1209662Slinton     File file;
12118217Slinton     String str;
1229662Slinton 
1239662Slinton     checkref(p);
12418217Slinton     if (traceeval) {
12518217Slinton 	fprintf(stderr, "begin eval %s\n", opname(p->op));
12612538Scsvaf     }
1279662Slinton     switch (degree(p->op)) {
1289662Slinton 	case BINARY:
1299662Slinton 	    poparg(1, r1, fr1);
1309662Slinton 	    poparg(0, r0, fr0);
1319662Slinton 	    break;
1329662Slinton 
1339662Slinton 	case UNARY:
1349662Slinton 	    poparg(0, r0, fr0);
1359662Slinton 	    break;
1369662Slinton 
1379662Slinton 	default:
1389662Slinton 	    /* do nothing */;
1399662Slinton     }
1409662Slinton     switch (p->op) {
1419662Slinton 	case O_SYM:
1429662Slinton 	    s = p->value.sym;
1439662Slinton 	    if (s == retaddrsym) {
1449662Slinton 		push(long, return_addr());
14518217Slinton 	    } else if (isvariable(s)) {
14618217Slinton 		if (s != program and not isactive(container(s))) {
14718217Slinton 		    error("\"%s\" is not active", symname(s));
14818217Slinton 		}
14918217Slinton 		if (isvarparam(s) and not isopenarray(s)) {
15018217Slinton 		    rpush(address(s, nil), sizeof(Address));
1519662Slinton 		} else {
15218217Slinton 		    push(Address, address(s, nil));
1539662Slinton 		}
15418217Slinton 	    } else if (isblock(s)) {
15518217Slinton 		push(Symbol, s);
15618217Slinton 	    } else if (isconst(s)) {
15718217Slinton 		eval(constval(s));
15818217Slinton 	    } else {
15918217Slinton 		error("can't evaluate a %s", classname(s));
1609662Slinton 	    }
1619662Slinton 	    break;
1629662Slinton 
1639662Slinton 	case O_LCON:
16418217Slinton 	case O_CCON:
1659662Slinton 	    r0 = p->value.lcon;
1669662Slinton 	    pushsmall(p->nodetype, r0);
1679662Slinton 	    break;
1689662Slinton 
1699662Slinton 	case O_FCON:
1709662Slinton 	    push(double, p->value.fcon);
1719662Slinton 	    break;
1729662Slinton 
1739662Slinton 	case O_SCON:
1749662Slinton 	    len = size(p->nodetype);
1759662Slinton 	    mov(p->value.scon, sp, len);
1769662Slinton 	    sp += len;
1779662Slinton 	    break;
1789662Slinton 
1799662Slinton 	case O_INDEX:
18018217Slinton 	    s = p->value.arg[0]->nodetype;
18118217Slinton 	    p->value.arg[0]->nodetype = t_addr;
18218217Slinton 	    eval(p->value.arg[0]);
18318217Slinton 	    p->value.arg[0]->nodetype = s;
18418217Slinton 	    n = pop(Address);
18518217Slinton 	    eval(p->value.arg[1]);
18618217Slinton 	    evalindex(s, n, popsmall(p->value.arg[1]->nodetype));
1879662Slinton 	    break;
1889662Slinton 
1899662Slinton 	case O_DOT:
1909662Slinton 	    s = p->value.arg[1]->value.sym;
19118217Slinton 	    eval(p->value.arg[0]);
19218217Slinton 	    n = pop(long);
1939662Slinton 	    push(long, n + (s->symvalue.field.offset div 8));
1949662Slinton 	    break;
1959662Slinton 
1969662Slinton 	/*
1979662Slinton 	 * Get the value of the expression addressed by the top of the stack.
1989662Slinton 	 * Push the result back on the stack.
1999662Slinton 	 */
2009662Slinton 
2019662Slinton 	case O_INDIR:
2029662Slinton 	case O_RVAL:
2039662Slinton 	    addr = pop(long);
2049662Slinton 	    if (addr == 0) {
2059662Slinton 		error("reference through nil pointer");
2069662Slinton 	    }
20718217Slinton 	    len = size(p->nodetype);
2089662Slinton 	    rpush(addr, len);
2099662Slinton 	    break;
2109662Slinton 
21111175Slinton 	/*
21218217Slinton 	 * Move the stack pointer so that the top of the stack has
21318217Slinton 	 * something corresponding to the size of the current node type.
21418217Slinton 	 * If this new type is bigger than the subtree (len > 0),
21518217Slinton 	 * then the stack is padded with nulls.  If it's smaller,
21618217Slinton 	 * the stack is just dropped by the appropriate amount.
21711175Slinton 	 */
21811175Slinton 	case O_TYPERENAME:
21918217Slinton 	    len = size(p->nodetype) - size(p->value.arg[0]->nodetype);
22018217Slinton 	    if (len > 0) {
22118217Slinton 		for (n = 0; n < len; n++) {
22218217Slinton 		    *sp++ = '\0';
22318217Slinton 		}
22418217Slinton 	    } else if (len < 0) {
22518217Slinton 		sp += len;
22618217Slinton 	    }
22711175Slinton 	    break;
22811175Slinton 
2299662Slinton 	case O_COMMA:
23018217Slinton 	    eval(p->value.arg[0]);
23118217Slinton 	    if (p->value.arg[1] != nil) {
23218217Slinton 		eval(p->value.arg[1]);
23318217Slinton 	    }
2349662Slinton 	    break;
2359662Slinton 
2369662Slinton 	case O_ITOF:
2379662Slinton 	    push(double, (double) r0);
2389662Slinton 	    break;
2399662Slinton 
2409662Slinton 	case O_ADD:
2419662Slinton 	    push(long, r0+r1);
2429662Slinton 	    break;
2439662Slinton 
2449662Slinton 	case O_ADDF:
2459662Slinton 	    push(double, fr0+fr1);
2469662Slinton 	    break;
2479662Slinton 
2489662Slinton 	case O_SUB:
2499662Slinton 	    push(long, r0-r1);
2509662Slinton 	    break;
2519662Slinton 
2529662Slinton 	case O_SUBF:
2539662Slinton 	    push(double, fr0-fr1);
2549662Slinton 	    break;
2559662Slinton 
2569662Slinton 	case O_NEG:
2579662Slinton 	    push(long, -r0);
2589662Slinton 	    break;
2599662Slinton 
2609662Slinton 	case O_NEGF:
2619662Slinton 	    push(double, -fr0);
2629662Slinton 	    break;
2639662Slinton 
2649662Slinton 	case O_MUL:
2659662Slinton 	    push(long, r0*r1);
2669662Slinton 	    break;
2679662Slinton 
2689662Slinton 	case O_MULF:
2699662Slinton 	    push(double, fr0*fr1);
2709662Slinton 	    break;
2719662Slinton 
2729662Slinton 	case O_DIVF:
2739662Slinton 	    if (fr1 == 0) {
2749662Slinton 		error("error: division by 0");
2759662Slinton 	    }
2769662Slinton 	    push(double, fr0 / fr1);
2779662Slinton 	    break;
2789662Slinton 
2799662Slinton 	case O_DIV:
2809662Slinton 	    if (r1 == 0) {
2819662Slinton 		error("error: div by 0");
2829662Slinton 	    }
2839662Slinton 	    push(long, r0 div r1);
2849662Slinton 	    break;
2859662Slinton 
2869662Slinton 	case O_MOD:
2879662Slinton 	    if (r1 == 0) {
2889662Slinton 		error("error: mod by 0");
2899662Slinton 	    }
2909662Slinton 	    push(long, r0 mod r1);
2919662Slinton 	    break;
2929662Slinton 
2939662Slinton 	case O_LT:
2949662Slinton 	    push(Boolrep, r0 < r1);
2959662Slinton 	    break;
2969662Slinton 
2979662Slinton 	case O_LTF:
2989662Slinton 	    push(Boolrep, fr0 < fr1);
2999662Slinton 	    break;
3009662Slinton 
3019662Slinton 	case O_LE:
3029662Slinton 	    push(Boolrep, r0 <= r1);
3039662Slinton 	    break;
3049662Slinton 
3059662Slinton 	case O_LEF:
3069662Slinton 	    push(Boolrep, fr0 <= fr1);
3079662Slinton 	    break;
3089662Slinton 
3099662Slinton 	case O_GT:
3109662Slinton 	    push(Boolrep, r0 > r1);
3119662Slinton 	    break;
3129662Slinton 
3139662Slinton 	case O_GTF:
3149662Slinton 	    push(Boolrep, fr0 > fr1);
3159662Slinton 	    break;
3169662Slinton 
3179662Slinton 	case O_EQ:
3189662Slinton 	    push(Boolrep, r0 == r1);
3199662Slinton 	    break;
3209662Slinton 
3219662Slinton 	case O_EQF:
3229662Slinton 	    push(Boolrep, fr0 == fr1);
3239662Slinton 	    break;
3249662Slinton 
3259662Slinton 	case O_NE:
3269662Slinton 	    push(Boolrep, r0 != r1);
3279662Slinton 	    break;
3289662Slinton 
3299662Slinton 	case O_NEF:
3309662Slinton 	    push(Boolrep, fr0 != fr1);
3319662Slinton 	    break;
3329662Slinton 
3339662Slinton 	case O_AND:
3349662Slinton 	    push(Boolrep, r0 and r1);
3359662Slinton 	    break;
3369662Slinton 
3379662Slinton 	case O_OR:
3389662Slinton 	    push(Boolrep, r0 or r1);
3399662Slinton 	    break;
3409662Slinton 
3419662Slinton 	case O_ASSIGN:
3429662Slinton 	    assign(p->value.arg[0], p->value.arg[1]);
3439662Slinton 	    break;
3449662Slinton 
3459662Slinton 	case O_CHFILE:
3469662Slinton 	    if (p->value.scon == nil) {
3479662Slinton 		printf("%s\n", cursource);
3489662Slinton 	    } else {
3499662Slinton 		file = opensource(p->value.scon);
3509662Slinton 		if (file == nil) {
3519662Slinton 		    error("can't read \"%s\"", p->value.scon);
3529662Slinton 		} else {
3539662Slinton 		    fclose(file);
3549662Slinton 		    setsource(p->value.scon);
3559662Slinton 		}
3569662Slinton 	    }
3579662Slinton 	    break;
3589662Slinton 
3599662Slinton 	case O_CONT:
36011871Slinton 	    cont(p->value.lcon);
3619662Slinton 	    printnews();
3629662Slinton 	    break;
3639662Slinton 
3649662Slinton 	case O_LIST:
36518217Slinton 	    list(p);
3669662Slinton 	    break;
3679662Slinton 
3689662Slinton 	case O_FUNC:
36918217Slinton 	    func(p->value.arg[0]);
3709662Slinton 	    break;
3719662Slinton 
3729662Slinton 	case O_EXAMINE:
3739662Slinton 	    eval(p->value.examine.beginaddr);
3749662Slinton 	    r0 = pop(long);
3759662Slinton 	    if (p->value.examine.endaddr == nil) {
3769662Slinton 		n = p->value.examine.count;
37711175Slinton 		if (n == 0) {
37811175Slinton 		    printvalue(r0, p->value.examine.mode);
37911175Slinton 		} else if (streq(p->value.examine.mode, "i")) {
3809662Slinton 		    printninst(n, (Address) r0);
3819662Slinton 		} else {
3829662Slinton 		    printndata(n, (Address) r0, p->value.examine.mode);
3839662Slinton 		}
3849662Slinton 	    } else {
3859662Slinton 		eval(p->value.examine.endaddr);
3869662Slinton 		r1 = pop(long);
3879662Slinton 		if (streq(p->value.examine.mode, "i")) {
3889662Slinton 		    printinst((Address)r0, (Address)r1);
3899662Slinton 		} else {
3909662Slinton 		    printdata((Address)r0, (Address)r1, p->value.examine.mode);
3919662Slinton 		}
3929662Slinton 	    }
3939662Slinton 	    break;
3949662Slinton 
3959662Slinton 	case O_PRINT:
3969662Slinton 	    for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) {
3979662Slinton 		eval(n1->value.arg[0]);
3989662Slinton 		printval(n1->value.arg[0]->nodetype);
3999662Slinton 		putchar(' ');
4009662Slinton 	    }
4019662Slinton 	    putchar('\n');
4029662Slinton 	    break;
4039662Slinton 
4049662Slinton 	case O_PSYM:
4059662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
4069662Slinton 		psym(p->value.arg[0]->value.sym);
4079662Slinton 	    } else {
4089662Slinton 		psym(p->value.arg[0]->nodetype);
4099662Slinton 	    }
4109662Slinton 	    break;
4119662Slinton 
4129662Slinton 	case O_QLINE:
4139662Slinton 	    eval(p->value.arg[1]);
4149662Slinton 	    break;
4159662Slinton 
4169662Slinton 	case O_STEP:
4179662Slinton 	    b = inst_tracing;
4189662Slinton 	    inst_tracing = (Boolean) (not p->value.step.source);
4199662Slinton 	    if (p->value.step.skipcalls) {
4209662Slinton 		next();
4219662Slinton 	    } else {
4229662Slinton 		stepc();
4239662Slinton 	    }
4249662Slinton 	    inst_tracing = b;
42514674Slinton 	    useInstLoc = (Boolean) (not p->value.step.source);
4269662Slinton 	    printnews();
4279662Slinton 	    break;
4289662Slinton 
4299662Slinton 	case O_WHATIS:
4309662Slinton 	    if (p->value.arg[0]->op == O_SYM) {
4319662Slinton 		printdecl(p->value.arg[0]->value.sym);
4329662Slinton 	    } else {
4339662Slinton 		printdecl(p->value.arg[0]->nodetype);
4349662Slinton 	    }
4359662Slinton 	    break;
4369662Slinton 
4379662Slinton 	case O_WHERE:
4389662Slinton 	    wherecmd();
4399662Slinton 	    break;
4409662Slinton 
4419662Slinton 	case O_WHEREIS:
44212538Scsvaf 	    if (p->value.arg[0]->op == O_SYM) {
44318217Slinton 		printwhereis(stdout, p->value.arg[0]->value.sym);
44412538Scsvaf 	    } else {
44518217Slinton 		printwhereis(stdout, p->value.arg[0]->nodetype);
44612538Scsvaf 	    }
4479662Slinton 	    break;
4489662Slinton 
4499662Slinton 	case O_WHICH:
45012538Scsvaf 	    if (p->value.arg[0]->op == O_SYM) {
45118217Slinton 		printwhich(stdout, p->value.arg[0]->value.sym);
45212538Scsvaf 	    } else {
45318217Slinton 		printwhich(stdout, p->value.arg[0]->nodetype);
45412538Scsvaf 	    }
4559662Slinton 	    putchar('\n');
4569662Slinton 	    break;
4579662Slinton 
4589662Slinton 	case O_ALIAS:
4599662Slinton 	    n1 = p->value.arg[0];
4609662Slinton 	    n2 = p->value.arg[1];
46118217Slinton 	    if (n2 == nil) {
46218217Slinton 		if (n1 == nil) {
46318217Slinton 		    alias(nil, nil, nil);
46418217Slinton 		} else {
46518217Slinton 		    alias(n1->value.name, nil, nil);
46618217Slinton 		}
46718217Slinton 	    } else if (n2->op == O_NAME) {
46818217Slinton 		str = ident(n2->value.name);
46918217Slinton 		alias(n1->value.name, nil, strdup(str));
4709662Slinton 	    } else {
47118217Slinton 		if (n1->op == O_COMMA) {
47218217Slinton 		    alias(
47318217Slinton 			n1->value.arg[0]->value.name,
47418217Slinton 			(List) n1->value.arg[1],
47518217Slinton 			n2->value.scon
47618217Slinton 		    );
47718217Slinton 		} else {
47818217Slinton 		    alias(n1->value.name, nil, n2->value.scon);
47918217Slinton 		}
4809662Slinton 	    }
4819662Slinton 	    break;
4829662Slinton 
48318217Slinton 	case O_UNALIAS:
48418217Slinton 	    unalias(p->value.arg[0]->value.name);
48518217Slinton 	    break;
48618217Slinton 
48718217Slinton 	case O_CALLPROC:
48818217Slinton 	    callproc(p, false);
48918217Slinton 	    break;
49018217Slinton 
4919662Slinton 	case O_CALL:
49218217Slinton 	    callproc(p, true);
4939662Slinton 	    break;
4949662Slinton 
4959662Slinton 	case O_CATCH:
49618217Slinton 	    if (p->value.lcon == 0) {
49718217Slinton 		printsigscaught(process);
49818217Slinton 	    } else {
49918217Slinton 		psigtrace(process, p->value.lcon, true);
50018217Slinton 	    }
5019662Slinton 	    break;
5029662Slinton 
5039662Slinton 	case O_EDIT:
5049662Slinton 	    edit(p->value.scon);
5059662Slinton 	    break;
5069662Slinton 
50712538Scsvaf         case O_DEBUG:
50812538Scsvaf             debug(p);
50912538Scsvaf 	    break;
51012538Scsvaf 
51116608Ssam 	case O_DOWN:
51216608Ssam 	    checkref(p->value.arg[0]);
51316608Ssam 	    assert(p->value.arg[0]->op == O_LCON);
51416608Ssam 	    down(p->value.arg[0]->value.lcon);
51516608Ssam 	    break;
51616608Ssam 
5179662Slinton 	case O_DUMP:
51818217Slinton 	    if (p->value.arg[0] == nil) {
51918217Slinton 		dumpall();
52018217Slinton 	    } else {
52118217Slinton 		s = p->value.arg[0]->value.sym;
52218217Slinton 		if (s == curfunc) {
52318217Slinton 		    dump(nil);
52418217Slinton 		} else {
52518217Slinton 		    dump(s);
52618217Slinton 		}
52718217Slinton 	    }
5289662Slinton 	    break;
5299662Slinton 
5309662Slinton 	case O_GRIPE:
5319662Slinton 	    gripe();
5329662Slinton 	    break;
5339662Slinton 
5349662Slinton 	case O_HELP:
5359662Slinton 	    help();
5369662Slinton 	    break;
5379662Slinton 
5389662Slinton 	case O_IGNORE:
53918217Slinton 	    if (p->value.lcon == 0) {
54018217Slinton 		printsigsignored(process);
54118217Slinton 	    } else {
54218217Slinton 		psigtrace(process, p->value.lcon, false);
54318217Slinton 	    }
5449662Slinton 	    break;
5459662Slinton 
54616608Ssam 	case O_RETURN:
54716608Ssam 	    if (p->value.arg[0] == nil) {
54816608Ssam 		rtnfunc(nil);
54916608Ssam 	    } else {
55016608Ssam 		assert(p->value.arg[0]->op == O_SYM);
55116608Ssam 		rtnfunc(p->value.arg[0]->value.sym);
55216608Ssam 	    }
55316608Ssam 	    break;
55416608Ssam 
5559662Slinton 	case O_RUN:
5569662Slinton 	    run();
5579662Slinton 	    break;
5589662Slinton 
55918217Slinton 	case O_SET:
56018217Slinton 	    set(p->value.arg[0], p->value.arg[1]);
56118217Slinton 	    break;
56218217Slinton 
56318217Slinton 	case O_SEARCH:
56418217Slinton 	    search(p->value.arg[0]->value.lcon, p->value.arg[1]->value.scon);
56518217Slinton 	    break;
56618217Slinton 
5679662Slinton 	case O_SOURCE:
5689662Slinton 	    setinput(p->value.scon);
5699662Slinton 	    break;
5709662Slinton 
5719662Slinton 	case O_STATUS:
5729662Slinton 	    status();
5739662Slinton 	    break;
5749662Slinton 
5759662Slinton 	case O_TRACE:
5769662Slinton 	case O_TRACEI:
5779662Slinton 	    trace(p);
5789662Slinton 	    break;
5799662Slinton 
5809662Slinton 	case O_STOP:
5819662Slinton 	case O_STOPI:
5829662Slinton 	    stop(p);
5839662Slinton 	    break;
5849662Slinton 
58518217Slinton 	case O_UNSET:
58618217Slinton 	    undefvar(p->value.arg[0]->value.name);
58718217Slinton 	    break;
58818217Slinton 
58916608Ssam 	case O_UP:
59016608Ssam 	    checkref(p->value.arg[0]);
59116608Ssam 	    assert(p->value.arg[0]->op == O_LCON);
59216608Ssam 	    up(p->value.arg[0]->value.lcon);
59316608Ssam 	    break;
59416608Ssam 
5959662Slinton 	case O_ADDEVENT:
5969662Slinton 	    addevent(p->value.event.cond, p->value.event.actions);
5979662Slinton 	    break;
5989662Slinton 
5999662Slinton 	case O_DELETE:
60016608Ssam 	    n1 = p->value.arg[0];
60116608Ssam 	    while (n1->op == O_COMMA) {
60216608Ssam 		n2 = n1->value.arg[0];
60316608Ssam 		assert(n2->op == O_LCON);
60416608Ssam 		if (not delevent((unsigned int) n2->value.lcon)) {
60516608Ssam 		    error("unknown event %ld", n2->value.lcon);
60616608Ssam 		}
60716608Ssam 		n1 = n1->value.arg[1];
60816608Ssam 	    }
60916608Ssam 	    assert(n1->op == O_LCON);
61016608Ssam 	    if (not delevent((unsigned int) n1->value.lcon)) {
61116608Ssam 		error("unknown event %ld", n1->value.lcon);
61216608Ssam 	    }
6139662Slinton 	    break;
6149662Slinton 
6159662Slinton 	case O_ENDX:
6169662Slinton 	    endprogram();
6179662Slinton 	    break;
6189662Slinton 
6199662Slinton 	case O_IF:
6209662Slinton 	    if (cond(p->value.event.cond)) {
6219662Slinton 		evalcmdlist(p->value.event.actions);
6229662Slinton 	    }
6239662Slinton 	    break;
6249662Slinton 
6259662Slinton 	case O_ONCE:
6269662Slinton 	    event_once(p->value.event.cond, p->value.event.actions);
6279662Slinton 	    break;
6289662Slinton 
6299662Slinton 	case O_PRINTCALL:
6309662Slinton 	    printcall(p->value.sym, whatblock(return_addr()));
6319662Slinton 	    break;
6329662Slinton 
6339662Slinton 	case O_PRINTIFCHANGED:
6349662Slinton 	    printifchanged(p->value.arg[0]);
6359662Slinton 	    break;
6369662Slinton 
6379662Slinton 	case O_PRINTRTN:
6389662Slinton 	    printrtn(p->value.sym);
6399662Slinton 	    break;
6409662Slinton 
6419662Slinton 	case O_PRINTSRCPOS:
6429662Slinton 	    getsrcpos();
6439662Slinton 	    if (p->value.arg[0] == nil) {
6449662Slinton 		printsrcpos();
6459662Slinton 		putchar('\n');
6469662Slinton 		printlines(curline, curline);
6479662Slinton 	    } else if (p->value.arg[0]->op == O_QLINE) {
6489662Slinton 		if (p->value.arg[0]->value.arg[1]->value.lcon == 0) {
6499662Slinton 		    printf("tracei: ");
6509662Slinton 		    printinst(pc, pc);
6519662Slinton 		} else {
65218217Slinton 		    if (canReadSource()) {
65318217Slinton 			printf("trace:  ");
65418217Slinton 			printlines(curline, curline);
65518217Slinton 		    }
6569662Slinton 		}
6579662Slinton 	    } else {
6589662Slinton 		printsrcpos();
6599662Slinton 		printf(": ");
6609662Slinton 		eval(p->value.arg[0]);
6619662Slinton 		prtree(stdout, p->value.arg[0]);
6629662Slinton 		printf(" = ");
6639662Slinton 		printval(p->value.arg[0]->nodetype);
6649662Slinton 		putchar('\n');
6659662Slinton 	    }
6669662Slinton 	    break;
6679662Slinton 
6689662Slinton 	case O_PROCRTN:
6699662Slinton 	    procreturn(p->value.sym);
6709662Slinton 	    break;
6719662Slinton 
6729662Slinton 	case O_STOPIFCHANGED:
6739662Slinton 	    stopifchanged(p->value.arg[0]);
6749662Slinton 	    break;
6759662Slinton 
6769662Slinton 	case O_STOPX:
6779662Slinton 	    isstopped = true;
6789662Slinton 	    break;
6799662Slinton 
6809662Slinton 	case O_TRACEON:
6819662Slinton 	    traceon(p->value.trace.inst, p->value.trace.event,
6829662Slinton 		p->value.trace.actions);
6839662Slinton 	    break;
6849662Slinton 
6859662Slinton 	case O_TRACEOFF:
6869662Slinton 	    traceoff(p->value.lcon);
6879662Slinton 	    break;
6889662Slinton 
6899662Slinton 	default:
6909662Slinton 	    panic("eval: bad op %d", p->op);
6919662Slinton     }
69218217Slinton     if (traceeval) {
69318217Slinton 	fprintf(stderr, "end eval %s\n", opname(p->op));
69418217Slinton     }
6959662Slinton }
6969662Slinton 
6979662Slinton /*
6989662Slinton  * Evaluate a list of commands.
6999662Slinton  */
7009662Slinton 
7019662Slinton public evalcmdlist(cl)
7029662Slinton Cmdlist cl;
7039662Slinton {
7049662Slinton     Command c;
7059662Slinton 
7069662Slinton     foreach (Command, c, cl)
7079662Slinton 	evalcmd(c);
7089662Slinton     endfor
7099662Slinton }
7109662Slinton 
7119662Slinton /*
7129662Slinton  * Push "len" bytes onto the expression stack from address "addr"
7139662Slinton  * in the process.  If there isn't room on the stack, print an error message.
7149662Slinton  */
7159662Slinton 
7169662Slinton public rpush(addr, len)
7179662Slinton Address addr;
7189662Slinton int len;
7199662Slinton {
7209662Slinton     if (not canpush(len)) {
7219662Slinton 	error("expression too large to evaluate");
7229662Slinton     } else {
7239662Slinton 	chksp();
7249662Slinton 	dread(sp, addr, len);
7259662Slinton 	sp += len;
7269662Slinton     }
7279662Slinton }
7289662Slinton 
7299662Slinton /*
7309662Slinton  * Check if the stack has n bytes available.
7319662Slinton  */
7329662Slinton 
7339662Slinton public Boolean canpush(n)
7349662Slinton Integer n;
7359662Slinton {
7369662Slinton     return (Boolean) (sp + n < &stack[STACKSIZE]);
7379662Slinton }
7389662Slinton 
7399662Slinton /*
7409662Slinton  * Push a small scalar of the given type onto the stack.
7419662Slinton  */
7429662Slinton 
7439662Slinton public pushsmall(t, v)
7449662Slinton Symbol t;
7459662Slinton long v;
7469662Slinton {
7479662Slinton     register Integer s;
7489662Slinton 
7499662Slinton     s = size(t);
7509662Slinton     switch (s) {
7519662Slinton 	case sizeof(char):
7529662Slinton 	    push(char, v);
7539662Slinton 	    break;
7549662Slinton 
7559662Slinton 	case sizeof(short):
7569662Slinton 	    push(short, v);
7579662Slinton 	    break;
7589662Slinton 
7599662Slinton 	case sizeof(long):
7609662Slinton 	    push(long, v);
7619662Slinton 	    break;
7629662Slinton 
7639662Slinton 	default:
7649662Slinton 	    panic("bad size %d in popsmall", s);
7659662Slinton     }
7669662Slinton }
7679662Slinton 
7689662Slinton /*
7699662Slinton  * Pop an item of the given type which is assumed to be no larger
7709662Slinton  * than a long and return it expanded into a long.
7719662Slinton  */
7729662Slinton 
7739662Slinton public long popsmall(t)
7749662Slinton Symbol t;
7759662Slinton {
77618217Slinton     register integer n;
7779662Slinton     long r;
7789662Slinton 
77918217Slinton     n = size(t);
78018217Slinton     if (n == sizeof(char)) {
78118217Slinton 	if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
78218217Slinton 	    r = (long) pop(unsigned char);
78318217Slinton 	} else {
7849662Slinton 	    r = (long) pop(char);
78518217Slinton 	}
78618217Slinton     } else if (n == sizeof(short)) {
78718217Slinton 	if (t->class == RANGE and t->symvalue.rangev.lower >= 0) {
78818217Slinton 	    r = (long) pop(unsigned short);
78918217Slinton 	} else {
7909662Slinton 	    r = (long) pop(short);
79118217Slinton 	}
79218217Slinton     } else if (n == sizeof(long)) {
79318217Slinton 	r = pop(long);
79418217Slinton     } else {
79518217Slinton 	error("[internal error: size %d in popsmall]", n);
7969662Slinton     }
7979662Slinton     return r;
7989662Slinton }
7999662Slinton 
8009662Slinton /*
8019662Slinton  * Evaluate a conditional expression.
8029662Slinton  */
8039662Slinton 
8049662Slinton public Boolean cond(p)
8059662Slinton Node p;
8069662Slinton {
8079662Slinton     register Boolean b;
8089662Slinton 
8099662Slinton     if (p == nil) {
8109662Slinton 	b = true;
8119662Slinton     } else {
8129662Slinton 	eval(p);
81313846Slinton 	b = (Boolean) pop(Boolrep);
8149662Slinton     }
8159662Slinton     return b;
8169662Slinton }
8179662Slinton 
8189662Slinton /*
8199662Slinton  * Return the address corresponding to a given tree.
8209662Slinton  */
8219662Slinton 
8229662Slinton public Address lval(p)
8239662Slinton Node p;
8249662Slinton {
8259662Slinton     if (p->op == O_RVAL) {
8269662Slinton 	eval(p->value.arg[0]);
8279662Slinton     } else {
8289662Slinton 	eval(p);
8299662Slinton     }
8309662Slinton     return (Address) (pop(long));
8319662Slinton }
8329662Slinton 
8339662Slinton /*
8349662Slinton  * Process a trace command, translating into the appropriate events
8359662Slinton  * and associated actions.
8369662Slinton  */
8379662Slinton 
8389662Slinton public trace(p)
8399662Slinton Node p;
8409662Slinton {
8419662Slinton     Node exp, place, cond;
8429662Slinton     Node left;
8439662Slinton 
8449662Slinton     exp = p->value.arg[0];
8459662Slinton     place = p->value.arg[1];
8469662Slinton     cond = p->value.arg[2];
8479662Slinton     if (exp == nil) {
8489662Slinton 	traceall(p->op, place, cond);
84911771Slinton     } else if (exp->op == O_QLINE or exp->op == O_LCON) {
8509662Slinton 	traceinst(p->op, exp, cond);
8519662Slinton     } else if (place != nil and place->op == O_QLINE) {
8529662Slinton 	traceat(p->op, exp, place, cond);
8539662Slinton     } else {
8549861Slinton 	left = exp;
8559861Slinton 	if (left->op == O_RVAL or left->op == O_CALL) {
8569861Slinton 	    left = left->value.arg[0];
8579861Slinton 	}
8589662Slinton 	if (left->op == O_SYM and isblock(left->value.sym)) {
8599662Slinton 	    traceproc(p->op, left->value.sym, place, cond);
8609662Slinton 	} else {
8619662Slinton 	    tracedata(p->op, exp, place, cond);
8629662Slinton 	}
8639662Slinton     }
8649662Slinton }
8659662Slinton 
8669662Slinton /*
8679662Slinton  * Set a breakpoint that will turn on tracing.
8689662Slinton  */
8699662Slinton 
8709662Slinton private traceall(op, place, cond)
8719662Slinton Operator op;
8729662Slinton Node place;
8739662Slinton Node cond;
8749662Slinton {
8759662Slinton     Symbol s;
8769662Slinton     Node event;
8779662Slinton     Command action;
8789662Slinton 
8799662Slinton     if (place == nil) {
8809662Slinton 	s = program;
8819662Slinton     } else {
8829662Slinton 	s = place->value.sym;
8839662Slinton     }
8849662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
8859662Slinton     action = build(O_PRINTSRCPOS,
8869662Slinton 	build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0)));
8879662Slinton     if (cond != nil) {
8889662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
8899662Slinton     }
8909662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
8919662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
89211871Slinton     if (isstdin()) {
89311871Slinton 	printevent(action->value.trace.event);
89411871Slinton     }
8959662Slinton }
8969662Slinton 
8979662Slinton /*
8989662Slinton  * Set up the appropriate breakpoint for tracing an instruction.
8999662Slinton  */
9009662Slinton 
9019662Slinton private traceinst(op, exp, cond)
9029662Slinton Operator op;
9039662Slinton Node exp;
9049662Slinton Node cond;
9059662Slinton {
90611771Slinton     Node event, wh;
9079662Slinton     Command action;
90811871Slinton     Event e;
9099662Slinton 
91011771Slinton     if (exp->op == O_LCON) {
91118217Slinton 	wh = build(O_QLINE, build(O_SCON, strdup(cursource)), exp);
91211771Slinton     } else {
91311771Slinton 	wh = exp;
91411771Slinton     }
9159662Slinton     if (op == O_TRACEI) {
91611771Slinton 	event = build(O_EQ, build(O_SYM, pcsym), wh);
9179662Slinton     } else {
91811771Slinton 	event = build(O_EQ, build(O_SYM, linesym), wh);
9199662Slinton     }
92011771Slinton     action = build(O_PRINTSRCPOS, wh);
9219662Slinton     if (cond) {
9229662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
9239662Slinton     }
92411871Slinton     e = addevent(event, buildcmdlist(action));
92511871Slinton     if (isstdin()) {
92611871Slinton 	printevent(e);
92711871Slinton     }
9289662Slinton }
9299662Slinton 
9309662Slinton /*
9319662Slinton  * Set a breakpoint to print an expression at a given line or address.
9329662Slinton  */
9339662Slinton 
9349662Slinton private traceat(op, exp, place, cond)
9359662Slinton Operator op;
9369662Slinton Node exp;
9379662Slinton Node place;
9389662Slinton Node cond;
9399662Slinton {
9409662Slinton     Node event;
9419662Slinton     Command action;
94211871Slinton     Event e;
9439662Slinton 
9449662Slinton     if (op == O_TRACEI) {
9459662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
9469662Slinton     } else {
9479662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
9489662Slinton     }
9499662Slinton     action = build(O_PRINTSRCPOS, exp);
9509662Slinton     if (cond != nil) {
9519662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
9529662Slinton     }
95311871Slinton     e = addevent(event, buildcmdlist(action));
95411871Slinton     if (isstdin()) {
95511871Slinton 	printevent(e);
95611871Slinton     }
9579662Slinton }
9589662Slinton 
9599662Slinton /*
9609662Slinton  * Construct event for tracing a procedure.
9619662Slinton  *
9629662Slinton  * What we want here is
9639662Slinton  *
9649662Slinton  * 	when $proc = p do
9659662Slinton  *	    if <condition> then
9669662Slinton  *	        printcall;
9679662Slinton  *	        once $pc = $retaddr do
9689662Slinton  *	            printrtn;
9699662Slinton  *	        end;
9709662Slinton  *	    end if;
9719662Slinton  *	end;
9729662Slinton  *
9739662Slinton  * Note that "once" is like "when" except that the event
9749662Slinton  * deletes itself as part of its associated action.
9759662Slinton  */
9769662Slinton 
9779662Slinton private traceproc(op, p, place, cond)
9789662Slinton Operator op;
9799662Slinton Symbol p;
9809662Slinton Node place;
9819662Slinton Node cond;
9829662Slinton {
9839662Slinton     Node event;
9849662Slinton     Command action;
9859662Slinton     Cmdlist actionlist;
98611871Slinton     Event e;
9879662Slinton 
9889662Slinton     action = build(O_PRINTCALL, p);
9899662Slinton     actionlist = list_alloc();
9909662Slinton     cmdlist_append(action, actionlist);
9919662Slinton     event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym));
9929662Slinton     action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p)));
9939662Slinton     cmdlist_append(action, actionlist);
9949662Slinton     if (cond != nil) {
9959662Slinton 	actionlist = buildcmdlist(build(O_IF, cond, actionlist));
9969662Slinton     }
9979662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
99811871Slinton     e = addevent(event, actionlist);
99911871Slinton     if (isstdin()) {
100011871Slinton 	printevent(e);
100111871Slinton     }
10029662Slinton }
10039662Slinton 
10049662Slinton /*
10059662Slinton  * Set up breakpoint for tracing data.
10069662Slinton  */
10079662Slinton 
10089662Slinton private tracedata(op, exp, place, cond)
10099662Slinton Operator op;
10109662Slinton Node exp;
10119662Slinton Node place;
10129662Slinton Node cond;
10139662Slinton {
10149662Slinton     Symbol p;
10159662Slinton     Node event;
10169662Slinton     Command action;
10179662Slinton 
10189662Slinton     p = (place == nil) ? tcontainer(exp) : place->value.sym;
10199662Slinton     if (p == nil) {
10209662Slinton 	p = program;
10219662Slinton     }
10229662Slinton     action = build(O_PRINTIFCHANGED, exp);
10239662Slinton     if (cond != nil) {
10249662Slinton 	action = build(O_IF, cond, buildcmdlist(action));
10259662Slinton     }
10269662Slinton     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
10279662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
10289662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
102911871Slinton     if (isstdin()) {
103011871Slinton 	printevent(action->value.trace.event);
103111871Slinton     }
10329662Slinton }
10339662Slinton 
10349662Slinton /*
10359662Slinton  * Setting and unsetting of stops.
10369662Slinton  */
10379662Slinton 
10389662Slinton public stop(p)
10399662Slinton Node p;
10409662Slinton {
104113846Slinton     Node exp, place, cond, t;
10429662Slinton     Symbol s;
10439662Slinton     Command action;
104411871Slinton     Event e;
10459662Slinton 
10469662Slinton     exp = p->value.arg[0];
10479662Slinton     place = p->value.arg[1];
10489662Slinton     cond = p->value.arg[2];
10499662Slinton     if (exp != nil) {
10509662Slinton 	stopvar(p->op, exp, place, cond);
105113846Slinton     } else {
105213846Slinton 	action = build(O_STOPX);
105313846Slinton 	if (cond != nil) {
105413846Slinton 	    action = build(O_IF, cond, buildcmdlist(action));
105511871Slinton 	}
105616608Ssam 	if (place == nil or place->op == O_SYM) {
105716608Ssam 	    if (place == nil) {
105816608Ssam 		s = program;
105916608Ssam 	    } else {
106016608Ssam 		s = place->value.sym;
106116608Ssam 	    }
106213846Slinton 	    t = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
106313846Slinton 	    if (cond != nil) {
106413846Slinton 		action = build(O_TRACEON, (p->op == O_STOPI),
106513846Slinton 		    buildcmdlist(action));
106613846Slinton 		e = addevent(t, buildcmdlist(action));
106713846Slinton 		action->value.trace.event = e;
106813846Slinton 	    } else {
106913846Slinton 		e = addevent(t, buildcmdlist(action));
107013846Slinton 	    }
107113846Slinton 	    if (isstdin()) {
107213846Slinton 		printevent(e);
107313846Slinton 	    }
107413846Slinton 	} else {
107513846Slinton 	    stopinst(p->op, place, cond, action);
107613846Slinton 	}
10779662Slinton     }
10789662Slinton }
10799662Slinton 
108013846Slinton private stopinst(op, place, cond, action)
10819662Slinton Operator op;
10829662Slinton Node place;
10839662Slinton Node cond;
108413846Slinton Command action;
10859662Slinton {
10869662Slinton     Node event;
108711871Slinton     Event e;
10889662Slinton 
10899662Slinton     if (op == O_STOP) {
10909662Slinton 	event = build(O_EQ, build(O_SYM, linesym), place);
10919662Slinton     } else {
10929662Slinton 	event = build(O_EQ, build(O_SYM, pcsym), place);
10939662Slinton     }
109413846Slinton     e = addevent(event, buildcmdlist(action));
109511871Slinton     if (isstdin()) {
109611871Slinton 	printevent(e);
109711871Slinton     }
10989662Slinton }
10999662Slinton 
11009662Slinton /*
11019662Slinton  * Implement stopping on assignment to a variable by adding it to
11029662Slinton  * the variable list.
11039662Slinton  */
11049662Slinton 
11059662Slinton private stopvar(op, exp, place, cond)
11069662Slinton Operator op;
11079662Slinton Node exp;
11089662Slinton Node place;
11099662Slinton Node cond;
11109662Slinton {
11119662Slinton     Symbol p;
11129662Slinton     Node event;
11139662Slinton     Command action;
11149662Slinton 
111514445Slinton     if (place == nil) {
111614445Slinton 	if (exp->op == O_LCON) {
111714445Slinton 	    p = program;
111814445Slinton 	} else {
111914445Slinton 	    p = tcontainer(exp);
112014445Slinton 	    if (p == nil) {
112114445Slinton 		p = program;
112214445Slinton 	    }
112314445Slinton 	}
112414445Slinton     } else {
112514445Slinton 	p = place->value.sym;
11269662Slinton     }
112714445Slinton     action = build(O_STOPIFCHANGED, exp);
112814445Slinton     if (cond != nil) {
112914445Slinton 	action = build(O_IF, cond, buildcmdlist(action));
113014445Slinton     }
11319662Slinton     action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action));
11329662Slinton     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
11339662Slinton     action->value.trace.event = addevent(event, buildcmdlist(action));
113411871Slinton     if (isstdin()) {
113511871Slinton 	printevent(action->value.trace.event);
113611871Slinton     }
11379662Slinton }
11389662Slinton 
11399662Slinton /*
11409662Slinton  * Assign the value of an expression to a variable (or term).
11419662Slinton  */
11429662Slinton 
11439662Slinton public assign(var, exp)
11449662Slinton Node var;
11459662Slinton Node exp;
11469662Slinton {
11479662Slinton     Address addr;
114816608Ssam     integer varsize, expsize;
11499662Slinton     char cvalue;
11509662Slinton     short svalue;
11519662Slinton     long lvalue;
115216608Ssam     float fvalue;
11539662Slinton 
115418217Slinton     if (var->op == O_SYM and regnum(var->value.sym) != -1) {
115518217Slinton 	eval(exp);
115618217Slinton 	setreg(regnum(var->value.sym), pop(Address));
115716608Ssam     } else {
115818217Slinton 	addr = lval(var);
115918217Slinton 	varsize = size(var->nodetype);
116018217Slinton 	expsize = size(exp->nodetype);
116118217Slinton 	eval(exp);
116218217Slinton 	if (varsize == sizeof(float) and expsize == sizeof(double)) {
116318217Slinton 	    fvalue = (float) pop(double);
116418217Slinton 	    dwrite(&fvalue, addr, sizeof(fvalue));
116518217Slinton 	} else {
116618217Slinton 	    if (varsize < sizeof(long)) {
116718217Slinton 		lvalue = 0;
116818217Slinton 		popn(expsize, &lvalue);
116918217Slinton 		if (varsize == sizeof(char)) {
117016608Ssam 		    cvalue = lvalue;
117116608Ssam 		    dwrite(&cvalue, addr, sizeof(cvalue));
117218217Slinton 		} else if (varsize == sizeof(short)) {
117316608Ssam 		    svalue = lvalue;
117416608Ssam 		    dwrite(&svalue, addr, sizeof(svalue));
117518217Slinton 		} else {
117618217Slinton 		    error("[internal error: bad size %d in assign]", varsize);
117718217Slinton 		}
117818217Slinton 	    } else {
117918217Slinton 		if (expsize <= varsize) {
118018217Slinton 		    sp -= expsize;
118118217Slinton 		    dwrite(sp, addr, expsize);
118218217Slinton 		} else {
118318217Slinton 		    sp -= expsize;
118418217Slinton 		    dwrite(sp, addr, varsize);
118518217Slinton 		}
118618217Slinton 	    }
118718217Slinton 	}
118818217Slinton     }
118918217Slinton }
11909662Slinton 
119118217Slinton /*
119218217Slinton  * Set a debugger variable.
119318217Slinton  */
119418217Slinton 
119518217Slinton private set (var, exp)
119618217Slinton Node var, exp;
119718217Slinton {
119818217Slinton     Symbol t;
119918217Slinton 
120018217Slinton     if (var == nil) {
120118217Slinton 	defvar(nil, nil);
120218217Slinton     } else if (exp == nil) {
120318217Slinton 	defvar(var->value.name, nil);
120418217Slinton     } else if (var->value.name == identname("$frame", true)) {
120518217Slinton 	t = exp->nodetype;
120618217Slinton 	if (not compatible(t, t_int) and not compatible(t, t_addr)) {
120718217Slinton 	    error("$frame must be an address");
120818217Slinton 	}
120918217Slinton 	eval(exp);
121018217Slinton 	getnewregs(pop(Address));
121118217Slinton     } else {
121218217Slinton 	defvar(var->value.name, unrval(exp));
121318217Slinton     }
121418217Slinton }
121518217Slinton 
121618217Slinton /*
121718217Slinton  * Execute a list command.
121818217Slinton  */
121918217Slinton 
122018217Slinton private list (p)
122118217Slinton Node p;
122218217Slinton {
122318217Slinton     Symbol f;
122418217Slinton     Address addr;
122518217Slinton     Lineno line, l1, l2;
122618217Slinton 
122718217Slinton     if (p->value.arg[0]->op == O_SYM) {
122818217Slinton 	f = p->value.arg[0]->value.sym;
122918217Slinton 	addr = firstline(f);
123018217Slinton 	if (addr == NOADDR) {
123118217Slinton 	    error("no source lines for \"%s\"", symname(f));
123218217Slinton 	}
123318217Slinton 	setsource(srcfilename(addr));
123418217Slinton 	line = srcline(addr);
123518217Slinton 	getsrcwindow(line, &l1, &l2);
123618217Slinton     } else {
123718217Slinton 	eval(p->value.arg[0]);
123818217Slinton 	l1 = (Lineno) (pop(long));
123918217Slinton 	eval(p->value.arg[1]);
124018217Slinton 	l2 = (Lineno) (pop(long));
124118217Slinton     }
124218217Slinton     printlines(l1, l2);
124318217Slinton }
124418217Slinton 
124518217Slinton /*
124618217Slinton  * Execute a func command.
124718217Slinton  */
124818217Slinton 
124918217Slinton private func (p)
125018217Slinton Node p;
125118217Slinton {
125218217Slinton     Symbol s, f;
125318217Slinton     Address addr;
125418217Slinton 
125518217Slinton     if (p == nil) {
125618217Slinton 	printname(stdout, curfunc);
125718217Slinton 	putchar('\n');
125818217Slinton     } else {
125918217Slinton 	s = p->value.sym;
126018217Slinton 	if (isroutine(s)) {
126118217Slinton 	    setcurfunc(s);
126216608Ssam 	} else {
126318217Slinton 	    find(f, s->name) where isroutine(f) endfind(f);
126418217Slinton 	    if (f == nil) {
126518217Slinton 		error("%s is not a procedure or function", symname(s));
126616608Ssam 	    }
126718217Slinton 	    setcurfunc(f);
12689662Slinton 	}
126918217Slinton 	addr = codeloc(curfunc);
127018217Slinton 	if (addr != NOADDR) {
127118217Slinton 	    setsource(srcfilename(addr));
127218217Slinton 	    cursrcline = srcline(addr);
127318217Slinton 	}
12749662Slinton     }
12759662Slinton }
12769662Slinton 
12779662Slinton /*
127818217Slinton  * Send a message to the current support person.
12799662Slinton  */
12809662Slinton 
12819662Slinton public gripe()
12829662Slinton {
12839662Slinton     typedef Operation();
12849662Slinton     Operation *old;
128514445Slinton     int pid, status;
128616608Ssam     extern int versionNumber;
128716608Ssam     char subject[100];
12889662Slinton 
12899662Slinton     puts("Type control-D to end your message.  Be sure to include");
12909662Slinton     puts("your name and the name of the file you are debugging.");
12919662Slinton     putchar('\n');
12929662Slinton     old = signal(SIGINT, SIG_DFL);
129318217Slinton     sprintf(subject, "dbx (version 3.%d) gripe", versionNumber);
129418217Slinton     pid = back("Mail", stdin, stdout, "-s", subject, MAINTAINER, nil);
129514445Slinton     signal(SIGINT, SIG_IGN);
129614445Slinton     pwait(pid, &status);
12979662Slinton     signal(SIGINT, old);
129814445Slinton     if (status == 0) {
129914445Slinton 	puts("Thank you.");
130014445Slinton     } else {
130114445Slinton 	puts("\nMail not sent.");
130214445Slinton     }
13039662Slinton }
13049662Slinton 
13059662Slinton /*
13069662Slinton  * Give the user some help.
13079662Slinton  */
13089662Slinton 
13099662Slinton public help()
13109662Slinton {
13119662Slinton     puts("run                    - begin execution of the program");
131216608Ssam     puts("print <exp>            - print the value of the expression");
131316608Ssam     puts("where                  - print currently active procedures");
131416608Ssam     puts("stop at <line>         - suspend execution at the line");
131516608Ssam     puts("stop in <proc>         - suspend execution when <proc> is called");
13169662Slinton     puts("cont                   - continue execution");
13179662Slinton     puts("step                   - single step one line");
13189662Slinton     puts("next                   - step to next line (skip over calls)");
13199662Slinton     puts("trace <line#>          - trace execution of the line");
13209662Slinton     puts("trace <proc>           - trace calls to the procedure");
13219662Slinton     puts("trace <var>            - trace changes to the variable");
13229662Slinton     puts("trace <exp> at <line#> - print <exp> when <line> is reached");
13239662Slinton     puts("status                 - print trace/stop's in effect");
13249662Slinton     puts("delete <number>        - remove trace or stop of given number");
132516608Ssam     puts("call <proc>            - call a procedure in program");
13269662Slinton     puts("whatis <name>          - print the declaration of the name");
13279662Slinton     puts("list <line>, <line>    - list source lines");
13289662Slinton     puts("gripe                  - send mail to the person in charge of dbx");
13299662Slinton     puts("quit                   - exit dbx");
13309662Slinton }
13319662Slinton 
13329662Slinton /*
13339662Slinton  * Divert output to the given file name.
13349662Slinton  * Cannot redirect to an existing file.
13359662Slinton  */
13369662Slinton 
13379662Slinton private int so_fd;
13389662Slinton private Boolean notstdout;
13399662Slinton 
13409662Slinton public setout(filename)
13419662Slinton String filename;
13429662Slinton {
13439662Slinton     File f;
13449662Slinton 
13459662Slinton     f = fopen(filename, "r");
13469662Slinton     if (f != nil) {
13479662Slinton 	fclose(f);
13489662Slinton 	error("%s: file already exists", filename);
13499662Slinton     } else {
13509662Slinton 	so_fd = dup(1);
13519662Slinton 	close(1);
13529662Slinton 	if (creat(filename, 0666) == nil) {
13539662Slinton 	    unsetout();
13549662Slinton 	    error("can't create %s", filename);
13559662Slinton 	}
13569662Slinton 	notstdout = true;
13579662Slinton     }
13589662Slinton }
13599662Slinton 
13609662Slinton /*
13619662Slinton  * Revert output to standard output.
13629662Slinton  */
13639662Slinton 
13649662Slinton public unsetout()
13659662Slinton {
13669662Slinton     fflush(stdout);
13679662Slinton     close(1);
13689662Slinton     if (dup(so_fd) != 1) {
13699662Slinton 	panic("standard out dup failed");
13709662Slinton     }
13719662Slinton     close(so_fd);
13729662Slinton     notstdout = false;
13739662Slinton }
13749662Slinton 
13759662Slinton /*
13769662Slinton  * Determine is standard output is currently being redirected
13779662Slinton  * to a file (as far as we know).
13789662Slinton  */
13799662Slinton 
13809662Slinton public Boolean isredirected()
13819662Slinton {
13829662Slinton     return notstdout;
13839662Slinton }
1384