xref: /csrg-svn/usr.bin/pascal/src/forop.c (revision 10798)
12187Smckusick /* Copyright (c) 1979 Regents of the University of California */
22187Smckusick 
3*10798Speter static char sccsid[] = "@(#)forop.c 1.14 02/09/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
143371Speter 
152187Smckusick     /*
16*10798Speter      *	for-statements.
17*10798Speter      *
18*10798Speter      *	the relevant quote from the standard:  6.8.3.9:
19*10798Speter      *	``The control-variable shall be an entire-variable whose identifier
20*10798Speter      *	is declared in the variable-declaration-part of the block closest-
21*10798Speter      *	containing the for-statement.  The control-variable shall possess
22*10798Speter      *	an ordinal-type, and the initial-value and the final-value shall be
23*10798Speter      *	of a type compatible with this type.  The statement of a for-statement
24*10798Speter      *	shall not contain an assigning-reference to the control-variable
25*10798Speter      *	of the for-statement.  The value of the final-value shall be
26*10798Speter      *	assignment-compatible with the control-variable when the initial-value
27*10798Speter      *	is assigned to the control-variable.  After a for-statement is
28*10798Speter      *	executed (other than being left by a goto-statement leading out of it)
29*10798Speter      *	the control-variable shall be undefined.  Apart from the restrictions
30*10798Speter      *	imposed by these requirements, the for-statement
31*10798Speter      *		for v := e1 to e2 do body
32*10798Speter      *	shall be equivalent to
33*10798Speter      *		begin
34*10798Speter      *		    temp1 := e1;
35*10798Speter      *		    temp2 := e2;
36*10798Speter      *		    if temp1 <= temp2 then begin
37*10798Speter      *			v := temp1;
38*10798Speter      *			body;
39*10798Speter      *			while v <> temp2 do begin
40*10798Speter      *			    v := succ(v);
41*10798Speter      *			    body;
42*10798Speter      *			end
43*10798Speter      *		    end
44*10798Speter      *		end
45*10798Speter      *	where temp1 and temp2 denote auxiliary variables that the program
46*10798Speter      *	does not otherwise contain, and that possess the type possessed by
47*10798Speter      *	the variable v if that type is not a subrange-type;  otherwise the
48*10798Speter      *	host type possessed by the variable v.''
49*10798Speter      *
50*10798Speter      *	The Berkeley Pascal systems try to do all that without duplicating
51*10798Speter      *	the body, and shadowing the control-variable in (possibly) a
52*10798Speter      *	register variable.
53*10798Speter      *
542187Smckusick      *	arg here looks like:
552187Smckusick      *	arg[0]	T_FORU or T_FORD
562187Smckusick      *	   [1]	lineof "for"
572187Smckusick      *	   [2]	[0]	T_ASGN
582187Smckusick      *		[1]	lineof ":="
592187Smckusick      *		[2]	[0]	T_VAR
602187Smckusick      *			[1]	lineof id
612187Smckusick      *			[2]	char * to id
622187Smckusick      *			[3]	qualifications
632187Smckusick      *		[3]	initial expression
642187Smckusick      *	  [3]	termination expression
652187Smckusick      *	  [4]	statement
662187Smckusick      */
672187Smckusick forop( arg )
682187Smckusick     int	*arg;
692187Smckusick     {
702187Smckusick 	int		*lhs;
712187Smckusick 	struct nl	*forvar;
722187Smckusick 	struct nl	*fortype;
7310666Speter #ifdef PC
74*10798Speter 	int		forp2type;
7510666Speter #endif PC
7610666Speter 	int		forwidth;
772187Smckusick 	int		*init;
782187Smckusick 	struct nl	*inittype;
793836Speter 	struct nl	*initnlp;	/* initial value namelist entry */
802187Smckusick 	int		*term;
812187Smckusick 	struct nl	*termtype;
823836Speter 	struct nl	*termnlp;	/* termination value namelist entry */
83*10798Speter 	struct nl	*shadownlp;	/* namelist entry for the shadow */
842187Smckusick 	int		*stat;
852187Smckusick 	int		goc;		/* saved gocnt */
862187Smckusick 	int		again;		/* label at the top of the loop */
872187Smckusick 	int		after;		/* label after the end of the loop */
88*10798Speter 	struct nl	saved_nl;	/* saved namelist entry for loop var */
892187Smckusick 
902187Smckusick 	goc = gocnt;
912187Smckusick 	forvar = NIL;
922187Smckusick 	if ( arg == NIL ) {
932187Smckusick 	    goto byebye;
942187Smckusick 	}
952187Smckusick 	if ( arg[2] == NIL ) {
962187Smckusick 	    goto byebye;
972187Smckusick 	}
982187Smckusick 	line = arg[1];
992187Smckusick 	putline();
1002187Smckusick 	lhs = ( (int *) arg[2] )[2];
1012187Smckusick 	init = ( (int *) arg[2] )[3];
1022187Smckusick 	term = arg[3];
1032187Smckusick 	stat = arg[4];
1043278Smckusic 	if (lhs == NIL) {
1053278Smckusic nogood:
1063584Speter 	    if (forvar != NIL) {
1073584Speter 		forvar->value[ NL_FORV ] = FORVAR;
1083584Speter 	    }
1092187Smckusick 	    rvalue( init , NIL , RREQ );
1102187Smckusick 	    rvalue( term , NIL , RREQ );
1112187Smckusick 	    statement( stat );
1122187Smckusick 	    goto byebye;
1132187Smckusick 	}
1142187Smckusick 	    /*
1152187Smckusick 	     * and this marks the variable as used!!!
1162187Smckusick 	     */
1172187Smckusick 	forvar = lookup( lhs[2] );
1182187Smckusick 	if ( forvar == NIL ) {
1193278Smckusic 	    goto nogood;
1202187Smckusick 	}
121*10798Speter 	saved_nl = *forvar;
1223278Smckusic 	if ( lhs[3] != NIL ) {
1233278Smckusic 	    error("For variable %s must be unqualified", forvar->symbol);
1243278Smckusic 	    goto nogood;
1253278Smckusic 	}
1263278Smckusic 	if (forvar->class == WITHPTR) {
1273278Smckusic 	    error("For variable %s cannot be an element of a record", lhs[2]);
1283278Smckusic 	    goto nogood;
1293278Smckusic 	}
1303836Speter 	if ( opt('s') &&
1313836Speter 	    ( ( bn != cbn ) ||
1323836Speter #ifdef OBJ
133*10798Speter 		(whereis(bn, forvar->value[NL_OFFS], 0) == PARAMVAR)
1343836Speter #endif OBJ
1353836Speter #ifdef PC
136*10798Speter 		(whereis(bn, forvar->value[NL_OFFS], forvar->extra_flags)
1373836Speter 		    == PARAMVAR )
1383836Speter #endif PC
1393836Speter 	    ) ) {
1403278Smckusic 	    standard();
1413278Smckusic 	    error("For variable %s must be declared in the block in which it is used", forvar->symbol);
1423278Smckusic 	}
1432187Smckusick 	    /*
1442187Smckusick 	     * find out the type of the loop variable
1452187Smckusick 	     */
1462187Smckusick 	codeoff();
1472187Smckusick 	fortype = lvalue( lhs , MOD , RREQ );
1482187Smckusick 	codeon();
1492187Smckusick 	if ( fortype == NIL ) {
1503278Smckusic 	    goto nogood;
1512187Smckusick 	}
1522187Smckusick 	if ( isnta( fortype , "bcis" ) ) {
1533278Smckusic 	    error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) );
1543278Smckusic 	    goto nogood;
1552187Smckusick 	}
1563584Speter 	if ( forvar->value[ NL_FORV ] & FORVAR ) {
1573584Speter 	    error("Can't modify the for variable %s in the range of the loop", forvar->symbol);
1583584Speter 	    forvar = NIL;
1593584Speter 	    goto nogood;
1603584Speter 	}
161*10798Speter 	forwidth = lwidth(fortype);
162*10798Speter #	ifdef PC
163*10798Speter 	    forp2type = p2type(fortype);
164*10798Speter #	endif PC
1652187Smckusick 	    /*
166*10798Speter 	     *	allocate temporaries for the initial and final expressions
167*10798Speter 	     *	and maybe a register to shadow the for variable.
1682187Smckusick 	     */
169*10798Speter 	initnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG);
170*10798Speter 	termnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG);
171*10798Speter 	shadownlp = tmpalloc(forwidth, fortype, REGOK);
1722187Smckusick #	ifdef PC
1732187Smckusick 		/*
1742187Smckusick 		 * compute and save the initial expression
1752187Smckusick 		 */
1763836Speter 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
177*10798Speter 		    initnlp -> extra_flags , P2INT );
1782187Smckusick #	endif PC
1792187Smckusick #	ifdef OBJ
1803836Speter 	    put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
1812187Smckusick #	endif OBJ
1822187Smckusick 	inittype = rvalue( init , fortype , RREQ );
1832187Smckusick 	if ( incompat( inittype , fortype , init ) ) {
1842187Smckusick 	    cerror("Type of initial expression clashed with index type in 'for' statement");
1853584Speter 	    if (forvar != NIL) {
1863584Speter 		forvar->value[ NL_FORV ] = FORVAR;
1873584Speter 	    }
1882187Smckusick 	    rvalue( term , NIL , RREQ );
1892187Smckusick 	    statement( stat );
1902187Smckusick 	    goto byebye;
1912187Smckusick 	}
1922187Smckusick #	ifdef PC
193*10798Speter 	    sconv(p2type(inittype), P2INT);
194*10798Speter 	    putop( P2ASSIGN , P2INT );
1952187Smckusick 	    putdot( filename , line );
1962187Smckusick 		/*
1972187Smckusick 		 * compute and save the termination expression
1982187Smckusick 		 */
1993836Speter 	    putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
200*10798Speter 		    termnlp -> extra_flags , P2INT );
2012187Smckusick #	endif PC
2022187Smckusick #	ifdef OBJ
203*10798Speter 	    gen(O_AS2, O_AS2, sizeof(long), width(inittype));
2042187Smckusick 		/*
2052187Smckusick 		 * compute and save the termination expression
2062187Smckusick 		 */
2073836Speter 	    put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
2082187Smckusick #	endif OBJ
2092187Smckusick 	termtype = rvalue( term , fortype , RREQ );
2102187Smckusick 	if ( incompat( termtype , fortype , term ) ) {
2112187Smckusick 	    cerror("Type of limit expression clashed with index type in 'for' statement");
2123584Speter 	    if (forvar != NIL) {
2133584Speter 		forvar->value[ NL_FORV ] = FORVAR;
2143584Speter 	    }
2152187Smckusick 	    statement( stat );
2162187Smckusick 	    goto byebye;
2172187Smckusick 	}
2182187Smckusick #	ifdef PC
219*10798Speter 	    sconv(p2type(termtype), P2INT);
220*10798Speter 	    putop( P2ASSIGN , P2INT );
2212187Smckusick 	    putdot( filename , line );
2222187Smckusick 		/*
2232187Smckusick 		 * we can skip the loop altogether if !( init <= term )
2242187Smckusick 		 */
2252187Smckusick 	    after = getlab();
2263836Speter 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
227*10798Speter 		    initnlp -> extra_flags , P2INT );
2283836Speter 	    putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
229*10798Speter 		    termnlp -> extra_flags , P2INT );
230*10798Speter 	    putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , P2INT );
2312187Smckusick 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
2322187Smckusick 	    putop( P2CBRANCH , P2INT );
2332187Smckusick 	    putdot( filename , line );
2342187Smckusick 		/*
235*10798Speter 		 * okay, so we have to execute the loop body,
236*10798Speter 		 * but first, if checking is on,
237*10798Speter 		 * check that the termination expression
238*10798Speter 		 * is assignment compatible with the control-variable.
239*10798Speter 		 */
240*10798Speter 	    if (opt('t')) {
241*10798Speter 		precheck(fortype, "_RANG4", "_RSNG4");
242*10798Speter 		putRV(0, cbn, termnlp -> value[NL_OFFS],
243*10798Speter 		    termnlp -> extra_flags, P2INT);
244*10798Speter 		postcheck(fortype, nl+T4INT);
245*10798Speter 		putdot(filename, line);
246*10798Speter 	    }
247*10798Speter 		/*
248*10798Speter 		 * assign the initial expression to the shadow
249*10798Speter 		 * checking the assignment if necessary.
250*10798Speter 		 */
251*10798Speter 	    putRV(0, cbn, shadownlp -> value[NL_OFFS],
252*10798Speter 		shadownlp -> extra_flags, forp2type);
253*10798Speter 	    if (opt('t')) {
254*10798Speter 		precheck(fortype, "_RANG4", "_RSNG4");
255*10798Speter 		putRV(0, cbn, initnlp -> value[NL_OFFS],
256*10798Speter 		    initnlp -> extra_flags, P2INT);
257*10798Speter 		postcheck(fortype, nl+T4INT);
258*10798Speter 	    } else {
259*10798Speter 		putRV(0, cbn, initnlp -> value[NL_OFFS],
260*10798Speter 		    initnlp -> extra_flags, P2INT);
261*10798Speter 	    }
262*10798Speter 	    sconv(P2INT, forp2type);
263*10798Speter 	    putop(P2ASSIGN, forp2type);
264*10798Speter 	    putdot(filename, line);
265*10798Speter 		/*
2663278Smckusic 		 * put down the label at the top of the loop
2673278Smckusic 		 */
2683278Smckusic 	    again = getlab();
2693278Smckusic 	    putlab( again );
2703278Smckusic 		/*
271*10798Speter 		 * each time through the loop
272*10798Speter 		 * assign the shadow to the for variable.
2732187Smckusick 		 */
274*10798Speter 	    lvalue(lhs, NOUSE, RREQ);
275*10798Speter 	    putRV(0, cbn, shadownlp -> value[NL_OFFS],
276*10798Speter 		    shadownlp -> extra_flags, forp2type);
277*10798Speter 	    putop(P2ASSIGN, forp2type);
278*10798Speter 	    putdot(filename, line);
2792187Smckusick #	endif PC
2802187Smckusick #	ifdef OBJ
281*10798Speter 	    gen(O_AS2, O_AS2, sizeof(long), width(termtype));
2822187Smckusick 		/*
2832187Smckusick 		 * we can skip the loop altogether if !( init <= term )
2842187Smckusick 		 */
285*10798Speter 	    put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
286*10798Speter 	    put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
287*10798Speter 	    gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long),
288*10798Speter 			sizeof(long));
2892187Smckusick 	    after = getlab();
2902187Smckusick 	    put(2, O_IF, after);
2912187Smckusick 		/*
292*10798Speter 		 * okay, so we have to execute the loop body,
293*10798Speter 		 * but first, if checking is on,
294*10798Speter 		 * check that the termination expression
295*10798Speter 		 * is assignment compatible with the control-variable.
296*10798Speter 		 */
297*10798Speter 	    if (opt('t')) {
298*10798Speter 		put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] );
299*10798Speter 		put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
300*10798Speter 		rangechk(fortype, nl+T4INT);
301*10798Speter 		gen(O_AS2, O_AS2, forwidth, sizeof(long));
302*10798Speter 	    }
303*10798Speter 		/*
304*10798Speter 		 * assign the initial expression to the shadow
305*10798Speter 		 * checking the assignment if necessary.
306*10798Speter 		 */
307*10798Speter 	    put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] );
308*10798Speter 	    put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
309*10798Speter 	    rangechk(fortype, nl+T4INT);
310*10798Speter 	    gen(O_AS2, O_AS2, forwidth, sizeof(long));
311*10798Speter 		/*
3123278Smckusic 		 * put down the label at the top of the loop
3133278Smckusic 		 */
3143278Smckusic 	    again = getlab();
3153278Smckusic 	    putlab( again );
3163278Smckusic 		/*
317*10798Speter 		 * each time through the loop
318*10798Speter 		 * assign the shadow to the for variable.
3192187Smckusick 		 */
320*10798Speter 	    lvalue(lhs, NOUSE, RREQ);
321*10798Speter 	    stackRV(shadownlp);
322*10798Speter 	    gen(O_AS2, O_AS2, forwidth, sizeof(long));
3232187Smckusick #	endif OBJ
3242187Smckusick 	    /*
3253584Speter 	     *	shadowing the real for variable
326*10798Speter 	     *	with the shadow temporary:
327*10798Speter 	     *	save the real for variable flags (including nl_block).
328*10798Speter 	     *	replace them with the shadow's offset,
329*10798Speter 	     *	and mark the for variable as being a for variable.
3303584Speter 	     */
331*10798Speter 	shadownlp -> nl_flags = forvar -> nl_flags;
332*10798Speter 	*forvar = *shadownlp;
333*10798Speter 	forvar -> symbol = saved_nl.symbol;
334*10798Speter 	forvar -> nl_next = saved_nl.nl_next;
335*10798Speter 	forvar -> type = saved_nl.type;
3363584Speter 	forvar -> value[ NL_FORV ] = FORVAR;
3373584Speter 	    /*
3382187Smckusick 	     * and don't forget ...
3392187Smckusick 	     */
3403278Smckusic 	putcnt();
3413278Smckusic 	statement( stat );
3422187Smckusick 	    /*
3432187Smckusick 	     * wasn't that fun?  do we get to do it again?
3442187Smckusick 	     *	we don't do it again if ( !( forvar < limit ) )
3452187Smckusick 	     *	pretend we were doing this at the top of the loop
3462187Smckusick 	     */
3472187Smckusick 	line = arg[ 1 ];
3482187Smckusick #	ifdef PC
3492187Smckusick 	    if ( opt( 'p' ) ) {
3502187Smckusick 		if ( opt('t') ) {
3512187Smckusick 		    putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
3522187Smckusick 			    , "_LINO" );
3532187Smckusick 		    putop( P2UNARY P2CALL , P2INT );
3542187Smckusick 		    putdot( filename , line );
3552187Smckusick 		} else {
3563836Speter 		    putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT );
3572187Smckusick 		    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
3582187Smckusick 		    putop( P2ASG P2PLUS , P2INT );
3592187Smckusick 		    putdot( filename , line );
3602187Smckusick 		}
3612187Smckusick 	    }
3623836Speter 	    /*rvalue( lhs , NIL , RREQ );*/
363*10798Speter 	    putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] ,
364*10798Speter 		    shadownlp -> extra_flags , forp2type );
365*10798Speter 	    sconv(forp2type, P2INT);
3663836Speter 	    putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
367*10798Speter 		    termnlp -> extra_flags , P2INT );
3683836Speter 	    putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT );
3692187Smckusick 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
3702187Smckusick 	    putop( P2CBRANCH , P2INT );
3712187Smckusick 	    putdot( filename , line );
3722187Smckusick 		/*
3732187Smckusick 		 * okay, so we have to do it again,
3742187Smckusick 		 * but first, increment the for variable.
375*10798Speter 		 * no need to rangecheck it, since we checked the
376*10798Speter 		 * termination value before we started.
3772187Smckusick 		 */
3783836Speter 	    /*lvalue( lhs , MOD , RREQ );*/
379*10798Speter 	    putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] ,
380*10798Speter 		    shadownlp -> extra_flags , forp2type );
3813836Speter 	    /*rvalue( lhs , NIL , RREQ );*/
382*10798Speter 	    putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] ,
383*10798Speter 		    shadownlp -> extra_flags , forp2type );
384*10798Speter 	    sconv(forp2type, P2INT);
3853633Smckusic 	    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
3863633Smckusic 	    putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT );
387*10798Speter 	    sconv(P2INT, forp2type);
388*10798Speter 	    putop( P2ASSIGN , forp2type );
3892187Smckusick 	    putdot( filename , line );
3902187Smckusick 		/*
3912187Smckusick 		 * and do it all again
3922187Smckusick 		 */
3932187Smckusick 	    putjbr( again );
3942187Smckusick 		/*
3952187Smckusick 		 * and here we are
3962187Smckusick 		 */
3972187Smckusick 	    putlab( after );
3982187Smckusick #	endif PC
3992187Smckusick #	ifdef OBJ
4002187Smckusick 		/*
4012187Smckusick 		 * okay, so we have to do it again.
4022187Smckusick 		 * Luckily we have a magic opcode which increments the
4032187Smckusick 		 * index variable, checks the limit falling through if
404*10798Speter 		 * it has been reached, else updating the index variable,
405*10798Speter 		 * and returning to the top of the loop.
4062187Smckusick 		 */
4072649Speter 	    putline();
408*10798Speter 	    put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
409*10798Speter 	    put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] );
410*10798Speter 	    put(2, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + (forwidth >> 1),
411*10798Speter 		    again);
4122187Smckusick 		/*
4132187Smckusick 		 * and here we are
4142187Smckusick 		 */
4152187Smckusick 	    patch( after );
4162187Smckusick #	endif OBJ
4172187Smckusick byebye:
4182187Smckusick 	noreach = 0;
4193584Speter 	if (forvar != NIL) {
420*10798Speter 	    saved_nl.nl_flags |= forvar -> nl_flags & (NUSED|NMOD);
421*10798Speter 	    *forvar = saved_nl;
4222187Smckusick 	}
4232187Smckusick 	if ( goc != gocnt ) {
4242187Smckusick 	    putcnt();
4252187Smckusick 	}
4262187Smckusick     }
427