xref: /csrg-svn/old/dbx/eval.c (revision 12538)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)eval.c 1.7 05/18/83";
4 
5 /*
6  * Tree evaluation.
7  */
8 
9 #include "defs.h"
10 #include "tree.h"
11 #include "operators.h"
12 #include "eval.h"
13 #include "events.h"
14 #include "symbols.h"
15 #include "scanner.h"
16 #include "source.h"
17 #include "object.h"
18 #include "mappings.h"
19 #include "process.h"
20 #include "machine.h"
21 #include <signal.h>
22 
23 #ifndef public
24 
25 #include "machine.h"
26 
27 #define STACKSIZE 20000
28 
29 typedef Char Stack;
30 
31 #define push(type, value) { \
32     ((type *) (sp += sizeof(type)))[-1] = (value); \
33 }
34 
35 #define pop(type) ( \
36     (*((type *) (sp -= sizeof(type)))) \
37 )
38 
39 #define alignstack() { \
40     sp = (Stack *) (( ((int) sp) + sizeof(int) - 1)&~(sizeof(int) - 1)); \
41 }
42 
43 #endif
44 
45 public Stack stack[STACKSIZE];
46 public Stack *sp = &stack[0];
47 
48 #define chksp() \
49 { \
50     if (sp < &stack[0]) { \
51 	panic("stack underflow"); \
52     } \
53 }
54 
55 #define poparg(n, r, fr) { \
56     eval(p->value.arg[n]); \
57     if (isreal(p->op)) { \
58 	fr = pop(double); \
59     } else if (isint(p->op)) { \
60 	r = popsmall(p->value.arg[n]->nodetype); \
61     } \
62 }
63 
64 #define Boolrep char	/* underlying representation type for booleans */
65 
66 /*
67  * Evaluate a parse tree leaving the value on the top of the stack.
68  */
69 
70 public eval(p)
71 register Node p;
72 {
73     long r0, r1;
74     double fr0, fr1;
75     Address addr;
76     long i, n;
77     int len;
78     Symbol s, f;
79     Node n1, n2;
80     Boolean b;
81     File file;
82 
83     checkref(p);
84     if(debug_flag[2]) {
85                      fprintf(stderr," evaluating %s \n",showoperator(p->op));
86     }
87     switch (degree(p->op)) {
88 	case BINARY:
89 	    poparg(1, r1, fr1);
90 	    poparg(0, r0, fr0);
91 	    break;
92 
93 	case UNARY:
94 	    poparg(0, r0, fr0);
95 	    break;
96 
97 	default:
98 	    /* do nothing */;
99     }
100     switch (p->op) {
101 	case O_SYM:
102 	    s = p->value.sym;
103 	    if (s == retaddrsym) {
104 		push(long, return_addr());
105 	    } else {
106 		if (isvariable(s)) {
107 		    if (s != program and not isactive(container(s))) {
108 			error("\"%s\" is not active", symname(s));
109 		    }
110 		    push(long, address(s, nil));
111 		} else if (isblock(s)) {
112 		    push(Symbol, s);
113 		} else {
114 		    error("can't evaluate a %s", classname(s));
115 		}
116 	    }
117 	    break;
118 
119 	case O_LCON:
120 	    r0 = p->value.lcon;
121 	    pushsmall(p->nodetype, r0);
122 	    break;
123 
124 	case O_FCON:
125 	    push(double, p->value.fcon);
126 	    break;
127 
128 	case O_SCON:
129 	    len = size(p->nodetype);
130 	    mov(p->value.scon, sp, len);
131 	    sp += len;
132 	    break;
133 
134 	case O_INDEX:
135 	    n = pop(long);
136 	    i = evalindex(p->value.arg[0]->nodetype,
137 		popsmall(p->value.arg[1]->nodetype));
138 	    push(long, n + i*size(p->nodetype));
139 	    break;
140 
141 	case O_DOT:
142 	    s = p->value.arg[1]->value.sym;
143 	    n = lval(p->value.arg[0]);
144 	    push(long, n + (s->symvalue.field.offset div 8));
145 	    break;
146 
147 	/*
148 	 * Get the value of the expression addressed by the top of the stack.
149 	 * Push the result back on the stack.
150 	 */
151 
152 	case O_INDIR:
153 	case O_RVAL:
154 	    addr = pop(long);
155 	    if (addr == 0) {
156 		error("reference through nil pointer");
157 	    }
158 	    if (p->op == O_INDIR) {
159 		len = sizeof(long);
160 	    } else {
161 		len = size(p->nodetype);
162 	    }
163 	    rpush(addr, len);
164 	addr = pop(long);
165         push(long, addr);
166 	    break;
167 
168 	/*
169 	 * Effectively, we want to pop n bytes off for the evaluated subtree
170 	 * and push len bytes on for the new type of the same tree.
171 	 */
172 	case O_TYPERENAME:
173 	    n = size(p->value.arg[0]->nodetype);
174 	    len = size(p->nodetype);
175 	    sp = sp - n + len;
176 	    break;
177 
178 	case O_COMMA:
179 	    break;
180 
181 	case O_ITOF:
182 	    push(double, (double) r0);
183 	    break;
184 
185 	case O_ADD:
186 	    push(long, r0+r1);
187 	    break;
188 
189 	case O_ADDF:
190 	    push(double, fr0+fr1);
191 	    break;
192 
193 	case O_SUB:
194 	    push(long, r0-r1);
195 	    break;
196 
197 	case O_SUBF:
198 	    push(double, fr0-fr1);
199 	    break;
200 
201 	case O_NEG:
202 	    push(long, -r0);
203 	    break;
204 
205 	case O_NEGF:
206 	    push(double, -fr0);
207 	    break;
208 
209 	case O_MUL:
210 	    push(long, r0*r1);
211 	    break;
212 
213 	case O_MULF:
214 	    push(double, fr0*fr1);
215 	    break;
216 
217 	case O_DIVF:
218 	    if (fr1 == 0) {
219 		error("error: division by 0");
220 	    }
221 	    push(double, fr0 / fr1);
222 	    break;
223 
224 	case O_DIV:
225 	    if (r1 == 0) {
226 		error("error: div by 0");
227 	    }
228 	    push(long, r0 div r1);
229 	    break;
230 
231 	case O_MOD:
232 	    if (r1 == 0) {
233 		error("error: mod by 0");
234 	    }
235 	    push(long, r0 mod r1);
236 	    break;
237 
238 	case O_LT:
239 	    push(Boolrep, r0 < r1);
240 	    break;
241 
242 	case O_LTF:
243 	    push(Boolrep, fr0 < fr1);
244 	    break;
245 
246 	case O_LE:
247 	    push(Boolrep, r0 <= r1);
248 	    break;
249 
250 	case O_LEF:
251 	    push(Boolrep, fr0 <= fr1);
252 	    break;
253 
254 	case O_GT:
255 	    push(Boolrep, r0 > r1);
256 	    break;
257 
258 	case O_GTF:
259 	    push(Boolrep, fr0 > fr1);
260 	    break;
261 
262 	case O_EQ:
263 	    push(Boolrep, r0 == r1);
264 	    break;
265 
266 	case O_EQF:
267 	    push(Boolrep, fr0 == fr1);
268 	    break;
269 
270 	case O_NE:
271 	    push(Boolrep, r0 != r1);
272 	    break;
273 
274 	case O_NEF:
275 	    push(Boolrep, fr0 != fr1);
276 	    break;
277 
278 	case O_AND:
279 	    push(Boolrep, r0 and r1);
280 	    break;
281 
282 	case O_OR:
283 	    push(Boolrep, r0 or r1);
284 	    break;
285 
286 	case O_ASSIGN:
287 	    assign(p->value.arg[0], p->value.arg[1]);
288 	    break;
289 
290 	case O_CHFILE:
291 	    if (p->value.scon == nil) {
292 		printf("%s\n", cursource);
293 	    } else {
294 		file = opensource(p->value.scon);
295 		if (file == nil) {
296 		    error("can't read \"%s\"", p->value.scon);
297 		} else {
298 		    fclose(file);
299 		    setsource(p->value.scon);
300 		}
301 	    }
302 	    break;
303 
304 	case O_CONT:
305 	    cont(p->value.lcon);
306 	    printnews();
307 	    break;
308 
309 	case O_LIST:
310 	    if (p->value.arg[0]->op == O_SYM) {
311 		f = p->value.arg[0]->value.sym;
312 		addr = firstline(f);
313 		if (addr == NOADDR) {
314 		    error("no source lines for \"%s\"", symname(f));
315 		}
316 		setsource(srcfilename(addr));
317 		r0 = srcline(addr) - 5;
318 		r1 = r0 + 10;
319 		if (r0 < 1) {
320 		    r0 = 1;
321 		}
322 	    } else {
323 		eval(p->value.arg[0]);
324 		r0 = pop(long);
325 		eval(p->value.arg[1]);
326 		r1 = pop(long);
327 	    }
328 	    printlines((Lineno) r0, (Lineno) r1);
329 	    break;
330 
331 	case O_FUNC:
332 	    if (p->value.arg[0] == nil) {
333 		printname(stdout, curfunc);
334 		putchar('\n');
335 	    } else {
336 		s = p->value.arg[0]->value.sym;
337 		find(f, s->name) where
338 		    f->class == FUNC or f->class == PROC
339 		endfind(f);
340 		if (f == nil) {
341 		    error("%s is not a procedure or function", symname(s));
342 		}
343 		curfunc = f;
344 		addr = codeloc(curfunc);
345 		if (addr != NOADDR) {
346 		    setsource(srcfilename(addr));
347 		    cursrcline = srcline(addr) - 5;
348 		    if (cursrcline < 1) {
349 			cursrcline = 1;
350 		    }
351 		}
352 	    }
353 	    break;
354 
355 	case O_EXAMINE:
356 	    eval(p->value.examine.beginaddr);
357 	    r0 = pop(long);
358 	    if (p->value.examine.endaddr == nil) {
359 		n = p->value.examine.count;
360 		if (n == 0) {
361 		    printvalue(r0, p->value.examine.mode);
362 		} else if (streq(p->value.examine.mode, "i")) {
363 		    printninst(n, (Address) r0);
364 		} else {
365 		    printndata(n, (Address) r0, p->value.examine.mode);
366 		}
367 	    } else {
368 		eval(p->value.examine.endaddr);
369 		r1 = pop(long);
370 		if (streq(p->value.examine.mode, "i")) {
371 		    printinst((Address)r0, (Address)r1);
372 		} else {
373 		    printdata((Address)r0, (Address)r1, p->value.examine.mode);
374 		}
375 	    }
376 	    break;
377 
378 	case O_PRINT:
379 	    for (n1 = p->value.arg[0]; n1 != nil; n1 = n1->value.arg[1]) {
380 		eval(n1->value.arg[0]);
381 		printval(n1->value.arg[0]->nodetype);
382 		putchar(' ');
383 	    }
384 	    putchar('\n');
385 	    break;
386 
387 	case O_PSYM:
388 	    if (p->value.arg[0]->op == O_SYM) {
389 		psym(p->value.arg[0]->value.sym);
390 	    } else {
391 		psym(p->value.arg[0]->nodetype);
392 	    }
393 	    break;
394 
395 	case O_QLINE:
396 	    eval(p->value.arg[1]);
397 	    break;
398 
399 	case O_STEP:
400 	    b = inst_tracing;
401 	    inst_tracing = (Boolean) (not p->value.step.source);
402 	    if (p->value.step.skipcalls) {
403 		next();
404 	    } else {
405 		stepc();
406 	    }
407 	    inst_tracing = b;
408 	    printnews();
409 	    break;
410 
411 	case O_WHATIS:
412 	    if (p->value.arg[0]->op == O_SYM) {
413 		printdecl(p->value.arg[0]->value.sym);
414 	    } else {
415 		printdecl(p->value.arg[0]->nodetype);
416 	    }
417 	    break;
418 
419 	case O_WHERE:
420 	    wherecmd();
421 	    break;
422 
423 	case O_WHEREIS:
424 	    if (p->value.arg[0]->op == O_SYM) {
425 		printwhereis(stdout,p->value.arg[0]->value.sym);
426 	    } else {
427 		printwhereis(stdout,p->value.arg[0]->nodetype);
428 	    }
429 	    break;
430 
431 	case O_WHICH:
432 	    if (p->value.arg[0]->op == O_SYM) {
433 		printwhich(stdout,p->value.arg[0]->value.sym);
434 	    } else {
435 		printwhich(stdout,p->value.arg[0]->nodetype);
436 	    }
437 	    putchar('\n');
438 	    break;
439 
440 	case O_ALIAS:
441 	    n1 = p->value.arg[0];
442 	    n2 = p->value.arg[1];
443 	    if (n1 == nil) {
444 		print_alias(nil);
445 	    } else if (n2 == nil) {
446 		print_alias(n1->value.name);
447 	    } else {
448 		enter_alias(n1->value.name, n2->value.name);
449 	    }
450 	    break;
451 
452 	case O_CALL:
453 	    callproc(p->value.arg[0], p->value.arg[1]);
454 	    break;
455 
456 	case O_CATCH:
457 	    psigtrace(process, p->value.lcon, true);
458 	    break;
459 
460 	case O_EDIT:
461 	    edit(p->value.scon);
462 	    break;
463 
464         case O_DEBUG:
465             debug(p);
466 	    break;
467 
468 	case O_DUMP:
469 	    dump();
470 	    break;
471 
472 	case O_GRIPE:
473 	    gripe();
474 	    break;
475 
476 	case O_HELP:
477 	    help();
478 	    break;
479 
480 	case O_IGNORE:
481 	    psigtrace(process, p->value.lcon, false);
482 	    break;
483 
484 	case O_RUN:
485 	    run();
486 	    break;
487 
488 	case O_SOURCE:
489 	    setinput(p->value.scon);
490 	    break;
491 
492 	case O_STATUS:
493 	    status();
494 	    break;
495 
496 	case O_TRACE:
497 	case O_TRACEI:
498 	    trace(p);
499 	    break;
500 
501 	case O_STOP:
502 	case O_STOPI:
503 	    stop(p);
504 	    break;
505 
506 	case O_ADDEVENT:
507 	    addevent(p->value.event.cond, p->value.event.actions);
508 	    break;
509 
510 	case O_DELETE:
511 	    delevent((unsigned int) p->value.lcon);
512 	    break;
513 
514 	case O_ENDX:
515 	    endprogram();
516 	    break;
517 
518 	case O_IF:
519 	    if (cond(p->value.event.cond)) {
520 		evalcmdlist(p->value.event.actions);
521 	    }
522 	    break;
523 
524 	case O_ONCE:
525 	    event_once(p->value.event.cond, p->value.event.actions);
526 	    break;
527 
528 	case O_PRINTCALL:
529 	    printcall(p->value.sym, whatblock(return_addr()));
530 	    break;
531 
532 	case O_PRINTIFCHANGED:
533 	    printifchanged(p->value.arg[0]);
534 	    break;
535 
536 	case O_PRINTRTN:
537 	    printrtn(p->value.sym);
538 	    break;
539 
540 	case O_PRINTSRCPOS:
541 	    getsrcpos();
542 	    if (p->value.arg[0] == nil) {
543 		printsrcpos();
544 		putchar('\n');
545 		printlines(curline, curline);
546 	    } else if (p->value.arg[0]->op == O_QLINE) {
547 		if (p->value.arg[0]->value.arg[1]->value.lcon == 0) {
548 		    printf("tracei: ");
549 		    printinst(pc, pc);
550 		} else {
551 		    printf("trace:  ");
552 		    printlines(curline, curline);
553 		}
554 	    } else {
555 		printsrcpos();
556 		printf(": ");
557 		eval(p->value.arg[0]);
558 		prtree(stdout, p->value.arg[0]);
559 		printf(" = ");
560 		printval(p->value.arg[0]->nodetype);
561 		putchar('\n');
562 	    }
563 	    break;
564 
565 	case O_PROCRTN:
566 	    procreturn(p->value.sym);
567 	    break;
568 
569 	case O_STOPIFCHANGED:
570 	    stopifchanged(p->value.arg[0]);
571 	    break;
572 
573 	case O_STOPX:
574 	    isstopped = true;
575 	    break;
576 
577 	case O_TRACEON:
578 	    traceon(p->value.trace.inst, p->value.trace.event,
579 		p->value.trace.actions);
580 	    break;
581 
582 	case O_TRACEOFF:
583 	    traceoff(p->value.lcon);
584 	    break;
585 
586 	default:
587 	    panic("eval: bad op %d", p->op);
588     }
589  if(debug_flag[2]) {
590 	fprintf(stderr," evaluated %s \n",showoperator(p->op));
591  }
592 
593 }
594 
595 /*
596  * Evaluate a list of commands.
597  */
598 
599 public evalcmdlist(cl)
600 Cmdlist cl;
601 {
602     Command c;
603 
604     foreach (Command, c, cl)
605 	evalcmd(c);
606     endfor
607 }
608 
609 /*
610  * Push "len" bytes onto the expression stack from address "addr"
611  * in the process.  If there isn't room on the stack, print an error message.
612  */
613 
614 public rpush(addr, len)
615 Address addr;
616 int len;
617 {
618     if (not canpush(len)) {
619 	error("expression too large to evaluate");
620     } else {
621 	chksp();
622 	dread(sp, addr, len);
623 	sp += len;
624     }
625 }
626 
627 /*
628  * Check if the stack has n bytes available.
629  */
630 
631 public Boolean canpush(n)
632 Integer n;
633 {
634     return (Boolean) (sp + n < &stack[STACKSIZE]);
635 }
636 
637 /*
638  * Push a small scalar of the given type onto the stack.
639  */
640 
641 public pushsmall(t, v)
642 Symbol t;
643 long v;
644 {
645     register Integer s;
646 
647     s = size(t);
648     switch (s) {
649 	case sizeof(char):
650 	    push(char, v);
651 	    break;
652 
653 	case sizeof(short):
654 	    push(short, v);
655 	    break;
656 
657 	case sizeof(long):
658 	    push(long, v);
659 	    break;
660 
661 	default:
662 	    panic("bad size %d in popsmall", s);
663     }
664 }
665 
666 /*
667  * Pop an item of the given type which is assumed to be no larger
668  * than a long and return it expanded into a long.
669  */
670 
671 public long popsmall(t)
672 Symbol t;
673 {
674     long r;
675 
676     switch (size(t)) {
677 	case sizeof(char):
678 	    r = (long) pop(char);
679 	    break;
680 
681 	case sizeof(short):
682 	    r = (long) pop(short);
683 	    break;
684 
685 	case sizeof(long):
686 	    r = pop(long);
687 	    break;
688 
689 	default:
690 	    panic("popsmall: size is %d", size(t));
691     }
692     return r;
693 }
694 
695 /*
696  * Evaluate a conditional expression.
697  */
698 
699 public Boolean cond(p)
700 Node p;
701 {
702     register Boolean b;
703 
704     if (p == nil) {
705 	b = true;
706     } else {
707 	eval(p);
708 	b = pop(Boolean);
709     }
710     return b;
711 }
712 
713 /*
714  * Return the address corresponding to a given tree.
715  */
716 
717 public Address lval(p)
718 Node p;
719 {
720     if (p->op == O_RVAL) {
721 	eval(p->value.arg[0]);
722     } else {
723 	eval(p);
724     }
725     return (Address) (pop(long));
726 }
727 
728 /*
729  * Process a trace command, translating into the appropriate events
730  * and associated actions.
731  */
732 
733 public trace(p)
734 Node p;
735 {
736     Node exp, place, cond;
737     Node left;
738 
739     exp = p->value.arg[0];
740     place = p->value.arg[1];
741     cond = p->value.arg[2];
742     if (exp == nil) {
743 	traceall(p->op, place, cond);
744     } else if (exp->op == O_QLINE or exp->op == O_LCON) {
745 	traceinst(p->op, exp, cond);
746     } else if (place != nil and place->op == O_QLINE) {
747 	traceat(p->op, exp, place, cond);
748     } else {
749 	left = exp;
750 	if (left->op == O_RVAL or left->op == O_CALL) {
751 	    left = left->value.arg[0];
752 	}
753 	if (left->op == O_SYM and isblock(left->value.sym)) {
754 	    traceproc(p->op, left->value.sym, place, cond);
755 	} else {
756 	    tracedata(p->op, exp, place, cond);
757 	}
758     }
759 }
760 
761 /*
762  * Set a breakpoint that will turn on tracing.
763  */
764 
765 private traceall(op, place, cond)
766 Operator op;
767 Node place;
768 Node cond;
769 {
770     Symbol s;
771     Node event;
772     Command action;
773 
774     if (place == nil) {
775 	s = program;
776     } else {
777 	s = place->value.sym;
778     }
779     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
780     action = build(O_PRINTSRCPOS,
781 	build(O_QLINE, nil, build(O_LCON, (op == O_TRACE) ? 1 : 0)));
782     if (cond != nil) {
783 	action = build(O_IF, cond, buildcmdlist(action));
784     }
785     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
786     action->value.trace.event = addevent(event, buildcmdlist(action));
787     if (isstdin()) {
788 	printevent(action->value.trace.event);
789     }
790 }
791 
792 /*
793  * Set up the appropriate breakpoint for tracing an instruction.
794  */
795 
796 private traceinst(op, exp, cond)
797 Operator op;
798 Node exp;
799 Node cond;
800 {
801     Node event, wh;
802     Command action;
803     Event e;
804 
805     if (exp->op == O_LCON) {
806 	wh = build(O_QLINE, build(O_SCON, cursource), exp);
807     } else {
808 	wh = exp;
809     }
810     if (op == O_TRACEI) {
811 	event = build(O_EQ, build(O_SYM, pcsym), wh);
812     } else {
813 	event = build(O_EQ, build(O_SYM, linesym), wh);
814     }
815     action = build(O_PRINTSRCPOS, wh);
816     if (cond) {
817 	action = build(O_IF, cond, buildcmdlist(action));
818     }
819     e = addevent(event, buildcmdlist(action));
820     if (isstdin()) {
821 	printevent(e);
822     }
823 }
824 
825 /*
826  * Set a breakpoint to print an expression at a given line or address.
827  */
828 
829 private traceat(op, exp, place, cond)
830 Operator op;
831 Node exp;
832 Node place;
833 Node cond;
834 {
835     Node event;
836     Command action;
837     Event e;
838 
839     if (op == O_TRACEI) {
840 	event = build(O_EQ, build(O_SYM, pcsym), place);
841     } else {
842 	event = build(O_EQ, build(O_SYM, linesym), place);
843     }
844     action = build(O_PRINTSRCPOS, exp);
845     if (cond != nil) {
846 	action = build(O_IF, cond, buildcmdlist(action));
847     }
848     e = addevent(event, buildcmdlist(action));
849     if (isstdin()) {
850 	printevent(e);
851     }
852 }
853 
854 /*
855  * Construct event for tracing a procedure.
856  *
857  * What we want here is
858  *
859  * 	when $proc = p do
860  *	    if <condition> then
861  *	        printcall;
862  *	        once $pc = $retaddr do
863  *	            printrtn;
864  *	        end;
865  *	    end if;
866  *	end;
867  *
868  * Note that "once" is like "when" except that the event
869  * deletes itself as part of its associated action.
870  */
871 
872 private traceproc(op, p, place, cond)
873 Operator op;
874 Symbol p;
875 Node place;
876 Node cond;
877 {
878     Node event;
879     Command action;
880     Cmdlist actionlist;
881     Event e;
882 
883     action = build(O_PRINTCALL, p);
884     actionlist = list_alloc();
885     cmdlist_append(action, actionlist);
886     event = build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym));
887     action = build(O_ONCE, event, buildcmdlist(build(O_PRINTRTN, p)));
888     cmdlist_append(action, actionlist);
889     if (cond != nil) {
890 	actionlist = buildcmdlist(build(O_IF, cond, actionlist));
891     }
892     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
893     e = addevent(event, actionlist);
894     if (isstdin()) {
895 	printevent(e);
896     }
897 }
898 
899 /*
900  * Set up breakpoint for tracing data.
901  */
902 
903 private tracedata(op, exp, place, cond)
904 Operator op;
905 Node exp;
906 Node place;
907 Node cond;
908 {
909     Symbol p;
910     Node event;
911     Command action;
912 
913     p = (place == nil) ? tcontainer(exp) : place->value.sym;
914     if (p == nil) {
915 	p = program;
916     }
917     action = build(O_PRINTIFCHANGED, exp);
918     if (cond != nil) {
919 	action = build(O_IF, cond, buildcmdlist(action));
920     }
921     action = build(O_TRACEON, (op == O_TRACEI), buildcmdlist(action));
922     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
923     action->value.trace.event = addevent(event, buildcmdlist(action));
924     if (isstdin()) {
925 	printevent(action->value.trace.event);
926     }
927 }
928 
929 /*
930  * Setting and unsetting of stops.
931  */
932 
933 public stop(p)
934 Node p;
935 {
936     Node exp, place, cond;
937     Symbol s;
938     Command action;
939     Event e;
940 
941     exp = p->value.arg[0];
942     place = p->value.arg[1];
943     cond = p->value.arg[2];
944     if (exp != nil) {
945 	stopvar(p->op, exp, place, cond);
946     } else if (cond != nil) {
947 	s = (place == nil) ? program : place->value.sym;
948 	action = build(O_IF, cond, buildcmdlist(build(O_STOPX)));
949 	action = build(O_TRACEON, (p->op == O_STOPI), buildcmdlist(action));
950 	cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
951 	action->value.trace.event = addevent(cond, buildcmdlist(action));
952     } else if (place->op == O_SYM) {
953 	s = place->value.sym;
954 	cond = build(O_EQ, build(O_SYM, procsym), build(O_SYM, s));
955 	e = addevent(cond, buildcmdlist(build(O_STOPX)));
956 	if (isstdin()) {
957 	    printevent(e);
958 	}
959     } else {
960 	stopinst(p->op, place, cond);
961     }
962 }
963 
964 private stopinst(op, place, cond)
965 Operator op;
966 Node place;
967 Node cond;
968 {
969     Node event;
970     Event e;
971 
972     if (op == O_STOP) {
973 	event = build(O_EQ, build(O_SYM, linesym), place);
974     } else {
975 	event = build(O_EQ, build(O_SYM, pcsym), place);
976     }
977     e = addevent(event, buildcmdlist(build(O_STOPX)));
978     if (isstdin()) {
979 	printevent(e);
980     }
981 }
982 
983 /*
984  * Implement stopping on assignment to a variable by adding it to
985  * the variable list.
986  */
987 
988 private stopvar(op, exp, place, cond)
989 Operator op;
990 Node exp;
991 Node place;
992 Node cond;
993 {
994     Symbol p;
995     Node event;
996     Command action;
997 
998     p = (place == nil) ? tcontainer(exp) : place->value.sym;
999     if (p == nil) {
1000 	p = program;
1001     }
1002     action = build(O_IF, cond, buildcmdlist(build(O_STOPIFCHANGED, exp)));
1003     action = build(O_TRACEON, (op == O_STOPI), buildcmdlist(action));
1004     event = build(O_EQ, build(O_SYM, procsym), build(O_SYM, p));
1005     action->value.trace.event = addevent(event, buildcmdlist(action));
1006     if (isstdin()) {
1007 	printevent(action->value.trace.event);
1008     }
1009 }
1010 
1011 /*
1012  * Assign the value of an expression to a variable (or term).
1013  */
1014 
1015 public assign(var, exp)
1016 Node var;
1017 Node exp;
1018 {
1019     Address addr;
1020     int varsize;
1021     char cvalue;
1022     short svalue;
1023     long lvalue;
1024 
1025     if (not compatible(var->nodetype, exp->nodetype)) {
1026 	error("incompatible types");
1027     }
1028     addr = lval(var);
1029     eval(exp);
1030     varsize = size(var->nodetype);
1031     if (varsize < sizeof(long)) {
1032 	lvalue = pop(long);
1033 	switch (varsize) {
1034 	    case sizeof(char):
1035 		cvalue = lvalue;
1036 		dwrite(&cvalue, addr, varsize);
1037 		break;
1038 
1039 	    case sizeof(short):
1040 		svalue = lvalue;
1041 		dwrite(&svalue, addr, varsize);
1042 		break;
1043 
1044 	    default:
1045 		panic("bad size %d", varsize);
1046 	}
1047     } else {
1048 	sp -= varsize;
1049 	dwrite(sp, addr, varsize);
1050     }
1051 }
1052 
1053 #define DEF_EDITOR  "vi"
1054 
1055 /*
1056  * Invoke an editor on the given file.  Which editor to use might change
1057  * installation to installation.  For now, we use "vi".  In any event,
1058  * the environment variable "EDITOR" overrides any default.
1059  */
1060 
1061 public edit(filename)
1062 String filename;
1063 {
1064     extern String getenv();
1065     String ed, src;
1066     File f;
1067     Symbol s;
1068     Address addr;
1069     char buff[10];
1070 
1071     ed = getenv("EDITOR");
1072     if (ed == nil) {
1073 	ed = DEF_EDITOR;
1074     }
1075     if (filename == nil) {
1076 	call(ed, stdin, stdout, cursource, nil);
1077     } else {
1078 	f = fopen(filename, "r");
1079 	if (f == nil) {
1080 	    s = which(identname(filename, true));
1081 	    if (not isblock(s)) {
1082 		error("can't read \"%s\"", filename);
1083 	    }
1084 	    addr = firstline(s);
1085 	    if (addr == NOADDR) {
1086 		error("no source for \"%s\"", filename);
1087 	    }
1088 	    src = srcfilename(addr);
1089 	    sprintf(buff, "+%d", srcline(addr));
1090 	    call(ed, stdin, stdout, buff, src, nil);
1091 	} else {
1092 	    fclose(f);
1093 	    call(ed, stdin, stdout, filename, nil);
1094 	}
1095     }
1096 }
1097 
1098 /*
1099  * Send some nasty mail to the current support person.
1100  */
1101 
1102 public gripe()
1103 {
1104     typedef Operation();
1105     Operation *old;
1106 
1107     char *maintainer = "linton@ucbarpa";
1108 
1109     puts("Type control-D to end your message.  Be sure to include");
1110     puts("your name and the name of the file you are debugging.");
1111     putchar('\n');
1112     old = signal(SIGINT, SIG_DFL);
1113     call("Mail", stdin, stdout, maintainer, nil);
1114     signal(SIGINT, old);
1115     puts("Thank you.");
1116 }
1117 
1118 /*
1119  * Give the user some help.
1120  */
1121 
1122 public help()
1123 {
1124     puts("run                    - begin execution of the program");
1125     puts("cont                   - continue execution");
1126     puts("step                   - single step one line");
1127     puts("next                   - step to next line (skip over calls)");
1128     puts("trace <line#>          - trace execution of the line");
1129     puts("trace <proc>           - trace calls to the procedure");
1130     puts("trace <var>            - trace changes to the variable");
1131     puts("trace <exp> at <line#> - print <exp> when <line> is reached");
1132     puts("stop at <line>         - suspend execution at the line");
1133     puts("stop in <proc>         - suspend execution when <proc> is called");
1134     puts("status                 - print trace/stop's in effect");
1135     puts("delete <number>        - remove trace or stop of given number");
1136     puts("call <proc>            - call the procedure");
1137     puts("where                  - print currently active procedures");
1138     puts("print <exp>            - print the value of the expression");
1139     puts("whatis <name>          - print the declaration of the name");
1140     puts("list <line>, <line>    - list source lines");
1141     puts("edit <proc>            - edit file containing <proc>");
1142     puts("gripe                  - send mail to the person in charge of dbx");
1143     puts("quit                   - exit dbx");
1144 }
1145 
1146 /*
1147  * Divert output to the given file name.
1148  * Cannot redirect to an existing file.
1149  */
1150 
1151 private int so_fd;
1152 private Boolean notstdout;
1153 
1154 public setout(filename)
1155 String filename;
1156 {
1157     File f;
1158 
1159     f = fopen(filename, "r");
1160     if (f != nil) {
1161 	fclose(f);
1162 	error("%s: file already exists", filename);
1163     } else {
1164 	so_fd = dup(1);
1165 	close(1);
1166 	if (creat(filename, 0666) == nil) {
1167 	    unsetout();
1168 	    error("can't create %s", filename);
1169 	}
1170 	notstdout = true;
1171     }
1172 }
1173 
1174 /*
1175  * Revert output to standard output.
1176  */
1177 
1178 public unsetout()
1179 {
1180     fflush(stdout);
1181     close(1);
1182     if (dup(so_fd) != 1) {
1183 	panic("standard out dup failed");
1184     }
1185     close(so_fd);
1186     notstdout = false;
1187 }
1188 
1189 /*
1190  * Determine is standard output is currently being redirected
1191  * to a file (as far as we know).
1192  */
1193 
1194 public Boolean isredirected()
1195 {
1196     return notstdout;
1197 }
1198