1 /* Copyright (c) 1979 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)forop.c 1.10 02/13/82"; 4 5 #include "whoami.h" 6 #include "0.h" 7 #include "opcode.h" 8 #include "tree.h" 9 #include "objfmt.h" 10 #ifdef PC 11 # include "pc.h" 12 # include "pcops.h" 13 #endif PC 14 15 /* 16 * forop for pc: 17 * this evaluates the initial and termination expressions, 18 * checks them to see if the loop executes at all, and then 19 * does the assignment and the loop. 20 * arg here looks like: 21 * arg[0] T_FORU or T_FORD 22 * [1] lineof "for" 23 * [2] [0] T_ASGN 24 * [1] lineof ":=" 25 * [2] [0] T_VAR 26 * [1] lineof id 27 * [2] char * to id 28 * [3] qualifications 29 * [3] initial expression 30 * [3] termination expression 31 * [4] statement 32 */ 33 forop( arg ) 34 int *arg; 35 { 36 int *lhs; 37 struct nl *forvar; 38 struct nl *fortype; 39 int *init; 40 struct nl *inittype; 41 struct nl *initnlp; /* initial value namelist entry */ 42 char forflags; 43 int *term; 44 struct nl *termtype; 45 struct nl *termnlp; /* termination value namelist entry */ 46 int *stat; 47 int goc; /* saved gocnt */ 48 int again; /* label at the top of the loop */ 49 int after; /* label after the end of the loop */ 50 struct nl shadow_nl; /* saved namelist entry for loop var */ 51 52 goc = gocnt; 53 forvar = NIL; 54 if ( arg == NIL ) { 55 goto byebye; 56 } 57 if ( arg[2] == NIL ) { 58 goto byebye; 59 } 60 line = arg[1]; 61 putline(); 62 lhs = ( (int *) arg[2] )[2]; 63 init = ( (int *) arg[2] )[3]; 64 term = arg[3]; 65 stat = arg[4]; 66 if (lhs == NIL) { 67 nogood: 68 if (forvar != NIL) { 69 forvar->value[ NL_FORV ] = FORVAR; 70 } 71 rvalue( init , NIL , RREQ ); 72 rvalue( term , NIL , RREQ ); 73 statement( stat ); 74 goto byebye; 75 } 76 /* 77 * and this marks the variable as used!!! 78 */ 79 forvar = lookup( lhs[2] ); 80 if ( forvar == NIL ) { 81 goto nogood; 82 } 83 shadow_nl = *forvar; 84 if ( lhs[3] != NIL ) { 85 error("For variable %s must be unqualified", forvar->symbol); 86 goto nogood; 87 } 88 if (forvar->class == WITHPTR) { 89 error("For variable %s cannot be an element of a record", lhs[2]); 90 goto nogood; 91 } 92 if ( opt('s') && 93 ( ( bn != cbn ) || 94 #ifdef OBJ 95 ( whereis( bn , forvar->value[NL_OFFS] , 0 ) == PARAMVAR ) 96 #endif OBJ 97 #ifdef PC 98 ( whereis( bn , forvar->value[NL_OFFS] , forvar -> extra_flags ) 99 == PARAMVAR ) 100 #endif PC 101 ) ) { 102 standard(); 103 error("For variable %s must be declared in the block in which it is used", forvar->symbol); 104 } 105 /* 106 * find out the type of the loop variable 107 */ 108 codeoff(); 109 fortype = lvalue( lhs , MOD , RREQ ); 110 codeon(); 111 if ( fortype == NIL ) { 112 goto nogood; 113 } 114 if ( isnta( fortype , "bcis" ) ) { 115 error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) ); 116 goto nogood; 117 } 118 if ( forvar->value[ NL_FORV ] & FORVAR ) { 119 error("Can't modify the for variable %s in the range of the loop", forvar->symbol); 120 forvar = NIL; 121 goto nogood; 122 } 123 /* 124 * allocate space for the initial and termination expressions 125 * the initial is tentatively placed in a register as it will 126 * shadow the for loop variable in the body of the loop. 127 */ 128 initnlp = tmpalloc(sizeof(long), nl+T4INT, REGOK); 129 termnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG); 130 # ifdef PC 131 /* 132 * compute and save the initial expression 133 */ 134 putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 135 initnlp -> extra_flags , P2INT ); 136 # endif PC 137 # ifdef OBJ 138 put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 139 # endif OBJ 140 inittype = rvalue( init , fortype , RREQ ); 141 if ( incompat( inittype , fortype , init ) ) { 142 cerror("Type of initial expression clashed with index type in 'for' statement"); 143 if (forvar != NIL) { 144 forvar->value[ NL_FORV ] = FORVAR; 145 } 146 rvalue( term , NIL , RREQ ); 147 statement( stat ); 148 goto byebye; 149 } 150 # ifdef PC 151 putop( P2ASSIGN , P2INT ); 152 putdot( filename , line ); 153 /* 154 * compute and save the termination expression 155 */ 156 putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 157 termnlp -> extra_flags , P2INT ); 158 # endif PC 159 # ifdef OBJ 160 gen(O_AS2, O_AS2, sizeof(long), width(inittype)); 161 /* 162 * compute and save the termination expression 163 */ 164 put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 165 # endif OBJ 166 termtype = rvalue( term , fortype , RREQ ); 167 if ( incompat( termtype , fortype , term ) ) { 168 cerror("Type of limit expression clashed with index type in 'for' statement"); 169 if (forvar != NIL) { 170 forvar->value[ NL_FORV ] = FORVAR; 171 } 172 statement( stat ); 173 goto byebye; 174 } 175 # ifdef PC 176 putop( P2ASSIGN , P2INT ); 177 putdot( filename , line ); 178 /* 179 * we can skip the loop altogether if !( init <= term ) 180 */ 181 after = getlab(); 182 putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 183 initnlp -> extra_flags , P2INT ); 184 putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 185 termnlp -> extra_flags , P2INT ); 186 putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , P2INT ); 187 putleaf( P2ICON , after , 0 , P2INT , 0 ); 188 putop( P2CBRANCH , P2INT ); 189 putdot( filename , line ); 190 /* 191 * put down the label at the top of the loop 192 */ 193 again = getlab(); 194 putlab( again ); 195 /* 196 * okay, then we have to execute the body, but first, 197 * assign the initial expression to the for variable. 198 * see the note in asgnop1 about why this is an rvalue. 199 */ 200 lvalue( lhs , NOUSE , RREQ ); 201 if ( opt( 't' ) ) { 202 precheck( fortype , "_RANG4" , "_RSNG4" ); 203 } 204 putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 205 initnlp -> extra_flags , P2INT ); 206 if ( opt( 't' ) ) { 207 postcheck( fortype ); 208 } 209 putop( P2ASSIGN , p2type( fortype ) ); 210 putdot( filename , line ); 211 # endif PC 212 # ifdef OBJ 213 gen(O_AS2, O_AS2, sizeof(long), width(termtype)); 214 /* 215 * we can skip the loop altogether if !( init <= term ) 216 */ 217 put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 218 put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 219 gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long), 220 sizeof(long)); 221 after = getlab(); 222 put(2, O_IF, after); 223 /* 224 * put down the label at the top of the loop 225 */ 226 again = getlab(); 227 putlab( again ); 228 /* 229 * okay, then we have to execute the body, but first, 230 * assign the initial expression to the for variable. 231 */ 232 lvalue( lhs , NOUSE , LREQ ); 233 put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 234 rangechk(fortype, nl+T4INT); 235 gen(O_AS2, O_AS2, width(fortype), sizeof(long)); 236 # endif OBJ 237 /* 238 * shadowing the real for variable 239 * with the initail expression temporary: 240 * save the real for variable's offset, flags 241 * (including nl_block). 242 * replace them with the initial expression's offset, 243 * and mark it as being a for variable. 244 */ 245 *forvar = *initnlp; 246 forvar -> symbol = shadow_nl.symbol; 247 forvar -> nl_next = shadow_nl.nl_next; 248 forvar -> value[ NL_FORV ] = FORVAR; 249 /* 250 * and don't forget ... 251 */ 252 putcnt(); 253 statement( stat ); 254 /* 255 * wasn't that fun? do we get to do it again? 256 * we don't do it again if ( !( forvar < limit ) ) 257 * pretend we were doing this at the top of the loop 258 */ 259 line = arg[ 1 ]; 260 # ifdef PC 261 if ( opt( 'p' ) ) { 262 if ( opt('t') ) { 263 putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 264 , "_LINO" ); 265 putop( P2UNARY P2CALL , P2INT ); 266 putdot( filename , line ); 267 } else { 268 putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT ); 269 putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 270 putop( P2ASG P2PLUS , P2INT ); 271 putdot( filename , line ); 272 } 273 } 274 /*rvalue( lhs , NIL , RREQ );*/ 275 putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 276 initnlp -> extra_flags , P2INT ); 277 putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 278 termnlp -> extra_flags , P2INT ); 279 putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT ); 280 putleaf( P2ICON , after , 0 , P2INT , 0 ); 281 putop( P2CBRANCH , P2INT ); 282 putdot( filename , line ); 283 /* 284 * okay, so we have to do it again, 285 * but first, increment the for variable. 286 * there it is again, an rvalue on the lhs of an assignment. 287 */ 288 /*lvalue( lhs , MOD , RREQ );*/ 289 putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 290 initnlp -> extra_flags , P2INT ); 291 if ( opt( 't' ) ) { 292 precheck( fortype , "_RANG4" , "_RSNG4" ); 293 } 294 /*rvalue( lhs , NIL , RREQ );*/ 295 putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 296 initnlp -> extra_flags , P2INT ); 297 putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 298 putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT ); 299 if ( opt( 't' ) ) { 300 postcheck( fortype ); 301 } 302 putop( P2ASSIGN , P2INT ); 303 putdot( filename , line ); 304 /* 305 * and do it all again 306 */ 307 putjbr( again ); 308 /* 309 * and here we are 310 */ 311 putlab( after ); 312 # endif PC 313 # ifdef OBJ 314 /* 315 * okay, so we have to do it again. 316 * Luckily we have a magic opcode which increments the 317 * index variable, checks the limit falling through if 318 * it has been reached, else range checking the result 319 * updating the index variable, and returning to the top 320 * of the loop. 321 */ 322 putline(); 323 put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 324 lvalue(lhs, MOD, LREQ); 325 if (width(fortype) <= 2) 326 put(4, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + 327 (width(fortype)>>1), (int)fortype->range[0], 328 (int)fortype->range[1], again); 329 else 330 put(4, (arg[0] == T_FORU ? O_FOR4U : O_FOR4D), 331 fortype->range[0], fortype->range[1], again); 332 /* 333 * and here we are 334 */ 335 patch( after ); 336 # endif OBJ 337 byebye: 338 noreach = 0; 339 if (forvar != NIL) { 340 *forvar = shadow_nl; 341 } 342 if ( goc != gocnt ) { 343 putcnt(); 344 } 345 } 346