xref: /csrg-svn/usr.bin/pascal/pc3/pc3.c (revision 48061)
1*48061Sbostic /*-
2*48061Sbostic  * Copyright (c) 1980, 1982, 1983 The Regents of the University of California.
3*48061Sbostic  * All rights reserved.
4*48061Sbostic  *
5*48061Sbostic  * %sccs.include.redist.c%
622261Sdist  */
722261Sdist 
813617Ssam #ifndef lint
922261Sdist char copyright[] =
10*48061Sbostic "@(#) Copyright (c) 1980, 1982, 1983 The Regents of the University of California.\n\
1122261Sdist  All rights reserved.\n";
12*48061Sbostic #endif /* not lint */
13822Speter 
1422261Sdist #ifndef lint
15*48061Sbostic static char sccsid[] = "@(#)pc3.c	5.2 (Berkeley) 04/16/91";
16*48061Sbostic #endif /* not lint */
1722261Sdist 
18822Speter     /*
19822Speter      *	     Pc3 is a pass in the Berkeley Pascal compilation
20822Speter      *	process that is performed just prior to linking Pascal
21822Speter      *	object files.  Its purpose is to enforce the rules of
22822Speter      *	separate compilation for Berkeley Pascal.  Pc3 is called
23822Speter      *	with the same argument list of object files that is sent to
24822Speter      *	the loader.  These checks are performed by pc3 by examining
25822Speter      *	the symbol tables of the object files:
2614129Speter      *	(1)  All .o files must be up to date with respect to the
2714129Speter      *	     runtime libraries.
28822Speter      *	(2)  Each global Pascal symbol (label, constant, type,
29822Speter      *	     variable, procedure, or function name) must be uniquely
30822Speter      *	     declared, i.e. declared in only one included file or
31822Speter      *	     source file.
32822Speter      *	(3)  Each external function (or procedure) may be resolved
33822Speter      *	     at most once in a source file which included the
34822Speter      *	     external declaration of the function.
35822Speter      *
36822Speter      *	     The symbol table of each object file is scanned and
37822Speter      *	each global Pascal symbol is placed in a hashed symbol
38822Speter      *	table.  The Pascal compiler has been modified to emit all
39822Speter      *	Pascal global symbols to the object file symbol table.  The
40822Speter      *	information stored in the symbol table for each such symbol
41822Speter      *	is:
42822Speter      *
43822Speter      *	   - the name of the symbol;
44844Speter      *	   - a subtype descriptor;
45822Speter      *	   - the file which logically contains the declaration of
4614129Speter      *	     the symbol or which caused the inclusion of an include file.
4714129Speter      *	   - for included files:
4814129Speter      *		- a checksum;
4914129Speter      *	   - for symbols:
5014129Speter      *	   	- the file which textually contains the declaration of
5114129Speter      *	   	  the symbol (possibly an include file);
5214129Speter      *	   	- the line number at which the symbol is declared;
5314129Speter      *	   	- the file which contains the resolution of the symbol.
5414129Speter      *	   	- the line number at which the symbol is resolved;
55822Speter      *
56822Speter      *	     If a symbol has been previously entered into the symbol
57822Speter      *	table, a check is made that the current declaration is of
58822Speter      *	the same type and from the same include file as the previous
59822Speter      *	one.  Except for files and functions and procedures, it is
60822Speter      *	an error for a symbol declaration to be encountered more
61822Speter      *	than once, unless the re-declarations come from the same
62822Speter      *	included file as the original.
63822Speter      *
64822Speter      *	     As an include file symbol is encountered in a source
65822Speter      *	file, the symbol table entry of each symbol declared in that
66822Speter      *	include file is modified to reflect its new logical
67822Speter      *	inclusion in the source file.  File symbols are also
68822Speter      *	encountered as an included file ends, signaling the
69822Speter      *	continuation of the enclosing file.
70822Speter      *
71822Speter      *	     Functions and procedures which have been declared
72822Speter      *	external may be resolved by declarations from source files
73822Speter      *	which included the external declaration of the function.
74822Speter      *	Functions and procedures may be resolved at most once across
75822Speter      *	a set of object files.  The loader will complain if a
76822Speter      *	function is not resolved at least once.
77822Speter      */
78822Speter 
79832Speter char	program[] = "pc";
80822Speter 
81822Speter #include <sys/types.h>
8213617Ssam #include <sys/stat.h>
83822Speter #include <ar.h>
84822Speter #include <stdio.h>
85822Speter #include <ctype.h>
86822Speter #include <a.out.h>
87822Speter #include <stab.h>
88858Speter #include "pstab.h"
89822Speter #include "pc3.h"
90822Speter 
917598Speter int	errors = NONE;
927598Speter BOOL	wflag = FALSE;
93822Speter 
94822Speter     /*
95822Speter      *	check each of the argument .o files (or archives of .o files).
96822Speter      */
97822Speter main( argc , argv )
98822Speter     int		argc;
99822Speter     char	**argv;
100822Speter     {
101822Speter 	struct fileinfo	ofile;
102822Speter 
1037598Speter 	for ( argv++ ; *argv != 0 && **argv == '-' ; argv++ ) {
1047598Speter 	    (*argv)++;
1057598Speter 	    switch ( **argv ) {
1067598Speter 		default:
1077598Speter 		    error( FATAL , "pc3: bad flag -%c\n" , **argv );
1087598Speter 		case 'w':
1097598Speter 		    wflag = TRUE;
1107598Speter 		    break;
1117598Speter 	    }
1127598Speter 	}
1137598Speter 	for ( /* void */ ; *argv != 0 ; argv++ ) {
114822Speter #	    ifdef DEBUG
115822Speter 		fprintf( stderr , "[main] *argv = %s\n" , *argv );
116822Speter #	    endif DEBUG
117822Speter 	    ofile.name = *argv;
118822Speter 	    checkfile( &ofile );
119822Speter 	}
120822Speter 	exit( errors );
121822Speter     }
122822Speter 
123822Speter     /*
124822Speter      *	check the namelist of a file, or all namelists of an archive.
125822Speter      */
126822Speter checkfile( ofilep )
127822Speter     struct fileinfo	*ofilep;
128822Speter     {
129822Speter 	union {
130822Speter 	    char	mag_armag[ SARMAG + 1 ];
131822Speter 	    struct exec	mag_exec;
132822Speter 	}		mag_un;
133822Speter 	int		red;
134822Speter 	struct stat	filestat;
135822Speter 
136822Speter 	ofilep -> file = fopen( ofilep -> name , "r" );
137822Speter 	if ( ofilep -> file == NULL ) {
1387598Speter 	    error( ERROR , "cannot open: %s" , ofilep -> name );
139822Speter 	    return;
140822Speter 	}
141822Speter 	fstat( fileno( ofilep -> file ) , &filestat );
142822Speter 	red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file );
143822Speter 	if ( red != sizeof mag_un ) {
1447598Speter 	    error( ERROR , "cannot read header: %s" , ofilep -> name );
145822Speter 	    return;
146822Speter 	}
147822Speter 	if ( mag_un.mag_exec.a_magic == OARMAG ) {
148822Speter 	    error( WARNING , "old archive: %s" , ofilep -> name );
149822Speter 	    return;
150822Speter 	}
151822Speter 	if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) {
152822Speter 		/* archive, iterate through elements */
153822Speter #	    ifdef DEBUG
154822Speter 		fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name );
155822Speter #	    endif DEBUG
156822Speter 	    ofilep -> nextoffset = SARMAG;
157822Speter 	    while ( nextelement( ofilep ) ) {
158822Speter 		checknl( ofilep );
159822Speter 	    }
160822Speter 	} else if ( N_BADMAG( mag_un.mag_exec ) ) {
161822Speter 		/* not a file.o */
1627598Speter 	    error( ERROR , "bad format: %s" , ofilep -> name );
163822Speter 	    return;
164822Speter 	} else {
165822Speter 		/* a file.o */
166822Speter #	    ifdef DEBUG
167822Speter 		fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name );
168822Speter #	    endif DEBUG
169822Speter 	    fseek( ofilep -> file , 0L , 0 );
170822Speter 	    ofilep -> nextoffset = filestat.st_size;
171822Speter 	    checknl( ofilep );
172822Speter 	}
173822Speter 	fclose( ofilep -> file );
174822Speter     }
175822Speter 
176822Speter     /*
177822Speter      *	check the namelist of this file for conflicts with
178822Speter      *	previously entered symbols.
179822Speter      */
180822Speter checknl( ofilep )
181822Speter     register struct fileinfo	*ofilep;
182822Speter     {
183822Speter 
184822Speter 	long			red;
185831Speter 	struct exec		oexec;
186822Speter 	off_t			symoff;
187822Speter 	long			numsyms;
188822Speter 	register struct nlist	*nlp;
189822Speter 	register char		*stringp;
190822Speter 	long			strsize;
191822Speter 	long			sym;
192822Speter 
193831Speter 	red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file );
194831Speter 	if ( red != sizeof oexec ) {
1957598Speter 	    error( ERROR , "error reading struct exec: %s"
196822Speter 		    , ofilep -> name );
197822Speter 	    return;
198822Speter 	}
199831Speter 	if ( N_BADMAG( oexec ) ) {
200822Speter 	    return;
201822Speter 	}
202831Speter 	symoff = N_SYMOFF( oexec ) - sizeof oexec;
203822Speter 	fseek( ofilep -> file , symoff , 1 );
204831Speter 	numsyms = oexec.a_syms / sizeof ( struct nlist );
205822Speter 	if ( numsyms == 0 ) {
206822Speter 	    error( WARNING , "no name list: %s" , ofilep -> name );
207822Speter 	    return;
208822Speter 	}
209822Speter 	nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) );
210822Speter 	if ( nlp == 0 ) {
211822Speter 	    error( FATAL , "no room for %d nlists" , numsyms );
212822Speter 	}
213822Speter 	red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist )
214822Speter 		    , ofilep -> file );
215822Speter 	if (   ftell( ofilep -> file ) + sizeof ( off_t )
216822Speter 	    >= ofilep -> nextoffset ) {
217822Speter 	    error( WARNING , "no string table (old format .o?)"
218822Speter 		    , ofilep -> name );
219822Speter 	    return;
220822Speter 	}
221822Speter 	red = fread( (char *) &strsize , sizeof strsize , 1
222822Speter 		    , ofilep -> file );
223822Speter 	if ( red != 1 ) {
224822Speter 	    error( WARNING , "no string table (old format .o?)"
225822Speter 		    , ofilep -> name );
226822Speter 	    return;
227822Speter 	}
228822Speter 	stringp  = ( char * ) malloc( strsize );
229822Speter 	if ( stringp == 0 ) {
230822Speter 	    error( FATAL , "no room for %d bytes of strings" , strsize );
231822Speter 	}
232822Speter 	red = fread( stringp + sizeof strsize
233822Speter 		    , strsize - sizeof ( strsize ) , 1 , ofilep -> file );
234822Speter 	if ( red != 1 ) {
235822Speter 	    error( WARNING , "error reading string table: %s"
236822Speter 		    , ofilep -> name );
237822Speter 	}
238822Speter #	ifdef DEBUG
239822Speter 	    fprintf( stderr , "[checknl] %s: %d symbols\n"
240822Speter 		    , ofilep -> name , numsyms );
241822Speter #	endif DEBUG
242822Speter 	for ( sym = 0 ; sym < numsyms ; sym++) {
243822Speter 	    if ( nlp[ sym ].n_un.n_strx ) {
244822Speter 		nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx;
245822Speter 	    } else {
246822Speter 		nlp[ sym ].n_un.n_name = "";
247822Speter 	    }
248822Speter 	    checksymbol( &nlp[ sym ] , ofilep );
249822Speter 	}
250822Speter 	if ( nlp ) {
251822Speter 	    free( nlp );
252822Speter 	}
253822Speter 	if ( stringp ) {
254822Speter 	    free( stringp );
255822Speter 	}
256822Speter     }
257822Speter 
258822Speter     /*
259822Speter      *	check a symbol.
260822Speter      *	look it up in the hashed symbol table,
261822Speter      *	entering it if necessary.
262822Speter      *	this maintains a state of which .p and .i files
263822Speter      *	it is currently in the midst from the nlist entries
264822Speter      *	for source and included files.
265822Speter      *	if we are inside a .p but not a .i, pfilep == ifilep.
266822Speter      */
267822Speter checksymbol( nlp , ofilep )
268822Speter     struct nlist	*nlp;
269822Speter     struct fileinfo	*ofilep;
270822Speter     {
271822Speter 	static struct symbol	*pfilep = NIL;
272822Speter 	static struct symbol	*ifilep = NIL;
273822Speter 	register struct symbol	*symbolp;
2747601Speter 	int			errtype;
275822Speter 
276822Speter #	ifdef DEBUG
277822Speter 	    if ( pfilep && ifilep ) {
278822Speter 		fprintf( stderr , "[checksymbol] pfile %s ifile %s\n"
279822Speter 			, pfilep -> name , ifilep -> name );
280822Speter 	    }
281844Speter 	    fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n"
282844Speter 		    , nlp -> n_un.n_name , nlp -> n_desc
283844Speter 		    , classify( nlp -> n_desc ) );
284822Speter #	endif DEBUG
285844Speter 	if ( nlp -> n_type != N_PC ) {
286844Speter 		/* don't care about the others */
287844Speter 	    return;
288822Speter 	}
289844Speter 	symbolp = entersymbol( nlp -> n_un.n_name );
290822Speter 	if ( symbolp -> lookup == NEW ) {
291822Speter #	    ifdef DEBUG
292822Speter 		fprintf( stderr , "[checksymbol] ->name %s is NEW\n"
293822Speter 			, symbolp -> name );
294822Speter #	    endif DEBUG
295844Speter 	    symbolp -> desc = nlp -> n_desc;
29614129Speter 	    symbolp -> fromp = pfilep;
297844Speter 	    switch ( symbolp -> desc ) {
2987550Speter 		default:
2997550Speter 			error( FATAL , "panic: [checksymbol] NEW" );
300844Speter 		case N_PGLABEL:
301844Speter 		case N_PGCONST:
302844Speter 		case N_PGTYPE:
303822Speter 		case N_PGVAR:
304844Speter 		case N_PGFUNC:
305844Speter 		case N_PGPROC:
3067601Speter 		case N_PLDATA:
3077601Speter 		case N_PLTEXT:
308831Speter 			symbolp -> sym_un.sym_str.rfilep = ifilep;
309831Speter 			symbolp -> sym_un.sym_str.rline = nlp -> n_value;
310831Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
311831Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
312831Speter 			return;
313844Speter 		case N_PEFUNC:
314844Speter 		case N_PEPROC:
315831Speter 			symbolp -> sym_un.sym_str.rfilep = NIL;
316831Speter 			symbolp -> sym_un.sym_str.rline = 0;
317831Speter 			    /*
318831Speter 			     *	functions can only be declared external
319831Speter 			     *	in included files.
320831Speter 			     */
321831Speter 			if ( pfilep == ifilep ) {
322831Speter 			    error( WARNING
323831Speter 				    , "%s, line %d: %s %s must be declared in included file"
324831Speter 				    , pfilep -> name , nlp -> n_value
325844Speter 				    , classify( symbolp -> desc )
326831Speter 				    , symbolp -> name );
327831Speter 			}
328822Speter 			symbolp -> sym_un.sym_str.fromi = ifilep;
329822Speter 			symbolp -> sym_un.sym_str.iline = nlp -> n_value;
330822Speter 			return;
331822Speter 		case N_PSO:
33214129Speter 			if ( nlp -> n_value < N_FLAGCHECKSUM ) {
33314129Speter 			    error( WARNING,
33414129Speter 				"%s is out of date and should be recompiled",
33514129Speter 				ofilep -> name );
33614129Speter 			}
337822Speter 			pfilep = symbolp;
33814129Speter 			ifilep = symbolp;
33914129Speter 			symbolp -> sym_un.checksum = N_FLAGCHECKSUM;
34014129Speter 			return;
341822Speter 		case N_PSOL:
342822Speter 			ifilep = symbolp;
34314129Speter 			symbolp -> sym_un.checksum = nlp -> n_value;
344822Speter 			return;
345822Speter 	    }
346822Speter 	} else {
347822Speter #	    ifdef DEBUG
348822Speter 		fprintf( stderr , "[checksymbol] ->name %s is OLD\n"
349822Speter 			, symbolp -> name );
350822Speter #	    endif DEBUG
3517601Speter 	    errtype = ERROR;
352844Speter 	    switch ( symbolp -> desc ) {
3537550Speter 		default:
3547550Speter 			error( FATAL , "panic [checksymbol] OLD" );
35514129Speter 			return;
356822Speter 		case N_PSO:
357822Speter 			    /*
358822Speter 			     *	finding a file again means you are back
359822Speter 			     *	in it after finishing an include file.
360822Speter 			     */
36114129Speter 			if ( symbolp -> desc != nlp -> n_desc ) {
36214129Speter 			    error( FATAL , "panic [checksymbol] PSO" );
36314129Speter 			    return;
36414129Speter 			}
365822Speter 			pfilep = symbolp;
36614129Speter 			ifilep = symbolp;
36714129Speter 			return;
368822Speter 		case N_PSOL:
369822Speter 			    /*
370822Speter 			     *	include files can be seen more than once,
37114129Speter 			     *	but their checksums are checked if they are
37214129Speter 			     *	greater than N_FLAGCHECKSUM.
37314129Speter 			     *	PSOL's are seen with checksums as the
37414129Speter 			     *	include file is entered, and with
37514129Speter 			     *	N_FLAGCHECKSUM as we are back in an
37614129Speter 			     *	included file from a nested include.
377822Speter 			     */
37814129Speter 			if ( symbolp -> desc != nlp -> n_desc ) {
37914129Speter 			    error( FATAL , "panic [checksymbol] PSOL" );
38014129Speter 			    return;
38114129Speter 			}
38214129Speter 			if ((unsigned) symbolp->sym_un.checksum > N_FLAGCHECKSUM
38314129Speter 			   && (unsigned) nlp -> n_value > N_FLAGCHECKSUM
38414129Speter 			   && symbolp -> sym_un.checksum != nlp -> n_value ) {
38514129Speter 			    error( ERROR,
38614129Speter 			    "%s included in %s differs from %s included in %s",
38714129Speter 				symbolp -> name, pfilep -> name,
38814129Speter 				symbolp -> name, symbolp -> fromp -> name );
38914129Speter 			}
390822Speter 			ifilep = symbolp;
391822Speter 			return;
392844Speter 		case N_PEFUNC:
393844Speter 		case N_PEPROC:
394822Speter 			    /*
3957550Speter 			     *	this might be the resolution of the external
3967550Speter 			     *	has to match func/proc of external
3977550Speter 			     *	and has to have included external
3987550Speter 			     *	and has to not have been previously resolved.
399822Speter 			     */
4007550Speter 			if (  (  ( symbolp -> desc == N_PEFUNC
4017550Speter 			         && nlp -> n_desc == N_PGFUNC )
4027550Speter 			      || ( symbolp -> desc == N_PEPROC
4037550Speter 				 && nlp -> n_desc == N_PGPROC ) )
40414129Speter 			   && ( symbolp -> fromp == pfilep )
4057550Speter 			   && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) {
4067550Speter 				/*
4077550Speter 				 *	resolve external
4087550Speter 				 */
4097550Speter #			    ifdef DEBUG
4107550Speter 				fprintf( stderr , "[checksymbol] resolving external\n" );
4117550Speter #			    endif DEBUG
4127550Speter 			    symbolp -> sym_un.sym_str.rfilep = ifilep;
4137550Speter 			    symbolp -> sym_un.sym_str.rline = nlp -> n_value;
4147550Speter 			    return;
415822Speter 			}
416822Speter 			    /*
4177550Speter 			     *	otherwise, it might be another external,
4187550Speter 			     *	which is okay if it's
4197550Speter 			     *	the same type and from the same include file
420822Speter 			     */
4217550Speter 			if (  (  ( symbolp -> desc == N_PEFUNC
4227550Speter 			         && nlp -> n_desc == N_PEFUNC )
4237550Speter 			      || ( symbolp -> desc == N_PEPROC
4247550Speter 				 && nlp -> n_desc == N_PEPROC ) )
4257550Speter 			   && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) {
4267550Speter 				/*
4277550Speter 				 *	just another pretty external
4287550Speter 				 *	make it look like it comes from here.
4297550Speter 				 */
4307550Speter #			    ifdef DEBUG
4317550Speter 				fprintf( stderr , "[checksymbol] just another pretty external\n" );
4327550Speter #			    endif DEBUG
43314129Speter 			    symbolp -> fromp = pfilep;
4347550Speter 			    return;
435822Speter 			}
436822Speter 			    /*
4377550Speter 			     *	something is wrong
4387598Speter 			     *	if it's not resolved, use the header file
4397598Speter 			     *	otherwise, it's just a regular error
440822Speter 			     */
4417598Speter 			if ( symbolp -> sym_un.sym_str.rfilep == NIL ) {
4427598Speter 			    error( ERROR ,
4437601Speter 		    "%s, line %d: %s is already defined\n\t(%s, line %d)." ,
4447598Speter 				ifilep -> name , nlp -> n_value ,
4457598Speter 				nlp -> n_un.n_name ,
4467598Speter 				symbolp -> sym_un.sym_str.fromi -> name ,
4477598Speter 				symbolp -> sym_un.sym_str.iline );
4487598Speter 			    return;
4497598Speter 			}
4507598Speter 			break;
451844Speter 		case N_PGFUNC:
452844Speter 		case N_PGPROC:
453822Speter 			    /*
454822Speter 			     *	functions may not be seen more than once.
455822Speter 			     *	the loader will complain about
456822Speter 			     *	`multiply defined', but we can, too.
457822Speter 			     */
458822Speter 			break;
459844Speter 		case N_PGLABEL:
460844Speter 		case N_PGCONST:
461844Speter 		case N_PGTYPE:
462822Speter 		case N_PGVAR:
463822Speter 			    /*
464822Speter 			     *	labels, constants, types, variables
465822Speter 			     *	and external declarations
466822Speter 			     *	may be seen as many times as they want,
467822Speter 			     *	as long as they come from the same include file.
468822Speter 			     *	make it look like they come from this .p file.
469822Speter 			     */
470822Speter included:
471844Speter 			if (  nlp -> n_desc != symbolp -> desc
472822Speter 			   || symbolp -> sym_un.sym_str.fromi != ifilep ) {
473822Speter 			    break;
474822Speter 			}
47514129Speter 			symbolp -> fromp = pfilep;
476822Speter 			return;
4777601Speter 		case N_PLDATA:
4787601Speter 		case N_PLTEXT:
4797601Speter 			switch ( nlp -> n_desc ) {
4807601Speter 			    default:
4817601Speter 				error( FATAL , "pc3: unknown stab 0x%x"
4827601Speter 					, nlp -> n_desc );
4837601Speter 				return;
4847601Speter 			    case N_PSO:
4857601Speter 			    case N_PSOL:
4867601Speter 			    case N_PGCONST:
4877601Speter 			    case N_PGTYPE:
4887601Speter 				/* these won't conflict with library */
4897601Speter 				return;
4907601Speter 			    case N_PGLABEL:
4917601Speter 			    case N_PGVAR:
4927601Speter 			    case N_PGFUNC:
4937601Speter 			    case N_PGPROC:
4947601Speter 			    case N_PEFUNC:
4957601Speter 			    case N_PEPROC:
4967601Speter 			    case N_PLDATA:
4977601Speter 			    case N_PLTEXT:
4987601Speter 				errtype = WARNING;
4997601Speter 				break;
5007601Speter 			}
5017601Speter 			break;
502822Speter 	    }
503822Speter 		/*
504822Speter 		 *	this is the breaks
505822Speter 		 */
5067601Speter 	    error( errtype
5077601Speter 		, "%s, line %d: %s %s is already defined\n\t%s%s (%s, line %d)."
5087601Speter 		, ifilep -> name
5097601Speter 		, nlp -> n_value
5107601Speter 		, classify( nlp -> n_desc )
5117601Speter 		, nlp -> n_un.n_name
5127601Speter 		, ( symbolp -> desc == nlp -> n_desc ? "" : " as " )
5137601Speter 		, ( symbolp -> desc == nlp -> n_desc
5147601Speter 			? "" : article( symbolp -> desc ) )
5157601Speter 		, symbolp -> sym_un.sym_str.rfilep -> name
5167601Speter 		, symbolp -> sym_un.sym_str.rline );
517822Speter 	}
518822Speter     }
519822Speter 
520822Speter     /*
521822Speter      *	quadratically hashed symbol table.
522822Speter      *	things are never deleted from the hash symbol table.
523822Speter      *	as more hash table is needed,
524822Speter      *	a new one is alloc'ed and chained to the end.
525822Speter      *	search is by rehashing within each table,
526822Speter      *	traversing chains to next table if unsuccessful.
527822Speter      */
528822Speter struct symbol *
529822Speter entersymbol( name )
530822Speter     char	*name;
531822Speter     {
5329572Speter 	static struct symboltableinfo	symboltable;
533822Speter 	char				*enteredname;
534822Speter 	long				hashindex;
535822Speter 	register struct symboltableinfo	*tablep;
536822Speter 	register struct symbol		**herep;
537822Speter 	register struct symbol		**limitp;
538822Speter 	register long			increment;
539822Speter 
540822Speter 	enteredname = enterstring( name );
541822Speter 	hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME;
5429572Speter 	for ( tablep = &symboltable ; /*return*/ ; tablep = tablep -> chain ) {
543822Speter 	    if ( tablep == NIL ) {
5449572Speter #		ifdef SPACEDEBUG
5459572Speter 		    fprintf( stderr ,
5469572Speter 			    "[entersymbol] calloc'ing table for %d symbols\n" ,
5479572Speter 			    SYMBOLPRIME );
5489572Speter #		endif SPACEDEBUG
5499572Speter 		for ( tablep = &symboltable
5509572Speter 		    ; tablep->chain != NIL
5519572Speter 		    ; tablep = tablep->chain ) {
5529572Speter 			continue;
5539572Speter 		}
5549572Speter 		tablep->chain = ( struct symboltableinfo * )
5559572Speter 			    calloc( 1 , sizeof ( struct symboltableinfo ) );
5569572Speter 		if ( tablep->chain == NIL ) {
557822Speter 		    error( FATAL , "ran out of memory (entersymbol)" );
558822Speter 		}
5599572Speter 		tablep = tablep->chain;
560822Speter 	    }
561822Speter 	    herep = &( tablep -> entry[ hashindex ] );
562822Speter 	    limitp = &( tablep -> entry[ SYMBOLPRIME ] );
563822Speter 	    increment = 1;
564822Speter 	    do {
565822Speter 		if ( *herep == NIL ) {
566822Speter 			/* empty */
5679572Speter 		    if ( tablep -> used > ( ( SYMBOLPRIME / 4 ) * 3 ) ) {
568822Speter 			    /* too full, break for next table */
569822Speter 			break;
570822Speter 		    }
571822Speter 		    tablep -> used++;
572822Speter 		    *herep = symbolalloc();
573822Speter 		    ( *herep ) -> name = enteredname;
574822Speter 		    ( *herep ) -> lookup = NEW;
5759572Speter #		    ifdef HASHDEBUG
5769572Speter 			fprintf( stderr ,
5779572Speter 				"[entersymbol] name %s NEW after %d\n" ,
5789572Speter 				enteredname , increment / 2 );
5799572Speter #		    endif HASHDEBUG
580822Speter 		    return *herep;
581822Speter 		}
582822Speter 		    /* a find? */
583822Speter 		if ( ( *herep ) -> name == enteredname ) {
584822Speter 		    ( *herep ) -> lookup = OLD;
5859572Speter #		    ifdef HASHDEBUG
5869572Speter 			fprintf( stderr , "[entersymbol] name %s OLD at %d\n" ,
5879572Speter 				enteredname , increment / 2 );
5889572Speter #		    endif HASHDEBUG
589822Speter 		    return *herep;
590822Speter 		}
591822Speter 		herep += increment;
592822Speter 		if ( herep >= limitp ) {
593822Speter 		    herep -= SYMBOLPRIME;
594822Speter 		}
595822Speter 		increment += 2;
596822Speter 	    } while ( increment < SYMBOLPRIME );
5979572Speter #	    ifdef HASHDEBUG
5989572Speter 		fprintf( stderr , "[entersymbol] next symboltable\n" );
5999572Speter #	    endif HASHDEBUG
600822Speter 	}
601822Speter     }
602822Speter 
603822Speter     /*
604822Speter      *	allocate a symbol from the dynamically allocated symbol table.
605822Speter      */
606822Speter struct symbol *
607822Speter symbolalloc()
608822Speter     {
609822Speter 	static struct symbol	*nextsymbol = NIL;
610822Speter 	static long		symbolsleft = 0;
611822Speter 	struct symbol		*newsymbol;
612822Speter 
613822Speter 	if ( symbolsleft <= 0 ) {
6149572Speter #	    ifdef SPACEDEBUG
6159572Speter 		fprintf( stderr ,
6169572Speter 			"[symbolalloc] malloc space for %d symbols\n" ,
6179572Speter 			SYMBOLALLOC / sizeof( struct symbol ) );
6189572Speter #	    endif SPACEDEBUG
619822Speter 	    nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC );
620822Speter 	    if ( nextsymbol == 0 ) {
621822Speter 		error( FATAL , "ran out of memory (symbolalloc)" );
622822Speter 	    }
623822Speter 	    symbolsleft = SYMBOLALLOC / sizeof( struct symbol );
624822Speter 	}
625822Speter 	newsymbol = nextsymbol;
626822Speter 	nextsymbol++;
627822Speter 	symbolsleft--;
628822Speter 	return newsymbol;
629822Speter     }
630822Speter 
631822Speter     /*
632822Speter      *	hash a string based on all of its characters.
633822Speter      */
634822Speter long
635822Speter hashstring( string )
636822Speter     char	*string;
637822Speter     {
638822Speter 	register char	*cp;
639822Speter 	register long	value;
640822Speter 
641822Speter 	value = 0;
642822Speter 	for ( cp = string ; *cp ; cp++ ) {
643822Speter 	    value = ( value * 2 ) + *cp;
644822Speter 	}
645822Speter 	return value;
646822Speter     }
647822Speter 
648822Speter     /*
649822Speter      *	quadratically hashed string table.
650822Speter      *	things are never deleted from the hash string table.
651822Speter      *	as more hash table is needed,
652822Speter      *	a new one is alloc'ed and chained to the end.
653822Speter      *	search is by rehashing within each table,
654822Speter      *	traversing chains to next table if unsuccessful.
655822Speter      */
656822Speter char *
657822Speter enterstring( string )
658822Speter     char	*string;
659822Speter     {
6609572Speter 	static struct stringtableinfo	stringtable;
661822Speter 	long				hashindex;
662822Speter 	register struct stringtableinfo	*tablep;
663822Speter 	register char			**herep;
664822Speter 	register char			**limitp;
665822Speter 	register long			increment;
666822Speter 
667822Speter 	hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME;
6689572Speter 	for ( tablep = &stringtable ; /*return*/ ; tablep = tablep -> chain ) {
669822Speter 	    if ( tablep == NIL ) {
6709572Speter #		ifdef SPACEDEBUG
6719572Speter 		    fprintf( stderr ,
6729572Speter 			    "[enterstring] calloc space for %d strings\n" ,
6739572Speter 			    STRINGPRIME );
6749572Speter #		endif SPACEDEBUG
6759572Speter 		for ( tablep = &stringtable
6769572Speter 		    ; tablep->chain != NIL
6779572Speter 		    ; tablep = tablep->chain ) {
6789572Speter 			continue;
6799572Speter 		}
6809572Speter 		tablep->chain = ( struct stringtableinfo * )
6819572Speter 			    calloc( 1 , sizeof ( struct stringtableinfo ) );
6829572Speter 		if ( tablep->chain == NIL ) {
683822Speter 		    error( FATAL , "ran out of memory (enterstring)" );
684822Speter 		}
6859572Speter 		tablep = tablep->chain;
686822Speter 	    }
687822Speter 	    herep = &( tablep -> entry[ hashindex ] );
688822Speter 	    limitp = &( tablep -> entry[ STRINGPRIME ] );
689822Speter 	    increment = 1;
690822Speter 	    do {
691822Speter 		if ( *herep == NIL ) {
692822Speter 			/* empty */
6939572Speter 		    if ( tablep -> used > ( ( STRINGPRIME / 4 ) * 3 ) ) {
694822Speter 			    /* too full, break for next table */
695822Speter 			break;
696822Speter 		    }
697822Speter 		    tablep -> used++;
698822Speter 		    *herep = charalloc( strlen( string ) );
699822Speter 		    strcpy( *herep , string );
7009572Speter #		    ifdef HASHDEBUG
7019572Speter 			fprintf( stderr ,
7029572Speter 				"[enterstring] string %s copied after %d\n" ,
7039572Speter 				*herep , increment / 2 );
7049572Speter #		    endif HASHDEBUG
705822Speter 		    return *herep;
706822Speter 		}
707822Speter 		    /* quick, check the first chars and then the rest */
708822Speter 		if ( **herep == *string && strcmp( *herep , string ) == 0 ) {
7099572Speter #		    ifdef HASHDEBUG
7109572Speter 			fprintf( stderr ,
7119572Speter 				"[enterstring] string %s found after %d\n" ,
7129572Speter 				*herep , increment / 2 );
7139572Speter #		    endif HASHDEBUG
714822Speter 		    return *herep;
715822Speter 		}
716822Speter 		herep += increment;
717822Speter 		if ( herep >= limitp ) {
718822Speter 		    herep -= STRINGPRIME;
719822Speter 		}
720822Speter 		increment += 2;
721822Speter 	    } while ( increment < STRINGPRIME );
7229572Speter #	    ifdef HASHDEBUG
7239572Speter 		fprintf( stderr , "[enterstring] next stringtable\n" );
7249572Speter #	    endif HASHDEBUG
725822Speter 	}
726822Speter     }
727822Speter 
728822Speter     /*
729822Speter      *	copy a string to the dynamically allocated character table.
730822Speter      */
731822Speter char *
732822Speter charalloc( length )
733822Speter     register long	length;
734822Speter     {
735822Speter 	static char	*nextchar = NIL;
736822Speter 	static long	charsleft = 0;
737822Speter 	register long	lengthplus1 = length + 1;
738822Speter 	register long	askfor;
739822Speter 	char		*newstring;
740822Speter 
741822Speter 	if ( charsleft < lengthplus1 ) {
742822Speter 	    askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC;
7439572Speter #	    ifdef SPACEDEBUG
7449572Speter 		fprintf( stderr , "[charalloc] malloc space for %d chars\n"
745822Speter 			, askfor );
7469572Speter #	    endif SPACEDEBUG
747822Speter 	    nextchar = ( char * ) malloc( askfor );
748822Speter 	    if ( nextchar == 0 ) {
749822Speter 		error( FATAL , "no room for %d characters" , askfor );
750822Speter 	    }
751822Speter 	    charsleft = askfor;
752822Speter 	}
753822Speter 	newstring = nextchar;
754822Speter 	nextchar += lengthplus1;
755822Speter 	charsleft -= lengthplus1;
756822Speter 	return newstring;
757822Speter     }
758822Speter 
759822Speter     /*
760822Speter      *	read an archive header for the next element
761822Speter      *	and find the offset of the one after this.
762822Speter      */
763822Speter BOOL
764822Speter nextelement( ofilep )
765822Speter     struct fileinfo	*ofilep;
766822Speter     {
767822Speter 	register char	*cp;
768822Speter 	register long	red;
769822Speter 	register off_t	arsize;
770822Speter 	struct ar_hdr	archdr;
771822Speter 
772822Speter 	fseek( ofilep -> file , ofilep -> nextoffset , 0 );
773822Speter 	red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file );
774822Speter 	if ( red != sizeof archdr ) {
775822Speter 	    return FALSE;
776822Speter 	}
777822Speter 	    /* null terminate the blank-padded name */
778822Speter 	cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ];
779822Speter 	*cp = '\0';
780822Speter 	while ( *--cp == ' ' ) {
781822Speter 	    *cp = '\0';
782822Speter 	}
783822Speter 	    /* set up the address of the beginning of next element */
784822Speter 	arsize = atol( archdr.ar_size );
785822Speter 	    /* archive elements are aligned on 0 mod 2 boundaries */
786822Speter 	if ( arsize & 1 ) {
787822Speter 	    arsize += 1;
788822Speter 	}
789822Speter 	ofilep -> nextoffset = ftell( ofilep -> file ) + arsize;
790822Speter 	    /* say we had one */
791822Speter 	return TRUE;
792822Speter     }
793822Speter 
794822Speter     /*
795822Speter      *	variable number of arguments to error, like printf.
796822Speter      */
7977601Speter error( type , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 )
7987598Speter     int		type;
799822Speter     char	*message;
800822Speter     {
8017598Speter 	errors = type > errors ? type : errors;
8027598Speter 	if ( wflag && type == WARNING ) {
8037598Speter 	    return;
8047598Speter 	}
805822Speter 	fprintf( stderr , "%s: " , program );
8067598Speter 	switch ( type ) {
8077598Speter 	    case WARNING:
8087598Speter 		    fprintf( stderr , "Warning: " );
8097598Speter 		    break;
8107598Speter 	    case ERROR:
8117598Speter 		    fprintf( stderr , "Error: " );
8127598Speter 		    break;
8137598Speter 	    case FATAL:
8147598Speter 		    fprintf( stderr , "Fatal: " );
8157598Speter 		    break;
8167598Speter 	    default:
8177598Speter 		    fprintf( stderr , "Ooops: " );
8187598Speter 		    break;
8197598Speter 	}
8207601Speter 	fprintf( stderr , message , arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 );
821822Speter 	fprintf( stderr , "\n" );
8227598Speter 	if ( type == FATAL ) {
8237598Speter 	    exit( FATAL );
824822Speter 	}
825822Speter     }
826822Speter 
827822Speter char *
828822Speter classify( type )
829822Speter     unsigned char	type;
830822Speter     {
831822Speter 	switch ( type ) {
832822Speter 	    case N_PSO:
833822Speter 		return "source file";
834822Speter 	    case N_PSOL:
835822Speter 		return "include file";
836844Speter 	    case N_PGLABEL:
837822Speter 		return "label";
838844Speter 	    case N_PGCONST:
839822Speter 		return "constant";
840844Speter 	    case N_PGTYPE:
841822Speter 		return "type";
842822Speter 	    case N_PGVAR:
843822Speter 		return "variable";
844844Speter 	    case N_PGFUNC:
845822Speter 		return "function";
846844Speter 	    case N_PGPROC:
847822Speter 		return "procedure";
848844Speter 	    case N_PEFUNC:
849822Speter 		return "external function";
850844Speter 	    case N_PEPROC:
851822Speter 		return "external procedure";
8527601Speter 	    case N_PLDATA:
8537601Speter 		return "library variable";
8547601Speter 	    case N_PLTEXT:
8557601Speter 		return "library routine";
856822Speter 	    default:
857822Speter 		return "unknown symbol";
858822Speter 	}
859822Speter     }
8607601Speter 
8617601Speter char *
8627601Speter article( type )
8637601Speter     unsigned char	type;
8647601Speter     {
8657601Speter 	switch ( type ) {
8667601Speter 	    case N_PSO:
8677601Speter 		return "a source file";
8687601Speter 	    case N_PSOL:
8697601Speter 		return "an include file";
8707601Speter 	    case N_PGLABEL:
8717601Speter 		return "a label";
8727601Speter 	    case N_PGCONST:
8737601Speter 		return "a constant";
8747601Speter 	    case N_PGTYPE:
8757601Speter 		return "a type";
8767601Speter 	    case N_PGVAR:
8777601Speter 		return "a variable";
8787601Speter 	    case N_PGFUNC:
8797601Speter 		return "a function";
8807601Speter 	    case N_PGPROC:
8817601Speter 		return "a procedure";
8827601Speter 	    case N_PEFUNC:
8837601Speter 		return "an external function";
8847601Speter 	    case N_PEPROC:
8857601Speter 		return "an external procedure";
8867601Speter 	    case N_PLDATA:
8877601Speter 		return "a library variable";
8887601Speter 	    case N_PLTEXT:
8897601Speter 		return "a library routine";
8907601Speter 	    default:
8917601Speter 		return "an unknown symbol";
8927601Speter 	}
8937601Speter     }
894