xref: /original-bsd/usr.bin/pascal/src/forop.c (revision 1f3a482a)
1 /* Copyright (c) 1979 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)forop.c 1.9 06/01/81";
4 
5 #include	"whoami.h"
6 #include	"0.h"
7 #include	"opcode.h"
8 #include	"tree.h"
9 #include	"objfmt.h"
10 #ifdef PC
11 #    include	"pc.h"
12 #    include	"pcops.h"
13 #endif PC
14 
15     /*
16      *	forop for pc:
17      *	    this evaluates the initial and termination expressions,
18      *	    checks them to see if the loop executes at all, and then
19      *	    does the assignment and the loop.
20      *	arg here looks like:
21      *	arg[0]	T_FORU or T_FORD
22      *	   [1]	lineof "for"
23      *	   [2]	[0]	T_ASGN
24      *		[1]	lineof ":="
25      *		[2]	[0]	T_VAR
26      *			[1]	lineof id
27      *			[2]	char * to id
28      *			[3]	qualifications
29      *		[3]	initial expression
30      *	  [3]	termination expression
31      *	  [4]	statement
32      */
33 forop( arg )
34     int	*arg;
35     {
36 	int		*lhs;
37 	struct nl	*forvar;
38 	struct nl	*fortype;
39 	int		*init;
40 	struct nl	*inittype;
41 	struct nl	*initnlp;	/* initial value namelist entry */
42 	char		forflags;
43 	int		*term;
44 	struct nl	*termtype;
45 	struct nl	*termnlp;	/* termination value namelist entry */
46 	int		*stat;
47 	int		goc;		/* saved gocnt */
48 	int		again;		/* label at the top of the loop */
49 	int		after;		/* label after the end of the loop */
50 	bool		shadowed;	/* shadowing for var in temporary? */
51 	long		s_offset;	/* saved offset of real for variable */
52 	long		s_flags;	/* saved flags of real for variable */
53 	long		s_forv;		/* saved NL_FORV of the for variable */
54 #	ifdef PC
55 	    char	s_extra_flags;	/* saved extra_flags of the for var */
56 #	endif PC
57 
58 	goc = gocnt;
59 	forvar = NIL;
60 	shadowed = FALSE;
61 	if ( arg == NIL ) {
62 	    goto byebye;
63 	}
64 	if ( arg[2] == NIL ) {
65 	    goto byebye;
66 	}
67 	line = arg[1];
68 	putline();
69 	lhs = ( (int *) arg[2] )[2];
70 	init = ( (int *) arg[2] )[3];
71 	term = arg[3];
72 	stat = arg[4];
73 	if (lhs == NIL) {
74 nogood:
75 	    if (forvar != NIL) {
76 		forvar->value[ NL_FORV ] = FORVAR;
77 	    }
78 	    rvalue( init , NIL , RREQ );
79 	    rvalue( term , NIL , RREQ );
80 	    statement( stat );
81 	    goto byebye;
82 	}
83 	    /*
84 	     * and this marks the variable as used!!!
85 	     */
86 	forvar = lookup( lhs[2] );
87 	if ( forvar == NIL ) {
88 	    goto nogood;
89 	}
90 	s_forv = forvar -> value[ NL_FORV ];
91 	if ( lhs[3] != NIL ) {
92 	    error("For variable %s must be unqualified", forvar->symbol);
93 	    goto nogood;
94 	}
95 	if (forvar->class == WITHPTR) {
96 	    error("For variable %s cannot be an element of a record", lhs[2]);
97 	    goto nogood;
98 	}
99 	if ( opt('s') &&
100 	    ( ( bn != cbn ) ||
101 #ifdef OBJ
102 		( whereis( bn , forvar->value[NL_OFFS] , 0 ) == PARAMVAR )
103 #endif OBJ
104 #ifdef PC
105 		( whereis( bn , forvar->value[NL_OFFS] , forvar -> extra_flags )
106 		    == PARAMVAR )
107 #endif PC
108 	    ) ) {
109 	    standard();
110 	    error("For variable %s must be declared in the block in which it is used", forvar->symbol);
111 	}
112 	    /*
113 	     * find out the type of the loop variable
114 	     */
115 	codeoff();
116 	fortype = lvalue( lhs , MOD , RREQ );
117 	codeon();
118 	if ( fortype == NIL ) {
119 	    goto nogood;
120 	}
121 	if ( isnta( fortype , "bcis" ) ) {
122 	    error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) );
123 	    goto nogood;
124 	}
125 	if ( forvar->value[ NL_FORV ] & FORVAR ) {
126 	    error("Can't modify the for variable %s in the range of the loop", forvar->symbol);
127 	    forvar = NIL;
128 	    goto nogood;
129 	}
130 	    /*
131 	     * allocate space for the initial and termination expressions
132 	     * the initial is tentatively placed in a register as it will
133 	     * shadow the for loop variable in the body of the loop.
134 	     */
135 	initnlp = tmpalloc(sizeof(long), nl+T4INT, REGOK);
136 	termnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG);
137 #	ifdef PC
138 		/*
139 		 * compute and save the initial expression
140 		 */
141 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
142 		    initnlp -> extra_flags , P2INT );
143 #	endif PC
144 #	ifdef OBJ
145 	    put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
146 #	endif OBJ
147 	inittype = rvalue( init , fortype , RREQ );
148 	if ( incompat( inittype , fortype , init ) ) {
149 	    cerror("Type of initial expression clashed with index type in 'for' statement");
150 	    if (forvar != NIL) {
151 		forvar->value[ NL_FORV ] = FORVAR;
152 	    }
153 	    rvalue( term , NIL , RREQ );
154 	    statement( stat );
155 	    goto byebye;
156 	}
157 #	ifdef PC
158 	    putop( P2ASSIGN , P2INT );
159 	    putdot( filename , line );
160 		/*
161 		 * compute and save the termination expression
162 		 */
163 	    putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
164 		    termnlp -> extra_flags , P2INT );
165 #	endif PC
166 #	ifdef OBJ
167 	    gen(O_AS2, O_AS2, sizeof(long), width(inittype));
168 		/*
169 		 * compute and save the termination expression
170 		 */
171 	    put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
172 #	endif OBJ
173 	termtype = rvalue( term , fortype , RREQ );
174 	if ( incompat( termtype , fortype , term ) ) {
175 	    cerror("Type of limit expression clashed with index type in 'for' statement");
176 	    if (forvar != NIL) {
177 		forvar->value[ NL_FORV ] = FORVAR;
178 	    }
179 	    statement( stat );
180 	    goto byebye;
181 	}
182 #	ifdef PC
183 	    putop( P2ASSIGN , P2INT );
184 	    putdot( filename , line );
185 		/*
186 		 * we can skip the loop altogether if !( init <= term )
187 		 */
188 	    after = getlab();
189 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
190 		    initnlp -> extra_flags , P2INT );
191 	    putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
192 		    termnlp -> extra_flags , P2INT );
193 	    putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , P2INT );
194 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
195 	    putop( P2CBRANCH , P2INT );
196 	    putdot( filename , line );
197 		/*
198 		 * put down the label at the top of the loop
199 		 */
200 	    again = getlab();
201 	    putlab( again );
202 		/*
203 		 * okay, then we have to execute the body, but first,
204 		 * assign the initial expression to the for variable.
205 		 * see the note in asgnop1 about why this is an rvalue.
206 		 */
207 	    lvalue( lhs , NOUSE , RREQ );
208 	    if ( opt( 't' ) ) {
209 		precheck( fortype , "_RANG4" , "_RSNG4" );
210 	    }
211 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
212 		    initnlp -> extra_flags , P2INT );
213 	    if ( opt( 't' ) ) {
214 		postcheck( fortype );
215 	    }
216 	    putop( P2ASSIGN , p2type( fortype ) );
217 	    putdot( filename , line );
218 #	endif PC
219 #	ifdef OBJ
220 	    gen(O_AS2, O_AS2, sizeof(long), width(termtype));
221 		/*
222 		 * we can skip the loop altogether if !( init <= term )
223 		 */
224 	    put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
225 	    put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
226 	    gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long),
227 			sizeof(long));
228 	    after = getlab();
229 	    put(2, O_IF, after);
230 		/*
231 		 * put down the label at the top of the loop
232 		 */
233 	    again = getlab();
234 	    putlab( again );
235 		/*
236 		 * okay, then we have to execute the body, but first,
237 		 * assign the initial expression to the for variable.
238 		 */
239 	    lvalue( lhs , NOUSE , LREQ );
240 	    put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
241 	    rangechk(fortype, nl+T4INT);
242 	    gen(O_AS2, O_AS2, width(fortype), sizeof(long));
243 #	endif OBJ
244 	    /*
245 	     *	shadowing the real for variable
246 	     *	with the initail expression temporary:
247 	     *	save the real for variable's offset, flags
248 	     *	(including nl_block).
249 	     *	replace them with the initial expression's offset,
250 	     *	and mark it as being a for variable.
251 	     */
252 	shadowed = TRUE;
253 	s_offset = forvar -> value[ NL_OFFS ];
254 	s_flags = forvar -> nl_flags;
255 	forvar -> value[ NL_OFFS ] = initnlp -> value[ NL_OFFS ];
256 	forvar -> nl_flags = cbn;
257 	forvar -> value[ NL_FORV ] = FORVAR;
258 #	ifdef PC
259 	    s_extra_flags = forvar -> extra_flags;
260 	    forvar -> extra_flags = initnlp -> extra_flags;
261 #	endif PC
262 	    /*
263 	     * and don't forget ...
264 	     */
265 	putcnt();
266 	statement( stat );
267 	    /*
268 	     * wasn't that fun?  do we get to do it again?
269 	     *	we don't do it again if ( !( forvar < limit ) )
270 	     *	pretend we were doing this at the top of the loop
271 	     */
272 	line = arg[ 1 ];
273 #	ifdef PC
274 	    if ( opt( 'p' ) ) {
275 		if ( opt('t') ) {
276 		    putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
277 			    , "_LINO" );
278 		    putop( P2UNARY P2CALL , P2INT );
279 		    putdot( filename , line );
280 		} else {
281 		    putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT );
282 		    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
283 		    putop( P2ASG P2PLUS , P2INT );
284 		    putdot( filename , line );
285 		}
286 	    }
287 	    /*rvalue( lhs , NIL , RREQ );*/
288 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
289 		    initnlp -> extra_flags , P2INT );
290 	    putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
291 		    termnlp -> extra_flags , P2INT );
292 	    putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT );
293 	    putleaf( P2ICON , after , 0 , P2INT , 0 );
294 	    putop( P2CBRANCH , P2INT );
295 	    putdot( filename , line );
296 		/*
297 		 * okay, so we have to do it again,
298 		 * but first, increment the for variable.
299 		 * there it is again, an rvalue on the lhs of an assignment.
300 		 */
301 	    /*lvalue( lhs , MOD , RREQ );*/
302 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
303 		    initnlp -> extra_flags , P2INT );
304 	    if ( opt( 't' ) ) {
305 		precheck( fortype , "_RANG4" , "_RSNG4" );
306 	    }
307 	    /*rvalue( lhs , NIL , RREQ );*/
308 	    putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
309 		    initnlp -> extra_flags , P2INT );
310 	    putleaf( P2ICON , 1 , 0 , P2INT , 0 );
311 	    putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT );
312 	    if ( opt( 't' ) ) {
313 		postcheck( fortype );
314 	    }
315 	    putop( P2ASSIGN , P2INT );
316 	    putdot( filename , line );
317 		/*
318 		 * and do it all again
319 		 */
320 	    putjbr( again );
321 		/*
322 		 * and here we are
323 		 */
324 	    putlab( after );
325 #	endif PC
326 #	ifdef OBJ
327 		/*
328 		 * okay, so we have to do it again.
329 		 * Luckily we have a magic opcode which increments the
330 		 * index variable, checks the limit falling through if
331 		 * it has been reached, else range checking the result
332 		 * updating the index variable, and returning to the top
333 		 * of the loop.
334 		 */
335 	    putline();
336 	    put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
337 	    lvalue(lhs, MOD, LREQ);
338 	    if (width(fortype) <= 2)
339 		    put(4, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) +
340 			    (width(fortype)>>1), (int)fortype->range[0],
341 			    (int)fortype->range[1], again);
342 	    else
343 		    put(4, (arg[0] == T_FORU ? O_FOR4U : O_FOR4D),
344 			    fortype->range[0], fortype->range[1], again);
345 		/*
346 		 * and here we are
347 		 */
348 	    patch( after );
349 #	endif OBJ
350 byebye:
351 	noreach = 0;
352 	if (forvar != NIL) {
353 	    forvar -> value[ NL_FORV ] = s_forv;
354 	}
355 	if ( shadowed ) {
356 	    forvar -> value[ NL_OFFS ] = s_offset;
357 	    forvar -> nl_flags = s_flags;
358 #	    ifdef PC
359 		forvar -> extra_flags = s_extra_flags;
360 #	    endif PC
361 	}
362 	if ( goc != gocnt ) {
363 	    putcnt();
364 	}
365     }
366