xref: /csrg-svn/usr.bin/pascal/src/forop.c (revision 10666)
12187Smckusick /* Copyright (c) 1979 Regents of the University of California */
22187Smckusick 
3*10666Speter static char sccsid[] = "@(#)forop.c 1.13 02/01/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     /*
162187Smckusick      *	forop for pc:
172187Smckusick      *	    this evaluates the initial and termination expressions,
182187Smckusick      *	    checks them to see if the loop executes at all, and then
192187Smckusick      *	    does the assignment and the loop.
202187Smckusick      *	arg here looks like:
212187Smckusick      *	arg[0]	T_FORU or T_FORD
222187Smckusick      *	   [1]	lineof "for"
232187Smckusick      *	   [2]	[0]	T_ASGN
242187Smckusick      *		[1]	lineof ":="
252187Smckusick      *		[2]	[0]	T_VAR
262187Smckusick      *			[1]	lineof id
272187Smckusick      *			[2]	char * to id
282187Smckusick      *			[3]	qualifications
292187Smckusick      *		[3]	initial expression
302187Smckusick      *	  [3]	termination expression
312187Smckusick      *	  [4]	statement
322187Smckusick      */
332187Smckusick forop( arg )
342187Smckusick     int	*arg;
352187Smckusick     {
362187Smckusick 	int		*lhs;
372187Smckusick 	struct nl	*forvar;
382187Smckusick 	struct nl	*fortype;
39*10666Speter #ifdef PC
40*10666Speter 	int		forctype;	/* p2type(fortype) */
41*10666Speter #endif PC
42*10666Speter 	int		forwidth;
432187Smckusick 	int		*init;
442187Smckusick 	struct nl	*inittype;
453836Speter 	struct nl	*initnlp;	/* initial value namelist entry */
463371Speter 	char		forflags;
472187Smckusick 	int		*term;
482187Smckusick 	struct nl	*termtype;
493836Speter 	struct nl	*termnlp;	/* termination value namelist entry */
502187Smckusick 	int		*stat;
512187Smckusick 	int		goc;		/* saved gocnt */
522187Smckusick 	int		again;		/* label at the top of the loop */
532187Smckusick 	int		after;		/* label after the end of the loop */
545775Smckusic 	struct nl	shadow_nl;	/* saved namelist entry for loop var */
552187Smckusick 
562187Smckusick 	goc = gocnt;
572187Smckusick 	forvar = NIL;
582187Smckusick 	if ( arg == NIL ) {
592187Smckusick 	    goto byebye;
602187Smckusick 	}
612187Smckusick 	if ( arg[2] == NIL ) {
622187Smckusick 	    goto byebye;
632187Smckusick 	}
642187Smckusick 	line = arg[1];
652187Smckusick 	putline();
662187Smckusick 	lhs = ( (int *) arg[2] )[2];
672187Smckusick 	init = ( (int *) arg[2] )[3];
682187Smckusick 	term = arg[3];
692187Smckusick 	stat = arg[4];
703278Smckusic 	if (lhs == NIL) {
713278Smckusic nogood:
723584Speter 	    if (forvar != NIL) {
733584Speter 		forvar->value[ NL_FORV ] = FORVAR;
743584Speter 	    }
752187Smckusick 	    rvalue( init , NIL , RREQ );
762187Smckusick 	    rvalue( term , NIL , RREQ );
772187Smckusick 	    statement( stat );
782187Smckusick 	    goto byebye;
792187Smckusick 	}
802187Smckusick 	    /*
812187Smckusick 	     * and this marks the variable as used!!!
822187Smckusick 	     */
832187Smckusick 	forvar = lookup( lhs[2] );
842187Smckusick 	if ( forvar == NIL ) {
853278Smckusic 	    goto nogood;
862187Smckusick 	}
875775Smckusic 	shadow_nl = *forvar;
883278Smckusic 	if ( lhs[3] != NIL ) {
893278Smckusic 	    error("For variable %s must be unqualified", forvar->symbol);
903278Smckusic 	    goto nogood;
913278Smckusic 	}
923278Smckusic 	if (forvar->class == WITHPTR) {
933278Smckusic 	    error("For variable %s cannot be an element of a record", lhs[2]);
943278Smckusic 	    goto nogood;
953278Smckusic 	}
963836Speter 	if ( opt('s') &&
973836Speter 	    ( ( bn != cbn ) ||
983836Speter #ifdef OBJ
993836Speter 		( whereis( bn , forvar->value[NL_OFFS] , 0 ) == PARAMVAR )
1003836Speter #endif OBJ
1013836Speter #ifdef PC
1023836Speter 		( whereis( bn , forvar->value[NL_OFFS] , forvar -> extra_flags )
1033836Speter 		    == PARAMVAR )
1043836Speter #endif PC
1053836Speter 	    ) ) {
1063278Smckusic 	    standard();
1073278Smckusic 	    error("For variable %s must be declared in the block in which it is used", forvar->symbol);
1083278Smckusic 	}
1092187Smckusick 	    /*
1102187Smckusick 	     * find out the type of the loop variable
1112187Smckusick 	     */
1122187Smckusick 	codeoff();
1132187Smckusick 	fortype = lvalue( lhs , MOD , RREQ );
1142187Smckusick 	codeon();
1152187Smckusick 	if ( fortype == NIL ) {
1163278Smckusic 	    goto nogood;
1172187Smckusick 	}
1182187Smckusick 	if ( isnta( fortype , "bcis" ) ) {
1193278Smckusic 	    error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) );
1203278Smckusic 	    goto nogood;
1212187Smckusick 	}
1223584Speter 	if ( forvar->value[ NL_FORV ] & FORVAR ) {
1233584Speter 	    error("Can't modify the for variable %s in the range of the loop", forvar->symbol);
1243584Speter 	    forvar = NIL;
1253584Speter 	    goto nogood;
1263584Speter 	}
1272187Smckusick 	    /*
1282187Smckusick 	     * allocate space for the initial and termination expressions
1293584Speter 	     * the initial is tentatively placed in a register as it will
1303584Speter 	     * shadow the for loop variable in the body of the loop.
1312187Smckusick 	     */
132*10666Speter 	forwidth = lwidth(fortype);
133*10666Speter 	initnlp = tmpalloc(forwidth, fortype, REGOK);
134*10666Speter 	termnlp = tmpalloc(forwidth, fortype, NOREG);
1352187Smckusick #	ifdef PC
136*10666Speter 	    forctype = p2type(fortype);
1372187Smckusick 		/*
1382187Smckusick 		 * compute and save the initial expression
1392187Smckusick 		 */
1403836Speter 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
141*10666Speter 		    initnlp -> extra_flags , forctype );
142*10666Speter 	    if ( opt( 't' ) ) {
143*10666Speter 		precheck( fortype , "_RANG4" , "_RSNG4" );
144*10666Speter 	    }
1452187Smckusick #	endif PC
1462187Smckusick #	ifdef OBJ
1473836Speter 	    put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
1482187Smckusick #	endif OBJ
1492187Smckusick 	inittype = rvalue( init , fortype , RREQ );
1502187Smckusick 	if ( incompat( inittype , fortype , init ) ) {
1512187Smckusick 	    cerror("Type of initial expression clashed with index type in 'for' statement");
1523584Speter 	    if (forvar != NIL) {
1533584Speter 		forvar->value[ NL_FORV ] = FORVAR;
1543584Speter 	    }
1552187Smckusick 	    rvalue( term , NIL , RREQ );
1562187Smckusick 	    statement( stat );
1572187Smckusick 	    goto byebye;
1582187Smckusick 	}
1592187Smckusick #	ifdef PC
160*10666Speter 	    if ( opt( 't' ) ) {
161*10666Speter 		postcheck(fortype, inittype);
162*10666Speter 	    }
163*10666Speter 	    sconv(p2type(inittype), forctype);
164*10666Speter 	    putop( P2ASSIGN , forctype );
1652187Smckusick 	    putdot( filename , line );
1662187Smckusick 		/*
1672187Smckusick 		 * compute and save the termination expression
1682187Smckusick 		 */
1693836Speter 	    putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
170*10666Speter 		    termnlp -> extra_flags , forctype );
171*10666Speter 	    if ( opt( 't' ) ) {
172*10666Speter 		precheck( fortype , "_RANG4" , "_RSNG4" );
173*10666Speter 	    }
1742187Smckusick #	endif PC
1752187Smckusick #	ifdef OBJ
176*10666Speter 	    rangechk(fortype, inittype);
177*10666Speter 	    gen(O_AS2, O_AS2, forwidth, lwidth(inittype));
1782187Smckusick 		/*
1792187Smckusick 		 * compute and save the termination expression
1802187Smckusick 		 */
1813836Speter 	    put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
1822187Smckusick #	endif OBJ
1832187Smckusick 	termtype = rvalue( term , fortype , RREQ );
1842187Smckusick 	if ( incompat( termtype , fortype , term ) ) {
1852187Smckusick 	    cerror("Type of limit expression clashed with index type in 'for' statement");
1863584Speter 	    if (forvar != NIL) {
1873584Speter 		forvar->value[ NL_FORV ] = FORVAR;
1883584Speter 	    }
1892187Smckusick 	    statement( stat );
1902187Smckusick 	    goto byebye;
1912187Smckusick 	}
1922187Smckusick #	ifdef PC
193*10666Speter 	    if ( opt( 't' ) ) {
194*10666Speter 		postcheck(fortype, termtype);
195*10666Speter 	    }
196*10666Speter 	    sconv(p2type(termtype), forctype);
197*10666Speter 	    putop( P2ASSIGN , forctype );
1982187Smckusick 	    putdot( filename , line );
1992187Smckusick 		/*
2002187Smckusick 		 * we can skip the loop altogether if !( init <= term )
2012187Smckusick 		 */
2022187Smckusick 	    after = getlab();
2033836Speter 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
204*10666Speter 		    initnlp -> extra_flags , forctype );
2053836Speter 	    putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
206*10666Speter 		    termnlp -> extra_flags , forctype );
207*10666Speter 	    putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , forctype );
2082187Smckusick 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
2092187Smckusick 	    putop( P2CBRANCH , P2INT );
2102187Smckusick 	    putdot( filename , line );
2112187Smckusick 		/*
2123278Smckusic 		 * put down the label at the top of the loop
2133278Smckusic 		 */
2143278Smckusic 	    again = getlab();
2153278Smckusic 	    putlab( again );
2163278Smckusic 		/*
2172187Smckusick 		 * okay, then we have to execute the body, but first,
2182187Smckusick 		 * assign the initial expression to the for variable.
2192187Smckusick 		 * see the note in asgnop1 about why this is an rvalue.
2202187Smckusick 		 */
2213371Speter 	    lvalue( lhs , NOUSE , RREQ );
2223836Speter 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
223*10666Speter 		    initnlp -> extra_flags , forctype );
2243836Speter 	    putop( P2ASSIGN , p2type( fortype ) );
2252187Smckusick 	    putdot( filename , line );
2262187Smckusick #	endif PC
2272187Smckusick #	ifdef OBJ
228*10666Speter 	    rangechk(fortype, termtype);
229*10666Speter 	    gen(O_AS2, O_AS2, forwidth, lwidth(termtype));
2302187Smckusick 		/*
2312187Smckusick 		 * we can skip the loop altogether if !( init <= term )
2322187Smckusick 		 */
233*10666Speter 	    stackRV(initnlp);
234*10666Speter 	    stackRV(termnlp);
235*10666Speter 	    gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, lwidth(nl+T4INT),
236*10666Speter 			lwidth(nl+T4INT));
2372187Smckusick 	    after = getlab();
2382187Smckusick 	    put(2, O_IF, after);
2392187Smckusick 		/*
2403278Smckusic 		 * put down the label at the top of the loop
2413278Smckusic 		 */
2423278Smckusic 	    again = getlab();
2433278Smckusic 	    putlab( again );
2443278Smckusic 		/*
2452187Smckusick 		 * okay, then we have to execute the body, but first,
2462187Smckusick 		 * assign the initial expression to the for variable.
2472187Smckusick 		 */
2482187Smckusick 	    lvalue( lhs , NOUSE , LREQ );
249*10666Speter 	    stackRV(initnlp);
250*10666Speter 	    gen(O_AS2, O_AS2, forwidth, lwidth(nl+T4INT));
2512187Smckusick #	endif OBJ
2522187Smckusick 	    /*
2533584Speter 	     *	shadowing the real for variable
2543584Speter 	     *	with the initail expression temporary:
2553584Speter 	     *	save the real for variable's offset, flags
2563584Speter 	     *	(including nl_block).
2573584Speter 	     *	replace them with the initial expression's offset,
2583584Speter 	     *	and mark it as being a for variable.
2593584Speter 	     */
2605871Smckusic 	shadow_nl.nl_flags = forvar -> nl_flags;
2615775Smckusic 	*forvar = *initnlp;
2625775Smckusic 	forvar -> symbol = shadow_nl.symbol;
2635775Smckusic 	forvar -> nl_next = shadow_nl.nl_next;
2643584Speter 	forvar -> value[ NL_FORV ] = FORVAR;
2653584Speter 	    /*
2662187Smckusick 	     * and don't forget ...
2672187Smckusick 	     */
2683278Smckusic 	putcnt();
2693278Smckusic 	statement( stat );
2702187Smckusick 	    /*
2712187Smckusick 	     * wasn't that fun?  do we get to do it again?
2722187Smckusick 	     *	we don't do it again if ( !( forvar < limit ) )
2732187Smckusick 	     *	pretend we were doing this at the top of the loop
2742187Smckusick 	     */
2752187Smckusick 	line = arg[ 1 ];
2762187Smckusick #	ifdef PC
2772187Smckusick 	    if ( opt( 'p' ) ) {
2782187Smckusick 		if ( opt('t') ) {
2792187Smckusick 		    putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
2802187Smckusick 			    , "_LINO" );
2812187Smckusick 		    putop( P2UNARY P2CALL , P2INT );
2822187Smckusick 		    putdot( filename , line );
2832187Smckusick 		} else {
2843836Speter 		    putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT );
2852187Smckusick 		    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
2862187Smckusick 		    putop( P2ASG P2PLUS , P2INT );
2872187Smckusick 		    putdot( filename , line );
2882187Smckusick 		}
2892187Smckusick 	    }
2903836Speter 	    /*rvalue( lhs , NIL , RREQ );*/
2913836Speter 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
292*10666Speter 		    initnlp -> extra_flags , forctype );
2933836Speter 	    putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
294*10666Speter 		    termnlp -> extra_flags , forctype );
2953836Speter 	    putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT );
2962187Smckusick 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
2972187Smckusick 	    putop( P2CBRANCH , P2INT );
2982187Smckusick 	    putdot( filename , line );
2992187Smckusick 		/*
3002187Smckusick 		 * okay, so we have to do it again,
3012187Smckusick 		 * but first, increment the for variable.
3022187Smckusick 		 * there it is again, an rvalue on the lhs of an assignment.
3032187Smckusick 		 */
3043836Speter 	    /*lvalue( lhs , MOD , RREQ );*/
3053836Speter 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
306*10666Speter 		    initnlp -> extra_flags , forctype );
3072187Smckusick 	    if ( opt( 't' ) ) {
3082187Smckusick 		precheck( fortype , "_RANG4" , "_RSNG4" );
3092187Smckusick 	    }
3103836Speter 	    /*rvalue( lhs , NIL , RREQ );*/
3113836Speter 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
312*10666Speter 		    initnlp -> extra_flags , forctype );
313*10666Speter 	    sconv(forctype, P2INT);
3143633Smckusic 	    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
3153633Smckusic 	    putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT );
3162187Smckusick 	    if ( opt( 't' ) ) {
31710363Smckusick 		postcheck(fortype, nl+T4INT);
3182187Smckusick 	    }
319*10666Speter 	    sconv(P2INT, forctype);
320*10666Speter 	    putop( P2ASSIGN , forctype );
3212187Smckusick 	    putdot( filename , line );
3222187Smckusick 		/*
3232187Smckusick 		 * and do it all again
3242187Smckusick 		 */
3252187Smckusick 	    putjbr( again );
3262187Smckusick 		/*
3272187Smckusick 		 * and here we are
3282187Smckusick 		 */
3292187Smckusick 	    putlab( after );
3302187Smckusick #	endif PC
3312187Smckusick #	ifdef OBJ
3322187Smckusick 		/*
3332187Smckusick 		 * okay, so we have to do it again.
3342187Smckusick 		 * Luckily we have a magic opcode which increments the
3352187Smckusick 		 * index variable, checks the limit falling through if
3362187Smckusick 		 * it has been reached, else range checking the result
3372187Smckusick 		 * updating the index variable, and returning to the top
3382187Smckusick 		 * of the loop.
3392187Smckusick 		 */
3402649Speter 	    putline();
341*10666Speter 	    stackRV(termnlp);
342*10666Speter 	    put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
343*10666Speter 	    if (forwidth <= 2)
344*10666Speter 		    put(4,
345*10666Speter 			(arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + (forwidth>>1),
346*10666Speter 			(int)fortype->range[0], (int)fortype->range[1], again);
3473083Smckusic 	    else
3483083Smckusic 		    put(4, (arg[0] == T_FORU ? O_FOR4U : O_FOR4D),
3493083Smckusic 			    fortype->range[0], fortype->range[1], again);
3502187Smckusick 		/*
3512187Smckusick 		 * and here we are
3522187Smckusick 		 */
3532187Smckusick 	    patch( after );
3542187Smckusick #	endif OBJ
355*10666Speter 	/* and fall through */
3562187Smckusick byebye:
3572187Smckusick 	noreach = 0;
3583584Speter 	if (forvar != NIL) {
3595871Smckusic 	    shadow_nl.nl_flags |= forvar -> nl_flags & (NUSED|NMOD);
3605775Smckusic 	    *forvar = shadow_nl;
3612187Smckusick 	}
3622187Smckusick 	if ( goc != gocnt ) {
3632187Smckusick 	    putcnt();
3642187Smckusick 	}
3652187Smckusick     }
366