xref: /csrg-svn/usr.bin/pascal/src/forop.c (revision 2187)
1*2187Smckusick /* Copyright (c) 1979 Regents of the University of California */
2*2187Smckusick 
3*2187Smckusick static	char sccsid[] = "@(#)forop.c 1.1 01/16/81";
4*2187Smckusick 
5*2187Smckusick #include	"whoami.h"
6*2187Smckusick #include	"0.h"
7*2187Smckusick #include	"opcode.h"
8*2187Smckusick #include	"tree.h"
9*2187Smckusick #include	"objfmt.h"
10*2187Smckusick #ifdef PC
11*2187Smckusick #    include	"pc.h"
12*2187Smckusick #    include	"pcops.h"
13*2187Smckusick #endif PC
14*2187Smckusick     /*
15*2187Smckusick      *	forop for pc:
16*2187Smckusick      *	    this evaluates the initial and termination expressions,
17*2187Smckusick      *	    checks them to see if the loop executes at all, and then
18*2187Smckusick      *	    does the assignment and the loop.
19*2187Smckusick      *	arg here looks like:
20*2187Smckusick      *	arg[0]	T_FORU or T_FORD
21*2187Smckusick      *	   [1]	lineof "for"
22*2187Smckusick      *	   [2]	[0]	T_ASGN
23*2187Smckusick      *		[1]	lineof ":="
24*2187Smckusick      *		[2]	[0]	T_VAR
25*2187Smckusick      *			[1]	lineof id
26*2187Smckusick      *			[2]	char * to id
27*2187Smckusick      *			[3]	qualifications
28*2187Smckusick      *		[3]	initial expression
29*2187Smckusick      *	  [3]	termination expression
30*2187Smckusick      *	  [4]	statement
31*2187Smckusick      */
32*2187Smckusick forop( arg )
33*2187Smckusick     int	*arg;
34*2187Smckusick     {
35*2187Smckusick 	int		*lhs;
36*2187Smckusick 	struct nl	*forvar;
37*2187Smckusick 	struct nl	*fortype;
38*2187Smckusick 	int		forctype;
39*2187Smckusick 	int		*init;
40*2187Smckusick 	struct nl	*inittype;
41*2187Smckusick 	int		initoff;
42*2187Smckusick 	int		*term;
43*2187Smckusick 	struct nl	*termtype;
44*2187Smckusick 	int		termoff;
45*2187Smckusick 	int		*stat;
46*2187Smckusick 	int		goc;		/* saved gocnt */
47*2187Smckusick 	int		again;		/* label at the top of the loop */
48*2187Smckusick 	int		after;		/* label after the end of the loop */
49*2187Smckusick 
50*2187Smckusick 	goc = gocnt;
51*2187Smckusick 	forvar = NIL;
52*2187Smckusick 	if ( arg == NIL ) {
53*2187Smckusick 	    goto byebye;
54*2187Smckusick 	}
55*2187Smckusick 	if ( arg[2] == NIL ) {
56*2187Smckusick 	    goto byebye;
57*2187Smckusick 	}
58*2187Smckusick 	line = arg[1];
59*2187Smckusick 	putline();
60*2187Smckusick 	lhs = ( (int *) arg[2] )[2];
61*2187Smckusick 	init = ( (int *) arg[2] )[3];
62*2187Smckusick 	term = arg[3];
63*2187Smckusick 	stat = arg[4];
64*2187Smckusick 	if ( lhs[3] != NIL ) {
65*2187Smckusick 	    error("For variable must be unqualified");
66*2187Smckusick 	    rvalue( init , NIL , RREQ );
67*2187Smckusick 	    rvalue( term , NIL , RREQ );
68*2187Smckusick 	    statement( stat );
69*2187Smckusick 	    goto byebye;
70*2187Smckusick 	}
71*2187Smckusick 	    /*
72*2187Smckusick 	     * and this marks the variable as used!!!
73*2187Smckusick 	     */
74*2187Smckusick 	forvar = lookup( lhs[2] );
75*2187Smckusick 	if ( forvar == NIL ) {
76*2187Smckusick 	    rvalue( init , NIL , RREQ );
77*2187Smckusick 	    rvalue( term , NIL , RREQ );
78*2187Smckusick 	    statement( stat );
79*2187Smckusick 	    goto byebye;
80*2187Smckusick 	}
81*2187Smckusick 	    /*
82*2187Smckusick 	     * find out the type of the loop variable
83*2187Smckusick 	     */
84*2187Smckusick 	codeoff();
85*2187Smckusick 	fortype = lvalue( lhs , MOD , RREQ );
86*2187Smckusick 	codeon();
87*2187Smckusick 	    /*
88*2187Smckusick 	     * mark the forvar so we can't change it during the loop
89*2187Smckusick 	     */
90*2187Smckusick 	forvar -> value[ NL_FORV ] = 1;
91*2187Smckusick 	if ( fortype == NIL ) {
92*2187Smckusick 	    rvalue( init , NIL , RREQ );
93*2187Smckusick 	    rvalue( term , NIL , RREQ );
94*2187Smckusick 	    statement( stat );
95*2187Smckusick 	    goto byebye;
96*2187Smckusick 	}
97*2187Smckusick 	if ( isnta( fortype , "bcis" ) ) {
98*2187Smckusick 	    error("For variables cannot be %ss" , nameof( fortype ) );
99*2187Smckusick 	    rvalue( init , NIL , RREQ );
100*2187Smckusick 	    rvalue( term , NIL , RREQ );
101*2187Smckusick 	    statement( stat );
102*2187Smckusick 	    goto byebye;
103*2187Smckusick 	}
104*2187Smckusick 	    /*
105*2187Smckusick 	     * allocate space for the initial and termination expressions
106*2187Smckusick 	     */
107*2187Smckusick 	sizes[cbn].om_off -= sizeof( long );
108*2187Smckusick 	initoff = sizes[cbn].om_off;
109*2187Smckusick 	sizes[cbn].om_off -= sizeof( long );
110*2187Smckusick 	termoff = sizes[cbn].om_off;
111*2187Smckusick 	if ( sizes[cbn].om_off < sizes[cbn].om_max ) {
112*2187Smckusick 	    sizes[cbn].om_max = sizes[cbn].om_off;
113*2187Smckusick 	}
114*2187Smckusick #	ifdef PC
115*2187Smckusick 	    putlbracket( ftnno , -sizes[cbn].om_off );
116*2187Smckusick 		/*
117*2187Smckusick 		 * compute and save the initial expression
118*2187Smckusick 		 */
119*2187Smckusick 	    forctype = p2type( fortype );
120*2187Smckusick 	    putRV( 0 , cbn , initoff , forctype );
121*2187Smckusick #	endif PC
122*2187Smckusick #	ifdef OBJ
123*2187Smckusick 	    put(2, O_LV | cbn<<8+INDX, initoff);
124*2187Smckusick #	endif OBJ
125*2187Smckusick 	inittype = rvalue( init , fortype , RREQ );
126*2187Smckusick 	if ( incompat( inittype , fortype , init ) ) {
127*2187Smckusick 	    cerror("Type of initial expression clashed with index type in 'for' statement");
128*2187Smckusick 	    rvalue( term , NIL , RREQ );
129*2187Smckusick 	    statement( stat );
130*2187Smckusick 	    goto byebye;
131*2187Smckusick 	}
132*2187Smckusick #	ifdef PC
133*2187Smckusick 	    putop( P2ASSIGN , forctype );
134*2187Smckusick 	    putdot( filename , line );
135*2187Smckusick 		/*
136*2187Smckusick 		 * compute and save the termination expression
137*2187Smckusick 		 */
138*2187Smckusick 	    putRV( 0 , cbn , termoff , forctype );
139*2187Smckusick #	endif PC
140*2187Smckusick #	ifdef OBJ
141*2187Smckusick 	    put(1, width(inittype) <= 2 ? O_AS24 : O_AS4);
142*2187Smckusick 		/*
143*2187Smckusick 		 * compute and save the termination expression
144*2187Smckusick 		 */
145*2187Smckusick 	    put(2, O_LV | cbn<<8+INDX, termoff);
146*2187Smckusick #	endif OBJ
147*2187Smckusick 	termtype = rvalue( term , fortype , RREQ );
148*2187Smckusick 	if ( incompat( termtype , fortype , term ) ) {
149*2187Smckusick 	    cerror("Type of limit expression clashed with index type in 'for' statement");
150*2187Smckusick 	    statement( stat );
151*2187Smckusick 	    goto byebye;
152*2187Smckusick 	}
153*2187Smckusick #	ifdef PC
154*2187Smckusick 	    putop( P2ASSIGN , forctype );
155*2187Smckusick 	    putdot( filename , line );
156*2187Smckusick 		/*
157*2187Smckusick 		 * we can skip the loop altogether if !( init <= term )
158*2187Smckusick 		 */
159*2187Smckusick 	    after = getlab();
160*2187Smckusick 	    putRV( 0 , cbn , initoff , forctype );
161*2187Smckusick 	    putRV( 0 , cbn , termoff , forctype );
162*2187Smckusick 	    putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , forctype );
163*2187Smckusick 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
164*2187Smckusick 	    putop( P2CBRANCH , P2INT );
165*2187Smckusick 	    putdot( filename , line );
166*2187Smckusick 		/*
167*2187Smckusick 		 * okay, then we have to execute the body, but first,
168*2187Smckusick 		 * assign the initial expression to the for variable.
169*2187Smckusick 		 * see the note in asgnop1 about why this is an rvalue.
170*2187Smckusick 		 */
171*2187Smckusick 	    rvalue( lhs , NIL , RREQ );
172*2187Smckusick 	    if ( opt( 't' ) ) {
173*2187Smckusick 		precheck( fortype , "_RANG4" , "_RSNG4" );
174*2187Smckusick 	    }
175*2187Smckusick 	    putRV( 0 , cbn , initoff , forctype );
176*2187Smckusick 	    if ( opt( 't' ) ) {
177*2187Smckusick 		postcheck( fortype );
178*2187Smckusick 	    }
179*2187Smckusick 	    putop( P2ASSIGN , forctype );
180*2187Smckusick 	    putdot( filename , line );
181*2187Smckusick #	endif PC
182*2187Smckusick #	ifdef OBJ
183*2187Smckusick 	    put(1, width(termtype) <= 2 ? O_AS24 : O_AS4);
184*2187Smckusick 		/*
185*2187Smckusick 		 * we can skip the loop altogether if !( init <= term )
186*2187Smckusick 		 */
187*2187Smckusick 	    put(2, O_RV4 | cbn<<8+INDX, initoff);
188*2187Smckusick 	    put(2, O_RV4 | cbn<<8+INDX, termoff);
189*2187Smckusick 	    gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long),
190*2187Smckusick 			sizeof(long));
191*2187Smckusick 	    after = getlab();
192*2187Smckusick 	    put(2, O_IF, after);
193*2187Smckusick 		/*
194*2187Smckusick 		 * okay, then we have to execute the body, but first,
195*2187Smckusick 		 * assign the initial expression to the for variable.
196*2187Smckusick 		 */
197*2187Smckusick 	    lvalue( lhs , NOUSE , LREQ );
198*2187Smckusick 	    put(2, O_RV4 | cbn<<8+INDX, initoff);
199*2187Smckusick 	    rangechk(fortype, nl+T4INT);
200*2187Smckusick 	    put(1, width(fortype) <= 2 ? O_AS42 : O_AS4);
201*2187Smckusick #	endif OBJ
202*2187Smckusick 	/*
203*2187Smckusick 	 * put down the label at the top of the loop
204*2187Smckusick 	 */
205*2187Smckusick 	again = getlab();
206*2187Smckusick 	putlab( again );
207*2187Smckusick 	putcnt();
208*2187Smckusick 	    /*
209*2187Smckusick 	     * and don't forget ...
210*2187Smckusick 	     */
211*2187Smckusick 	statement( arg[ 4 ] );
212*2187Smckusick 	    /*
213*2187Smckusick 	     * wasn't that fun?  do we get to do it again?
214*2187Smckusick 	     *	we don't do it again if ( !( forvar < limit ) )
215*2187Smckusick 	     *	pretend we were doing this at the top of the loop
216*2187Smckusick 	     */
217*2187Smckusick 	line = arg[ 1 ];
218*2187Smckusick #	ifdef PC
219*2187Smckusick 	    if ( opt( 'p' ) ) {
220*2187Smckusick 		if ( opt('t') ) {
221*2187Smckusick 		    putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
222*2187Smckusick 			    , "_LINO" );
223*2187Smckusick 		    putop( P2UNARY P2CALL , P2INT );
224*2187Smckusick 		    putdot( filename , line );
225*2187Smckusick 		} else {
226*2187Smckusick 		    putRV( STMTCOUNT , 0 , 0 , P2INT );
227*2187Smckusick 		    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
228*2187Smckusick 		    putop( P2ASG P2PLUS , P2INT );
229*2187Smckusick 		    putdot( filename , line );
230*2187Smckusick 		}
231*2187Smckusick 	    }
232*2187Smckusick 	    rvalue( lhs , NIL , RREQ );
233*2187Smckusick 	    putRV( 0 , cbn , termoff , forctype );
234*2187Smckusick 	    putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , forctype );
235*2187Smckusick 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
236*2187Smckusick 	    putop( P2CBRANCH , P2INT );
237*2187Smckusick 	    putdot( filename , line );
238*2187Smckusick 		/*
239*2187Smckusick 		 * okay, so we have to do it again,
240*2187Smckusick 		 * but first, increment the for variable.
241*2187Smckusick 		 * there it is again, an rvalue on the lhs of an assignment.
242*2187Smckusick 		 */
243*2187Smckusick 	    rvalue( lhs , NIL , RREQ );
244*2187Smckusick 	    if ( opt( 't' ) ) {
245*2187Smckusick 		precheck( fortype , "_RANG4" , "_RSNG4" );
246*2187Smckusick 	    }
247*2187Smckusick 	    rvalue( lhs , NIL , RREQ );
248*2187Smckusick 	    putleaf( P2ICON , 1 , 0 , forctype , 0 );
249*2187Smckusick 	    putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , forctype );
250*2187Smckusick 	    if ( opt( 't' ) ) {
251*2187Smckusick 		postcheck( fortype );
252*2187Smckusick 	    }
253*2187Smckusick 	    putop( P2ASSIGN , forctype );
254*2187Smckusick 	    putdot( filename , line );
255*2187Smckusick 		/*
256*2187Smckusick 		 * and do it all again
257*2187Smckusick 		 */
258*2187Smckusick 	    putjbr( again );
259*2187Smckusick 		/*
260*2187Smckusick 		 * and here we are
261*2187Smckusick 		 */
262*2187Smckusick 	    putlab( after );
263*2187Smckusick 		/*
264*2187Smckusick 		 * deallocate the initial and limit variables
265*2187Smckusick 		 */
266*2187Smckusick 	    sizes[cbn].om_off += 2 * ( sizeof( long ) );
267*2187Smckusick 	    putlbracket( ftnno , -sizes[cbn].om_off );
268*2187Smckusick #	endif PC
269*2187Smckusick #	ifdef OBJ
270*2187Smckusick 		/*
271*2187Smckusick 		 * okay, so we have to do it again.
272*2187Smckusick 		 * Luckily we have a magic opcode which increments the
273*2187Smckusick 		 * index variable, checks the limit falling through if
274*2187Smckusick 		 * it has been reached, else range checking the result
275*2187Smckusick 		 * updating the index variable, and returning to the top
276*2187Smckusick 		 * of the loop.
277*2187Smckusick 		 */
278*2187Smckusick 	    put(2, O_RV4 | cbn<<8+INDX, termoff);
279*2187Smckusick 	    lvalue(lhs, MOD, LREQ);
280*2187Smckusick 	    put(4, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + (width(fortype)>>1),
281*2187Smckusick 		    fortype->range[0], fortype->range[1], again);
282*2187Smckusick 		/*
283*2187Smckusick 		 * and here we are
284*2187Smckusick 		 */
285*2187Smckusick 	    patch( after );
286*2187Smckusick 		/*
287*2187Smckusick 		 * deallocate the initial and limit variables
288*2187Smckusick 		 */
289*2187Smckusick 	    sizes[cbn].om_off += 2 * ( sizeof( long ) );
290*2187Smckusick #	endif OBJ
291*2187Smckusick byebye:
292*2187Smckusick 	noreach = 0;
293*2187Smckusick 	if ( forvar != NIL ) {
294*2187Smckusick 	    forvar -> value[ NL_FORV ] = 0;
295*2187Smckusick 	}
296*2187Smckusick 	if ( goc != gocnt ) {
297*2187Smckusick 	    putcnt();
298*2187Smckusick 	}
299*2187Smckusick     }
300