12187Smckusick /* Copyright (c) 1979 Regents of the University of California */ 22187Smckusick 3*3584Speter static char sccsid[] = "@(#)forop.c 1.7 04/21/81"; 42187Smckusick 52187Smckusick #include "whoami.h" 62187Smckusick #include "0.h" 72187Smckusick #include "opcode.h" 82187Smckusick #include "tree.h" 92187Smckusick #include "objfmt.h" 102187Smckusick #ifdef PC 112187Smckusick # include "pc.h" 122187Smckusick # include "pcops.h" 132187Smckusick #endif PC 143371Speter 152187Smckusick /* 162187Smckusick * forop for pc: 172187Smckusick * this evaluates the initial and termination expressions, 182187Smckusick * checks them to see if the loop executes at all, and then 192187Smckusick * does the assignment and the loop. 202187Smckusick * arg here looks like: 212187Smckusick * arg[0] T_FORU or T_FORD 222187Smckusick * [1] lineof "for" 232187Smckusick * [2] [0] T_ASGN 242187Smckusick * [1] lineof ":=" 252187Smckusick * [2] [0] T_VAR 262187Smckusick * [1] lineof id 272187Smckusick * [2] char * to id 282187Smckusick * [3] qualifications 292187Smckusick * [3] initial expression 302187Smckusick * [3] termination expression 312187Smckusick * [4] statement 322187Smckusick */ 332187Smckusick forop( arg ) 342187Smckusick int *arg; 352187Smckusick { 362187Smckusick int *lhs; 372187Smckusick struct nl *forvar; 382187Smckusick struct nl *fortype; 392187Smckusick int forctype; 402187Smckusick int *init; 412187Smckusick struct nl *inittype; 422187Smckusick int initoff; 433371Speter char forflags; 442187Smckusick int *term; 452187Smckusick struct nl *termtype; 462187Smckusick int termoff; 472187Smckusick int *stat; 482187Smckusick int goc; /* saved gocnt */ 492187Smckusick int again; /* label at the top of the loop */ 502187Smckusick int after; /* label after the end of the loop */ 51*3584Speter bool shadowed; /* shadowing for var in temporary? */ 52*3584Speter long s_offset; /* saved offset of real for variable */ 53*3584Speter long s_flags; /* saved flags of real for variable */ 54*3584Speter long s_forv; /* saved NL_FORV of the for variable */ 552187Smckusick 562187Smckusick goc = gocnt; 572187Smckusick forvar = NIL; 58*3584Speter shadowed = FALSE; 592187Smckusick if ( arg == NIL ) { 602187Smckusick goto byebye; 612187Smckusick } 622187Smckusick if ( arg[2] == NIL ) { 632187Smckusick goto byebye; 642187Smckusick } 652187Smckusick line = arg[1]; 662187Smckusick putline(); 672187Smckusick lhs = ( (int *) arg[2] )[2]; 682187Smckusick init = ( (int *) arg[2] )[3]; 692187Smckusick term = arg[3]; 702187Smckusick stat = arg[4]; 713278Smckusic if (lhs == NIL) { 723278Smckusic nogood: 73*3584Speter if (forvar != NIL) { 74*3584Speter forvar->value[ NL_FORV ] = FORVAR; 75*3584Speter } 762187Smckusick rvalue( init , NIL , RREQ ); 772187Smckusick rvalue( term , NIL , RREQ ); 782187Smckusick statement( stat ); 792187Smckusick goto byebye; 802187Smckusick } 812187Smckusick /* 822187Smckusick * and this marks the variable as used!!! 832187Smckusick */ 842187Smckusick forvar = lookup( lhs[2] ); 852187Smckusick if ( forvar == NIL ) { 863278Smckusic goto nogood; 872187Smckusick } 88*3584Speter s_forv = forvar -> value[ NL_FORV ]; 893278Smckusic if ( lhs[3] != NIL ) { 903278Smckusic error("For variable %s must be unqualified", forvar->symbol); 913278Smckusic goto nogood; 923278Smckusic } 933278Smckusic if (forvar->class == WITHPTR) { 943278Smckusic error("For variable %s cannot be an element of a record", lhs[2]); 953278Smckusic goto nogood; 963278Smckusic } 973278Smckusic if (opt('s') && 983278Smckusic (bn != cbn || whereis(forvar->value[NL_OFFS]) == PARAMVAR)) { 993278Smckusic standard(); 1003278Smckusic error("For variable %s must be declared in the block in which it is used", forvar->symbol); 1013278Smckusic } 1022187Smckusick /* 1032187Smckusick * find out the type of the loop variable 1042187Smckusick */ 1052187Smckusick codeoff(); 1062187Smckusick fortype = lvalue( lhs , MOD , RREQ ); 1072187Smckusick codeon(); 1082187Smckusick if ( fortype == NIL ) { 1093278Smckusic goto nogood; 1102187Smckusick } 1112187Smckusick if ( isnta( fortype , "bcis" ) ) { 1123278Smckusic error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) ); 1133278Smckusic goto nogood; 1142187Smckusick } 115*3584Speter if ( forvar->value[ NL_FORV ] & FORVAR ) { 116*3584Speter error("Can't modify the for variable %s in the range of the loop", forvar->symbol); 117*3584Speter forvar = NIL; 118*3584Speter goto nogood; 119*3584Speter } 1202187Smckusick /* 1212187Smckusick * allocate space for the initial and termination expressions 122*3584Speter * the initial is tentatively placed in a register as it will 123*3584Speter * shadow the for loop variable in the body of the loop. 1242187Smckusick */ 1253230Smckusic initoff = tmpalloc(sizeof(long), nl+T4INT, REGOK); 126*3584Speter termoff = tmpalloc(sizeof(long), nl+T4INT, NOREG); 1272187Smckusick # ifdef PC 1282187Smckusick /* 1292187Smckusick * compute and save the initial expression 1302187Smckusick */ 1312187Smckusick forctype = p2type( fortype ); 1322187Smckusick putRV( 0 , cbn , initoff , forctype ); 1332187Smckusick # endif PC 1342187Smckusick # ifdef OBJ 1352187Smckusick put(2, O_LV | cbn<<8+INDX, initoff); 1362187Smckusick # endif OBJ 1372187Smckusick inittype = rvalue( init , fortype , RREQ ); 1382187Smckusick if ( incompat( inittype , fortype , init ) ) { 1392187Smckusick cerror("Type of initial expression clashed with index type in 'for' statement"); 140*3584Speter if (forvar != NIL) { 141*3584Speter forvar->value[ NL_FORV ] = FORVAR; 142*3584Speter } 1432187Smckusick rvalue( term , NIL , RREQ ); 1442187Smckusick statement( stat ); 1452187Smckusick goto byebye; 1462187Smckusick } 1472187Smckusick # ifdef PC 1482187Smckusick putop( P2ASSIGN , forctype ); 1492187Smckusick putdot( filename , line ); 1502187Smckusick /* 1512187Smckusick * compute and save the termination expression 1522187Smckusick */ 1532187Smckusick putRV( 0 , cbn , termoff , forctype ); 1542187Smckusick # endif PC 1552187Smckusick # ifdef OBJ 1563083Smckusic gen(O_AS2, O_AS2, sizeof(long), width(inittype)); 1572187Smckusick /* 1582187Smckusick * compute and save the termination expression 1592187Smckusick */ 1602187Smckusick put(2, O_LV | cbn<<8+INDX, termoff); 1612187Smckusick # endif OBJ 1622187Smckusick termtype = rvalue( term , fortype , RREQ ); 1632187Smckusick if ( incompat( termtype , fortype , term ) ) { 1642187Smckusick cerror("Type of limit expression clashed with index type in 'for' statement"); 165*3584Speter if (forvar != NIL) { 166*3584Speter forvar->value[ NL_FORV ] = FORVAR; 167*3584Speter } 1682187Smckusick statement( stat ); 1692187Smckusick goto byebye; 1702187Smckusick } 1712187Smckusick # ifdef PC 1722187Smckusick putop( P2ASSIGN , forctype ); 1732187Smckusick putdot( filename , line ); 1742187Smckusick /* 1752187Smckusick * we can skip the loop altogether if !( init <= term ) 1762187Smckusick */ 1772187Smckusick after = getlab(); 1782187Smckusick putRV( 0 , cbn , initoff , forctype ); 1792187Smckusick putRV( 0 , cbn , termoff , forctype ); 1802187Smckusick putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , forctype ); 1812187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 1822187Smckusick putop( P2CBRANCH , P2INT ); 1832187Smckusick putdot( filename , line ); 1842187Smckusick /* 1853278Smckusic * put down the label at the top of the loop 1863278Smckusic */ 1873278Smckusic again = getlab(); 1883278Smckusic putlab( again ); 1893278Smckusic /* 1902187Smckusick * okay, then we have to execute the body, but first, 1912187Smckusick * assign the initial expression to the for variable. 1922187Smckusick * see the note in asgnop1 about why this is an rvalue. 1932187Smckusick */ 1943371Speter lvalue( lhs , NOUSE , RREQ ); 1952187Smckusick if ( opt( 't' ) ) { 1962187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 1972187Smckusick } 1982187Smckusick putRV( 0 , cbn , initoff , forctype ); 1992187Smckusick if ( opt( 't' ) ) { 2002187Smckusick postcheck( fortype ); 2012187Smckusick } 2022187Smckusick putop( P2ASSIGN , forctype ); 2032187Smckusick putdot( filename , line ); 2042187Smckusick # endif PC 2052187Smckusick # ifdef OBJ 2063083Smckusic gen(O_AS2, O_AS2, sizeof(long), width(termtype)); 2072187Smckusick /* 2082187Smckusick * we can skip the loop altogether if !( init <= term ) 2092187Smckusick */ 2102187Smckusick put(2, O_RV4 | cbn<<8+INDX, initoff); 2112187Smckusick put(2, O_RV4 | cbn<<8+INDX, termoff); 2122187Smckusick gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long), 2132187Smckusick sizeof(long)); 2142187Smckusick after = getlab(); 2152187Smckusick put(2, O_IF, after); 2162187Smckusick /* 2173278Smckusic * put down the label at the top of the loop 2183278Smckusic */ 2193278Smckusic again = getlab(); 2203278Smckusic putlab( again ); 2213278Smckusic /* 2222187Smckusick * okay, then we have to execute the body, but first, 2232187Smckusick * assign the initial expression to the for variable. 2242187Smckusick */ 2252187Smckusick lvalue( lhs , NOUSE , LREQ ); 2262187Smckusick put(2, O_RV4 | cbn<<8+INDX, initoff); 2272187Smckusick rangechk(fortype, nl+T4INT); 2283083Smckusic gen(O_AS2, O_AS2, width(fortype), sizeof(long)); 2292187Smckusick # endif OBJ 2302187Smckusick /* 231*3584Speter * shadowing the real for variable 232*3584Speter * with the initail expression temporary: 233*3584Speter * save the real for variable's offset, flags 234*3584Speter * (including nl_block). 235*3584Speter * replace them with the initial expression's offset, 236*3584Speter * and mark it as being a for variable. 237*3584Speter */ 238*3584Speter shadowed = TRUE; 239*3584Speter s_offset = forvar -> value[ NL_OFFS ]; 240*3584Speter s_flags = forvar -> nl_flags; 241*3584Speter forvar -> value[ NL_OFFS ] = initoff; 242*3584Speter forvar -> nl_flags = cbn; 243*3584Speter forvar -> value[ NL_FORV ] = FORVAR; 244*3584Speter /* 2452187Smckusick * and don't forget ... 2462187Smckusick */ 2473278Smckusic putcnt(); 2483278Smckusic statement( stat ); 2492187Smckusick /* 2502187Smckusick * wasn't that fun? do we get to do it again? 2512187Smckusick * we don't do it again if ( !( forvar < limit ) ) 2522187Smckusick * pretend we were doing this at the top of the loop 2532187Smckusick */ 2542187Smckusick line = arg[ 1 ]; 2552187Smckusick # ifdef PC 2562187Smckusick if ( opt( 'p' ) ) { 2572187Smckusick if ( opt('t') ) { 2582187Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 2592187Smckusick , "_LINO" ); 2602187Smckusick putop( P2UNARY P2CALL , P2INT ); 2612187Smckusick putdot( filename , line ); 2622187Smckusick } else { 2632187Smckusick putRV( STMTCOUNT , 0 , 0 , P2INT ); 2642187Smckusick putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 2652187Smckusick putop( P2ASG P2PLUS , P2INT ); 2662187Smckusick putdot( filename , line ); 2672187Smckusick } 2682187Smckusick } 2692187Smckusick rvalue( lhs , NIL , RREQ ); 2702187Smckusick putRV( 0 , cbn , termoff , forctype ); 2712187Smckusick putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , forctype ); 2722187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 2732187Smckusick putop( P2CBRANCH , P2INT ); 2742187Smckusick putdot( filename , line ); 2752187Smckusick /* 2762187Smckusick * okay, so we have to do it again, 2772187Smckusick * but first, increment the for variable. 2782187Smckusick * there it is again, an rvalue on the lhs of an assignment. 2792187Smckusick */ 2803371Speter lvalue( lhs , MOD , RREQ ); 2812187Smckusick if ( opt( 't' ) ) { 2822187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 2832187Smckusick } 2842187Smckusick rvalue( lhs , NIL , RREQ ); 2852187Smckusick putleaf( P2ICON , 1 , 0 , forctype , 0 ); 2862187Smckusick putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , forctype ); 2872187Smckusick if ( opt( 't' ) ) { 2882187Smckusick postcheck( fortype ); 2892187Smckusick } 2902187Smckusick putop( P2ASSIGN , forctype ); 2912187Smckusick putdot( filename , line ); 2922187Smckusick /* 2932187Smckusick * and do it all again 2942187Smckusick */ 2952187Smckusick putjbr( again ); 2962187Smckusick /* 2972187Smckusick * and here we are 2982187Smckusick */ 2992187Smckusick putlab( after ); 3002187Smckusick # endif PC 3012187Smckusick # ifdef OBJ 3022187Smckusick /* 3032187Smckusick * okay, so we have to do it again. 3042187Smckusick * Luckily we have a magic opcode which increments the 3052187Smckusick * index variable, checks the limit falling through if 3062187Smckusick * it has been reached, else range checking the result 3072187Smckusick * updating the index variable, and returning to the top 3082187Smckusick * of the loop. 3092187Smckusick */ 3102649Speter putline(); 3112187Smckusick put(2, O_RV4 | cbn<<8+INDX, termoff); 3122187Smckusick lvalue(lhs, MOD, LREQ); 3133083Smckusic if (width(fortype) <= 2) 3143083Smckusic put(4, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + 3153083Smckusic (width(fortype)>>1), (int)fortype->range[0], 3163083Smckusic (int)fortype->range[1], again); 3173083Smckusic else 3183083Smckusic put(4, (arg[0] == T_FORU ? O_FOR4U : O_FOR4D), 3193083Smckusic fortype->range[0], fortype->range[1], again); 3202187Smckusick /* 3212187Smckusick * and here we are 3222187Smckusick */ 3232187Smckusick patch( after ); 3242187Smckusick # endif OBJ 3252187Smckusick byebye: 3262187Smckusick noreach = 0; 327*3584Speter if (forvar != NIL) { 328*3584Speter forvar -> value[ NL_FORV ] = s_forv; 3292187Smckusick } 330*3584Speter if ( shadowed ) { 331*3584Speter forvar -> value[ NL_OFFS ] = s_offset; 332*3584Speter forvar -> nl_flags = s_flags; 333*3584Speter } 3342187Smckusick if ( goc != gocnt ) { 3352187Smckusick putcnt(); 3362187Smckusick } 3372187Smckusick } 338