|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)match.c 1.1 86/02/03 SMI"; ! 3: #endif ! 4: ! 5: # include "cpass2.h" ! 6: ! 7: # ifdef WCARD1 ! 8: # ifdef WCARD2 ! 9: # define NOINDIRECT ! 10: # endif ! 11: # endif ! 12: ! 13: extern vdebug; ! 14: ! 15: int fldsz, fldshf; ! 16: ! 17: int mamask[] = { /* masks for matching dope with shapes */ ! 18: SIMPFLG, /* OPSIMP */ ! 19: SIMPFLG|ASGFLG, /* ASG OPSIMP */ ! 20: COMMFLG, /* OPCOMM */ ! 21: COMMFLG|ASGFLG, /* ASG OPCOMM */ ! 22: MULFLG, /* OPMUL */ ! 23: MULFLG|ASGFLG, /* ASG OPMUL */ ! 24: DIVFLG, /* OPDIV */ ! 25: DIVFLG|ASGFLG, /* ASG OPDIV */ ! 26: UTYPE, /* OPUNARY */ ! 27: TYFLG, /* ASG OPUNARY is senseless */ ! 28: LTYPE, /* OPLEAF */ ! 29: TYFLG, /* ASG OPLEAF is senseless */ ! 30: 0, /* OPANY */ ! 31: ASGOPFLG|ASGFLG,/* ASG OPANY */ ! 32: LOGFLG, /* OPLOG */ ! 33: TYFLG, /* ASG OPLOG is senseless */ ! 34: FLOFLG, /* OPFLOAT */ ! 35: FLOFLG|ASGFLG, /* ASG OPFLOAT */ ! 36: SHFFLG, /* OPSHFT */ ! 37: SHFFLG|ASGFLG, /* ASG OPSHIFT */ ! 38: SPFLG, /* OPLTYPE */ ! 39: TYFLG, /* ASG OPLTYPE is senseless */ ! 40: INTRFLG, /* OPINTR */ ! 41: TYFLG, /* ASG OPINTR is senseless */ ! 42: }; ! 43: ! 44: int sdebug = 0; ! 45: ! 46: tshape( p, shape ) ! 47: register NODE *p; ! 48: { ! 49: /* ! 50: * return true if shape is appropriate for the node p ! 51: * side effect for SFLD is to set up fldsz,etc ! 52: */ ! 53: register o, mask; ! 54: register lval; ! 55: ! 56: o = p->in.op; ! 57: ! 58: # ifndef BUG3 ! 59: if ( sdebug ){ ! 60: printf( "tshape( %o, %o), op = %d\n", p, shape, o ); ! 61: } ! 62: # endif ! 63: ! 64: if ( shape & SPECIAL ){ ! 65: switch ( shape ){ ! 66: case SZERO: ! 67: if ( o != ICON || p->in.name[0] ) return(0); ! 68: return(p->tn.lval == 0); ! 69: case SONE: ! 70: if ( o != ICON || p->in.name[0] ) return(0); ! 71: return(p->tn.lval == 1); ! 72: case SMONE: ! 73: if ( o != ICON || p->in.name[0] ) return(0); ! 74: return(p->tn.lval == -1); ! 75: case SSCON: ! 76: if ( o != ICON || p->in.name[0] ) return(0); ! 77: lval = p->tn.lval; ! 78: return(lval >= -32768 && lval <= 32767); ! 79: case SCCON: ! 80: if ( o != ICON || p->in.name[0] ) return(0); ! 81: lval = p->tn.lval; ! 82: return(lval >= -128 && lval <= 127); ! 83: case SSOREG: /* non-indexed OREG */ ! 84: return(o == OREG && !R2TEST(p->tn.rval)); ! 85: ! 86: default: ! 87: # ifdef MULTILEVEL ! 88: if ( shape & MULTILEVEL ) ! 89: return( mlmatch(p,shape,0) ); ! 90: else ! 91: # endif ! 92: return (special( p, shape )); ! 93: } ! 94: } ! 95: if ( shape & SANY ) return(1); ! 96: if ( (shape&INTEMP) && shtemp(p) ) return(1); ! 97: if ( (shape&SWADD) && (o==NAME||o==OREG) ){ ! 98: if ( BYTEOFF(p->tn.lval) ) return(0); ! 99: } ! 100: ! 101: # ifdef WCARD1 ! 102: if ( shape & WCARD1 ) ! 103: return( wcard1(p) & shape ); ! 104: # endif ! 105: ! 106: # ifdef WCARD2 ! 107: if ( shape & WCARD2 ) ! 108: return( wcard2(p) & shape ); ! 109: # endif ! 110: switch( o ){ ! 111: case NAME: ! 112: return( shape&SNAME ); ! 113: case FCON: ! 114: case ICON: ! 115: mask = SCON; ! 116: return( shape & mask ); ! 117: case FLD: ! 118: if ( shape & SFLD ){ ! 119: if ( !flshape( p->in.left ) ) return(0); ! 120: /* it is a FIELD shape; make side-effects */ ! 121: o = p->tn.rval; ! 122: fldsz = UPKFSZ(o); ! 123: # ifdef RTOLBYTES ! 124: fldshf = UPKFOFF(o); ! 125: # else ! 126: fldshf = SZINT - fldsz - UPKFOFF(o); ! 127: # endif ! 128: return(1); ! 129: } ! 130: return(0); ! 131: case FCCODES: ! 132: case CCODES: ! 133: return( shape&SCC ); ! 134: case REG: ! 135: /* distinctions: ! 136: * SAREG any scalar register ! 137: * STAREG any temporary scalar register ! 138: * SBREG any lvalue (index) register ! 139: * STBREG any temporary lvalue register ! 140: * SCREG any floating register ! 141: * STCREG any temporary floating register ! 142: */ ! 143: if (isbreg( p->tn.rval )) ! 144: mask = SBREG; ! 145: else if (iscreg( p->tn.rval )) ! 146: mask = SCREG; ! 147: else ! 148: mask = SAREG; ! 149: if ( istreg( p->tn.rval ) && busy[p->tn.rval]<=1 ) { ! 150: if (mask==SAREG) ! 151: mask |= STAREG; ! 152: else if (mask==SBREG) ! 153: mask |= STBREG; ! 154: else ! 155: mask |= STCREG; ! 156: } ! 157: return( shape & mask ); ! 158: case OREG: ! 159: return( shape & SOREG ); ! 160: ! 161: # ifndef NOINDIRECT ! 162: case UNARY MUL: ! 163: /* return STARNM or STARREG or 0 */ ! 164: return( shumul(p->in.left) & shape ); ! 165: # endif ! 166: ! 167: } ! 168: ! 169: return(0); ! 170: } ! 171: ! 172: int tdebug = 0; ! 173: ! 174: ttype( t, tword ) ! 175: register TWORD t; ! 176: register tword; ! 177: { ! 178: /* does the type t match tword */ ! 179: ! 180: if ( tword & TANY ) return(1); ! 181: if ( t == UNDEF ) t=INT; /* void functions eased thru tables */ ! 182: # ifndef BUG3 ! 183: if ( tdebug ){ ! 184: printf( "ttype( %o, %o )\n", t, tword ); ! 185: } ! 186: # endif ! 187: if ( ISPTR(t) && (tword&TPTRTO) ) { ! 188: do { ! 189: t = DECREF(t); ! 190: } while ( ISARY(t) ); ! 191: /* arrays that are left are usually only ! 192: in structure references... */ ! 193: return( ttype( t, tword&(~TPTRTO) ) ); ! 194: } ! 195: if ( t != BTYPE(t) ) ! 196: return( tword & TPOINT ); /* TPOINT means not simple! */ ! 197: if ( tword & TPTRTO ) return(0); ! 198: switch( t ){ ! 199: case CHAR: ! 200: return( tword & TCHAR ); ! 201: case SHORT: ! 202: return( tword & TSHORT ); ! 203: case STRTY: ! 204: case UNIONTY: ! 205: return( tword & TSTRUCT ); ! 206: case INT: ! 207: return( tword & TINT ); ! 208: case UNSIGNED: ! 209: return( tword & TUNSIGNED ); ! 210: case USHORT: ! 211: return( tword & TUSHORT ); ! 212: case UCHAR: ! 213: return( tword & TUCHAR ); ! 214: case ULONG: ! 215: return( tword & TULONG ); ! 216: case LONG: ! 217: return( tword & TLONG ); ! 218: case FLOAT: ! 219: return( tword & TFLOAT ); ! 220: case DOUBLE: ! 221: return( tword & TDOUBLE ); ! 222: } ! 223: return(0); ! 224: } ! 225: ! 226: #define MAXOPSET 2000 ! 227: ! 228: struct opvect { ! 229: struct optab **first; ! 230: struct optab **rewrite; ! 231: }; ! 232: ! 233: struct opvect opvect[DSIZE]; ! 234: struct optab *opsets[MAXOPSET]; ! 235: ! 236: static struct optab **firstelement= opsets; ! 237: static struct optab **nextelement = opsets; ! 238: ! 239: extern int opmatch(/* op, targetop */); /* returns 1 if op matches targetop */ ! 240: ! 241: /* ! 242: * setrew() ! 243: * Generates sets of templates to be examined by match(), one ! 244: * for each operator in 0..DSIZE. The sets are represented as ! 245: * vectors of pointers into the code table. The sets could be ! 246: * constructed by a separate program when the compiler is compiled, ! 247: * but doing it at startup enables us to deal more conveniently ! 248: * with user-selected processor options (e.g., -m68020 -m68881) ! 249: */ ! 250: ! 251: setrew() ! 252: { ! 253: register struct optab *q; ! 254: register int op; ! 255: register struct optab **nextel = nextelement; ! 256: register struct optab **firstel = firstelement; ! 257: ! 258: for( op = 0; op < DSIZE; ++op ) { ! 259: if (dope[op]) { ! 260: /* ! 261: * operator exists; ! 262: * scan table for matching templates ! 263: */ ! 264: register struct optab **firstrew; ! 265: firstrew = (struct optab**)NULL; ! 266: for (q = table; q->op != FREE; q++) { ! 267: if (opmatch(op, q->op)) { ! 268: if (q->needs == REWRITE) { ! 269: if (!firstrew) { ! 270: firstrew = nextel; ! 271: } ! 272: } ! 273: *nextel++ = q; ! 274: } ! 275: } ! 276: if (nextel-opsets >= MAXOPSET) { ! 277: cerror("too many opsets (%d)", ! 278: nextel-opsets); ! 279: } ! 280: opvect[op].first = firstel; ! 281: opvect[op].rewrite = firstrew; ! 282: *nextel++ = (struct optab*)NULL; ! 283: firstel = nextel; ! 284: } else { ! 285: /* no operator */ ! 286: opvect[op].first = (struct optab**)NULL; ! 287: opvect[op].rewrite = (struct optab**)NULL; ! 288: } /* else */ ! 289: } /* for each op */ ! 290: nextelement = nextel; ! 291: firstelement = firstel; ! 292: } /* setrew */ ! 293: ! 294: match( p, cookie ) ! 295: NODE *p; ! 296: { ! 297: /* ! 298: * called by: order, gencall ! 299: * look for match in table and generate code if found unless ! 300: * entry specified REWRITE. ! 301: * returns MDONE, MNOPE, or rewrite specification from table ! 302: */ ! 303: ! 304: register struct optab **opset; ! 305: register struct optab *q; ! 306: register op; ! 307: register NODE *r; ! 308: ! 309: rcount(); ! 310: op = p->in.op; ! 311: if (cookie == FORREW) { ! 312: opset = opvect[op].rewrite; ! 313: } else { ! 314: opset = opvect[op].first; ! 315: /* ! 316: * finish the special-case test for autoincrement trees ! 317: */ ! 318: if (op == UNARY MUL && !shumul(p->in.left)) { ! 319: return(MNOPE); ! 320: } ! 321: } ! 322: if (opset == (struct optab**)NULL) { ! 323: cerror("no template for op '%s'", opst[op]); ! 324: } ! 325: for (q = *opset++; q != (struct optab *)NULL; q = *opset++) { ! 326: ! 327: /* see if goal matches */ ! 328: if ( !(q->visit & cookie ) ) continue; ! 329: ! 330: /* see if left child matches */ ! 331: r = ( optype( op ) == LTYPE ? p : p->in.left ); ! 332: if ( !tshape( r, q->lshape ) ) ! 333: continue; ! 334: if ( !ttype( r->in.type, q->ltype ) ) ! 335: continue; ! 336: ! 337: /* see if right child matches */ ! 338: r = ( optype( op ) != BITYPE ? p : p->in.right ); ! 339: if ( !tshape( r, q->rshape ) ) ! 340: continue; ! 341: if ( !ttype( r->in.type, q->rtype ) ) ! 342: continue; ! 343: ! 344: /* ! 345: * REWRITE means no code from this match but go ahead ! 346: * and rewrite node to help future match. ! 347: */ ! 348: if ( q->needs & REWRITE ) ! 349: return( q->rewrite ); ! 350: if ( !allo( p, q ) ) ! 351: continue; /* if can't generate code, skip entry */ ! 352: ! 353: /* resources are available */ ! 354: ! 355: /* generate code */ ! 356: expand( p, cookie, q->cstring ); ! 357: reclaim( p, q->rewrite, cookie ); ! 358: ! 359: return(MDONE); ! 360: ! 361: } ! 362: ! 363: return(MNOPE); ! 364: } ! 365: ! 366: int rtyflg = 0; ! 367: ! 368: expand( p, cookie, cp ) ! 369: NODE *p; ! 370: register char *cp; ! 371: { ! 372: /* generate code by interpreting table entry */ ! 373: ! 374: register char c; ! 375: CONSZ val; ! 376: ! 377: rtyflg = 0; ! 378: ! 379: for( ; *cp; ++cp ){ ! 380: switch( *cp ){ ! 381: ! 382: case '\\': ! 383: cp++; ! 384: /* FALL THROUGH */ ! 385: default: ! 386: PUTCHAR( *cp ); ! 387: continue; /* this is the usual case... */ ! 388: case 'T': ! 389: /* rewrite register type is suppressed */ ! 390: rtyflg = 1; ! 391: continue; ! 392: ! 393: case 'Z': /* special machine dependent operations */ ! 394: # ifdef NEWZZZ ! 395: switch( c = *++cp ) { ! 396: ! 397: case '1': ! 398: case '2': ! 399: case '3': ! 400: case 'R': ! 401: case 'L': /* get down first */ ! 402: zzzcode( getlr( p, c ), *++cp ); ! 403: break; ! 404: default: /* normal zzzcode processing otherwise */ ! 405: zzzcode( p, c ); ! 406: break; ! 407: } ! 408: # else ! 409: zzzcode( p, *++cp, cookie ); ! 410: # endif ! 411: continue; ! 412: ! 413: case 'F': /* this line deleted if FOREFF is active */ ! 414: if ( cookie & FOREFF ) ! 415: while( *++cp != '\n' ) ! 416: ; /* VOID */ ! 417: continue; ! 418: ! 419: #ifdef undef ! 420: case 'R': /* this line deleted if descendent is already in a temp register */ ! 421: { ! 422: NODE * t; ! 423: ! 424: t = getlr(p, *++cp ); ! 425: if ( istnode(t) ) ! 426: while( *++cp != '\n' ) ! 427: ; /* VOID */ ! 428: continue; ! 429: } ! 430: #endif sun ! 431: case 'S': /* field size */ ! 432: print_d(fldsz ); ! 433: continue; ! 434: ! 435: case 'H': /* field shift */ ! 436: print_d( fldshf ); ! 437: continue; ! 438: ! 439: case 'M': /* field mask */ ! 440: case 'N': /* complement of field mask */ ! 441: val = 1; ! 442: val <<= fldsz; ! 443: --val; ! 444: val <<= fldshf; ! 445: adrcon( *cp=='M' ? val : ~val ); ! 446: continue; ! 447: ! 448: case 'L': /* output special label field */ ! 449: print_d( p->bn.label ); ! 450: continue; ! 451: ! 452: case 'O': /* opcode string */ ! 453: hopcode( *++cp, p->in.op ); ! 454: continue; ! 455: ! 456: case 'B': /* byte offset in word */ ! 457: val = getlr(p,*++cp)->tn.lval; ! 458: val = BYTEOFF(val); ! 459: printf( CONFMT, val ); ! 460: continue; ! 461: ! 462: case 'C': /* for constant value only */ ! 463: conput( getlr( p, *++cp ) ); ! 464: continue; ! 465: ! 466: case 'I': /* in instruction */ ! 467: insput( getlr( p, *++cp ) ); ! 468: continue; ! 469: ! 470: case 'A': /* address of */ ! 471: adrput( getlr( p, *++cp ) ); ! 472: continue; ! 473: ! 474: case 'U': /* for upper half of address, only */ ! 475: upput( getlr( p, *++cp ) ); ! 476: continue; ! 477: ! 478: } ! 479: ! 480: } ! 481: ! 482: } ! 483: ! 484: NODE * ! 485: getlr( p, c ) ! 486: NODE *p; ! 487: { ! 488: ! 489: /* ! 490: * return the pointer to the left or right side of p, or p itself, ! 491: * depending on the optype of p ! 492: */ ! 493: ! 494: switch ( c ) { ! 495: ! 496: case '1': ! 497: case '2': ! 498: case '3': ! 499: return ( &resc[c-'1'] ); ! 500: ! 501: case 'L': ! 502: return ( optype( p->in.op ) == LTYPE ? p : p->in.left ); ! 503: ! 504: case 'R': ! 505: return ( optype( p->in.op ) != BITYPE ? p : p->in.right ); ! 506: ! 507: case '.': ! 508: return ( p ); ! 509: ! 510: } ! 511: cerror( "bad getlr: %c", c ); ! 512: /* NOTREACHED */ ! 513: } ! 514: ! 515: # ifdef MULTILEVEL ! 516: ! 517: union mltemplate{ ! 518: struct ml_head{ ! 519: int tag; /* identifies class of tree */ ! 520: int subtag; /* subclass of tree */ ! 521: union mltemplate * nexthead; /* linked by mlinit() */ ! 522: } mlhead; ! 523: struct ml_node{ ! 524: int op; /* either an operator or op description */ ! 525: int nshape; /* shape of node */ ! 526: /* both op and nshape must match the node. ! 527: * where the work is to be done entirely by ! 528: * op, nshape can be SANY, visa versa, op can ! 529: * be OPANY. ! 530: */ ! 531: int ntype; /* type descriptor from mfile2 */ ! 532: } mlnode; ! 533: }; ! 534: ! 535: # define MLSZ 30 ! 536: ! 537: extern union mltemplate mltree[]; ! 538: int mlstack[MLSZ]; ! 539: int *mlsp; /* pointing into mlstack */ ! 540: NODE * ststack[MLSZ]; ! 541: NODE **stp; /* pointing into ststack */ ! 542: ! 543: mlinit(){ ! 544: union mltemplate **lastlink; ! 545: register union mltemplate *n; ! 546: register mlop; ! 547: ! 548: lastlink = &(mltree[0].nexthead); ! 549: n = &mltree[0]; ! 550: for( ; (n++)->mlhead.tag != 0; ! 551: *lastlink = ++n, lastlink = &(n->mlhead.nexthead) ){ ! 552: # ifndef BUG3 ! 553: if ( vdebug )print_str_d_nl("mlinit: ",(n-1)->mlhead.tag); ! 554: # endif ! 555: /* wander thru a tree with a stack finding ! 556: * its structure so the next header can be located. ! 557: */ ! 558: mlsp = mlstack; ! 559: ! 560: for( ;; ++n ){ ! 561: if ( (mlop = n->mlnode.op) < OPSIMP ){ ! 562: switch( optype(mlop) ){ ! 563: ! 564: default: ! 565: cerror("(1)unknown opcode: %o",mlop); ! 566: case BITYPE: ! 567: goto binary; ! 568: case UTYPE: ! 569: break; ! 570: case LTYPE: ! 571: goto leaf; ! 572: } ! 573: } ! 574: else{ ! 575: if ( mamask[mlop-OPSIMP] & ! 576: (SIMPFLG|COMMFLG|MULFLG|DIVFLG|LOGFLG|FLOFLG|SHFFLG) ){ ! 577: binary: ! 578: *mlsp++ = BITYPE; ! 579: } ! 580: else if ( ! (mamask[mlop-OPSIMP] & UTYPE) ){/* includes OPANY */ ! 581: ! 582: leaf: ! 583: if ( mlsp == mlstack ) ! 584: goto tree_end; ! 585: else if ( *--mlsp != BITYPE ) ! 586: cerror("(1)bad multi-level tree descriptor around mltree[%d]", ! 587: n-mltree); ! 588: } ! 589: } ! 590: } ! 591: tree_end: /* n points to final leaf */ ! 592: ; ! 593: } ! 594: # ifndef BUG3 ! 595: if ( vdebug > 3 ){ ! 596: print_str("mltree={\n"); ! 597: for( n= &(mltree[0]); n->mlhead.tag != 0; ++n) ! 598: printf("%o: %d, %d, %o,\n",n, ! 599: n->mlhead.tag,n->mlhead.subtag,n->mlhead.nexthead); ! 600: print_str(" }\n"); ! 601: } ! 602: # endif ! 603: } ! 604: ! 605: mlmatch( subtree, target, subtarget ) NODE * subtree; int target,subtarget;{ ! 606: /* ! 607: * does subtree match a multi-level tree with ! 608: * tag "target"? Return zero on failure, ! 609: * non-zero subtag on success (or MDONE if ! 610: * there is a zero subtag field). ! 611: */ ! 612: union mltemplate *head; /* current template header */ ! 613: register union mltemplate *n; /* node being matched */ ! 614: NODE * st; /* subtree being matched */ ! 615: register int mlop; ! 616: ! 617: # ifndef BUG3 ! 618: if ( vdebug ) printf("mlmatch(%o,%d)\n",subtree,target); ! 619: # endif ! 620: for( head = &(mltree[0]); head->mlhead.tag != 0; ! 621: head=head->mlhead.nexthead){ ! 622: # ifndef BUG3 ! 623: if ( vdebug > 1 )printf("mlmatch head(%o) tag(%d)\n", ! 624: head->mlhead.tag); ! 625: # endif ! 626: if ( head->mlhead.tag != target )continue; ! 627: if ( subtarget && head->mlhead.subtag != subtarget)continue; ! 628: # ifndef BUG3 ! 629: if ( vdebug ) print_str_d_nl("mlmatch for ",target); ! 630: # endif ! 631: ! 632: /* potential for match */ ! 633: ! 634: n = head + 1; ! 635: st = subtree; ! 636: stp = ststack; ! 637: mlsp = mlstack; ! 638: /* compare n->op, ->nshape, ->ntype to ! 639: * the subtree node st ! 640: */ ! 641: for( ;; ++n ){ /* for each node in multi-level template */ ! 642: /* opmatch */ ! 643: if ( n->op < OPSIMP ){ ! 644: if ( st->op != n->op )break; ! 645: } ! 646: else { ! 647: register opmtemp; ! 648: if ((opmtemp=mamask[n->op-OPSIMP])&SPFLG){ ! 649: if (st->op!=NAME && st->op!=ICON && st->op!=OREG && ! 650: ! shltype(st->op,st)) break; ! 651: } ! 652: else if ((dope[st->op]&(opmtemp|ASGFLG))!=opmtemp) break; ! 653: } ! 654: /* check shape and type */ ! 655: ! 656: if ( ! tshape( st, n->mlnode.nshape ) ) break; ! 657: if ( ! ttype( st->type, n->mlnode.ntype ) ) break; ! 658: ! 659: /* that node matched, let's try another */ ! 660: /* must advance both st and n and halt at right time */ ! 661: ! 662: if ( (mlop = n->mlnode.op) < OPSIMP ){ ! 663: switch( optype(mlop) ){ ! 664: ! 665: default: ! 666: cerror("(2)unknown opcode: %o",mlop); ! 667: case BITYPE: ! 668: goto binary; ! 669: case UTYPE: ! 670: st = st->left; ! 671: break; ! 672: case LTYPE: ! 673: goto leaf; ! 674: } ! 675: } ! 676: else{ ! 677: if ( mamask[mlop - OPSIMP] & ! 678: (SIMPFLG|COMMFLG|MULFLG|DIVFLG|LOGFLG|FLOFLG|SHFFLG) ){ ! 679: binary: ! 680: *mlsp++ = BITYPE; ! 681: *stp++ = st; ! 682: st = st->left; ! 683: } ! 684: else if ( ! (mamask[mlop-OPSIMP] & UTYPE) ){/* includes OPANY */ ! 685: ! 686: leaf: ! 687: if ( mlsp == mlstack ) ! 688: goto matched; ! 689: else if ( *--mlsp != BITYPE ) ! 690: cerror("(2)bad multi-level tree descriptor around mltree[%d]", ! 691: n-mltree); ! 692: st = (*--stp)->right; ! 693: } ! 694: else /* UNARY */ st = st->left; ! 695: } ! 696: continue; ! 697: ! 698: matched: ! 699: /* complete multi-level match successful */ ! 700: # ifndef BUG3 ! 701: if ( vdebug ) print_str("mlmatch() success\n"); ! 702: # endif ! 703: if ( head->mlhead.subtag == 0 ) return( MDONE ); ! 704: else { ! 705: # ifndef BUG3 ! 706: if ( vdebug )print_str_d_nl("\treturns ", ! 707: head->mlhead.subtag ); ! 708: # endif ! 709: return( head->mlhead.subtag ); ! 710: } ! 711: } ! 712: } ! 713: return( 0 ); ! 714: } ! 715: # endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.