Commit | Line | Data |
---|---|---|
a0ce3a0c 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 | #include "opcode.h" | |
13 | ||
14 | extern char *opnames[]; | |
15 | /* | |
16 | * Rvalue - an expression. | |
17 | * | |
18 | * Contype is the type that the caller would prefer, nand is important | |
19 | * if constant sets or constant strings are involved, the latter | |
20 | * because of string padding. | |
21 | */ | |
22 | rvalue(r, contype) | |
23 | int *r; | |
24 | struct nl *contype; | |
25 | { | |
26 | register struct nl *p, *p1; | |
27 | register struct nl *q; | |
28 | int c, c1, *rt, w, g; | |
29 | char *cp, *cp1, *opname; | |
30 | long l; | |
31 | double f; | |
32 | ||
33 | if (r == NIL) | |
34 | return (NIL); | |
35 | if (nowexp(r)) | |
36 | return (NIL); | |
37 | /* | |
38 | * Pick up the name of the operation | |
39 | * for future error messages. | |
40 | */ | |
41 | if (r[0] <= T_IN) | |
42 | opname = opnames[r[0]]; | |
43 | ||
44 | /* | |
45 | * The root of the tree tells us what sort of expression we have. | |
46 | */ | |
47 | switch (r[0]) { | |
48 | ||
49 | /* | |
50 | * The constant nil | |
51 | */ | |
52 | case T_NIL: | |
53 | put2(O_CON2, 0); | |
54 | return (nl+TNIL); | |
55 | ||
56 | /* | |
57 | * Function call with arguments. | |
58 | */ | |
59 | case T_FCALL: | |
60 | return (funccod(r)); | |
61 | ||
62 | case T_VAR: | |
63 | p = lookup(r[2]); | |
64 | if (p == NIL || p->class == BADUSE) | |
65 | return (NIL); | |
66 | switch (p->class) { | |
67 | case VAR: | |
68 | /* | |
69 | * If a variable is | |
70 | * qualified then get | |
71 | * the rvalue by a | |
72 | * lvalue and an ind. | |
73 | */ | |
74 | if (r[3] != NIL) | |
75 | goto ind; | |
76 | q = p->type; | |
77 | if (q == NIL) | |
78 | return (NIL); | |
79 | w = width(q); | |
80 | switch (w) { | |
81 | case 8: | |
82 | w = 6; | |
83 | case 4: | |
84 | case 2: | |
85 | case 1: | |
86 | put2(O_RV1 + (w >> 1) | bn << 9, p->value[0]); | |
87 | break; | |
88 | default: | |
89 | put3(O_RV | bn << 9, p->value[0], w); | |
90 | } | |
91 | return (q); | |
92 | ||
93 | case WITHPTR: | |
94 | case REF: | |
95 | /* | |
96 | * A lvalue for these | |
97 | * is actually what one | |
98 | * might consider a rvalue. | |
99 | */ | |
100 | ind: | |
101 | q = lvalue(r, NOMOD); | |
102 | if (q == NIL) | |
103 | return (NIL); | |
104 | w = width(q); | |
105 | switch (w) { | |
106 | case 8: | |
107 | w = 6; | |
108 | case 4: | |
109 | case 2: | |
110 | case 1: | |
111 | put1(O_IND1 + (w >> 1)); | |
112 | break; | |
113 | default: | |
114 | put2(O_IND, w); | |
115 | } | |
116 | return (q); | |
117 | ||
118 | case CONST: | |
119 | if (r[3] != NIL) { | |
120 | error("%s is a constant and cannot be qualified", r[2]); | |
121 | return (NIL); | |
122 | } | |
123 | q = p->type; | |
124 | if (q == NIL) | |
125 | return (NIL); | |
126 | if (q == nl+TSTR) { | |
127 | /* | |
128 | * Find the size of the string | |
129 | * constant if needed. | |
130 | */ | |
131 | cp = p->value[0]; | |
132 | cstrng: | |
133 | cp1 = cp; | |
134 | for (c = 0; *cp++; c++) | |
135 | continue; | |
136 | if (contype != NIL && !opt('s')) { | |
137 | if (width(contype) < c && classify(contype) == TSTR) { | |
138 | error("Constant string too long"); | |
139 | return (NIL); | |
140 | } | |
141 | c = width(contype); | |
142 | } | |
143 | put3(O_CONG, c, cp1); | |
144 | /* | |
145 | * Define the string temporarily | |
146 | * so later people can know its | |
147 | * width. | |
148 | * cleaned out by stat. | |
149 | */ | |
150 | q = defnl(0, STR, 0, c); | |
151 | q->type = q; | |
152 | return (q); | |
153 | } | |
154 | if (q == nl+T1CHAR) { | |
155 | put2(O_CONC, p->value[0]); | |
156 | return (q); | |
157 | } | |
158 | /* | |
159 | * Every other kind of constant here | |
160 | */ | |
161 | switch (width(q)) { | |
162 | case 8: | |
163 | #ifndef DEBUG | |
164 | put(5, O_CON8, p->real); | |
165 | #else | |
166 | if (hp21mx) { | |
167 | f = p->real; | |
168 | conv(&f); | |
169 | l = f.plong; | |
170 | put3(O_CON4, l); | |
171 | } else | |
172 | put(5, O_CON8, p->real); | |
173 | #endif | |
174 | break; | |
175 | case 4: | |
176 | put3(O_CON4, p->range[0]); | |
177 | break; | |
178 | case 2: | |
179 | put2(O_CON2, p->value[1]); | |
180 | break; | |
181 | case 1: | |
182 | put2(O_CON1, p->value[0]); | |
183 | break; | |
184 | default: | |
185 | panic("rval"); | |
186 | } | |
187 | return (q); | |
188 | ||
189 | case FUNC: | |
190 | /* | |
191 | * Function call with no arguments. | |
192 | */ | |
193 | if (r[3]) { | |
194 | error("Can't qualify a function result value"); | |
195 | return (NIL); | |
196 | } | |
197 | return (funccod(r)); | |
198 | ||
199 | case TYPE: | |
200 | error("Type names (e.g. %s) allowed only in declarations", p->symbol); | |
201 | return (NIL); | |
202 | ||
203 | case PROC: | |
204 | error("Procedure %s found where expression required", p->symbol); | |
205 | return (NIL); | |
206 | default: | |
207 | panic("rvid"); | |
208 | } | |
209 | /* | |
210 | * Constant sets | |
211 | */ | |
212 | case T_CSET: | |
213 | return (cset(r, contype, NIL)); | |
214 | ||
215 | /* | |
216 | * Unary plus and minus | |
217 | */ | |
218 | case T_PLUS: | |
219 | case T_MINUS: | |
220 | q = rvalue(r[2], NIL); | |
221 | if (q == NIL) | |
222 | return (NIL); | |
223 | if (isnta(q, "id")) { | |
224 | error("Operand of %s must be integer or real, not %s", opname, nameof(q)); | |
225 | return (NIL); | |
226 | } | |
227 | if (r[0] == T_MINUS) { | |
228 | put1(O_NEG2 + (width(q) >> 2)); | |
229 | return (isa(q, "d") ? q : nl+T4INT); | |
230 | } | |
231 | return (q); | |
232 | ||
233 | case T_NOT: | |
234 | q = rvalue(r[2], NIL); | |
235 | if (q == NIL) | |
236 | return (NIL); | |
237 | if (isnta(q, "b")) { | |
238 | error("not must operate on a Boolean, not %s", nameof(q)); | |
239 | return (NIL); | |
240 | } | |
241 | put1(O_NOT); | |
242 | return (nl+T1BOOL); | |
243 | ||
244 | case T_AND: | |
245 | case T_OR: | |
246 | p = rvalue(r[2], NIL); | |
247 | p1 = rvalue(r[3], NIL); | |
248 | if (p == NIL || p1 == NIL) | |
249 | return (NIL); | |
250 | if (isnta(p, "b")) { | |
251 | error("Left operand of %s must be Boolean, not %s", opname, nameof(p)); | |
252 | return (NIL); | |
253 | } | |
254 | if (isnta(p1, "b")) { | |
255 | error("Right operand of %s must be Boolean, not %s", opname, nameof(p1)); | |
256 | return (NIL); | |
257 | } | |
258 | put1(r[0] == T_AND ? O_AND : O_OR); | |
259 | return (nl+T1BOOL); | |
260 | ||
261 | case T_DIVD: | |
262 | p = rvalue(r[2], NIL); | |
263 | p1 = rvalue(r[3], NIL); | |
264 | if (p == NIL || p1 == NIL) | |
265 | return (NIL); | |
266 | if (isnta(p, "id")) { | |
267 | error("Left operand of / must be integer or real, not %s", nameof(p)); | |
268 | return (NIL); | |
269 | } | |
270 | if (isnta(p1, "id")) { | |
271 | error("Right operand of / must be integer or real, not %s", nameof(p1)); | |
272 | return (NIL); | |
273 | } | |
274 | return (gen(NIL, r[0], width(p), width(p1))); | |
275 | ||
276 | case T_MULT: | |
277 | case T_SUB: | |
278 | case T_ADD: | |
279 | /* | |
280 | * If the context hasn't told us | |
281 | * the type and a constant set is | |
282 | * present on the left we need to infer | |
283 | * the type from the right if possible | |
284 | * before generating left side code. | |
285 | */ | |
286 | if (contype == NIL && (rt = r[2]) != NIL && rt[1] == SAWCON) { | |
287 | codeoff(); | |
288 | contype = rvalue(r[3], NIL); | |
289 | codeon(); | |
290 | if (contype == NIL) | |
291 | return (NIL); | |
292 | } | |
293 | p = rvalue(r[2], contype); | |
294 | p1 = rvalue(r[3], p); | |
295 | if (p == NIL || p1 == NIL) | |
296 | return (NIL); | |
297 | if (isa(p, "id") && isa(p1, "id")) | |
298 | return (gen(NIL, r[0], width(p), width(p1))); | |
299 | if (isa(p, "t") && isa(p1, "t")) { | |
300 | if (p != p1) { | |
301 | error("Set types of operands of %s must be identical", opname); | |
302 | return (NIL); | |
303 | } | |
304 | gen(TSET, r[0], width(p), 0); | |
305 | /* | |
306 | * Note that set was filled in by the call | |
307 | * to width above. | |
308 | */ | |
309 | if (r[0] == T_SUB) | |
310 | put2(NIL, 0177777 << ((set.uprbp & 017) + 1)); | |
311 | return (p); | |
312 | } | |
313 | if (isnta(p, "idt")) { | |
314 | error("Left operand of %s must be integer, real or set, not %s", opname, nameof(p)); | |
315 | return (NIL); | |
316 | } | |
317 | if (isnta(p1, "idt")) { | |
318 | error("Right operand of %s must be integer, real or set, not %s", opname, nameof(p1)); | |
319 | return (NIL); | |
320 | } | |
321 | error("Cannot mix sets with integers and reals as operands of %s", opname); | |
322 | return (NIL); | |
323 | ||
324 | case T_MOD: | |
325 | case T_DIV: | |
326 | p = rvalue(r[2], NIL); | |
327 | p1 = rvalue(r[3], NIL); | |
328 | if (p == NIL || p1 == NIL) | |
329 | return (NIL); | |
330 | if (isnta(p, "i")) { | |
331 | error("Left operand of %s must be integer, not %s", opname, nameof(p)); | |
332 | return (NIL); | |
333 | } | |
334 | if (isnta(p1, "i")) { | |
335 | error("Right operand of %s must be integer, not %s", opname, nameof(p1)); | |
336 | return (NIL); | |
337 | } | |
338 | return (gen(NIL, r[0], width(p), width(p1))); | |
339 | ||
340 | case T_EQ: | |
341 | case T_NE: | |
342 | case T_GE: | |
343 | case T_LE: | |
344 | case T_GT: | |
345 | case T_LT: | |
346 | /* | |
347 | * Since there can be no, a priori, knowledge | |
348 | * of the context type should a constant string | |
349 | * or set arise, we must poke around to find such | |
350 | * a type if possible. Since constant strings can | |
351 | * always masquerade as identifiers, this is always | |
352 | * necessary. | |
353 | */ | |
354 | codeoff(); | |
355 | p1 = rvalue(r[3], NIL); | |
356 | codeon(); | |
357 | if (p1 == NIL) | |
358 | return (NIL); | |
359 | contype = p1; | |
360 | if (p1 == nl+TSET || p1->class == STR) { | |
361 | /* | |
362 | * For constant strings we want | |
363 | * the longest type so as to be | |
364 | * able to do padding (more importantly | |
365 | * avoiding truncation). For clarity, | |
366 | * we get this length here. | |
367 | */ | |
368 | codeoff(); | |
369 | p = rvalue(r[2], NIL); | |
370 | codeon(); | |
371 | if (p == NIL) | |
372 | return (NIL); | |
373 | if (p1 == nl+TSET || width(p) > width(p1)) | |
374 | contype = p; | |
375 | } | |
376 | /* | |
377 | * Now we generate code for | |
378 | * the operands of the relational | |
379 | * operation. | |
380 | */ | |
381 | p = rvalue(r[2], contype); | |
382 | if (p == NIL) | |
383 | return (NIL); | |
384 | p1 = rvalue(r[3], p); | |
385 | if (p1 == NIL) | |
386 | return (NIL); | |
387 | c = classify(p); | |
388 | c1 = classify(p1); | |
389 | if (nocomp(c) || nocomp(c1)) | |
390 | return (NIL); | |
391 | g = NIL; | |
392 | switch (c) { | |
393 | case TBOOL: | |
394 | case TCHAR: | |
395 | if (c != c1) | |
396 | goto clash; | |
397 | break; | |
398 | case TINT: | |
399 | case TDOUBLE: | |
400 | if (c1 != TINT && c1 != TDOUBLE) | |
401 | goto clash; | |
402 | break; | |
403 | case TSCAL: | |
404 | if (c1 != TSCAL) | |
405 | goto clash; | |
406 | if (scalar(p) != scalar(p1)) | |
407 | goto nonident; | |
408 | break; | |
409 | case TSET: | |
410 | if (c1 != TSET) | |
411 | goto clash; | |
412 | if (p != p1) | |
413 | goto nonident; | |
414 | g = TSET; | |
415 | break; | |
416 | case TPTR: | |
417 | case TNIL: | |
418 | if (c1 != TPTR && c1 != TNIL) | |
419 | goto clash; | |
420 | if (r[0] != T_EQ && r[0] != T_NE) { | |
421 | error("%s not allowed on pointers - only allow = and <>"); | |
422 | return (NIL); | |
423 | } | |
424 | break; | |
425 | case TSTR: | |
426 | if (c1 != TSTR) | |
427 | goto clash; | |
428 | if (width(p) != width(p1)) { | |
429 | error("Strings not same length in %s comparison", opname); | |
430 | return (NIL); | |
431 | } | |
432 | g = TSTR; | |
433 | break; | |
434 | default: | |
435 | panic("rval2"); | |
436 | } | |
437 | return (gen(g, r[0], width(p), width(p1))); | |
438 | clash: | |
439 | error("%ss and %ss cannot be compared - operator was %s", clnames[c], clnames[c1], opname); | |
440 | return (NIL); | |
441 | nonident: | |
442 | error("%s types must be identical in comparisons - operator was %s", clnames[c1], opname); | |
443 | return (NIL); | |
444 | ||
445 | case T_IN: | |
446 | rt = r[3]; | |
447 | if (rt != NIL && rt[0] == T_CSET) | |
448 | p1 = cset(rt, NIL, 1); | |
449 | else { | |
450 | p1 = rvalue(r[3], NIL); | |
451 | rt = NIL; | |
452 | } | |
453 | if (p1 == nl+TSET) { | |
454 | warning(); | |
455 | error("... in [] makes little sense, since it is always false!"); | |
456 | put1(O_CON1, 0); | |
457 | return (nl+T1BOOL); | |
458 | } | |
459 | p = rvalue(r[2], NIL); | |
460 | if (p == NIL || p1 == NIL) | |
461 | return (NIL); | |
462 | if (p1->class != SET) { | |
463 | error("Right operand of 'in' must be a set, not %s", nameof(p1)); | |
464 | return (NIL); | |
465 | } | |
466 | if (incompat(p, p1->type, r[2])) { | |
467 | cerror("Index type clashed with set component type for 'in'"); | |
468 | return (NIL); | |
469 | } | |
470 | convert(p, nl+T2INT); | |
471 | setran(p1->type); | |
472 | if (rt == NIL) | |
473 | put4(O_IN, width(p1), set.lwrb, set.uprbp); | |
474 | else | |
475 | put1(O_INCT); | |
476 | return (nl+T1BOOL); | |
477 | ||
478 | default: | |
479 | if (r[2] == NIL) | |
480 | return (NIL); | |
481 | switch (r[0]) { | |
482 | default: | |
483 | panic("rval3"); | |
484 | ||
485 | ||
486 | /* | |
487 | * An octal number | |
488 | */ | |
489 | case T_BINT: | |
490 | f = a8tol(r[2]); | |
491 | goto conint; | |
492 | ||
493 | /* | |
494 | * A decimal number | |
495 | */ | |
496 | case T_INT: | |
497 | f = atof(r[2]); | |
498 | conint: | |
499 | if (f > MAXINT || f < MININT) { | |
500 | error("Constant too large for this implementation"); | |
501 | return (NIL); | |
502 | } | |
503 | l = f; | |
504 | if (bytes(l, l) <= 2) { | |
505 | put2(O_CON2, c=l); | |
506 | return (nl+T2INT); | |
507 | } | |
508 | put3(O_CON4, l); | |
509 | return (nl+T4INT); | |
510 | ||
511 | /* | |
512 | * A floating point number | |
513 | */ | |
514 | case T_FINT: | |
515 | put(5, O_CON8, atof(r[2])); | |
516 | return (nl+TDOUBLE); | |
517 | ||
518 | /* | |
519 | * Constant strings. Note that constant characters | |
520 | * are constant strings of length one; there is | |
521 | * no constant string of length one. | |
522 | */ | |
523 | case T_STRNG: | |
524 | cp = r[2]; | |
525 | if (cp[1] == 0) { | |
526 | put2(O_CONC, cp[0]); | |
527 | return (nl+T1CHAR); | |
528 | } | |
529 | goto cstrng; | |
530 | } | |
531 | ||
532 | } | |
533 | } | |
534 | ||
535 | /* | |
536 | * Can a class appear | |
537 | * in a comparison ? | |
538 | */ | |
539 | nocomp(c) | |
540 | int c; | |
541 | { | |
542 | ||
543 | switch (c) { | |
544 | case TFILE: | |
545 | case TARY: | |
546 | case TREC: | |
547 | error("%ss may not participate in comparisons", clnames[c]); | |
548 | return (1); | |
549 | } | |
550 | return (NIL); | |
551 | } |