Commit | Line | Data |
---|---|---|
21e15a40 SL |
1 | #ifndef lint |
2 | static char sccsid[] = "@(#)stabstring.c 1.1 (Berkeley) %G%"; /* from 1.4 84/03/27 10:24:04 linton Exp */ | |
3 | #endif | |
4 | ||
5 | /* | |
6 | * String information interpretation | |
7 | * | |
8 | * The string part of a stab entry is broken up into name and type information. | |
9 | */ | |
10 | ||
11 | #include "defs.h" | |
12 | #include "stabstring.h" | |
13 | #include "object.h" | |
14 | #include "main.h" | |
15 | #include "symbols.h" | |
16 | #include "names.h" | |
17 | #include "languages.h" | |
18 | #include <a.out.h> | |
19 | #include <ctype.h> | |
20 | ||
21 | #ifndef public | |
22 | #endif | |
23 | ||
24 | /* | |
25 | * Special characters in symbol table information. | |
26 | */ | |
27 | ||
28 | #define TYPENAME 't' | |
29 | #define TAGNAME 'T' | |
30 | #define MODULEBEGIN 'm' | |
31 | #define EXTPROCEDURE 'P' | |
32 | #define PRIVPROCEDURE 'Q' | |
33 | #define INTPROCEDURE 'I' | |
34 | #define EXTFUNCTION 'F' | |
35 | #define PRIVFUNCTION 'f' | |
36 | #define INTFUNCTION 'J' | |
37 | #define EXTVAR 'G' | |
38 | #define MODULEVAR 'S' | |
39 | #define OWNVAR 'V' | |
40 | #define REGVAR 'r' | |
41 | #define VALUEPARAM 'p' | |
42 | #define VARIABLEPARAM 'v' | |
43 | #define LOCALVAR /* default */ | |
44 | ||
45 | /* | |
46 | * Type information special characters. | |
47 | */ | |
48 | ||
49 | #define T_SUBRANGE 'r' | |
50 | #define T_ARRAY 'a' | |
51 | #define T_OPENARRAY 'A' | |
52 | #define T_RECORD 's' | |
53 | #define T_UNION 'u' | |
54 | #define T_ENUM 'e' | |
55 | #define T_PTR '*' | |
56 | #define T_FUNCVAR 'f' | |
57 | #define T_PROCVAR 'p' | |
58 | #define T_IMPORTED 'i' | |
59 | #define T_SET 'S' | |
60 | #define T_OPAQUE 'o' | |
61 | ||
62 | /* | |
63 | * Table of types indexed by per-file unique identification number. | |
64 | */ | |
65 | ||
66 | #define NTYPES 1000 | |
67 | ||
68 | private Symbol typetable[NTYPES]; | |
69 | ||
70 | public initTypeTable () | |
71 | { | |
72 | bzero(typetable, sizeof(typetable)); | |
73 | (*language_op(curlang, L_MODINIT))(typetable); | |
74 | } | |
75 | ||
76 | /* | |
77 | * Put an nlist entry into the symbol table. | |
78 | * If it's already there just add the associated information. | |
79 | * | |
80 | * Type information is encoded in the name following a ":". | |
81 | */ | |
82 | ||
83 | private Symbol constype(); | |
84 | private Char *curchar; | |
85 | ||
86 | #define skipchar(ptr, ch) \ | |
87 | { \ | |
88 | if (*ptr != ch) { \ | |
89 | panic("expected char '%c', found '%s'", ch, ptr); \ | |
90 | } \ | |
91 | ++ptr; \ | |
92 | } | |
93 | ||
94 | #define optchar(ptr, ch) \ | |
95 | { \ | |
96 | if (*ptr == ch) { \ | |
97 | ++ptr; \ | |
98 | } \ | |
99 | } | |
100 | ||
101 | #define chkcont(ptr) \ | |
102 | { \ | |
103 | if (*ptr == '?') { \ | |
104 | ptr = getcont(); \ | |
105 | } \ | |
106 | } | |
107 | ||
108 | #define newSym(s, n) \ | |
109 | { \ | |
110 | s = insert(n); \ | |
111 | s->level = curblock->level + 1; \ | |
112 | s->language = curlang; \ | |
113 | s->block = curblock; \ | |
114 | } | |
115 | ||
116 | #define makeVariable(s, n, off) \ | |
117 | { \ | |
118 | newSym(s, n); \ | |
119 | s->class = VAR; \ | |
120 | s->symvalue.offset = off; \ | |
121 | getType(s); \ | |
122 | } | |
123 | ||
124 | #define makeParameter(s, n, cl, off) \ | |
125 | { \ | |
126 | newSym(s, n); \ | |
127 | s->class = cl; \ | |
128 | s->symvalue.offset = off; \ | |
129 | curparam->chain = s; \ | |
130 | curparam = s; \ | |
131 | getType(s); \ | |
132 | } | |
133 | ||
134 | public entersym (name, np) | |
135 | String name; | |
136 | struct nlist *np; | |
137 | { | |
138 | Symbol s; | |
139 | char *p; | |
140 | register Name n; | |
141 | char c; | |
142 | ||
143 | p = index(name, ':'); | |
144 | *p = '\0'; | |
145 | c = *(p+1); | |
146 | n = identname(name, true); | |
147 | chkUnnamedBlock(); | |
148 | curchar = p + 2; | |
149 | switch (c) { | |
150 | case TYPENAME: | |
151 | newSym(s, n); | |
152 | typeName(s); | |
153 | break; | |
154 | ||
155 | case TAGNAME: | |
156 | newSym(s, n); | |
157 | tagName(s); | |
158 | break; | |
159 | ||
160 | case MODULEBEGIN: | |
161 | newSym(s, n); | |
162 | publicRoutine(s, MODULE, np->n_value); | |
163 | curmodule = s; | |
164 | break; | |
165 | ||
166 | case EXTPROCEDURE: | |
167 | newSym(s, n); | |
168 | publicRoutine(s, PROC, np->n_value); | |
169 | break; | |
170 | ||
171 | case PRIVPROCEDURE: | |
172 | privateRoutine(&s, n, PROC, np->n_value); | |
173 | break; | |
174 | ||
175 | case INTPROCEDURE: | |
176 | newSym(s, n); | |
177 | markInternal(s); | |
178 | publicRoutine(s, PROC, np->n_value); | |
179 | break; | |
180 | ||
181 | case EXTFUNCTION: | |
182 | newSym(s, n); | |
183 | publicRoutine(s, FUNC, np->n_value); | |
184 | break; | |
185 | ||
186 | case PRIVFUNCTION: | |
187 | privateRoutine(&s, n, FUNC, np->n_value); | |
188 | break; | |
189 | ||
190 | case INTFUNCTION: | |
191 | newSym(s, n); | |
192 | markInternal(s); | |
193 | publicRoutine(s, FUNC, np->n_value); | |
194 | break; | |
195 | ||
196 | case EXTVAR: | |
197 | find(s, n) where | |
198 | s->level == program->level and s->class == VAR | |
199 | endfind(s); | |
200 | if (s == nil) { | |
201 | makeVariable(s, n, np->n_value); | |
202 | s->level = program->level; | |
203 | s->block = program; | |
204 | getExtRef(s); | |
205 | } | |
206 | break; | |
207 | ||
208 | case MODULEVAR: | |
209 | if (curblock->class != MODULE) { | |
210 | exitblock(); | |
211 | } | |
212 | makeVariable(s, n, np->n_value); | |
213 | s->level = program->level; | |
214 | s->block = curmodule; | |
215 | getExtRef(s); | |
216 | break; | |
217 | ||
218 | case OWNVAR: | |
219 | makeVariable(s, n, np->n_value); | |
220 | ownVariable(s, np->n_value); | |
221 | getExtRef(s); | |
222 | break; | |
223 | ||
224 | case REGVAR: | |
225 | makeVariable(s, n, np->n_value); | |
226 | s->level = -(s->level); | |
227 | break; | |
228 | ||
229 | case VALUEPARAM: | |
230 | makeParameter(s, n, VAR, np->n_value); | |
231 | break; | |
232 | ||
233 | case VARIABLEPARAM: | |
234 | makeParameter(s, n, REF, np->n_value); | |
235 | break; | |
236 | ||
237 | default: /* local variable */ | |
238 | --curchar; | |
239 | makeVariable(s, n, np->n_value); | |
240 | break; | |
241 | } | |
242 | if (tracesyms) { | |
243 | printdecl(s); | |
244 | fflush(stdout); | |
245 | } | |
246 | } | |
247 | ||
248 | /* | |
249 | * Enter a type name. | |
250 | */ | |
251 | ||
252 | private typeName (s) | |
253 | Symbol s; | |
254 | { | |
255 | register integer i; | |
256 | ||
257 | s->class = TYPE; | |
258 | s->language = curlang; | |
259 | s->block = curblock; | |
260 | s->level = curblock->level + 1; | |
261 | i = getint(); | |
262 | if (i == 0) { | |
263 | panic("bad input on type \"%s\" at \"%s\"", symname(s), curchar); | |
264 | } else if (i >= NTYPES) { | |
265 | panic("too many types in file \"%s\"", curfilename()); | |
266 | } | |
267 | /* | |
268 | * A hack for C typedefs that don't create new types, | |
269 | * e.g. typedef unsigned int Hashvalue; | |
270 | * or typedef struct blah BLAH; | |
271 | */ | |
272 | if (*curchar != '=') { | |
273 | s->type = typetable[i]; | |
274 | if (s->type == nil) { | |
275 | s->type = symbol_alloc(); | |
276 | typetable[i] = s->type; | |
277 | } | |
278 | } else { | |
279 | if (typetable[i] != nil) { | |
280 | typetable[i]->language = curlang; | |
281 | typetable[i]->class = TYPE; | |
282 | typetable[i]->type = s; | |
283 | } else { | |
284 | typetable[i] = s; | |
285 | } | |
286 | skipchar(curchar, '='); | |
287 | getType(s); | |
288 | } | |
289 | } | |
290 | ||
291 | /* | |
292 | * Enter a tag name. | |
293 | */ | |
294 | ||
295 | private tagName (s) | |
296 | Symbol s; | |
297 | { | |
298 | register integer i; | |
299 | ||
300 | s->class = TAG; | |
301 | i = getint(); | |
302 | if (i == 0) { | |
303 | panic("bad input on tag \"%s\" at \"%s\"", symname(s), curchar); | |
304 | } else if (i >= NTYPES) { | |
305 | panic("too many types in file \"%s\"", curfilename()); | |
306 | } | |
307 | if (typetable[i] != nil) { | |
308 | typetable[i]->language = curlang; | |
309 | typetable[i]->class = TYPE; | |
310 | typetable[i]->type = s; | |
311 | } else { | |
312 | typetable[i] = s; | |
313 | } | |
314 | skipchar(curchar, '='); | |
315 | getType(s); | |
316 | } | |
317 | ||
318 | /* | |
319 | * Setup a symbol entry for a public procedure or function. | |
320 | */ | |
321 | ||
322 | private publicRoutine (s, class, addr) | |
323 | Symbol s; | |
324 | Symclass class; | |
325 | Address addr; | |
326 | { | |
327 | enterRoutine(s, class); | |
328 | s->level = program->level; | |
329 | } | |
330 | ||
331 | /* | |
332 | * Setup a symbol entry for a private procedure or function. | |
333 | */ | |
334 | ||
335 | private privateRoutine (s, n, class, addr) | |
336 | Symbol *s; | |
337 | Name n; | |
338 | Symclass class; | |
339 | Address addr; | |
340 | { | |
341 | Symbol t; | |
342 | boolean isnew; | |
343 | ||
344 | find(t, n) where | |
345 | t->level == curmodule->level and t->class == class | |
346 | endfind(t); | |
347 | if (t == nil) { | |
348 | isnew = true; | |
349 | t = insert(n); | |
350 | } else { | |
351 | isnew = false; | |
352 | } | |
353 | t->language = curlang; | |
354 | enterRoutine(t, class); | |
355 | if (isnew) { | |
356 | t->symvalue.funcv.src = false; | |
357 | t->symvalue.funcv.inline = false; | |
358 | t->symvalue.funcv.beginaddr = addr; | |
359 | newfunc(t, codeloc(t)); | |
360 | findbeginning(t); | |
361 | } | |
362 | *s = t; | |
363 | } | |
364 | ||
365 | /* | |
366 | * Set up for beginning a new procedure, function, or module. | |
367 | * If it's a function, then read the type. | |
368 | * | |
369 | * If the next character is a ",", then read the name of the enclosing block. | |
370 | * Otherwise assume the previous function, if any, is over, and the current | |
371 | * routine is at the same level. | |
372 | */ | |
373 | ||
374 | private enterRoutine (s, class) | |
375 | Symbol s; | |
376 | Symclass class; | |
377 | { | |
378 | s->class = class; | |
379 | if (class == FUNC) { | |
380 | getType(s); | |
381 | } | |
382 | if (s->class != MODULE) { | |
383 | getExtRef(s); | |
384 | } else if (*curchar == ',') { | |
385 | ++curchar; | |
386 | } | |
387 | if (*curchar != '\0') { | |
388 | exitblock(); | |
389 | enterNestedBlock(s); | |
390 | } else { | |
391 | if (curblock->class == FUNC or curblock->class == PROC) { | |
392 | exitblock(); | |
393 | } | |
394 | if (class == MODULE) { | |
395 | exitblock(); | |
396 | } | |
397 | enterblock(s); | |
398 | } | |
399 | curparam = s; | |
400 | } | |
401 | ||
402 | /* | |
403 | * Check to see if the stab string contains the name of the external | |
404 | * reference. If so, we create a symbol with that name and class EXTREF, and | |
405 | * connect it to the given symbol. This link is created so that when | |
406 | * we see the linker symbol we can resolve it to the given symbol. | |
407 | */ | |
408 | ||
409 | private getExtRef (s) | |
410 | Symbol s; | |
411 | { | |
412 | char *p; | |
413 | Name n; | |
414 | Symbol t; | |
415 | ||
416 | if (*curchar == ',' and *(curchar + 1) != '\0') { | |
417 | p = index(curchar + 1, ','); | |
418 | *curchar = '\0'; | |
419 | if (p != nil) { | |
420 | *p = '\0'; | |
421 | n = identname(curchar + 1, false); | |
422 | curchar = p + 1; | |
423 | } else { | |
424 | n = identname(curchar + 1, true); | |
425 | } | |
426 | t = insert(n); | |
427 | t->language = s->language; | |
428 | t->class = EXTREF; | |
429 | t->block = program; | |
430 | t->level = program->level; | |
431 | t->symvalue.extref = s; | |
432 | } | |
433 | } | |
434 | ||
435 | /* | |
436 | * Find a block with the given identifier in the given outer block. | |
437 | * If not there, then create it. | |
438 | */ | |
439 | ||
440 | private Symbol findBlock (id, m) | |
441 | String id; | |
442 | Symbol m; | |
443 | { | |
444 | Name n; | |
445 | Symbol s; | |
446 | ||
447 | n = identname(id, true); | |
448 | find(s, n) where s->block == m and isblock(s) endfind(s); | |
449 | if (s == nil) { | |
450 | s = insert(n); | |
451 | s->block = m; | |
452 | s->language = curlang; | |
453 | s->class = MODULE; | |
454 | s->level = m->level + 1; | |
455 | } | |
456 | return s; | |
457 | } | |
458 | ||
459 | /* | |
460 | * Enter a nested block. | |
461 | * The block within which it is nested is described | |
462 | * by "module{:module}[:proc]". | |
463 | */ | |
464 | ||
465 | private enterNestedBlock (b) | |
466 | Symbol b; | |
467 | { | |
468 | register char *p, *q; | |
469 | Symbol m, s; | |
470 | Name n; | |
471 | ||
472 | q = curchar; | |
473 | p = index(q, ':'); | |
474 | m = program; | |
475 | while (p != nil) { | |
476 | *p = '\0'; | |
477 | m = findBlock(q, m); | |
478 | q = p + 1; | |
479 | p = index(q, ':'); | |
480 | } | |
481 | if (*q != '\0') { | |
482 | m = findBlock(q, m); | |
483 | } | |
484 | b->level = m->level + 1; | |
485 | b->block = m; | |
486 | pushBlock(b); | |
487 | } | |
488 | ||
489 | /* | |
490 | * Enter a statically-allocated variable defined within a routine. | |
491 | * | |
492 | * Global BSS variables are chained together so we can resolve them | |
493 | * when the start of common is determined. The list is kept in order | |
494 | * so that f77 can display all vars in a COMMON. | |
495 | */ | |
496 | ||
497 | private ownVariable (s, addr) | |
498 | Symbol s; | |
499 | Address addr; | |
500 | { | |
501 | s->level = 1; | |
502 | if (curcomm) { | |
503 | if (commchain != nil) { | |
504 | commchain->symvalue.common.chain = s; | |
505 | } else { | |
506 | curcomm->symvalue.common.offset = (integer) s; | |
507 | } | |
508 | commchain = s; | |
509 | s->symvalue.common.offset = addr; | |
510 | s->symvalue.common.chain = nil; | |
511 | } | |
512 | } | |
513 | ||
514 | /* | |
515 | * Get a type from the current stab string for the given symbol. | |
516 | */ | |
517 | ||
518 | private getType (s) | |
519 | Symbol s; | |
520 | { | |
521 | s->type = constype(nil); | |
522 | if (s->class == TAG) { | |
523 | addtag(s); | |
524 | } | |
525 | } | |
526 | ||
527 | /* | |
528 | * Construct a type out of a string encoding. | |
529 | * | |
530 | * The forms of the string are | |
531 | * | |
532 | * <number> | |
533 | * <number>=<type> | |
534 | * r<type>;<number>;<number> -- subrange | |
535 | * a<type>;<type> -- array[index] of element | |
536 | * A<type> -- open array | |
537 | * s<size>{<name>:<type>;<number>;<number>}-- record | |
538 | * u<size>{<name>:<type>;<number>;<number>}-- union | |
539 | * *<type> -- pointer | |
540 | * f<type>,<integer>;<paramlist> -- function variable | |
541 | * p<integer>;<paramlist> -- procedure variable | |
542 | * S<type> -- set of type | |
543 | * o<name>[,<type>] -- opaque type | |
544 | * i<name>,<type> -- imported type | |
545 | */ | |
546 | ||
547 | private Rangetype getRangeBoundType(); | |
548 | ||
549 | private Symbol constype (type) | |
550 | Symbol type; | |
551 | { | |
552 | register Symbol t; | |
553 | register integer n; | |
554 | char class; | |
555 | ||
556 | if (isdigit(*curchar)) { | |
557 | n = getint(); | |
558 | if (n >= NTYPES) { | |
559 | panic("too many types in file \"%s\"", curfilename()); | |
560 | } | |
561 | if (*curchar == '=') { | |
562 | if (typetable[n] != nil) { | |
563 | t = typetable[n]; | |
564 | } else { | |
565 | t = symbol_alloc(); | |
566 | typetable[n] = t; | |
567 | } | |
568 | ++curchar; | |
569 | constype(t); | |
570 | } else { | |
571 | t = typetable[n]; | |
572 | if (t == nil) { | |
573 | t = symbol_alloc(); | |
574 | typetable[n] = t; | |
575 | } | |
576 | } | |
577 | } else { | |
578 | if (type == nil) { | |
579 | t = symbol_alloc(); | |
580 | } else { | |
581 | t = type; | |
582 | } | |
583 | t->language = curlang; | |
584 | t->level = curblock->level + 1; | |
585 | t->block = curblock; | |
586 | class = *curchar++; | |
587 | switch (class) { | |
588 | case T_SUBRANGE: | |
589 | consSubrange(t); | |
590 | break; | |
591 | ||
592 | case T_ARRAY: | |
593 | t->class = ARRAY; | |
594 | t->chain = constype(nil); | |
595 | skipchar(curchar, ';'); | |
596 | chkcont(curchar); | |
597 | t->type = constype(nil); | |
598 | break; | |
599 | ||
600 | case T_OPENARRAY: | |
601 | t->class = ARRAY; | |
602 | t->chain = t_open; | |
603 | t->type = constype(nil); | |
604 | break; | |
605 | ||
606 | case T_RECORD: | |
607 | consRecord(t, RECORD); | |
608 | break; | |
609 | ||
610 | case T_UNION: | |
611 | consRecord(t, VARNT); | |
612 | break; | |
613 | ||
614 | case T_ENUM: | |
615 | consEnum(t); | |
616 | break; | |
617 | ||
618 | case T_PTR: | |
619 | t->class = PTR; | |
620 | t->type = constype(nil); | |
621 | break; | |
622 | ||
623 | /* | |
624 | * C function variables are different from Modula-2's. | |
625 | */ | |
626 | case T_FUNCVAR: | |
627 | t->class = FFUNC; | |
628 | t->type = constype(nil); | |
629 | if (not streq(language_name(curlang), "c")) { | |
630 | skipchar(curchar, ','); | |
631 | consParamlist(t); | |
632 | } | |
633 | break; | |
634 | ||
635 | case T_PROCVAR: | |
636 | t->class = FPROC; | |
637 | consParamlist(t); | |
638 | break; | |
639 | ||
640 | case T_IMPORTED: | |
641 | consImpType(t); | |
642 | break; | |
643 | ||
644 | case T_SET: | |
645 | t->class = SET; | |
646 | t->type = constype(nil); | |
647 | break; | |
648 | ||
649 | case T_OPAQUE: | |
650 | consOpaqType(t); | |
651 | break; | |
652 | ||
653 | default: | |
654 | badcaseval(class); | |
655 | } | |
656 | } | |
657 | return t; | |
658 | } | |
659 | ||
660 | /* | |
661 | * Construct a subrange type. | |
662 | */ | |
663 | ||
664 | private consSubrange (t) | |
665 | Symbol t; | |
666 | { | |
667 | t->class = RANGE; | |
668 | t->type = constype(nil); | |
669 | skipchar(curchar, ';'); | |
670 | chkcont(curchar); | |
671 | t->symvalue.rangev.lowertype = getRangeBoundType(); | |
672 | t->symvalue.rangev.lower = getint(); | |
673 | skipchar(curchar, ';'); | |
674 | chkcont(curchar); | |
675 | t->symvalue.rangev.uppertype = getRangeBoundType(); | |
676 | t->symvalue.rangev.upper = getint(); | |
677 | } | |
678 | ||
679 | /* | |
680 | * Figure out the bound type of a range. | |
681 | * | |
682 | * Some letters indicate a dynamic bound, ie what follows | |
683 | * is the offset from the fp which contains the bound; this will | |
684 | * need a different encoding when pc a['A'..'Z'] is | |
685 | * added; J is a special flag to handle fortran a(*) bounds | |
686 | */ | |
687 | ||
688 | private Rangetype getRangeBoundType () | |
689 | { | |
690 | Rangetype r; | |
691 | ||
692 | switch (*curchar) { | |
693 | case 'A': | |
694 | r = R_ARG; | |
695 | curchar++; | |
696 | break; | |
697 | ||
698 | case 'T': | |
699 | r = R_TEMP; | |
700 | curchar++; | |
701 | break; | |
702 | ||
703 | case 'J': | |
704 | r = R_ADJUST; | |
705 | curchar++; | |
706 | break; | |
707 | ||
708 | default: | |
709 | r = R_CONST; | |
710 | break; | |
711 | } | |
712 | return r; | |
713 | } | |
714 | ||
715 | /* | |
716 | * Construct a record or union type. | |
717 | */ | |
718 | ||
719 | private consRecord (t, class) | |
720 | Symbol t; | |
721 | Symclass class; | |
722 | { | |
723 | register Symbol u; | |
724 | register char *cur, *p; | |
725 | Name name; | |
726 | integer d; | |
727 | ||
728 | t->class = class; | |
729 | t->symvalue.offset = getint(); | |
730 | d = curblock->level + 1; | |
731 | u = t; | |
732 | cur = curchar; | |
733 | while (*cur != ';' and *cur != '\0') { | |
734 | p = index(cur, ':'); | |
735 | if (p == nil) { | |
736 | panic("index(\"%s\", ':') failed", curchar); | |
737 | } | |
738 | *p = '\0'; | |
739 | name = identname(cur, true); | |
740 | u->chain = newSymbol(name, d, FIELD, nil, nil); | |
741 | cur = p + 1; | |
742 | u = u->chain; | |
743 | u->language = curlang; | |
744 | curchar = cur; | |
745 | u->type = constype(nil); | |
746 | skipchar(curchar, ','); | |
747 | u->symvalue.field.offset = getint(); | |
748 | skipchar(curchar, ','); | |
749 | u->symvalue.field.length = getint(); | |
750 | skipchar(curchar, ';'); | |
751 | chkcont(curchar); | |
752 | cur = curchar; | |
753 | } | |
754 | if (*cur == ';') { | |
755 | ++cur; | |
756 | } | |
757 | curchar = cur; | |
758 | } | |
759 | ||
760 | /* | |
761 | * Construct an enumeration type. | |
762 | */ | |
763 | ||
764 | private consEnum (t) | |
765 | Symbol t; | |
766 | { | |
767 | register Symbol u; | |
768 | register char *p; | |
769 | register integer count; | |
770 | ||
771 | t->class = SCAL; | |
772 | count = 0; | |
773 | u = t; | |
774 | while (*curchar != ';' and *curchar != '\0') { | |
775 | p = index(curchar, ':'); | |
776 | assert(p != nil); | |
777 | *p = '\0'; | |
778 | u->chain = insert(identname(curchar, true)); | |
779 | curchar = p + 1; | |
780 | u = u->chain; | |
781 | u->language = curlang; | |
782 | u->class = CONST; | |
783 | u->level = curblock->level + 1; | |
784 | u->block = curblock; | |
785 | u->type = t; | |
786 | u->symvalue.iconval = getint(); | |
787 | ++count; | |
788 | skipchar(curchar, ','); | |
789 | chkcont(curchar); | |
790 | } | |
791 | if (*curchar == ';') { | |
792 | ++curchar; | |
793 | } | |
794 | t->symvalue.iconval = count; | |
795 | } | |
796 | ||
797 | /* | |
798 | * Construct a parameter list for a function or procedure variable. | |
799 | */ | |
800 | ||
801 | private consParamlist (t) | |
802 | Symbol t; | |
803 | { | |
804 | Symbol p; | |
805 | integer i, d, n, paramclass; | |
806 | ||
807 | n = getint(); | |
808 | skipchar(curchar, ';'); | |
809 | p = t; | |
810 | d = curblock->level + 1; | |
811 | for (i = 0; i < n; i++) { | |
812 | p->chain = newSymbol(nil, d, VAR, nil, nil); | |
813 | p = p->chain; | |
814 | p->type = constype(nil); | |
815 | skipchar(curchar, ','); | |
816 | paramclass = getint(); | |
817 | if (paramclass == 0) { | |
818 | p->class = REF; | |
819 | } | |
820 | skipchar(curchar, ';'); | |
821 | chkcont(curchar); | |
822 | } | |
823 | } | |
824 | ||
825 | /* | |
826 | * Construct an imported type. | |
827 | * Add it to a list of symbols to get fixed up. | |
828 | */ | |
829 | ||
830 | private consImpType (t) | |
831 | Symbol t; | |
832 | { | |
833 | register char *p; | |
834 | Symbol tmp; | |
835 | ||
836 | p = curchar; | |
837 | while (*p != ',' and *p != ';' and *p != '\0') { | |
838 | ++p; | |
839 | } | |
840 | if (*p == '\0') { | |
841 | panic("bad import symbol entry '%s'", curchar); | |
842 | } | |
843 | t->class = TYPEREF; | |
844 | t->symvalue.typeref = curchar; | |
845 | curchar = p + 1; | |
846 | if (*p == ',') { | |
847 | curchar = p + 1; | |
848 | tmp = constype(nil); | |
849 | } | |
850 | skipchar(curchar, ';'); | |
851 | *p = '\0'; | |
852 | } | |
853 | ||
854 | /* | |
855 | * Construct an opaque type entry. | |
856 | */ | |
857 | ||
858 | private consOpaqType (t) | |
859 | Symbol t; | |
860 | { | |
861 | register char *p; | |
862 | register Symbol s; | |
863 | register Name n; | |
864 | boolean def; | |
865 | ||
866 | p = curchar; | |
867 | while (*p != ';' and *p != ',') { | |
868 | if (*p == '\0') { | |
869 | panic("bad opaque symbol entry '%s'", curchar); | |
870 | } | |
871 | ++p; | |
872 | } | |
873 | def = (Boolean) (*p == ','); | |
874 | *p = '\0'; | |
875 | n = identname(curchar, true); | |
876 | find(s, n) where s->class == TYPEREF endfind(s); | |
877 | if (s == nil) { | |
878 | s = insert(n); | |
879 | s->class = TYPEREF; | |
880 | s->type = nil; | |
881 | } | |
882 | curchar = p + 1; | |
883 | if (def) { | |
884 | s->type = constype(nil); | |
885 | skipchar(curchar, ';'); | |
886 | } | |
887 | t->class = TYPE; | |
888 | t->type = s; | |
889 | } | |
890 | ||
891 | /* | |
892 | * Read an integer from the current position in the type string. | |
893 | */ | |
894 | ||
895 | private integer getint () | |
896 | { | |
897 | register integer n; | |
898 | register char *p; | |
899 | register Boolean isneg; | |
900 | ||
901 | n = 0; | |
902 | p = curchar; | |
903 | if (*p == '-') { | |
904 | isneg = true; | |
905 | ++p; | |
906 | } else { | |
907 | isneg = false; | |
908 | } | |
909 | while (isdigit(*p)) { | |
910 | n = 10*n + (*p - '0'); | |
911 | ++p; | |
912 | } | |
913 | curchar = p; | |
914 | return isneg ? (-n) : n; | |
915 | } | |
916 | ||
917 | /* | |
918 | * Add a tag name. This is a kludge to be able to refer | |
919 | * to tags that have the same name as some other symbol | |
920 | * in the same block. | |
921 | */ | |
922 | ||
923 | private addtag (s) | |
924 | register Symbol s; | |
925 | { | |
926 | register Symbol t; | |
927 | char buf[100]; | |
928 | ||
929 | sprintf(buf, "$$%.90s", ident(s->name)); | |
930 | t = insert(identname(buf, false)); | |
931 | t->language = s->language; | |
932 | t->class = TAG; | |
933 | t->type = s->type; | |
934 | t->block = s->block; | |
935 | } |