xref: /csrg-svn/usr.bin/pascal/src/forop.c (revision 3584)
12187Smckusick /* Copyright (c) 1979 Regents of the University of California */
22187Smckusick 
3*3584Speter static char sccsid[] = "@(#)forop.c 1.7 04/21/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
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;
392187Smckusick 	int		forctype;
402187Smckusick 	int		*init;
412187Smckusick 	struct nl	*inittype;
422187Smckusick 	int		initoff;
433371Speter 	char		forflags;
442187Smckusick 	int		*term;
452187Smckusick 	struct nl	*termtype;
462187Smckusick 	int		termoff;
472187Smckusick 	int		*stat;
482187Smckusick 	int		goc;		/* saved gocnt */
492187Smckusick 	int		again;		/* label at the top of the loop */
502187Smckusick 	int		after;		/* label after the end of the loop */
51*3584Speter 	bool		shadowed;	/* shadowing for var in temporary? */
52*3584Speter 	long		s_offset;	/* saved offset of real for variable */
53*3584Speter 	long		s_flags;	/* saved flags of real for variable */
54*3584Speter 	long		s_forv;		/* saved NL_FORV of the for variable */
552187Smckusick 
562187Smckusick 	goc = gocnt;
572187Smckusick 	forvar = NIL;
58*3584Speter 	shadowed = FALSE;
592187Smckusick 	if ( arg == NIL ) {
602187Smckusick 	    goto byebye;
612187Smckusick 	}
622187Smckusick 	if ( arg[2] == NIL ) {
632187Smckusick 	    goto byebye;
642187Smckusick 	}
652187Smckusick 	line = arg[1];
662187Smckusick 	putline();
672187Smckusick 	lhs = ( (int *) arg[2] )[2];
682187Smckusick 	init = ( (int *) arg[2] )[3];
692187Smckusick 	term = arg[3];
702187Smckusick 	stat = arg[4];
713278Smckusic 	if (lhs == NIL) {
723278Smckusic nogood:
73*3584Speter 	    if (forvar != NIL) {
74*3584Speter 		forvar->value[ NL_FORV ] = FORVAR;
75*3584Speter 	    }
762187Smckusick 	    rvalue( init , NIL , RREQ );
772187Smckusick 	    rvalue( term , NIL , RREQ );
782187Smckusick 	    statement( stat );
792187Smckusick 	    goto byebye;
802187Smckusick 	}
812187Smckusick 	    /*
822187Smckusick 	     * and this marks the variable as used!!!
832187Smckusick 	     */
842187Smckusick 	forvar = lookup( lhs[2] );
852187Smckusick 	if ( forvar == NIL ) {
863278Smckusic 	    goto nogood;
872187Smckusick 	}
88*3584Speter 	s_forv = forvar -> value[ NL_FORV ];
893278Smckusic 	if ( lhs[3] != NIL ) {
903278Smckusic 	    error("For variable %s must be unqualified", forvar->symbol);
913278Smckusic 	    goto nogood;
923278Smckusic 	}
933278Smckusic 	if (forvar->class == WITHPTR) {
943278Smckusic 	    error("For variable %s cannot be an element of a record", lhs[2]);
953278Smckusic 	    goto nogood;
963278Smckusic 	}
973278Smckusic 	if (opt('s') &&
983278Smckusic 	    (bn != cbn || whereis(forvar->value[NL_OFFS]) == PARAMVAR)) {
993278Smckusic 	    standard();
1003278Smckusic 	    error("For variable %s must be declared in the block in which it is used", forvar->symbol);
1013278Smckusic 	}
1022187Smckusick 	    /*
1032187Smckusick 	     * find out the type of the loop variable
1042187Smckusick 	     */
1052187Smckusick 	codeoff();
1062187Smckusick 	fortype = lvalue( lhs , MOD , RREQ );
1072187Smckusick 	codeon();
1082187Smckusick 	if ( fortype == NIL ) {
1093278Smckusic 	    goto nogood;
1102187Smckusick 	}
1112187Smckusick 	if ( isnta( fortype , "bcis" ) ) {
1123278Smckusic 	    error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) );
1133278Smckusic 	    goto nogood;
1142187Smckusick 	}
115*3584Speter 	if ( forvar->value[ NL_FORV ] & FORVAR ) {
116*3584Speter 	    error("Can't modify the for variable %s in the range of the loop", forvar->symbol);
117*3584Speter 	    forvar = NIL;
118*3584Speter 	    goto nogood;
119*3584Speter 	}
1202187Smckusick 	    /*
1212187Smckusick 	     * allocate space for the initial and termination expressions
122*3584Speter 	     * the initial is tentatively placed in a register as it will
123*3584Speter 	     * shadow the for loop variable in the body of the loop.
1242187Smckusick 	     */
1253230Smckusic 	initoff = tmpalloc(sizeof(long), nl+T4INT, REGOK);
126*3584Speter 	termoff = tmpalloc(sizeof(long), nl+T4INT, NOREG);
1272187Smckusick #	ifdef PC
1282187Smckusick 		/*
1292187Smckusick 		 * compute and save the initial expression
1302187Smckusick 		 */
1312187Smckusick 	    forctype = p2type( fortype );
1322187Smckusick 	    putRV( 0 , cbn , initoff , forctype );
1332187Smckusick #	endif PC
1342187Smckusick #	ifdef OBJ
1352187Smckusick 	    put(2, O_LV | cbn<<8+INDX, initoff);
1362187Smckusick #	endif OBJ
1372187Smckusick 	inittype = rvalue( init , fortype , RREQ );
1382187Smckusick 	if ( incompat( inittype , fortype , init ) ) {
1392187Smckusick 	    cerror("Type of initial expression clashed with index type in 'for' statement");
140*3584Speter 	    if (forvar != NIL) {
141*3584Speter 		forvar->value[ NL_FORV ] = FORVAR;
142*3584Speter 	    }
1432187Smckusick 	    rvalue( term , NIL , RREQ );
1442187Smckusick 	    statement( stat );
1452187Smckusick 	    goto byebye;
1462187Smckusick 	}
1472187Smckusick #	ifdef PC
1482187Smckusick 	    putop( P2ASSIGN , forctype );
1492187Smckusick 	    putdot( filename , line );
1502187Smckusick 		/*
1512187Smckusick 		 * compute and save the termination expression
1522187Smckusick 		 */
1532187Smckusick 	    putRV( 0 , cbn , termoff , forctype );
1542187Smckusick #	endif PC
1552187Smckusick #	ifdef OBJ
1563083Smckusic 	    gen(O_AS2, O_AS2, sizeof(long), width(inittype));
1572187Smckusick 		/*
1582187Smckusick 		 * compute and save the termination expression
1592187Smckusick 		 */
1602187Smckusick 	    put(2, O_LV | cbn<<8+INDX, termoff);
1612187Smckusick #	endif OBJ
1622187Smckusick 	termtype = rvalue( term , fortype , RREQ );
1632187Smckusick 	if ( incompat( termtype , fortype , term ) ) {
1642187Smckusick 	    cerror("Type of limit expression clashed with index type in 'for' statement");
165*3584Speter 	    if (forvar != NIL) {
166*3584Speter 		forvar->value[ NL_FORV ] = FORVAR;
167*3584Speter 	    }
1682187Smckusick 	    statement( stat );
1692187Smckusick 	    goto byebye;
1702187Smckusick 	}
1712187Smckusick #	ifdef PC
1722187Smckusick 	    putop( P2ASSIGN , forctype );
1732187Smckusick 	    putdot( filename , line );
1742187Smckusick 		/*
1752187Smckusick 		 * we can skip the loop altogether if !( init <= term )
1762187Smckusick 		 */
1772187Smckusick 	    after = getlab();
1782187Smckusick 	    putRV( 0 , cbn , initoff , forctype );
1792187Smckusick 	    putRV( 0 , cbn , termoff , forctype );
1802187Smckusick 	    putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , forctype );
1812187Smckusick 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
1822187Smckusick 	    putop( P2CBRANCH , P2INT );
1832187Smckusick 	    putdot( filename , line );
1842187Smckusick 		/*
1853278Smckusic 		 * put down the label at the top of the loop
1863278Smckusic 		 */
1873278Smckusic 	    again = getlab();
1883278Smckusic 	    putlab( again );
1893278Smckusic 		/*
1902187Smckusick 		 * okay, then we have to execute the body, but first,
1912187Smckusick 		 * assign the initial expression to the for variable.
1922187Smckusick 		 * see the note in asgnop1 about why this is an rvalue.
1932187Smckusick 		 */
1943371Speter 	    lvalue( lhs , NOUSE , RREQ );
1952187Smckusick 	    if ( opt( 't' ) ) {
1962187Smckusick 		precheck( fortype , "_RANG4" , "_RSNG4" );
1972187Smckusick 	    }
1982187Smckusick 	    putRV( 0 , cbn , initoff , forctype );
1992187Smckusick 	    if ( opt( 't' ) ) {
2002187Smckusick 		postcheck( fortype );
2012187Smckusick 	    }
2022187Smckusick 	    putop( P2ASSIGN , forctype );
2032187Smckusick 	    putdot( filename , line );
2042187Smckusick #	endif PC
2052187Smckusick #	ifdef OBJ
2063083Smckusic 	    gen(O_AS2, O_AS2, sizeof(long), width(termtype));
2072187Smckusick 		/*
2082187Smckusick 		 * we can skip the loop altogether if !( init <= term )
2092187Smckusick 		 */
2102187Smckusick 	    put(2, O_RV4 | cbn<<8+INDX, initoff);
2112187Smckusick 	    put(2, O_RV4 | cbn<<8+INDX, termoff);
2122187Smckusick 	    gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long),
2132187Smckusick 			sizeof(long));
2142187Smckusick 	    after = getlab();
2152187Smckusick 	    put(2, O_IF, after);
2162187Smckusick 		/*
2173278Smckusic 		 * put down the label at the top of the loop
2183278Smckusic 		 */
2193278Smckusic 	    again = getlab();
2203278Smckusic 	    putlab( again );
2213278Smckusic 		/*
2222187Smckusick 		 * okay, then we have to execute the body, but first,
2232187Smckusick 		 * assign the initial expression to the for variable.
2242187Smckusick 		 */
2252187Smckusick 	    lvalue( lhs , NOUSE , LREQ );
2262187Smckusick 	    put(2, O_RV4 | cbn<<8+INDX, initoff);
2272187Smckusick 	    rangechk(fortype, nl+T4INT);
2283083Smckusic 	    gen(O_AS2, O_AS2, width(fortype), sizeof(long));
2292187Smckusick #	endif OBJ
2302187Smckusick 	    /*
231*3584Speter 	     *	shadowing the real for variable
232*3584Speter 	     *	with the initail expression temporary:
233*3584Speter 	     *	save the real for variable's offset, flags
234*3584Speter 	     *	(including nl_block).
235*3584Speter 	     *	replace them with the initial expression's offset,
236*3584Speter 	     *	and mark it as being a for variable.
237*3584Speter 	     */
238*3584Speter 	shadowed = TRUE;
239*3584Speter 	s_offset = forvar -> value[ NL_OFFS ];
240*3584Speter 	s_flags = forvar -> nl_flags;
241*3584Speter 	forvar -> value[ NL_OFFS ] = initoff;
242*3584Speter 	forvar -> nl_flags = cbn;
243*3584Speter 	forvar -> value[ NL_FORV ] = FORVAR;
244*3584Speter 	    /*
2452187Smckusick 	     * and don't forget ...
2462187Smckusick 	     */
2473278Smckusic 	putcnt();
2483278Smckusic 	statement( stat );
2492187Smckusick 	    /*
2502187Smckusick 	     * wasn't that fun?  do we get to do it again?
2512187Smckusick 	     *	we don't do it again if ( !( forvar < limit ) )
2522187Smckusick 	     *	pretend we were doing this at the top of the loop
2532187Smckusick 	     */
2542187Smckusick 	line = arg[ 1 ];
2552187Smckusick #	ifdef PC
2562187Smckusick 	    if ( opt( 'p' ) ) {
2572187Smckusick 		if ( opt('t') ) {
2582187Smckusick 		    putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
2592187Smckusick 			    , "_LINO" );
2602187Smckusick 		    putop( P2UNARY P2CALL , P2INT );
2612187Smckusick 		    putdot( filename , line );
2622187Smckusick 		} else {
2632187Smckusick 		    putRV( STMTCOUNT , 0 , 0 , P2INT );
2642187Smckusick 		    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
2652187Smckusick 		    putop( P2ASG P2PLUS , P2INT );
2662187Smckusick 		    putdot( filename , line );
2672187Smckusick 		}
2682187Smckusick 	    }
2692187Smckusick 	    rvalue( lhs , NIL , RREQ );
2702187Smckusick 	    putRV( 0 , cbn , termoff , forctype );
2712187Smckusick 	    putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , forctype );
2722187Smckusick 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
2732187Smckusick 	    putop( P2CBRANCH , P2INT );
2742187Smckusick 	    putdot( filename , line );
2752187Smckusick 		/*
2762187Smckusick 		 * okay, so we have to do it again,
2772187Smckusick 		 * but first, increment the for variable.
2782187Smckusick 		 * there it is again, an rvalue on the lhs of an assignment.
2792187Smckusick 		 */
2803371Speter 	    lvalue( lhs , MOD , RREQ );
2812187Smckusick 	    if ( opt( 't' ) ) {
2822187Smckusick 		precheck( fortype , "_RANG4" , "_RSNG4" );
2832187Smckusick 	    }
2842187Smckusick 	    rvalue( lhs , NIL , RREQ );
2852187Smckusick 	    putleaf( P2ICON , 1 , 0 , forctype , 0 );
2862187Smckusick 	    putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , forctype );
2872187Smckusick 	    if ( opt( 't' ) ) {
2882187Smckusick 		postcheck( fortype );
2892187Smckusick 	    }
2902187Smckusick 	    putop( P2ASSIGN , forctype );
2912187Smckusick 	    putdot( filename , line );
2922187Smckusick 		/*
2932187Smckusick 		 * and do it all again
2942187Smckusick 		 */
2952187Smckusick 	    putjbr( again );
2962187Smckusick 		/*
2972187Smckusick 		 * and here we are
2982187Smckusick 		 */
2992187Smckusick 	    putlab( after );
3002187Smckusick #	endif PC
3012187Smckusick #	ifdef OBJ
3022187Smckusick 		/*
3032187Smckusick 		 * okay, so we have to do it again.
3042187Smckusick 		 * Luckily we have a magic opcode which increments the
3052187Smckusick 		 * index variable, checks the limit falling through if
3062187Smckusick 		 * it has been reached, else range checking the result
3072187Smckusick 		 * updating the index variable, and returning to the top
3082187Smckusick 		 * of the loop.
3092187Smckusick 		 */
3102649Speter 	    putline();
3112187Smckusick 	    put(2, O_RV4 | cbn<<8+INDX, termoff);
3122187Smckusick 	    lvalue(lhs, MOD, LREQ);
3133083Smckusic 	    if (width(fortype) <= 2)
3143083Smckusic 		    put(4, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) +
3153083Smckusic 			    (width(fortype)>>1), (int)fortype->range[0],
3163083Smckusic 			    (int)fortype->range[1], again);
3173083Smckusic 	    else
3183083Smckusic 		    put(4, (arg[0] == T_FORU ? O_FOR4U : O_FOR4D),
3193083Smckusic 			    fortype->range[0], fortype->range[1], again);
3202187Smckusick 		/*
3212187Smckusick 		 * and here we are
3222187Smckusick 		 */
3232187Smckusick 	    patch( after );
3242187Smckusick #	endif OBJ
3252187Smckusick byebye:
3262187Smckusick 	noreach = 0;
327*3584Speter 	if (forvar != NIL) {
328*3584Speter 	    forvar -> value[ NL_FORV ] = s_forv;
3292187Smckusick 	}
330*3584Speter 	if ( shadowed ) {
331*3584Speter 	    forvar -> value[ NL_OFFS ] = s_offset;
332*3584Speter 	    forvar -> nl_flags = s_flags;
333*3584Speter 	}
3342187Smckusick 	if ( goc != gocnt ) {
3352187Smckusick 	    putcnt();
3362187Smckusick 	}
3372187Smckusick     }
338