12187Smckusick /* Copyright (c) 1979 Regents of the University of California */ 22187Smckusick 3*11335Speter static char sccsid[] = "@(#)forop.c 1.16 02/28/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 14*11335Speter #include "tmps.h" 153371Speter 162187Smckusick /* 1710798Speter * for-statements. 1810798Speter * 1910798Speter * the relevant quote from the standard: 6.8.3.9: 2010798Speter * ``The control-variable shall be an entire-variable whose identifier 2110798Speter * is declared in the variable-declaration-part of the block closest- 2210798Speter * containing the for-statement. The control-variable shall possess 2310798Speter * an ordinal-type, and the initial-value and the final-value shall be 2410798Speter * of a type compatible with this type. The statement of a for-statement 2510798Speter * shall not contain an assigning-reference to the control-variable 2610798Speter * of the for-statement. The value of the final-value shall be 2710798Speter * assignment-compatible with the control-variable when the initial-value 2810798Speter * is assigned to the control-variable. After a for-statement is 2910798Speter * executed (other than being left by a goto-statement leading out of it) 3010798Speter * the control-variable shall be undefined. Apart from the restrictions 3110798Speter * imposed by these requirements, the for-statement 3210798Speter * for v := e1 to e2 do body 3310798Speter * shall be equivalent to 3410798Speter * begin 3510798Speter * temp1 := e1; 3610798Speter * temp2 := e2; 3710798Speter * if temp1 <= temp2 then begin 3810798Speter * v := temp1; 3910798Speter * body; 4010798Speter * while v <> temp2 do begin 4110798Speter * v := succ(v); 4210798Speter * body; 4310798Speter * end 4410798Speter * end 4510798Speter * end 4610798Speter * where temp1 and temp2 denote auxiliary variables that the program 4710798Speter * does not otherwise contain, and that possess the type possessed by 4810798Speter * the variable v if that type is not a subrange-type; otherwise the 4910798Speter * host type possessed by the variable v.'' 5010798Speter * 5110798Speter * The Berkeley Pascal systems try to do all that without duplicating 5210798Speter * the body, and shadowing the control-variable in (possibly) a 5310798Speter * register variable. 5410798Speter * 552187Smckusick * arg here looks like: 562187Smckusick * arg[0] T_FORU or T_FORD 572187Smckusick * [1] lineof "for" 582187Smckusick * [2] [0] T_ASGN 592187Smckusick * [1] lineof ":=" 602187Smckusick * [2] [0] T_VAR 612187Smckusick * [1] lineof id 622187Smckusick * [2] char * to id 632187Smckusick * [3] qualifications 642187Smckusick * [3] initial expression 652187Smckusick * [3] termination expression 662187Smckusick * [4] statement 672187Smckusick */ 682187Smckusick forop( arg ) 692187Smckusick int *arg; 702187Smckusick { 712187Smckusick int *lhs; 722187Smckusick struct nl *forvar; 732187Smckusick struct nl *fortype; 7410666Speter #ifdef PC 7510798Speter int forp2type; 7610666Speter #endif PC 7710666Speter int forwidth; 782187Smckusick int *init; 792187Smckusick struct nl *inittype; 803836Speter struct nl *initnlp; /* initial value namelist entry */ 812187Smckusick int *term; 822187Smckusick struct nl *termtype; 833836Speter struct nl *termnlp; /* termination value namelist entry */ 8410798Speter struct nl *shadownlp; /* namelist entry for the shadow */ 852187Smckusick int *stat; 862187Smckusick int goc; /* saved gocnt */ 872187Smckusick int again; /* label at the top of the loop */ 882187Smckusick int after; /* label after the end of the loop */ 8910798Speter struct nl saved_nl; /* saved namelist entry for loop var */ 902187Smckusick 912187Smckusick goc = gocnt; 922187Smckusick forvar = NIL; 932187Smckusick if ( arg == NIL ) { 942187Smckusick goto byebye; 952187Smckusick } 962187Smckusick if ( arg[2] == NIL ) { 972187Smckusick goto byebye; 982187Smckusick } 992187Smckusick line = arg[1]; 1002187Smckusick putline(); 1012187Smckusick lhs = ( (int *) arg[2] )[2]; 1022187Smckusick init = ( (int *) arg[2] )[3]; 1032187Smckusick term = arg[3]; 1042187Smckusick stat = arg[4]; 1053278Smckusic if (lhs == NIL) { 1063278Smckusic nogood: 1073584Speter if (forvar != NIL) { 1083584Speter forvar->value[ NL_FORV ] = FORVAR; 1093584Speter } 1102187Smckusick rvalue( init , NIL , RREQ ); 1112187Smckusick rvalue( term , NIL , RREQ ); 1122187Smckusick statement( stat ); 1132187Smckusick goto byebye; 1142187Smckusick } 1152187Smckusick /* 1162187Smckusick * and this marks the variable as used!!! 1172187Smckusick */ 1182187Smckusick forvar = lookup( lhs[2] ); 1192187Smckusick if ( forvar == NIL ) { 1203278Smckusic goto nogood; 1212187Smckusick } 12210798Speter saved_nl = *forvar; 1233278Smckusic if ( lhs[3] != NIL ) { 1243278Smckusic error("For variable %s must be unqualified", forvar->symbol); 1253278Smckusic goto nogood; 1263278Smckusic } 1273278Smckusic if (forvar->class == WITHPTR) { 1283278Smckusic error("For variable %s cannot be an element of a record", lhs[2]); 1293278Smckusic goto nogood; 1303278Smckusic } 1313836Speter if ( opt('s') && 1323836Speter ( ( bn != cbn ) || 1333836Speter #ifdef OBJ 13410798Speter (whereis(bn, forvar->value[NL_OFFS], 0) == PARAMVAR) 1353836Speter #endif OBJ 1363836Speter #ifdef PC 13710798Speter (whereis(bn, forvar->value[NL_OFFS], forvar->extra_flags) 1383836Speter == PARAMVAR ) 1393836Speter #endif PC 1403836Speter ) ) { 1413278Smckusic standard(); 1423278Smckusic error("For variable %s must be declared in the block in which it is used", forvar->symbol); 1433278Smckusic } 1442187Smckusick /* 1452187Smckusick * find out the type of the loop variable 1462187Smckusick */ 1472187Smckusick codeoff(); 1482187Smckusick fortype = lvalue( lhs , MOD , RREQ ); 1492187Smckusick codeon(); 1502187Smckusick if ( fortype == NIL ) { 1513278Smckusic goto nogood; 1522187Smckusick } 1532187Smckusick if ( isnta( fortype , "bcis" ) ) { 1543278Smckusic error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) ); 1553278Smckusic goto nogood; 1562187Smckusick } 1573584Speter if ( forvar->value[ NL_FORV ] & FORVAR ) { 1583584Speter error("Can't modify the for variable %s in the range of the loop", forvar->symbol); 1593584Speter forvar = NIL; 1603584Speter goto nogood; 1613584Speter } 16210798Speter forwidth = lwidth(fortype); 16310798Speter # ifdef PC 16410798Speter forp2type = p2type(fortype); 16510798Speter # endif PC 1662187Smckusick /* 16710798Speter * allocate temporaries for the initial and final expressions 16810798Speter * and maybe a register to shadow the for variable. 1692187Smckusick */ 17010798Speter initnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG); 17110798Speter termnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG); 17210798Speter shadownlp = tmpalloc(forwidth, fortype, REGOK); 1732187Smckusick # ifdef PC 1742187Smckusick /* 1752187Smckusick * compute and save the initial expression 1762187Smckusick */ 1773836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 17810798Speter initnlp -> extra_flags , P2INT ); 1792187Smckusick # endif PC 1802187Smckusick # ifdef OBJ 1813836Speter put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 1822187Smckusick # endif OBJ 1832187Smckusick inittype = rvalue( init , fortype , RREQ ); 1842187Smckusick if ( incompat( inittype , fortype , init ) ) { 1852187Smckusick cerror("Type of initial expression clashed with index type in 'for' statement"); 1863584Speter if (forvar != NIL) { 1873584Speter forvar->value[ NL_FORV ] = FORVAR; 1883584Speter } 1892187Smckusick rvalue( term , NIL , RREQ ); 1902187Smckusick statement( stat ); 1912187Smckusick goto byebye; 1922187Smckusick } 1932187Smckusick # ifdef PC 19410798Speter sconv(p2type(inittype), P2INT); 19510798Speter putop( P2ASSIGN , P2INT ); 1962187Smckusick putdot( filename , line ); 1972187Smckusick /* 1982187Smckusick * compute and save the termination expression 1992187Smckusick */ 2003836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 20110798Speter termnlp -> extra_flags , P2INT ); 2022187Smckusick # endif PC 2032187Smckusick # ifdef OBJ 20410798Speter gen(O_AS2, O_AS2, sizeof(long), width(inittype)); 2052187Smckusick /* 2062187Smckusick * compute and save the termination expression 2072187Smckusick */ 2083836Speter put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 2092187Smckusick # endif OBJ 2102187Smckusick termtype = rvalue( term , fortype , RREQ ); 2112187Smckusick if ( incompat( termtype , fortype , term ) ) { 2122187Smckusick cerror("Type of limit expression clashed with index type in 'for' statement"); 2133584Speter if (forvar != NIL) { 2143584Speter forvar->value[ NL_FORV ] = FORVAR; 2153584Speter } 2162187Smckusick statement( stat ); 2172187Smckusick goto byebye; 2182187Smckusick } 2192187Smckusick # ifdef PC 22010798Speter sconv(p2type(termtype), P2INT); 22110798Speter putop( P2ASSIGN , P2INT ); 2222187Smckusick putdot( filename , line ); 2232187Smckusick /* 2242187Smckusick * we can skip the loop altogether if !( init <= term ) 2252187Smckusick */ 2262187Smckusick after = getlab(); 2273836Speter putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 22810798Speter initnlp -> extra_flags , P2INT ); 2293836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 23010798Speter termnlp -> extra_flags , P2INT ); 23110798Speter putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , P2INT ); 2322187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 2332187Smckusick putop( P2CBRANCH , P2INT ); 2342187Smckusick putdot( filename , line ); 2352187Smckusick /* 23610798Speter * okay, so we have to execute the loop body, 23710798Speter * but first, if checking is on, 23810798Speter * check that the termination expression 23910798Speter * is assignment compatible with the control-variable. 24010798Speter */ 24110798Speter if (opt('t')) { 24210798Speter precheck(fortype, "_RANG4", "_RSNG4"); 24310798Speter putRV(0, cbn, termnlp -> value[NL_OFFS], 24410798Speter termnlp -> extra_flags, P2INT); 24510798Speter postcheck(fortype, nl+T4INT); 24610798Speter putdot(filename, line); 24710798Speter } 24810798Speter /* 24910798Speter * assign the initial expression to the shadow 25010798Speter * checking the assignment if necessary. 25110798Speter */ 25210798Speter putRV(0, cbn, shadownlp -> value[NL_OFFS], 25310798Speter shadownlp -> extra_flags, forp2type); 25410798Speter if (opt('t')) { 25510798Speter precheck(fortype, "_RANG4", "_RSNG4"); 25610798Speter putRV(0, cbn, initnlp -> value[NL_OFFS], 25710798Speter initnlp -> extra_flags, P2INT); 25810798Speter postcheck(fortype, nl+T4INT); 25910798Speter } else { 26010798Speter putRV(0, cbn, initnlp -> value[NL_OFFS], 26110798Speter initnlp -> extra_flags, P2INT); 26210798Speter } 26310798Speter sconv(P2INT, forp2type); 26410798Speter putop(P2ASSIGN, forp2type); 26510798Speter putdot(filename, line); 26610798Speter /* 2673278Smckusic * put down the label at the top of the loop 2683278Smckusic */ 2693278Smckusic again = getlab(); 2703278Smckusic putlab( again ); 2713278Smckusic /* 27210798Speter * each time through the loop 27310798Speter * assign the shadow to the for variable. 2742187Smckusick */ 27510798Speter lvalue(lhs, NOUSE, RREQ); 27610798Speter putRV(0, cbn, shadownlp -> value[NL_OFFS], 27710798Speter shadownlp -> extra_flags, forp2type); 27810798Speter putop(P2ASSIGN, forp2type); 27910798Speter putdot(filename, line); 2802187Smckusick # endif PC 2812187Smckusick # ifdef OBJ 28210798Speter gen(O_AS2, O_AS2, sizeof(long), width(termtype)); 2832187Smckusick /* 2842187Smckusick * we can skip the loop altogether if !( init <= term ) 2852187Smckusick */ 28610798Speter put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 28710798Speter put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 28810798Speter gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long), 28910798Speter sizeof(long)); 2902187Smckusick after = getlab(); 2912187Smckusick put(2, O_IF, after); 2922187Smckusick /* 29310798Speter * okay, so we have to execute the loop body, 29410798Speter * but first, if checking is on, 29510798Speter * check that the termination expression 29610798Speter * is assignment compatible with the control-variable. 29710798Speter */ 29810798Speter if (opt('t')) { 29910798Speter put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] ); 30010798Speter put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 30110798Speter rangechk(fortype, nl+T4INT); 30210798Speter gen(O_AS2, O_AS2, forwidth, sizeof(long)); 30310798Speter } 30410798Speter /* 30510798Speter * assign the initial expression to the shadow 30610798Speter * checking the assignment if necessary. 30710798Speter */ 30810798Speter put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] ); 30910798Speter put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 31010798Speter rangechk(fortype, nl+T4INT); 31110798Speter gen(O_AS2, O_AS2, forwidth, sizeof(long)); 31210798Speter /* 3133278Smckusic * put down the label at the top of the loop 3143278Smckusic */ 3153278Smckusic again = getlab(); 3163278Smckusic putlab( again ); 3173278Smckusic /* 31810798Speter * each time through the loop 31910798Speter * assign the shadow to the for variable. 3202187Smckusick */ 32110798Speter lvalue(lhs, NOUSE, RREQ); 32210798Speter stackRV(shadownlp); 32310798Speter gen(O_AS2, O_AS2, forwidth, sizeof(long)); 3242187Smckusick # endif OBJ 3252187Smckusick /* 3263584Speter * shadowing the real for variable 32710798Speter * with the shadow temporary: 32810798Speter * save the real for variable flags (including nl_block). 32910798Speter * replace them with the shadow's offset, 33010798Speter * and mark the for variable as being a for variable. 3313584Speter */ 33210842Smckusick shadownlp -> nl_flags |= NLFLAGS(forvar -> nl_flags); 33310798Speter *forvar = *shadownlp; 33410798Speter forvar -> symbol = saved_nl.symbol; 33510798Speter forvar -> nl_next = saved_nl.nl_next; 33610798Speter forvar -> type = saved_nl.type; 3373584Speter forvar -> value[ NL_FORV ] = FORVAR; 3383584Speter /* 3392187Smckusick * and don't forget ... 3402187Smckusick */ 3413278Smckusic putcnt(); 3423278Smckusic statement( stat ); 3432187Smckusick /* 3442187Smckusick * wasn't that fun? do we get to do it again? 3452187Smckusick * we don't do it again if ( !( forvar < limit ) ) 3462187Smckusick * pretend we were doing this at the top of the loop 3472187Smckusick */ 3482187Smckusick line = arg[ 1 ]; 3492187Smckusick # ifdef PC 3502187Smckusick if ( opt( 'p' ) ) { 3512187Smckusick if ( opt('t') ) { 3522187Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 3532187Smckusick , "_LINO" ); 3542187Smckusick putop( P2UNARY P2CALL , P2INT ); 3552187Smckusick putdot( filename , line ); 3562187Smckusick } else { 3573836Speter putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT ); 3582187Smckusick putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 3592187Smckusick putop( P2ASG P2PLUS , P2INT ); 3602187Smckusick putdot( filename , line ); 3612187Smckusick } 3622187Smckusick } 3633836Speter /*rvalue( lhs , NIL , RREQ );*/ 36410798Speter putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] , 36510798Speter shadownlp -> extra_flags , forp2type ); 36610798Speter sconv(forp2type, P2INT); 3673836Speter putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 36810798Speter termnlp -> extra_flags , P2INT ); 3693836Speter putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT ); 3702187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 3712187Smckusick putop( P2CBRANCH , P2INT ); 3722187Smckusick putdot( filename , line ); 3732187Smckusick /* 3742187Smckusick * okay, so we have to do it again, 3752187Smckusick * but first, increment the for variable. 37610798Speter * no need to rangecheck it, since we checked the 37710798Speter * termination value before we started. 3782187Smckusick */ 3793836Speter /*lvalue( lhs , MOD , RREQ );*/ 38010798Speter putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] , 38110798Speter shadownlp -> extra_flags , forp2type ); 3823836Speter /*rvalue( lhs , NIL , RREQ );*/ 38310798Speter putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] , 38410798Speter shadownlp -> extra_flags , forp2type ); 38510798Speter sconv(forp2type, P2INT); 3863633Smckusic putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 3873633Smckusic putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT ); 38810798Speter sconv(P2INT, forp2type); 38910798Speter putop( P2ASSIGN , forp2type ); 3902187Smckusick putdot( filename , line ); 3912187Smckusick /* 3922187Smckusick * and do it all again 3932187Smckusick */ 3942187Smckusick putjbr( again ); 3952187Smckusick /* 3962187Smckusick * and here we are 3972187Smckusick */ 3982187Smckusick putlab( after ); 3992187Smckusick # endif PC 4002187Smckusick # ifdef OBJ 4012187Smckusick /* 4022187Smckusick * okay, so we have to do it again. 4032187Smckusick * Luckily we have a magic opcode which increments the 4042187Smckusick * index variable, checks the limit falling through if 40510798Speter * it has been reached, else updating the index variable, 40610798Speter * and returning to the top of the loop. 4072187Smckusick */ 4082649Speter putline(); 40910798Speter put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 41010798Speter put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] ); 41110798Speter put(2, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + (forwidth >> 1), 41210798Speter again); 4132187Smckusick /* 4142187Smckusick * and here we are 4152187Smckusick */ 4162187Smckusick patch( after ); 4172187Smckusick # endif OBJ 4182187Smckusick byebye: 4192187Smckusick noreach = 0; 4203584Speter if (forvar != NIL) { 42110842Smckusick saved_nl.nl_flags |= NLFLAGS(forvar -> nl_flags) & (NUSED|NMOD); 42210798Speter *forvar = saved_nl; 4232187Smckusick } 4242187Smckusick if ( goc != gocnt ) { 4252187Smckusick putcnt(); 4262187Smckusick } 4272187Smckusick } 428