xref: /csrg-svn/old/dbx/tree.c (revision 21626)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)tree.c	5.1 (Berkeley) 05/31/85";
9 #endif not lint
10 
11 static char rcsid[] = "$Header: tree.c,v 1.5 84/12/26 10:42:55 linton Exp $";
12 
13 /*
14  * Parse tree management.
15  */
16 
17 #include "defs.h"
18 #include "tree.h"
19 #include "operators.h"
20 #include "debug.h"
21 #include "eval.h"
22 #include "events.h"
23 #include "symbols.h"
24 #include "scanner.h"
25 #include "source.h"
26 #include "object.h"
27 #include "mappings.h"
28 #include "process.h"
29 #include "machine.h"
30 
31 #ifndef public
32 #include "lists.h"
33 
34 typedef struct Node *Node;
35 typedef Node Command;
36 typedef List Cmdlist;
37 
38 #include "operators.h"
39 #include "symbols.h"
40 #include "events.h"
41 
42 #define MAXNARGS 5
43 
44 struct Node {
45     Operator op;
46     Symbol nodetype;
47     union treevalue {
48 	Symbol sym;
49 	Name name;
50 	long lcon;
51 	double fcon;
52 	String scon;
53 	Node arg[MAXNARGS];
54 	struct {
55 	    Node cond;
56 	    Cmdlist actions;
57 	} event;
58 	struct {
59 	    Boolean inst;
60 	    Event event;
61 	    Cmdlist actions;
62 	} trace;
63 	struct {
64 	    Boolean source;
65 	    Boolean skipcalls;
66 	} step;
67 	struct {
68 	    String mode;
69 	    Node beginaddr;
70 	    Node endaddr;
71 	    Integer count;
72 	} examine;
73     } value;
74 };
75 
76 #define evalcmd(cmd) eval(cmd)
77 #define cmdlist_append(cmd, cl) list_append(list_item(cmd), nil, cl)
78 
79 #endif
80 
81 typedef char *Arglist;
82 
83 #define nextarg(type)  ((type *) (ap += sizeof(type)))[-1]
84 
85 /*
86  * Build a tree.
87  */
88 
89 /* VARARGS1 */
90 public Node build(op, args)
91 Operator op;
92 {
93     register Node p, q;
94     register Arglist ap;
95     Integer i;
96 
97     p = new(Node);
98     p->op = op;
99     p->nodetype = nil;
100     ap = (Arglist) &args;
101     switch (op) {
102 	case O_NAME:
103 	    p->value.name = nextarg(Name);
104 	    break;
105 
106 	case O_SYM:
107 	case O_PRINTCALL:
108 	case O_PRINTRTN:
109 	case O_PROCRTN:
110 	    p->value.sym = nextarg(Symbol);
111 	    break;
112 
113 	case O_DEBUG:
114 	case O_LCON:
115 	case O_CCON:
116 	case O_CONT:
117 	case O_CATCH:
118 	case O_IGNORE:
119 	case O_TRACEOFF:
120 	    p->value.lcon = nextarg(long);
121 	    break;
122 
123 	case O_FCON:
124 	    p->value.fcon = nextarg(double);
125 	    break;
126 
127 	case O_SCON:
128 	case O_CHFILE:
129 	case O_EDIT:
130 	case O_SOURCE:
131 	    p->value.scon = nextarg(String);
132 	    break;
133 
134 	case O_RVAL:
135 	case O_INDIR:
136 	    p->value.arg[0] = nextarg(Node);
137 	    break;
138 
139 	case O_CALL:
140 	    q = nextarg(Node);
141 	    if (q->op == O_SYM and
142 		(q->value.sym->class == TYPE or q->value.sym->class == TAG)
143 	    ) {
144 		p->op = O_TYPERENAME;
145 		p->value.arg[0] = nextarg(Node);
146 		p->value.arg[1] = q;
147 		q = p->value.arg[0];
148 		if (q->value.arg[1] != nil) {
149 		    error("too many arguments to type rename");
150 		}
151 		p->value.arg[0] = q->value.arg[0];
152 	    } else {
153 		p->value.arg[0] = q;
154 		p->value.arg[1] = nextarg(Node);
155 	    }
156 	    break;
157 
158 	case O_ADDEVENT:
159 	case O_ONCE:
160 	case O_IF:
161 	    p->value.event.cond = nextarg(Node);
162 	    p->value.event.actions = nextarg(Cmdlist);
163 	    break;
164 
165 	case O_TRACEON:
166 	    p->value.trace.inst = nextarg(Boolean);
167 	    p->value.trace.event = nil;
168 	    p->value.trace.actions = nextarg(Cmdlist);
169 	    break;
170 
171 	case O_STEP:
172 	    p->value.step.source = nextarg(Boolean);
173 	    p->value.step.skipcalls = nextarg(Boolean);
174 	    break;
175 
176 	case O_EXAMINE:
177 	    p->value.examine.mode = nextarg(String);
178 	    p->value.examine.beginaddr = nextarg(Node);
179 	    p->value.examine.endaddr = nextarg(Node);
180 	    p->value.examine.count = nextarg(Integer);
181 	    break;
182 
183 	default:
184 	    for (i = 0; i < nargs(op); i++) {
185 		p->value.arg[i] = nextarg(Node);
186 	    }
187 	    break;
188     }
189     check(p);
190     assigntypes(p);
191     if (tracetree) {
192 	printf("built %s node 0x%x with arg[0] 0x%x arg[1] 0x%x\n",
193 	    opname(p->op), p, p->value.arg[0], p->value.arg[1]);
194 	fflush(stdout);
195     }
196     return p;
197 }
198 
199 /*
200  * Strip away indirection from a node, thus returning a node for
201  * interpreting the expression as an lvalue.
202  */
203 
204 public Node unrval (exp)
205 Node exp;
206 {
207     Node p;
208     Symbol t;
209 
210     if (exp->op == O_RVAL) {
211 	p = exp->value.arg[0];
212 	dispose(exp);
213     } else if (exp->op == O_INDIR) {
214 	p = exp->value.arg[0];
215 	if (p->op == O_RVAL) {
216 	    p->op = O_INDIR;
217 	    p->nodetype = exp->nodetype;
218 	}
219 	dispose(exp);
220     } else {
221 	p = exp;
222     }
223     return p;
224 }
225 
226 /*
227  * Create a node for renaming a node to a pointer type.
228  */
229 
230 public Node renameptr (p, t)
231 Node p;
232 Node t;
233 {
234     t->nodetype = newSymbol(nil, 0, PTR, t->nodetype, nil);
235     p = build(O_TYPERENAME, p, t);
236 }
237 
238 /*
239  * Return the tree for a unary ampersand operator.
240  */
241 
242 public Node amper(p)
243 Node p;
244 {
245     Node r;
246 
247     checkref(p);
248     switch (p->op) {
249 	case O_RVAL:
250 	case O_INDIR:
251 	    r = p->value.arg[0];
252 	    r->nodetype = t_addr;
253 	    dispose(p);
254 	    break;
255 
256 	case O_TYPERENAME:
257 	    r = p;
258 	    r->nodetype = newSymbol(nil, 0, PTR, r->nodetype, nil);
259 	    break;
260 
261 	case O_SYM:
262 	    if (isblock(p->value.sym)) {
263 		r = build(O_LCON, codeloc(p->value.sym));
264 	    } else {
265 		r = build(O_LCON, address(p->value.sym, nil));
266 	    }
267 	    r->nodetype = t_addr;
268 	    dispose(p);
269 	    break;
270 
271 	case O_DOT:
272 	    r = p;
273 	    r->nodetype = t_addr;
274 	    break;
275 
276 	default:
277 	    beginerrmsg();
278 	    fprintf(stderr, "expected variable, found \"");
279 	    prtree(stderr, p);
280 	    fprintf(stderr, "\"");
281 	    tfree(p);
282 	    enderrmsg();
283 	    /* NOTREACHED */
284     }
285     return r;
286 }
287 
288 /*
289  * Create a "concrete" version of a node.
290  * This is necessary when the type of the node contains
291  * an unresolved type reference.
292  */
293 
294 public Node concrete(p)
295 Node p;
296 {
297     findtype(p->nodetype);
298     return build(O_INDIR, p);
299 }
300 
301 /*
302  * Create a command list from a single command.
303  */
304 
305 public Cmdlist buildcmdlist(cmd)
306 Command cmd;
307 {
308     Cmdlist cmdlist;
309 
310     cmdlist = list_alloc();
311     cmdlist_append(cmd, cmdlist);
312     return cmdlist;
313 }
314 
315 /*
316  * Print out a command.
317  */
318 
319 public printcmd(f, cmd)
320 File f;
321 Command cmd;
322 {
323     register Integer i;
324     register Command c;
325     register Node p;
326 
327     switch (cmd->op) {
328 	case O_PRINTIFCHANGED:
329 	case O_PRINTSRCPOS:
330 	case O_STOPIFCHANGED:
331 	case O_TRACEON:
332 	    break;
333 
334 	case O_STEP:
335 	    if (cmd->value.step.skipcalls) {
336 		fprintf(f, "next");
337 	    } else {
338 		fprintf(f, "step");
339 	    }
340 	    if (not cmd->value.step.source) {
341 		fprintf(f, "i");
342 	    }
343 	    break;
344 
345 	default:
346 	    fprintf(f, "%s", opinfo[ord(cmd->op)].opstring);
347 	    if (nargs(cmd->op) != 0) {
348 		fprintf(f, " ");
349 	    }
350 	    break;
351     }
352     switch (cmd->op) {
353 	case O_PRINTCALL:
354 	case O_PRINTRTN:
355 	case O_PROCRTN:
356 	    fprintf(f, "%s", symname(cmd->value.sym));
357 	    break;
358 
359 	case O_PRINTSRCPOS:
360 	    p = cmd->value.arg[0];
361 	    if (p != nil and p->op != O_QLINE) {
362 		printf("trace ");
363 		prtree(f, p);
364 	    }
365 	    break;
366 
367 	case O_CHFILE:
368 	case O_EDIT:
369 	case O_SOURCE:
370 	    fprintf(f, "%s", cmd->value.scon);
371 	    break;
372 
373 	case O_CATCH:
374 	case O_IGNORE:
375 	case O_TRACEOFF:
376 	    fprintf(f, "%d", cmd->value.lcon);
377 	    break;
378 
379 	case O_ADDEVENT:
380 	case O_ONCE:
381 	case O_IF:
382 	    fprintf(f, " ");
383 	    prtree(f, cmd->value.event.cond);
384 	    fprintf(f, " { ");
385 	    foreach (Command, c, cmd->value.event.actions)
386 		printcmd(f, c);
387 		if (not list_islast()) {
388 		    fprintf(f, ";");
389 		}
390 	    endfor
391 	    fprintf(f, " }", opinfo[ord(cmd->op)].opstring);
392 	    break;
393 
394 	case O_TRACEON:
395 	    print_tracestop(f, cmd);
396 	    break;
397 
398 	case O_EXAMINE:
399 	    prtree(f, cmd->value.examine.beginaddr);
400 	    if (cmd->value.examine.endaddr != nil) {
401 		fprintf(f, ",");
402 		prtree(f, cmd->value.examine.endaddr);
403 	    }
404 	    fprintf(f, "/");
405 	    if (cmd->value.examine.count > 1) {
406 		fprintf(f, "%d", cmd->value.examine.count);
407 	    }
408 	    fprintf("%s", cmd->value.examine.mode);
409 	    break;
410 
411 	default:
412 	    if (nargs(cmd->op) != 0) {
413 		i = 0;
414 		for (;;) {
415 		    prtree(f, cmd->value.arg[i]);
416 		    ++i;
417 		if (i >= nargs(cmd->op)) break;
418 		    fprintf(f, " ");
419 		}
420 	    }
421 	    break;
422     }
423 }
424 
425 /*
426  * Print out a trace/stop command name.
427  */
428 
429 #define fprintI(f, b) { if (b) fprintf(f, "i"); }
430 
431 private print_tracestop(f, cmd)
432 File f;
433 Command cmd;
434 {
435     register Command c, ifcmd, stopcmd;
436     Boolean done;
437 
438     done = false;
439     ifcmd = list_element(Command, list_head(cmd->value.trace.actions));
440     checkref(ifcmd);
441     if (ifcmd->op == O_IF) {
442 	stopcmd = list_element(Command, list_head(ifcmd->value.event.actions));
443 	checkref(stopcmd);
444 	if (stopcmd->op == O_STOPX) {
445 	    fprintf(f, "stop");
446 	    fprintI(f, cmd->value.trace.inst);
447 	    fprintf(f, " if ");
448 	    prtree(f, ifcmd->value.event.cond);
449 	    done = true;
450 	}
451     } else if (ifcmd->op == O_STOPIFCHANGED) {
452 	fprintf(f, "stop");
453 	fprintI(f, cmd->value.trace.inst);
454 	fprintf(f, " ");
455 	prtree(f, ifcmd->value.arg[0]);
456 	done = true;
457     }
458     if (not done) {
459 	fprintf(f, "%s ", cmd->value.trace.inst ? "tracei" : "trace");
460 	foreach (Command, c, cmd->value.trace.actions)
461 	    printcmd(f, c);
462 	    if (not list_islast()) {
463 		fprintf(f, ";");
464 	    }
465 	endfor
466     }
467 }
468 
469 /*
470  * Print out a tree.
471  */
472 
473 public prtree(f, p)
474 File f;
475 register Node p;
476 {
477     register Node q;
478     Operator op;
479 
480     if (p != nil) {
481 	op = p->op;
482 	if (ord(op) > ord(O_LASTOP)) {
483 	    panic("bad op %d in prtree", p->op);
484 	}
485 	switch (op) {
486 	    case O_NAME:
487 		fprintf(f, "%s", ident(p->value.name));
488 		break;
489 
490 	    case O_SYM:
491 		printname(f, p->value.sym);
492 		break;
493 
494 	    case O_QLINE:
495 		if (nlhdr.nfiles > 1) {
496 		    prtree(f, p->value.arg[0]);
497 		    fprintf(f, ":");
498 		}
499 		prtree(f, p->value.arg[1]);
500 		break;
501 
502 	    case O_LCON:
503 		fprintf(f, "%d", p->value.lcon);
504 		break;
505 
506 	    case O_CCON:
507 		fprintf(f, "'%c'", p->value.lcon);
508 		break;
509 
510 	    case O_FCON:
511 		fprintf(f, "%g", p->value.fcon);
512 		break;
513 
514 	    case O_SCON:
515 		fprintf(f, "\"%s\"", p->value.scon);
516 		break;
517 
518 	    case O_INDEX:
519 		prtree(f, p->value.arg[0]);
520 		fprintf(f, "[");
521 		prtree(f, p->value.arg[1]);
522 		fprintf(f, "]");
523 		break;
524 
525 	    case O_COMMA:
526 		prtree(f, p->value.arg[0]);
527 		if (p->value.arg[1] != nil) {
528 		    fprintf(f, ", ");
529 		    prtree(f, p->value.arg[1]);
530 		}
531 		break;
532 
533 	    case O_RVAL:
534 	    case O_ITOF:
535 		prtree(f, p->value.arg[0]);
536 		break;
537 
538 	    case O_CALL:
539 		prtree(f, p->value.arg[0]);
540 		if (p->value.arg[1]!= nil) {
541 		    fprintf(f, "(");
542 		    prtree(f, p->value.arg[1]);
543 		    fprintf(f, ")");
544 		}
545 		break;
546 
547 	    case O_INDIR:
548 		prtree(f, p->value.arg[0]);
549 		fprintf(f, "^");
550 		break;
551 
552 	    case O_DOT:
553 		prtree(f, p->value.arg[0]);
554 		fprintf(f, ".%s", symname(p->value.arg[1]->value.sym));
555 		break;
556 
557 	    case O_TYPERENAME:
558 		prtree(f, p->value.arg[1]);
559 		fprintf(f, "(");
560 		prtree(f, p->value.arg[0]);
561 		fprintf(f, ")");
562 		break;
563 
564 	    default:
565 		switch (degree(op)) {
566 		    case BINARY:
567 			prtree(f, p->value.arg[0]);
568 			fprintf(f, "%s", opinfo[ord(op)].opstring);
569 			prtree(f, p->value.arg[1]);
570 			break;
571 
572 		    case UNARY:
573 			fprintf(f, "%s", opinfo[ord(op)].opstring);
574 			prtree(f, p->value.arg[0]);
575 			break;
576 
577 		    default:
578 			if (opinfo[ord(op)].opstring == nil) {
579 			    fprintf(f, "[op %d]", ord(op));
580 			} else {
581 			    fprintf(f, "%s", opinfo[ord(op)].opstring);
582 			}
583 			break;
584 		}
585 		break;
586 	}
587     }
588 }
589 
590 /*
591  * Free storage associated with a tree.
592  */
593 
594 public tfree(p)
595 Node p;
596 {
597     Integer i;
598 
599     if (p == nil) {
600 	return;
601     }
602     switch (p->op) {
603 	case O_QLINE:
604 	    dispose(p->value.arg[0]->value.scon);
605 	    dispose(p->value.arg[0]);
606 	    tfree(p->value.arg[1]);
607 	    break;
608 
609 	case O_SCON:
610 	    unmkstring(p->nodetype);
611 	    dispose(p->nodetype);
612 	    dispose(p->value.scon);
613 	    break;
614 
615 	default:
616 	    for (i = 0; i < nargs(p->op); i++) {
617 		tfree(p->value.arg[i]);
618 	    }
619 	    break;
620     }
621     dispose(p);
622 }
623