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