xref: /csrg-svn/old/dbx/object.c (revision 14443)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)object.c 1.11 08/10/83";
4 
5 /*
6  * Object code interface, mainly for extraction of symbolic information.
7  */
8 
9 #include "defs.h"
10 #include "object.h"
11 #include "main.h"
12 #include "symbols.h"
13 #include "names.h"
14 #include "languages.h"
15 #include "mappings.h"
16 #include "lists.h"
17 #include <a.out.h>
18 #include <stab.h>
19 #include <ctype.h>
20 
21 #ifndef public
22 
23 struct {
24     unsigned int stringsize;	/* size of the dumped string table */
25     unsigned int nsyms;		/* number of symbols */
26     unsigned int nfiles;	/* number of files */
27     unsigned int nlines;	/* number of lines */
28 } nlhdr;
29 
30 #endif
31 
32 public String objname = "a.out";
33 public Integer objsize;
34 public char *stringtab;
35 
36 private String progname = nil;
37 private Language curlang;
38 private Symbol curmodule;
39 private Symbol curparam;
40 private Boolean warned;
41 private Symbol curcomm;
42 private Symbol commchain;
43 private Boolean strip_ = false;
44 
45 private Filetab *filep;
46 private Linetab *linep, *prevlinep;
47 
48 #define curfilename() (filep-1)->filename
49 
50 /*
51  * Blocks are figured out on the fly while reading the symbol table.
52  */
53 
54 #define MAXBLKDEPTH 25
55 
56 private Symbol curblock;
57 private Symbol blkstack[MAXBLKDEPTH];
58 private Integer curlevel;
59 private Integer bnum, nesting;
60 private Address addrstk[MAXBLKDEPTH];
61 
62 #define enterblock(b) { \
63     blkstack[curlevel] = curblock; \
64     ++curlevel; \
65     b->level = curlevel; \
66     b->block = curblock; \
67     curblock = b; \
68 }
69 
70 #define exitblock() { \
71     if (curblock->class == FUNC or curblock->class == PROC) { \
72 	if (prevlinep != linep) { \
73 	    curblock->symvalue.funcv.src = true; \
74 	} \
75     } \
76     --curlevel; \
77     curblock = blkstack[curlevel]; \
78 }
79 
80 /*
81  * Enter a source line or file name reference into the appropriate table.
82  * Expanded inline to reduce procedure calls.
83  *
84  * private enterline(linenumber, address)
85  * Lineno linenumber;
86  * Address address;
87  *  ...
88  */
89 
90 #define enterline(linenumber, address) \
91 { \
92     register Linetab *lp; \
93  \
94     lp = linep - 1; \
95     if (linenumber != lp->line) { \
96 	if (address != lp->addr) { \
97 	    ++lp; \
98 	} \
99 	lp->line = linenumber; \
100 	lp->addr = address; \
101 	linep = lp + 1; \
102     } \
103 }
104 
105 #define NTYPES 1000
106 
107 private Symbol typetable[NTYPES];
108 
109 /*
110  * Read in the namelist from the obj file.
111  *
112  * Reads and seeks are used instead of fread's and fseek's
113  * for efficiency sake; there's a lot of data being read here.
114  */
115 
116 public readobj(file)
117 String file;
118 {
119     Fileid f;
120     struct exec hdr;
121     struct nlist nlist;
122 
123     f = open(file, 0);
124     if (f < 0) {
125 	fatal("can't open %s", file);
126     }
127     read(f, &hdr, sizeof(hdr));
128     objsize = hdr.a_text;
129     nlhdr.nsyms = hdr.a_syms / sizeof(nlist);
130     nlhdr.nfiles = nlhdr.nsyms;
131     nlhdr.nlines = nlhdr.nsyms;
132     if (nlhdr.nsyms > 0) {
133 	lseek(f, (long) N_STROFF(hdr), 0);
134 	read(f, &(nlhdr.stringsize), sizeof(nlhdr.stringsize));
135 	nlhdr.stringsize -= 4;
136 	stringtab = newarr(char, nlhdr.stringsize);
137 	read(f, stringtab, nlhdr.stringsize);
138 	allocmaps(nlhdr.nfiles, nlhdr.nlines);
139 	lseek(f, (long) N_SYMOFF(hdr), 0);
140 	readsyms(f);
141 	ordfunctab();
142 	setnlines();
143 	setnfiles();
144     }
145     close(f);
146 }
147 
148 /*
149  * Read in symbols from object file.
150  */
151 
152 private readsyms(f)
153 Fileid f;
154 {
155     struct nlist *namelist;
156     register struct nlist *np, *ub;
157     register int index;
158     register String name;
159     register Boolean afterlg;
160 
161     initsyms();
162     namelist = newarr(struct nlist, nlhdr.nsyms);
163     read(f, namelist, nlhdr.nsyms * sizeof(struct nlist));
164     afterlg = false;
165     ub = &namelist[nlhdr.nsyms];
166     for (np = &namelist[0]; np < ub; np++) {
167 	index = np->n_un.n_strx;
168 	if (index != 0) {
169 	    name = &stringtab[index - 4];
170 	    /*
171              *  if the program contains any .f files a trailing _ is stripped
172        	     *  from the name on the assumption it was added by the compiler.
173 	     *  This only affects names that follow the sdb N_SO entry with
174              *  the .f name.
175              */
176             if (strip_ and name[0] != '\0' ) {
177 		register char *p;
178 
179 		p = name;
180 		while (*p != '\0') {
181 		    ++p;
182 		}
183 		--p;
184 		if (*p == '-') {
185 		    *p = '\0';
186 		}
187             }
188 
189 	} else {
190 	    name = nil;
191 	}
192 	/*
193 	 * assumptions:
194 	 *	not an N_STAB	==> name != nil
195 	 *	name[0] == '-'	==> name == "-lg"
196 	 *	name[0] != '_'	==> filename or invisible
197 	 *
198 	 * The "-lg" signals the beginning of global loader symbols.
199          *
200 	 */
201 	if ((np->n_type&N_STAB) != 0) {
202 	    enter_nl(name, np);
203 	} else if (name[0] == '-') {
204 	    afterlg = true;
205 	    if (curblock->class != PROG) {
206 		exitblock();
207 		if (curblock->class != PROG) {
208 		    exitblock();
209 		}
210 	    }
211 	    enterline(0, (linep-1)->addr + 1);
212 	} else if (afterlg) {
213 	    if (name[0] == '_') {
214 		check_global(&name[1], np);
215 	    }
216 	} else if (name[0] == '_') {
217 	    check_local(&name[1], np);
218 	} else if ((np->n_type&N_TEXT) == N_TEXT) {
219 	    check_filename(name);
220 	}
221     }
222     if (not afterlg) {
223 	panic("not linked for debugging, use \"cc -g ...\"");
224     }
225     dispose(namelist);
226 }
227 
228 /*
229  * Initialize symbol information.
230  */
231 
232 private initsyms()
233 {
234     curblock = nil;
235     curlevel = 0;
236     nesting = 0;
237     if (progname == nil) {
238 	progname = strdup(objname);
239 	if (rindex(progname, '/') != nil) {
240 	    progname = rindex(progname, '/') + 1;
241 	}
242 	if (index(progname, '.') != nil) {
243 	    *(index(progname, '.')) = '\0';
244 	}
245     }
246     program = insert(identname(progname, true));
247     program->class = PROG;
248     program->symvalue.funcv.beginaddr = 0;
249     program->symvalue.funcv.inline = false;
250     newfunc(program, codeloc(program));
251     findbeginning(program);
252     enterblock(program);
253     curmodule = program;
254     t_boolean = maketype("$boolean", 0L, 1L);
255     t_int = maketype("$integer", 0x80000000L, 0x7fffffffL);
256     t_char = maketype("$char", 0L, 127L);
257     t_real = maketype("$real", 8L, 0L);
258     t_nil = maketype("$nil", 0L, 0L);
259 }
260 
261 /*
262  * Free all the object file information that's being stored.
263  */
264 
265 public objfree()
266 {
267     symbol_free();
268     keywords_free();
269     names_free();
270     dispose(stringtab);
271     clrfunctab();
272 }
273 
274 /*
275  * Enter a namelist entry.
276  */
277 
278 private enter_nl(name, np)
279 String name;
280 register struct nlist *np;
281 {
282     register Symbol s;
283     register Name n, nn;
284     char buf[100];
285 
286     s = nil;
287     if (name == nil) {
288 	n = nil;
289     } else {
290 	n = identname(name, true);
291     }
292     switch (np->n_type) {
293 	/*
294 	 * Build a symbol for the FORTRAN common area.  All GSYMS that follow
295 	 * will be chained in a list with the head kept in common.offset, and
296 	 * the tail in common.chain.
297 	 */
298 	case N_BCOMM:
299  	    if (curcomm) {
300 		curcomm->symvalue.common.chain = commchain;
301 	    }
302 	    curcomm = lookup(n);
303 	    if (curcomm == nil) {
304 		curcomm = insert(n);
305 		curcomm->class = COMMON;
306 		curcomm->block = curblock;
307 		curcomm->level = program->level;
308 		curcomm->symvalue.common.chain = nil;
309 	    }
310 	    commchain = curcomm->symvalue.common.chain;
311 	    break;
312 
313 	case N_ECOMM:
314 	    if (curcomm) {
315 		curcomm->symvalue.common.chain = commchain;
316 		curcomm = nil;
317 	    }
318 	    break;
319 
320 	case N_LBRAC:
321 	    ++nesting;
322 	    addrstk[nesting] = (linep - 1)->addr;
323 	    break;
324 
325 	case N_RBRAC:
326 	    if (addrstk[nesting] == NOADDR) {
327 		exitblock();
328 		newfunc(curblock, (linep - 1)->addr);
329 	    }
330 	    --nesting;
331 	    break;
332 
333 	case N_SLINE:
334 	    enterline((Lineno) np->n_desc, (Address) np->n_value);
335 	    break;
336 
337 	/*
338 	 * Source files.
339 	 */
340 	case N_SO:
341 	    enterSourceModule(n, (Address) np->n_value);
342 	    break;
343 
344 	/*
345 	 * Textually included files.
346 	 */
347 	case N_SOL:
348 	    enterfile(name, (Address) np->n_value);
349 	    break;
350 
351 	/*
352 	 * These symbols are assumed to have non-nil names.
353 	 */
354 	case N_GSYM:
355 	case N_FUN:
356 	case N_STSYM:
357 	case N_LCSYM:
358 	case N_RSYM:
359 	case N_PSYM:
360 	case N_LSYM:
361 	case N_SSYM:
362 	case N_LENG:
363 	    if (index(name, ':') == nil) {
364 		if (not warned) {
365 		    warned = true;
366 		    warning("old style symbol information found in \"%s\"",
367 			curfilename());
368 		}
369 	    } else {
370 		entersym(name, np);
371 	    }
372 	    break;
373 
374 	case N_PC:
375 	    break;
376 
377 	default:
378 	    printf("warning:  stab entry unrecognized: ");
379 	    if (name != nil) {
380 		printf("name %s,", name);
381 	    }
382 	    printf("ntype %2x, desc %x, value %x'\n",
383 		np->n_type, np->n_desc, np->n_value);
384 	    break;
385     }
386 }
387 
388 /*
389  * Check to see if a global _name is already in the symbol table,
390  * if not then insert it.
391  */
392 
393 private check_global(name, np)
394 String name;
395 register struct nlist *np;
396 {
397     register Name n;
398     register Symbol t, u;
399 
400     if (not streq(name, "end")) {
401 	n = identname(name, true);
402 	if ((np->n_type&N_TYPE) == N_TEXT) {
403 	    find(t, n) where
404 		t->level == program->level and
405 		(t->class == PROC or t->class == FUNC)
406 	    endfind(t);
407 	    if (t == nil) {
408 		t = insert(n);
409 		t->language = findlanguage(".s");
410 		t->class = FUNC;
411 		t->type = t_int;
412 		t->block = curblock;
413 		t->level = program->level;
414 		t->symvalue.funcv.src = false;
415 		t->symvalue.funcv.inline = false;
416 	    }
417 	    t->symvalue.funcv.beginaddr = np->n_value;
418 	    newfunc(t, codeloc(t));
419 	    findbeginning(t);
420 	} else if ((np->n_type&N_TYPE) == N_BSS) {
421 	    find(t, n) where
422 		t->class == COMMON
423 	    endfind(t);
424 	    if (t != nil) {
425 		u = (Symbol) t->symvalue.common.offset;
426 		while (u != nil) {
427 		    u->symvalue.offset = u->symvalue.common.offset+np->n_value;
428 		    u = u->symvalue.common.chain;
429 		}
430             } else {
431 		check_var(np, n);
432 	    }
433         } else {
434 	    check_var(np, n);
435 	}
436     }
437 }
438 
439 /*
440  * Check to see if a namelist entry refers to a variable.
441  * If not, create a variable for the entry.  In any case,
442  * set the offset of the variable according to the value field
443  * in the entry.
444  */
445 
446 private check_var(np, n)
447 struct nlist *np;
448 register Name n;
449 {
450     register Symbol t;
451 
452     find(t, n) where
453 	t->class == VAR and t->level == program->level
454     endfind(t);
455     if (t == nil) {
456 	t = insert(n);
457 	t->language = findlanguage(".s");
458 	t->class = VAR;
459 	t->type = t_int;
460 	t->level = program->level;
461     }
462     t->block = curblock;
463     t->symvalue.offset = np->n_value;
464 }
465 
466 /*
467  * Check to see if a local _name is known in the current scope.
468  * If not then enter it.
469  */
470 
471 private check_local(name, np)
472 String name;
473 register struct nlist *np;
474 {
475     register Name n;
476     register Symbol t, cur;
477 
478     n = identname(name, true);
479     cur = ((np->n_type&N_TYPE) == N_TEXT) ? curmodule : curblock;
480     find(t, n) where t->block == cur endfind(t);
481     if (t == nil) {
482 	t = insert(n);
483 	t->language = findlanguage(".s");
484 	t->type = t_int;
485 	t->block = cur;
486 	t->level = cur->level;
487 	if ((np->n_type&N_TYPE) == N_TEXT) {
488 	    t->class = FUNC;
489 	    t->symvalue.funcv.src = false;
490 	    t->symvalue.funcv.inline = false;
491 	    t->symvalue.funcv.beginaddr = np->n_value;
492 	    newfunc(t, codeloc(t));
493 	    findbeginning(t);
494 	} else {
495 	    t->class = VAR;
496 	    t->symvalue.offset = np->n_value;
497 	}
498     }
499 }
500 
501 /*
502  * Check to see if a symbol corresponds to a object file name.
503  * For some reason these are listed as in the text segment.
504  */
505 
506 private check_filename(name)
507 String name;
508 {
509     register String mname;
510     register Integer i;
511     register Symbol s;
512 
513     mname = strdup(name);
514     i = strlen(mname) - 2;
515     if (i >= 0 and mname[i] == '.' and mname[i+1] == 'o') {
516 	mname[i] = '\0';
517 	--i;
518 	while (mname[i] != '/' and i >= 0) {
519 	    --i;
520 	}
521 	s = insert(identname(&mname[i+1], true));
522 	s->language = findlanguage(".s");
523 	s->class = MODULE;
524 	s->symvalue.funcv.beginaddr = 0;
525 	findbeginning(s);
526 	if (curblock->class != PROG) {
527 	    exitblock();
528 	    if (curblock->class != PROG) {
529 		exitblock();
530 	    }
531 	}
532 	enterblock(s);
533 	curmodule = s;
534     }
535 }
536 
537 /*
538  * Check to see if a symbol is about to be defined within an unnamed block.
539  * If this happens, we create a procedure for the unnamed block, make it
540  * "inline" so that tracebacks don't associate an activation record with it,
541  * and enter it into the function table so that it will be detected
542  * by "whatblock".
543  */
544 
545 private unnamed_block()
546 {
547     register Symbol s;
548     static int bnum = 0;
549     char buf[100];
550 
551     ++bnum;
552     sprintf(buf, "$b%d", bnum);
553     s = insert(identname(buf, false));
554     s->class = PROG;
555     s->symvalue.funcv.src = false;
556     s->symvalue.funcv.inline = true;
557     s->symvalue.funcv.beginaddr = addrstk[nesting];
558     enterblock(s);
559     newfunc(s, addrstk[nesting]);
560     addrstk[nesting] = NOADDR;
561 }
562 
563 /*
564  * Compilation unit.  C associates scope with filenames
565  * so we treat them as "modules".  The filename without
566  * the suffix is used for the module name.
567  *
568  * Because there is no explicit "end-of-block" mark in
569  * the object file, we must exit blocks for the current
570  * procedure and module.
571  */
572 
573 private enterSourceModule(n, addr)
574 Name n;
575 Address addr;
576 {
577     register Symbol s;
578     Name nn;
579     String mname, suffix;
580 
581     mname = strdup(ident(n));
582     if (rindex(mname, '/') != nil) {
583 	mname = rindex(mname, '/') + 1;
584     }
585     suffix = rindex(mname, '.');
586     curlang = findlanguage(suffix);
587     if (curlang == findlanguage(".f")) {
588 	strip_ = true;
589     }
590     if (suffix != nil) {
591 	*suffix = '\0';
592     }
593     if (curblock->class != PROG) {
594 	exitblock();
595 	if (curblock->class != PROG) {
596 	    exitblock();
597 	}
598     }
599     nn = identname(mname, true);
600     if (curmodule == nil or curmodule->name != nn) {
601 	s = insert(nn);
602 	s->class = MODULE;
603 	s->symvalue.funcv.beginaddr = 0;
604 	findbeginning(s);
605     } else {
606 	s = curmodule;
607     }
608     s->language = curlang;
609     enterblock(s);
610     curmodule = s;
611     if (program->language == nil) {
612 	program->language = curlang;
613     }
614     warned = false;
615     enterfile(ident(n), addr);
616     bzero(typetable, sizeof(typetable));
617 }
618 
619 /*
620  * Put an nlist into the symbol table.
621  * If it's already there just add the associated information.
622  *
623  * Type information is encoded in the name following a ":".
624  */
625 
626 private Symbol constype();
627 private Char *curchar;
628 
629 #define skipchar(ptr, ch) { \
630     if (*ptr != ch) { \
631 	panic("expected char '%c', found char '%c'", ch, *ptr); \
632     } \
633     ++ptr; \
634 }
635 
636 private entersym(str, np)
637 String str;
638 struct nlist *np;
639 {
640     register Symbol s;
641     register char *p;
642     register int c;
643     register Name n;
644     register Integer i;
645     Boolean knowtype, isnew;
646     Symclass class;
647     Integer level;
648 
649     p = index(str, ':');
650     *p = '\0';
651     c = *(p+1);
652     n = identname(str, true);
653     if (index("FfGV", c) != nil) {
654 	if (c == 'F' or c == 'f') {
655 	    class = FUNC;
656 	} else {
657 	    class = VAR;
658 	}
659 	level = (c == 'f' ? curmodule->level : program->level);
660 	find(s, n) where s->level == level and s->class == class endfind(s);
661 	if (s == nil) {
662 	    isnew = true;
663 	    s = insert(n);
664 	} else {
665 	    isnew = false;
666 	}
667     } else {
668 	isnew = true;
669 	s = insert(n);
670     }
671 
672     if (nesting > 0 and addrstk[nesting] != NOADDR) {
673 	unnamed_block();
674     }
675 
676     /*
677      * Default attributes.
678      */
679     s->language = curlang;
680     s->class = VAR;
681     s->block = curblock;
682     s->level = curlevel;
683     s->symvalue.offset = np->n_value;
684     curchar = p + 2;
685     knowtype = false;
686     switch (c) {
687 	case 't':	/* type name */
688 	    s->class = TYPE;
689 	    i = getint();
690 	    if (i == 0) {
691 		panic("bad input on type \"%s\" at \"%s\"", symname(s),
692 		    curchar);
693 	    } else if (i >= NTYPES) {
694 		panic("too many types in file \"%s\"", curfilename());
695 	    }
696 	    /*
697 	     * A hack for C typedefs that don't create new types,
698 	     * e.g. typedef unsigned int Hashvalue;
699 	     *  or  typedef struct blah BLAH;
700 	     */
701 	    if (*curchar == '\0') {
702 		s->type = typetable[i];
703 		if (s->type == nil) {
704 		    s->type = symbol_alloc();
705 		    typetable[i] = s->type;
706 		}
707 		knowtype = true;
708 	    } else {
709 		typetable[i] = s;
710 		skipchar(curchar, '=');
711 	    }
712 	    break;
713 
714 	case 'T':	/* tag */
715 	    s->class = TAG;
716 	    i = getint();
717 	    if (i == 0) {
718 		panic("bad input on tag \"%s\" at \"%s\"", symname(s),
719 		    curchar);
720 	    } else if (i >= NTYPES) {
721 		panic("too many types in file \"%s\"", curfilename());
722 	    }
723 	    if (typetable[i] != nil) {
724 		typetable[i]->language = curlang;
725 		typetable[i]->class = TYPE;
726 		typetable[i]->type = s;
727 	    } else {
728 		typetable[i] = s;
729 	    }
730 	    skipchar(curchar, '=');
731 	    break;
732 
733 	case 'F':	/* public function */
734 	case 'f':	/* private function */
735 	    s->class = FUNC;
736 	    if (curblock->class == FUNC or curblock->class == PROC) {
737 		exitblock();
738 	    }
739 	    enterblock(s);
740 	    if (c == 'F') {
741 		s->level = program->level;
742 		isnew = false;
743 	    }
744 	    curparam = s;
745 	    if (isnew) {
746 		s->symvalue.funcv.src = false;
747 		s->symvalue.funcv.inline = false;
748 		s->symvalue.funcv.beginaddr = np->n_value;
749 		newfunc(s, codeloc(s));
750 		findbeginning(s);
751 	    }
752 	    break;
753 
754 	case 'G':	/* public variable */
755 	    s->level = program->level;
756 	    break;
757 
758 	case 'S':	/* private variable */
759 	    s->level = curmodule->level;
760 	    s->block = curmodule;
761 	    break;
762 
763 /*
764  *  keep global BSS variables chained so can resolve when get the start
765  *  of common; keep the list in order so f77 can display all vars in a COMMON
766 */
767 	case 'V':	/* own variable */
768 	    s->level = 2;
769 	    if (curcomm) {
770 	      if (commchain != nil) {
771  		  commchain->symvalue.common.chain = s;
772 	      }
773 	      else {
774 		  curcomm->symvalue.common.offset = (int) s;
775 	      }
776               commchain = s;
777               s->symvalue.common.offset = np->n_value;
778               s->symvalue.common.chain = nil;
779 	    }
780 	    break;
781 
782 	case 'r':	/* register variable */
783 	    s->level = -(s->level);
784 	    break;
785 
786 	case 'p':	/* parameter variable */
787 	    curparam->chain = s;
788 	    curparam = s;
789 	    break;
790 
791 	case 'v':	/* varies parameter */
792 	    s->class = REF;
793 	    s->symvalue.offset = np->n_value;
794 	    curparam->chain = s;
795 	    curparam = s;
796 	    break;
797 
798 	default:	/* local variable */
799 	    --curchar;
800 	    break;
801     }
802     if (not knowtype) {
803 	s->type = constype(nil);
804 	if (s->class == TAG) {
805 	    addtag(s);
806 	}
807     }
808     if (tracesyms) {
809 	printdecl(s);
810 	fflush(stdout);
811     }
812 }
813 
814 /*
815  * Construct a type out of a string encoding.
816  *
817  * The forms of the string are
818  *
819  *	<number>
820  *	<number>=<type>
821  *	r<type>;<number>;<number>		$ subrange
822  *	a<type>;<type>				$ array[index] of element
823  *	s{<name>:<type>;<number>;<number>}	$ record
824  *	*<type>					$ pointer
825  */
826 
827 private Symbol constype(type)
828 Symbol type;
829 {
830     register Symbol t, u;
831     register Char *p, *cur;
832     register Integer n;
833     Integer b;
834     Name name;
835     Char class;
836 
837     b = curlevel;
838     if (isdigit(*curchar)) {
839 	n = getint();
840 	if (n == 0) {
841 	    panic("bad type number at \"%s\"", curchar);
842 	} else if (n >= NTYPES) {
843 	    panic("too many types in file \"%s\"", curfilename());
844 	}
845 	if (*curchar == '=') {
846 	    if (typetable[n] != nil) {
847 		t = typetable[n];
848 	    } else {
849 		t = symbol_alloc();
850 		typetable[n] = t;
851 	    }
852 	    ++curchar;
853 	    constype(t);
854 	} else {
855 	    t = typetable[n];
856 	    if (t == nil) {
857 		t = symbol_alloc();
858 		typetable[n] = t;
859 	    }
860 	}
861     } else {
862 	if (type == nil) {
863 	    t = symbol_alloc();
864 	} else {
865 	    t = type;
866 	}
867 	t->language = curlang;
868 	t->level = b;
869 	t->block = curblock;
870 	class = *curchar++;
871 	switch (class) {
872 
873 	    case 'r':
874 		t->class = RANGE;
875 		t->type = constype(nil);
876 		skipchar(curchar, ';');
877                 /* some letters indicate a dynamic bound, ie what follows
878                    is the offset from the fp which contains the bound; this will
879                    need a different encoding when pc a['A'..'Z'] is
880                    added; J is a special flag to handle fortran a(*) bounds
881                 */
882 		switch(*curchar) {
883 			case 'A':
884 				t->symvalue.rangev.lowertype = R_ARG;
885                   		curchar++;
886 			        break;
887 
888 			case 'T':
889 				t->symvalue.rangev.lowertype = R_TEMP;
890                   		curchar++;
891 			        break;
892 
893 			case 'J':
894 				t->symvalue.rangev.lowertype = R_ADJUST;
895                   		curchar++;
896 			  	break;
897 
898 			default:
899 				 t->symvalue.rangev.lowertype = R_CONST;
900 			  	 break;
901 
902 		}
903 	        t->symvalue.rangev.lower = getint();
904 		skipchar(curchar, ';');
905 		switch(*curchar) {
906 			case 'A':
907 				t->symvalue.rangev.uppertype = R_ARG;
908                   		curchar++;
909 			        break;
910 
911 			case 'T':
912 				t->symvalue.rangev.uppertype = R_TEMP;
913                   		curchar++;
914 			        break;
915 
916 			case 'J':
917 				t->symvalue.rangev.uppertype = R_ADJUST;
918                   		curchar++;
919 			  	break;
920 
921 			default:
922 				 t->symvalue.rangev.uppertype = R_CONST;
923 			  	 break;
924 
925 		}
926 		t->symvalue.rangev.upper = getint();
927 		break;
928 
929 	    case 'a':
930 		t->class = ARRAY;
931 		t->chain = constype(nil);
932 		skipchar(curchar, ';');
933 		t->type = constype(nil);
934 		break;
935 
936 	    case 's':
937 	    case 'u':
938 		t->class = (class == 's') ? RECORD : VARNT;
939 		t->symvalue.offset = getint();
940 		u = t;
941 		cur = curchar;
942 		while (*cur != ';' and *cur != '\0') {
943 		    p = index(cur, ':');
944 		    if (p == nil) {
945 			panic("index(\"%s\", ':') failed", curchar);
946 		    }
947 		    *p = '\0';
948 		    name = identname(cur, true);
949 		    u->chain = newSymbol(name, b, FIELD, nil, nil);
950 		    cur = p + 1;
951 		    u = u->chain;
952 		    u->language = curlang;
953 		    curchar = cur;
954 		    u->type = constype(nil);
955 		    skipchar(curchar, ',');
956 		    u->symvalue.field.offset = getint();
957 		    skipchar(curchar, ',');
958 		    u->symvalue.field.length = getint();
959 		    skipchar(curchar, ';');
960 		    cur = curchar;
961 		}
962 		if (*cur == ';') {
963 		    ++cur;
964 		}
965 		curchar = cur;
966 		break;
967 
968 	    case 'e':
969 		t->class = SCAL;
970 		u = t;
971 		while (*curchar != ';' and *curchar != '\0') {
972 		    p = index(curchar, ':');
973 		    assert(p != nil);
974 		    *p = '\0';
975 		    u->chain = insert(identname(curchar, true));
976 		    curchar = p + 1;
977 		    u = u->chain;
978 		    u->language = curlang;
979 		    u->class = CONST;
980 		    u->level = b;
981 		    u->block = curblock;
982 		    u->type = t;
983 		    u->symvalue.iconval = getint();
984 		    skipchar(curchar, ',');
985 		}
986 		break;
987 
988 	    case '*':
989 		t->class = PTR;
990 		t->type = constype(nil);
991 		break;
992 
993 	    case 'f':
994 		t->class = FUNC;
995 		t->type = constype(nil);
996 		break;
997 
998 	    default:
999 		badcaseval(class);
1000 	}
1001     }
1002     return t;
1003 }
1004 
1005 /*
1006  * Read an integer from the current position in the type string.
1007  */
1008 
1009 private Integer getint()
1010 {
1011     register Integer n;
1012     register char *p;
1013     register Boolean isneg;
1014 
1015     n = 0;
1016     p = curchar;
1017     if (*p == '-') {
1018 	isneg = true;
1019 	++p;
1020     } else {
1021 	isneg = false;
1022     }
1023     while (isdigit(*p)) {
1024 	n = 10*n + (*p - '0');
1025 	++p;
1026     }
1027     curchar = p;
1028     return isneg ? (-n) : n;
1029 }
1030 
1031 /*
1032  * Add a tag name.  This is a kludge to be able to refer
1033  * to tags that have the same name as some other symbol
1034  * in the same block.
1035  */
1036 
1037 private addtag(s)
1038 register Symbol s;
1039 {
1040     register Symbol t;
1041     char buf[100];
1042 
1043     sprintf(buf, "$$%.90s", ident(s->name));
1044     t = insert(identname(buf, false));
1045     t->language = s->language;
1046     t->class = TAG;
1047     t->type = s->type;
1048     t->block = s->block;
1049 }
1050 
1051 /*
1052  * Allocate file and line tables and initialize indices.
1053  */
1054 
1055 private allocmaps(nf, nl)
1056 Integer nf, nl;
1057 {
1058     if (filetab != nil) {
1059 	dispose(filetab);
1060     }
1061     if (linetab != nil) {
1062 	dispose(linetab);
1063     }
1064     filetab = newarr(Filetab, nf);
1065     linetab = newarr(Linetab, nl);
1066     filep = filetab;
1067     linep = linetab;
1068 }
1069 
1070 /*
1071  * Add a file to the file table.
1072  *
1073  * If the new address is the same as the previous file address
1074  * this routine used to not enter the file, but this caused some
1075  * problems so it has been removed.  It's not clear that this in
1076  * turn may not also cause a problem.
1077  */
1078 
1079 private enterfile(filename, addr)
1080 String filename;
1081 Address addr;
1082 {
1083     filep->addr = addr;
1084     filep->filename = filename;
1085     filep->lineindex = linep - linetab;
1086     ++filep;
1087 }
1088 
1089 /*
1090  * Since we only estimated the number of lines (and it was a poor
1091  * estimation) and since we need to know the exact number of lines
1092  * to do a binary search, we set it when we're done.
1093  */
1094 
1095 private setnlines()
1096 {
1097     nlhdr.nlines = linep - linetab;
1098 }
1099 
1100 /*
1101  * Similarly for nfiles ...
1102  */
1103 
1104 private setnfiles()
1105 {
1106     nlhdr.nfiles = filep - filetab;
1107     setsource(filetab[0].filename);
1108 }
1109