xref: /csrg-svn/old/dbx/object.c (revision 9673)
1*9673Slinton /* Copyright (c) 1982 Regents of the University of California */
2*9673Slinton 
3*9673Slinton static char sccsid[] = "@(#)@(#)object.c 1.1 12/15/82";
4*9673Slinton 
5*9673Slinton /*
6*9673Slinton  * Object code interface, mainly for extraction of symbolic information.
7*9673Slinton  */
8*9673Slinton 
9*9673Slinton #include "defs.h"
10*9673Slinton #include "object.h"
11*9673Slinton #include "main.h"
12*9673Slinton #include "symbols.h"
13*9673Slinton #include "names.h"
14*9673Slinton #include "languages.h"
15*9673Slinton #include "mappings.h"
16*9673Slinton #include "lists.h"
17*9673Slinton #include <a.out.h>
18*9673Slinton #include <stab.h>
19*9673Slinton #include <ctype.h>
20*9673Slinton 
21*9673Slinton #ifndef public
22*9673Slinton 
23*9673Slinton struct {
24*9673Slinton     unsigned int stringsize;	/* size of the dumped string table */
25*9673Slinton     unsigned int nsyms;		/* number of symbols */
26*9673Slinton     unsigned int nfiles;	/* number of files */
27*9673Slinton     unsigned int nlines;	/* number of lines */
28*9673Slinton } nlhdr;
29*9673Slinton 
30*9673Slinton #endif
31*9673Slinton 
32*9673Slinton public String objname = "a.out";
33*9673Slinton public Integer objsize;
34*9673Slinton public char *stringtab;
35*9673Slinton 
36*9673Slinton private String progname = nil;
37*9673Slinton private Language curlang;
38*9673Slinton private Symbol curmodule;
39*9673Slinton private Symbol curparam;
40*9673Slinton private Boolean warned;
41*9673Slinton 
42*9673Slinton private Filetab *filep;
43*9673Slinton private Linetab *linep;
44*9673Slinton private Address curfaddr;
45*9673Slinton 
46*9673Slinton #define curfilename() (filep-1)->filename
47*9673Slinton 
48*9673Slinton /*
49*9673Slinton  * Blocks are figured out on the fly while reading the symbol table.
50*9673Slinton  */
51*9673Slinton 
52*9673Slinton #define MAXBLKDEPTH 25
53*9673Slinton 
54*9673Slinton private Symbol curblock;
55*9673Slinton private Symbol blkstack[MAXBLKDEPTH];
56*9673Slinton private Integer curlevel;
57*9673Slinton 
58*9673Slinton #define enterblock(b) { \
59*9673Slinton     blkstack[curlevel] = curblock; \
60*9673Slinton     ++curlevel; \
61*9673Slinton     b->level = curlevel; \
62*9673Slinton     b->block = curblock; \
63*9673Slinton     curblock = b; \
64*9673Slinton }
65*9673Slinton 
66*9673Slinton #define exitblock() { \
67*9673Slinton     --curlevel; \
68*9673Slinton     curblock = blkstack[curlevel]; \
69*9673Slinton }
70*9673Slinton 
71*9673Slinton /*
72*9673Slinton  * Enter a source line or file name reference into the appropriate table.
73*9673Slinton  * Expanded inline to reduce procedure calls.
74*9673Slinton  *
75*9673Slinton  * private enterline(linenumber, address)
76*9673Slinton  * Lineno linenumber;
77*9673Slinton  * Address address;
78*9673Slinton  *  ...
79*9673Slinton  */
80*9673Slinton 
81*9673Slinton #define enterline(linenumber, address) \
82*9673Slinton { \
83*9673Slinton     register Linetab *lp; \
84*9673Slinton  \
85*9673Slinton     lp = linep - 1; \
86*9673Slinton     if (linenumber != lp->line) { \
87*9673Slinton 	if (address != lp->addr) { \
88*9673Slinton 	    ++lp; \
89*9673Slinton 	} \
90*9673Slinton 	lp->line = linenumber; \
91*9673Slinton 	lp->addr = address; \
92*9673Slinton 	linep = lp + 1; \
93*9673Slinton     } \
94*9673Slinton }
95*9673Slinton 
96*9673Slinton #define NTYPES 1000
97*9673Slinton 
98*9673Slinton private Symbol typetable[NTYPES];
99*9673Slinton 
100*9673Slinton /*
101*9673Slinton  * Read in the namelist from the obj file.
102*9673Slinton  *
103*9673Slinton  * Reads and seeks are used instead of fread's and fseek's
104*9673Slinton  * for efficiency sake; there's a lot of data being read here.
105*9673Slinton  */
106*9673Slinton 
107*9673Slinton public readobj(file)
108*9673Slinton String file;
109*9673Slinton {
110*9673Slinton     Fileid f;
111*9673Slinton     struct exec hdr;
112*9673Slinton     struct nlist nlist;
113*9673Slinton 
114*9673Slinton     f = open(file, 0);
115*9673Slinton     if (f < 0) {
116*9673Slinton 	fatal("can't open %s", file);
117*9673Slinton     }
118*9673Slinton     read(f, &hdr, sizeof(hdr));
119*9673Slinton     objsize = hdr.a_text;
120*9673Slinton     nlhdr.nsyms = hdr.a_syms / sizeof(nlist);
121*9673Slinton     nlhdr.nfiles = nlhdr.nsyms;
122*9673Slinton     nlhdr.nlines = nlhdr.nsyms;
123*9673Slinton     lseek(f, (long) N_STROFF(hdr), 0);
124*9673Slinton     read(f, &(nlhdr.stringsize), sizeof(nlhdr.stringsize));
125*9673Slinton     nlhdr.stringsize -= 4;
126*9673Slinton     stringtab = newarr(char, nlhdr.stringsize);
127*9673Slinton     read(f, stringtab, nlhdr.stringsize);
128*9673Slinton     allocmaps(nlhdr.nfiles, nlhdr.nlines);
129*9673Slinton     lseek(f, (long) N_SYMOFF(hdr), 0);
130*9673Slinton     readsyms(f);
131*9673Slinton     ordfunctab();
132*9673Slinton     setnlines();
133*9673Slinton     setnfiles();
134*9673Slinton     close(f);
135*9673Slinton }
136*9673Slinton 
137*9673Slinton /*
138*9673Slinton  * Read in symbols from object file.
139*9673Slinton  */
140*9673Slinton 
141*9673Slinton private readsyms(f)
142*9673Slinton Fileid f;
143*9673Slinton {
144*9673Slinton     struct nlist *namelist;
145*9673Slinton     register struct nlist *np, *ub;
146*9673Slinton     register int index;
147*9673Slinton     register String name;
148*9673Slinton     register Boolean afterlg;
149*9673Slinton 
150*9673Slinton     initsyms();
151*9673Slinton     namelist = newarr(struct nlist, nlhdr.nsyms);
152*9673Slinton     read(f, namelist, nlhdr.nsyms * sizeof(struct nlist));
153*9673Slinton     afterlg = false;
154*9673Slinton     ub = &namelist[nlhdr.nsyms];
155*9673Slinton     for (np = &namelist[0]; np < ub; np++) {
156*9673Slinton 	index = np->n_un.n_strx;
157*9673Slinton 	if (index != 0) {
158*9673Slinton 	    name = &stringtab[index - 4];
159*9673Slinton 	} else {
160*9673Slinton 	    name = nil;
161*9673Slinton 	}
162*9673Slinton 	/*
163*9673Slinton 	 * assumptions:
164*9673Slinton 	 *	not an N_STAB	==> name != nil
165*9673Slinton 	 *	name[0] == '-'	==> name == "-lg"
166*9673Slinton 	 *	name[0] != '_'	==> filename or invisible
167*9673Slinton 	 *
168*9673Slinton 	 * The "-lg" signals the beginning of global loader symbols.
169*9673Slinton 	 */
170*9673Slinton 	if ((np->n_type&N_STAB) != 0) {
171*9673Slinton 	    enter_nl(name, np);
172*9673Slinton 	} else if (name[0] == '-') {
173*9673Slinton 	    afterlg = true;
174*9673Slinton 	    if (curblock->class != PROG) {
175*9673Slinton 		exitblock();
176*9673Slinton 		if (curblock->class != PROG) {
177*9673Slinton 		    exitblock();
178*9673Slinton 		}
179*9673Slinton 	    }
180*9673Slinton 	    enterline(0, (linep-1)->addr + 1);
181*9673Slinton 	} else if (name[0] == '_') {
182*9673Slinton 	    if (afterlg) {
183*9673Slinton 		check_global(&name[1], np);
184*9673Slinton 	    } else if (curblock->name != nil) {
185*9673Slinton 		check_local(&name[1], np);
186*9673Slinton 	    }
187*9673Slinton 	} else if ((np->n_type&N_TEXT) == N_TEXT) {
188*9673Slinton 	    check_filename(name);
189*9673Slinton 	}
190*9673Slinton     }
191*9673Slinton     dispose(namelist);
192*9673Slinton }
193*9673Slinton 
194*9673Slinton /*
195*9673Slinton  * Initialize symbol information.
196*9673Slinton  */
197*9673Slinton 
198*9673Slinton private initsyms()
199*9673Slinton {
200*9673Slinton     curblock = nil;
201*9673Slinton     curlevel = 0;
202*9673Slinton     if (progname == nil) {
203*9673Slinton 	progname = strdup(objname);
204*9673Slinton 	if (rindex(progname, '/') != nil) {
205*9673Slinton 	    progname = rindex(progname, '/') + 1;
206*9673Slinton 	}
207*9673Slinton 	if (index(progname, '.') != nil) {
208*9673Slinton 	    *(index(progname, '.')) = '\0';
209*9673Slinton 	}
210*9673Slinton     }
211*9673Slinton     program = insert(identname(progname, true));
212*9673Slinton     program->class = PROG;
213*9673Slinton     newfunc(program);
214*9673Slinton     findbeginning(program);
215*9673Slinton     enterblock(program);
216*9673Slinton     curmodule = program;
217*9673Slinton     t_boolean = maketype("$boolean", 0L, 1L);
218*9673Slinton     t_int = maketype("$integer", 0x80000000L, 0x7fffffffL);
219*9673Slinton     t_char = maketype("$char", 0L, 127L);
220*9673Slinton     t_real = maketype("$real", 4L, 0L);
221*9673Slinton     t_nil = maketype("$nil", 0L, 0L);
222*9673Slinton }
223*9673Slinton 
224*9673Slinton /*
225*9673Slinton  * Free all the object file information that's being stored.
226*9673Slinton  */
227*9673Slinton 
228*9673Slinton public objfree()
229*9673Slinton {
230*9673Slinton     symbol_free();
231*9673Slinton     keywords_free();
232*9673Slinton     names_free();
233*9673Slinton     dispose(stringtab);
234*9673Slinton     clrfunctab();
235*9673Slinton }
236*9673Slinton 
237*9673Slinton /*
238*9673Slinton  * Enter a namelist entry.
239*9673Slinton  */
240*9673Slinton 
241*9673Slinton private enter_nl(name, np)
242*9673Slinton String name;
243*9673Slinton register struct nlist *np;
244*9673Slinton {
245*9673Slinton     register Symbol s;
246*9673Slinton     String mname, suffix;
247*9673Slinton     register Name n;
248*9673Slinton     register Symbol *tt;
249*9673Slinton 
250*9673Slinton     s = nil;
251*9673Slinton     if (name == nil) {
252*9673Slinton 	n = nil;
253*9673Slinton     } else {
254*9673Slinton 	n = identname(name, true);
255*9673Slinton     }
256*9673Slinton     switch (np->n_type) {
257*9673Slinton 	case N_LBRAC:
258*9673Slinton 	    s = symbol_alloc();
259*9673Slinton 	    s->class = PROC;
260*9673Slinton 	    enterblock(s);
261*9673Slinton 	    break;
262*9673Slinton 
263*9673Slinton 	case N_RBRAC:
264*9673Slinton 	    exitblock();
265*9673Slinton 	    break;
266*9673Slinton 
267*9673Slinton 	case N_SLINE:
268*9673Slinton 	    enterline((Lineno) np->n_desc, (Address) np->n_value);
269*9673Slinton 	    break;
270*9673Slinton 
271*9673Slinton 	/*
272*9673Slinton 	 * Compilation unit.  C associates scope with filenames
273*9673Slinton 	 * so we treat them as "modules".  The filename without
274*9673Slinton 	 * the suffix is used for the module name.
275*9673Slinton 	 *
276*9673Slinton 	 * Because there is no explicit "end-of-block" mark in
277*9673Slinton 	 * the object file, we must exit blocks for the current
278*9673Slinton 	 * procedure and module.
279*9673Slinton 	 */
280*9673Slinton 	case N_SO:
281*9673Slinton 	    mname = strdup(ident(n));
282*9673Slinton 	    if (rindex(mname, '/') != nil) {
283*9673Slinton 		mname = rindex(mname, '/') + 1;
284*9673Slinton 	    }
285*9673Slinton 	    suffix = rindex(mname, '.');
286*9673Slinton 	    curlang = findlanguage(suffix);
287*9673Slinton 	    if (suffix != nil) {
288*9673Slinton 		*suffix = '\0';
289*9673Slinton 	    }
290*9673Slinton 	    if (curblock->class != PROG) {
291*9673Slinton 		exitblock();
292*9673Slinton 		if (curblock->class != PROG) {
293*9673Slinton 		    exitblock();
294*9673Slinton 		}
295*9673Slinton 	    }
296*9673Slinton 	    s = insert(identname(mname, true));
297*9673Slinton 	    s->language = curlang;
298*9673Slinton 	    s->class = MODULE;
299*9673Slinton 	    enterblock(s);
300*9673Slinton 	    curmodule = s;
301*9673Slinton 	    if (program->language == nil) {
302*9673Slinton 		program->language = curlang;
303*9673Slinton 	    }
304*9673Slinton 	    warned = false;
305*9673Slinton 	    enterfile(ident(n), (Address) np->n_value);
306*9673Slinton 	    for (tt = &typetable[0]; tt < &typetable[NTYPES]; tt++) {
307*9673Slinton 		*tt = nil;
308*9673Slinton 	    }
309*9673Slinton 	    break;
310*9673Slinton 
311*9673Slinton 	/*
312*9673Slinton 	 * Textually included files.
313*9673Slinton 	 */
314*9673Slinton 	case N_SOL:
315*9673Slinton 	    enterfile(name, (Address) np->n_value);
316*9673Slinton 	    break;
317*9673Slinton 
318*9673Slinton 	/*
319*9673Slinton 	 * These symbols are assumed to have non-nil names.
320*9673Slinton 	 */
321*9673Slinton 	case N_GSYM:
322*9673Slinton 	case N_FUN:
323*9673Slinton 	case N_STSYM:
324*9673Slinton 	case N_LCSYM:
325*9673Slinton 	case N_RSYM:
326*9673Slinton 	case N_PSYM:
327*9673Slinton 	case N_LSYM:
328*9673Slinton 	case N_SSYM:
329*9673Slinton 	    if (index(name, ':') == nil) {
330*9673Slinton 		if (not warned) {
331*9673Slinton 		    warned = true;
332*9673Slinton 		    /*
333*9673Slinton 		     * Shouldn't do this if user might be typing.
334*9673Slinton 		     *
335*9673Slinton 		    warning("old style symbol information found in \"%s\"",
336*9673Slinton 			curfilename());
337*9673Slinton 		     *
338*9673Slinton 		     */
339*9673Slinton 		}
340*9673Slinton 	    } else {
341*9673Slinton 		entersym(name, np);
342*9673Slinton 	    }
343*9673Slinton 	    break;
344*9673Slinton 
345*9673Slinton 	case N_PC:
346*9673Slinton 	    break;
347*9673Slinton 
348*9673Slinton 	default:
349*9673Slinton 	    if (name != nil) {
350*9673Slinton 		printf("%s, ", name);
351*9673Slinton 	    }
352*9673Slinton 	    printf("ntype %2x, desc %x, value %x\n",
353*9673Slinton 		np->n_type, np->n_desc, np->n_value);
354*9673Slinton 	    break;
355*9673Slinton     }
356*9673Slinton }
357*9673Slinton 
358*9673Slinton /*
359*9673Slinton  * Check to see if a global _name is already in the symbol table,
360*9673Slinton  * if not then insert it.
361*9673Slinton  */
362*9673Slinton 
363*9673Slinton private check_global(name, np)
364*9673Slinton String name;
365*9673Slinton register struct nlist *np;
366*9673Slinton {
367*9673Slinton     register Name n;
368*9673Slinton     register Symbol t;
369*9673Slinton 
370*9673Slinton     if (not streq(name, "end")) {
371*9673Slinton 	n = identname(name, true);
372*9673Slinton 	if ((np->n_type&N_TYPE) == N_TEXT) {
373*9673Slinton 	    find(t, n) where
374*9673Slinton 		t->level == program->level and isblock(t)
375*9673Slinton 	    endfind(t);
376*9673Slinton 	    if (t == nil) {
377*9673Slinton 		t = insert(n);
378*9673Slinton 		t->language = findlanguage(".s");
379*9673Slinton 		t->class = FUNC;
380*9673Slinton 		t->type = t_int;
381*9673Slinton 		t->block = curblock;
382*9673Slinton 		t->level = program->level;
383*9673Slinton 	    }
384*9673Slinton 	    t->symvalue.funcv.beginaddr = np->n_value;
385*9673Slinton 	    newfunc(t);
386*9673Slinton 	    findbeginning(t);
387*9673Slinton 	} else {
388*9673Slinton 	    find(t, n) where
389*9673Slinton 		t->class == VAR and t->level == program->level
390*9673Slinton 	    endfind(t);
391*9673Slinton 	    if (t == nil) {
392*9673Slinton 		t = insert(n);
393*9673Slinton 		t->language = findlanguage(".s");
394*9673Slinton 		t->class = VAR;
395*9673Slinton 		t->type = t_int;
396*9673Slinton 		t->block = curblock;
397*9673Slinton 		t->level = program->level;
398*9673Slinton 	    }
399*9673Slinton 	    t->symvalue.offset = np->n_value;
400*9673Slinton 	}
401*9673Slinton     }
402*9673Slinton }
403*9673Slinton 
404*9673Slinton /*
405*9673Slinton  * Check to see if a local _name is known in the current scope.
406*9673Slinton  * If not then enter it.
407*9673Slinton  */
408*9673Slinton 
409*9673Slinton private check_local(name, np)
410*9673Slinton String name;
411*9673Slinton register struct nlist *np;
412*9673Slinton {
413*9673Slinton     register Name n;
414*9673Slinton     register Symbol t, cur;
415*9673Slinton 
416*9673Slinton     n = identname(name, true);
417*9673Slinton     cur = ((np->n_type&N_TYPE) == N_TEXT) ? curmodule : curblock;
418*9673Slinton     find(t, n) where t->block == cur endfind(t);
419*9673Slinton     if (t == nil) {
420*9673Slinton 	t = insert(n);
421*9673Slinton 	t->language = findlanguage(".s");
422*9673Slinton 	t->type = t_int;
423*9673Slinton 	t->block = cur;
424*9673Slinton 	t->level = cur->level;
425*9673Slinton 	if ((np->n_type&N_TYPE) == N_TEXT) {
426*9673Slinton 	    t->class = FUNC;
427*9673Slinton 	    t->symvalue.funcv.beginaddr = np->n_value;
428*9673Slinton 	    newfunc(t);
429*9673Slinton 	    findbeginning(t);
430*9673Slinton 	} else {
431*9673Slinton 	    t->class = VAR;
432*9673Slinton 	    t->symvalue.offset = np->n_value;
433*9673Slinton 	}
434*9673Slinton     }
435*9673Slinton }
436*9673Slinton 
437*9673Slinton /*
438*9673Slinton  * Check to see if a symbol corresponds to a object file name.
439*9673Slinton  * For some reason these are listed as in the text segment.
440*9673Slinton  */
441*9673Slinton 
442*9673Slinton private check_filename(name)
443*9673Slinton String name;
444*9673Slinton {
445*9673Slinton     register String mname;
446*9673Slinton     register Integer i;
447*9673Slinton     register Symbol s;
448*9673Slinton 
449*9673Slinton     mname = strdup(name);
450*9673Slinton     i = strlen(mname) - 2;
451*9673Slinton     if (i >= 0 and mname[i] == '.' and mname[i+1] == 'o') {
452*9673Slinton 	mname[i] = '\0';
453*9673Slinton 	--i;
454*9673Slinton 	while (mname[i] != '/' and i >= 0) {
455*9673Slinton 	    --i;
456*9673Slinton 	}
457*9673Slinton 	s = insert(identname(&mname[i+1], true));
458*9673Slinton 	s->language = findlanguage(".s");
459*9673Slinton 	s->class = MODULE;
460*9673Slinton 	if (curblock->class != PROG) {
461*9673Slinton 	    exitblock();
462*9673Slinton 	    if (curblock->class != PROG) {
463*9673Slinton 		exitblock();
464*9673Slinton 	    }
465*9673Slinton 	}
466*9673Slinton 	enterblock(s);
467*9673Slinton 	curmodule = s;
468*9673Slinton     }
469*9673Slinton }
470*9673Slinton 
471*9673Slinton /*
472*9673Slinton  * Put an nlist into the symbol table.
473*9673Slinton  * If it's already there just add the associated information.
474*9673Slinton  *
475*9673Slinton  * Type information is encoded in the name following a ":".
476*9673Slinton  */
477*9673Slinton 
478*9673Slinton private Symbol constype();
479*9673Slinton private Char *curchar;
480*9673Slinton 
481*9673Slinton #define skipchar(ptr, ch) { \
482*9673Slinton     if (*ptr != ch) { \
483*9673Slinton 	panic("expected char '%c', found char '%c'", ch, *ptr); \
484*9673Slinton     } \
485*9673Slinton     ++ptr; \
486*9673Slinton }
487*9673Slinton 
488*9673Slinton private entersym(str, np)
489*9673Slinton String str;
490*9673Slinton struct nlist *np;
491*9673Slinton {
492*9673Slinton     register Symbol s;
493*9673Slinton     register char *p;
494*9673Slinton     register int c;
495*9673Slinton     register Name n;
496*9673Slinton     register Integer i;
497*9673Slinton     Boolean knowtype, isnew;
498*9673Slinton     Symclass class;
499*9673Slinton     Integer level;
500*9673Slinton 
501*9673Slinton     p = index(str, ':');
502*9673Slinton     *p = '\0';
503*9673Slinton     c = *(p+1);
504*9673Slinton     n = identname(str, true);
505*9673Slinton     if (index("FfGV", c) != nil) {
506*9673Slinton 	if (c == 'F' or c == 'f') {
507*9673Slinton 	    class = FUNC;
508*9673Slinton 	} else {
509*9673Slinton 	    class = VAR;
510*9673Slinton 	}
511*9673Slinton 	level = (c == 'f' ? curmodule->level : program->level);
512*9673Slinton 	find(s, n) where s->level == level and s->class == class endfind(s);
513*9673Slinton 	if (s == nil) {
514*9673Slinton 	    isnew = true;
515*9673Slinton 	    s = insert(n);
516*9673Slinton 	} else {
517*9673Slinton 	    isnew = false;
518*9673Slinton 	}
519*9673Slinton     } else {
520*9673Slinton 	isnew = true;
521*9673Slinton 	s = insert(n);
522*9673Slinton     }
523*9673Slinton 
524*9673Slinton     /*
525*9673Slinton      * Default attributes.
526*9673Slinton      */
527*9673Slinton     s->language = curlang;
528*9673Slinton     s->class = VAR;
529*9673Slinton     s->block = curblock;
530*9673Slinton     s->level = curlevel;
531*9673Slinton     s->symvalue.offset = np->n_value;
532*9673Slinton     curchar = p + 2;
533*9673Slinton     knowtype = false;
534*9673Slinton     switch (c) {
535*9673Slinton 	case 't':	/* type name */
536*9673Slinton 	    s->class = TYPE;
537*9673Slinton 	    i = getint();
538*9673Slinton 	    if (i == 0) {
539*9673Slinton 		panic("bad input on type \"%s\" at \"%s\"", symname(s),
540*9673Slinton 		    curchar);
541*9673Slinton 	    } else if (i >= NTYPES) {
542*9673Slinton 		panic("too many types in file \"%s\"", curfilename());
543*9673Slinton 	    }
544*9673Slinton 	    /*
545*9673Slinton 	     * A hack for C typedefs that don't create new types,
546*9673Slinton 	     * e.g. typedef unsigned int Hashvalue;
547*9673Slinton 	     */
548*9673Slinton 	    if (*curchar == '\0') {
549*9673Slinton 		s->type = typetable[i];
550*9673Slinton 		if (s->type == nil) {
551*9673Slinton 		    panic("nil type for %d", i);
552*9673Slinton 		}
553*9673Slinton 		knowtype = true;
554*9673Slinton 	    } else {
555*9673Slinton 		typetable[i] = s;
556*9673Slinton 		skipchar(curchar, '=');
557*9673Slinton 	    }
558*9673Slinton 	    break;
559*9673Slinton 
560*9673Slinton 	case 'T':	/* tag */
561*9673Slinton 	    s->class = TAG;
562*9673Slinton 	    i = getint();
563*9673Slinton 	    if (i == 0) {
564*9673Slinton 		panic("bad input on tag \"%s\" at \"%s\"", symname(s),
565*9673Slinton 		    curchar);
566*9673Slinton 	    } else if (i >= NTYPES) {
567*9673Slinton 		panic("too many types in file \"%s\"", curfilename());
568*9673Slinton 	    }
569*9673Slinton 	    if (typetable[i] != nil) {
570*9673Slinton 		typetable[i]->language = curlang;
571*9673Slinton 		typetable[i]->class = TYPE;
572*9673Slinton 		typetable[i]->type = s;
573*9673Slinton 	    } else {
574*9673Slinton 		typetable[i] = s;
575*9673Slinton 	    }
576*9673Slinton 	    skipchar(curchar, '=');
577*9673Slinton 	    break;
578*9673Slinton 
579*9673Slinton 	case 'F':	/* public function */
580*9673Slinton 	case 'f':	/* private function */
581*9673Slinton 	    s->class = FUNC;
582*9673Slinton 	    if (curblock->class == FUNC or curblock->class == PROC) {
583*9673Slinton 		exitblock();
584*9673Slinton 	    }
585*9673Slinton 	    enterblock(s);
586*9673Slinton 	    if (c == 'F') {
587*9673Slinton 		s->level = program->level;
588*9673Slinton 		isnew = false;
589*9673Slinton 	    }
590*9673Slinton 	    curparam = s;
591*9673Slinton 	    if (isnew) {
592*9673Slinton 		s->symvalue.funcv.beginaddr = np->n_value;
593*9673Slinton 		newfunc(s);
594*9673Slinton 		findbeginning(s);
595*9673Slinton 	    }
596*9673Slinton 	    break;
597*9673Slinton 
598*9673Slinton 	case 'G':	/* public variable */
599*9673Slinton 	    s->level = program->level;
600*9673Slinton 	    break;
601*9673Slinton 
602*9673Slinton 	case 'S':	/* private variable */
603*9673Slinton 	    s->level = curmodule->level;
604*9673Slinton 	    s->block = curmodule;
605*9673Slinton 	    break;
606*9673Slinton 
607*9673Slinton 	case 'V':	/* own variable */
608*9673Slinton 	    s->level = 2;
609*9673Slinton 	    break;
610*9673Slinton 
611*9673Slinton 	case 'r':	/* register variable */
612*9673Slinton 	    s->level = -(s->level);
613*9673Slinton 	    break;
614*9673Slinton 
615*9673Slinton 	case 'p':	/* parameter variable */
616*9673Slinton 	    curparam->chain = s;
617*9673Slinton 	    curparam = s;
618*9673Slinton 	    break;
619*9673Slinton 
620*9673Slinton 	case 'v':	/* varies parameter */
621*9673Slinton 	    s->class = REF;
622*9673Slinton 	    s->symvalue.offset = np->n_value;
623*9673Slinton 	    curparam->chain = s;
624*9673Slinton 	    curparam = s;
625*9673Slinton 	    break;
626*9673Slinton 
627*9673Slinton 	default:	/* local variable */
628*9673Slinton 	    --curchar;
629*9673Slinton 	    break;
630*9673Slinton     }
631*9673Slinton     if (not knowtype) {
632*9673Slinton 	s->type = constype(nil);
633*9673Slinton 	if (s->class == TAG) {
634*9673Slinton 	    addtag(s);
635*9673Slinton 	}
636*9673Slinton     }
637*9673Slinton     if (tracesyms) {
638*9673Slinton 	printdecl(s);
639*9673Slinton 	fflush(stdout);
640*9673Slinton     }
641*9673Slinton }
642*9673Slinton 
643*9673Slinton /*
644*9673Slinton  * Construct a type out of a string encoding.
645*9673Slinton  *
646*9673Slinton  * The forms of the string are
647*9673Slinton  *
648*9673Slinton  *	<number>
649*9673Slinton  *	<number>=<type>
650*9673Slinton  *	r<type>;<number>;<number>		$ subrange
651*9673Slinton  *	a<type>;<type>				$ array[index] of element
652*9673Slinton  *	s{<name>:<type>;<number>;<number>}	$ record
653*9673Slinton  *	*<type>					$ pointer
654*9673Slinton  */
655*9673Slinton 
656*9673Slinton private Symbol constype(type)
657*9673Slinton Symbol type;
658*9673Slinton {
659*9673Slinton     register Symbol t, u;
660*9673Slinton     register Char *p, *cur;
661*9673Slinton     register Integer n;
662*9673Slinton     Integer b;
663*9673Slinton     Name name;
664*9673Slinton     Char class;
665*9673Slinton 
666*9673Slinton     b = curlevel;
667*9673Slinton     if (isdigit(*curchar)) {
668*9673Slinton 	n = getint();
669*9673Slinton 	if (n == 0) {
670*9673Slinton 	    panic("bad type number at \"%s\"", curchar);
671*9673Slinton 	} else if (n >= NTYPES) {
672*9673Slinton 	    panic("too many types in file \"%s\"", curfilename());
673*9673Slinton 	}
674*9673Slinton 	if (*curchar == '=') {
675*9673Slinton 	    if (typetable[n] != nil) {
676*9673Slinton 		t = typetable[n];
677*9673Slinton 	    } else {
678*9673Slinton 		t = symbol_alloc();
679*9673Slinton 		typetable[n] = t;
680*9673Slinton 	    }
681*9673Slinton 	    ++curchar;
682*9673Slinton 	    constype(t);
683*9673Slinton 	} else {
684*9673Slinton 	    t = typetable[n];
685*9673Slinton 	    if (t == nil) {
686*9673Slinton 		t = symbol_alloc();
687*9673Slinton 		typetable[n] = t;
688*9673Slinton 	    }
689*9673Slinton 	}
690*9673Slinton     } else {
691*9673Slinton 	if (type == nil) {
692*9673Slinton 	    t = symbol_alloc();
693*9673Slinton 	} else {
694*9673Slinton 	    t = type;
695*9673Slinton 	}
696*9673Slinton 	t->language = curlang;
697*9673Slinton 	t->level = b;
698*9673Slinton 	class = *curchar++;
699*9673Slinton 	switch (class) {
700*9673Slinton 	    case 'r':
701*9673Slinton 		t->class = RANGE;
702*9673Slinton 		t->type = constype(nil);
703*9673Slinton 		skipchar(curchar, ';');
704*9673Slinton 		t->symvalue.rangev.lower = getint();
705*9673Slinton 		skipchar(curchar, ';');
706*9673Slinton 		t->symvalue.rangev.upper = getint();
707*9673Slinton 		break;
708*9673Slinton 
709*9673Slinton 	    case 'a':
710*9673Slinton 		t->class = ARRAY;
711*9673Slinton 		t->chain = constype(nil);
712*9673Slinton 		skipchar(curchar, ';');
713*9673Slinton 		t->type = constype(nil);
714*9673Slinton 		break;
715*9673Slinton 
716*9673Slinton 	    case 's':
717*9673Slinton 	    case 'u':
718*9673Slinton 		t->class = (class == 's') ? RECORD : VARNT;
719*9673Slinton 		t->symvalue.offset = getint();
720*9673Slinton 		u = t;
721*9673Slinton 		cur = curchar;
722*9673Slinton 		while (*cur != ';' and *cur != '\0') {
723*9673Slinton 		    p = index(cur, ':');
724*9673Slinton 		    if (p == nil) {
725*9673Slinton 			panic("index(\"%s\", ':') failed", curchar);
726*9673Slinton 		    }
727*9673Slinton 		    *p = '\0';
728*9673Slinton 		    name = identname(cur, true);
729*9673Slinton 		    u->chain = newSymbol(name, b, FIELD, nil, nil);
730*9673Slinton 		    cur = p + 1;
731*9673Slinton 		    u = u->chain;
732*9673Slinton 		    u->language = curlang;
733*9673Slinton 		    curchar = cur;
734*9673Slinton 		    u->type = constype(nil);
735*9673Slinton 		    skipchar(curchar, ',');
736*9673Slinton 		    u->symvalue.field.offset = getint();
737*9673Slinton 		    skipchar(curchar, ',');
738*9673Slinton 		    u->symvalue.field.length = getint();
739*9673Slinton 		    skipchar(curchar, ';');
740*9673Slinton 		    cur = curchar;
741*9673Slinton 		}
742*9673Slinton 		if (*cur == ';') {
743*9673Slinton 		    ++cur;
744*9673Slinton 		}
745*9673Slinton 		curchar = cur;
746*9673Slinton 		break;
747*9673Slinton 
748*9673Slinton 	    case 'e':
749*9673Slinton 		t->class = SCAL;
750*9673Slinton 		u = t;
751*9673Slinton 		while (*curchar != ';' and *curchar != '\0') {
752*9673Slinton 		    p = index(curchar, ':');
753*9673Slinton 		    assert(p != nil);
754*9673Slinton 		    *p = '\0';
755*9673Slinton 		    u->chain = insert(identname(curchar, true));
756*9673Slinton 		    curchar = p + 1;
757*9673Slinton 		    u = u->chain;
758*9673Slinton 		    u->language = curlang;
759*9673Slinton 		    u->class = CONST;
760*9673Slinton 		    u->level = b;
761*9673Slinton 		    u->block = curblock;
762*9673Slinton 		    u->type = t;
763*9673Slinton 		    u->symvalue.iconval = getint();
764*9673Slinton 		    skipchar(curchar, ',');
765*9673Slinton 		}
766*9673Slinton 		break;
767*9673Slinton 
768*9673Slinton 	    case '*':
769*9673Slinton 		t->class = PTR;
770*9673Slinton 		t->type = constype(nil);
771*9673Slinton 		break;
772*9673Slinton 
773*9673Slinton 	    case 'f':
774*9673Slinton 		t->class = FUNC;
775*9673Slinton 		t->type = constype(nil);
776*9673Slinton 		break;
777*9673Slinton 
778*9673Slinton 	    default:
779*9673Slinton 		badcaseval(class);
780*9673Slinton 	}
781*9673Slinton     }
782*9673Slinton     return t;
783*9673Slinton }
784*9673Slinton 
785*9673Slinton /*
786*9673Slinton  * Read an integer from the current position in the type string.
787*9673Slinton  */
788*9673Slinton 
789*9673Slinton private Integer getint()
790*9673Slinton {
791*9673Slinton     register Integer n;
792*9673Slinton     register char *p;
793*9673Slinton     register Boolean isneg;
794*9673Slinton 
795*9673Slinton     n = 0;
796*9673Slinton     p = curchar;
797*9673Slinton     if (*p == '-') {
798*9673Slinton 	isneg = true;
799*9673Slinton 	++p;
800*9673Slinton     } else {
801*9673Slinton 	isneg = false;
802*9673Slinton     }
803*9673Slinton     while (isdigit(*p)) {
804*9673Slinton 	n = 10*n + (*p - '0');
805*9673Slinton 	++p;
806*9673Slinton     }
807*9673Slinton     curchar = p;
808*9673Slinton     return isneg ? (-n) : n;
809*9673Slinton }
810*9673Slinton 
811*9673Slinton /*
812*9673Slinton  * Add a tag name.  This is a kludge to be able to refer
813*9673Slinton  * to tags that have the same name as some other symbol
814*9673Slinton  * in the same block.
815*9673Slinton  */
816*9673Slinton 
817*9673Slinton private addtag(s)
818*9673Slinton register Symbol s;
819*9673Slinton {
820*9673Slinton     register Symbol t;
821*9673Slinton     char buf[100];
822*9673Slinton 
823*9673Slinton     sprintf(buf, "$$%.90s", ident(s->name));
824*9673Slinton     t = insert(identname(buf, false));
825*9673Slinton     t->language = s->language;
826*9673Slinton     t->class = TAG;
827*9673Slinton     t->type = s->type;
828*9673Slinton     t->block = s->block;
829*9673Slinton }
830*9673Slinton 
831*9673Slinton /*
832*9673Slinton  * Allocate file and line tables and initialize indices.
833*9673Slinton  */
834*9673Slinton 
835*9673Slinton private allocmaps(nf, nl)
836*9673Slinton Integer nf, nl;
837*9673Slinton {
838*9673Slinton     if (filetab != nil) {
839*9673Slinton 	dispose(filetab);
840*9673Slinton     }
841*9673Slinton     if (linetab != nil) {
842*9673Slinton 	dispose(linetab);
843*9673Slinton     }
844*9673Slinton     filetab = newarr(Filetab, nf);
845*9673Slinton     linetab = newarr(Linetab, nl);
846*9673Slinton     filep = filetab;
847*9673Slinton     linep = linetab;
848*9673Slinton }
849*9673Slinton 
850*9673Slinton /*
851*9673Slinton  * Add a file to the file table.
852*9673Slinton  */
853*9673Slinton 
854*9673Slinton private enterfile(filename, addr)
855*9673Slinton String filename;
856*9673Slinton Address addr;
857*9673Slinton {
858*9673Slinton     if (addr != curfaddr) {
859*9673Slinton 	filep->addr = addr;
860*9673Slinton 	filep->filename = filename;
861*9673Slinton 	filep->lineindex = linep - linetab;
862*9673Slinton 	++filep;
863*9673Slinton 	curfaddr = addr;
864*9673Slinton     }
865*9673Slinton }
866*9673Slinton 
867*9673Slinton /*
868*9673Slinton  * Since we only estimated the number of lines (and it was a poor
869*9673Slinton  * estimation) and since we need to know the exact number of lines
870*9673Slinton  * to do a binary search, we set it when we're done.
871*9673Slinton  */
872*9673Slinton 
873*9673Slinton private setnlines()
874*9673Slinton {
875*9673Slinton     nlhdr.nlines = linep - linetab;
876*9673Slinton }
877*9673Slinton 
878*9673Slinton /*
879*9673Slinton  * Similarly for nfiles ...
880*9673Slinton  */
881*9673Slinton 
882*9673Slinton private setnfiles()
883*9673Slinton {
884*9673Slinton     nlhdr.nfiles = filep - filetab;
885*9673Slinton     setsource(filetab[0].filename);
886*9673Slinton }
887