12187Smckusick /* Copyright (c) 1979 Regents of the University of California */ 22187Smckusick 3*3371Speter static char sccsid[] = "@(#)forop.c 1.6 03/26/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 14*3371Speter 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; 43*3371Speter 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 */ 512187Smckusick 522187Smckusick goc = gocnt; 532187Smckusick forvar = NIL; 542187Smckusick if ( arg == NIL ) { 552187Smckusick goto byebye; 562187Smckusick } 572187Smckusick if ( arg[2] == NIL ) { 582187Smckusick goto byebye; 592187Smckusick } 602187Smckusick line = arg[1]; 612187Smckusick putline(); 622187Smckusick lhs = ( (int *) arg[2] )[2]; 632187Smckusick init = ( (int *) arg[2] )[3]; 642187Smckusick term = arg[3]; 652187Smckusick stat = arg[4]; 663278Smckusic if (lhs == NIL) { 673278Smckusic nogood: 682187Smckusick rvalue( init , NIL , RREQ ); 692187Smckusick rvalue( term , NIL , RREQ ); 702187Smckusick statement( stat ); 712187Smckusick goto byebye; 722187Smckusick } 732187Smckusick /* 742187Smckusick * and this marks the variable as used!!! 752187Smckusick */ 762187Smckusick forvar = lookup( lhs[2] ); 772187Smckusick if ( forvar == NIL ) { 783278Smckusic goto nogood; 792187Smckusick } 803278Smckusic if ( lhs[3] != NIL ) { 813278Smckusic error("For variable %s must be unqualified", forvar->symbol); 823278Smckusic goto nogood; 833278Smckusic } 843278Smckusic if (forvar->class == WITHPTR) { 853278Smckusic error("For variable %s cannot be an element of a record", lhs[2]); 863278Smckusic goto nogood; 873278Smckusic } 883278Smckusic if (opt('s') && 893278Smckusic (bn != cbn || whereis(forvar->value[NL_OFFS]) == PARAMVAR)) { 903278Smckusic standard(); 913278Smckusic error("For variable %s must be declared in the block in which it is used", forvar->symbol); 923278Smckusic } 932187Smckusick /* 942187Smckusick * find out the type of the loop variable 952187Smckusick */ 962187Smckusick codeoff(); 972187Smckusick fortype = lvalue( lhs , MOD , RREQ ); 982187Smckusick codeon(); 992187Smckusick /* 1002187Smckusick * mark the forvar so we can't change it during the loop 1012187Smckusick */ 102*3371Speter if ( forvar->value[ NL_FORV ] & FORBOUND ) { 1033278Smckusic error("Can't modify the for variable %s in the range of the loop", forvar->symbol); 1043278Smckusic forvar = NIL; 1053278Smckusic goto nogood; 1063278Smckusic } 107*3371Speter forvar -> value[ NL_FORV ] |= LOOPVAR; 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 } 1152187Smckusick /* 1162187Smckusick * allocate space for the initial and termination expressions 117*3371Speter * save the old offset of this variable in NL_SOFFS 118*3371Speter * save the old flags (and block) in NL_FORV 119*3371Speter * and mark the variable as being a for-variable in a temporary 120*3371Speter * set the new offset to be the offset of the initial temp 121*3371Speter * set the flags/block to be the old flags and the current block 1222187Smckusick */ 1233230Smckusic initoff = tmpalloc(sizeof(long), nl+T4INT, REGOK); 1243278Smckusic forvar -> value[ NL_SOFFS ] = forvar -> value[ NL_OFFS ]; 125*3371Speter forvar -> value[ NL_FORV ] = TEMPBOUND | forvar -> nl_flags; 1263278Smckusic forvar -> value[ NL_OFFS ] = initoff; 127*3371Speter forflags = NLFLAGS( forvar -> nl_flags ) + cbn; 128*3371Speter forvar -> nl_flags = forflags; 1293230Smckusic termoff = tmpalloc(sizeof(long), nl+T4INT, REGOK); 1302187Smckusick # ifdef PC 1312187Smckusick /* 1322187Smckusick * compute and save the initial expression 1332187Smckusick */ 1342187Smckusick forctype = p2type( fortype ); 1352187Smckusick putRV( 0 , cbn , initoff , forctype ); 1362187Smckusick # endif PC 1372187Smckusick # ifdef OBJ 1382187Smckusick put(2, O_LV | cbn<<8+INDX, initoff); 1392187Smckusick # endif OBJ 1402187Smckusick inittype = rvalue( init , fortype , RREQ ); 1412187Smckusick if ( incompat( inittype , fortype , init ) ) { 1422187Smckusick cerror("Type of initial expression clashed with index type in 'for' statement"); 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"); 1652187Smckusick statement( stat ); 1662187Smckusick goto byebye; 1672187Smckusick } 1682187Smckusick # ifdef PC 1692187Smckusick putop( P2ASSIGN , forctype ); 1702187Smckusick putdot( filename , line ); 1712187Smckusick /* 1722187Smckusick * we can skip the loop altogether if !( init <= term ) 1732187Smckusick */ 1742187Smckusick after = getlab(); 1752187Smckusick putRV( 0 , cbn , initoff , forctype ); 1762187Smckusick putRV( 0 , cbn , termoff , forctype ); 1772187Smckusick putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , forctype ); 1782187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 1792187Smckusick putop( P2CBRANCH , P2INT ); 1802187Smckusick putdot( filename , line ); 1812187Smckusick /* 1823278Smckusic * put down the label at the top of the loop 1833278Smckusic */ 1843278Smckusic again = getlab(); 1853278Smckusic putlab( again ); 1863278Smckusic /* 1872187Smckusick * okay, then we have to execute the body, but first, 1882187Smckusick * assign the initial expression to the for variable. 1892187Smckusick * see the note in asgnop1 about why this is an rvalue. 1902187Smckusick */ 1913278Smckusic forvar -> value[ NL_OFFS ] = forvar -> value[ NL_SOFFS ]; 192*3371Speter forflags |= forvar -> nl_flags; 193*3371Speter forvar -> nl_flags = (char) forvar -> value[ NL_FORV ] &~ FORBOUND; 194*3371Speter lvalue( lhs , NOUSE , RREQ ); 1953278Smckusic forvar -> value[ NL_OFFS ] = initoff; 196*3371Speter forvar -> nl_flags = forflags; 1972187Smckusick if ( opt( 't' ) ) { 1982187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 1992187Smckusick } 2002187Smckusick putRV( 0 , cbn , initoff , forctype ); 2012187Smckusick if ( opt( 't' ) ) { 2022187Smckusick postcheck( fortype ); 2032187Smckusick } 2042187Smckusick putop( P2ASSIGN , forctype ); 2052187Smckusick putdot( filename , line ); 2062187Smckusick # endif PC 2072187Smckusick # ifdef OBJ 2083083Smckusic gen(O_AS2, O_AS2, sizeof(long), width(termtype)); 2092187Smckusick /* 2102187Smckusick * we can skip the loop altogether if !( init <= term ) 2112187Smckusick */ 2122187Smckusick put(2, O_RV4 | cbn<<8+INDX, initoff); 2132187Smckusick put(2, O_RV4 | cbn<<8+INDX, termoff); 2142187Smckusick gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long), 2152187Smckusick sizeof(long)); 2162187Smckusick after = getlab(); 2172187Smckusick put(2, O_IF, after); 2182187Smckusick /* 2193278Smckusic * put down the label at the top of the loop 2203278Smckusic */ 2213278Smckusic again = getlab(); 2223278Smckusic putlab( again ); 2233278Smckusic /* 2242187Smckusick * okay, then we have to execute the body, but first, 2252187Smckusick * assign the initial expression to the for variable. 2262187Smckusick */ 2273278Smckusic forvar -> value[ NL_OFFS ] = forvar -> value[ NL_SOFFS ]; 228*3371Speter forflags |= forvar -> nl_flags; 229*3371Speter forvar -> nl_flags = (char) forvar -> value[ NL_FORV ] &~ FORBOUND; 2302187Smckusick lvalue( lhs , NOUSE , LREQ ); 231*3371Speter forvar -> value[ NL_OFFS ] = initoff; 232*3371Speter forvar -> nl_flags = forflags; 2332187Smckusick put(2, O_RV4 | cbn<<8+INDX, initoff); 2342187Smckusick rangechk(fortype, nl+T4INT); 2353083Smckusic gen(O_AS2, O_AS2, width(fortype), sizeof(long)); 2362187Smckusick # endif OBJ 2372187Smckusick /* 2382187Smckusick * and don't forget ... 2392187Smckusick */ 2403278Smckusic putcnt(); 2413278Smckusic statement( stat ); 2422187Smckusick /* 2432187Smckusick * wasn't that fun? do we get to do it again? 2442187Smckusick * we don't do it again if ( !( forvar < limit ) ) 2452187Smckusick * pretend we were doing this at the top of the loop 2462187Smckusick */ 2472187Smckusick line = arg[ 1 ]; 2482187Smckusick # ifdef PC 2492187Smckusick if ( opt( 'p' ) ) { 2502187Smckusick if ( opt('t') ) { 2512187Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 2522187Smckusick , "_LINO" ); 2532187Smckusick putop( P2UNARY P2CALL , P2INT ); 2542187Smckusick putdot( filename , line ); 2552187Smckusick } else { 2562187Smckusick putRV( STMTCOUNT , 0 , 0 , P2INT ); 2572187Smckusick putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 2582187Smckusick putop( P2ASG P2PLUS , P2INT ); 2592187Smckusick putdot( filename , line ); 2602187Smckusick } 2612187Smckusick } 2622187Smckusick rvalue( lhs , NIL , RREQ ); 2632187Smckusick putRV( 0 , cbn , termoff , forctype ); 2642187Smckusick putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , forctype ); 2652187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 2662187Smckusick putop( P2CBRANCH , P2INT ); 2672187Smckusick putdot( filename , line ); 2682187Smckusick /* 2692187Smckusick * okay, so we have to do it again, 2702187Smckusick * but first, increment the for variable. 2712187Smckusick * there it is again, an rvalue on the lhs of an assignment. 2722187Smckusick */ 273*3371Speter lvalue( lhs , MOD , RREQ ); 2742187Smckusick if ( opt( 't' ) ) { 2752187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 2762187Smckusick } 2772187Smckusick rvalue( lhs , NIL , RREQ ); 2782187Smckusick putleaf( P2ICON , 1 , 0 , forctype , 0 ); 2792187Smckusick putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , forctype ); 2802187Smckusick if ( opt( 't' ) ) { 2812187Smckusick postcheck( fortype ); 2822187Smckusick } 2832187Smckusick putop( P2ASSIGN , forctype ); 2842187Smckusick putdot( filename , line ); 2852187Smckusick /* 2862187Smckusick * and do it all again 2872187Smckusick */ 2882187Smckusick putjbr( again ); 2892187Smckusick /* 2902187Smckusick * and here we are 2912187Smckusick */ 2922187Smckusick putlab( after ); 2932187Smckusick # endif PC 2942187Smckusick # ifdef OBJ 2952187Smckusick /* 2962187Smckusick * okay, so we have to do it again. 2972187Smckusick * Luckily we have a magic opcode which increments the 2982187Smckusick * index variable, checks the limit falling through if 2992187Smckusick * it has been reached, else range checking the result 3002187Smckusick * updating the index variable, and returning to the top 3012187Smckusick * of the loop. 3022187Smckusick */ 3032649Speter putline(); 3042187Smckusick put(2, O_RV4 | cbn<<8+INDX, termoff); 3052187Smckusick lvalue(lhs, MOD, LREQ); 3063083Smckusic if (width(fortype) <= 2) 3073083Smckusic put(4, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + 3083083Smckusic (width(fortype)>>1), (int)fortype->range[0], 3093083Smckusic (int)fortype->range[1], again); 3103083Smckusic else 3113083Smckusic put(4, (arg[0] == T_FORU ? O_FOR4U : O_FOR4D), 3123083Smckusic fortype->range[0], fortype->range[1], again); 3132187Smckusick /* 3142187Smckusick * and here we are 3152187Smckusick */ 3162187Smckusick patch( after ); 3172187Smckusick # endif OBJ 3182187Smckusick byebye: 3192187Smckusick noreach = 0; 3202187Smckusick if ( forvar != NIL ) { 321*3371Speter if (forvar -> value[ NL_FORV ] & TEMPBOUND ) { 3223278Smckusic forvar -> value[ NL_OFFS ] = forvar -> value[ NL_SOFFS ]; 323*3371Speter forvar -> nl_flags = 324*3371Speter (char) ( ( forvar -> value[ NL_FORV ] &~ FORBOUND ) 325*3371Speter | NLFLAGS( forvar -> nl_flags ) ); 326*3371Speter } 327*3371Speter forvar -> value[ NL_FORV ] = NIL; 3282187Smckusick } 3292187Smckusick if ( goc != gocnt ) { 3302187Smckusick putcnt(); 3312187Smckusick } 3322187Smckusick } 333