|
|
1.1 root 1: /* Copyright (c) 1979 Regents of the University of California */
2:
3: static char sccsid[] = "@(#)forop.c 1.16 2/28/83";
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: #include "tmps.h"
15:
16: /*
17: * for-statements.
18: *
19: * the relevant quote from the standard: 6.8.3.9:
20: * ``The control-variable shall be an entire-variable whose identifier
21: * is declared in the variable-declaration-part of the block closest-
22: * containing the for-statement. The control-variable shall possess
23: * an ordinal-type, and the initial-value and the final-value shall be
24: * of a type compatible with this type. The statement of a for-statement
25: * shall not contain an assigning-reference to the control-variable
26: * of the for-statement. The value of the final-value shall be
27: * assignment-compatible with the control-variable when the initial-value
28: * is assigned to the control-variable. After a for-statement is
29: * executed (other than being left by a goto-statement leading out of it)
30: * the control-variable shall be undefined. Apart from the restrictions
31: * imposed by these requirements, the for-statement
32: * for v := e1 to e2 do body
33: * shall be equivalent to
34: * begin
35: * temp1 := e1;
36: * temp2 := e2;
37: * if temp1 <= temp2 then begin
38: * v := temp1;
39: * body;
40: * while v <> temp2 do begin
41: * v := succ(v);
42: * body;
43: * end
44: * end
45: * end
46: * where temp1 and temp2 denote auxiliary variables that the program
47: * does not otherwise contain, and that possess the type possessed by
48: * the variable v if that type is not a subrange-type; otherwise the
49: * host type possessed by the variable v.''
50: *
51: * The Berkeley Pascal systems try to do all that without duplicating
52: * the body, and shadowing the control-variable in (possibly) a
53: * register variable.
54: *
55: * arg here looks like:
56: * arg[0] T_FORU or T_FORD
57: * [1] lineof "for"
58: * [2] [0] T_ASGN
59: * [1] lineof ":="
60: * [2] [0] T_VAR
61: * [1] lineof id
62: * [2] char * to id
63: * [3] qualifications
64: * [3] initial expression
65: * [3] termination expression
66: * [4] statement
67: */
68: forop( arg )
69: int *arg;
70: {
71: int *lhs;
72: struct nl *forvar;
73: struct nl *fortype;
74: #ifdef PC
75: int forp2type;
76: #endif PC
77: int forwidth;
78: int *init;
79: struct nl *inittype;
80: struct nl *initnlp; /* initial value namelist entry */
81: int *term;
82: struct nl *termtype;
83: struct nl *termnlp; /* termination value namelist entry */
84: struct nl *shadownlp; /* namelist entry for the shadow */
85: int *stat;
86: int goc; /* saved gocnt */
87: int again; /* label at the top of the loop */
88: int after; /* label after the end of the loop */
89: struct nl saved_nl; /* saved namelist entry for loop var */
90:
91: goc = gocnt;
92: forvar = NIL;
93: if ( arg == NIL ) {
94: goto byebye;
95: }
96: if ( arg[2] == NIL ) {
97: goto byebye;
98: }
99: line = arg[1];
100: putline();
101: lhs = ( (int *) arg[2] )[2];
102: init = ( (int *) arg[2] )[3];
103: term = arg[3];
104: stat = arg[4];
105: if (lhs == NIL) {
106: nogood:
107: if (forvar != NIL) {
108: forvar->value[ NL_FORV ] = FORVAR;
109: }
110: rvalue( init , NIL , RREQ );
111: rvalue( term , NIL , RREQ );
112: statement( stat );
113: goto byebye;
114: }
115: /*
116: * and this marks the variable as used!!!
117: */
118: forvar = lookup( lhs[2] );
119: if ( forvar == NIL ) {
120: goto nogood;
121: }
122: saved_nl = *forvar;
123: if ( lhs[3] != NIL ) {
124: error("For variable %s must be unqualified", forvar->symbol);
125: goto nogood;
126: }
127: if (forvar->class == WITHPTR) {
128: error("For variable %s cannot be an element of a record", lhs[2]);
129: goto nogood;
130: }
131: if ( opt('s') &&
132: ( ( bn != cbn ) ||
133: #ifdef OBJ
134: (whereis(bn, forvar->value[NL_OFFS], 0) == PARAMVAR)
135: #endif OBJ
136: #ifdef PC
137: (whereis(bn, forvar->value[NL_OFFS], forvar->extra_flags)
138: == PARAMVAR )
139: #endif PC
140: ) ) {
141: standard();
142: error("For variable %s must be declared in the block in which it is used", forvar->symbol);
143: }
144: /*
145: * find out the type of the loop variable
146: */
147: codeoff();
148: fortype = lvalue( lhs , MOD , RREQ );
149: codeon();
150: if ( fortype == NIL ) {
151: goto nogood;
152: }
153: if ( isnta( fortype , "bcis" ) ) {
154: error("For variable %s cannot be %ss", forvar->symbol, nameof( fortype ) );
155: goto nogood;
156: }
157: if ( forvar->value[ NL_FORV ] & FORVAR ) {
158: error("Can't modify the for variable %s in the range of the loop", forvar->symbol);
159: forvar = NIL;
160: goto nogood;
161: }
162: forwidth = lwidth(fortype);
163: # ifdef PC
164: forp2type = p2type(fortype);
165: # endif PC
166: /*
167: * allocate temporaries for the initial and final expressions
168: * and maybe a register to shadow the for variable.
169: */
170: initnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG);
171: termnlp = tmpalloc(sizeof(long), nl+T4INT, NOREG);
172: shadownlp = tmpalloc(forwidth, fortype, REGOK);
173: # ifdef PC
174: /*
175: * compute and save the initial expression
176: */
177: putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
178: initnlp -> extra_flags , P2INT );
179: # endif PC
180: # ifdef OBJ
181: put(2, O_LV | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
182: # endif OBJ
183: inittype = rvalue( init , fortype , RREQ );
184: if ( incompat( inittype , fortype , init ) ) {
185: cerror("Type of initial expression clashed with index type in 'for' statement");
186: if (forvar != NIL) {
187: forvar->value[ NL_FORV ] = FORVAR;
188: }
189: rvalue( term , NIL , RREQ );
190: statement( stat );
191: goto byebye;
192: }
193: # ifdef PC
194: sconv(p2type(inittype), P2INT);
195: putop( P2ASSIGN , P2INT );
196: putdot( filename , line );
197: /*
198: * compute and save the termination expression
199: */
200: putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
201: termnlp -> extra_flags , P2INT );
202: # endif PC
203: # ifdef OBJ
204: gen(O_AS2, O_AS2, sizeof(long), width(inittype));
205: /*
206: * compute and save the termination expression
207: */
208: put(2, O_LV | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
209: # endif OBJ
210: termtype = rvalue( term , fortype , RREQ );
211: if ( incompat( termtype , fortype , term ) ) {
212: cerror("Type of limit expression clashed with index type in 'for' statement");
213: if (forvar != NIL) {
214: forvar->value[ NL_FORV ] = FORVAR;
215: }
216: statement( stat );
217: goto byebye;
218: }
219: # ifdef PC
220: sconv(p2type(termtype), P2INT);
221: putop( P2ASSIGN , P2INT );
222: putdot( filename , line );
223: /*
224: * we can skip the loop altogether if !( init <= term )
225: */
226: after = getlab();
227: putRV( 0 , cbn , initnlp -> value[ NL_OFFS ] ,
228: initnlp -> extra_flags , P2INT );
229: putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
230: termnlp -> extra_flags , P2INT );
231: putop( ( arg[0] == T_FORU ? P2LE : P2GE ) , P2INT );
232: putleaf( P2ICON , after , 0 , P2INT , 0 );
233: putop( P2CBRANCH , P2INT );
234: putdot( filename , line );
235: /*
236: * okay, so we have to execute the loop body,
237: * but first, if checking is on,
238: * check that the termination expression
239: * is assignment compatible with the control-variable.
240: */
241: if (opt('t')) {
242: precheck(fortype, "_RANG4", "_RSNG4");
243: putRV(0, cbn, termnlp -> value[NL_OFFS],
244: termnlp -> extra_flags, P2INT);
245: postcheck(fortype, nl+T4INT);
246: putdot(filename, line);
247: }
248: /*
249: * assign the initial expression to the shadow
250: * checking the assignment if necessary.
251: */
252: putRV(0, cbn, shadownlp -> value[NL_OFFS],
253: shadownlp -> extra_flags, forp2type);
254: if (opt('t')) {
255: precheck(fortype, "_RANG4", "_RSNG4");
256: putRV(0, cbn, initnlp -> value[NL_OFFS],
257: initnlp -> extra_flags, P2INT);
258: postcheck(fortype, nl+T4INT);
259: } else {
260: putRV(0, cbn, initnlp -> value[NL_OFFS],
261: initnlp -> extra_flags, P2INT);
262: }
263: sconv(P2INT, forp2type);
264: putop(P2ASSIGN, forp2type);
265: putdot(filename, line);
266: /*
267: * put down the label at the top of the loop
268: */
269: again = getlab();
270: putlab( again );
271: /*
272: * each time through the loop
273: * assign the shadow to the for variable.
274: */
275: lvalue(lhs, NOUSE, RREQ);
276: putRV(0, cbn, shadownlp -> value[NL_OFFS],
277: shadownlp -> extra_flags, forp2type);
278: putop(P2ASSIGN, forp2type);
279: putdot(filename, line);
280: # endif PC
281: # ifdef OBJ
282: gen(O_AS2, O_AS2, sizeof(long), width(termtype));
283: /*
284: * we can skip the loop altogether if !( init <= term )
285: */
286: put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
287: put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
288: gen(NIL, arg[0] == T_FORU ? T_LE : T_GE, sizeof(long),
289: sizeof(long));
290: after = getlab();
291: put(2, O_IF, after);
292: /*
293: * okay, so we have to execute the loop body,
294: * but first, if checking is on,
295: * check that the termination expression
296: * is assignment compatible with the control-variable.
297: */
298: if (opt('t')) {
299: put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] );
300: put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
301: rangechk(fortype, nl+T4INT);
302: gen(O_AS2, O_AS2, forwidth, sizeof(long));
303: }
304: /*
305: * assign the initial expression to the shadow
306: * checking the assignment if necessary.
307: */
308: put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] );
309: put(2, O_RV4 | cbn<<8+INDX, initnlp -> value[ NL_OFFS ] );
310: rangechk(fortype, nl+T4INT);
311: gen(O_AS2, O_AS2, forwidth, sizeof(long));
312: /*
313: * put down the label at the top of the loop
314: */
315: again = getlab();
316: putlab( again );
317: /*
318: * each time through the loop
319: * assign the shadow to the for variable.
320: */
321: lvalue(lhs, NOUSE, RREQ);
322: stackRV(shadownlp);
323: gen(O_AS2, O_AS2, forwidth, sizeof(long));
324: # endif OBJ
325: /*
326: * shadowing the real for variable
327: * with the shadow temporary:
328: * save the real for variable flags (including nl_block).
329: * replace them with the shadow's offset,
330: * and mark the for variable as being a for variable.
331: */
332: shadownlp -> nl_flags |= NLFLAGS(forvar -> nl_flags);
333: *forvar = *shadownlp;
334: forvar -> symbol = saved_nl.symbol;
335: forvar -> nl_next = saved_nl.nl_next;
336: forvar -> type = saved_nl.type;
337: forvar -> value[ NL_FORV ] = FORVAR;
338: /*
339: * and don't forget ...
340: */
341: putcnt();
342: statement( stat );
343: /*
344: * wasn't that fun? do we get to do it again?
345: * we don't do it again if ( !( forvar < limit ) )
346: * pretend we were doing this at the top of the loop
347: */
348: line = arg[ 1 ];
349: # ifdef PC
350: if ( opt( 'p' ) ) {
351: if ( opt('t') ) {
352: putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR )
353: , "_LINO" );
354: putop( P2UNARY P2CALL , P2INT );
355: putdot( filename , line );
356: } else {
357: putRV( STMTCOUNT , 0 , 0 , NGLOBAL , P2INT );
358: putleaf( P2ICON , 1 , 0 , P2INT , 0 );
359: putop( P2ASG P2PLUS , P2INT );
360: putdot( filename , line );
361: }
362: }
363: /*rvalue( lhs , NIL , RREQ );*/
364: putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] ,
365: shadownlp -> extra_flags , forp2type );
366: sconv(forp2type, P2INT);
367: putRV( 0 , cbn , termnlp -> value[ NL_OFFS ] ,
368: termnlp -> extra_flags , P2INT );
369: putop( ( arg[ 0 ] == T_FORU ? P2LT : P2GT ) , P2INT );
370: putleaf( P2ICON , after , 0 , P2INT , 0 );
371: putop( P2CBRANCH , P2INT );
372: putdot( filename , line );
373: /*
374: * okay, so we have to do it again,
375: * but first, increment the for variable.
376: * no need to rangecheck it, since we checked the
377: * termination value before we started.
378: */
379: /*lvalue( lhs , MOD , RREQ );*/
380: putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] ,
381: shadownlp -> extra_flags , forp2type );
382: /*rvalue( lhs , NIL , RREQ );*/
383: putRV( 0 , cbn , shadownlp -> value[ NL_OFFS ] ,
384: shadownlp -> extra_flags , forp2type );
385: sconv(forp2type, P2INT);
386: putleaf( P2ICON , 1 , 0 , P2INT , 0 );
387: putop( ( arg[0] == T_FORU ? P2PLUS : P2MINUS ) , P2INT );
388: sconv(P2INT, forp2type);
389: putop( P2ASSIGN , forp2type );
390: putdot( filename , line );
391: /*
392: * and do it all again
393: */
394: putjbr( again );
395: /*
396: * and here we are
397: */
398: putlab( after );
399: # endif PC
400: # ifdef OBJ
401: /*
402: * okay, so we have to do it again.
403: * Luckily we have a magic opcode which increments the
404: * index variable, checks the limit falling through if
405: * it has been reached, else updating the index variable,
406: * and returning to the top of the loop.
407: */
408: putline();
409: put(2, O_RV4 | cbn<<8+INDX, termnlp -> value[ NL_OFFS ] );
410: put(2, O_LV | cbn<<8+INDX, shadownlp -> value[ NL_OFFS ] );
411: put(2, (arg[0] == T_FORU ? O_FOR1U : O_FOR1D) + (forwidth >> 1),
412: again);
413: /*
414: * and here we are
415: */
416: patch( after );
417: # endif OBJ
418: byebye:
419: noreach = 0;
420: if (forvar != NIL) {
421: saved_nl.nl_flags |= NLFLAGS(forvar -> nl_flags) & (NUSED|NMOD);
422: *forvar = saved_nl;
423: }
424: if ( goc != gocnt ) {
425: putcnt();
426: }
427: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.