xref: /csrg-svn/usr.bin/pascal/src/forop.c (revision 11335)
12187Smckusick /* Copyright (c) 1979 Regents of the University of California */
22187Smckusick 
3*11335Speter static char sccsid[] = "@(#)forop.c 1.16 02/28/83";
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
14*11335Speter #include	"tmps.h"
153371Speter 
162187Smckusick     /*
1710798Speter      *	for-statements.
1810798Speter      *
1910798Speter      *	the relevant quote from the standard:  6.8.3.9:
2010798Speter      *	``The control-variable shall be an entire-variable whose identifier
2110798Speter      *	is declared in the variable-declaration-part of the block closest-
2210798Speter      *	containing the for-statement.  The control-variable shall possess
2310798Speter      *	an ordinal-type, and the initial-value and the final-value shall be
2410798Speter      *	of a type compatible with this type.  The statement of a for-statement
2510798Speter      *	shall not contain an assigning-reference to the control-variable
2610798Speter      *	of the for-statement.  The value of the final-value shall be
2710798Speter      *	assignment-compatible with the control-variable when the initial-value
2810798Speter      *	is assigned to the control-variable.  After a for-statement is
2910798Speter      *	executed (other than being left by a goto-statement leading out of it)
3010798Speter      *	the control-variable shall be undefined.  Apart from the restrictions
3110798Speter      *	imposed by these requirements, the for-statement
3210798Speter      *		for v := e1 to e2 do body
3310798Speter      *	shall be equivalent to
3410798Speter      *		begin
3510798Speter      *		    temp1 := e1;
3610798Speter      *		    temp2 := e2;
3710798Speter      *		    if temp1 <= temp2 then begin
3810798Speter      *			v := temp1;
3910798Speter      *			body;
4010798Speter      *			while v <> temp2 do begin
4110798Speter      *			    v := succ(v);
4210798Speter      *			    body;
4310798Speter      *			end
4410798Speter      *		    end
4510798Speter      *		end
4610798Speter      *	where temp1 and temp2 denote auxiliary variables that the program
4710798Speter      *	does not otherwise contain, and that possess the type possessed by
4810798Speter      *	the variable v if that type is not a subrange-type;  otherwise the
4910798Speter      *	host type possessed by the variable v.''
5010798Speter      *
5110798Speter      *	The Berkeley Pascal systems try to do all that without duplicating
5210798Speter      *	the body, and shadowing the control-variable in (possibly) a
5310798Speter      *	register variable.
5410798Speter      *
552187Smckusick      *	arg here looks like:
562187Smckusick      *	arg[0]	T_FORU or T_FORD
572187Smckusick      *	   [1]	lineof "for"
582187Smckusick      *	   [2]	[0]	T_ASGN
592187Smckusick      *		[1]	lineof ":="
602187Smckusick      *		[2]	[0]	T_VAR
612187Smckusick      *			[1]	lineof id
622187Smckusick      *			[2]	char * to id
632187Smckusick      *			[3]	qualifications
642187Smckusick      *		[3]	initial expression
652187Smckusick      *	  [3]	termination expression
662187Smckusick      *	  [4]	statement
672187Smckusick      */
682187Smckusick forop( arg )
692187Smckusick     int	*arg;
702187Smckusick     {
712187Smckusick 	int		*lhs;
722187Smckusick 	struct nl	*forvar;
732187Smckusick 	struct nl	*fortype;
7410666Speter #ifdef PC
7510798Speter 	int		forp2type;
7610666Speter #endif PC
7710666Speter 	int		forwidth;
782187Smckusick 	int		*init;
792187Smckusick 	struct nl	*inittype;
803836Speter 	struct nl	*initnlp;	/* initial value namelist entry */
812187Smckusick 	int		*term;
822187Smckusick 	struct nl	*termtype;
833836Speter 	struct nl	*termnlp;	/* termination value namelist entry */
8410798Speter 	struct nl	*shadownlp;	/* namelist entry for the shadow */
852187Smckusick 	int		*stat;
862187Smckusick 	int		goc;		/* saved gocnt */
872187Smckusick 	int		again;		/* label at the top of the loop */
882187Smckusick 	int		after;		/* label after the end of the loop */
8910798Speter 	struct nl	saved_nl;	/* saved namelist entry for loop var */
902187Smckusick 
912187Smckusick 	goc = gocnt;
922187Smckusick 	forvar = NIL;
932187Smckusick 	if ( arg == NIL ) {
942187Smckusick 	    goto byebye;
952187Smckusick 	}
962187Smckusick 	if ( arg[2] == NIL ) {
972187Smckusick 	    goto byebye;
982187Smckusick 	}
992187Smckusick 	line = arg[1];
1002187Smckusick 	putline();
1012187Smckusick 	lhs = ( (int *) arg[2] )[2];
1022187Smckusick 	init = ( (int *) arg[2] )[3];
1032187Smckusick 	term = arg[3];
1042187Smckusick 	stat = arg[4];
1053278Smckusic 	if (lhs == NIL) {
1063278Smckusic nogood:
1073584Speter 	    if (forvar != NIL) {
1083584Speter 		forvar->value[ NL_FORV ] = FORVAR;
1093584Speter 	    }
1102187Smckusick 	    rvalue( init , NIL , RREQ );
1112187Smckusick 	    rvalue( term , NIL , RREQ );
1122187Smckusick 	    statement( stat );
1132187Smckusick 	    goto byebye;
1142187Smckusick 	}
1152187Smckusick 	    /*
1162187Smckusick 	     * and this marks the variable as used!!!
1172187Smckusick 	     */
1182187Smckusick 	forvar = lookup( lhs[2] );
1192187Smckusick 	if ( forvar == NIL ) {
1203278Smckusic 	    goto nogood;
1212187Smckusick 	}
12210798Speter 	saved_nl = *forvar;
1233278Smckusic 	if ( lhs[3] != NIL ) {
1243278Smckusic 	    error("For variable %s must be unqualified", forvar->symbol);
1253278Smckusic 	    goto nogood;
1263278Smckusic 	}
1273278Smckusic 	if (forvar->class == WITHPTR) {
1283278Smckusic 	    error("For variable %s cannot be an element of a record", lhs[2]);
1293278Smckusic 	    goto nogood;
1303278Smckusic 	}
1313836Speter 	if ( opt('s') &&
1323836Speter 	    ( ( bn != cbn ) ||
1333836Speter #ifdef OBJ
13410798Speter 		(whereis(bn, forvar->value[NL_OFFS], 0) == PARAMVAR)
1353836Speter #endif OBJ
1363836Speter #ifdef PC
13710798Speter 		(whereis(bn, forvar->value[NL_OFFS], forvar->extra_flags)
1383836Speter 		    == PARAMVAR )
1393836Speter #endif PC
1403836Speter 	    ) ) {
1413278Smckusic 	    standard();
1423278Smckusic 	    error("For variable %s must be declared in the block in which it is used", forvar->symbol);
1433278Smckusic 	}
1442187Smckusick 	    /*
1452187Smckusick 	     * find out the type of the loop variable
1462187Smckusick 	     */
1472187Smckusick 	codeoff();
1482187Smckusick 	fortype = lvalue( lhs , MOD , RREQ );
1492187Smckusick 	codeon();
1502187Smckusick 	if ( fortype == NIL ) {
1513278Smckusic 	    goto nogood;
1522187Smckusick 	}
1532187Smckusick 	if ( isnta( fortype , "bcis" ) ) {
1543278Smckusic 	    error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) );
1553278Smckusic 	    goto nogood;
1562187Smckusick 	}
1573584Speter 	if ( forvar->value[ NL_FORV ] & FORVAR ) {
1583584Speter 	    error("Can't modify the for variable %s in the range of the loop", forvar->symbol);
1593584Speter 	    forvar = NIL;
1603584Speter 	    goto nogood;
1613584Speter 	}
16210798Speter 	forwidth = lwidth(fortype);
16310798Speter #	ifdef PC
16410798Speter 	    forp2type = p2type(fortype);
16510798Speter #	endif PC
1662187Smckusick 	    /*
16710798Speter 	     *	allocate temporaries for the initial and final expressions
16810798Speter 	     *	and maybe a register to shadow the for variable.
1692187Smckusick 	     */
17010798Speter 	initnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG);
17110798Speter 	termnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG);
17210798Speter 	shadownlp = tmpalloc(forwidth, fortype, REGOK);
1732187Smckusick #	ifdef PC
1742187Smckusick 		/*
1752187Smckusick 		 * compute and save the initial expression
1762187Smckusick 		 */
1773836Speter 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
17810798Speter 		    initnlp -> extra_flags , P2INT );
1792187Smckusick #	endif PC
1802187Smckusick #	ifdef OBJ
1813836Speter 	    put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
1822187Smckusick #	endif OBJ
1832187Smckusick 	inittype = rvalue( init , fortype , RREQ );
1842187Smckusick 	if ( incompat( inittype , fortype , init ) ) {
1852187Smckusick 	    cerror("Type of initial expression clashed with index type in 'for' statement");
1863584Speter 	    if (forvar != NIL) {
1873584Speter 		forvar->value[ NL_FORV ] = FORVAR;
1883584Speter 	    }
1892187Smckusick 	    rvalue( term , NIL , RREQ );
1902187Smckusick 	    statement( stat );
1912187Smckusick 	    goto byebye;
1922187Smckusick 	}
1932187Smckusick #	ifdef PC
19410798Speter 	    sconv(p2type(inittype), P2INT);
19510798Speter 	    putop( P2ASSIGN , P2INT );
1962187Smckusick 	    putdot( filename , line );
1972187Smckusick 		/*
1982187Smckusick 		 * compute and save the termination expression
1992187Smckusick 		 */
2003836Speter 	    putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
20110798Speter 		    termnlp -> extra_flags , P2INT );
2022187Smckusick #	endif PC
2032187Smckusick #	ifdef OBJ
20410798Speter 	    gen(O_AS2, O_AS2, sizeof(long), width(inittype));
2052187Smckusick 		/*
2062187Smckusick 		 * compute and save the termination expression
2072187Smckusick 		 */
2083836Speter 	    put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
2092187Smckusick #	endif OBJ
2102187Smckusick 	termtype = rvalue( term , fortype , RREQ );
2112187Smckusick 	if ( incompat( termtype , fortype , term ) ) {
2122187Smckusick 	    cerror("Type of limit expression clashed with index type in 'for' statement");
2133584Speter 	    if (forvar != NIL) {
2143584Speter 		forvar->value[ NL_FORV ] = FORVAR;
2153584Speter 	    }
2162187Smckusick 	    statement( stat );
2172187Smckusick 	    goto byebye;
2182187Smckusick 	}
2192187Smckusick #	ifdef PC
22010798Speter 	    sconv(p2type(termtype), P2INT);
22110798Speter 	    putop( P2ASSIGN , P2INT );
2222187Smckusick 	    putdot( filename , line );
2232187Smckusick 		/*
2242187Smckusick 		 * we can skip the loop altogether if !( init <= term )
2252187Smckusick 		 */
2262187Smckusick 	    after = getlab();
2273836Speter 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
22810798Speter 		    initnlp -> extra_flags , P2INT );
2293836Speter 	    putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
23010798Speter 		    termnlp -> extra_flags , P2INT );
23110798Speter 	    putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , P2INT );
2322187Smckusick 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
2332187Smckusick 	    putop( P2CBRANCH , P2INT );
2342187Smckusick 	    putdot( filename , line );
2352187Smckusick 		/*
23610798Speter 		 * okay, so we have to execute the loop body,
23710798Speter 		 * but first, if checking is on,
23810798Speter 		 * check that the termination expression
23910798Speter 		 * is assignment compatible with the control-variable.
24010798Speter 		 */
24110798Speter 	    if (opt('t')) {
24210798Speter 		precheck(fortype, "_RANG4", "_RSNG4");
24310798Speter 		putRV(0, cbn, termnlp -> value[NL_OFFS],
24410798Speter 		    termnlp -> extra_flags, P2INT);
24510798Speter 		postcheck(fortype, nl+T4INT);
24610798Speter 		putdot(filename, line);
24710798Speter 	    }
24810798Speter 		/*
24910798Speter 		 * assign the initial expression to the shadow
25010798Speter 		 * checking the assignment if necessary.
25110798Speter 		 */
25210798Speter 	    putRV(0, cbn, shadownlp -> value[NL_OFFS],
25310798Speter 		shadownlp -> extra_flags, forp2type);
25410798Speter 	    if (opt('t')) {
25510798Speter 		precheck(fortype, "_RANG4", "_RSNG4");
25610798Speter 		putRV(0, cbn, initnlp -> value[NL_OFFS],
25710798Speter 		    initnlp -> extra_flags, P2INT);
25810798Speter 		postcheck(fortype, nl+T4INT);
25910798Speter 	    } else {
26010798Speter 		putRV(0, cbn, initnlp -> value[NL_OFFS],
26110798Speter 		    initnlp -> extra_flags, P2INT);
26210798Speter 	    }
26310798Speter 	    sconv(P2INT, forp2type);
26410798Speter 	    putop(P2ASSIGN, forp2type);
26510798Speter 	    putdot(filename, line);
26610798Speter 		/*
2673278Smckusic 		 * put down the label at the top of the loop
2683278Smckusic 		 */
2693278Smckusic 	    again = getlab();
2703278Smckusic 	    putlab( again );
2713278Smckusic 		/*
27210798Speter 		 * each time through the loop
27310798Speter 		 * assign the shadow to the for variable.
2742187Smckusick 		 */
27510798Speter 	    lvalue(lhs, NOUSE, RREQ);
27610798Speter 	    putRV(0, cbn, shadownlp -> value[NL_OFFS],
27710798Speter 		    shadownlp -> extra_flags, forp2type);
27810798Speter 	    putop(P2ASSIGN, forp2type);
27910798Speter 	    putdot(filename, line);
2802187Smckusick #	endif PC
2812187Smckusick #	ifdef OBJ
28210798Speter 	    gen(O_AS2, O_AS2, sizeof(long), width(termtype));
2832187Smckusick 		/*
2842187Smckusick 		 * we can skip the loop altogether if !( init <= term )
2852187Smckusick 		 */
28610798Speter 	    put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
28710798Speter 	    put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
28810798Speter 	    gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long),
28910798Speter 			sizeof(long));
2902187Smckusick 	    after = getlab();
2912187Smckusick 	    put(2, O_IF, after);
2922187Smckusick 		/*
29310798Speter 		 * okay, so we have to execute the loop body,
29410798Speter 		 * but first, if checking is on,
29510798Speter 		 * check that the termination expression
29610798Speter 		 * is assignment compatible with the control-variable.
29710798Speter 		 */
29810798Speter 	    if (opt('t')) {
29910798Speter 		put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] );
30010798Speter 		put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
30110798Speter 		rangechk(fortype, nl+T4INT);
30210798Speter 		gen(O_AS2, O_AS2, forwidth, sizeof(long));
30310798Speter 	    }
30410798Speter 		/*
30510798Speter 		 * assign the initial expression to the shadow
30610798Speter 		 * checking the assignment if necessary.
30710798Speter 		 */
30810798Speter 	    put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] );
30910798Speter 	    put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
31010798Speter 	    rangechk(fortype, nl+T4INT);
31110798Speter 	    gen(O_AS2, O_AS2, forwidth, sizeof(long));
31210798Speter 		/*
3133278Smckusic 		 * put down the label at the top of the loop
3143278Smckusic 		 */
3153278Smckusic 	    again = getlab();
3163278Smckusic 	    putlab( again );
3173278Smckusic 		/*
31810798Speter 		 * each time through the loop
31910798Speter 		 * assign the shadow to the for variable.
3202187Smckusick 		 */
32110798Speter 	    lvalue(lhs, NOUSE, RREQ);
32210798Speter 	    stackRV(shadownlp);
32310798Speter 	    gen(O_AS2, O_AS2, forwidth, sizeof(long));
3242187Smckusick #	endif OBJ
3252187Smckusick 	    /*
3263584Speter 	     *	shadowing the real for variable
32710798Speter 	     *	with the shadow temporary:
32810798Speter 	     *	save the real for variable flags (including nl_block).
32910798Speter 	     *	replace them with the shadow's offset,
33010798Speter 	     *	and mark the for variable as being a for variable.
3313584Speter 	     */
33210842Smckusick 	shadownlp -> nl_flags |= NLFLAGS(forvar -> nl_flags);
33310798Speter 	*forvar = *shadownlp;
33410798Speter 	forvar -> symbol = saved_nl.symbol;
33510798Speter 	forvar -> nl_next = saved_nl.nl_next;
33610798Speter 	forvar -> type = saved_nl.type;
3373584Speter 	forvar -> value[ NL_FORV ] = FORVAR;
3383584Speter 	    /*
3392187Smckusick 	     * and don't forget ...
3402187Smckusick 	     */
3413278Smckusic 	putcnt();
3423278Smckusic 	statement( stat );
3432187Smckusick 	    /*
3442187Smckusick 	     * wasn't that fun?  do we get to do it again?
3452187Smckusick 	     *	we don't do it again if ( !( forvar < limit ) )
3462187Smckusick 	     *	pretend we were doing this at the top of the loop
3472187Smckusick 	     */
3482187Smckusick 	line = arg[ 1 ];
3492187Smckusick #	ifdef PC
3502187Smckusick 	    if ( opt( 'p' ) ) {
3512187Smckusick 		if ( opt('t') ) {
3522187Smckusick 		    putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
3532187Smckusick 			    , "_LINO" );
3542187Smckusick 		    putop( P2UNARY P2CALL , P2INT );
3552187Smckusick 		    putdot( filename , line );
3562187Smckusick 		} else {
3573836Speter 		    putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT );
3582187Smckusick 		    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
3592187Smckusick 		    putop( P2ASG P2PLUS , P2INT );
3602187Smckusick 		    putdot( filename , line );
3612187Smckusick 		}
3622187Smckusick 	    }
3633836Speter 	    /*rvalue( lhs , NIL , RREQ );*/
36410798Speter 	    putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] ,
36510798Speter 		    shadownlp -> extra_flags , forp2type );
36610798Speter 	    sconv(forp2type, P2INT);
3673836Speter 	    putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
36810798Speter 		    termnlp -> extra_flags , P2INT );
3693836Speter 	    putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT );
3702187Smckusick 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
3712187Smckusick 	    putop( P2CBRANCH , P2INT );
3722187Smckusick 	    putdot( filename , line );
3732187Smckusick 		/*
3742187Smckusick 		 * okay, so we have to do it again,
3752187Smckusick 		 * but first, increment the for variable.
37610798Speter 		 * no need to rangecheck it, since we checked the
37710798Speter 		 * termination value before we started.
3782187Smckusick 		 */
3793836Speter 	    /*lvalue( lhs , MOD , RREQ );*/
38010798Speter 	    putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] ,
38110798Speter 		    shadownlp -> extra_flags , forp2type );
3823836Speter 	    /*rvalue( lhs , NIL , RREQ );*/
38310798Speter 	    putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] ,
38410798Speter 		    shadownlp -> extra_flags , forp2type );
38510798Speter 	    sconv(forp2type, P2INT);
3863633Smckusic 	    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
3873633Smckusic 	    putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT );
38810798Speter 	    sconv(P2INT, forp2type);
38910798Speter 	    putop( P2ASSIGN , forp2type );
3902187Smckusick 	    putdot( filename , line );
3912187Smckusick 		/*
3922187Smckusick 		 * and do it all again
3932187Smckusick 		 */
3942187Smckusick 	    putjbr( again );
3952187Smckusick 		/*
3962187Smckusick 		 * and here we are
3972187Smckusick 		 */
3982187Smckusick 	    putlab( after );
3992187Smckusick #	endif PC
4002187Smckusick #	ifdef OBJ
4012187Smckusick 		/*
4022187Smckusick 		 * okay, so we have to do it again.
4032187Smckusick 		 * Luckily we have a magic opcode which increments the
4042187Smckusick 		 * index variable, checks the limit falling through if
40510798Speter 		 * it has been reached, else updating the index variable,
40610798Speter 		 * and returning to the top of the loop.
4072187Smckusick 		 */
4082649Speter 	    putline();
40910798Speter 	    put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
41010798Speter 	    put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] );
41110798Speter 	    put(2, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + (forwidth >> 1),
41210798Speter 		    again);
4132187Smckusick 		/*
4142187Smckusick 		 * and here we are
4152187Smckusick 		 */
4162187Smckusick 	    patch( after );
4172187Smckusick #	endif OBJ
4182187Smckusick byebye:
4192187Smckusick 	noreach = 0;
4203584Speter 	if (forvar != NIL) {
42110842Smckusick 	    saved_nl.nl_flags |= NLFLAGS(forvar -> nl_flags) & (NUSED|NMOD);
42210798Speter 	    *forvar = saved_nl;
4232187Smckusick 	}
4242187Smckusick 	if ( goc != gocnt ) {
4252187Smckusick 	    putcnt();
4262187Smckusick 	}
4272187Smckusick     }
428