1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: static char sccsid[] = "@(#)forop.c 5.1 (Berkeley) 6/5/85"; 9: #endif not lint 10: 11: 12: #include "whoami.h" 13: #include "0.h" 14: #include "opcode.h" 15: #include "tree.h" 16: #include "objfmt.h" 17: #ifdef PC 18: # include "pc.h" 19: # include <pcc.h> 20: #endif PC 21: #include "tmps.h" 22: #include "tree_ty.h" 23: 24: /* 25: * for-statements. 26: * 27: * the relevant quote from the standard: 6.8.3.9: 28: * ``The control-variable shall be an entire-variable whose identifier 29: * is declared in the variable-declaration-part of the block closest- 30: * containing the for-statement. The control-variable shall possess 31: * an ordinal-type, and the initial-value and the final-value shall be 32: * of a type compatible with this type. The statement of a for-statement 33: * shall not contain an assigning-reference to the control-variable 34: * of the for-statement. The value of the final-value shall be 35: * assignment-compatible with the control-variable when the initial-value 36: * is assigned to the control-variable. After a for-statement is 37: * executed (other than being left by a goto-statement leading out of it) 38: * the control-variable shall be undefined. Apart from the restrictions 39: * imposed by these requirements, the for-statement 40: * for v := e1 to e2 do body 41: * shall be equivalent to 42: * begin 43: * temp1 := e1; 44: * temp2 := e2; 45: * if temp1 <= temp2 then begin 46: * v := temp1; 47: * body; 48: * while v <> temp2 do begin 49: * v := succ(v); 50: * body; 51: * end 52: * end 53: * end 54: * where temp1 and temp2 denote auxiliary variables that the program 55: * does not otherwise contain, and that possess the type possessed by 56: * the variable v if that type is not a subrange-type; otherwise the 57: * host type possessed by the variable v.'' 58: * 59: * The Berkeley Pascal systems try to do all that without duplicating 60: * the body, and shadowing the control-variable in (possibly) a 61: * register variable. 62: * 63: * arg here looks like: 64: * arg[0] T_FORU or T_FORD 65: * [1] lineof "for" 66: * [2] [0] T_ASGN 67: * [1] lineof ":=" 68: * [2] [0] T_VAR 69: * [1] lineof id 70: * [2] char * to id 71: * [3] qualifications 72: * [3] initial expression 73: * [3] termination expression 74: * [4] statement 75: */ 76: forop( tree_node) 77: struct tnode *tree_node; 78: { 79: struct tnode *lhs; 80: VAR_NODE *lhs_node; 81: FOR_NODE *f_node; 82: struct nl *forvar; 83: struct nl *fortype; 84: #ifdef PC 85: int forp2type; 86: #endif PC 87: int forwidth; 88: struct tnode *init_node; 89: struct nl *inittype; 90: struct nl *initnlp; /* initial value namelist entry */ 91: struct tnode *term_node; 92: struct nl *termtype; 93: struct nl *termnlp; /* termination value namelist entry */ 94: struct nl *shadownlp; /* namelist entry for the shadow */ 95: struct tnode *stat_node; 96: int goc; /* saved gocnt */ 97: int again; /* label at the top of the loop */ 98: int after; /* label after the end of the loop */ 99: struct nl saved_nl; /* saved namelist entry for loop var */ 100: 101: goc = gocnt; 102: forvar = NLNIL; 103: if ( tree_node == TR_NIL ) { 104: goto byebye; 105: } 106: f_node = &(tree_node->for_node); 107: if ( f_node->init_asg == TR_NIL ) { 108: goto byebye; 109: } 110: line = f_node->line_no; 111: putline(); 112: lhs = f_node->init_asg->asg_node.lhs_var; 113: init_node = f_node->init_asg->asg_node.rhs_expr; 114: term_node = f_node->term_expr; 115: stat_node = f_node->for_stmnt; 116: if (lhs == TR_NIL) { 117: nogood: 118: if (forvar != NIL) { 119: forvar->value[ NL_FORV ] = FORVAR; 120: } 121: (void) rvalue( init_node , NLNIL , RREQ ); 122: (void) rvalue( term_node , NLNIL , RREQ ); 123: statement( stat_node ); 124: goto byebye; 125: } 126: else lhs_node = &(lhs->var_node); 127: /* 128: * and this marks the variable as used!!! 129: */ 130: forvar = lookup( lhs_node->cptr ); 131: if ( forvar == NIL ) { 132: goto nogood; 133: } 134: saved_nl = *forvar; 135: if ( lhs_node->qual != TR_NIL ) { 136: error("For variable %s must be unqualified", forvar->symbol); 137: goto nogood; 138: } 139: if (forvar->class == WITHPTR) { 140: error("For variable %s cannot be an element of a record", 141: lhs_node->cptr); 142: goto nogood; 143: } 144: if ( opt('s') && 145: ( ( bn != cbn ) || 146: #ifdef OBJ 147: (whereis(forvar->value[NL_OFFS], 0) == PARAMVAR) 148: #endif OBJ 149: #ifdef PC 150: (whereis(forvar->value[NL_OFFS], forvar->extra_flags) 151: == PARAMVAR ) 152: #endif PC 153: ) ) { 154: standard(); 155: error("For variable %s must be declared in the block in which it is used", forvar->symbol); 156: } 157: /* 158: * find out the type of the loop variable 159: */ 160: codeoff(); 161: fortype = lvalue( lhs , MOD , RREQ ); 162: codeon(); 163: if ( fortype == NLNIL ) { 164: goto nogood; 165: } 166: if ( isnta( fortype , "bcis" ) ) { 167: error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) ); 168: goto nogood; 169: } 170: if ( forvar->value[ NL_FORV ] & FORVAR ) { 171: error("Can't modify the for variable %s in the range of the loop", forvar->symbol); 172: forvar = NLNIL; 173: goto nogood; 174: } 175: forwidth = lwidth(fortype); 176: # ifdef PC 177: forp2type = p2type(fortype); 178: # endif PC 179: /* 180: * allocate temporaries for the initial and final expressions 181: * and maybe a register to shadow the for variable. 182: */ 183: initnlp = tmpalloc((long) sizeof(long), nl+T4INT, NOREG); 184: termnlp = tmpalloc((long) sizeof(long), nl+T4INT, NOREG); 185: shadownlp = tmpalloc((long) forwidth, fortype, REGOK); 186: # ifdef PC 187: /* 188: * compute and save the initial expression 189: */ 190: putRV((char *) 0 , cbn , initnlp -> value[ NL_OFFS ] , 191: initnlp -> extra_flags , PCCT_INT ); 192: # endif PC 193: # ifdef OBJ 194: (void) put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 195: # endif OBJ 196: inittype = rvalue( init_node , fortype , RREQ ); 197: if ( incompat( inittype , fortype , init_node ) ) { 198: cerror("Type of initial expression clashed with index type in 'for' statement"); 199: if (forvar != NLNIL) { 200: forvar->value[ NL_FORV ] = FORVAR; 201: } 202: (void) rvalue( term_node , NLNIL , RREQ ); 203: statement( stat_node ); 204: goto byebye; 205: } 206: # ifdef PC 207: sconv(p2type(inittype), PCCT_INT); 208: putop( PCC_ASSIGN , PCCT_INT ); 209: putdot( filename , line ); 210: /* 211: * compute and save the termination expression 212: */ 213: putRV((char *) 0 , cbn , termnlp -> value[ NL_OFFS ] , 214: termnlp -> extra_flags , PCCT_INT ); 215: # endif PC 216: # ifdef OBJ 217: (void) gen(O_AS2, O_AS2, sizeof(long), width(inittype)); 218: /* 219: * compute and save the termination expression 220: */ 221: (void) put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 222: # endif OBJ 223: termtype = rvalue( term_node , fortype , RREQ ); 224: if ( incompat( termtype , fortype , term_node ) ) { 225: cerror("Type of limit expression clashed with index type in 'for' statement"); 226: if (forvar != NLNIL) { 227: forvar->value[ NL_FORV ] = FORVAR; 228: } 229: statement( stat_node ); 230: goto byebye; 231: } 232: # ifdef PC 233: sconv(p2type(termtype), PCCT_INT); 234: putop( PCC_ASSIGN , PCCT_INT ); 235: putdot( filename , line ); 236: /* 237: * we can skip the loop altogether if !( init <= term ) 238: */ 239: after = (int) getlab(); 240: putRV((char *) 0 , cbn , initnlp -> value[ NL_OFFS ] , 241: initnlp -> extra_flags , PCCT_INT ); 242: putRV((char *) 0 , cbn , termnlp -> value[ NL_OFFS ] , 243: termnlp -> extra_flags , PCCT_INT ); 244: putop( ( tree_node->tag == T_FORU ? PCC_LE : PCC_GE ) , PCCT_INT ); 245: putleaf( PCC_ICON , after , 0 , PCCT_INT, (char *) 0 ); 246: putop( PCC_CBRANCH , PCCT_INT ); 247: putdot( filename , line ); 248: /* 249: * okay, so we have to execute the loop body, 250: * but first, if checking is on, 251: * check that the termination expression 252: * is assignment compatible with the control-variable. 253: */ 254: if (opt('t')) { 255: precheck(fortype, "_RANG4", "_RSNG4"); 256: putRV((char *) 0, cbn, termnlp -> value[NL_OFFS], 257: termnlp -> extra_flags, PCCT_INT); 258: postcheck(fortype, nl+T4INT); 259: putdot(filename, line); 260: } 261: /* 262: * assign the initial expression to the shadow 263: * checking the assignment if necessary. 264: */ 265: putRV((char *) 0, cbn, shadownlp -> value[NL_OFFS], 266: shadownlp -> extra_flags, forp2type); 267: if (opt('t')) { 268: precheck(fortype, "_RANG4", "_RSNG4"); 269: putRV((char *) 0, cbn, initnlp -> value[NL_OFFS], 270: initnlp -> extra_flags, PCCT_INT); 271: postcheck(fortype, nl+T4INT); 272: } else { 273: putRV((char *) 0, cbn, initnlp -> value[NL_OFFS], 274: initnlp -> extra_flags, PCCT_INT); 275: } 276: sconv(PCCT_INT, forp2type); 277: putop(PCC_ASSIGN, forp2type); 278: putdot(filename, line); 279: /* 280: * put down the label at the top of the loop 281: */ 282: again = (int) getlab(); 283: (void) putlab((char *) again ); 284: /* 285: * each time through the loop 286: * assign the shadow to the for variable. 287: */ 288: (void) lvalue(lhs, NOUSE, RREQ); 289: putRV((char *) 0, cbn, shadownlp -> value[NL_OFFS], 290: shadownlp -> extra_flags, forp2type); 291: putop(PCC_ASSIGN, forp2type); 292: putdot(filename, line); 293: # endif PC 294: # ifdef OBJ 295: (void) gen(O_AS2, O_AS2, sizeof(long), width(termtype)); 296: /* 297: * we can skip the loop altogether if !( init <= term ) 298: */ 299: (void) put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 300: (void) put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 301: (void) gen(NIL, tree_node->tag == T_FORU ? T_LE : T_GE, sizeof(long), 302: sizeof(long)); 303: after = (int) getlab(); 304: (void) put(2, O_IF, after); 305: /* 306: * okay, so we have to execute the loop body, 307: * but first, if checking is on, 308: * check that the termination expression 309: * is assignment compatible with the control-variable. 310: */ 311: if (opt('t')) { 312: (void) put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] ); 313: (void) put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 314: rangechk(fortype, nl+T4INT); 315: (void) gen(O_AS2, O_AS2, forwidth, sizeof(long)); 316: } 317: /* 318: * assign the initial expression to the shadow 319: * checking the assignment if necessary. 320: */ 321: (void) put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] ); 322: (void) put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 323: rangechk(fortype, nl+T4INT); 324: (void) gen(O_AS2, O_AS2, forwidth, sizeof(long)); 325: /* 326: * put down the label at the top of the loop 327: */ 328: again = (int) getlab(); 329: (void) putlab( (char *) again ); 330: /* 331: * each time through the loop 332: * assign the shadow to the for variable. 333: */ 334: (void) lvalue(lhs, NOUSE, RREQ); 335: (void) stackRV(shadownlp); 336: (void) gen(O_AS2, O_AS2, forwidth, sizeof(long)); 337: # endif OBJ 338: /* 339: * shadowing the real for variable 340: * with the shadow temporary: 341: * save the real for variable flags (including nl_block). 342: * replace them with the shadow's offset, 343: * and mark the for variable as being a for variable. 344: */ 345: shadownlp -> nl_flags |= NLFLAGS(forvar -> nl_flags); 346: *forvar = *shadownlp; 347: forvar -> symbol = saved_nl.symbol; 348: forvar -> nl_next = saved_nl.nl_next; 349: forvar -> type = saved_nl.type; 350: forvar -> value[ NL_FORV ] = FORVAR; 351: /* 352: * and don't forget ... 353: */ 354: putcnt(); 355: statement( stat_node ); 356: /* 357: * wasn't that fun? do we get to do it again? 358: * we don't do it again if ( !( forvar < limit ) ) 359: * pretend we were doing this at the top of the loop 360: */ 361: line = f_node->line_no; 362: # ifdef PC 363: if ( opt( 'p' ) ) { 364: if ( opt('t') ) { 365: putleaf( PCC_ICON , 0 , 0 , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR ) 366: , "_LINO" ); 367: putop( PCCOM_UNARY PCC_CALL , PCCT_INT ); 368: putdot( filename , line ); 369: } else { 370: putRV( STMTCOUNT , 0 , 0 , NGLOBAL , PCCT_INT ); 371: putleaf( PCC_ICON , 1 , 0 , PCCT_INT , (char *) 0 ); 372: putop( PCCOM_ASG PCC_PLUS , PCCT_INT ); 373: putdot( filename , line ); 374: } 375: } 376: /*rvalue( lhs_node , NIL , RREQ );*/ 377: putRV( (char *) 0 , cbn , shadownlp -> value[ NL_OFFS ] , 378: shadownlp -> extra_flags , forp2type ); 379: sconv(forp2type, PCCT_INT); 380: putRV( (char *) 0 , cbn , termnlp -> value[ NL_OFFS ] , 381: termnlp -> extra_flags , PCCT_INT ); 382: putop( ( tree_node->tag == T_FORU ? PCC_LT : PCC_GT ) , PCCT_INT ); 383: putleaf( PCC_ICON , after , 0 , PCCT_INT , (char *) 0 ); 384: putop( PCC_CBRANCH , PCCT_INT ); 385: putdot( filename , line ); 386: /* 387: * okay, so we have to do it again, 388: * but first, increment the for variable. 389: * no need to rangecheck it, since we checked the 390: * termination value before we started. 391: */ 392: /*lvalue( lhs , MOD , RREQ );*/ 393: putRV( (char *) 0 , cbn , shadownlp -> value[ NL_OFFS ] , 394: shadownlp -> extra_flags , forp2type ); 395: /*rvalue( lhs_node , NIL , RREQ );*/ 396: putRV( (char *) 0 , cbn , shadownlp -> value[ NL_OFFS ] , 397: shadownlp -> extra_flags , forp2type ); 398: sconv(forp2type, PCCT_INT); 399: putleaf( PCC_ICON , 1 , 0 , PCCT_INT , (char *) 0 ); 400: putop( ( tree_node->tag == T_FORU ? PCC_PLUS : PCC_MINUS ) , PCCT_INT ); 401: sconv(PCCT_INT, forp2type); 402: putop( PCC_ASSIGN , forp2type ); 403: putdot( filename , line ); 404: /* 405: * and do it all again 406: */ 407: putjbr( (long) again ); 408: /* 409: * and here we are 410: */ 411: (void) putlab( (char *) after ); 412: # endif PC 413: # ifdef OBJ 414: /* 415: * okay, so we have to do it again. 416: * Luckily we have a magic opcode which increments the 417: * index variable, checks the limit falling through if 418: * it has been reached, else updating the index variable, 419: * and returning to the top of the loop. 420: */ 421: putline(); 422: (void) put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 423: (void) put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] ); 424: (void) put(2, (tree_node->tag == T_FORU ? O_FOR1U : O_FOR1D) + (forwidth >> 1), 425: again); 426: /* 427: * and here we are 428: */ 429: patch( (PTR_DCL) after ); 430: # endif OBJ 431: byebye: 432: noreach = FALSE; 433: if (forvar != NLNIL) { 434: saved_nl.nl_flags |= NLFLAGS(forvar -> nl_flags) & (NUSED|NMOD); 435: *forvar = saved_nl; 436: } 437: if ( goc != gocnt ) { 438: putcnt(); 439: } 440: }