12187Smckusick /* Copyright (c) 1979 Regents of the University of California */ 22187Smckusick 3*10798Speter static char sccsid[] = "@(#)forop.c 1.14 02/09/83"; 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 /* 16*10798Speter * for-statements. 17*10798Speter * 18*10798Speter * the relevant quote from the standard: 6.8.3.9: 19*10798Speter * ``The control-variable shall be an entire-variable whose identifier 20*10798Speter * is declared in the variable-declaration-part of the block closest- 21*10798Speter * containing the for-statement. The control-variable shall possess 22*10798Speter * an ordinal-type, and the initial-value and the final-value shall be 23*10798Speter * of a type compatible with this type. The statement of a for-statement 24*10798Speter * shall not contain an assigning-reference to the control-variable 25*10798Speter * of the for-statement. The value of the final-value shall be 26*10798Speter * assignment-compatible with the control-variable when the initial-value 27*10798Speter * is assigned to the control-variable. After a for-statement is 28*10798Speter * executed (other than being left by a goto-statement leading out of it) 29*10798Speter * the control-variable shall be undefined. Apart from the restrictions 30*10798Speter * imposed by these requirements, the for-statement 31*10798Speter * for v := e1 to e2 do body 32*10798Speter * shall be equivalent to 33*10798Speter * begin 34*10798Speter * temp1 := e1; 35*10798Speter * temp2 := e2; 36*10798Speter * if temp1 <= temp2 then begin 37*10798Speter * v := temp1; 38*10798Speter * body; 39*10798Speter * while v <> temp2 do begin 40*10798Speter * v := succ(v); 41*10798Speter * body; 42*10798Speter * end 43*10798Speter * end 44*10798Speter * end 45*10798Speter * where temp1 and temp2 denote auxiliary variables that the program 46*10798Speter * does not otherwise contain, and that possess the type possessed by 47*10798Speter * the variable v if that type is not a subrange-type; otherwise the 48*10798Speter * host type possessed by the variable v.'' 49*10798Speter * 50*10798Speter * The Berkeley Pascal systems try to do all that without duplicating 51*10798Speter * the body, and shadowing the control-variable in (possibly) a 52*10798Speter * register variable. 53*10798Speter * 542187Smckusick * arg here looks like: 552187Smckusick * arg[0] T_FORU or T_FORD 562187Smckusick * [1] lineof "for" 572187Smckusick * [2] [0] T_ASGN 582187Smckusick * [1] lineof ":=" 592187Smckusick * [2] [0] T_VAR 602187Smckusick * [1] lineof id 612187Smckusick * [2] char * to id 622187Smckusick * [3] qualifications 632187Smckusick * [3] initial expression 642187Smckusick * [3] termination expression 652187Smckusick * [4] statement 662187Smckusick */ 672187Smckusick forop( arg ) 682187Smckusick int *arg; 692187Smckusick { 702187Smckusick int *lhs; 712187Smckusick struct nl *forvar; 722187Smckusick struct nl *fortype; 7310666Speter #ifdef PC 74*10798Speter int forp2type; 7510666Speter #endif PC 7610666Speter int forwidth; 772187Smckusick int *init; 782187Smckusick struct nl *inittype; 793836Speter struct nl *initnlp; /* initial value namelist entry */ 802187Smckusick int *term; 812187Smckusick struct nl *termtype; 823836Speter struct nl *termnlp; /* termination value namelist entry */ 83*10798Speter struct nl *shadownlp; /* namelist entry for the shadow */ 842187Smckusick int *stat; 852187Smckusick int goc; /* saved gocnt */ 862187Smckusick int again; /* label at the top of the loop */ 872187Smckusick int after; /* label after the end of the loop */ 88*10798Speter struct nl saved_nl; /* saved namelist entry for loop var */ 892187Smckusick 902187Smckusick goc = gocnt; 912187Smckusick forvar = NIL; 922187Smckusick if ( arg == NIL ) { 932187Smckusick goto byebye; 942187Smckusick } 952187Smckusick if ( arg[2] == NIL ) { 962187Smckusick goto byebye; 972187Smckusick } 982187Smckusick line = arg[1]; 992187Smckusick putline(); 1002187Smckusick lhs = ( (int *) arg[2] )[2]; 1012187Smckusick init = ( (int *) arg[2] )[3]; 1022187Smckusick term = arg[3]; 1032187Smckusick stat = arg[4]; 1043278Smckusic if (lhs == NIL) { 1053278Smckusic nogood: 1063584Speter if (forvar != NIL) { 1073584Speter forvar->value[ NL_FORV ] = FORVAR; 1083584Speter } 1092187Smckusick rvalue( init , NIL , RREQ ); 1102187Smckusick rvalue( term , NIL , RREQ ); 1112187Smckusick statement( stat ); 1122187Smckusick goto byebye; 1132187Smckusick } 1142187Smckusick /* 1152187Smckusick * and this marks the variable as used!!! 1162187Smckusick */ 1172187Smckusick forvar = lookup( lhs[2] ); 1182187Smckusick if ( forvar == NIL ) { 1193278Smckusic goto nogood; 1202187Smckusick } 121*10798Speter saved_nl = *forvar; 1223278Smckusic if ( lhs[3] != NIL ) { 1233278Smckusic error("For variable %s must be unqualified", forvar->symbol); 1243278Smckusic goto nogood; 1253278Smckusic } 1263278Smckusic if (forvar->class == WITHPTR) { 1273278Smckusic error("For variable %s cannot be an element of a record", lhs[2]); 1283278Smckusic goto nogood; 1293278Smckusic } 1303836Speter if ( opt('s') && 1313836Speter ( ( bn != cbn ) || 1323836Speter #ifdef OBJ 133*10798Speter (whereis(bn, forvar->value[NL_OFFS], 0) == PARAMVAR) 1343836Speter #endif OBJ 1353836Speter #ifdef PC 136*10798Speter (whereis(bn, forvar->value[NL_OFFS], forvar->extra_flags) 1373836Speter == PARAMVAR ) 1383836Speter #endif PC 1393836Speter ) ) { 1403278Smckusic standard(); 1413278Smckusic error("For variable %s must be declared in the block in which it is used", forvar->symbol); 1423278Smckusic } 1432187Smckusick /* 1442187Smckusick * find out the type of the loop variable 1452187Smckusick */ 1462187Smckusick codeoff(); 1472187Smckusick fortype = lvalue( lhs , MOD , RREQ ); 1482187Smckusick codeon(); 1492187Smckusick if ( fortype == NIL ) { 1503278Smckusic goto nogood; 1512187Smckusick } 1522187Smckusick if ( isnta( fortype , "bcis" ) ) { 1533278Smckusic error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) ); 1543278Smckusic goto nogood; 1552187Smckusick } 1563584Speter if ( forvar->value[ NL_FORV ] & FORVAR ) { 1573584Speter error("Can't modify the for variable %s in the range of the loop", forvar->symbol); 1583584Speter forvar = NIL; 1593584Speter goto nogood; 1603584Speter } 161*10798Speter forwidth = lwidth(fortype); 162*10798Speter # ifdef PC 163*10798Speter forp2type = p2type(fortype); 164*10798Speter # endif PC 1652187Smckusick /* 166*10798Speter * allocate temporaries for the initial and final expressions 167*10798Speter * and maybe a register to shadow the for variable. 1682187Smckusick */ 169*10798Speter initnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG); 170*10798Speter termnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG); 171*10798Speter shadownlp = tmpalloc(forwidth, fortype, REGOK); 1722187Smckusick # ifdef PC 1732187Smckusick /* 1742187Smckusick * compute and save the initial expression 1752187Smckusick */ 1763836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 177*10798Speter initnlp -> extra_flags , P2INT ); 1782187Smckusick # endif PC 1792187Smckusick # ifdef OBJ 1803836Speter put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 1812187Smckusick # endif OBJ 1822187Smckusick inittype = rvalue( init , fortype , RREQ ); 1832187Smckusick if ( incompat( inittype , fortype , init ) ) { 1842187Smckusick cerror("Type of initial expression clashed with index type in 'for' statement"); 1853584Speter if (forvar != NIL) { 1863584Speter forvar->value[ NL_FORV ] = FORVAR; 1873584Speter } 1882187Smckusick rvalue( term , NIL , RREQ ); 1892187Smckusick statement( stat ); 1902187Smckusick goto byebye; 1912187Smckusick } 1922187Smckusick # ifdef PC 193*10798Speter sconv(p2type(inittype), P2INT); 194*10798Speter putop( P2ASSIGN , P2INT ); 1952187Smckusick putdot( filename , line ); 1962187Smckusick /* 1972187Smckusick * compute and save the termination expression 1982187Smckusick */ 1993836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 200*10798Speter termnlp -> extra_flags , P2INT ); 2012187Smckusick # endif PC 2022187Smckusick # ifdef OBJ 203*10798Speter gen(O_AS2, O_AS2, sizeof(long), width(inittype)); 2042187Smckusick /* 2052187Smckusick * compute and save the termination expression 2062187Smckusick */ 2073836Speter put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 2082187Smckusick # endif OBJ 2092187Smckusick termtype = rvalue( term , fortype , RREQ ); 2102187Smckusick if ( incompat( termtype , fortype , term ) ) { 2112187Smckusick cerror("Type of limit expression clashed with index type in 'for' statement"); 2123584Speter if (forvar != NIL) { 2133584Speter forvar->value[ NL_FORV ] = FORVAR; 2143584Speter } 2152187Smckusick statement( stat ); 2162187Smckusick goto byebye; 2172187Smckusick } 2182187Smckusick # ifdef PC 219*10798Speter sconv(p2type(termtype), P2INT); 220*10798Speter putop( P2ASSIGN , P2INT ); 2212187Smckusick putdot( filename , line ); 2222187Smckusick /* 2232187Smckusick * we can skip the loop altogether if !( init <= term ) 2242187Smckusick */ 2252187Smckusick after = getlab(); 2263836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 227*10798Speter initnlp -> extra_flags , P2INT ); 2283836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 229*10798Speter termnlp -> extra_flags , P2INT ); 230*10798Speter putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , P2INT ); 2312187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 2322187Smckusick putop( P2CBRANCH , P2INT ); 2332187Smckusick putdot( filename , line ); 2342187Smckusick /* 235*10798Speter * okay, so we have to execute the loop body, 236*10798Speter * but first, if checking is on, 237*10798Speter * check that the termination expression 238*10798Speter * is assignment compatible with the control-variable. 239*10798Speter */ 240*10798Speter if (opt('t')) { 241*10798Speter precheck(fortype, "_RANG4", "_RSNG4"); 242*10798Speter putRV(0, cbn, termnlp -> value[NL_OFFS], 243*10798Speter termnlp -> extra_flags, P2INT); 244*10798Speter postcheck(fortype, nl+T4INT); 245*10798Speter putdot(filename, line); 246*10798Speter } 247*10798Speter /* 248*10798Speter * assign the initial expression to the shadow 249*10798Speter * checking the assignment if necessary. 250*10798Speter */ 251*10798Speter putRV(0, cbn, shadownlp -> value[NL_OFFS], 252*10798Speter shadownlp -> extra_flags, forp2type); 253*10798Speter if (opt('t')) { 254*10798Speter precheck(fortype, "_RANG4", "_RSNG4"); 255*10798Speter putRV(0, cbn, initnlp -> value[NL_OFFS], 256*10798Speter initnlp -> extra_flags, P2INT); 257*10798Speter postcheck(fortype, nl+T4INT); 258*10798Speter } else { 259*10798Speter putRV(0, cbn, initnlp -> value[NL_OFFS], 260*10798Speter initnlp -> extra_flags, P2INT); 261*10798Speter } 262*10798Speter sconv(P2INT, forp2type); 263*10798Speter putop(P2ASSIGN, forp2type); 264*10798Speter putdot(filename, line); 265*10798Speter /* 2663278Smckusic * put down the label at the top of the loop 2673278Smckusic */ 2683278Smckusic again = getlab(); 2693278Smckusic putlab( again ); 2703278Smckusic /* 271*10798Speter * each time through the loop 272*10798Speter * assign the shadow to the for variable. 2732187Smckusick */ 274*10798Speter lvalue(lhs, NOUSE, RREQ); 275*10798Speter putRV(0, cbn, shadownlp -> value[NL_OFFS], 276*10798Speter shadownlp -> extra_flags, forp2type); 277*10798Speter putop(P2ASSIGN, forp2type); 278*10798Speter putdot(filename, line); 2792187Smckusick # endif PC 2802187Smckusick # ifdef OBJ 281*10798Speter gen(O_AS2, O_AS2, sizeof(long), width(termtype)); 2822187Smckusick /* 2832187Smckusick * we can skip the loop altogether if !( init <= term ) 2842187Smckusick */ 285*10798Speter put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 286*10798Speter put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 287*10798Speter gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long), 288*10798Speter sizeof(long)); 2892187Smckusick after = getlab(); 2902187Smckusick put(2, O_IF, after); 2912187Smckusick /* 292*10798Speter * okay, so we have to execute the loop body, 293*10798Speter * but first, if checking is on, 294*10798Speter * check that the termination expression 295*10798Speter * is assignment compatible with the control-variable. 296*10798Speter */ 297*10798Speter if (opt('t')) { 298*10798Speter put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] ); 299*10798Speter put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 300*10798Speter rangechk(fortype, nl+T4INT); 301*10798Speter gen(O_AS2, O_AS2, forwidth, sizeof(long)); 302*10798Speter } 303*10798Speter /* 304*10798Speter * assign the initial expression to the shadow 305*10798Speter * checking the assignment if necessary. 306*10798Speter */ 307*10798Speter put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] ); 308*10798Speter put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 309*10798Speter rangechk(fortype, nl+T4INT); 310*10798Speter gen(O_AS2, O_AS2, forwidth, sizeof(long)); 311*10798Speter /* 3123278Smckusic * put down the label at the top of the loop 3133278Smckusic */ 3143278Smckusic again = getlab(); 3153278Smckusic putlab( again ); 3163278Smckusic /* 317*10798Speter * each time through the loop 318*10798Speter * assign the shadow to the for variable. 3192187Smckusick */ 320*10798Speter lvalue(lhs, NOUSE, RREQ); 321*10798Speter stackRV(shadownlp); 322*10798Speter gen(O_AS2, O_AS2, forwidth, sizeof(long)); 3232187Smckusick # endif OBJ 3242187Smckusick /* 3253584Speter * shadowing the real for variable 326*10798Speter * with the shadow temporary: 327*10798Speter * save the real for variable flags (including nl_block). 328*10798Speter * replace them with the shadow's offset, 329*10798Speter * and mark the for variable as being a for variable. 3303584Speter */ 331*10798Speter shadownlp -> nl_flags = forvar -> nl_flags; 332*10798Speter *forvar = *shadownlp; 333*10798Speter forvar -> symbol = saved_nl.symbol; 334*10798Speter forvar -> nl_next = saved_nl.nl_next; 335*10798Speter forvar -> type = saved_nl.type; 3363584Speter forvar -> value[ NL_FORV ] = FORVAR; 3373584Speter /* 3382187Smckusick * and don't forget ... 3392187Smckusick */ 3403278Smckusic putcnt(); 3413278Smckusic statement( stat ); 3422187Smckusick /* 3432187Smckusick * wasn't that fun? do we get to do it again? 3442187Smckusick * we don't do it again if ( !( forvar < limit ) ) 3452187Smckusick * pretend we were doing this at the top of the loop 3462187Smckusick */ 3472187Smckusick line = arg[ 1 ]; 3482187Smckusick # ifdef PC 3492187Smckusick if ( opt( 'p' ) ) { 3502187Smckusick if ( opt('t') ) { 3512187Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 3522187Smckusick , "_LINO" ); 3532187Smckusick putop( P2UNARY P2CALL , P2INT ); 3542187Smckusick putdot( filename , line ); 3552187Smckusick } else { 3563836Speter putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT ); 3572187Smckusick putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 3582187Smckusick putop( P2ASG P2PLUS , P2INT ); 3592187Smckusick putdot( filename , line ); 3602187Smckusick } 3612187Smckusick } 3623836Speter /*rvalue( lhs , NIL , RREQ );*/ 363*10798Speter putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] , 364*10798Speter shadownlp -> extra_flags , forp2type ); 365*10798Speter sconv(forp2type, P2INT); 3663836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 367*10798Speter termnlp -> extra_flags , P2INT ); 3683836Speter putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT ); 3692187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 3702187Smckusick putop( P2CBRANCH , P2INT ); 3712187Smckusick putdot( filename , line ); 3722187Smckusick /* 3732187Smckusick * okay, so we have to do it again, 3742187Smckusick * but first, increment the for variable. 375*10798Speter * no need to rangecheck it, since we checked the 376*10798Speter * termination value before we started. 3772187Smckusick */ 3783836Speter /*lvalue( lhs , MOD , RREQ );*/ 379*10798Speter putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] , 380*10798Speter shadownlp -> extra_flags , forp2type ); 3813836Speter /*rvalue( lhs , NIL , RREQ );*/ 382*10798Speter putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] , 383*10798Speter shadownlp -> extra_flags , forp2type ); 384*10798Speter sconv(forp2type, P2INT); 3853633Smckusic putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 3863633Smckusic putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT ); 387*10798Speter sconv(P2INT, forp2type); 388*10798Speter putop( P2ASSIGN , forp2type ); 3892187Smckusick putdot( filename , line ); 3902187Smckusick /* 3912187Smckusick * and do it all again 3922187Smckusick */ 3932187Smckusick putjbr( again ); 3942187Smckusick /* 3952187Smckusick * and here we are 3962187Smckusick */ 3972187Smckusick putlab( after ); 3982187Smckusick # endif PC 3992187Smckusick # ifdef OBJ 4002187Smckusick /* 4012187Smckusick * okay, so we have to do it again. 4022187Smckusick * Luckily we have a magic opcode which increments the 4032187Smckusick * index variable, checks the limit falling through if 404*10798Speter * it has been reached, else updating the index variable, 405*10798Speter * and returning to the top of the loop. 4062187Smckusick */ 4072649Speter putline(); 408*10798Speter put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 409*10798Speter put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] ); 410*10798Speter put(2, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + (forwidth >> 1), 411*10798Speter again); 4122187Smckusick /* 4132187Smckusick * and here we are 4142187Smckusick */ 4152187Smckusick patch( after ); 4162187Smckusick # endif OBJ 4172187Smckusick byebye: 4182187Smckusick noreach = 0; 4193584Speter if (forvar != NIL) { 420*10798Speter saved_nl.nl_flags |= forvar -> nl_flags & (NUSED|NMOD); 421*10798Speter *forvar = saved_nl; 4222187Smckusick } 4232187Smckusick if ( goc != gocnt ) { 4242187Smckusick putcnt(); 4252187Smckusick } 4262187Smckusick } 427