xref: /csrg-svn/usr.bin/pascal/src/forop.c (revision 2649)
12187Smckusick /* Copyright (c) 1979 Regents of the University of California */
22187Smckusick 
3*2649Speter static	char sccsid[] = "@(#)forop.c 1.2 02/24/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 	     */
1072187Smckusick 	sizes[cbn].om_off -= sizeof( long );
1082187Smckusick 	initoff = sizes[cbn].om_off;
1092187Smckusick 	sizes[cbn].om_off -= sizeof( long );
1102187Smckusick 	termoff = sizes[cbn].om_off;
1112187Smckusick 	if ( sizes[cbn].om_off < sizes[cbn].om_max ) {
1122187Smckusick 	    sizes[cbn].om_max = sizes[cbn].om_off;
1132187Smckusick 	}
1142187Smckusick #	ifdef PC
1152187Smckusick 	    putlbracket( ftnno , -sizes[cbn].om_off );
1162187Smckusick 		/*
1172187Smckusick 		 * compute and save the initial expression
1182187Smckusick 		 */
1192187Smckusick 	    forctype = p2type( fortype );
1202187Smckusick 	    putRV( 0 , cbn , initoff , forctype );
1212187Smckusick #	endif PC
1222187Smckusick #	ifdef OBJ
1232187Smckusick 	    put(2, O_LV | cbn<<8+INDX, initoff);
1242187Smckusick #	endif OBJ
1252187Smckusick 	inittype = rvalue( init , fortype , RREQ );
1262187Smckusick 	if ( incompat( inittype , fortype , init ) ) {
1272187Smckusick 	    cerror("Type of initial expression clashed with index type in 'for' statement");
1282187Smckusick 	    rvalue( term , NIL , RREQ );
1292187Smckusick 	    statement( stat );
1302187Smckusick 	    goto byebye;
1312187Smckusick 	}
1322187Smckusick #	ifdef PC
1332187Smckusick 	    putop( P2ASSIGN , forctype );
1342187Smckusick 	    putdot( filename , line );
1352187Smckusick 		/*
1362187Smckusick 		 * compute and save the termination expression
1372187Smckusick 		 */
1382187Smckusick 	    putRV( 0 , cbn , termoff , forctype );
1392187Smckusick #	endif PC
1402187Smckusick #	ifdef OBJ
1412187Smckusick 	    put(1, width(inittype) <= 2 ? O_AS24 : O_AS4);
1422187Smckusick 		/*
1432187Smckusick 		 * compute and save the termination expression
1442187Smckusick 		 */
1452187Smckusick 	    put(2, O_LV | cbn<<8+INDX, termoff);
1462187Smckusick #	endif OBJ
1472187Smckusick 	termtype = rvalue( term , fortype , RREQ );
1482187Smckusick 	if ( incompat( termtype , fortype , term ) ) {
1492187Smckusick 	    cerror("Type of limit expression clashed with index type in 'for' statement");
1502187Smckusick 	    statement( stat );
1512187Smckusick 	    goto byebye;
1522187Smckusick 	}
1532187Smckusick #	ifdef PC
1542187Smckusick 	    putop( P2ASSIGN , forctype );
1552187Smckusick 	    putdot( filename , line );
1562187Smckusick 		/*
1572187Smckusick 		 * we can skip the loop altogether if !( init <= term )
1582187Smckusick 		 */
1592187Smckusick 	    after = getlab();
1602187Smckusick 	    putRV( 0 , cbn , initoff , forctype );
1612187Smckusick 	    putRV( 0 , cbn , termoff , forctype );
1622187Smckusick 	    putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , forctype );
1632187Smckusick 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
1642187Smckusick 	    putop( P2CBRANCH , P2INT );
1652187Smckusick 	    putdot( filename , line );
1662187Smckusick 		/*
1672187Smckusick 		 * okay, then we have to execute the body, but first,
1682187Smckusick 		 * assign the initial expression to the for variable.
1692187Smckusick 		 * see the note in asgnop1 about why this is an rvalue.
1702187Smckusick 		 */
1712187Smckusick 	    rvalue( lhs , NIL , RREQ );
1722187Smckusick 	    if ( opt( 't' ) ) {
1732187Smckusick 		precheck( fortype , "_RANG4" , "_RSNG4" );
1742187Smckusick 	    }
1752187Smckusick 	    putRV( 0 , cbn , initoff , forctype );
1762187Smckusick 	    if ( opt( 't' ) ) {
1772187Smckusick 		postcheck( fortype );
1782187Smckusick 	    }
1792187Smckusick 	    putop( P2ASSIGN , forctype );
1802187Smckusick 	    putdot( filename , line );
1812187Smckusick #	endif PC
1822187Smckusick #	ifdef OBJ
1832187Smckusick 	    put(1, width(termtype) <= 2 ? O_AS24 : O_AS4);
1842187Smckusick 		/*
1852187Smckusick 		 * we can skip the loop altogether if !( init <= term )
1862187Smckusick 		 */
1872187Smckusick 	    put(2, O_RV4 | cbn<<8+INDX, initoff);
1882187Smckusick 	    put(2, O_RV4 | cbn<<8+INDX, termoff);
1892187Smckusick 	    gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long),
1902187Smckusick 			sizeof(long));
1912187Smckusick 	    after = getlab();
1922187Smckusick 	    put(2, O_IF, after);
1932187Smckusick 		/*
1942187Smckusick 		 * okay, then we have to execute the body, but first,
1952187Smckusick 		 * assign the initial expression to the for variable.
1962187Smckusick 		 */
1972187Smckusick 	    lvalue( lhs , NOUSE , LREQ );
1982187Smckusick 	    put(2, O_RV4 | cbn<<8+INDX, initoff);
1992187Smckusick 	    rangechk(fortype, nl+T4INT);
2002187Smckusick 	    put(1, width(fortype) <= 2 ? O_AS42 : O_AS4);
2012187Smckusick #	endif OBJ
2022187Smckusick 	/*
2032187Smckusick 	 * put down the label at the top of the loop
2042187Smckusick 	 */
2052187Smckusick 	again = getlab();
2062187Smckusick 	putlab( again );
2072187Smckusick 	putcnt();
2082187Smckusick 	    /*
2092187Smckusick 	     * and don't forget ...
2102187Smckusick 	     */
2112187Smckusick 	statement( arg[ 4 ] );
2122187Smckusick 	    /*
2132187Smckusick 	     * wasn't that fun?  do we get to do it again?
2142187Smckusick 	     *	we don't do it again if ( !( forvar < limit ) )
2152187Smckusick 	     *	pretend we were doing this at the top of the loop
2162187Smckusick 	     */
2172187Smckusick 	line = arg[ 1 ];
2182187Smckusick #	ifdef PC
2192187Smckusick 	    if ( opt( 'p' ) ) {
2202187Smckusick 		if ( opt('t') ) {
2212187Smckusick 		    putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
2222187Smckusick 			    , "_LINO" );
2232187Smckusick 		    putop( P2UNARY P2CALL , P2INT );
2242187Smckusick 		    putdot( filename , line );
2252187Smckusick 		} else {
2262187Smckusick 		    putRV( STMTCOUNT , 0 , 0 , P2INT );
2272187Smckusick 		    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
2282187Smckusick 		    putop( P2ASG P2PLUS , P2INT );
2292187Smckusick 		    putdot( filename , line );
2302187Smckusick 		}
2312187Smckusick 	    }
2322187Smckusick 	    rvalue( lhs , NIL , RREQ );
2332187Smckusick 	    putRV( 0 , cbn , termoff , forctype );
2342187Smckusick 	    putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , forctype );
2352187Smckusick 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
2362187Smckusick 	    putop( P2CBRANCH , P2INT );
2372187Smckusick 	    putdot( filename , line );
2382187Smckusick 		/*
2392187Smckusick 		 * okay, so we have to do it again,
2402187Smckusick 		 * but first, increment the for variable.
2412187Smckusick 		 * there it is again, an rvalue on the lhs of an assignment.
2422187Smckusick 		 */
2432187Smckusick 	    rvalue( lhs , NIL , RREQ );
2442187Smckusick 	    if ( opt( 't' ) ) {
2452187Smckusick 		precheck( fortype , "_RANG4" , "_RSNG4" );
2462187Smckusick 	    }
2472187Smckusick 	    rvalue( lhs , NIL , RREQ );
2482187Smckusick 	    putleaf( P2ICON , 1 , 0 , forctype , 0 );
2492187Smckusick 	    putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , forctype );
2502187Smckusick 	    if ( opt( 't' ) ) {
2512187Smckusick 		postcheck( fortype );
2522187Smckusick 	    }
2532187Smckusick 	    putop( P2ASSIGN , forctype );
2542187Smckusick 	    putdot( filename , line );
2552187Smckusick 		/*
2562187Smckusick 		 * and do it all again
2572187Smckusick 		 */
2582187Smckusick 	    putjbr( again );
2592187Smckusick 		/*
2602187Smckusick 		 * and here we are
2612187Smckusick 		 */
2622187Smckusick 	    putlab( after );
2632187Smckusick 		/*
2642187Smckusick 		 * deallocate the initial and limit variables
2652187Smckusick 		 */
2662187Smckusick 	    sizes[cbn].om_off += 2 * ( sizeof( long ) );
2672187Smckusick 	    putlbracket( ftnno , -sizes[cbn].om_off );
2682187Smckusick #	endif PC
2692187Smckusick #	ifdef OBJ
2702187Smckusick 		/*
2712187Smckusick 		 * okay, so we have to do it again.
2722187Smckusick 		 * Luckily we have a magic opcode which increments the
2732187Smckusick 		 * index variable, checks the limit falling through if
2742187Smckusick 		 * it has been reached, else range checking the result
2752187Smckusick 		 * updating the index variable, and returning to the top
2762187Smckusick 		 * of the loop.
2772187Smckusick 		 */
278*2649Speter 	    putline();
2792187Smckusick 	    put(2, O_RV4 | cbn<<8+INDX, termoff);
2802187Smckusick 	    lvalue(lhs, MOD, LREQ);
2812187Smckusick 	    put(4, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + (width(fortype)>>1),
2822187Smckusick 		    fortype->range[0], fortype->range[1], again);
2832187Smckusick 		/*
2842187Smckusick 		 * and here we are
2852187Smckusick 		 */
2862187Smckusick 	    patch( after );
2872187Smckusick 		/*
2882187Smckusick 		 * deallocate the initial and limit variables
2892187Smckusick 		 */
2902187Smckusick 	    sizes[cbn].om_off += 2 * ( sizeof( long ) );
2912187Smckusick #	endif OBJ
2922187Smckusick byebye:
2932187Smckusick 	noreach = 0;
2942187Smckusick 	if ( forvar != NIL ) {
2952187Smckusick 	    forvar -> value[ NL_FORV ] = 0;
2962187Smckusick 	}
2972187Smckusick 	if ( goc != gocnt ) {
2982187Smckusick 	    putcnt();
2992187Smckusick 	}
3002187Smckusick     }
301