#if !defined(lint) && defined(DOSCCS) static char *sccsid ="@(#)reader.c 4.4.1 (2.11BSD GTE) 1/17/94"; #endif lint # include "pass2.h" /* some storage declarations */ # ifndef ONEPASS NODE node[TREESZ]; char filename[100] = ""; /* the name of the file */ int ftnno; /* number of current function */ int lineno; # else # define NOMAIN #endif int nrecur; int lflag; #ifdef FORT int Oflag = 0; #endif extern int Wflag; int edebug = 0; int xdebug = 0; int udebug = 0; int vdebug = 0; OFFSZ tmpoff; /* offset for first temporary, in bits for current block */ OFFSZ maxoff; /* maximum temporary offset over all blocks in current ftn, in bits */ int maxtreg; NODE *stotree; int stocook; OFFSZ baseoff = 0; OFFSZ maxtemp = 0; p2init( argc, argv ) char *argv[];{ /* set the values of the pass 2 arguments */ register int c; register char *cp; register files; allo0(); /* free all regs */ files = 0; for( c=1; c argc ) return( nerrors ); freopen( argv[files], "r", stdin ); } while( (c=getchar()) > 0 ) switch( c ){ case ')': /* copy line unchanged */ if ( c != ')' ) PUTCHAR( c ); /* initial tab */ while( (c=getchar()) > 0 ){ PUTCHAR(c); if( c == '\n' ) break; } continue; case BBEG: /* beginning of a block */ temp = rdin(10); /* ftnno */ tmpoff = baseoff = rdin(10); /* autooff for block gives max offset of autos in block */ maxtreg = rdin(10); if( getchar() != '\n' ) cerror("intermediate file format error"); if( temp != ftnno ){ /* beginning of function */ maxoff = baseoff; ftnno = temp; maxtemp = 0; } else { if( baseoff > maxoff ) maxoff = baseoff; /* maxoff at end of ftn is max of autos and temps over all blocks in the function */ } setregs(); continue; case BEND: /* end of block */ SETOFF( maxoff, ALSTACK ); eobl2(); while( (c=getchar()) != '\n' ){ if( c <= 0 ) cerror("intermediate file format eof" ); } continue; case EXPR: /* compile code for an expression */ lineno = rdin( 10 ); for( cp=filename; (*cp=getchar()) != '\n'; ++cp ) ; /* VOID, reads filename */ *cp = '\0'; if( lflag ) lineid( lineno, filename ); tmpoff = baseoff; /* expression at top level reuses temps */ p = eread(); # ifndef BUG4 if( edebug ) fwalk( p, eprint, 0 ); # endif # ifdef MYREADER MYREADER(p); /* do your own laundering of the input */ # endif nrecur = 0; delay( p ); /* expression statement throws out results */ reclaim( p, RNULL, 0 ); allchk(); tcheck(); continue; default: cerror("intermediate file format error" ); } /* EOF */ if( files ) goto reread; return(nerrors); } # endif # ifdef ONEPASS p2compile( p ) NODE *p; { if( lflag ) lineid( lineno, filename ); tmpoff = baseoff; /* expression at top level reuses temps */ /* generate code for the tree p */ # ifndef BUG4 if( edebug ) fwalk( p, eprint, 0 ); # endif # ifdef MYREADER MYREADER(p); /* do your own laundering of the input */ # endif nrecur = 0; delay( p ); /* do the code generation */ reclaim( p, RNULL, 0 ); allchk(); /* can't do tcheck here; some stuff (e.g., attributes) may be around from first pass */ /* first pass will do it... */ } p2bbeg( aoff, myreg ) { static int myftn = -1; tmpoff = baseoff = (unsigned int) aoff; maxtreg = myreg; if( myftn != ftnno ){ /* beginning of function */ maxoff = baseoff; myftn = ftnno; maxtemp = 0; } else { if( baseoff > maxoff ) maxoff = baseoff; /* maxoff at end of ftn is max of autos and temps over all blocks */ } setregs(); } p2bend(){ SETOFF( maxoff, ALSTACK ); eobl2(); } # endif NODE *deltrees[DELAYS]; int deli; delay( p ) register NODE *p; { /* look in all legal places for COMOP's and ++ and -- ops to delay */ /* note; don't delay ++ and -- within calls or things like /* getchar (in their macro forms) will start behaving strangely */ register i; /* look for visible COMOPS, and rewrite repeatedly */ while( delay1( p ) ) { /* VOID */ } /* look for visible, delayable ++ and -- */ deli = 0; delay2( p ); codgen( p, FOREFF ); /* do what is left */ for( i = 0; iin.op; ty = optype( o ); if( ty == LTYPE ) return( 0 ); else if( ty == UTYPE ) return( delay1( p->in.left ) ); switch( o ){ case QUEST: case ANDAND: case OROR: /* don't look on RHS */ return( delay1(p->in.left ) ); case COMOP: /* the meat of the routine */ delay( p->in.left ); /* completely evaluate the LHS */ /* rewrite the COMOP */ { register NODE *q; q = p->in.right; ncopy( p, p->in.right ); q->in.op = FREE; } return( 1 ); } return( delay1(p->in.left) || delay1(p->in.right ) ); } delay2( p ) register NODE *p; { /* look for delayable ++ and -- operators */ register o, ty; o = p->in.op; ty = optype( o ); switch( o ){ case NOT: case QUEST: case ANDAND: case OROR: case CALL: case UNARY CALL: case STCALL: case UNARY STCALL: case FORTCALL: case UNARY FORTCALL: case COMOP: case CBRANCH: /* for the moment, don't delay past a conditional context, or /* inside of a call */ return; case UNARY MUL: /* if *p++, do not rewrite */ if( autoincr( p ) ) return; break; case INCR: case DECR: if( deltest( p ) ){ if( deli < DELAYS ){ register NODE *q; deltrees[deli++] = tcopy(p); q = p->in.left; p->in.right->in.op = FREE; /* zap constant */ ncopy( p, q ); q->in.op = FREE; return; } } } if( ty == BITYPE ) delay2( p->in.right ); if( ty != LTYPE ) delay2( p->in.left ); } codgen( p, cookie ) NODE *p; { /* generate the code for p; order may call codgen recursively */ /* cookie is used to describe the context */ for(;;){ canon(p); /* creats OREG from * if possible and does sucomp */ stotree = NIL; # ifndef BUG4 if( edebug ){ printf( "store called on:\n" ); fwalk( p, eprint, 0 ); } # endif store(p); if( stotree==NIL ) break; /* because it's minimal, can do w.o. stores */ order( stotree, stocook ); } order( p, cookie ); } # ifndef BUG4 char *cnames[] = { "SANY", "SAREG", "STAREG", "SBREG", "STBREG", "SCC", "SNAME", "SCON", "SFLD", "SOREG", # ifdef WCARD1 "WCARD1", # else "STARNM", # endif # ifdef WCARD2 "WCARD2", # else "STARREG", # endif "INTEMP", "FORARG", "SWADD", 0, }; prcook( cookie ){ /* print a nice-looking description of cookie */ int i, flag; if( cookie & SPECIAL ){ if( cookie == SZERO ) printf( "SZERO" ); else if( cookie == SONE ) printf( "SONE" ); else if( cookie == SMONE ) printf( "SMONE" ); else if( cookie == SCCON ) printf( "SCCON" ); else if( cookie == SSCON ) printf( "SSCON" ); else if( cookie == SSOREG ) printf( "SSOREG" ); else printf( "SPECIAL+%d", cookie & ~SPECIAL ); return; } flag = 0; for( i=0; cnames[i]; ++i ){ if( cookie & (1<in.rall ); goto first; /* by this time, p should be able to be generated without stores; the only question is how */ again: if ( p->in.op == FREE ) return; /* whole tree was done */ cookie = cook; rcount(); canon(p); rallo( p, p->in.rall ); /* if any rewriting and canonicalization has put * the tree (p) into a shape that cook is happy * with (exclusive of FOREFF, FORREW, and INTEMP) * then we are done. * this allows us to call order with shapes in * addition to cookies and stop short if possible. */ if( tshape(p, cook &(~(FOREFF|FORREW|INTEMP))) )return; first: # ifndef BUG4 if( odebug ){ printf( "order( %o, ", p ); prcook( cookie ); printf( " )\n" ); fwalk( p, eprint, 0 ); } # endif o = p->in.op; ty = optype(o); /* first of all, for most ops, see if it is in the table */ /* look for ops */ switch( m = p->in.op ){ default: /* look for op in table */ for(;;){ if( (m = match( p, cookie ) ) == MDONE ) goto cleanup; else if( m == MNOPE ){ if( !(cookie = nextcook( p, cookie ) ) ) goto nomat; continue; } else break; } break; case COMOP: case FORCE: case CBRANCH: case QUEST: case ANDAND: case OROR: case NOT: case UNARY CALL: case CALL: case UNARY STCALL: case STCALL: case UNARY FORTCALL: case FORTCALL: /* don't even go near the table... */ ; } /* get here to do rewriting if no match or fall through from above for hard ops */ p1 = p->in.left; if( ty == BITYPE ) p2 = p->in.right; else p2 = NIL; # ifndef BUG4 if( odebug ){ printf( "order( %o, ", p ); prcook( cook ); printf( " ), cookie " ); prcook( cookie ); printf( ", rewrite %s\n", opst[m] ); } # endif switch( m ){ default: nomat: cerror("no table entry for op %s", opst[p->in.op] ); case COMOP: codgen( p1, FOREFF ); p2->in.rall = p->in.rall; codgen( p2, cookie ); ncopy( p, p2 ); p2->in.op = FREE; goto cleanup; case FORCE: /* recurse, letting the work be done by rallo */ p = p->in.left; cook = INTAREG|INTBREG; goto again; case CBRANCH: o = p2->tn.lval; cbranch( p1, -1, o ); p2->in.op = FREE; p->in.op = FREE; return; case QUEST: cbranch( p1, -1, m=getlab() ); p2->in.left->in.rall = p->in.rall; codgen( p2->in.left, INTAREG|INTBREG ); /* force right to compute result into same reg used by left */ p2->in.right->in.rall = p2->in.left->tn.rval|MUSTDO; reclaim( p2->in.left, RNULL, 0 ); cbgen( 0, m1 = getlab(), 'I' ); deflab( m ); codgen( p2->in.right, INTAREG|INTBREG ); deflab( m1 ); p->in.op = REG; /* set up node describing result */ p->tn.lval = 0; p->tn.rval = p2->in.right->tn.rval; p->in.type = p2->in.right->in.type; tfree( p2->in.right ); p2->in.op = FREE; goto cleanup; case ANDAND: case OROR: case NOT: /* logical operators */ /* if here, must be a logical operator for 0-1 value */ cbranch( p, -1, m=getlab() ); p->in.op = CCODES; p->bn.label = m; order( p, INTAREG ); goto cleanup; case FLD: /* fields of funny type */ if ( p1->in.op == UNARY MUL ){ offstar( p1->in.left ); goto again; } case UNARY MINUS: order( p1, INBREG|INAREG ); goto again; case NAME: /* all leaves end up here ... */ if( o == REG ) goto nomat; order( p, INTAREG|INTBREG ); goto again; case INIT: uerror("illegal initialization" ); return; case UNARY FORTCALL: p->in.right = NIL; case FORTCALL: o = p->in.op = UNARY FORTCALL; if( genfcall( p, cookie ) ) goto nomat; goto cleanup; case UNARY CALL: p->in.right = NIL; case CALL: o = p->in.op = UNARY CALL; if( gencall( p, cookie ) ) goto nomat; goto cleanup; case UNARY STCALL: p->in.right = NIL; case STCALL: o = p->in.op = UNARY STCALL; if( genscall( p, cookie ) ) goto nomat; goto cleanup; /* if arguments are passed in register, care must be taken that reclaim /* not throw away the register which now has the result... */ case UNARY MUL: if( cook == FOREFF ){ /* do nothing */ order( p->in.left, FOREFF ); p->in.op = FREE; return; } offstar( p->in.left ); goto again; case INCR: /* INCR and DECR */ if( setincr(p) ) goto again; /* x++ becomes (x += 1) -1; */ if( cook & FOREFF ){ /* result not needed so inc or dec and be done with it */ /* x++ => x += 1 */ p->in.op = (p->in.op==INCR)?ASG PLUS:ASG MINUS; goto again; } p1 = tcopy(p); reclaim( p->in.left, RNULL, 0 ); p->in.left = p1; p1->in.op = (p->in.op==INCR)?ASG PLUS:ASG MINUS; p->in.op = (p->in.op==INCR)?MINUS:PLUS; goto again; case STASG: if( setstr( p ) ) goto again; goto nomat; case ASG PLUS: /* and other assignment ops */ if( setasop(p) ) goto again; /* there are assumed to be no side effects in LHS */ p2 = tcopy(p); p->in.op = ASSIGN; reclaim( p->in.right, RNULL, 0 ); p->in.right = p2; canon(p); rallo( p, p->in.rall ); # ifndef BUG4 if( odebug ) fwalk( p, eprint, 0 ); # endif order( p2->in.left, INTBREG|INTAREG ); order( p2, INTBREG|INTAREG ); goto again; case ASSIGN: if( setasg( p ) ) goto again; goto nomat; case BITYPE: if( setbin( p ) ) goto again; /* try to replace binary ops by =ops */ switch(o){ case PLUS: case MINUS: case MUL: case DIV: case MOD: case AND: case OR: case ER: case LS: case RS: p->in.op = ASG o; goto again; } goto nomat; } cleanup: /* if it is not yet in the right state, put it there */ if( cook & FOREFF ){ reclaim( p, RNULL, 0 ); return; } if( p->in.op==FREE ) return; if( tshape( p, cook ) ) return; if( (m=match(p,cook) ) == MDONE ) return; /* we are in bad shape, try one last chance */ if( lastchance( p, cook ) ) goto again; goto nomat; } int callflag; int fregs; store( p ) register NODE *p; { /* find a subtree of p which should be stored */ register o, ty; o = p->in.op; ty = optype(o); if( ty == LTYPE ) return; switch( o ){ case UNARY CALL: case UNARY FORTCALL: case UNARY STCALL: ++callflag; break; case UNARY MUL: if( asgop(p->in.left->in.op) ) stoasg( p->in.left, UNARY MUL ); break; case CALL: case FORTCALL: case STCALL: store( p->in.left ); stoarg( p->in.right, o ); ++callflag; return; case COMOP: markcall( p->in.right ); if( p->in.right->in.su > fregs ) SETSTO( p, INTEMP ); store( p->in.left ); return; case ANDAND: case OROR: case QUEST: markcall( p->in.right ); if( p->in.right->in.su > fregs ) SETSTO( p, INTEMP ); case CBRANCH: /* to prevent complicated expressions on the LHS from being stored */ case NOT: constore( p->in.left ); return; } if( ty == UTYPE ){ store( p->in.left ); return; } if( asgop( p->in.right->in.op ) ) stoasg( p->in.right, o ); if( p->in.su>fregs ){ /* must store */ mkadrs( p ); /* set up stotree and stocook to subtree that must be stored */ } store( p->in.right ); store( p->in.left ); } constore( p ) register NODE *p; { /* store conditional expressions */ /* the point is, avoid storing expressions in conditional conditional context, since the evaluation order is predetermined */ switch( p->in.op ) { case ANDAND: case OROR: case QUEST: markcall( p->in.right ); case NOT: constore( p->in.left ); return; } store( p ); } markcall( p ) register NODE *p; { /* mark off calls below the current node */ again: switch( p->in.op ){ case UNARY CALL: case UNARY STCALL: case UNARY FORTCALL: case CALL: case STCALL: case FORTCALL: ++callflag; return; } switch( optype( p->in.op ) ){ case BITYPE: markcall( p->in.right ); case UTYPE: p = p->in.left; /* eliminate recursion (aren't I clever...) */ goto again; case LTYPE: return; } } stoarg( p, calltype ) register NODE *p; { /* arrange to store the args */ if( p->in.op == CM ){ stoarg( p->in.left, calltype ); p = p->in.right ; } if( calltype == CALL ){ STOARG(p); } else if( calltype == STCALL ){ STOSTARG(p); } else { STOFARG(p); } callflag = 0; store(p); # ifndef NESTCALLS if( callflag ){ /* prevent two calls from being active at once */ SETSTO(p,INTEMP); store(p); /* do again to preserve bottom up nature.... */ } #endif } int negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE } ; /* negatives of relationals */ cbranch( p, true, false ) NODE *p; { /* evaluate p for truth value, and branch to true or false /* accordingly: label <0 means fall through */ register o, lab, flab, tlab; lab = -1; switch( o=p->in.op ){ case ULE: case ULT: case UGE: case UGT: case EQ: case NE: case LE: case LT: case GE: case GT: if( true < 0 ){ o = p->in.op = negrel[ o-EQ ]; true = false; false = -1; } #ifndef NOOPT if( p->in.right->in.op == ICON && p->in.right->tn.lval == 0 && p->in.right->in.name[0] == '\0' ){ switch( o ){ case UGT: case ULE: o = p->in.op = (o==UGT)?NE:EQ; case EQ: case NE: case LE: case LT: case GE: case GT: if( logop(p->in.left->in.op) ){ /* strange situation: e.g., (a!=0) == 0 */ /* must prevent reference to p->in.left->lable, so get 0/1 */ /* we could optimize, but why bother */ codgen( p->in.left, INAREG|INBREG ); } codgen( p->in.left, FORCC ); cbgen( o, true, 'I' ); break; case UGE: codgen(p->in.left, FORCC); cbgen( 0, true, 'I' ); /* unconditional branch */ break; case ULT: codgen(p->in.left, FORCC); } } else #endif { p->bn.label = true; codgen( p, FORCC ); } if( false>=0 ) cbgen( 0, false, 'I' ); reclaim( p, RNULL, 0 ); return; case ANDAND: lab = false<0 ? getlab() : false ; cbranch( p->in.left, -1, lab ); cbranch( p->in.right, true, false ); if( false < 0 ) deflab( lab ); p->in.op = FREE; return; case OROR: lab = true<0 ? getlab() : true; cbranch( p->in.left, lab, -1 ); cbranch( p->in.right, true, false ); if( true < 0 ) deflab( lab ); p->in.op = FREE; return; case NOT: cbranch( p->in.left, false, true ); p->in.op = FREE; break; case COMOP: codgen( p->in.left, FOREFF ); p->in.op = FREE; cbranch( p->in.right, true, false ); return; case QUEST: flab = false<0 ? getlab() : false; tlab = true<0 ? getlab() : true; cbranch( p->in.left, -1, lab = getlab() ); cbranch( p->in.right->in.left, tlab, flab ); deflab( lab ); cbranch( p->in.right->in.right, true, false ); if( true < 0 ) deflab( tlab); if( false < 0 ) deflab( flab ); p->in.right->in.op = FREE; p->in.op = FREE; return; case ICON: if( p->in.type != FLOAT && p->in.type != DOUBLE ){ if( p->tn.lval || p->in.name[0] ){ /* addresses of C objects are never 0 */ if( true>=0 ) cbgen( 0, true, 'I' ); } else if( false>=0 ) cbgen( 0, false, 'I' ); p->in.op = FREE; return; } /* fall through to default with other strange constants */ default: /* get condition codes */ codgen( p, FORCC ); if( true >= 0 ) cbgen( NE, true, 'I' ); if( false >= 0 ) cbgen( true >= 0 ? 0 : EQ, false, 'I' ); reclaim( p, RNULL, 0 ); return; } } rcount(){ /* count recursions */ if( ++nrecur > NRECUR ){ cerror("expression causes compiler loop: try simplifying" ); } } # ifndef BUG4 eprint( p, down, a, b ) NODE *p; int *a, *b; { *a = *b = down+1; while( down >= 2 ){ printf( "\t" ); down -= 2; } if( down-- ) printf( " " ); printf( "%o) %s", p, opst[p->in.op] ); switch( p->in.op ) { /* special cases */ case REG: printf( " %s", rnames[p->tn.rval] ); break; case ICON: case NAME: case OREG: printf( " " ); adrput( p ); break; case STCALL: case UNARY STCALL: case STARG: case STASG: printf( " size=%d", p->stn.stsize ); printf( " align=%d", p->stn.stalign ); break; } printf( ", " ); tprint( p->in.type ); printf( ", " ); if( p->in.rall == NOPREF ) printf( "NOPREF" ); else { if( p->in.rall & MUSTDO ) printf( "MUSTDO " ); else printf( "PREF " ); printf( "%s", rnames[p->in.rall&~MUSTDO]); } printf( ", SU= %d\n", p->in.su ); } # endif # ifndef NOMAIN NODE * eread(){ /* call eread recursively to get subtrees, if any */ register NODE *p; register i, c; register char *pc; register j; i = rdin( 10 ); p = talloc(); p->in.op = i; i = optype(i); if( i == LTYPE ) p->tn.lval = rdin( 10 ); if( i != BITYPE ) p->tn.rval = rdin( 10 ); p->in.type = rdin(8 ); p->in.rall = NOPREF; /* register allocation information */ if( p->in.op == STASG || p->in.op == STARG || p->in.op == STCALL || p->in.op == UNARY STCALL ){ p->stn.stsize = (rdin( 10 ) + (SZCHAR-1) )/SZCHAR; p->stn.stalign = rdin(10) / SZCHAR; if( getchar() != '\n' ) cerror("illegal \n" ); } else { /* usual case */ if( p->in.op == REG ) rbusy( p->tn.rval, p->in.type ); /* non usually, but sometimes justified */ #ifndef FLEXNAMES for( pc=p->in.name,j=0; ( c = getchar() ) != '\n'; ++j ){ if( j < NCHNAM ) *pc++ = c; } if( j < NCHNAM ) *pc = '\0'; #else { char buf[BUFSIZ]; for( pc=buf,j=0; ( c = getchar() ) != '\n'; ++j ){ if( j < BUFSIZ ) *pc++ = c; } if( j < BUFSIZ ) *pc = '\0'; p->in.name = tstr(buf); } #endif } /* now, recursively read descendents, if any */ if( i != LTYPE ) p->in.left = eread(); if( i == BITYPE ) p->in.right = eread(); return( p ); } CONSZ rdin( base ){ register sign, c; CONSZ val; sign = 1; val = 0; while( (c=getchar()) > 0 ) { if( c == '-' ){ if( val != 0 ) cerror("illegal -"); sign = -sign; continue; } if( c == '\t' ) break; if( c>='0' && c<='9' ) { val *= base; if( sign > 0 ) val += c-'0'; else val -= c-'0'; continue; } cerror("illegal character `%c' on intermediate file", c ); break; } if( c <= 0 ) { cerror("unexpected EOF"); } return( val ); } # endif #ifndef FIELDOPS /* do this if there is no special hardware support for fields */ ffld( p, down, down1, down2 ) NODE *p; int *down1, *down2; { /* look for fields that are not in an lvalue context, and rewrite them... */ register NODE *shp; register s, o, v, ty; *down1 = asgop( p->in.op ); *down2 = 0; if( !down && p->in.op == FLD ){ /* rewrite the node */ if( !rewfld(p) ) return; ty = (szty(p->in.type) == 2)? LONG: INT; v = p->tn.rval; s = UPKFSZ(v); # ifdef RTOLBYTES o = UPKFOFF(v); /* amount to shift */ # else o = szty(p->in.type)*SZINT - s - UPKFOFF(v); /* amount to shift */ #endif /* make & mask part */ p->in.left->in.type = ty; p->in.op = AND; p->in.right = talloc(); p->in.right->in.op = ICON; p->in.right->in.rall = NOPREF; p->in.right->in.type = ty; p->in.right->tn.lval = 1; p->in.right->tn.rval = 0; #ifndef FLEXNAMES p->in.right->in.name[0] = '\0'; #else p->in.right->in.name = ""; #endif p->in.right->tn.lval <<= s; p->in.right->tn.lval--; /* now, if a shift is needed, do it */ if( o != 0 ){ shp = talloc(); shp->in.op = RS; shp->in.rall = NOPREF; shp->in.type = ty; shp->in.left = p->in.left; shp->in.right = talloc(); shp->in.right->in.op = ICON; shp->in.right->in.rall = NOPREF; shp->in.right->in.type = ty; shp->in.right->tn.rval = 0; shp->in.right->tn.lval = o; /* amount to shift */ #ifndef FLEXNAMES shp->in.right->in.name[0] = '\0'; #else shp->in.right->in.name = ""; #endif p->in.left = shp; /* whew! */ } } } #endif oreg2( p ) register NODE *p; { /* look for situations where we can turn * into OREG */ NODE *q; register i; register r; register char *cp; register NODE *ql, *qr; CONSZ temp; if( p->in.op == UNARY MUL ){ q = p->in.left; if( q->in.op == REG ){ temp = q->tn.lval; r = q->tn.rval; cp = q->in.name; goto ormake; } if( q->in.op != PLUS && q->in.op != MINUS ) return; ql = q->in.left; qr = q->in.right; #ifdef R2REGS /* look for doubly indexed expressions */ if( q->in.op == PLUS) { if( (r=base(ql))>=0 && (i=offset(qr, tlen(p)))>=0) { makeor2(p, ql, r, i); return; } else if( (r=base(qr))>=0 && (i=offset(ql, tlen(p)))>=0) { makeor2(p, qr, r, i); return; } } #endif if( (q->in.op==PLUS || q->in.op==MINUS) && qr->in.op == ICON && ql->in.op==REG && szty(qr->in.type)==1) { temp = qr->tn.lval; if( q->in.op == MINUS ) temp = -temp; r = ql->tn.rval; temp += ql->tn.lval; cp = qr->in.name; if( *cp && ( q->in.op == MINUS || *ql->in.name ) ) return; if( !*cp ) cp = ql->in.name; ormake: if( notoff( p->in.type, r, temp, cp ) ) return; p->in.op = OREG; p->tn.rval = r; p->tn.lval = temp; #ifndef FLEXNAMES for( i=0; iin.name[i] = *cp++; #else p->in.name = cp; #endif tfree(q); return; } } } canon(p) NODE *p; { /* put p in canonical form */ int oreg2(), sucomp(); #ifndef FIELDOPS int ffld(); fwalk( p, ffld, 0 ); /* look for field operators */ # endif walkf( p, oreg2 ); /* look for and create OREG nodes */ #ifdef MYCANON MYCANON(p); /* your own canonicalization routine(s) */ #endif walkf( p, sucomp ); /* do the Sethi-Ullman computation */ }