Commit | Line | Data |
---|---|---|
16494185 BJ |
1 | /* Copyright (c) 1979 Regents of the University of California */ |
2 | # | |
3 | /* | |
4 | * pi - Pascal interpreter code translator | |
5 | * | |
6 | * Charles Haley, Bill Joy UCB | |
7 | * Version 1.2 January 1979 | |
8 | */ | |
9 | ||
10 | #include "0.h" | |
11 | #include "tree.h" | |
12 | ||
13 | int cntstat; | |
14 | int cnts 2; | |
15 | #include "opcode.h" | |
16 | ||
17 | /* | |
18 | * Statement list | |
19 | */ | |
20 | statlist(r) | |
21 | int *r; | |
22 | { | |
23 | register *sl; | |
24 | ||
25 | for (sl=r; sl != NIL; sl=sl[2]) | |
26 | statement(sl[1]); | |
27 | } | |
28 | ||
29 | /* | |
30 | * Statement | |
31 | */ | |
32 | statement(r) | |
33 | int *r; | |
34 | { | |
35 | register *s; | |
36 | register struct nl *snlp; | |
37 | ||
38 | s = r; | |
39 | snlp = nlp; | |
40 | top: | |
41 | if (cntstat) { | |
42 | cntstat = 0; | |
43 | putcnt(); | |
44 | } | |
45 | if (s == NIL) | |
46 | return; | |
47 | line = s[1]; | |
48 | if (s[0] == T_LABEL) { | |
49 | labeled(s[2]); | |
50 | s = s[3]; | |
51 | noreach = 0; | |
52 | cntstat = 1; | |
53 | goto top; | |
54 | } | |
55 | if (noreach) { | |
56 | noreach = 0; | |
57 | warning(); | |
58 | error("Unreachable statement"); | |
59 | } | |
60 | switch (s[0]) { | |
61 | case T_PCALL: | |
62 | putline(); | |
63 | proc(s); | |
64 | break; | |
65 | case T_ASGN: | |
66 | putline(); | |
67 | asgnop(s); | |
68 | break; | |
69 | case T_GOTO: | |
70 | putline(); | |
71 | gotoop(s[2]); | |
72 | noreach = 1; | |
73 | cntstat = 1; | |
74 | break; | |
75 | default: | |
76 | level++; | |
77 | switch (s[0]) { | |
78 | default: | |
79 | panic("stat"); | |
80 | case T_IF: | |
81 | case T_IFEL: | |
82 | ifop(s); | |
83 | break; | |
84 | case T_WHILE: | |
85 | whilop(s); | |
86 | noreach = 0; | |
87 | break; | |
88 | case T_REPEAT: | |
89 | repop(s); | |
90 | break; | |
91 | case T_FORU: | |
92 | case T_FORD: | |
93 | forop(s); | |
94 | noreach = 0; | |
95 | break; | |
96 | case T_BLOCK: | |
97 | statlist(s[2]); | |
98 | break; | |
99 | case T_CASE: | |
100 | putline(); | |
101 | caseop(s); | |
102 | break; | |
103 | case T_WITH: | |
104 | withop(s); | |
105 | break; | |
106 | case T_ASRT: | |
107 | putline(); | |
108 | asrtop(s); | |
109 | break; | |
110 | } | |
111 | --level; | |
112 | if (gotos[cbn]) | |
113 | ungoto(); | |
114 | break; | |
115 | } | |
116 | /* | |
117 | * Free the temporary name list entries defined in | |
118 | * expressions, e.g. STRs, and WITHPTRs from withs. | |
119 | */ | |
120 | nlfree(snlp); | |
121 | } | |
122 | ||
123 | ungoto() | |
124 | { | |
125 | register struct nl *p; | |
126 | ||
127 | for (p = gotos[cbn]; p != NIL; p = p->chain) | |
128 | if ((p->nl_flags & NFORWD) != 0) { | |
129 | if (p->value[NL_GOLEV] != NOTYET) | |
130 | if (p->value[NL_GOLEV] > level) | |
131 | p->value[NL_GOLEV] = level; | |
132 | } else | |
133 | if (p->value[NL_GOLEV] != DEAD) | |
134 | if (p->value[NL_GOLEV] > level) | |
135 | p->value[NL_GOLEV] = DEAD; | |
136 | } | |
137 | ||
138 | putcnt() | |
139 | { | |
140 | ||
141 | if (monflg == 0) | |
142 | return; | |
143 | cnts++; | |
144 | put2(O_COUNT, cnts); | |
145 | } | |
146 | ||
147 | putline() | |
148 | { | |
149 | ||
150 | if (opt('p') != 0) | |
151 | put2(O_LINO, line); | |
152 | } | |
153 | ||
154 | /* | |
155 | * With varlist do stat | |
156 | * | |
157 | * With statement requires an extra word | |
158 | * in automatic storage for each level of withing. | |
159 | * These indirect pointers are initialized here, and | |
160 | * the scoping effect of the with statement occurs | |
161 | * because lookup examines the field names of the records | |
162 | * associated with the WITHPTRs on the withlist. | |
163 | */ | |
164 | withop(s) | |
165 | int *s; | |
166 | { | |
167 | register *p; | |
168 | register struct nl *r; | |
169 | int i; | |
170 | int *swl; | |
171 | long soffset; | |
172 | ||
173 | putline(); | |
174 | swl = withlist; | |
175 | soffset = sizes[cbn].om_off; | |
176 | for (p = s[2]; p != NIL; p = p[2]) { | |
177 | sizes[cbn].om_off =- 2; | |
178 | put2(O_LV | cbn <<9, i = sizes[cbn].om_off); | |
179 | r = lvalue(p[1], MOD); | |
180 | if (r == NIL) | |
181 | continue; | |
182 | if (r->class != RECORD) { | |
183 | error("Variable in with statement refers to %s, not to a record", nameof(r)); | |
184 | continue; | |
185 | } | |
186 | r = defnl(0, WITHPTR, r, i); | |
187 | r->nl_next = withlist; | |
188 | withlist = r; | |
189 | put1(O_AS2); | |
190 | } | |
191 | if (sizes[cbn].om_off < sizes[cbn].om_max) | |
192 | sizes[cbn].om_max = sizes[cbn].om_off; | |
193 | statement(s[3]); | |
194 | sizes[cbn].om_off = soffset; | |
195 | withlist = swl; | |
196 | } | |
197 | ||
198 | extern flagwas; | |
199 | /* | |
200 | * var := expr | |
201 | */ | |
202 | asgnop(r) | |
203 | int *r; | |
204 | { | |
205 | register struct nl *p; | |
206 | register *av; | |
207 | ||
208 | if (r == NIL) | |
209 | return (NIL); | |
210 | /* | |
211 | * Asgnop's only function is | |
212 | * to handle function variable | |
213 | * assignments. All other assignment | |
214 | * stuff is handled by asgnop1. | |
215 | */ | |
216 | av = r[2]; | |
217 | if (av != NIL && av[0] == T_VAR && av[3] == NIL) { | |
218 | p = lookup1(av[2]); | |
219 | if (p != NIL) | |
220 | p->nl_flags = flagwas; | |
221 | if (p != NIL && p->class == FVAR) { | |
222 | /* | |
223 | * Give asgnop1 the func | |
224 | * which is the chain of | |
225 | * the FVAR. | |
226 | */ | |
227 | p->nl_flags =| NUSED|NMOD; | |
228 | p = p->chain; | |
229 | if (p == NIL) { | |
230 | rvalue(r[3], NIL); | |
231 | return; | |
232 | } | |
233 | put2(O_LV | bn << 9, p->value[NL_OFFS]); | |
234 | if (isa(p->type, "i") && width(p->type) == 1) | |
235 | asgnop1(r, nl+T2INT); | |
236 | else | |
237 | asgnop1(r, p->type); | |
238 | return; | |
239 | } | |
240 | } | |
241 | asgnop1(r, NIL); | |
242 | } | |
243 | ||
244 | /* | |
245 | * Asgnop1 handles all assignments. | |
246 | * If p is not nil then we are assigning | |
247 | * to a function variable, otherwise | |
248 | * we look the variable up ourselves. | |
249 | */ | |
250 | asgnop1(r, p) | |
251 | int *r; | |
252 | register struct nl *p; | |
253 | { | |
254 | register struct nl *p1; | |
255 | ||
256 | if (r == NIL) | |
257 | return (NIL); | |
258 | if (p == NIL) { | |
259 | p = lvalue(r[2], MOD|ASGN|NOUSE); | |
260 | if (p == NIL) { | |
261 | rvalue(r[3], NIL); | |
262 | return (NIL); | |
263 | } | |
264 | } | |
265 | p1 = rvalue(r[3], p); | |
266 | if (p1 == NIL) | |
267 | return (NIL); | |
268 | if (incompat(p1, p, r[3])) { | |
269 | cerror("Type of expression clashed with type of variable in assignment"); | |
270 | return (NIL); | |
271 | } | |
272 | switch (classify(p)) { | |
273 | case TBOOL: | |
274 | case TCHAR: | |
275 | case TINT: | |
276 | case TSCAL: | |
277 | rangechk(p, p1); | |
278 | case TDOUBLE: | |
279 | case TPTR: | |
280 | gen(O_AS2, O_AS2, width(p), width(p1)); | |
281 | break; | |
282 | default: | |
283 | put2(O_AS, width(p)); | |
284 | } | |
285 | return (p); /* Used by for statement */ | |
286 | } | |
287 | ||
288 | /* | |
289 | * for var := expr [down]to expr do stat | |
290 | */ | |
291 | forop(r) | |
292 | int *r; | |
293 | { | |
294 | register struct nl *t1, *t2; | |
295 | int l1, l2, l3; | |
296 | long soffset; | |
297 | register op; | |
298 | struct nl *p; | |
299 | int *rr, goc, i; | |
300 | #ifdef DEBUG | |
301 | int limitrv = (hp21mx ? O_RV2 : O_RV4) | cbn << 9; | |
302 | int limitsz = (hp21mx ? 2 : 4); | |
303 | #endif | |
304 | ||
305 | p = NIL; | |
306 | goc = gocnt; | |
307 | if (r == NIL) | |
308 | goto aloha; | |
309 | putline(); | |
310 | /* | |
311 | * Allocate automatic | |
312 | * space for limit variable | |
313 | */ | |
314 | #ifndef DEBUG | |
315 | sizes[cbn].om_off =- 4; | |
316 | #else | |
317 | sizes[cbn].om_off =- limitsz; | |
318 | #endif | |
319 | if (sizes[cbn].om_off < sizes[cbn].om_max) | |
320 | sizes[cbn].om_max = sizes[cbn].om_off; | |
321 | i = sizes[cbn].om_off; | |
322 | /* | |
323 | * Initialize the limit variable | |
324 | */ | |
325 | put2(O_LV | cbn<<9, i); | |
326 | t2 = rvalue(r[3], NIL); | |
327 | #ifndef DEBUG | |
328 | put1(width(t2) <= 2 ? O_AS24 : O_AS4); | |
329 | #else | |
330 | if (hp21mx) | |
331 | put1(O_AS2); | |
332 | else | |
333 | put1(width(t2) <= 2 ? O_AS24 : O_AS4); | |
334 | #endif | |
335 | /* | |
336 | * Assignment of initial value to for variable | |
337 | */ | |
338 | t1 = asgnop1(r[2], NIL); | |
339 | if (t1 == NIL) { | |
340 | rvalue(r[3], NIL); | |
341 | statement(r[4]); | |
342 | goto aloha; | |
343 | } | |
344 | rr = r[2]; /* Assignment */ | |
345 | rr = rr[2]; /* Lhs variable */ | |
346 | if (rr[3] != NIL) { | |
347 | error("For variable must be unqualified"); | |
348 | rvalue(r[3], NIL); | |
349 | statement(r[4]); | |
350 | goto aloha; | |
351 | } | |
352 | p = lookup(rr[2]); | |
353 | p->value[NL_FORV] = 1; | |
354 | if (isnta(t1, "bcis")) { | |
355 | error("For variables cannot be %ss", nameof(t1)); | |
356 | statement(r[4]); | |
357 | goto aloha; | |
358 | } | |
359 | if (incompat(t2, t1, r[3])) { | |
360 | cerror("Limit type clashed with index type in 'for' statement"); | |
361 | statement(r[4]); | |
362 | goto aloha; | |
363 | } | |
364 | /* | |
365 | * See if we can skip the loop altogether | |
366 | */ | |
367 | rr = r[2]; | |
368 | if (rr != NIL) | |
369 | rvalue(rr[2], NIL); | |
370 | #ifndef DEBUG | |
371 | put2(O_RV4 | cbn<<9, i); | |
372 | gen(NIL, r[0] == T_FORU ? T_LE : T_GE, width(t1), 4); | |
373 | #else | |
374 | put1(limitrv, i); | |
375 | gen(NIL, r[0] == T_FORU ? T_LE : T_GE, width(t1), limitsz); | |
376 | #endif | |
377 | /* | |
378 | * L1 will be patched to skip the body of the loop. | |
379 | * L2 marks the top of the loop when we go around. | |
380 | */ | |
381 | put2(O_IF, (l1 = getlab())); | |
382 | putlab(l2 = getlab()); | |
383 | putcnt(); | |
384 | statement(r[4]); | |
385 | /* | |
386 | * now we see if we get to go again | |
387 | */ | |
388 | if (opt('t') == 0) { | |
389 | /* | |
390 | * Easy if we dont have to test | |
391 | */ | |
392 | #ifndef DEBUG | |
393 | put2(O_RV4 | cbn<<9, i); | |
394 | #else | |
395 | put2(limitrv, i); | |
396 | #endif | |
397 | if (rr != NIL) | |
398 | lvalue(rr[2], MOD); | |
399 | put2((r[0] == T_FORU ? O_FOR1U : O_FOR1D) + (width(t1) >> 1), l2); | |
400 | } else { | |
401 | line = r[1]; | |
402 | putline(); | |
403 | if (rr != NIL) | |
404 | rvalue(rr[2], NIL); | |
405 | #ifndef DEBUG | |
406 | put2(O_RV4 | cbn << 9, i); | |
407 | gen(NIL, (r[0] == T_FORU ? T_LT : T_GT), width(t1), 4); | |
408 | #else | |
409 | put2(limitrv, i); | |
410 | gen(NIL, (r[0] == T_FORU ? T_LT : T_GT), width(t1), limitsz); | |
411 | #endif | |
412 | l3 = put2(O_IF, getlab()); | |
413 | lvalue(rr[2], MOD); | |
414 | rvalue(rr[2], NIL); | |
415 | put2(O_CON2, 1); | |
416 | t2 = gen(NIL, r[0] == T_FORU ? T_ADD: T_SUB, width(t1), 2); | |
417 | rangechk(t1, t2); /* The point of all this */ | |
418 | gen(O_AS2, O_AS2, width(t1), width(t2)); | |
419 | put2(O_TRA, l2); | |
420 | patch(l3); | |
421 | } | |
422 | #ifdef DEBUG | |
423 | sizes[cbn].om_off =+ limitsz; | |
424 | #else | |
425 | sizes[cbn].om_off =+ 4; | |
426 | #endif | |
427 | patch(l1); | |
428 | aloha: | |
429 | noreach = 0; | |
430 | if (p != NIL) | |
431 | p->value[NL_FORV] = 0; | |
432 | if (goc != gocnt) | |
433 | putcnt(); | |
434 | } | |
435 | ||
436 | /* | |
437 | * if expr then stat [ else stat ] | |
438 | */ | |
439 | ifop(r) | |
440 | int *r; | |
441 | { | |
442 | register struct nl *p; | |
443 | register l1, l2; | |
444 | int nr, goc; | |
445 | ||
446 | goc = gocnt; | |
447 | if (r == NIL) | |
448 | return; | |
449 | putline(); | |
450 | p = rvalue(r[2], NIL); | |
451 | if (p == NIL) { | |
452 | statement(r[3]); | |
453 | noreach = 0; | |
454 | statement(r[4]); | |
455 | noreach = 0; | |
456 | return; | |
457 | } | |
458 | if (isnta(p, "b")) { | |
459 | error("Type of expression in if statement must be Boolean, not %s", nameof(p)); | |
460 | statement(r[3]); | |
461 | noreach = 0; | |
462 | statement(r[4]); | |
463 | noreach = 0; | |
464 | return; | |
465 | } | |
466 | l1 = put2(O_IF, getlab()); | |
467 | putcnt(); | |
468 | statement(r[3]); | |
469 | nr = noreach; | |
470 | if (r[4] != NIL) { | |
471 | /* | |
472 | * else stat | |
473 | */ | |
474 | --level; | |
475 | ungoto(); | |
476 | ++level; | |
477 | l2 = put2(O_TRA, getlab()); | |
478 | patch(l1); | |
479 | noreach = 0; | |
480 | statement(r[4]); | |
481 | noreach =& nr; | |
482 | l1 = l2; | |
483 | } else | |
484 | noreach = 0; | |
485 | patch(l1); | |
486 | if (goc != gocnt) | |
487 | putcnt(); | |
488 | } | |
489 | ||
490 | /* | |
491 | * while expr do stat | |
492 | */ | |
493 | whilop(r) | |
494 | int *r; | |
495 | { | |
496 | register struct nl *p; | |
497 | register l1, l2; | |
498 | int goc; | |
499 | ||
500 | goc = gocnt; | |
501 | if (r == NIL) | |
502 | return; | |
503 | putlab(l1 = getlab()); | |
504 | putline(); | |
505 | p = rvalue(r[2], NIL); | |
506 | if (p == NIL) { | |
507 | statement(r[3]); | |
508 | noreach = 0; | |
509 | return; | |
510 | } | |
511 | if (isnta(p, "b")) { | |
512 | error("Type of expression in while statement must be Boolean, not %s", nameof(p)); | |
513 | statement(r[3]); | |
514 | noreach = 0; | |
515 | return; | |
516 | } | |
517 | put2(O_IF, (l2 = getlab())); | |
518 | putcnt(); | |
519 | statement(r[3]); | |
520 | put2(O_TRA, l1); | |
521 | patch(l2); | |
522 | if (goc != gocnt) | |
523 | putcnt(); | |
524 | } | |
525 | ||
526 | /* | |
527 | * repeat stat* until expr | |
528 | */ | |
529 | repop(r) | |
530 | int *r; | |
531 | { | |
532 | register struct nl *p; | |
533 | register l; | |
534 | int goc; | |
535 | ||
536 | goc = gocnt; | |
537 | if (r == NIL) | |
538 | return; | |
539 | l = putlab(getlab()); | |
540 | putcnt(); | |
541 | statlist(r[2]); | |
542 | line = r[1]; | |
543 | p = rvalue(r[3], NIL); | |
544 | if (p == NIL) | |
545 | return; | |
546 | if (isnta(p,"b")) { | |
547 | error("Until expression type must be Boolean, not %s, in repeat statement", nameof(p)); | |
548 | return; | |
549 | } | |
550 | put2(O_IF, l); | |
551 | if (goc != gocnt) | |
552 | putcnt(); | |
553 | } | |
554 | ||
555 | /* | |
556 | * assert expr | |
557 | */ | |
558 | asrtop(r) | |
559 | register int *r; | |
560 | { | |
561 | register struct nl *q; | |
562 | ||
563 | if (opt('s')) { | |
564 | standard(); | |
565 | error("Assert statement is non-standard"); | |
566 | } | |
567 | if (!opt('t')) | |
568 | return; | |
569 | r = r[2]; | |
570 | q = rvalue(r, NIL); | |
571 | if (q == NIL) | |
572 | return; | |
573 | if (isnta(q, "b")) | |
574 | error("Assert expression must be Boolean, not %ss", nameof(q)); | |
575 | put1(O_ASRT); | |
576 | } |