1 /* Copyright (c) 1979 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)forop.c 1.11 02/16/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 shadow_nl.nl_flags = forvar -> nl_flags; 246 *forvar = *initnlp; 247 forvar -> symbol = shadow_nl.symbol; 248 forvar -> nl_next = shadow_nl.nl_next; 249 forvar -> type = shadow_nl.type; 250 forvar -> value[ NL_FORV ] = FORVAR; 251 /* 252 * and don't forget ... 253 */ 254 putcnt(); 255 statement( stat ); 256 /* 257 * wasn't that fun? do we get to do it again? 258 * we don't do it again if ( !( forvar < limit ) ) 259 * pretend we were doing this at the top of the loop 260 */ 261 line = arg[ 1 ]; 262 # ifdef PC 263 if ( opt( 'p' ) ) { 264 if ( opt('t') ) { 265 putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 266 , "_LINO" ); 267 putop( P2UNARY P2CALL , P2INT ); 268 putdot( filename , line ); 269 } else { 270 putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT ); 271 putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 272 putop( P2ASG P2PLUS , P2INT ); 273 putdot( filename , line ); 274 } 275 } 276 /*rvalue( lhs , NIL , RREQ );*/ 277 putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 278 initnlp -> extra_flags , P2INT ); 279 putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] , 280 termnlp -> extra_flags , P2INT ); 281 putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT ); 282 putleaf( P2ICON , after , 0 , P2INT , 0 ); 283 putop( P2CBRANCH , P2INT ); 284 putdot( filename , line ); 285 /* 286 * okay, so we have to do it again, 287 * but first, increment the for variable. 288 * there it is again, an rvalue on the lhs of an assignment. 289 */ 290 /*lvalue( lhs , MOD , RREQ );*/ 291 putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 292 initnlp -> extra_flags , P2INT ); 293 if ( opt( 't' ) ) { 294 precheck( fortype , "_RANG4" , "_RSNG4" ); 295 } 296 /*rvalue( lhs , NIL , RREQ );*/ 297 putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] , 298 initnlp -> extra_flags , P2INT ); 299 putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 300 putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT ); 301 if ( opt( 't' ) ) { 302 postcheck( fortype ); 303 } 304 putop( P2ASSIGN , P2INT ); 305 putdot( filename , line ); 306 /* 307 * and do it all again 308 */ 309 putjbr( again ); 310 /* 311 * and here we are 312 */ 313 putlab( after ); 314 # endif PC 315 # ifdef OBJ 316 /* 317 * okay, so we have to do it again. 318 * Luckily we have a magic opcode which increments the 319 * index variable, checks the limit falling through if 320 * it has been reached, else range checking the result 321 * updating the index variable, and returning to the top 322 * of the loop. 323 */ 324 putline(); 325 put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 326 lvalue(lhs, MOD, LREQ); 327 if (width(fortype) <= 2) 328 put(4, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + 329 (width(fortype)>>1), (int)fortype->range[0], 330 (int)fortype->range[1], again); 331 else 332 put(4, (arg[0] == T_FORU ? O_FOR4U : O_FOR4D), 333 fortype->range[0], fortype->range[1], again); 334 /* 335 * and here we are 336 */ 337 patch( after ); 338 # endif OBJ 339 byebye: 340 noreach = 0; 341 if (forvar != NIL) { 342 shadow_nl.nl_flags |= forvar -> nl_flags & (NUSED|NMOD); 343 *forvar = shadow_nl; 344 } 345 if ( goc != gocnt ) { 346 putcnt(); 347 } 348 } 349