xref: /csrg-svn/old/dbx/object.c (revision 11558)
19673Slinton /* Copyright (c) 1982 Regents of the University of California */
29673Slinton 
3*11558Slinton static char sccsid[] = "@(#)object.c 1.5 03/13/83";
49673Slinton 
59673Slinton /*
69673Slinton  * Object code interface, mainly for extraction of symbolic information.
79673Slinton  */
89673Slinton 
99673Slinton #include "defs.h"
109673Slinton #include "object.h"
119673Slinton #include "main.h"
129673Slinton #include "symbols.h"
139673Slinton #include "names.h"
149673Slinton #include "languages.h"
159673Slinton #include "mappings.h"
169673Slinton #include "lists.h"
179673Slinton #include <a.out.h>
189673Slinton #include <stab.h>
199673Slinton #include <ctype.h>
209673Slinton 
219673Slinton #ifndef public
229673Slinton 
239673Slinton struct {
249673Slinton     unsigned int stringsize;	/* size of the dumped string table */
259673Slinton     unsigned int nsyms;		/* number of symbols */
269673Slinton     unsigned int nfiles;	/* number of files */
279673Slinton     unsigned int nlines;	/* number of lines */
289673Slinton } nlhdr;
299673Slinton 
309673Slinton #endif
319673Slinton 
329673Slinton public String objname = "a.out";
339673Slinton public Integer objsize;
349673Slinton public char *stringtab;
359673Slinton 
369673Slinton private String progname = nil;
379673Slinton private Language curlang;
389673Slinton private Symbol curmodule;
399673Slinton private Symbol curparam;
409673Slinton private Boolean warned;
419673Slinton 
429673Slinton private Filetab *filep;
439673Slinton private Linetab *linep;
449673Slinton private Address curfaddr;
459673Slinton 
469673Slinton #define curfilename() (filep-1)->filename
479673Slinton 
489673Slinton /*
499673Slinton  * Blocks are figured out on the fly while reading the symbol table.
509673Slinton  */
519673Slinton 
529673Slinton #define MAXBLKDEPTH 25
539673Slinton 
549673Slinton private Symbol curblock;
559673Slinton private Symbol blkstack[MAXBLKDEPTH];
569673Slinton private Integer curlevel;
579673Slinton 
589673Slinton #define enterblock(b) { \
599673Slinton     blkstack[curlevel] = curblock; \
609673Slinton     ++curlevel; \
619673Slinton     b->level = curlevel; \
629673Slinton     b->block = curblock; \
639673Slinton     curblock = b; \
649673Slinton }
659673Slinton 
669673Slinton #define exitblock() { \
679673Slinton     --curlevel; \
689673Slinton     curblock = blkstack[curlevel]; \
699673Slinton }
709673Slinton 
719673Slinton /*
729673Slinton  * Enter a source line or file name reference into the appropriate table.
739673Slinton  * Expanded inline to reduce procedure calls.
749673Slinton  *
759673Slinton  * private enterline(linenumber, address)
769673Slinton  * Lineno linenumber;
779673Slinton  * Address address;
789673Slinton  *  ...
799673Slinton  */
809673Slinton 
819673Slinton #define enterline(linenumber, address) \
829673Slinton { \
839673Slinton     register Linetab *lp; \
849673Slinton  \
859673Slinton     lp = linep - 1; \
869673Slinton     if (linenumber != lp->line) { \
879673Slinton 	if (address != lp->addr) { \
889673Slinton 	    ++lp; \
899673Slinton 	} \
909673Slinton 	lp->line = linenumber; \
919673Slinton 	lp->addr = address; \
929673Slinton 	linep = lp + 1; \
939673Slinton     } \
949673Slinton }
959673Slinton 
969673Slinton #define NTYPES 1000
979673Slinton 
989673Slinton private Symbol typetable[NTYPES];
999673Slinton 
1009673Slinton /*
1019673Slinton  * Read in the namelist from the obj file.
1029673Slinton  *
1039673Slinton  * Reads and seeks are used instead of fread's and fseek's
1049673Slinton  * for efficiency sake; there's a lot of data being read here.
1059673Slinton  */
1069673Slinton 
1079673Slinton public readobj(file)
1089673Slinton String file;
1099673Slinton {
1109673Slinton     Fileid f;
1119673Slinton     struct exec hdr;
1129673Slinton     struct nlist nlist;
1139673Slinton 
1149673Slinton     f = open(file, 0);
1159673Slinton     if (f < 0) {
1169673Slinton 	fatal("can't open %s", file);
1179673Slinton     }
1189673Slinton     read(f, &hdr, sizeof(hdr));
1199673Slinton     objsize = hdr.a_text;
1209673Slinton     nlhdr.nsyms = hdr.a_syms / sizeof(nlist);
1219673Slinton     nlhdr.nfiles = nlhdr.nsyms;
1229673Slinton     nlhdr.nlines = nlhdr.nsyms;
1239673Slinton     lseek(f, (long) N_STROFF(hdr), 0);
1249673Slinton     read(f, &(nlhdr.stringsize), sizeof(nlhdr.stringsize));
1259673Slinton     nlhdr.stringsize -= 4;
1269673Slinton     stringtab = newarr(char, nlhdr.stringsize);
1279673Slinton     read(f, stringtab, nlhdr.stringsize);
1289673Slinton     allocmaps(nlhdr.nfiles, nlhdr.nlines);
1299673Slinton     lseek(f, (long) N_SYMOFF(hdr), 0);
1309673Slinton     readsyms(f);
1319673Slinton     ordfunctab();
1329673Slinton     setnlines();
1339673Slinton     setnfiles();
1349673Slinton     close(f);
1359673Slinton }
1369673Slinton 
1379673Slinton /*
1389673Slinton  * Read in symbols from object file.
1399673Slinton  */
1409673Slinton 
1419673Slinton private readsyms(f)
1429673Slinton Fileid f;
1439673Slinton {
1449673Slinton     struct nlist *namelist;
1459673Slinton     register struct nlist *np, *ub;
1469673Slinton     register int index;
1479673Slinton     register String name;
1489673Slinton     register Boolean afterlg;
1499673Slinton 
1509673Slinton     initsyms();
1519673Slinton     namelist = newarr(struct nlist, nlhdr.nsyms);
1529673Slinton     read(f, namelist, nlhdr.nsyms * sizeof(struct nlist));
1539673Slinton     afterlg = false;
1549673Slinton     ub = &namelist[nlhdr.nsyms];
1559673Slinton     for (np = &namelist[0]; np < ub; np++) {
1569673Slinton 	index = np->n_un.n_strx;
1579673Slinton 	if (index != 0) {
1589673Slinton 	    name = &stringtab[index - 4];
1599673Slinton 	} else {
1609673Slinton 	    name = nil;
1619673Slinton 	}
1629673Slinton 	/*
1639673Slinton 	 * assumptions:
1649673Slinton 	 *	not an N_STAB	==> name != nil
1659673Slinton 	 *	name[0] == '-'	==> name == "-lg"
1669673Slinton 	 *	name[0] != '_'	==> filename or invisible
1679673Slinton 	 *
1689673Slinton 	 * The "-lg" signals the beginning of global loader symbols.
1699673Slinton 	 */
1709673Slinton 	if ((np->n_type&N_STAB) != 0) {
1719673Slinton 	    enter_nl(name, np);
1729673Slinton 	} else if (name[0] == '-') {
1739673Slinton 	    afterlg = true;
1749673Slinton 	    if (curblock->class != PROG) {
1759673Slinton 		exitblock();
1769673Slinton 		if (curblock->class != PROG) {
1779673Slinton 		    exitblock();
1789673Slinton 		}
1799673Slinton 	    }
1809673Slinton 	    enterline(0, (linep-1)->addr + 1);
18111104Slinton 	} else if (afterlg) {
18211104Slinton 	    if (name[0] == '_') {
1839673Slinton 		check_global(&name[1], np);
1849673Slinton 	    }
18511104Slinton 	} else if (name[0] == '_') {
18611104Slinton 	    check_local(&name[1], np);
1879673Slinton 	} else if ((np->n_type&N_TEXT) == N_TEXT) {
1889673Slinton 	    check_filename(name);
1899673Slinton 	}
1909673Slinton     }
1919673Slinton     dispose(namelist);
1929673Slinton }
1939673Slinton 
1949673Slinton /*
1959673Slinton  * Initialize symbol information.
1969673Slinton  */
1979673Slinton 
1989673Slinton private initsyms()
1999673Slinton {
2009673Slinton     curblock = nil;
2019673Slinton     curlevel = 0;
2029673Slinton     if (progname == nil) {
2039673Slinton 	progname = strdup(objname);
2049673Slinton 	if (rindex(progname, '/') != nil) {
2059673Slinton 	    progname = rindex(progname, '/') + 1;
2069673Slinton 	}
2079673Slinton 	if (index(progname, '.') != nil) {
2089673Slinton 	    *(index(progname, '.')) = '\0';
2099673Slinton 	}
2109673Slinton     }
2119673Slinton     program = insert(identname(progname, true));
2129673Slinton     program->class = PROG;
2139673Slinton     newfunc(program);
2149673Slinton     findbeginning(program);
2159673Slinton     enterblock(program);
2169673Slinton     curmodule = program;
2179673Slinton     t_boolean = maketype("$boolean", 0L, 1L);
2189673Slinton     t_int = maketype("$integer", 0x80000000L, 0x7fffffffL);
2199673Slinton     t_char = maketype("$char", 0L, 127L);
2209673Slinton     t_real = maketype("$real", 4L, 0L);
2219673Slinton     t_nil = maketype("$nil", 0L, 0L);
2229673Slinton }
2239673Slinton 
2249673Slinton /*
2259673Slinton  * Free all the object file information that's being stored.
2269673Slinton  */
2279673Slinton 
2289673Slinton public objfree()
2299673Slinton {
2309673Slinton     symbol_free();
2319673Slinton     keywords_free();
2329673Slinton     names_free();
2339673Slinton     dispose(stringtab);
2349673Slinton     clrfunctab();
2359673Slinton }
2369673Slinton 
2379673Slinton /*
2389673Slinton  * Enter a namelist entry.
2399673Slinton  */
2409673Slinton 
2419673Slinton private enter_nl(name, np)
2429673Slinton String name;
2439673Slinton register struct nlist *np;
2449673Slinton {
2459673Slinton     register Symbol s;
2469673Slinton     String mname, suffix;
2479673Slinton     register Name n;
2489673Slinton     register Symbol *tt;
2499673Slinton 
2509673Slinton     s = nil;
2519673Slinton     if (name == nil) {
2529673Slinton 	n = nil;
2539673Slinton     } else {
2549673Slinton 	n = identname(name, true);
2559673Slinton     }
2569673Slinton     switch (np->n_type) {
2579673Slinton 	case N_LBRAC:
2589673Slinton 	    s = symbol_alloc();
2599673Slinton 	    s->class = PROC;
2609673Slinton 	    enterblock(s);
2619673Slinton 	    break;
2629673Slinton 
2639673Slinton 	case N_RBRAC:
2649673Slinton 	    exitblock();
2659673Slinton 	    break;
2669673Slinton 
2679673Slinton 	case N_SLINE:
2689673Slinton 	    enterline((Lineno) np->n_desc, (Address) np->n_value);
2699673Slinton 	    break;
2709673Slinton 
2719673Slinton 	/*
2729673Slinton 	 * Compilation unit.  C associates scope with filenames
2739673Slinton 	 * so we treat them as "modules".  The filename without
2749673Slinton 	 * the suffix is used for the module name.
2759673Slinton 	 *
2769673Slinton 	 * Because there is no explicit "end-of-block" mark in
2779673Slinton 	 * the object file, we must exit blocks for the current
2789673Slinton 	 * procedure and module.
2799673Slinton 	 */
2809673Slinton 	case N_SO:
2819673Slinton 	    mname = strdup(ident(n));
2829673Slinton 	    if (rindex(mname, '/') != nil) {
2839673Slinton 		mname = rindex(mname, '/') + 1;
2849673Slinton 	    }
2859673Slinton 	    suffix = rindex(mname, '.');
2869673Slinton 	    curlang = findlanguage(suffix);
2879673Slinton 	    if (suffix != nil) {
2889673Slinton 		*suffix = '\0';
2899673Slinton 	    }
2909673Slinton 	    if (curblock->class != PROG) {
2919673Slinton 		exitblock();
2929673Slinton 		if (curblock->class != PROG) {
2939673Slinton 		    exitblock();
2949673Slinton 		}
2959673Slinton 	    }
2969673Slinton 	    s = insert(identname(mname, true));
2979673Slinton 	    s->language = curlang;
2989673Slinton 	    s->class = MODULE;
2999673Slinton 	    enterblock(s);
3009673Slinton 	    curmodule = s;
3019673Slinton 	    if (program->language == nil) {
3029673Slinton 		program->language = curlang;
3039673Slinton 	    }
3049673Slinton 	    warned = false;
3059673Slinton 	    enterfile(ident(n), (Address) np->n_value);
3069673Slinton 	    for (tt = &typetable[0]; tt < &typetable[NTYPES]; tt++) {
3079673Slinton 		*tt = nil;
3089673Slinton 	    }
3099673Slinton 	    break;
3109673Slinton 
3119673Slinton 	/*
3129673Slinton 	 * Textually included files.
3139673Slinton 	 */
3149673Slinton 	case N_SOL:
3159673Slinton 	    enterfile(name, (Address) np->n_value);
3169673Slinton 	    break;
3179673Slinton 
3189673Slinton 	/*
3199673Slinton 	 * These symbols are assumed to have non-nil names.
3209673Slinton 	 */
3219673Slinton 	case N_GSYM:
3229673Slinton 	case N_FUN:
3239673Slinton 	case N_STSYM:
3249673Slinton 	case N_LCSYM:
3259673Slinton 	case N_RSYM:
3269673Slinton 	case N_PSYM:
3279673Slinton 	case N_LSYM:
3289673Slinton 	case N_SSYM:
3299673Slinton 	    if (index(name, ':') == nil) {
3309673Slinton 		if (not warned) {
3319673Slinton 		    warned = true;
3329673Slinton 		    /*
3339673Slinton 		     * Shouldn't do this if user might be typing.
3349673Slinton 		     *
3359673Slinton 		    warning("old style symbol information found in \"%s\"",
3369673Slinton 			curfilename());
3379673Slinton 		     *
3389673Slinton 		     */
3399673Slinton 		}
3409673Slinton 	    } else {
3419673Slinton 		entersym(name, np);
3429673Slinton 	    }
3439673Slinton 	    break;
3449673Slinton 
3459673Slinton 	case N_PC:
3469673Slinton 	    break;
3479673Slinton 
3489840Slinton 	case N_LENG:
349*11558Slinton 	default:
3509840Slinton 	    /*
3519840Slinton 	     * Should complain out this, obviously the wrong symbol format.
352*11558Slinton 	     *
3539673Slinton 	    if (name != nil) {
3549673Slinton 		printf("%s, ", name);
3559673Slinton 	    }
3569673Slinton 	    printf("ntype %2x, desc %x, value %x\n",
3579673Slinton 		np->n_type, np->n_desc, np->n_value);
358*11558Slinton 	     *
359*11558Slinton 	     */
3609673Slinton 	    break;
3619673Slinton     }
3629673Slinton }
3639673Slinton 
3649673Slinton /*
3659673Slinton  * Check to see if a global _name is already in the symbol table,
3669673Slinton  * if not then insert it.
3679673Slinton  */
3689673Slinton 
3699673Slinton private check_global(name, np)
3709673Slinton String name;
3719673Slinton register struct nlist *np;
3729673Slinton {
3739673Slinton     register Name n;
3749673Slinton     register Symbol t;
3759673Slinton 
3769673Slinton     if (not streq(name, "end")) {
3779673Slinton 	n = identname(name, true);
3789673Slinton 	if ((np->n_type&N_TYPE) == N_TEXT) {
3799673Slinton 	    find(t, n) where
3809673Slinton 		t->level == program->level and isblock(t)
3819673Slinton 	    endfind(t);
3829673Slinton 	    if (t == nil) {
3839673Slinton 		t = insert(n);
3849673Slinton 		t->language = findlanguage(".s");
3859673Slinton 		t->class = FUNC;
3869673Slinton 		t->type = t_int;
3879673Slinton 		t->block = curblock;
3889673Slinton 		t->level = program->level;
3899673Slinton 	    }
3909673Slinton 	    t->symvalue.funcv.beginaddr = np->n_value;
3919673Slinton 	    newfunc(t);
3929673Slinton 	    findbeginning(t);
3939673Slinton 	} else {
3949673Slinton 	    find(t, n) where
3959673Slinton 		t->class == VAR and t->level == program->level
3969673Slinton 	    endfind(t);
3979673Slinton 	    if (t == nil) {
3989673Slinton 		t = insert(n);
3999673Slinton 		t->language = findlanguage(".s");
4009673Slinton 		t->class = VAR;
4019673Slinton 		t->type = t_int;
4029673Slinton 		t->block = curblock;
4039673Slinton 		t->level = program->level;
4049673Slinton 	    }
4059673Slinton 	    t->symvalue.offset = np->n_value;
4069673Slinton 	}
4079673Slinton     }
4089673Slinton }
4099673Slinton 
4109673Slinton /*
4119673Slinton  * Check to see if a local _name is known in the current scope.
4129673Slinton  * If not then enter it.
4139673Slinton  */
4149673Slinton 
4159673Slinton private check_local(name, np)
4169673Slinton String name;
4179673Slinton register struct nlist *np;
4189673Slinton {
4199673Slinton     register Name n;
4209673Slinton     register Symbol t, cur;
4219673Slinton 
4229673Slinton     n = identname(name, true);
4239673Slinton     cur = ((np->n_type&N_TYPE) == N_TEXT) ? curmodule : curblock;
4249673Slinton     find(t, n) where t->block == cur endfind(t);
4259673Slinton     if (t == nil) {
4269673Slinton 	t = insert(n);
4279673Slinton 	t->language = findlanguage(".s");
4289673Slinton 	t->type = t_int;
4299673Slinton 	t->block = cur;
4309673Slinton 	t->level = cur->level;
4319673Slinton 	if ((np->n_type&N_TYPE) == N_TEXT) {
4329673Slinton 	    t->class = FUNC;
4339673Slinton 	    t->symvalue.funcv.beginaddr = np->n_value;
4349673Slinton 	    newfunc(t);
4359673Slinton 	    findbeginning(t);
4369673Slinton 	} else {
4379673Slinton 	    t->class = VAR;
4389673Slinton 	    t->symvalue.offset = np->n_value;
4399673Slinton 	}
4409673Slinton     }
4419673Slinton }
4429673Slinton 
4439673Slinton /*
4449673Slinton  * Check to see if a symbol corresponds to a object file name.
4459673Slinton  * For some reason these are listed as in the text segment.
4469673Slinton  */
4479673Slinton 
4489673Slinton private check_filename(name)
4499673Slinton String name;
4509673Slinton {
4519673Slinton     register String mname;
4529673Slinton     register Integer i;
4539673Slinton     register Symbol s;
4549673Slinton 
4559673Slinton     mname = strdup(name);
4569673Slinton     i = strlen(mname) - 2;
4579673Slinton     if (i >= 0 and mname[i] == '.' and mname[i+1] == 'o') {
4589673Slinton 	mname[i] = '\0';
4599673Slinton 	--i;
4609673Slinton 	while (mname[i] != '/' and i >= 0) {
4619673Slinton 	    --i;
4629673Slinton 	}
4639673Slinton 	s = insert(identname(&mname[i+1], true));
4649673Slinton 	s->language = findlanguage(".s");
4659673Slinton 	s->class = MODULE;
4669673Slinton 	if (curblock->class != PROG) {
4679673Slinton 	    exitblock();
4689673Slinton 	    if (curblock->class != PROG) {
4699673Slinton 		exitblock();
4709673Slinton 	    }
4719673Slinton 	}
4729673Slinton 	enterblock(s);
4739673Slinton 	curmodule = s;
4749673Slinton     }
4759673Slinton }
4769673Slinton 
4779673Slinton /*
4789673Slinton  * Put an nlist into the symbol table.
4799673Slinton  * If it's already there just add the associated information.
4809673Slinton  *
4819673Slinton  * Type information is encoded in the name following a ":".
4829673Slinton  */
4839673Slinton 
4849673Slinton private Symbol constype();
4859673Slinton private Char *curchar;
4869673Slinton 
4879673Slinton #define skipchar(ptr, ch) { \
4889673Slinton     if (*ptr != ch) { \
4899673Slinton 	panic("expected char '%c', found char '%c'", ch, *ptr); \
4909673Slinton     } \
4919673Slinton     ++ptr; \
4929673Slinton }
4939673Slinton 
4949673Slinton private entersym(str, np)
4959673Slinton String str;
4969673Slinton struct nlist *np;
4979673Slinton {
4989673Slinton     register Symbol s;
4999673Slinton     register char *p;
5009673Slinton     register int c;
5019673Slinton     register Name n;
5029673Slinton     register Integer i;
5039673Slinton     Boolean knowtype, isnew;
5049673Slinton     Symclass class;
5059673Slinton     Integer level;
5069673Slinton 
5079673Slinton     p = index(str, ':');
5089673Slinton     *p = '\0';
5099673Slinton     c = *(p+1);
5109673Slinton     n = identname(str, true);
5119673Slinton     if (index("FfGV", c) != nil) {
5129673Slinton 	if (c == 'F' or c == 'f') {
5139673Slinton 	    class = FUNC;
5149673Slinton 	} else {
5159673Slinton 	    class = VAR;
5169673Slinton 	}
5179673Slinton 	level = (c == 'f' ? curmodule->level : program->level);
5189673Slinton 	find(s, n) where s->level == level and s->class == class endfind(s);
5199673Slinton 	if (s == nil) {
5209673Slinton 	    isnew = true;
5219673Slinton 	    s = insert(n);
5229673Slinton 	} else {
5239673Slinton 	    isnew = false;
5249673Slinton 	}
5259673Slinton     } else {
5269673Slinton 	isnew = true;
5279673Slinton 	s = insert(n);
5289673Slinton     }
5299673Slinton 
5309673Slinton     /*
5319673Slinton      * Default attributes.
5329673Slinton      */
5339673Slinton     s->language = curlang;
5349673Slinton     s->class = VAR;
5359673Slinton     s->block = curblock;
5369673Slinton     s->level = curlevel;
5379673Slinton     s->symvalue.offset = np->n_value;
5389673Slinton     curchar = p + 2;
5399673Slinton     knowtype = false;
5409673Slinton     switch (c) {
5419673Slinton 	case 't':	/* type name */
5429673Slinton 	    s->class = TYPE;
5439673Slinton 	    i = getint();
5449673Slinton 	    if (i == 0) {
5459673Slinton 		panic("bad input on type \"%s\" at \"%s\"", symname(s),
5469673Slinton 		    curchar);
5479673Slinton 	    } else if (i >= NTYPES) {
5489673Slinton 		panic("too many types in file \"%s\"", curfilename());
5499673Slinton 	    }
5509673Slinton 	    /*
5519673Slinton 	     * A hack for C typedefs that don't create new types,
5529673Slinton 	     * e.g. typedef unsigned int Hashvalue;
553*11558Slinton 	     *  or  typedef struct blah BLAH;
5549673Slinton 	     */
5559673Slinton 	    if (*curchar == '\0') {
5569673Slinton 		s->type = typetable[i];
5579673Slinton 		if (s->type == nil) {
558*11558Slinton 		    s->type = symbol_alloc();
559*11558Slinton 		    typetable[i] = s->type;
5609673Slinton 		}
5619673Slinton 		knowtype = true;
5629673Slinton 	    } else {
5639673Slinton 		typetable[i] = s;
5649673Slinton 		skipchar(curchar, '=');
5659673Slinton 	    }
5669673Slinton 	    break;
5679673Slinton 
5689673Slinton 	case 'T':	/* tag */
5699673Slinton 	    s->class = TAG;
5709673Slinton 	    i = getint();
5719673Slinton 	    if (i == 0) {
5729673Slinton 		panic("bad input on tag \"%s\" at \"%s\"", symname(s),
5739673Slinton 		    curchar);
5749673Slinton 	    } else if (i >= NTYPES) {
5759673Slinton 		panic("too many types in file \"%s\"", curfilename());
5769673Slinton 	    }
5779673Slinton 	    if (typetable[i] != nil) {
5789673Slinton 		typetable[i]->language = curlang;
5799673Slinton 		typetable[i]->class = TYPE;
5809673Slinton 		typetable[i]->type = s;
5819673Slinton 	    } else {
5829673Slinton 		typetable[i] = s;
5839673Slinton 	    }
5849673Slinton 	    skipchar(curchar, '=');
5859673Slinton 	    break;
5869673Slinton 
5879673Slinton 	case 'F':	/* public function */
5889673Slinton 	case 'f':	/* private function */
5899673Slinton 	    s->class = FUNC;
5909673Slinton 	    if (curblock->class == FUNC or curblock->class == PROC) {
5919673Slinton 		exitblock();
5929673Slinton 	    }
5939673Slinton 	    enterblock(s);
5949673Slinton 	    if (c == 'F') {
5959673Slinton 		s->level = program->level;
5969673Slinton 		isnew = false;
5979673Slinton 	    }
5989673Slinton 	    curparam = s;
5999673Slinton 	    if (isnew) {
6009673Slinton 		s->symvalue.funcv.beginaddr = np->n_value;
6019673Slinton 		newfunc(s);
6029673Slinton 		findbeginning(s);
6039673Slinton 	    }
6049673Slinton 	    break;
6059673Slinton 
6069673Slinton 	case 'G':	/* public variable */
6079673Slinton 	    s->level = program->level;
6089673Slinton 	    break;
6099673Slinton 
6109673Slinton 	case 'S':	/* private variable */
6119673Slinton 	    s->level = curmodule->level;
6129673Slinton 	    s->block = curmodule;
6139673Slinton 	    break;
6149673Slinton 
6159673Slinton 	case 'V':	/* own variable */
6169673Slinton 	    s->level = 2;
6179673Slinton 	    break;
6189673Slinton 
6199673Slinton 	case 'r':	/* register variable */
6209673Slinton 	    s->level = -(s->level);
6219673Slinton 	    break;
6229673Slinton 
6239673Slinton 	case 'p':	/* parameter variable */
6249673Slinton 	    curparam->chain = s;
6259673Slinton 	    curparam = s;
6269673Slinton 	    break;
6279673Slinton 
6289673Slinton 	case 'v':	/* varies parameter */
6299673Slinton 	    s->class = REF;
6309673Slinton 	    s->symvalue.offset = np->n_value;
6319673Slinton 	    curparam->chain = s;
6329673Slinton 	    curparam = s;
6339673Slinton 	    break;
6349673Slinton 
6359673Slinton 	default:	/* local variable */
6369673Slinton 	    --curchar;
6379673Slinton 	    break;
6389673Slinton     }
6399673Slinton     if (not knowtype) {
6409673Slinton 	s->type = constype(nil);
6419673Slinton 	if (s->class == TAG) {
6429673Slinton 	    addtag(s);
6439673Slinton 	}
6449673Slinton     }
6459673Slinton     if (tracesyms) {
6469673Slinton 	printdecl(s);
6479673Slinton 	fflush(stdout);
6489673Slinton     }
6499673Slinton }
6509673Slinton 
6519673Slinton /*
6529673Slinton  * Construct a type out of a string encoding.
6539673Slinton  *
6549673Slinton  * The forms of the string are
6559673Slinton  *
6569673Slinton  *	<number>
6579673Slinton  *	<number>=<type>
6589673Slinton  *	r<type>;<number>;<number>		$ subrange
6599673Slinton  *	a<type>;<type>				$ array[index] of element
6609673Slinton  *	s{<name>:<type>;<number>;<number>}	$ record
6619673Slinton  *	*<type>					$ pointer
6629673Slinton  */
6639673Slinton 
6649673Slinton private Symbol constype(type)
6659673Slinton Symbol type;
6669673Slinton {
6679673Slinton     register Symbol t, u;
6689673Slinton     register Char *p, *cur;
6699673Slinton     register Integer n;
6709673Slinton     Integer b;
6719673Slinton     Name name;
6729673Slinton     Char class;
6739673Slinton 
6749673Slinton     b = curlevel;
6759673Slinton     if (isdigit(*curchar)) {
6769673Slinton 	n = getint();
6779673Slinton 	if (n == 0) {
6789673Slinton 	    panic("bad type number at \"%s\"", curchar);
6799673Slinton 	} else if (n >= NTYPES) {
6809673Slinton 	    panic("too many types in file \"%s\"", curfilename());
6819673Slinton 	}
6829673Slinton 	if (*curchar == '=') {
6839673Slinton 	    if (typetable[n] != nil) {
6849673Slinton 		t = typetable[n];
6859673Slinton 	    } else {
6869673Slinton 		t = symbol_alloc();
6879673Slinton 		typetable[n] = t;
6889673Slinton 	    }
6899673Slinton 	    ++curchar;
6909673Slinton 	    constype(t);
6919673Slinton 	} else {
6929673Slinton 	    t = typetable[n];
6939673Slinton 	    if (t == nil) {
6949673Slinton 		t = symbol_alloc();
6959673Slinton 		typetable[n] = t;
6969673Slinton 	    }
6979673Slinton 	}
6989673Slinton     } else {
6999673Slinton 	if (type == nil) {
7009673Slinton 	    t = symbol_alloc();
7019673Slinton 	} else {
7029673Slinton 	    t = type;
7039673Slinton 	}
7049673Slinton 	t->language = curlang;
7059673Slinton 	t->level = b;
7069673Slinton 	class = *curchar++;
7079673Slinton 	switch (class) {
7089673Slinton 	    case 'r':
7099673Slinton 		t->class = RANGE;
7109673Slinton 		t->type = constype(nil);
7119673Slinton 		skipchar(curchar, ';');
7129673Slinton 		t->symvalue.rangev.lower = getint();
7139673Slinton 		skipchar(curchar, ';');
7149673Slinton 		t->symvalue.rangev.upper = getint();
7159673Slinton 		break;
7169673Slinton 
7179673Slinton 	    case 'a':
7189673Slinton 		t->class = ARRAY;
7199673Slinton 		t->chain = constype(nil);
7209673Slinton 		skipchar(curchar, ';');
7219673Slinton 		t->type = constype(nil);
7229673Slinton 		break;
7239673Slinton 
7249673Slinton 	    case 's':
7259673Slinton 	    case 'u':
7269673Slinton 		t->class = (class == 's') ? RECORD : VARNT;
7279673Slinton 		t->symvalue.offset = getint();
7289673Slinton 		u = t;
7299673Slinton 		cur = curchar;
7309673Slinton 		while (*cur != ';' and *cur != '\0') {
7319673Slinton 		    p = index(cur, ':');
7329673Slinton 		    if (p == nil) {
7339673Slinton 			panic("index(\"%s\", ':') failed", curchar);
7349673Slinton 		    }
7359673Slinton 		    *p = '\0';
7369673Slinton 		    name = identname(cur, true);
7379673Slinton 		    u->chain = newSymbol(name, b, FIELD, nil, nil);
7389673Slinton 		    cur = p + 1;
7399673Slinton 		    u = u->chain;
7409673Slinton 		    u->language = curlang;
7419673Slinton 		    curchar = cur;
7429673Slinton 		    u->type = constype(nil);
7439673Slinton 		    skipchar(curchar, ',');
7449673Slinton 		    u->symvalue.field.offset = getint();
7459673Slinton 		    skipchar(curchar, ',');
7469673Slinton 		    u->symvalue.field.length = getint();
7479673Slinton 		    skipchar(curchar, ';');
7489673Slinton 		    cur = curchar;
7499673Slinton 		}
7509673Slinton 		if (*cur == ';') {
7519673Slinton 		    ++cur;
7529673Slinton 		}
7539673Slinton 		curchar = cur;
7549673Slinton 		break;
7559673Slinton 
7569673Slinton 	    case 'e':
7579673Slinton 		t->class = SCAL;
7589673Slinton 		u = t;
7599673Slinton 		while (*curchar != ';' and *curchar != '\0') {
7609673Slinton 		    p = index(curchar, ':');
7619673Slinton 		    assert(p != nil);
7629673Slinton 		    *p = '\0';
7639673Slinton 		    u->chain = insert(identname(curchar, true));
7649673Slinton 		    curchar = p + 1;
7659673Slinton 		    u = u->chain;
7669673Slinton 		    u->language = curlang;
7679673Slinton 		    u->class = CONST;
7689673Slinton 		    u->level = b;
7699673Slinton 		    u->block = curblock;
7709673Slinton 		    u->type = t;
7719673Slinton 		    u->symvalue.iconval = getint();
7729673Slinton 		    skipchar(curchar, ',');
7739673Slinton 		}
7749673Slinton 		break;
7759673Slinton 
7769673Slinton 	    case '*':
7779673Slinton 		t->class = PTR;
7789673Slinton 		t->type = constype(nil);
7799673Slinton 		break;
7809673Slinton 
7819673Slinton 	    case 'f':
7829673Slinton 		t->class = FUNC;
7839673Slinton 		t->type = constype(nil);
7849673Slinton 		break;
7859673Slinton 
7869673Slinton 	    default:
7879673Slinton 		badcaseval(class);
7889673Slinton 	}
7899673Slinton     }
7909673Slinton     return t;
7919673Slinton }
7929673Slinton 
7939673Slinton /*
7949673Slinton  * Read an integer from the current position in the type string.
7959673Slinton  */
7969673Slinton 
7979673Slinton private Integer getint()
7989673Slinton {
7999673Slinton     register Integer n;
8009673Slinton     register char *p;
8019673Slinton     register Boolean isneg;
8029673Slinton 
8039673Slinton     n = 0;
8049673Slinton     p = curchar;
8059673Slinton     if (*p == '-') {
8069673Slinton 	isneg = true;
8079673Slinton 	++p;
8089673Slinton     } else {
8099673Slinton 	isneg = false;
8109673Slinton     }
8119673Slinton     while (isdigit(*p)) {
8129673Slinton 	n = 10*n + (*p - '0');
8139673Slinton 	++p;
8149673Slinton     }
8159673Slinton     curchar = p;
8169673Slinton     return isneg ? (-n) : n;
8179673Slinton }
8189673Slinton 
8199673Slinton /*
8209673Slinton  * Add a tag name.  This is a kludge to be able to refer
8219673Slinton  * to tags that have the same name as some other symbol
8229673Slinton  * in the same block.
8239673Slinton  */
8249673Slinton 
8259673Slinton private addtag(s)
8269673Slinton register Symbol s;
8279673Slinton {
8289673Slinton     register Symbol t;
8299673Slinton     char buf[100];
8309673Slinton 
8319673Slinton     sprintf(buf, "$$%.90s", ident(s->name));
8329673Slinton     t = insert(identname(buf, false));
8339673Slinton     t->language = s->language;
8349673Slinton     t->class = TAG;
8359673Slinton     t->type = s->type;
8369673Slinton     t->block = s->block;
8379673Slinton }
8389673Slinton 
8399673Slinton /*
8409673Slinton  * Allocate file and line tables and initialize indices.
8419673Slinton  */
8429673Slinton 
8439673Slinton private allocmaps(nf, nl)
8449673Slinton Integer nf, nl;
8459673Slinton {
8469673Slinton     if (filetab != nil) {
8479673Slinton 	dispose(filetab);
8489673Slinton     }
8499673Slinton     if (linetab != nil) {
8509673Slinton 	dispose(linetab);
8519673Slinton     }
8529673Slinton     filetab = newarr(Filetab, nf);
8539673Slinton     linetab = newarr(Linetab, nl);
8549673Slinton     filep = filetab;
8559673Slinton     linep = linetab;
8569673Slinton }
8579673Slinton 
8589673Slinton /*
8599673Slinton  * Add a file to the file table.
8609673Slinton  */
8619673Slinton 
8629673Slinton private enterfile(filename, addr)
8639673Slinton String filename;
8649673Slinton Address addr;
8659673Slinton {
8669673Slinton     if (addr != curfaddr) {
8679673Slinton 	filep->addr = addr;
8689673Slinton 	filep->filename = filename;
8699673Slinton 	filep->lineindex = linep - linetab;
8709673Slinton 	++filep;
8719673Slinton 	curfaddr = addr;
8729673Slinton     }
8739673Slinton }
8749673Slinton 
8759673Slinton /*
8769673Slinton  * Since we only estimated the number of lines (and it was a poor
8779673Slinton  * estimation) and since we need to know the exact number of lines
8789673Slinton  * to do a binary search, we set it when we're done.
8799673Slinton  */
8809673Slinton 
8819673Slinton private setnlines()
8829673Slinton {
8839673Slinton     nlhdr.nlines = linep - linetab;
8849673Slinton }
8859673Slinton 
8869673Slinton /*
8879673Slinton  * Similarly for nfiles ...
8889673Slinton  */
8899673Slinton 
8909673Slinton private setnfiles()
8919673Slinton {
8929673Slinton     nlhdr.nfiles = filep - filetab;
8939673Slinton     setsource(filetab[0].filename);
8949673Slinton }
895