Commit | Line | Data |
---|---|---|
438ea14e ML |
1 | /* Copyright (c) 1982 Regents of the University of California */ |
2 | ||
550fe947 | 3 | static char sccsid[] = "@(#)c.c 1.2 %G%"; |
438ea14e ML |
4 | |
5 | /* | |
6 | * C-dependent symbol routines. | |
7 | */ | |
8 | ||
9 | #include "defs.h" | |
10 | #include "symbols.h" | |
11 | #include "printsym.h" | |
12 | #include "languages.h" | |
13 | #include "c.h" | |
14 | #include "tree.h" | |
15 | #include "eval.h" | |
16 | #include "operators.h" | |
17 | #include "mappings.h" | |
18 | #include "process.h" | |
19 | #include "runtime.h" | |
20 | #include "machine.h" | |
21 | ||
22 | #define isdouble(range) ( \ | |
23 | range->symvalue.rangev.upper == 0 and range->symvalue.rangev.lower > 0 \ | |
24 | ) | |
25 | ||
26 | #define isrange(t, name) (t->class == RANGE and istypename(t->type, name)) | |
27 | ||
28 | /* | |
29 | * Initialize C language information. | |
30 | */ | |
31 | ||
32 | public c_init() | |
33 | { | |
34 | Language lang; | |
35 | ||
36 | lang = language_define("c", ".c"); | |
37 | language_setop(lang, L_PRINTDECL, c_printdecl); | |
38 | language_setop(lang, L_PRINTVAL, c_printval); | |
39 | language_setop(lang, L_TYPEMATCH, c_typematch); | |
40 | } | |
41 | ||
42 | /* | |
43 | * Test if two types are compatible. | |
44 | * | |
45 | * Integers and reals are not compatible since they cannot always be mixed. | |
46 | */ | |
47 | ||
48 | public Boolean c_typematch(type1, type2) | |
49 | Symbol type1, type2; | |
50 | { | |
51 | Boolean b; | |
52 | register Symbol t1, t2, tmp; | |
53 | ||
54 | t1 = type1; | |
55 | t2 = type2; | |
56 | if (t1 == t2) { | |
57 | b = true; | |
58 | } else { | |
59 | t1 = rtype(t1); | |
60 | t2 = rtype(t2); | |
61 | if (t1->type == t_int or t1->type == t_char) { | |
62 | tmp = t1; | |
63 | t1 = t2; | |
64 | t2 = tmp; | |
65 | } | |
66 | b = (Boolean) ( | |
67 | ( | |
68 | isrange(t1, "int") and | |
69 | (t2->type == t_int or t2->type == t_char) | |
70 | ) or ( | |
71 | isrange(t1, "char") and | |
72 | (t2->type == t_char or t2->type == t_int) | |
73 | ) or ( | |
74 | t1->type == t2->type and ( | |
75 | (t1->class == t2->class) or | |
76 | (t1->class == SCAL and t2->class == CONST) or | |
77 | (t1->class == CONST and t2->class == SCAL) | |
78 | ) | |
79 | ) | |
80 | ); | |
81 | } | |
82 | return b; | |
83 | } | |
84 | ||
85 | /* | |
86 | * Decide if a field is a bit field. | |
87 | */ | |
88 | ||
89 | private Boolean isbitfield(s) | |
90 | register Symbol s; | |
91 | { | |
92 | Boolean b; | |
93 | register Integer off, len; | |
94 | register Symbol t; | |
95 | ||
96 | off = s->symvalue.field.offset; | |
97 | len = s->symvalue.field.length; | |
98 | if ((off mod BITSPERBYTE) != 0 or (len mod BITSPERBYTE) != 0) { | |
99 | b = true; | |
100 | } else { | |
101 | t = rtype(s->type); | |
102 | b = (Boolean) | |
103 | (t->class == SCAL and len != (sizeof(int)*BITSPERBYTE) or | |
104 | len != (size(t)*BITSPERBYTE) | |
105 | ); | |
106 | } | |
107 | return b; | |
108 | } | |
109 | ||
110 | /* | |
111 | * Print out the declaration of a C variable. | |
112 | */ | |
113 | ||
114 | public c_printdecl(s) | |
115 | Symbol s; | |
116 | { | |
117 | printdecl(s, 0); | |
118 | } | |
119 | ||
120 | private printdecl(s, indent) | |
121 | register Symbol s; | |
122 | Integer indent; | |
123 | { | |
124 | register Symbol t; | |
125 | Boolean semicolon, newline; | |
126 | ||
127 | semicolon = true; | |
128 | newline = true; | |
129 | if (indent > 0) { | |
130 | printf("%*c", indent, ' '); | |
131 | } | |
132 | if (s->class == TYPE) { | |
133 | printf("typedef "); | |
134 | } | |
135 | switch (s->class) { | |
136 | case CONST: | |
137 | if (s->type->class == SCAL) { | |
138 | printf("(enumeration constant, ord %ld)", | |
139 | s->symvalue.iconval); | |
140 | } else { | |
141 | printf("const %s = ", symname(s)); | |
142 | printval(s); | |
143 | } | |
144 | break; | |
145 | ||
146 | case TYPE: | |
147 | case VAR: | |
148 | if (s->class != TYPE) { | |
149 | if (s->level == 2) { | |
150 | printf("static "); | |
151 | } else if (s->level < 0) { | |
152 | printf("register "); | |
153 | } | |
154 | } | |
155 | if (s->type->class == ARRAY) { | |
156 | printtype(s->type, s->type->type, indent); | |
157 | t = rtype(s->type->chain); | |
158 | assert(t->class == RANGE); | |
159 | printf(" %s[%d]", symname(s), t->symvalue.rangev.upper + 1); | |
160 | } else { | |
161 | printtype(s, s->type, indent); | |
162 | if (s->type->class != PTR) { | |
163 | printf(" "); | |
164 | } | |
165 | printf("%s", symname(s)); | |
166 | } | |
167 | break; | |
168 | ||
169 | case FIELD: | |
170 | if (s->type->class == ARRAY) { | |
171 | printtype(s->type, s->type->type, indent); | |
172 | t = rtype(s->type->chain); | |
173 | assert(t->class == RANGE); | |
174 | printf(" %s[%d]", symname(s), t->symvalue.rangev.upper + 1); | |
175 | } else { | |
176 | printtype(s, s->type, indent); | |
177 | if (s->type->class != PTR) { | |
178 | printf(" "); | |
179 | } | |
180 | printf("%s", symname(s)); | |
181 | } | |
182 | if (isbitfield(s)) { | |
183 | printf(" : %d", s->symvalue.field.length); | |
184 | } | |
185 | break; | |
186 | ||
187 | case TAG: | |
188 | if (s->type == nil) { | |
189 | findtype(s); | |
190 | if (s->type == nil) { | |
191 | error("unexpected missing type information"); | |
192 | } | |
193 | } | |
194 | printtype(s, s->type, indent); | |
195 | break; | |
196 | ||
197 | case RANGE: | |
198 | case ARRAY: | |
199 | case RECORD: | |
200 | case VARNT: | |
201 | case PTR: | |
202 | semicolon = false; | |
203 | printtype(s, s, indent); | |
204 | break; | |
205 | ||
206 | case PROC: | |
207 | semicolon = false; | |
208 | printf("%s", symname(s)); | |
209 | c_listparams(s); | |
210 | newline = false; | |
211 | break; | |
212 | ||
213 | case FUNC: | |
214 | semicolon = false; | |
215 | if (not istypename(s->type, "void")) { | |
216 | printtype(s, s->type, indent); | |
217 | printf(" "); | |
218 | } | |
219 | printf("%s", symname(s)); | |
220 | c_listparams(s); | |
221 | newline = false; | |
222 | break; | |
223 | ||
224 | case MODULE: | |
225 | semicolon = false; | |
226 | printf("source file \"%s.c\"", symname(s)); | |
227 | break; | |
228 | ||
229 | case PROG: | |
230 | semicolon = false; | |
231 | printf("executable file \"%s\"", symname(s)); | |
232 | break; | |
233 | ||
234 | default: | |
235 | error("class %s in c_printdecl", classname(s)); | |
236 | } | |
237 | if (semicolon) { | |
238 | putchar(';'); | |
239 | } | |
240 | if (newline) { | |
241 | putchar('\n'); | |
242 | } | |
243 | } | |
244 | ||
245 | /* | |
246 | * Recursive whiz-bang procedure to print the type portion | |
247 | * of a declaration. | |
248 | * | |
249 | * The symbol associated with the type is passed to allow | |
250 | * searching for type names without getting "type blah = blah". | |
251 | */ | |
252 | ||
253 | private printtype(s, t, indent) | |
254 | Symbol s; | |
255 | Symbol t; | |
256 | Integer indent; | |
257 | { | |
258 | register Symbol i; | |
259 | long r0, r1; | |
260 | register String p; | |
261 | ||
262 | checkref(s); | |
263 | checkref(t); | |
264 | switch (t->class) { | |
265 | case VAR: | |
266 | case CONST: | |
267 | case PROC: | |
268 | panic("printtype: class %s", classname(t)); | |
269 | break; | |
270 | ||
271 | case ARRAY: | |
272 | printf("array["); | |
273 | i = t->chain; | |
274 | if (i != nil) { | |
275 | for (;;) { | |
276 | printtype(i, i, indent); | |
277 | i = i->chain; | |
278 | if (i == nil) { | |
279 | break; | |
280 | } | |
281 | printf(", "); | |
282 | } | |
283 | } | |
284 | printf("] of "); | |
285 | printtype(t, t->type, indent); | |
286 | break; | |
287 | ||
288 | case RECORD: | |
289 | case VARNT: | |
290 | printf("%s ", c_classname(t)); | |
291 | if (s->name != nil and s->class == TAG) { | |
292 | p = symname(s); | |
293 | if (p[0] == '$' and p[1] == '$') { | |
294 | printf("%s ", &p[2]); | |
295 | } else { | |
296 | printf("%s ", p); | |
297 | } | |
298 | } | |
299 | printf("{\n", t->class == RECORD ? "struct" : "union"); | |
300 | for (i = t->chain; i != nil; i = i->chain) { | |
301 | assert(i->class == FIELD); | |
302 | printdecl(i, indent+4); | |
303 | } | |
304 | if (indent > 0) { | |
305 | printf("%*c", indent, ' '); | |
306 | } | |
307 | printf("}"); | |
308 | break; | |
309 | ||
310 | case RANGE: | |
311 | r0 = t->symvalue.rangev.lower; | |
312 | r1 = t->symvalue.rangev.upper; | |
313 | if (istypename(t->type, "char")) { | |
314 | if (r0 < 0x20 or r0 > 0x7e) { | |
315 | printf("%ld..", r0); | |
316 | } else { | |
317 | printf("'%c'..", (char) r0); | |
318 | } | |
319 | if (r1 < 0x20 or r1 > 0x7e) { | |
320 | printf("\\%lo", r1); | |
321 | } else { | |
322 | printf("'%c'", (char) r1); | |
323 | } | |
324 | } else if (r0 > 0 and r1 == 0) { | |
325 | printf("%ld byte real", r0); | |
326 | } else if (r0 >= 0) { | |
327 | printf("%lu..%lu", r0, r1); | |
328 | } else { | |
329 | printf("%ld..%ld", r0, r1); | |
330 | } | |
331 | break; | |
332 | ||
333 | case PTR: | |
334 | printtype(t, t->type, indent); | |
335 | if (t->type->class != PTR) { | |
336 | printf(" "); | |
337 | } | |
338 | printf("*"); | |
339 | break; | |
340 | ||
341 | case FUNC: | |
342 | printtype(t, t->type, indent); | |
343 | printf("()"); | |
344 | break; | |
345 | ||
346 | case TYPE: | |
347 | if (t->name != nil) { | |
348 | printname(stdout, t); | |
349 | } else { | |
350 | printtype(t, t->type, indent); | |
351 | } | |
352 | break; | |
353 | ||
354 | case TYPEREF: | |
355 | printf("@%s", symname(t)); | |
356 | break; | |
357 | ||
358 | case SCAL: | |
359 | printf("enum "); | |
360 | if (s->name != nil and s->class == TAG) { | |
361 | printf("%s ", symname(s)); | |
362 | } | |
363 | printf("{ "); | |
364 | i = t->chain; | |
365 | if (i != nil) { | |
366 | for (;;) { | |
367 | printf("%s", symname(i)); | |
368 | i = i->chain; | |
369 | if (i == nil) break; | |
370 | printf(", "); | |
371 | } | |
372 | } | |
373 | printf(" }"); | |
374 | break; | |
375 | ||
376 | case TAG: | |
377 | if (t->type == nil) { | |
378 | printf("unresolved tag %s", symname(t)); | |
379 | } else { | |
380 | i = rtype(t->type); | |
381 | printf("%s %s", c_classname(i), symname(t)); | |
382 | } | |
383 | break; | |
384 | ||
385 | default: | |
386 | printf("(class %d)", t->class); | |
387 | break; | |
388 | } | |
389 | } | |
390 | ||
391 | /* | |
392 | * List the parameters of a procedure or function. | |
393 | * No attempt is made to combine like types. | |
394 | */ | |
395 | ||
396 | public c_listparams(s) | |
397 | Symbol s; | |
398 | { | |
399 | register Symbol t; | |
400 | ||
401 | putchar('('); | |
402 | for (t = s->chain; t != nil; t = t->chain) { | |
403 | printf("%s", symname(t)); | |
404 | if (t->chain != nil) { | |
405 | printf(", "); | |
406 | } | |
407 | } | |
408 | putchar(')'); | |
409 | if (s->chain != nil) { | |
410 | printf("\n"); | |
411 | for (t = s->chain; t != nil; t = t->chain) { | |
412 | if (t->class != VAR) { | |
413 | panic("unexpected class %d for parameter", t->class); | |
414 | } | |
415 | printdecl(t, 0); | |
416 | } | |
417 | } else { | |
418 | putchar('\n'); | |
419 | } | |
420 | } | |
421 | ||
422 | /* | |
423 | * Print out the value on the top of the expression stack | |
424 | * in the format for the type of the given symbol. | |
425 | */ | |
426 | ||
427 | public c_printval(s) | |
428 | Symbol s; | |
429 | { | |
430 | register Symbol t; | |
431 | register Address a; | |
432 | register int i, len; | |
433 | ||
434 | switch (s->class) { | |
435 | case CONST: | |
436 | case TYPE: | |
437 | case VAR: | |
438 | case REF: | |
439 | case FVAR: | |
440 | case TAG: | |
441 | c_printval(s->type); | |
442 | break; | |
443 | ||
444 | case FIELD: | |
445 | if (isbitfield(s)) { | |
446 | len = s->symvalue.field.length; | |
447 | if (len <= BITSPERBYTE) { | |
448 | i = pop(char); | |
449 | } else if (len <= sizeof(short)*BITSPERBYTE) { | |
450 | i = pop(short); | |
451 | } else { | |
452 | i = pop(long); | |
453 | } | |
454 | i >>= (s->symvalue.field.offset mod BITSPERBYTE); | |
455 | i &= ((1 << len) - 1); | |
456 | t = rtype(s->type); | |
457 | if (t->class == SCAL) { | |
458 | printenum(i, t); | |
459 | } else { | |
460 | printrange(i, t); | |
461 | } | |
462 | } else { | |
463 | c_printval(s->type); | |
464 | } | |
465 | break; | |
466 | ||
467 | case ARRAY: | |
468 | t = rtype(s->type); | |
469 | if (t->class == RANGE and istypename(t->type, "char")) { | |
470 | len = size(s); | |
471 | sp -= len; | |
472 | printf("\"%.*s\"", len, sp); | |
473 | } else { | |
474 | printarray(s); | |
475 | } | |
476 | break; | |
477 | ||
478 | case RECORD: | |
479 | case VARNT: | |
480 | c_printstruct(s); | |
481 | break; | |
482 | ||
483 | case RANGE: | |
484 | if (istypename(s->type, "boolean")) { | |
485 | printrange(popsmall(s), s); | |
486 | } else if (istypename(s->type, "char")) { | |
487 | printrange(pop(char), s); | |
488 | } else if (isdouble(s)) { | |
489 | switch (s->symvalue.rangev.lower) { | |
490 | case sizeof(float): | |
491 | prtreal(pop(float)); | |
492 | break; | |
493 | ||
494 | case sizeof(double): | |
495 | prtreal(pop(double)); | |
496 | break; | |
497 | ||
498 | default: | |
499 | panic("bad real size %d", t->symvalue.rangev.lower); | |
500 | break; | |
501 | } | |
502 | } else { | |
503 | printrange(popsmall(s), s); | |
504 | } | |
505 | break; | |
506 | ||
507 | case PTR: | |
508 | t = rtype(s->type); | |
509 | a = pop(Address); | |
510 | if (a == 0) { | |
511 | printf("(nil)"); | |
512 | } else if (t->class == RANGE and istypename(t->type, "char")) { | |
513 | printstring(a); | |
514 | } else { | |
515 | printf("0x%x", a); | |
516 | } | |
517 | break; | |
518 | ||
519 | case SCAL: | |
520 | i = pop(Integer); | |
521 | printenum(i, s); | |
522 | break; | |
523 | ||
524 | default: | |
525 | if (ord(s->class) > ord(TYPEREF)) { | |
526 | panic("printval: bad class %d", ord(s->class)); | |
527 | } | |
528 | error("don't know how to print a %s", c_classname(s)); | |
529 | /* NOTREACHED */ | |
530 | } | |
531 | } | |
532 | ||
533 | /* | |
534 | * Print out a C structure. | |
535 | */ | |
536 | ||
537 | private c_printstruct(s) | |
538 | Symbol s; | |
539 | { | |
540 | register Symbol f; | |
541 | register Stack *savesp; | |
542 | register Integer n, off, len; | |
543 | ||
544 | sp -= size(s); | |
545 | savesp = sp; | |
546 | printf("("); | |
547 | f = s->chain; | |
548 | for (;;) { | |
549 | off = f->symvalue.field.offset; | |
550 | len = f->symvalue.field.length; | |
551 | n = (off + len + 7) div BITSPERBYTE; | |
552 | sp += n; | |
553 | printf("%s = ", symname(f)); | |
554 | c_printval(f); | |
555 | sp = savesp; | |
556 | f = f->chain; | |
557 | if (f == nil) break; | |
558 | printf(", "); | |
559 | } | |
560 | printf(")"); | |
561 | } | |
562 | ||
563 | /* | |
564 | * Print out a range type (integer, char, or boolean). | |
565 | */ | |
566 | ||
567 | private printrange(i, t) | |
568 | Integer i; | |
569 | register Symbol t; | |
570 | { | |
571 | if (istypename(t->type, "boolean")) { | |
572 | printf(((Boolean) i) == true ? "true" : "false"); | |
573 | } else if (istypename(t->type, "char")) { | |
574 | putchar('\''); | |
575 | printchar(i); | |
576 | putchar('\''); | |
577 | } else if (t->symvalue.rangev.lower >= 0) { | |
578 | printf("%lu", i); | |
579 | } else { | |
580 | printf("%ld", i); | |
581 | } | |
582 | } | |
583 | ||
584 | /* | |
585 | * Print out a null-terminated string (pointer to char) | |
586 | * starting at the given address. | |
587 | */ | |
588 | ||
589 | private printstring(addr) | |
590 | Address addr; | |
591 | { | |
592 | register Address a; | |
593 | register Integer i, len; | |
594 | register Boolean endofstring; | |
595 | union { | |
596 | char ch[sizeof(Word)]; | |
597 | int word; | |
598 | } u; | |
599 | ||
600 | putchar('"'); | |
601 | a = addr; | |
602 | endofstring = false; | |
603 | while (not endofstring) { | |
604 | dread(&u, a, sizeof(u)); | |
605 | i = 0; | |
606 | do { | |
607 | if (u.ch[i] == '\0') { | |
608 | endofstring = true; | |
609 | } else { | |
610 | printchar(u.ch[i]); | |
611 | } | |
612 | ++i; | |
613 | } while (i < sizeof(Word) and not endofstring); | |
614 | a += sizeof(Word); | |
615 | } | |
616 | putchar('"'); | |
617 | } | |
618 | ||
619 | /* | |
620 | * Print out an enumerated value by finding the corresponding | |
621 | * name in the enumeration list. | |
622 | */ | |
623 | ||
624 | private printenum(i, t) | |
625 | Integer i; | |
626 | Symbol t; | |
627 | { | |
628 | register Symbol e; | |
629 | ||
630 | e = t->chain; | |
631 | while (e != nil and e->symvalue.iconval != i) { | |
632 | e = e->chain; | |
633 | } | |
634 | if (e != nil) { | |
635 | printf("%s", symname(e)); | |
636 | } else { | |
637 | printf("%d", i); | |
638 | } | |
639 | } | |
640 | ||
641 | /* | |
642 | * Return the C name for the particular class of a symbol. | |
643 | */ | |
644 | ||
645 | public String c_classname(s) | |
646 | Symbol s; | |
647 | { | |
648 | String str; | |
649 | ||
650 | switch (s->class) { | |
651 | case RECORD: | |
652 | str = "struct"; | |
653 | break; | |
654 | ||
655 | case VARNT: | |
656 | str = "union"; | |
657 | break; | |
658 | ||
659 | case SCAL: | |
660 | str = "enum"; | |
661 | break; | |
662 | ||
663 | default: | |
664 | str = classname(s); | |
665 | } | |
666 | return str; | |
667 | } |