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