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