BSD 4_3 release
[unix-history] / usr / src / ucb / dbx / tree.c
/*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef lint
static char sccsid[] = "@(#)tree.c 5.1 (Berkeley) 5/31/85";
#endif not lint
static char rcsid[] = "$Header: tree.c,v 1.5 84/12/26 10:42:55 linton Exp $";
/*
* Parse tree management.
*/
#include "defs.h"
#include "tree.h"
#include "operators.h"
#include "debug.h"
#include "eval.h"
#include "events.h"
#include "symbols.h"
#include "scanner.h"
#include "source.h"
#include "object.h"
#include "mappings.h"
#include "process.h"
#include "machine.h"
#ifndef public
#include "lists.h"
typedef struct Node *Node;
typedef Node Command;
typedef List Cmdlist;
#include "operators.h"
#include "symbols.h"
#include "events.h"
#define MAXNARGS 5
struct Node {
Operator op;
Symbol nodetype;
union treevalue {
Symbol sym;
Name name;
long lcon;
double fcon;
String scon;
Node arg[MAXNARGS];
struct {
Node cond;
Cmdlist actions;
} event;
struct {
Boolean inst;
Event event;
Cmdlist actions;
} trace;
struct {
Boolean source;
Boolean skipcalls;
} step;
struct {
String mode;
Node beginaddr;
Node endaddr;
Integer count;
} examine;
} value;
};
#define evalcmd(cmd) eval(cmd)
#define cmdlist_append(cmd, cl) list_append(list_item(cmd), nil, cl)
#endif
typedef char *Arglist;
#define nextarg(type) ((type *) (ap += sizeof(type)))[-1]
/*
* Build a tree.
*/
/* VARARGS1 */
public Node build(op, args)
Operator op;
{
register Node p, q;
register Arglist ap;
Integer i;
p = new(Node);
p->op = op;
p->nodetype = nil;
ap = (Arglist) &args;
switch (op) {
case O_NAME:
p->value.name = nextarg(Name);
break;
case O_SYM:
case O_PRINTCALL:
case O_PRINTRTN:
case O_PROCRTN:
p->value.sym = nextarg(Symbol);
break;
case O_DEBUG:
case O_LCON:
case O_CCON:
case O_CONT:
case O_CATCH:
case O_IGNORE:
case O_TRACEOFF:
p->value.lcon = nextarg(long);
break;
case O_FCON:
p->value.fcon = nextarg(double);
break;
case O_SCON:
case O_CHFILE:
case O_EDIT:
case O_SOURCE:
p->value.scon = nextarg(String);
break;
case O_RVAL:
case O_INDIR:
p->value.arg[0] = nextarg(Node);
break;
case O_CALL:
q = nextarg(Node);
if (q->op == O_SYM and
(q->value.sym->class == TYPE or q->value.sym->class == TAG)
) {
p->op = O_TYPERENAME;
p->value.arg[0] = nextarg(Node);
p->value.arg[1] = q;
q = p->value.arg[0];
if (q->value.arg[1] != nil) {
error("too many arguments to type rename");
}
p->value.arg[0] = q->value.arg[0];
} else {
p->value.arg[0] = q;
p->value.arg[1] = nextarg(Node);
}
break;
case O_ADDEVENT:
case O_ONCE:
case O_IF:
p->value.event.cond = nextarg(Node);
p->value.event.actions = nextarg(Cmdlist);
break;
case O_TRACEON:
p->value.trace.inst = nextarg(Boolean);
p->value.trace.event = nil;
p->value.trace.actions = nextarg(Cmdlist);
break;
case O_STEP:
p->value.step.source = nextarg(Boolean);
p->value.step.skipcalls = nextarg(Boolean);
break;
case O_EXAMINE:
p->value.examine.mode = nextarg(String);
p->value.examine.beginaddr = nextarg(Node);
p->value.examine.endaddr = nextarg(Node);
p->value.examine.count = nextarg(Integer);
break;
default:
for (i = 0; i < nargs(op); i++) {
p->value.arg[i] = nextarg(Node);
}
break;
}
check(p);
assigntypes(p);
if (tracetree) {
printf("built %s node 0x%x with arg[0] 0x%x arg[1] 0x%x\n",
opname(p->op), p, p->value.arg[0], p->value.arg[1]);
fflush(stdout);
}
return p;
}
/*
* Strip away indirection from a node, thus returning a node for
* interpreting the expression as an lvalue.
*/
public Node unrval (exp)
Node exp;
{
Node p;
Symbol t;
if (exp->op == O_RVAL) {
p = exp->value.arg[0];
dispose(exp);
} else if (exp->op == O_INDIR) {
p = exp->value.arg[0];
if (p->op == O_RVAL) {
p->op = O_INDIR;
p->nodetype = exp->nodetype;
}
dispose(exp);
} else {
p = exp;
}
return p;
}
/*
* Create a node for renaming a node to a pointer type.
*/
public Node renameptr (p, t)
Node p;
Node t;
{
t->nodetype = newSymbol(nil, 0, PTR, t->nodetype, nil);
p = build(O_TYPERENAME, p, t);
}
/*
* Return the tree for a unary ampersand operator.
*/
public Node amper(p)
Node p;
{
Node r;
checkref(p);
switch (p->op) {
case O_RVAL:
case O_INDIR:
r = p->value.arg[0];
r->nodetype = t_addr;
dispose(p);
break;
case O_TYPERENAME:
r = p;
r->nodetype = newSymbol(nil, 0, PTR, r->nodetype, nil);
break;
case O_SYM:
if (isblock(p->value.sym)) {
r = build(O_LCON, codeloc(p->value.sym));
} else {
r = build(O_LCON, address(p->value.sym, nil));
}
r->nodetype = t_addr;
dispose(p);
break;
case O_DOT:
r = p;
r->nodetype = t_addr;
break;
default:
beginerrmsg();
fprintf(stderr, "expected variable, found \"");
prtree(stderr, p);
fprintf(stderr, "\"");
tfree(p);
enderrmsg();
/* NOTREACHED */
}
return r;
}
/*
* Create a "concrete" version of a node.
* This is necessary when the type of the node contains
* an unresolved type reference.
*/
public Node concrete(p)
Node p;
{
findtype(p->nodetype);
return build(O_INDIR, p);
}
/*
* Create a command list from a single command.
*/
public Cmdlist buildcmdlist(cmd)
Command cmd;
{
Cmdlist cmdlist;
cmdlist = list_alloc();
cmdlist_append(cmd, cmdlist);
return cmdlist;
}
/*
* Print out a command.
*/
public printcmd(f, cmd)
File f;
Command cmd;
{
register Integer i;
register Command c;
register Node p;
switch (cmd->op) {
case O_PRINTIFCHANGED:
case O_PRINTSRCPOS:
case O_STOPIFCHANGED:
case O_TRACEON:
break;
case O_STEP:
if (cmd->value.step.skipcalls) {
fprintf(f, "next");
} else {
fprintf(f, "step");
}
if (not cmd->value.step.source) {
fprintf(f, "i");
}
break;
default:
fprintf(f, "%s", opinfo[ord(cmd->op)].opstring);
if (nargs(cmd->op) != 0) {
fprintf(f, " ");
}
break;
}
switch (cmd->op) {
case O_PRINTCALL:
case O_PRINTRTN:
case O_PROCRTN:
fprintf(f, "%s", symname(cmd->value.sym));
break;
case O_PRINTSRCPOS:
p = cmd->value.arg[0];
if (p != nil and p->op != O_QLINE) {
printf("trace ");
prtree(f, p);
}
break;
case O_CHFILE:
case O_EDIT:
case O_SOURCE:
fprintf(f, "%s", cmd->value.scon);
break;
case O_CATCH:
case O_IGNORE:
case O_TRACEOFF:
fprintf(f, "%d", cmd->value.lcon);
break;
case O_ADDEVENT:
case O_ONCE:
case O_IF:
fprintf(f, " ");
prtree(f, cmd->value.event.cond);
fprintf(f, " { ");
foreach (Command, c, cmd->value.event.actions)
printcmd(f, c);
if (not list_islast()) {
fprintf(f, ";");
}
endfor
fprintf(f, " }", opinfo[ord(cmd->op)].opstring);
break;
case O_TRACEON:
print_tracestop(f, cmd);
break;
case O_EXAMINE:
prtree(f, cmd->value.examine.beginaddr);
if (cmd->value.examine.endaddr != nil) {
fprintf(f, ",");
prtree(f, cmd->value.examine.endaddr);
}
fprintf(f, "/");
if (cmd->value.examine.count > 1) {
fprintf(f, "%d", cmd->value.examine.count);
}
fprintf("%s", cmd->value.examine.mode);
break;
default:
if (nargs(cmd->op) != 0) {
i = 0;
for (;;) {
prtree(f, cmd->value.arg[i]);
++i;
if (i >= nargs(cmd->op)) break;
fprintf(f, " ");
}
}
break;
}
}
/*
* Print out a trace/stop command name.
*/
#define fprintI(f, b) { if (b) fprintf(f, "i"); }
private print_tracestop(f, cmd)
File f;
Command cmd;
{
register Command c, ifcmd, stopcmd;
Boolean done;
done = false;
ifcmd = list_element(Command, list_head(cmd->value.trace.actions));
checkref(ifcmd);
if (ifcmd->op == O_IF) {
stopcmd = list_element(Command, list_head(ifcmd->value.event.actions));
checkref(stopcmd);
if (stopcmd->op == O_STOPX) {
fprintf(f, "stop");
fprintI(f, cmd->value.trace.inst);
fprintf(f, " if ");
prtree(f, ifcmd->value.event.cond);
done = true;
}
} else if (ifcmd->op == O_STOPIFCHANGED) {
fprintf(f, "stop");
fprintI(f, cmd->value.trace.inst);
fprintf(f, " ");
prtree(f, ifcmd->value.arg[0]);
done = true;
}
if (not done) {
fprintf(f, "%s ", cmd->value.trace.inst ? "tracei" : "trace");
foreach (Command, c, cmd->value.trace.actions)
printcmd(f, c);
if (not list_islast()) {
fprintf(f, ";");
}
endfor
}
}
/*
* Print out a tree.
*/
public prtree(f, p)
File f;
register Node p;
{
register Node q;
Operator op;
if (p != nil) {
op = p->op;
if (ord(op) > ord(O_LASTOP)) {
panic("bad op %d in prtree", p->op);
}
switch (op) {
case O_NAME:
fprintf(f, "%s", ident(p->value.name));
break;
case O_SYM:
printname(f, p->value.sym);
break;
case O_QLINE:
if (nlhdr.nfiles > 1) {
prtree(f, p->value.arg[0]);
fprintf(f, ":");
}
prtree(f, p->value.arg[1]);
break;
case O_LCON:
fprintf(f, "%d", p->value.lcon);
break;
case O_CCON:
fprintf(f, "'%c'", p->value.lcon);
break;
case O_FCON:
fprintf(f, "%g", p->value.fcon);
break;
case O_SCON:
fprintf(f, "\"%s\"", p->value.scon);
break;
case O_INDEX:
prtree(f, p->value.arg[0]);
fprintf(f, "[");
prtree(f, p->value.arg[1]);
fprintf(f, "]");
break;
case O_COMMA:
prtree(f, p->value.arg[0]);
if (p->value.arg[1] != nil) {
fprintf(f, ", ");
prtree(f, p->value.arg[1]);
}
break;
case O_RVAL:
case O_ITOF:
prtree(f, p->value.arg[0]);
break;
case O_CALL:
prtree(f, p->value.arg[0]);
if (p->value.arg[1]!= nil) {
fprintf(f, "(");
prtree(f, p->value.arg[1]);
fprintf(f, ")");
}
break;
case O_INDIR:
prtree(f, p->value.arg[0]);
fprintf(f, "^");
break;
case O_DOT:
prtree(f, p->value.arg[0]);
fprintf(f, ".%s", symname(p->value.arg[1]->value.sym));
break;
case O_TYPERENAME:
prtree(f, p->value.arg[1]);
fprintf(f, "(");
prtree(f, p->value.arg[0]);
fprintf(f, ")");
break;
default:
switch (degree(op)) {
case BINARY:
prtree(f, p->value.arg[0]);
fprintf(f, "%s", opinfo[ord(op)].opstring);
prtree(f, p->value.arg[1]);
break;
case UNARY:
fprintf(f, "%s", opinfo[ord(op)].opstring);
prtree(f, p->value.arg[0]);
break;
default:
if (opinfo[ord(op)].opstring == nil) {
fprintf(f, "[op %d]", ord(op));
} else {
fprintf(f, "%s", opinfo[ord(op)].opstring);
}
break;
}
break;
}
}
}
/*
* Free storage associated with a tree.
*/
public tfree(p)
Node p;
{
Integer i;
if (p == nil) {
return;
}
switch (p->op) {
case O_QLINE:
dispose(p->value.arg[0]->value.scon);
dispose(p->value.arg[0]);
tfree(p->value.arg[1]);
break;
case O_SCON:
unmkstring(p->nodetype);
dispose(p->nodetype);
dispose(p->value.scon);
break;
default:
for (i = 0; i < nargs(p->op); i++) {
tfree(p->value.arg[i]);
}
break;
}
dispose(p);
}