12187Smckusick /* Copyright (c) 1979 Regents of the University of California */ 22187Smckusick 3*3230Smckusic static char sccsid[] = "@(#)forop.c 1.4 03/11/81"; 42187Smckusick 52187Smckusick #include "whoami.h" 62187Smckusick #include "0.h" 72187Smckusick #include "opcode.h" 82187Smckusick #include "tree.h" 92187Smckusick #include "objfmt.h" 102187Smckusick #ifdef PC 112187Smckusick # include "pc.h" 122187Smckusick # include "pcops.h" 132187Smckusick #endif PC 142187Smckusick /* 152187Smckusick * forop for pc: 162187Smckusick * this evaluates the initial and termination expressions, 172187Smckusick * checks them to see if the loop executes at all, and then 182187Smckusick * does the assignment and the loop. 192187Smckusick * arg here looks like: 202187Smckusick * arg[0] T_FORU or T_FORD 212187Smckusick * [1] lineof "for" 222187Smckusick * [2] [0] T_ASGN 232187Smckusick * [1] lineof ":=" 242187Smckusick * [2] [0] T_VAR 252187Smckusick * [1] lineof id 262187Smckusick * [2] char * to id 272187Smckusick * [3] qualifications 282187Smckusick * [3] initial expression 292187Smckusick * [3] termination expression 302187Smckusick * [4] statement 312187Smckusick */ 322187Smckusick forop( arg ) 332187Smckusick int *arg; 342187Smckusick { 352187Smckusick int *lhs; 362187Smckusick struct nl *forvar; 372187Smckusick struct nl *fortype; 382187Smckusick int forctype; 392187Smckusick int *init; 402187Smckusick struct nl *inittype; 412187Smckusick int initoff; 422187Smckusick int *term; 432187Smckusick struct nl *termtype; 442187Smckusick int termoff; 452187Smckusick int *stat; 462187Smckusick int goc; /* saved gocnt */ 472187Smckusick int again; /* label at the top of the loop */ 482187Smckusick int after; /* label after the end of the loop */ 492187Smckusick 502187Smckusick goc = gocnt; 512187Smckusick forvar = NIL; 522187Smckusick if ( arg == NIL ) { 532187Smckusick goto byebye; 542187Smckusick } 552187Smckusick if ( arg[2] == NIL ) { 562187Smckusick goto byebye; 572187Smckusick } 582187Smckusick line = arg[1]; 592187Smckusick putline(); 602187Smckusick lhs = ( (int *) arg[2] )[2]; 612187Smckusick init = ( (int *) arg[2] )[3]; 622187Smckusick term = arg[3]; 632187Smckusick stat = arg[4]; 642187Smckusick if ( lhs[3] != NIL ) { 652187Smckusick error("For variable must be unqualified"); 662187Smckusick rvalue( init , NIL , RREQ ); 672187Smckusick rvalue( term , NIL , RREQ ); 682187Smckusick statement( stat ); 692187Smckusick goto byebye; 702187Smckusick } 712187Smckusick /* 722187Smckusick * and this marks the variable as used!!! 732187Smckusick */ 742187Smckusick forvar = lookup( lhs[2] ); 752187Smckusick if ( forvar == NIL ) { 762187Smckusick rvalue( init , NIL , RREQ ); 772187Smckusick rvalue( term , NIL , RREQ ); 782187Smckusick statement( stat ); 792187Smckusick goto byebye; 802187Smckusick } 812187Smckusick /* 822187Smckusick * find out the type of the loop variable 832187Smckusick */ 842187Smckusick codeoff(); 852187Smckusick fortype = lvalue( lhs , MOD , RREQ ); 862187Smckusick codeon(); 872187Smckusick /* 882187Smckusick * mark the forvar so we can't change it during the loop 892187Smckusick */ 902187Smckusick forvar -> value[ NL_FORV ] = 1; 912187Smckusick if ( fortype == NIL ) { 922187Smckusick rvalue( init , NIL , RREQ ); 932187Smckusick rvalue( term , NIL , RREQ ); 942187Smckusick statement( stat ); 952187Smckusick goto byebye; 962187Smckusick } 972187Smckusick if ( isnta( fortype , "bcis" ) ) { 982187Smckusick error("For variables cannot be %ss" , nameof( fortype ) ); 992187Smckusick rvalue( init , NIL , RREQ ); 1002187Smckusick rvalue( term , NIL , RREQ ); 1012187Smckusick statement( stat ); 1022187Smckusick goto byebye; 1032187Smckusick } 1042187Smckusick /* 1052187Smckusick * allocate space for the initial and termination expressions 1062187Smckusick */ 107*3230Smckusic initoff = tmpalloc(sizeof(long), nl+T4INT, REGOK); 108*3230Smckusic termoff = tmpalloc(sizeof(long), nl+T4INT, REGOK); 1092187Smckusick # ifdef PC 1102187Smckusick /* 1112187Smckusick * compute and save the initial expression 1122187Smckusick */ 1132187Smckusick forctype = p2type( fortype ); 1142187Smckusick putRV( 0 , cbn , initoff , forctype ); 1152187Smckusick # endif PC 1162187Smckusick # ifdef OBJ 1172187Smckusick put(2, O_LV | cbn<<8+INDX, initoff); 1182187Smckusick # endif OBJ 1192187Smckusick inittype = rvalue( init , fortype , RREQ ); 1202187Smckusick if ( incompat( inittype , fortype , init ) ) { 1212187Smckusick cerror("Type of initial expression clashed with index type in 'for' statement"); 1222187Smckusick rvalue( term , NIL , RREQ ); 1232187Smckusick statement( stat ); 1242187Smckusick goto byebye; 1252187Smckusick } 1262187Smckusick # ifdef PC 1272187Smckusick putop( P2ASSIGN , forctype ); 1282187Smckusick putdot( filename , line ); 1292187Smckusick /* 1302187Smckusick * compute and save the termination expression 1312187Smckusick */ 1322187Smckusick putRV( 0 , cbn , termoff , forctype ); 1332187Smckusick # endif PC 1342187Smckusick # ifdef OBJ 1353083Smckusic gen(O_AS2, O_AS2, sizeof(long), width(inittype)); 1362187Smckusick /* 1372187Smckusick * compute and save the termination expression 1382187Smckusick */ 1392187Smckusick put(2, O_LV | cbn<<8+INDX, termoff); 1402187Smckusick # endif OBJ 1412187Smckusick termtype = rvalue( term , fortype , RREQ ); 1422187Smckusick if ( incompat( termtype , fortype , term ) ) { 1432187Smckusick cerror("Type of limit expression clashed with index type in 'for' statement"); 1442187Smckusick statement( stat ); 1452187Smckusick goto byebye; 1462187Smckusick } 1472187Smckusick # ifdef PC 1482187Smckusick putop( P2ASSIGN , forctype ); 1492187Smckusick putdot( filename , line ); 1502187Smckusick /* 1512187Smckusick * we can skip the loop altogether if !( init <= term ) 1522187Smckusick */ 1532187Smckusick after = getlab(); 1542187Smckusick putRV( 0 , cbn , initoff , forctype ); 1552187Smckusick putRV( 0 , cbn , termoff , forctype ); 1562187Smckusick putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , forctype ); 1572187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 1582187Smckusick putop( P2CBRANCH , P2INT ); 1592187Smckusick putdot( filename , line ); 1602187Smckusick /* 1612187Smckusick * okay, then we have to execute the body, but first, 1622187Smckusick * assign the initial expression to the for variable. 1632187Smckusick * see the note in asgnop1 about why this is an rvalue. 1642187Smckusick */ 1652187Smckusick rvalue( lhs , NIL , RREQ ); 1662187Smckusick if ( opt( 't' ) ) { 1672187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 1682187Smckusick } 1692187Smckusick putRV( 0 , cbn , initoff , forctype ); 1702187Smckusick if ( opt( 't' ) ) { 1712187Smckusick postcheck( fortype ); 1722187Smckusick } 1732187Smckusick putop( P2ASSIGN , forctype ); 1742187Smckusick putdot( filename , line ); 1752187Smckusick # endif PC 1762187Smckusick # ifdef OBJ 1773083Smckusic gen(O_AS2, O_AS2, sizeof(long), width(termtype)); 1782187Smckusick /* 1792187Smckusick * we can skip the loop altogether if !( init <= term ) 1802187Smckusick */ 1812187Smckusick put(2, O_RV4 | cbn<<8+INDX, initoff); 1822187Smckusick put(2, O_RV4 | cbn<<8+INDX, termoff); 1832187Smckusick gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long), 1842187Smckusick sizeof(long)); 1852187Smckusick after = getlab(); 1862187Smckusick put(2, O_IF, after); 1872187Smckusick /* 1882187Smckusick * okay, then we have to execute the body, but first, 1892187Smckusick * assign the initial expression to the for variable. 1902187Smckusick */ 1912187Smckusick lvalue( lhs , NOUSE , LREQ ); 1922187Smckusick put(2, O_RV4 | cbn<<8+INDX, initoff); 1932187Smckusick rangechk(fortype, nl+T4INT); 1943083Smckusic gen(O_AS2, O_AS2, width(fortype), sizeof(long)); 1952187Smckusick # endif OBJ 1962187Smckusick /* 1972187Smckusick * put down the label at the top of the loop 1982187Smckusick */ 1992187Smckusick again = getlab(); 2002187Smckusick putlab( again ); 2012187Smckusick putcnt(); 2022187Smckusick /* 2032187Smckusick * and don't forget ... 2042187Smckusick */ 2052187Smckusick statement( arg[ 4 ] ); 2062187Smckusick /* 2072187Smckusick * wasn't that fun? do we get to do it again? 2082187Smckusick * we don't do it again if ( !( forvar < limit ) ) 2092187Smckusick * pretend we were doing this at the top of the loop 2102187Smckusick */ 2112187Smckusick line = arg[ 1 ]; 2122187Smckusick # ifdef PC 2132187Smckusick if ( opt( 'p' ) ) { 2142187Smckusick if ( opt('t') ) { 2152187Smckusick putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 2162187Smckusick , "_LINO" ); 2172187Smckusick putop( P2UNARY P2CALL , P2INT ); 2182187Smckusick putdot( filename , line ); 2192187Smckusick } else { 2202187Smckusick putRV( STMTCOUNT , 0 , 0 , P2INT ); 2212187Smckusick putleaf( P2ICON , 1 , 0 , P2INT , 0 ); 2222187Smckusick putop( P2ASG P2PLUS , P2INT ); 2232187Smckusick putdot( filename , line ); 2242187Smckusick } 2252187Smckusick } 2262187Smckusick rvalue( lhs , NIL , RREQ ); 2272187Smckusick putRV( 0 , cbn , termoff , forctype ); 2282187Smckusick putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , forctype ); 2292187Smckusick putleaf( P2ICON , after , 0 , P2INT , 0 ); 2302187Smckusick putop( P2CBRANCH , P2INT ); 2312187Smckusick putdot( filename , line ); 2322187Smckusick /* 2332187Smckusick * okay, so we have to do it again, 2342187Smckusick * but first, increment the for variable. 2352187Smckusick * there it is again, an rvalue on the lhs of an assignment. 2362187Smckusick */ 2372187Smckusick rvalue( lhs , NIL , RREQ ); 2382187Smckusick if ( opt( 't' ) ) { 2392187Smckusick precheck( fortype , "_RANG4" , "_RSNG4" ); 2402187Smckusick } 2412187Smckusick rvalue( lhs , NIL , RREQ ); 2422187Smckusick putleaf( P2ICON , 1 , 0 , forctype , 0 ); 2432187Smckusick putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , forctype ); 2442187Smckusick if ( opt( 't' ) ) { 2452187Smckusick postcheck( fortype ); 2462187Smckusick } 2472187Smckusick putop( P2ASSIGN , forctype ); 2482187Smckusick putdot( filename , line ); 2492187Smckusick /* 2502187Smckusick * and do it all again 2512187Smckusick */ 2522187Smckusick putjbr( again ); 2532187Smckusick /* 2542187Smckusick * and here we are 2552187Smckusick */ 2562187Smckusick putlab( after ); 2572187Smckusick # endif PC 2582187Smckusick # ifdef OBJ 2592187Smckusick /* 2602187Smckusick * okay, so we have to do it again. 2612187Smckusick * Luckily we have a magic opcode which increments the 2622187Smckusick * index variable, checks the limit falling through if 2632187Smckusick * it has been reached, else range checking the result 2642187Smckusick * updating the index variable, and returning to the top 2652187Smckusick * of the loop. 2662187Smckusick */ 2672649Speter putline(); 2682187Smckusick put(2, O_RV4 | cbn<<8+INDX, termoff); 2692187Smckusick lvalue(lhs, MOD, LREQ); 2703083Smckusic if (width(fortype) <= 2) 2713083Smckusic put(4, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + 2723083Smckusic (width(fortype)>>1), (int)fortype->range[0], 2733083Smckusic (int)fortype->range[1], again); 2743083Smckusic else 2753083Smckusic put(4, (arg[0] == T_FORU ? O_FOR4U : O_FOR4D), 2763083Smckusic fortype->range[0], fortype->range[1], again); 2772187Smckusick /* 2782187Smckusick * and here we are 2792187Smckusick */ 2802187Smckusick patch( after ); 2812187Smckusick # endif OBJ 2822187Smckusick byebye: 2832187Smckusick noreach = 0; 2842187Smckusick if ( forvar != NIL ) { 2852187Smckusick forvar -> value[ NL_FORV ] = 0; 2862187Smckusick } 2872187Smckusick if ( goc != gocnt ) { 2882187Smckusick putcnt(); 2892187Smckusick } 2902187Smckusick } 291