xref: /csrg-svn/old/dbx/tree.c (revision 38105)
121626Sdist /*
2*38105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
3*38105Sbostic  * All rights reserved.
4*38105Sbostic  *
5*38105Sbostic  * Redistribution and use in source and binary forms are permitted
6*38105Sbostic  * provided that the above copyright notice and this paragraph are
7*38105Sbostic  * duplicated in all such forms and that any documentation,
8*38105Sbostic  * advertising materials, and other materials related to such
9*38105Sbostic  * distribution and use acknowledge that the software was developed
10*38105Sbostic  * by the University of California, Berkeley.  The name of the
11*38105Sbostic  * University may not be used to endorse or promote products derived
12*38105Sbostic  * from this software without specific prior written permission.
13*38105Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*38105Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*38105Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621626Sdist  */
179681Slinton 
1821626Sdist #ifndef lint
19*38105Sbostic static char sccsid[] = "@(#)tree.c	5.4 (Berkeley) 05/23/89";
20*38105Sbostic #endif /* not lint */
219681Slinton 
229681Slinton /*
239681Slinton  * Parse tree management.
249681Slinton  */
259681Slinton 
269681Slinton #include "defs.h"
279681Slinton #include "tree.h"
289681Slinton #include "operators.h"
2918236Slinton #include "debug.h"
309681Slinton #include "eval.h"
319681Slinton #include "events.h"
329681Slinton #include "symbols.h"
339681Slinton #include "scanner.h"
349681Slinton #include "source.h"
359681Slinton #include "object.h"
369681Slinton #include "mappings.h"
379681Slinton #include "process.h"
389681Slinton #include "machine.h"
399681Slinton 
409681Slinton #ifndef public
419681Slinton #include "lists.h"
429681Slinton 
439681Slinton typedef struct Node *Node;
449681Slinton typedef Node Command;
459681Slinton typedef List Cmdlist;
469681Slinton 
479681Slinton #include "operators.h"
489681Slinton #include "symbols.h"
499681Slinton #include "events.h"
509681Slinton 
519681Slinton #define MAXNARGS 5
529681Slinton 
539681Slinton struct Node {
549681Slinton     Operator op;
559681Slinton     Symbol nodetype;
569681Slinton     union treevalue {
579681Slinton 	Symbol sym;
589681Slinton 	Name name;
599681Slinton 	long lcon;
609681Slinton 	double fcon;
619681Slinton 	String scon;
629681Slinton 	Node arg[MAXNARGS];
639681Slinton 	struct {
649681Slinton 	    Node cond;
659681Slinton 	    Cmdlist actions;
669681Slinton 	} event;
679681Slinton 	struct {
689681Slinton 	    Boolean inst;
699681Slinton 	    Event event;
709681Slinton 	    Cmdlist actions;
719681Slinton 	} trace;
729681Slinton 	struct {
739681Slinton 	    Boolean source;
749681Slinton 	    Boolean skipcalls;
759681Slinton 	} step;
769681Slinton 	struct {
779681Slinton 	    String mode;
789681Slinton 	    Node beginaddr;
799681Slinton 	    Node endaddr;
809681Slinton 	    Integer count;
819681Slinton 	} examine;
829681Slinton     } value;
839681Slinton };
849681Slinton 
859681Slinton #define evalcmd(cmd) eval(cmd)
869681Slinton #define cmdlist_append(cmd, cl) list_append(list_item(cmd), nil, cl)
879681Slinton 
889681Slinton #endif
899681Slinton 
909681Slinton typedef char *Arglist;
919681Slinton 
929681Slinton #define nextarg(type)  ((type *) (ap += sizeof(type)))[-1]
939681Slinton 
949681Slinton /*
959681Slinton  * Build a tree.
969681Slinton  */
979681Slinton 
989681Slinton /* VARARGS1 */
999681Slinton public Node build(op, args)
1009681Slinton Operator op;
1019681Slinton {
1029681Slinton     register Node p, q;
1039681Slinton     register Arglist ap;
1049681Slinton     Integer i;
1059681Slinton 
1069681Slinton     p = new(Node);
1079681Slinton     p->op = op;
1089681Slinton     p->nodetype = nil;
1099681Slinton     ap = (Arglist) &args;
1109681Slinton     switch (op) {
1119681Slinton 	case O_NAME:
1129681Slinton 	    p->value.name = nextarg(Name);
1139681Slinton 	    break;
1149681Slinton 
1159681Slinton 	case O_SYM:
1169681Slinton 	case O_PRINTCALL:
1179681Slinton 	case O_PRINTRTN:
1189681Slinton 	case O_PROCRTN:
1199681Slinton 	    p->value.sym = nextarg(Symbol);
1209681Slinton 	    break;
1219681Slinton 
12212548Scsvaf 	case O_DEBUG:
1239681Slinton 	case O_LCON:
12418236Slinton 	case O_CCON:
12511862Slinton 	case O_CONT:
12618236Slinton 	case O_CATCH:
12718236Slinton 	case O_IGNORE:
1289681Slinton 	case O_TRACEOFF:
1299681Slinton 	    p->value.lcon = nextarg(long);
1309681Slinton 	    break;
1319681Slinton 
1329681Slinton 	case O_FCON:
1339681Slinton 	    p->value.fcon = nextarg(double);
1349681Slinton 	    break;
1359681Slinton 
1369681Slinton 	case O_SCON:
1379681Slinton 	case O_CHFILE:
1389681Slinton 	case O_EDIT:
1399681Slinton 	case O_SOURCE:
1409681Slinton 	    p->value.scon = nextarg(String);
1419681Slinton 	    break;
1429681Slinton 
1439681Slinton 	case O_RVAL:
14418236Slinton 	case O_INDIR:
14518236Slinton 	    p->value.arg[0] = nextarg(Node);
1469681Slinton 	    break;
1479681Slinton 
14818236Slinton 	case O_CALL:
1499681Slinton 	    q = nextarg(Node);
15018236Slinton 	    if (q->op == O_SYM and
15118236Slinton 		(q->value.sym->class == TYPE or q->value.sym->class == TAG)
15218236Slinton 	    ) {
15318236Slinton 		p->op = O_TYPERENAME;
15418236Slinton 		p->value.arg[0] = nextarg(Node);
15518236Slinton 		p->value.arg[1] = q;
15618236Slinton 		q = p->value.arg[0];
15718236Slinton 		if (q->value.arg[1] != nil) {
15818236Slinton 		    error("too many arguments to type rename");
15918236Slinton 		}
1609681Slinton 		p->value.arg[0] = q->value.arg[0];
1619681Slinton 	    } else {
1629681Slinton 		p->value.arg[0] = q;
16318236Slinton 		p->value.arg[1] = nextarg(Node);
1649681Slinton 	    }
1659681Slinton 	    break;
1669681Slinton 
1679681Slinton 	case O_ADDEVENT:
1689681Slinton 	case O_ONCE:
1699681Slinton 	case O_IF:
1709681Slinton 	    p->value.event.cond = nextarg(Node);
1719681Slinton 	    p->value.event.actions = nextarg(Cmdlist);
1729681Slinton 	    break;
1739681Slinton 
1749681Slinton 	case O_TRACEON:
1759681Slinton 	    p->value.trace.inst = nextarg(Boolean);
1769681Slinton 	    p->value.trace.event = nil;
1779681Slinton 	    p->value.trace.actions = nextarg(Cmdlist);
1789681Slinton 	    break;
1799681Slinton 
1809681Slinton 	case O_STEP:
1819681Slinton 	    p->value.step.source = nextarg(Boolean);
1829681Slinton 	    p->value.step.skipcalls = nextarg(Boolean);
1839681Slinton 	    break;
1849681Slinton 
1859681Slinton 	case O_EXAMINE:
1869681Slinton 	    p->value.examine.mode = nextarg(String);
1879681Slinton 	    p->value.examine.beginaddr = nextarg(Node);
1889681Slinton 	    p->value.examine.endaddr = nextarg(Node);
1899681Slinton 	    p->value.examine.count = nextarg(Integer);
1909681Slinton 	    break;
1919681Slinton 
1929681Slinton 	default:
1939681Slinton 	    for (i = 0; i < nargs(op); i++) {
1949681Slinton 		p->value.arg[i] = nextarg(Node);
1959681Slinton 	    }
1969681Slinton 	    break;
1979681Slinton     }
1989681Slinton     check(p);
1999681Slinton     assigntypes(p);
20018236Slinton     if (tracetree) {
20118236Slinton 	printf("built %s node 0x%x with arg[0] 0x%x arg[1] 0x%x\n",
20218236Slinton 	    opname(p->op), p, p->value.arg[0], p->value.arg[1]);
20318236Slinton 	fflush(stdout);
20412548Scsvaf     }
2059681Slinton     return p;
2069681Slinton }
2079681Slinton 
2089681Slinton /*
20918236Slinton  * Strip away indirection from a node, thus returning a node for
21018236Slinton  * interpreting the expression as an lvalue.
2119681Slinton  */
2129681Slinton 
21318236Slinton public Node unrval (exp)
21418236Slinton Node exp;
2159681Slinton {
21618236Slinton     Node p;
21718236Slinton     Symbol t;
2189681Slinton 
21918236Slinton     if (exp->op == O_RVAL) {
22018236Slinton 	p = exp->value.arg[0];
22118236Slinton 	dispose(exp);
22218236Slinton     } else if (exp->op == O_INDIR) {
22318236Slinton 	p = exp->value.arg[0];
22418236Slinton 	if (p->op == O_RVAL) {
22518236Slinton 	    p->op = O_INDIR;
22618236Slinton 	    p->nodetype = exp->nodetype;
22718236Slinton 	}
22818236Slinton 	dispose(exp);
22918236Slinton     } else {
23018236Slinton 	p = exp;
23118236Slinton     }
23218236Slinton     return p;
2339681Slinton }
2349681Slinton 
2359681Slinton /*
23618236Slinton  * Create a node for renaming a node to a pointer type.
23718236Slinton  */
23818236Slinton 
23918236Slinton public Node renameptr (p, t)
24018236Slinton Node p;
24118236Slinton Node t;
24218236Slinton {
24318236Slinton     t->nodetype = newSymbol(nil, 0, PTR, t->nodetype, nil);
24418236Slinton     p = build(O_TYPERENAME, p, t);
24518236Slinton }
24618236Slinton 
24718236Slinton /*
2489681Slinton  * Return the tree for a unary ampersand operator.
2499681Slinton  */
2509681Slinton 
2519681Slinton public Node amper(p)
2529681Slinton Node p;
2539681Slinton {
2549681Slinton     Node r;
2559681Slinton 
2569681Slinton     checkref(p);
2579681Slinton     switch (p->op) {
2589681Slinton 	case O_RVAL:
25918236Slinton 	case O_INDIR:
2609681Slinton 	    r = p->value.arg[0];
26118236Slinton 	    r->nodetype = t_addr;
26218236Slinton 	    dispose(p);
2639681Slinton 	    break;
2649681Slinton 
26518236Slinton 	case O_TYPERENAME:
26618236Slinton 	    r = p;
26718236Slinton 	    r->nodetype = newSymbol(nil, 0, PTR, r->nodetype, nil);
26833339Sdonn 	    r->nodetype->language = p->nodetype->language;
2699681Slinton 	    break;
2709681Slinton 
2719681Slinton 	case O_SYM:
2729681Slinton 	    if (isblock(p->value.sym)) {
2739681Slinton 		r = build(O_LCON, codeloc(p->value.sym));
2749681Slinton 	    } else {
2759681Slinton 		r = build(O_LCON, address(p->value.sym, nil));
2769681Slinton 	    }
27718236Slinton 	    r->nodetype = t_addr;
27818236Slinton 	    dispose(p);
2799681Slinton 	    break;
2809681Slinton 
2819681Slinton 	case O_DOT:
2829681Slinton 	    r = p;
28318236Slinton 	    r->nodetype = t_addr;
2849681Slinton 	    break;
2859681Slinton 
2869681Slinton 	default:
2879681Slinton 	    beginerrmsg();
28818236Slinton 	    fprintf(stderr, "expected variable, found \"");
2899681Slinton 	    prtree(stderr, p);
29018236Slinton 	    fprintf(stderr, "\"");
2919681Slinton 	    tfree(p);
2929681Slinton 	    enderrmsg();
2939681Slinton 	    /* NOTREACHED */
2949681Slinton     }
2959681Slinton     return r;
2969681Slinton }
2979681Slinton 
2989681Slinton /*
2999681Slinton  * Create a "concrete" version of a node.
3009681Slinton  * This is necessary when the type of the node contains
3019681Slinton  * an unresolved type reference.
3029681Slinton  */
3039681Slinton 
3049681Slinton public Node concrete(p)
3059681Slinton Node p;
3069681Slinton {
3079681Slinton     findtype(p->nodetype);
3089681Slinton     return build(O_INDIR, p);
3099681Slinton }
3109681Slinton 
3119681Slinton /*
31218236Slinton  * Create a command list from a single command.
31318236Slinton  */
31418236Slinton 
31518236Slinton public Cmdlist buildcmdlist(cmd)
31618236Slinton Command cmd;
31718236Slinton {
31818236Slinton     Cmdlist cmdlist;
31918236Slinton 
32018236Slinton     cmdlist = list_alloc();
32118236Slinton     cmdlist_append(cmd, cmdlist);
32218236Slinton     return cmdlist;
32318236Slinton }
32418236Slinton 
32518236Slinton /*
3269681Slinton  * Print out a command.
3279681Slinton  */
3289681Slinton 
3299681Slinton public printcmd(f, cmd)
3309681Slinton File f;
3319681Slinton Command cmd;
3329681Slinton {
3339681Slinton     register Integer i;
3349681Slinton     register Command c;
3359681Slinton     register Node p;
3369681Slinton 
3379681Slinton     switch (cmd->op) {
3389681Slinton 	case O_PRINTIFCHANGED:
3399681Slinton 	case O_PRINTSRCPOS:
3409681Slinton 	case O_STOPIFCHANGED:
3419681Slinton 	case O_TRACEON:
3429681Slinton 	    break;
3439681Slinton 
3449681Slinton 	case O_STEP:
3459681Slinton 	    if (cmd->value.step.skipcalls) {
3469681Slinton 		fprintf(f, "next");
3479681Slinton 	    } else {
3489681Slinton 		fprintf(f, "step");
3499681Slinton 	    }
3509681Slinton 	    if (not cmd->value.step.source) {
3519681Slinton 		fprintf(f, "i");
3529681Slinton 	    }
3539681Slinton 	    break;
3549681Slinton 
3559681Slinton 	default:
3569681Slinton 	    fprintf(f, "%s", opinfo[ord(cmd->op)].opstring);
3579681Slinton 	    if (nargs(cmd->op) != 0) {
3589681Slinton 		fprintf(f, " ");
3599681Slinton 	    }
3609681Slinton 	    break;
3619681Slinton     }
3629681Slinton     switch (cmd->op) {
3639681Slinton 	case O_PRINTCALL:
3649681Slinton 	case O_PRINTRTN:
3659681Slinton 	case O_PROCRTN:
3669681Slinton 	    fprintf(f, "%s", symname(cmd->value.sym));
3679681Slinton 	    break;
3689681Slinton 
3699681Slinton 	case O_PRINTSRCPOS:
3709681Slinton 	    p = cmd->value.arg[0];
3719681Slinton 	    if (p != nil and p->op != O_QLINE) {
3729681Slinton 		printf("trace ");
3739681Slinton 		prtree(f, p);
3749681Slinton 	    }
3759681Slinton 	    break;
3769681Slinton 
3779681Slinton 	case O_CHFILE:
3789681Slinton 	case O_EDIT:
3799681Slinton 	case O_SOURCE:
3809681Slinton 	    fprintf(f, "%s", cmd->value.scon);
3819681Slinton 	    break;
3829681Slinton 
38318236Slinton 	case O_CATCH:
38418236Slinton 	case O_IGNORE:
3859681Slinton 	case O_TRACEOFF:
3869681Slinton 	    fprintf(f, "%d", cmd->value.lcon);
3879681Slinton 	    break;
3889681Slinton 
3899681Slinton 	case O_ADDEVENT:
3909681Slinton 	case O_ONCE:
3919681Slinton 	case O_IF:
3929681Slinton 	    fprintf(f, " ");
3939681Slinton 	    prtree(f, cmd->value.event.cond);
3949681Slinton 	    fprintf(f, " { ");
3959681Slinton 	    foreach (Command, c, cmd->value.event.actions)
3969681Slinton 		printcmd(f, c);
3979681Slinton 		if (not list_islast()) {
3989681Slinton 		    fprintf(f, ";");
3999681Slinton 		}
4009681Slinton 	    endfor
40130798Sbostic 	    fprintf(f, "%s }", opinfo[ord(cmd->op)].opstring);
4029681Slinton 	    break;
4039681Slinton 
4049681Slinton 	case O_TRACEON:
4059681Slinton 	    print_tracestop(f, cmd);
4069681Slinton 	    break;
4079681Slinton 
4089681Slinton 	case O_EXAMINE:
4099681Slinton 	    prtree(f, cmd->value.examine.beginaddr);
4109681Slinton 	    if (cmd->value.examine.endaddr != nil) {
4119681Slinton 		fprintf(f, ",");
4129681Slinton 		prtree(f, cmd->value.examine.endaddr);
4139681Slinton 	    }
4149681Slinton 	    fprintf(f, "/");
4159681Slinton 	    if (cmd->value.examine.count > 1) {
4169681Slinton 		fprintf(f, "%d", cmd->value.examine.count);
4179681Slinton 	    }
4189681Slinton 	    fprintf("%s", cmd->value.examine.mode);
4199681Slinton 	    break;
4209681Slinton 
4219681Slinton 	default:
4229681Slinton 	    if (nargs(cmd->op) != 0) {
4239681Slinton 		i = 0;
4249681Slinton 		for (;;) {
4259681Slinton 		    prtree(f, cmd->value.arg[i]);
4269681Slinton 		    ++i;
4279681Slinton 		if (i >= nargs(cmd->op)) break;
4289681Slinton 		    fprintf(f, " ");
4299681Slinton 		}
4309681Slinton 	    }
4319681Slinton 	    break;
4329681Slinton     }
4339681Slinton }
4349681Slinton 
4359681Slinton /*
4369681Slinton  * Print out a trace/stop command name.
4379681Slinton  */
4389681Slinton 
43914446Slinton #define fprintI(f, b) { if (b) fprintf(f, "i"); }
44014446Slinton 
4419681Slinton private print_tracestop(f, cmd)
4429681Slinton File f;
4439681Slinton Command cmd;
4449681Slinton {
4459681Slinton     register Command c, ifcmd, stopcmd;
4469681Slinton     Boolean done;
4479681Slinton 
4489681Slinton     done = false;
4499681Slinton     ifcmd = list_element(Command, list_head(cmd->value.trace.actions));
4509681Slinton     checkref(ifcmd);
4519681Slinton     if (ifcmd->op == O_IF) {
4529681Slinton 	stopcmd = list_element(Command, list_head(ifcmd->value.event.actions));
4539681Slinton 	checkref(stopcmd);
4549681Slinton 	if (stopcmd->op == O_STOPX) {
45514446Slinton 	    fprintf(f, "stop");
45614446Slinton 	    fprintI(f, cmd->value.trace.inst);
45714446Slinton 	    fprintf(f, " if ");
4589681Slinton 	    prtree(f, ifcmd->value.event.cond);
4599681Slinton 	    done = true;
4609681Slinton 	}
46114446Slinton     } else if (ifcmd->op == O_STOPIFCHANGED) {
46214446Slinton 	fprintf(f, "stop");
46314446Slinton 	fprintI(f, cmd->value.trace.inst);
46414446Slinton 	fprintf(f, " ");
46514446Slinton 	prtree(f, ifcmd->value.arg[0]);
46614446Slinton 	done = true;
4679681Slinton     }
4689681Slinton     if (not done) {
4699681Slinton 	fprintf(f, "%s ", cmd->value.trace.inst ? "tracei" : "trace");
4709681Slinton 	foreach (Command, c, cmd->value.trace.actions)
4719681Slinton 	    printcmd(f, c);
4729681Slinton 	    if (not list_islast()) {
4739681Slinton 		fprintf(f, ";");
4749681Slinton 	    }
4759681Slinton 	endfor
4769681Slinton     }
4779681Slinton }
4789681Slinton 
4799681Slinton /*
48014446Slinton  * Print out a tree.
4819681Slinton  */
4829681Slinton 
4839681Slinton public prtree(f, p)
4849681Slinton File f;
4859681Slinton register Node p;
4869681Slinton {
4879681Slinton     register Node q;
4889681Slinton     Operator op;
4899681Slinton 
4909681Slinton     if (p != nil) {
4919681Slinton 	op = p->op;
4929681Slinton 	if (ord(op) > ord(O_LASTOP)) {
4939681Slinton 	    panic("bad op %d in prtree", p->op);
4949681Slinton 	}
4959681Slinton 	switch (op) {
4969681Slinton 	    case O_NAME:
4979681Slinton 		fprintf(f, "%s", ident(p->value.name));
4989681Slinton 		break;
4999681Slinton 
5009681Slinton 	    case O_SYM:
5019681Slinton 		printname(f, p->value.sym);
5029681Slinton 		break;
5039681Slinton 
5049681Slinton 	    case O_QLINE:
5059681Slinton 		if (nlhdr.nfiles > 1) {
5069681Slinton 		    prtree(f, p->value.arg[0]);
5079681Slinton 		    fprintf(f, ":");
5089681Slinton 		}
5099681Slinton 		prtree(f, p->value.arg[1]);
5109681Slinton 		break;
5119681Slinton 
5129681Slinton 	    case O_LCON:
51318236Slinton 		fprintf(f, "%d", p->value.lcon);
5149681Slinton 		break;
5159681Slinton 
51618236Slinton 	    case O_CCON:
51718236Slinton 		fprintf(f, "'%c'", p->value.lcon);
51818236Slinton 		break;
51918236Slinton 
5209681Slinton 	    case O_FCON:
5219681Slinton 		fprintf(f, "%g", p->value.fcon);
5229681Slinton 		break;
5239681Slinton 
5249681Slinton 	    case O_SCON:
5259681Slinton 		fprintf(f, "\"%s\"", p->value.scon);
5269681Slinton 		break;
5279681Slinton 
5289681Slinton 	    case O_INDEX:
5299681Slinton 		prtree(f, p->value.arg[0]);
5309681Slinton 		fprintf(f, "[");
5319681Slinton 		prtree(f, p->value.arg[1]);
5329681Slinton 		fprintf(f, "]");
5339681Slinton 		break;
5349681Slinton 
5359681Slinton 	    case O_COMMA:
5369681Slinton 		prtree(f, p->value.arg[0]);
5379681Slinton 		if (p->value.arg[1] != nil) {
5389681Slinton 		    fprintf(f, ", ");
5399681Slinton 		    prtree(f, p->value.arg[1]);
5409681Slinton 		}
5419681Slinton 		break;
5429681Slinton 
5439681Slinton 	    case O_RVAL:
5449681Slinton 	    case O_ITOF:
5459681Slinton 		prtree(f, p->value.arg[0]);
5469681Slinton 		break;
5479681Slinton 
5489681Slinton 	    case O_CALL:
5499681Slinton 		prtree(f, p->value.arg[0]);
5509681Slinton 		if (p->value.arg[1]!= nil) {
5519681Slinton 		    fprintf(f, "(");
5529681Slinton 		    prtree(f, p->value.arg[1]);
5539681Slinton 		    fprintf(f, ")");
5549681Slinton 		}
5559681Slinton 		break;
5569681Slinton 
5579681Slinton 	    case O_INDIR:
55818236Slinton 		prtree(f, p->value.arg[0]);
55918236Slinton 		fprintf(f, "^");
5609681Slinton 		break;
5619681Slinton 
5629681Slinton 	    case O_DOT:
56318236Slinton 		prtree(f, p->value.arg[0]);
5649681Slinton 		fprintf(f, ".%s", symname(p->value.arg[1]->value.sym));
5659681Slinton 		break;
5669681Slinton 
56718236Slinton 	    case O_TYPERENAME:
56818236Slinton 		prtree(f, p->value.arg[1]);
56918236Slinton 		fprintf(f, "(");
57018236Slinton 		prtree(f, p->value.arg[0]);
57118236Slinton 		fprintf(f, ")");
57218236Slinton 		break;
57318236Slinton 
5749681Slinton 	    default:
5759681Slinton 		switch (degree(op)) {
5769681Slinton 		    case BINARY:
5779681Slinton 			prtree(f, p->value.arg[0]);
5789681Slinton 			fprintf(f, "%s", opinfo[ord(op)].opstring);
5799681Slinton 			prtree(f, p->value.arg[1]);
5809681Slinton 			break;
5819681Slinton 
5829681Slinton 		    case UNARY:
5839681Slinton 			fprintf(f, "%s", opinfo[ord(op)].opstring);
5849681Slinton 			prtree(f, p->value.arg[0]);
5859681Slinton 			break;
5869681Slinton 
5879681Slinton 		    default:
58818236Slinton 			if (opinfo[ord(op)].opstring == nil) {
58918236Slinton 			    fprintf(f, "[op %d]", ord(op));
59018236Slinton 			} else {
59118236Slinton 			    fprintf(f, "%s", opinfo[ord(op)].opstring);
59218236Slinton 			}
59318236Slinton 			break;
5949681Slinton 		}
5959681Slinton 		break;
5969681Slinton 	}
5979681Slinton     }
5989681Slinton }
5999681Slinton 
6009681Slinton /*
6019681Slinton  * Free storage associated with a tree.
6029681Slinton  */
6039681Slinton 
6049681Slinton public tfree(p)
6059681Slinton Node p;
6069681Slinton {
6079681Slinton     Integer i;
6089681Slinton 
6099681Slinton     if (p == nil) {
6109681Slinton 	return;
6119681Slinton     }
6129681Slinton     switch (p->op) {
6139681Slinton 	case O_QLINE:
6149681Slinton 	    dispose(p->value.arg[0]->value.scon);
6159681Slinton 	    dispose(p->value.arg[0]);
6169681Slinton 	    tfree(p->value.arg[1]);
6179681Slinton 	    break;
6189681Slinton 
6199681Slinton 	case O_SCON:
6209681Slinton 	    unmkstring(p->nodetype);
6219681Slinton 	    dispose(p->nodetype);
6229681Slinton 	    dispose(p->value.scon);
6239681Slinton 	    break;
6249681Slinton 
6259681Slinton 	default:
6269681Slinton 	    for (i = 0; i < nargs(p->op); i++) {
6279681Slinton 		tfree(p->value.arg[i]);
6289681Slinton 	    }
6299681Slinton 	    break;
6309681Slinton     }
6319681Slinton     dispose(p);
6329681Slinton }
633