1 /*
2 * Copyright (c) 1983 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)tree.c 5.5 (Berkeley) 06/01/90";
10 #endif /* not lint */
11
12 /*
13 * Parse tree management.
14 */
15
16 #include "defs.h"
17 #include "tree.h"
18 #include "operators.h"
19 #include "debug.h"
20 #include "eval.h"
21 #include "events.h"
22 #include "symbols.h"
23 #include "scanner.h"
24 #include "source.h"
25 #include "object.h"
26 #include "mappings.h"
27 #include "process.h"
28 #include "machine.h"
29
30 #ifndef public
31 #include "lists.h"
32
33 typedef struct Node *Node;
34 typedef Node Command;
35 typedef List Cmdlist;
36
37 #include "operators.h"
38 #include "symbols.h"
39 #include "events.h"
40
41 #define MAXNARGS 5
42
43 struct Node {
44 Operator op;
45 Symbol nodetype;
46 union treevalue {
47 Symbol sym;
48 Name name;
49 long lcon;
50 double fcon;
51 String scon;
52 Node arg[MAXNARGS];
53 struct {
54 Node cond;
55 Cmdlist actions;
56 } event;
57 struct {
58 Boolean inst;
59 Event event;
60 Cmdlist actions;
61 } trace;
62 struct {
63 Boolean source;
64 Boolean skipcalls;
65 } step;
66 struct {
67 String mode;
68 Node beginaddr;
69 Node endaddr;
70 Integer count;
71 } examine;
72 } value;
73 };
74
75 #define evalcmd(cmd) eval(cmd)
76 #define cmdlist_append(cmd, cl) list_append(list_item(cmd), nil, cl)
77
78 #endif
79
80 typedef char *Arglist;
81
82 #define nextarg(type) ((type *) (ap += sizeof(type)))[-1]
83
84 /*
85 * Build a tree.
86 */
87
88 /* VARARGS1 */
build(op,args)89 public Node build(op, args)
90 Operator op;
91 {
92 register Node p, q;
93 register Arglist ap;
94 Integer i;
95
96 p = new(Node);
97 p->op = op;
98 p->nodetype = nil;
99 ap = (Arglist) &args;
100 switch (op) {
101 case O_NAME:
102 p->value.name = nextarg(Name);
103 break;
104
105 case O_SYM:
106 case O_PRINTCALL:
107 case O_PRINTRTN:
108 case O_PROCRTN:
109 p->value.sym = nextarg(Symbol);
110 break;
111
112 case O_DEBUG:
113 case O_LCON:
114 case O_CCON:
115 case O_CONT:
116 case O_CATCH:
117 case O_IGNORE:
118 case O_TRACEOFF:
119 p->value.lcon = nextarg(long);
120 break;
121
122 case O_FCON:
123 p->value.fcon = nextarg(double);
124 break;
125
126 case O_SCON:
127 case O_CHFILE:
128 case O_EDIT:
129 case O_SOURCE:
130 p->value.scon = nextarg(String);
131 break;
132
133 case O_RVAL:
134 case O_INDIR:
135 p->value.arg[0] = nextarg(Node);
136 break;
137
138 case O_CALL:
139 q = nextarg(Node);
140 if (q->op == O_SYM and
141 (q->value.sym->class == TYPE or q->value.sym->class == TAG)
142 ) {
143 p->op = O_TYPERENAME;
144 p->value.arg[0] = nextarg(Node);
145 p->value.arg[1] = q;
146 q = p->value.arg[0];
147 if (q->value.arg[1] != nil) {
148 error("too many arguments to type rename");
149 }
150 p->value.arg[0] = q->value.arg[0];
151 } else {
152 p->value.arg[0] = q;
153 p->value.arg[1] = nextarg(Node);
154 }
155 break;
156
157 case O_ADDEVENT:
158 case O_ONCE:
159 case O_IF:
160 p->value.event.cond = nextarg(Node);
161 p->value.event.actions = nextarg(Cmdlist);
162 break;
163
164 case O_TRACEON:
165 p->value.trace.inst = nextarg(Boolean);
166 p->value.trace.event = nil;
167 p->value.trace.actions = nextarg(Cmdlist);
168 break;
169
170 case O_STEP:
171 p->value.step.source = nextarg(Boolean);
172 p->value.step.skipcalls = nextarg(Boolean);
173 break;
174
175 case O_EXAMINE:
176 p->value.examine.mode = nextarg(String);
177 p->value.examine.beginaddr = nextarg(Node);
178 p->value.examine.endaddr = nextarg(Node);
179 p->value.examine.count = nextarg(Integer);
180 break;
181
182 default:
183 for (i = 0; i < nargs(op); i++) {
184 p->value.arg[i] = nextarg(Node);
185 }
186 break;
187 }
188 check(p);
189 assigntypes(p);
190 if (tracetree) {
191 printf("built %s node 0x%x with arg[0] 0x%x arg[1] 0x%x\n",
192 opname(p->op), p, p->value.arg[0], p->value.arg[1]);
193 fflush(stdout);
194 }
195 return p;
196 }
197
198 /*
199 * Strip away indirection from a node, thus returning a node for
200 * interpreting the expression as an lvalue.
201 */
202
unrval(exp)203 public Node unrval (exp)
204 Node exp;
205 {
206 Node p;
207 Symbol t;
208
209 if (exp->op == O_RVAL) {
210 p = exp->value.arg[0];
211 dispose(exp);
212 } else if (exp->op == O_INDIR) {
213 p = exp->value.arg[0];
214 if (p->op == O_RVAL) {
215 p->op = O_INDIR;
216 p->nodetype = exp->nodetype;
217 }
218 dispose(exp);
219 } else {
220 p = exp;
221 }
222 return p;
223 }
224
225 /*
226 * Create a node for renaming a node to a pointer type.
227 */
228
renameptr(p,t)229 public Node renameptr (p, t)
230 Node p;
231 Node t;
232 {
233 t->nodetype = newSymbol(nil, 0, PTR, t->nodetype, nil);
234 p = build(O_TYPERENAME, p, t);
235 }
236
237 /*
238 * Return the tree for a unary ampersand operator.
239 */
240
amper(p)241 public Node amper(p)
242 Node p;
243 {
244 Node r;
245
246 checkref(p);
247 switch (p->op) {
248 case O_RVAL:
249 case O_INDIR:
250 r = p->value.arg[0];
251 r->nodetype = t_addr;
252 dispose(p);
253 break;
254
255 case O_TYPERENAME:
256 r = p;
257 r->nodetype = newSymbol(nil, 0, PTR, r->nodetype, nil);
258 r->nodetype->language = p->nodetype->language;
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
concrete(p)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
buildcmdlist(cmd)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
printcmd(f,cmd)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, "%s }", 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
print_tracestop(f,cmd)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
prtree(f,p)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
tfree(p)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