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