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