148116Sbostic /*- 2*62211Sbostic * Copyright (c) 1980, 1993 3*62211Sbostic * The Regents of the University of California. All rights reserved. 448116Sbostic * 548116Sbostic * %sccs.include.redist.c% 622167Sdist */ 714732Sthien 814732Sthien #ifndef lint 9*62211Sbostic static char sccsid[] = "@(#)forop.c 8.1 (Berkeley) 06/06/93"; 1048116Sbostic #endif /* not lint */ 112187Smckusick 122187Smckusick #include "whoami.h" 132187Smckusick #include "0.h" 142187Smckusick #include "opcode.h" 152187Smckusick #include "tree.h" 162187Smckusick #include "objfmt.h" 172187Smckusick #ifdef PC 182187Smckusick # include "pc.h" 1918459Sralph # include <pcc.h> 202187Smckusick #endif PC 2111335Speter #include "tmps.h" 2214732Sthien #include "tree_ty.h" 233371Speter 242187Smckusick /* 2510798Speter * for-statements. 2610798Speter * 2710798Speter * the relevant quote from the standard: 6.8.3.9: 2810798Speter * ``The control-variable shall be an entire-variable whose identifier 2910798Speter * is declared in the variable-declaration-part of the block closest- 3010798Speter * containing the for-statement. The control-variable shall possess 3110798Speter * an ordinal-type, and the initial-value and the final-value shall be 3210798Speter * of a type compatible with this type. The statement of a for-statement 3310798Speter * shall not contain an assigning-reference to the control-variable 3410798Speter * of the for-statement. The value of the final-value shall be 3510798Speter * assignment-compatible with the control-variable when the initial-value 3610798Speter * is assigned to the control-variable. After a for-statement is 3710798Speter * executed (other than being left by a goto-statement leading out of it) 3810798Speter * the control-variable shall be undefined. Apart from the restrictions 3910798Speter * imposed by these requirements, the for-statement 4010798Speter * for v := e1 to e2 do body 4110798Speter * shall be equivalent to 4210798Speter * begin 4310798Speter * temp1 := e1; 4410798Speter * temp2 := e2; 4510798Speter * if temp1 <= temp2 then begin 4610798Speter * v := temp1; 4710798Speter * body; 4810798Speter * while v <> temp2 do begin 4910798Speter * v := succ(v); 5010798Speter * body; 5110798Speter * end 5210798Speter * end 5310798Speter * end 5410798Speter * where temp1 and temp2 denote auxiliary variables that the program 5510798Speter * does not otherwise contain, and that possess the type possessed by 5610798Speter * the variable v if that type is not a subrange-type; otherwise the 5710798Speter * host type possessed by the variable v.'' 5810798Speter * 5910798Speter * The Berkeley Pascal systems try to do all that without duplicating 6010798Speter * the body, and shadowing the control-variable in (possibly) a 6110798Speter * register variable. 6210798Speter * 632187Smckusick * arg here looks like: 642187Smckusick * arg[0] T_FORU or T_FORD 652187Smckusick * [1] lineof "for" 662187Smckusick * [2] [0] T_ASGN 672187Smckusick * [1] lineof ":=" 682187Smckusick * [2] [0] T_VAR 692187Smckusick * [1] lineof id 702187Smckusick * [2] char * to id 712187Smckusick * [3] qualifications 722187Smckusick * [3] initial expression 732187Smckusick * [3] termination expression 742187Smckusick * [4] statement 752187Smckusick */ 7614732Sthien forop( tree_node) 7714732Sthien struct tnode *tree_node; 782187Smckusick { 7914732Sthien struct tnode *lhs; 8014732Sthien VAR_NODE *lhs_node; 8114732Sthien FOR_NODE *f_node; 822187Smckusick struct nl *forvar; 832187Smckusick struct nl *fortype; 8410666Speter #ifdef PC 8510798Speter int forp2type; 8610666Speter #endif PC 8710666Speter int forwidth; 8814732Sthien struct tnode *init_node; 892187Smckusick struct nl *inittype; 903836Speter struct nl *initnlp; /* initial value namelist entry */ 9114732Sthien struct tnode *term_node; 922187Smckusick struct nl *termtype; 933836Speter struct nl *termnlp; /* termination value namelist entry */ 9410798Speter struct nl *shadownlp; /* namelist entry for the shadow */ 9514732Sthien struct tnode *stat_node; 962187Smckusick int goc; /* saved gocnt */ 972187Smckusick int again; /* label at the top of the loop */ 982187Smckusick int after; /* label after the end of the loop */ 9910798Speter struct nl saved_nl; /* saved namelist entry for loop var */ 1002187Smckusick 1012187Smckusick goc = gocnt; 10214732Sthien forvar = NLNIL; 10314732Sthien if ( tree_node == TR_NIL ) { 1042187Smckusick goto byebye; 1052187Smckusick } 10614732Sthien f_node = &(tree_node->for_node); 10714732Sthien if ( f_node->init_asg == TR_NIL ) { 1082187Smckusick goto byebye; 1092187Smckusick } 11014732Sthien line = f_node->line_no; 1112187Smckusick putline(); 11214732Sthien lhs = f_node->init_asg->asg_node.lhs_var; 11314732Sthien init_node = f_node->init_asg->asg_node.rhs_expr; 11414732Sthien term_node = f_node->term_expr; 11514732Sthien stat_node = f_node->for_stmnt; 11614732Sthien if (lhs == TR_NIL) { 1173278Smckusic nogood: 1183584Speter if (forvar != NIL) { 1193584Speter forvar->value[ NL_FORV ] = FORVAR; 1203584Speter } 12114732Sthien (void) rvalue( init_node , NLNIL , RREQ ); 12214732Sthien (void) rvalue( term_node , NLNIL , RREQ ); 12314732Sthien statement( stat_node ); 1242187Smckusick goto byebye; 1252187Smckusick } 12614732Sthien else lhs_node = &(lhs->var_node); 1272187Smckusick /* 1282187Smckusick * and this marks the variable as used!!! 1292187Smckusick */ 13014732Sthien forvar = lookup( lhs_node->cptr ); 1312187Smckusick if ( forvar == NIL ) { 1323278Smckusic goto nogood; 1332187Smckusick } 13410798Speter saved_nl = *forvar; 13514732Sthien if ( lhs_node->qual != TR_NIL ) { 1363278Smckusic error("For variable %s must be unqualified", forvar->symbol); 1373278Smckusic goto nogood; 1383278Smckusic } 1393278Smckusic if (forvar->class == WITHPTR) { 14014732Sthien error("For variable %s cannot be an element of a record", 14114732Sthien lhs_node->cptr); 1423278Smckusic goto nogood; 1433278Smckusic } 1443836Speter if ( opt('s') && 1453836Speter ( ( bn != cbn ) || 1463836Speter #ifdef OBJ 14714732Sthien (whereis(forvar->value[NL_OFFS], 0) == PARAMVAR) 1483836Speter #endif OBJ 1493836Speter #ifdef PC 15014732Sthien (whereis(forvar->value[NL_OFFS], forvar->extra_flags) 1513836Speter == PARAMVAR ) 1523836Speter #endif PC 1533836Speter ) ) { 1543278Smckusic standard(); 1553278Smckusic error("For variable %s must be declared in the block in which it is used", forvar->symbol); 1563278Smckusic } 1572187Smckusick /* 1582187Smckusick * find out the type of the loop variable 1592187Smckusick */ 1602187Smckusick codeoff(); 1612187Smckusick fortype = lvalue( lhs , MOD , RREQ ); 1622187Smckusick codeon(); 16314732Sthien if ( fortype == NLNIL ) { 1643278Smckusic goto nogood; 1652187Smckusick } 1662187Smckusick if ( isnta( fortype , "bcis" ) ) { 1673278Smckusic error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) ); 1683278Smckusic goto nogood; 1692187Smckusick } 1703584Speter if ( forvar->value[ NL_FORV ] & FORVAR ) { 1713584Speter error("Can't modify the for variable %s in the range of the loop", forvar->symbol); 17214732Sthien forvar = NLNIL; 1733584Speter goto nogood; 1743584Speter } 17510798Speter forwidth = lwidth(fortype); 17610798Speter # ifdef PC 17710798Speter forp2type = p2type(fortype); 17810798Speter # endif PC 1792187Smckusick /* 18010798Speter * allocate temporaries for the initial and final expressions 18110798Speter * and maybe a register to shadow the for variable. 1822187Smckusick */ 18314732Sthien initnlp = tmpalloc((long) sizeof(long), nl+T4INT, NOREG); 18414732Sthien termnlp = tmpalloc((long) sizeof(long), nl+T4INT, NOREG); 18514732Sthien shadownlp = tmpalloc((long) forwidth, fortype, REGOK); 1862187Smckusick # ifdef PC 1872187Smckusick /* 1882187Smckusick * compute and save the initial expression 1892187Smckusick */ 19014732Sthien putRV((char *) 0 , cbn , initnlp -> value[ NL_OFFS ] , 19118459Sralph initnlp -> extra_flags , PCCT_INT ); 1922187Smckusick # endif PC 1932187Smckusick # ifdef OBJ 19414732Sthien (void) put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 1952187Smckusick # endif OBJ 19614732Sthien inittype = rvalue( init_node , fortype , RREQ ); 19714732Sthien if ( incompat( inittype , fortype , init_node ) ) { 1982187Smckusick cerror("Type of initial expression clashed with index type in 'for' statement"); 19914732Sthien if (forvar != NLNIL) { 2003584Speter forvar->value[ NL_FORV ] = FORVAR; 2013584Speter } 20214732Sthien (void) rvalue( term_node , NLNIL , RREQ ); 20314732Sthien statement( stat_node ); 2042187Smckusick goto byebye; 2052187Smckusick } 2062187Smckusick # ifdef PC 20718459Sralph sconv(p2type(inittype), PCCT_INT); 20818459Sralph putop( PCC_ASSIGN , PCCT_INT ); 2092187Smckusick putdot( filename , line ); 2102187Smckusick /* 2112187Smckusick * compute and save the termination expression 2122187Smckusick */ 21314732Sthien putRV((char *) 0 , cbn , termnlp -> value[ NL_OFFS ] , 21418459Sralph termnlp -> extra_flags , PCCT_INT ); 2152187Smckusick # endif PC 2162187Smckusick # ifdef OBJ 21714732Sthien (void) gen(O_AS2, O_AS2, sizeof(long), width(inittype)); 2182187Smckusick /* 2192187Smckusick * compute and save the termination expression 2202187Smckusick */ 22114732Sthien (void) put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 2222187Smckusick # endif OBJ 22314732Sthien termtype = rvalue( term_node , fortype , RREQ ); 22414732Sthien if ( incompat( termtype , fortype , term_node ) ) { 2252187Smckusick cerror("Type of limit expression clashed with index type in 'for' statement"); 22614732Sthien if (forvar != NLNIL) { 2273584Speter forvar->value[ NL_FORV ] = FORVAR; 2283584Speter } 22914732Sthien statement( stat_node ); 2302187Smckusick goto byebye; 2312187Smckusick } 2322187Smckusick # ifdef PC 23318459Sralph sconv(p2type(termtype), PCCT_INT); 23418459Sralph putop( PCC_ASSIGN , PCCT_INT ); 2352187Smckusick putdot( filename , line ); 2362187Smckusick /* 2372187Smckusick * we can skip the loop altogether if !( init <= term ) 2382187Smckusick */ 23914732Sthien after = (int) getlab(); 24014732Sthien putRV((char *) 0 , cbn , initnlp -> value[ NL_OFFS ] , 24118459Sralph initnlp -> extra_flags , PCCT_INT ); 24214732Sthien putRV((char *) 0 , cbn , termnlp -> value[ NL_OFFS ] , 24318459Sralph termnlp -> extra_flags , PCCT_INT ); 24418459Sralph putop( ( tree_node->tag == T_FORU ? PCC_LE : PCC_GE ) , PCCT_INT ); 24518459Sralph putleaf( PCC_ICON , after , 0 , PCCT_INT, (char *) 0 ); 24618459Sralph putop( PCC_CBRANCH , PCCT_INT ); 2472187Smckusick putdot( filename , line ); 2482187Smckusick /* 24910798Speter * okay, so we have to execute the loop body, 25010798Speter * but first, if checking is on, 25110798Speter * check that the termination expression 25210798Speter * is assignment compatible with the control-variable. 25310798Speter */ 25410798Speter if (opt('t')) { 25510798Speter precheck(fortype, "_RANG4", "_RSNG4"); 25614732Sthien putRV((char *) 0, cbn, termnlp -> value[NL_OFFS], 25718459Sralph termnlp -> extra_flags, PCCT_INT); 25810798Speter postcheck(fortype, nl+T4INT); 25910798Speter putdot(filename, line); 26010798Speter } 26110798Speter /* 26210798Speter * assign the initial expression to the shadow 26310798Speter * checking the assignment if necessary. 26410798Speter */ 26514732Sthien putRV((char *) 0, cbn, shadownlp -> value[NL_OFFS], 26610798Speter shadownlp -> extra_flags, forp2type); 26710798Speter if (opt('t')) { 26810798Speter precheck(fortype, "_RANG4", "_RSNG4"); 26914732Sthien putRV((char *) 0, cbn, initnlp -> value[NL_OFFS], 27018459Sralph initnlp -> extra_flags, PCCT_INT); 27110798Speter postcheck(fortype, nl+T4INT); 27210798Speter } else { 27314732Sthien putRV((char *) 0, cbn, initnlp -> value[NL_OFFS], 27418459Sralph initnlp -> extra_flags, PCCT_INT); 27510798Speter } 27618459Sralph sconv(PCCT_INT, forp2type); 27718459Sralph putop(PCC_ASSIGN, forp2type); 27810798Speter putdot(filename, line); 27910798Speter /* 2803278Smckusic * put down the label at the top of the loop 2813278Smckusic */ 28214732Sthien again = (int) getlab(); 28314732Sthien (void) putlab((char *) again ); 2843278Smckusic /* 28510798Speter * each time through the loop 28610798Speter * assign the shadow to the for variable. 2872187Smckusick */ 28814732Sthien (void) lvalue(lhs, NOUSE, RREQ); 28914732Sthien putRV((char *) 0, cbn, shadownlp -> value[NL_OFFS], 29010798Speter shadownlp -> extra_flags, forp2type); 29118459Sralph putop(PCC_ASSIGN, forp2type); 29210798Speter putdot(filename, line); 2932187Smckusick # endif PC 2942187Smckusick # ifdef OBJ 29514732Sthien (void) gen(O_AS2, O_AS2, sizeof(long), width(termtype)); 2962187Smckusick /* 2972187Smckusick * we can skip the loop altogether if !( init <= term ) 2982187Smckusick */ 29914732Sthien (void) put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 30014732Sthien (void) put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 30114732Sthien (void) gen(NIL, tree_node->tag == T_FORU ? T_LE : T_GE, sizeof(long), 30210798Speter sizeof(long)); 30314732Sthien after = (int) getlab(); 30414732Sthien (void) put(2, O_IF, after); 3052187Smckusick /* 30610798Speter * okay, so we have to execute the loop body, 30710798Speter * but first, if checking is on, 30810798Speter * check that the termination expression 30910798Speter * is assignment compatible with the control-variable. 31010798Speter */ 31110798Speter if (opt('t')) { 31214732Sthien (void) put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] ); 31314732Sthien (void) put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 31410798Speter rangechk(fortype, nl+T4INT); 31514732Sthien (void) gen(O_AS2, O_AS2, forwidth, sizeof(long)); 31610798Speter } 31710798Speter /* 31810798Speter * assign the initial expression to the shadow 31910798Speter * checking the assignment if necessary. 32010798Speter */ 32114732Sthien (void) put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] ); 32214732Sthien (void) put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] ); 32310798Speter rangechk(fortype, nl+T4INT); 32414732Sthien (void) gen(O_AS2, O_AS2, forwidth, sizeof(long)); 32510798Speter /* 3263278Smckusic * put down the label at the top of the loop 3273278Smckusic */ 32814732Sthien again = (int) getlab(); 32914732Sthien (void) putlab( (char *) again ); 3303278Smckusic /* 33110798Speter * each time through the loop 33210798Speter * assign the shadow to the for variable. 3332187Smckusick */ 33414732Sthien (void) lvalue(lhs, NOUSE, RREQ); 33514732Sthien (void) stackRV(shadownlp); 33614732Sthien (void) gen(O_AS2, O_AS2, forwidth, sizeof(long)); 3372187Smckusick # endif OBJ 3382187Smckusick /* 3393584Speter * shadowing the real for variable 34010798Speter * with the shadow temporary: 34110798Speter * save the real for variable flags (including nl_block). 34210798Speter * replace them with the shadow's offset, 34310798Speter * and mark the for variable as being a for variable. 3443584Speter */ 34510842Smckusick shadownlp -> nl_flags |= NLFLAGS(forvar -> nl_flags); 34610798Speter *forvar = *shadownlp; 34710798Speter forvar -> symbol = saved_nl.symbol; 34810798Speter forvar -> nl_next = saved_nl.nl_next; 34910798Speter forvar -> type = saved_nl.type; 3503584Speter forvar -> value[ NL_FORV ] = FORVAR; 3513584Speter /* 3522187Smckusick * and don't forget ... 3532187Smckusick */ 3543278Smckusic putcnt(); 35514732Sthien statement( stat_node ); 3562187Smckusick /* 3572187Smckusick * wasn't that fun? do we get to do it again? 3582187Smckusick * we don't do it again if ( !( forvar < limit ) ) 3592187Smckusick * pretend we were doing this at the top of the loop 3602187Smckusick */ 36114732Sthien line = f_node->line_no; 3622187Smckusick # ifdef PC 3632187Smckusick if ( opt( 'p' ) ) { 3642187Smckusick if ( opt('t') ) { 36518459Sralph putleaf( PCC_ICON , 0 , 0 , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR ) 3662187Smckusick , "_LINO" ); 36718459Sralph putop( PCCOM_UNARY PCC_CALL , PCCT_INT ); 3682187Smckusick putdot( filename , line ); 3692187Smckusick } else { 37018459Sralph putRV( STMTCOUNT , 0 , 0 , NGLOBAL , PCCT_INT ); 37118459Sralph putleaf( PCC_ICON , 1 , 0 , PCCT_INT , (char *) 0 ); 37218459Sralph putop( PCCOM_ASG PCC_PLUS , PCCT_INT ); 3732187Smckusick putdot( filename , line ); 3742187Smckusick } 3752187Smckusick } 37614732Sthien /*rvalue( lhs_node , NIL , RREQ );*/ 37714732Sthien putRV( (char *) 0 , cbn , shadownlp -> value[ NL_OFFS ] , 37810798Speter shadownlp -> extra_flags , forp2type ); 37918459Sralph sconv(forp2type, PCCT_INT); 38014732Sthien putRV( (char *) 0 , cbn , termnlp -> value[ NL_OFFS ] , 38118459Sralph termnlp -> extra_flags , PCCT_INT ); 38218459Sralph putop( ( tree_node->tag == T_FORU ? PCC_LT : PCC_GT ) , PCCT_INT ); 38318459Sralph putleaf( PCC_ICON , after , 0 , PCCT_INT , (char *) 0 ); 38418459Sralph putop( PCC_CBRANCH , PCCT_INT ); 3852187Smckusick putdot( filename , line ); 3862187Smckusick /* 3872187Smckusick * okay, so we have to do it again, 3882187Smckusick * but first, increment the for variable. 38910798Speter * no need to rangecheck it, since we checked the 39010798Speter * termination value before we started. 3912187Smckusick */ 3923836Speter /*lvalue( lhs , MOD , RREQ );*/ 39314732Sthien putRV( (char *) 0 , cbn , shadownlp -> value[ NL_OFFS ] , 39410798Speter shadownlp -> extra_flags , forp2type ); 39514732Sthien /*rvalue( lhs_node , NIL , RREQ );*/ 39614732Sthien putRV( (char *) 0 , cbn , shadownlp -> value[ NL_OFFS ] , 39710798Speter shadownlp -> extra_flags , forp2type ); 39818459Sralph sconv(forp2type, PCCT_INT); 39918459Sralph putleaf( PCC_ICON , 1 , 0 , PCCT_INT , (char *) 0 ); 40018459Sralph putop( ( tree_node->tag == T_FORU ? PCC_PLUS : PCC_MINUS ) , PCCT_INT ); 40118459Sralph sconv(PCCT_INT, forp2type); 40218459Sralph putop( PCC_ASSIGN , forp2type ); 4032187Smckusick putdot( filename , line ); 4042187Smckusick /* 4052187Smckusick * and do it all again 4062187Smckusick */ 40714732Sthien putjbr( (long) again ); 4082187Smckusick /* 4092187Smckusick * and here we are 4102187Smckusick */ 41114732Sthien (void) putlab( (char *) after ); 4122187Smckusick # endif PC 4132187Smckusick # ifdef OBJ 4142187Smckusick /* 4152187Smckusick * okay, so we have to do it again. 4162187Smckusick * Luckily we have a magic opcode which increments the 4172187Smckusick * index variable, checks the limit falling through if 41810798Speter * it has been reached, else updating the index variable, 41910798Speter * and returning to the top of the loop. 4202187Smckusick */ 4212649Speter putline(); 42214732Sthien (void) put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] ); 42314732Sthien (void) put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] ); 42414732Sthien (void) put(2, (tree_node->tag == T_FORU ? O_FOR1U : O_FOR1D) + (forwidth >> 1), 42510798Speter again); 4262187Smckusick /* 4272187Smckusick * and here we are 4282187Smckusick */ 42914732Sthien patch( (PTR_DCL) after ); 4302187Smckusick # endif OBJ 4312187Smckusick byebye: 43214732Sthien noreach = FALSE; 43314732Sthien if (forvar != NLNIL) { 43410842Smckusick saved_nl.nl_flags |= NLFLAGS(forvar -> nl_flags) & (NUSED|NMOD); 43510798Speter *forvar = saved_nl; 4362187Smckusick } 4372187Smckusick if ( goc != gocnt ) { 4382187Smckusick putcnt(); 4392187Smckusick } 4402187Smckusick } 441