Commit | Line | Data |
---|---|---|
8c1e6983 KB |
1 | /*- |
2 | * Copyright (c) 1980, 1982, 1983 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * %sccs.include.redist.c% | |
252367af DF |
6 | */ |
7 | ||
8 | #ifndef lint | |
9 | char copyright[] = | |
8c1e6983 | 10 | "@(#) Copyright (c) 1980, 1982, 1983 The Regents of the University of California.\n\ |
252367af | 11 | All rights reserved.\n"; |
8c1e6983 | 12 | #endif /* not lint */ |
252367af | 13 | |
840fc587 | 14 | #ifndef lint |
8c1e6983 KB |
15 | static char sccsid[] = "@(#)pc3.c 5.2 (Berkeley) %G%"; |
16 | #endif /* not lint */ | |
893f2bd0 | 17 | |
893f2bd0 PK |
18 | /* |
19 | * Pc3 is a pass in the Berkeley Pascal compilation | |
20 | * process that is performed just prior to linking Pascal | |
21 | * object files. Its purpose is to enforce the rules of | |
22 | * separate compilation for Berkeley Pascal. Pc3 is called | |
23 | * with the same argument list of object files that is sent to | |
24 | * the loader. These checks are performed by pc3 by examining | |
25 | * the symbol tables of the object files: | |
2dc241d5 PK |
26 | * (1) All .o files must be up to date with respect to the |
27 | * runtime libraries. | |
893f2bd0 PK |
28 | * (2) Each global Pascal symbol (label, constant, type, |
29 | * variable, procedure, or function name) must be uniquely | |
30 | * declared, i.e. declared in only one included file or | |
31 | * source file. | |
32 | * (3) Each external function (or procedure) may be resolved | |
33 | * at most once in a source file which included the | |
34 | * external declaration of the function. | |
35 | * | |
36 | * The symbol table of each object file is scanned and | |
37 | * each global Pascal symbol is placed in a hashed symbol | |
38 | * table. The Pascal compiler has been modified to emit all | |
39 | * Pascal global symbols to the object file symbol table. The | |
40 | * information stored in the symbol table for each such symbol | |
41 | * is: | |
42 | * | |
43 | * - the name of the symbol; | |
99f6998f | 44 | * - a subtype descriptor; |
893f2bd0 | 45 | * - the file which logically contains the declaration of |
2dc241d5 PK |
46 | * the symbol or which caused the inclusion of an include file. |
47 | * - for included files: | |
48 | * - a checksum; | |
49 | * - for symbols: | |
50 | * - the file which textually contains the declaration of | |
51 | * the symbol (possibly an include file); | |
52 | * - the line number at which the symbol is declared; | |
53 | * - the file which contains the resolution of the symbol. | |
54 | * - the line number at which the symbol is resolved; | |
893f2bd0 PK |
55 | * |
56 | * If a symbol has been previously entered into the symbol | |
57 | * table, a check is made that the current declaration is of | |
58 | * the same type and from the same include file as the previous | |
59 | * one. Except for files and functions and procedures, it is | |
60 | * an error for a symbol declaration to be encountered more | |
61 | * than once, unless the re-declarations come from the same | |
62 | * included file as the original. | |
63 | * | |
64 | * As an include file symbol is encountered in a source | |
65 | * file, the symbol table entry of each symbol declared in that | |
66 | * include file is modified to reflect its new logical | |
67 | * inclusion in the source file. File symbols are also | |
68 | * encountered as an included file ends, signaling the | |
69 | * continuation of the enclosing file. | |
70 | * | |
71 | * Functions and procedures which have been declared | |
72 | * external may be resolved by declarations from source files | |
73 | * which included the external declaration of the function. | |
74 | * Functions and procedures may be resolved at most once across | |
75 | * a set of object files. The loader will complain if a | |
76 | * function is not resolved at least once. | |
77 | */ | |
78 | \f | |
26c1063b | 79 | char program[] = "pc"; |
893f2bd0 PK |
80 | |
81 | #include <sys/types.h> | |
840fc587 | 82 | #include <sys/stat.h> |
893f2bd0 PK |
83 | #include <ar.h> |
84 | #include <stdio.h> | |
85 | #include <ctype.h> | |
86 | #include <a.out.h> | |
87 | #include <stab.h> | |
a3aa5379 | 88 | #include "pstab.h" |
893f2bd0 PK |
89 | #include "pc3.h" |
90 | ||
f54dd2f6 PK |
91 | int errors = NONE; |
92 | BOOL wflag = FALSE; | |
893f2bd0 PK |
93 | |
94 | /* | |
95 | * check each of the argument .o files (or archives of .o files). | |
96 | */ | |
97 | main( argc , argv ) | |
98 | int argc; | |
99 | char **argv; | |
100 | { | |
101 | struct fileinfo ofile; | |
102 | ||
f54dd2f6 PK |
103 | for ( argv++ ; *argv != 0 && **argv == '-' ; argv++ ) { |
104 | (*argv)++; | |
105 | switch ( **argv ) { | |
106 | default: | |
107 | error( FATAL , "pc3: bad flag -%c\n" , **argv ); | |
108 | case 'w': | |
109 | wflag = TRUE; | |
110 | break; | |
111 | } | |
112 | } | |
113 | for ( /* void */ ; *argv != 0 ; argv++ ) { | |
893f2bd0 PK |
114 | # ifdef DEBUG |
115 | fprintf( stderr , "[main] *argv = %s\n" , *argv ); | |
116 | # endif DEBUG | |
117 | ofile.name = *argv; | |
118 | checkfile( &ofile ); | |
893f2bd0 PK |
119 | } |
120 | exit( errors ); | |
121 | } | |
122 | ||
123 | /* | |
124 | * check the namelist of a file, or all namelists of an archive. | |
125 | */ | |
126 | checkfile( ofilep ) | |
127 | struct fileinfo *ofilep; | |
128 | { | |
129 | union { | |
130 | char mag_armag[ SARMAG + 1 ]; | |
131 | struct exec mag_exec; | |
132 | } mag_un; | |
133 | int red; | |
134 | struct stat filestat; | |
135 | ||
136 | ofilep -> file = fopen( ofilep -> name , "r" ); | |
137 | if ( ofilep -> file == NULL ) { | |
f54dd2f6 | 138 | error( ERROR , "cannot open: %s" , ofilep -> name ); |
893f2bd0 PK |
139 | return; |
140 | } | |
141 | fstat( fileno( ofilep -> file ) , &filestat ); | |
893f2bd0 PK |
142 | red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file ); |
143 | if ( red != sizeof mag_un ) { | |
f54dd2f6 | 144 | error( ERROR , "cannot read header: %s" , ofilep -> name ); |
893f2bd0 PK |
145 | return; |
146 | } | |
147 | if ( mag_un.mag_exec.a_magic == OARMAG ) { | |
148 | error( WARNING , "old archive: %s" , ofilep -> name ); | |
149 | return; | |
150 | } | |
151 | if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) { | |
152 | /* archive, iterate through elements */ | |
153 | # ifdef DEBUG | |
154 | fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name ); | |
155 | # endif DEBUG | |
156 | ofilep -> nextoffset = SARMAG; | |
157 | while ( nextelement( ofilep ) ) { | |
158 | checknl( ofilep ); | |
159 | } | |
160 | } else if ( N_BADMAG( mag_un.mag_exec ) ) { | |
161 | /* not a file.o */ | |
f54dd2f6 | 162 | error( ERROR , "bad format: %s" , ofilep -> name ); |
893f2bd0 PK |
163 | return; |
164 | } else { | |
165 | /* a file.o */ | |
166 | # ifdef DEBUG | |
167 | fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name ); | |
168 | # endif DEBUG | |
169 | fseek( ofilep -> file , 0L , 0 ); | |
170 | ofilep -> nextoffset = filestat.st_size; | |
171 | checknl( ofilep ); | |
172 | } | |
173 | fclose( ofilep -> file ); | |
174 | } | |
175 | ||
176 | /* | |
177 | * check the namelist of this file for conflicts with | |
178 | * previously entered symbols. | |
179 | */ | |
180 | checknl( ofilep ) | |
181 | register struct fileinfo *ofilep; | |
182 | { | |
183 | ||
184 | long red; | |
b605cae0 | 185 | struct exec oexec; |
893f2bd0 PK |
186 | off_t symoff; |
187 | long numsyms; | |
188 | register struct nlist *nlp; | |
189 | register char *stringp; | |
190 | long strsize; | |
191 | long sym; | |
192 | ||
b605cae0 PK |
193 | red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file ); |
194 | if ( red != sizeof oexec ) { | |
f54dd2f6 | 195 | error( ERROR , "error reading struct exec: %s" |
893f2bd0 PK |
196 | , ofilep -> name ); |
197 | return; | |
198 | } | |
b605cae0 | 199 | if ( N_BADMAG( oexec ) ) { |
893f2bd0 PK |
200 | return; |
201 | } | |
b605cae0 | 202 | symoff = N_SYMOFF( oexec ) - sizeof oexec; |
893f2bd0 | 203 | fseek( ofilep -> file , symoff , 1 ); |
b605cae0 | 204 | numsyms = oexec.a_syms / sizeof ( struct nlist ); |
893f2bd0 PK |
205 | if ( numsyms == 0 ) { |
206 | error( WARNING , "no name list: %s" , ofilep -> name ); | |
207 | return; | |
208 | } | |
209 | nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) ); | |
210 | if ( nlp == 0 ) { | |
211 | error( FATAL , "no room for %d nlists" , numsyms ); | |
212 | } | |
213 | red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist ) | |
214 | , ofilep -> file ); | |
215 | if ( ftell( ofilep -> file ) + sizeof ( off_t ) | |
216 | >= ofilep -> nextoffset ) { | |
217 | error( WARNING , "no string table (old format .o?)" | |
218 | , ofilep -> name ); | |
219 | return; | |
220 | } | |
221 | red = fread( (char *) &strsize , sizeof strsize , 1 | |
222 | , ofilep -> file ); | |
223 | if ( red != 1 ) { | |
224 | error( WARNING , "no string table (old format .o?)" | |
225 | , ofilep -> name ); | |
226 | return; | |
227 | } | |
228 | stringp = ( char * ) malloc( strsize ); | |
229 | if ( stringp == 0 ) { | |
230 | error( FATAL , "no room for %d bytes of strings" , strsize ); | |
231 | } | |
232 | red = fread( stringp + sizeof strsize | |
233 | , strsize - sizeof ( strsize ) , 1 , ofilep -> file ); | |
234 | if ( red != 1 ) { | |
235 | error( WARNING , "error reading string table: %s" | |
236 | , ofilep -> name ); | |
237 | } | |
238 | # ifdef DEBUG | |
239 | fprintf( stderr , "[checknl] %s: %d symbols\n" | |
240 | , ofilep -> name , numsyms ); | |
241 | # endif DEBUG | |
242 | for ( sym = 0 ; sym < numsyms ; sym++) { | |
243 | if ( nlp[ sym ].n_un.n_strx ) { | |
244 | nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx; | |
245 | } else { | |
246 | nlp[ sym ].n_un.n_name = ""; | |
247 | } | |
248 | checksymbol( &nlp[ sym ] , ofilep ); | |
249 | } | |
250 | if ( nlp ) { | |
251 | free( nlp ); | |
252 | } | |
253 | if ( stringp ) { | |
254 | free( stringp ); | |
255 | } | |
256 | } | |
257 | ||
258 | /* | |
259 | * check a symbol. | |
260 | * look it up in the hashed symbol table, | |
261 | * entering it if necessary. | |
262 | * this maintains a state of which .p and .i files | |
263 | * it is currently in the midst from the nlist entries | |
264 | * for source and included files. | |
265 | * if we are inside a .p but not a .i, pfilep == ifilep. | |
266 | */ | |
267 | checksymbol( nlp , ofilep ) | |
268 | struct nlist *nlp; | |
269 | struct fileinfo *ofilep; | |
270 | { | |
271 | static struct symbol *pfilep = NIL; | |
272 | static struct symbol *ifilep = NIL; | |
273 | register struct symbol *symbolp; | |
a65b6a9e | 274 | int errtype; |
893f2bd0 PK |
275 | |
276 | # ifdef DEBUG | |
277 | if ( pfilep && ifilep ) { | |
278 | fprintf( stderr , "[checksymbol] pfile %s ifile %s\n" | |
279 | , pfilep -> name , ifilep -> name ); | |
280 | } | |
99f6998f PK |
281 | fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n" |
282 | , nlp -> n_un.n_name , nlp -> n_desc | |
283 | , classify( nlp -> n_desc ) ); | |
893f2bd0 | 284 | # endif DEBUG |
99f6998f PK |
285 | if ( nlp -> n_type != N_PC ) { |
286 | /* don't care about the others */ | |
287 | return; | |
893f2bd0 | 288 | } |
99f6998f | 289 | symbolp = entersymbol( nlp -> n_un.n_name ); |
893f2bd0 PK |
290 | if ( symbolp -> lookup == NEW ) { |
291 | # ifdef DEBUG | |
292 | fprintf( stderr , "[checksymbol] ->name %s is NEW\n" | |
293 | , symbolp -> name ); | |
294 | # endif DEBUG | |
99f6998f | 295 | symbolp -> desc = nlp -> n_desc; |
2dc241d5 | 296 | symbolp -> fromp = pfilep; |
99f6998f | 297 | switch ( symbolp -> desc ) { |
1eaf955b PK |
298 | default: |
299 | error( FATAL , "panic: [checksymbol] NEW" ); | |
99f6998f PK |
300 | case N_PGLABEL: |
301 | case N_PGCONST: | |
302 | case N_PGTYPE: | |
893f2bd0 | 303 | case N_PGVAR: |
99f6998f PK |
304 | case N_PGFUNC: |
305 | case N_PGPROC: | |
a65b6a9e PK |
306 | case N_PLDATA: |
307 | case N_PLTEXT: | |
b605cae0 PK |
308 | symbolp -> sym_un.sym_str.rfilep = ifilep; |
309 | symbolp -> sym_un.sym_str.rline = nlp -> n_value; | |
b605cae0 PK |
310 | symbolp -> sym_un.sym_str.fromi = ifilep; |
311 | symbolp -> sym_un.sym_str.iline = nlp -> n_value; | |
312 | return; | |
99f6998f PK |
313 | case N_PEFUNC: |
314 | case N_PEPROC: | |
b605cae0 PK |
315 | symbolp -> sym_un.sym_str.rfilep = NIL; |
316 | symbolp -> sym_un.sym_str.rline = 0; | |
317 | /* | |
318 | * functions can only be declared external | |
319 | * in included files. | |
320 | */ | |
321 | if ( pfilep == ifilep ) { | |
322 | error( WARNING | |
323 | , "%s, line %d: %s %s must be declared in included file" | |
324 | , pfilep -> name , nlp -> n_value | |
99f6998f | 325 | , classify( symbolp -> desc ) |
b605cae0 PK |
326 | , symbolp -> name ); |
327 | } | |
893f2bd0 PK |
328 | symbolp -> sym_un.sym_str.fromi = ifilep; |
329 | symbolp -> sym_un.sym_str.iline = nlp -> n_value; | |
893f2bd0 PK |
330 | return; |
331 | case N_PSO: | |
2dc241d5 PK |
332 | if ( nlp -> n_value < N_FLAGCHECKSUM ) { |
333 | error( WARNING, | |
334 | "%s is out of date and should be recompiled", | |
335 | ofilep -> name ); | |
336 | } | |
893f2bd0 | 337 | pfilep = symbolp; |
2dc241d5 PK |
338 | ifilep = symbolp; |
339 | symbolp -> sym_un.checksum = N_FLAGCHECKSUM; | |
340 | return; | |
893f2bd0 PK |
341 | case N_PSOL: |
342 | ifilep = symbolp; | |
2dc241d5 | 343 | symbolp -> sym_un.checksum = nlp -> n_value; |
893f2bd0 PK |
344 | return; |
345 | } | |
346 | } else { | |
347 | # ifdef DEBUG | |
348 | fprintf( stderr , "[checksymbol] ->name %s is OLD\n" | |
349 | , symbolp -> name ); | |
350 | # endif DEBUG | |
a65b6a9e | 351 | errtype = ERROR; |
99f6998f | 352 | switch ( symbolp -> desc ) { |
1eaf955b PK |
353 | default: |
354 | error( FATAL , "panic [checksymbol] OLD" ); | |
2dc241d5 | 355 | return; |
893f2bd0 PK |
356 | case N_PSO: |
357 | /* | |
358 | * finding a file again means you are back | |
359 | * in it after finishing an include file. | |
360 | */ | |
2dc241d5 PK |
361 | if ( symbolp -> desc != nlp -> n_desc ) { |
362 | error( FATAL , "panic [checksymbol] PSO" ); | |
363 | return; | |
364 | } | |
893f2bd0 | 365 | pfilep = symbolp; |
2dc241d5 PK |
366 | ifilep = symbolp; |
367 | return; | |
893f2bd0 PK |
368 | case N_PSOL: |
369 | /* | |
370 | * include files can be seen more than once, | |
2dc241d5 PK |
371 | * but their checksums are checked if they are |
372 | * greater than N_FLAGCHECKSUM. | |
373 | * PSOL's are seen with checksums as the | |
374 | * include file is entered, and with | |
375 | * N_FLAGCHECKSUM as we are back in an | |
376 | * included file from a nested include. | |
893f2bd0 | 377 | */ |
2dc241d5 PK |
378 | if ( symbolp -> desc != nlp -> n_desc ) { |
379 | error( FATAL , "panic [checksymbol] PSOL" ); | |
380 | return; | |
381 | } | |
382 | if ((unsigned) symbolp->sym_un.checksum > N_FLAGCHECKSUM | |
383 | && (unsigned) nlp -> n_value > N_FLAGCHECKSUM | |
384 | && symbolp -> sym_un.checksum != nlp -> n_value ) { | |
385 | error( ERROR, | |
386 | "%s included in %s differs from %s included in %s", | |
387 | symbolp -> name, pfilep -> name, | |
388 | symbolp -> name, symbolp -> fromp -> name ); | |
893f2bd0 | 389 | } |
2dc241d5 | 390 | ifilep = symbolp; |
893f2bd0 | 391 | return; |
99f6998f PK |
392 | case N_PEFUNC: |
393 | case N_PEPROC: | |
893f2bd0 | 394 | /* |
1eaf955b PK |
395 | * this might be the resolution of the external |
396 | * has to match func/proc of external | |
397 | * and has to have included external | |
398 | * and has to not have been previously resolved. | |
893f2bd0 | 399 | */ |
1eaf955b PK |
400 | if ( ( ( symbolp -> desc == N_PEFUNC |
401 | && nlp -> n_desc == N_PGFUNC ) | |
402 | || ( symbolp -> desc == N_PEPROC | |
403 | && nlp -> n_desc == N_PGPROC ) ) | |
2dc241d5 | 404 | && ( symbolp -> fromp == pfilep ) |
1eaf955b PK |
405 | && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) { |
406 | /* | |
407 | * resolve external | |
408 | */ | |
409 | # ifdef DEBUG | |
410 | fprintf( stderr , "[checksymbol] resolving external\n" ); | |
411 | # endif DEBUG | |
412 | symbolp -> sym_un.sym_str.rfilep = ifilep; | |
413 | symbolp -> sym_un.sym_str.rline = nlp -> n_value; | |
414 | return; | |
893f2bd0 PK |
415 | } |
416 | /* | |
1eaf955b PK |
417 | * otherwise, it might be another external, |
418 | * which is okay if it's | |
419 | * the same type and from the same include file | |
893f2bd0 | 420 | */ |
1eaf955b PK |
421 | if ( ( ( symbolp -> desc == N_PEFUNC |
422 | && nlp -> n_desc == N_PEFUNC ) | |
423 | || ( symbolp -> desc == N_PEPROC | |
424 | && nlp -> n_desc == N_PEPROC ) ) | |
425 | && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) { | |
426 | /* | |
427 | * just another pretty external | |
428 | * make it look like it comes from here. | |
429 | */ | |
430 | # ifdef DEBUG | |
431 | fprintf( stderr , "[checksymbol] just another pretty external\n" ); | |
432 | # endif DEBUG | |
2dc241d5 | 433 | symbolp -> fromp = pfilep; |
1eaf955b | 434 | return; |
893f2bd0 PK |
435 | } |
436 | /* | |
1eaf955b | 437 | * something is wrong |
f54dd2f6 PK |
438 | * if it's not resolved, use the header file |
439 | * otherwise, it's just a regular error | |
893f2bd0 | 440 | */ |
f54dd2f6 PK |
441 | if ( symbolp -> sym_un.sym_str.rfilep == NIL ) { |
442 | error( ERROR , | |
a65b6a9e | 443 | "%s, line %d: %s is already defined\n\t(%s, line %d)." , |
f54dd2f6 PK |
444 | ifilep -> name , nlp -> n_value , |
445 | nlp -> n_un.n_name , | |
446 | symbolp -> sym_un.sym_str.fromi -> name , | |
447 | symbolp -> sym_un.sym_str.iline ); | |
448 | return; | |
449 | } | |
450 | break; | |
99f6998f PK |
451 | case N_PGFUNC: |
452 | case N_PGPROC: | |
893f2bd0 PK |
453 | /* |
454 | * functions may not be seen more than once. | |
455 | * the loader will complain about | |
456 | * `multiply defined', but we can, too. | |
457 | */ | |
458 | break; | |
99f6998f PK |
459 | case N_PGLABEL: |
460 | case N_PGCONST: | |
461 | case N_PGTYPE: | |
893f2bd0 PK |
462 | case N_PGVAR: |
463 | /* | |
464 | * labels, constants, types, variables | |
465 | * and external declarations | |
466 | * may be seen as many times as they want, | |
467 | * as long as they come from the same include file. | |
468 | * make it look like they come from this .p file. | |
469 | */ | |
470 | included: | |
99f6998f | 471 | if ( nlp -> n_desc != symbolp -> desc |
893f2bd0 PK |
472 | || symbolp -> sym_un.sym_str.fromi != ifilep ) { |
473 | break; | |
474 | } | |
2dc241d5 | 475 | symbolp -> fromp = pfilep; |
893f2bd0 | 476 | return; |
a65b6a9e PK |
477 | case N_PLDATA: |
478 | case N_PLTEXT: | |
479 | switch ( nlp -> n_desc ) { | |
480 | default: | |
481 | error( FATAL , "pc3: unknown stab 0x%x" | |
482 | , nlp -> n_desc ); | |
483 | return; | |
484 | case N_PSO: | |
485 | case N_PSOL: | |
486 | case N_PGCONST: | |
487 | case N_PGTYPE: | |
488 | /* these won't conflict with library */ | |
489 | return; | |
490 | case N_PGLABEL: | |
491 | case N_PGVAR: | |
492 | case N_PGFUNC: | |
493 | case N_PGPROC: | |
494 | case N_PEFUNC: | |
495 | case N_PEPROC: | |
496 | case N_PLDATA: | |
497 | case N_PLTEXT: | |
498 | errtype = WARNING; | |
499 | break; | |
500 | } | |
501 | break; | |
893f2bd0 PK |
502 | } |
503 | /* | |
504 | * this is the breaks | |
505 | */ | |
a65b6a9e PK |
506 | error( errtype |
507 | , "%s, line %d: %s %s is already defined\n\t%s%s (%s, line %d)." | |
508 | , ifilep -> name | |
509 | , nlp -> n_value | |
510 | , classify( nlp -> n_desc ) | |
511 | , nlp -> n_un.n_name | |
512 | , ( symbolp -> desc == nlp -> n_desc ? "" : " as " ) | |
513 | , ( symbolp -> desc == nlp -> n_desc | |
514 | ? "" : article( symbolp -> desc ) ) | |
515 | , symbolp -> sym_un.sym_str.rfilep -> name | |
516 | , symbolp -> sym_un.sym_str.rline ); | |
893f2bd0 PK |
517 | } |
518 | } | |
519 | ||
520 | /* | |
521 | * quadratically hashed symbol table. | |
522 | * things are never deleted from the hash symbol table. | |
523 | * as more hash table is needed, | |
524 | * a new one is alloc'ed and chained to the end. | |
525 | * search is by rehashing within each table, | |
526 | * traversing chains to next table if unsuccessful. | |
527 | */ | |
893f2bd0 PK |
528 | struct symbol * |
529 | entersymbol( name ) | |
530 | char *name; | |
531 | { | |
29f8a6a1 | 532 | static struct symboltableinfo symboltable; |
893f2bd0 PK |
533 | char *enteredname; |
534 | long hashindex; | |
535 | register struct symboltableinfo *tablep; | |
536 | register struct symbol **herep; | |
537 | register struct symbol **limitp; | |
538 | register long increment; | |
539 | ||
540 | enteredname = enterstring( name ); | |
541 | hashindex = SHORT_ABS( ( long ) enteredname ) % SYMBOLPRIME; | |
29f8a6a1 | 542 | for ( tablep = &symboltable ; /*return*/ ; tablep = tablep -> chain ) { |
893f2bd0 | 543 | if ( tablep == NIL ) { |
29f8a6a1 PK |
544 | # ifdef SPACEDEBUG |
545 | fprintf( stderr , | |
546 | "[entersymbol] calloc'ing table for %d symbols\n" , | |
547 | SYMBOLPRIME ); | |
548 | # endif SPACEDEBUG | |
549 | for ( tablep = &symboltable | |
550 | ; tablep->chain != NIL | |
551 | ; tablep = tablep->chain ) { | |
552 | continue; | |
893f2bd0 | 553 | } |
29f8a6a1 PK |
554 | tablep->chain = ( struct symboltableinfo * ) |
555 | calloc( 1 , sizeof ( struct symboltableinfo ) ); | |
556 | if ( tablep->chain == NIL ) { | |
557 | error( FATAL , "ran out of memory (entersymbol)" ); | |
893f2bd0 | 558 | } |
29f8a6a1 | 559 | tablep = tablep->chain; |
893f2bd0 PK |
560 | } |
561 | herep = &( tablep -> entry[ hashindex ] ); | |
562 | limitp = &( tablep -> entry[ SYMBOLPRIME ] ); | |
563 | increment = 1; | |
564 | do { | |
893f2bd0 PK |
565 | if ( *herep == NIL ) { |
566 | /* empty */ | |
29f8a6a1 | 567 | if ( tablep -> used > ( ( SYMBOLPRIME / 4 ) * 3 ) ) { |
893f2bd0 PK |
568 | /* too full, break for next table */ |
569 | break; | |
570 | } | |
571 | tablep -> used++; | |
572 | *herep = symbolalloc(); | |
573 | ( *herep ) -> name = enteredname; | |
574 | ( *herep ) -> lookup = NEW; | |
29f8a6a1 PK |
575 | # ifdef HASHDEBUG |
576 | fprintf( stderr , | |
577 | "[entersymbol] name %s NEW after %d\n" , | |
578 | enteredname , increment / 2 ); | |
579 | # endif HASHDEBUG | |
893f2bd0 PK |
580 | return *herep; |
581 | } | |
582 | /* a find? */ | |
583 | if ( ( *herep ) -> name == enteredname ) { | |
584 | ( *herep ) -> lookup = OLD; | |
29f8a6a1 PK |
585 | # ifdef HASHDEBUG |
586 | fprintf( stderr , "[entersymbol] name %s OLD at %d\n" , | |
587 | enteredname , increment / 2 ); | |
588 | # endif HASHDEBUG | |
893f2bd0 PK |
589 | return *herep; |
590 | } | |
591 | herep += increment; | |
592 | if ( herep >= limitp ) { | |
593 | herep -= SYMBOLPRIME; | |
594 | } | |
595 | increment += 2; | |
596 | } while ( increment < SYMBOLPRIME ); | |
29f8a6a1 PK |
597 | # ifdef HASHDEBUG |
598 | fprintf( stderr , "[entersymbol] next symboltable\n" ); | |
599 | # endif HASHDEBUG | |
893f2bd0 PK |
600 | } |
601 | } | |
602 | ||
603 | /* | |
604 | * allocate a symbol from the dynamically allocated symbol table. | |
605 | */ | |
893f2bd0 PK |
606 | struct symbol * |
607 | symbolalloc() | |
608 | { | |
609 | static struct symbol *nextsymbol = NIL; | |
610 | static long symbolsleft = 0; | |
611 | struct symbol *newsymbol; | |
612 | ||
613 | if ( symbolsleft <= 0 ) { | |
29f8a6a1 PK |
614 | # ifdef SPACEDEBUG |
615 | fprintf( stderr , | |
616 | "[symbolalloc] malloc space for %d symbols\n" , | |
617 | SYMBOLALLOC / sizeof( struct symbol ) ); | |
618 | # endif SPACEDEBUG | |
893f2bd0 PK |
619 | nextsymbol = ( struct symbol * ) malloc( SYMBOLALLOC ); |
620 | if ( nextsymbol == 0 ) { | |
621 | error( FATAL , "ran out of memory (symbolalloc)" ); | |
622 | } | |
623 | symbolsleft = SYMBOLALLOC / sizeof( struct symbol ); | |
624 | } | |
625 | newsymbol = nextsymbol; | |
626 | nextsymbol++; | |
627 | symbolsleft--; | |
628 | return newsymbol; | |
629 | } | |
630 | ||
631 | /* | |
632 | * hash a string based on all of its characters. | |
633 | */ | |
634 | long | |
635 | hashstring( string ) | |
636 | char *string; | |
637 | { | |
638 | register char *cp; | |
639 | register long value; | |
640 | ||
641 | value = 0; | |
642 | for ( cp = string ; *cp ; cp++ ) { | |
643 | value = ( value * 2 ) + *cp; | |
644 | } | |
645 | return value; | |
646 | } | |
647 | ||
648 | /* | |
649 | * quadratically hashed string table. | |
650 | * things are never deleted from the hash string table. | |
651 | * as more hash table is needed, | |
652 | * a new one is alloc'ed and chained to the end. | |
653 | * search is by rehashing within each table, | |
654 | * traversing chains to next table if unsuccessful. | |
655 | */ | |
893f2bd0 PK |
656 | char * |
657 | enterstring( string ) | |
658 | char *string; | |
659 | { | |
29f8a6a1 | 660 | static struct stringtableinfo stringtable; |
893f2bd0 PK |
661 | long hashindex; |
662 | register struct stringtableinfo *tablep; | |
663 | register char **herep; | |
664 | register char **limitp; | |
665 | register long increment; | |
666 | ||
667 | hashindex = SHORT_ABS( hashstring( string ) ) % STRINGPRIME; | |
29f8a6a1 | 668 | for ( tablep = &stringtable ; /*return*/ ; tablep = tablep -> chain ) { |
893f2bd0 | 669 | if ( tablep == NIL ) { |
29f8a6a1 PK |
670 | # ifdef SPACEDEBUG |
671 | fprintf( stderr , | |
672 | "[enterstring] calloc space for %d strings\n" , | |
673 | STRINGPRIME ); | |
674 | # endif SPACEDEBUG | |
675 | for ( tablep = &stringtable | |
676 | ; tablep->chain != NIL | |
677 | ; tablep = tablep->chain ) { | |
678 | continue; | |
893f2bd0 | 679 | } |
29f8a6a1 PK |
680 | tablep->chain = ( struct stringtableinfo * ) |
681 | calloc( 1 , sizeof ( struct stringtableinfo ) ); | |
682 | if ( tablep->chain == NIL ) { | |
683 | error( FATAL , "ran out of memory (enterstring)" ); | |
893f2bd0 | 684 | } |
29f8a6a1 | 685 | tablep = tablep->chain; |
893f2bd0 PK |
686 | } |
687 | herep = &( tablep -> entry[ hashindex ] ); | |
688 | limitp = &( tablep -> entry[ STRINGPRIME ] ); | |
689 | increment = 1; | |
690 | do { | |
893f2bd0 PK |
691 | if ( *herep == NIL ) { |
692 | /* empty */ | |
29f8a6a1 | 693 | if ( tablep -> used > ( ( STRINGPRIME / 4 ) * 3 ) ) { |
893f2bd0 PK |
694 | /* too full, break for next table */ |
695 | break; | |
696 | } | |
697 | tablep -> used++; | |
698 | *herep = charalloc( strlen( string ) ); | |
699 | strcpy( *herep , string ); | |
29f8a6a1 PK |
700 | # ifdef HASHDEBUG |
701 | fprintf( stderr , | |
702 | "[enterstring] string %s copied after %d\n" , | |
703 | *herep , increment / 2 ); | |
704 | # endif HASHDEBUG | |
893f2bd0 PK |
705 | return *herep; |
706 | } | |
707 | /* quick, check the first chars and then the rest */ | |
708 | if ( **herep == *string && strcmp( *herep , string ) == 0 ) { | |
29f8a6a1 PK |
709 | # ifdef HASHDEBUG |
710 | fprintf( stderr , | |
711 | "[enterstring] string %s found after %d\n" , | |
712 | *herep , increment / 2 ); | |
713 | # endif HASHDEBUG | |
893f2bd0 PK |
714 | return *herep; |
715 | } | |
716 | herep += increment; | |
717 | if ( herep >= limitp ) { | |
718 | herep -= STRINGPRIME; | |
719 | } | |
720 | increment += 2; | |
721 | } while ( increment < STRINGPRIME ); | |
29f8a6a1 PK |
722 | # ifdef HASHDEBUG |
723 | fprintf( stderr , "[enterstring] next stringtable\n" ); | |
724 | # endif HASHDEBUG | |
893f2bd0 PK |
725 | } |
726 | } | |
727 | ||
728 | /* | |
729 | * copy a string to the dynamically allocated character table. | |
730 | */ | |
893f2bd0 PK |
731 | char * |
732 | charalloc( length ) | |
733 | register long length; | |
734 | { | |
735 | static char *nextchar = NIL; | |
736 | static long charsleft = 0; | |
737 | register long lengthplus1 = length + 1; | |
738 | register long askfor; | |
739 | char *newstring; | |
740 | ||
741 | if ( charsleft < lengthplus1 ) { | |
742 | askfor = lengthplus1 > CHARALLOC ? lengthplus1 : CHARALLOC; | |
29f8a6a1 PK |
743 | # ifdef SPACEDEBUG |
744 | fprintf( stderr , "[charalloc] malloc space for %d chars\n" | |
893f2bd0 | 745 | , askfor ); |
29f8a6a1 | 746 | # endif SPACEDEBUG |
893f2bd0 PK |
747 | nextchar = ( char * ) malloc( askfor ); |
748 | if ( nextchar == 0 ) { | |
749 | error( FATAL , "no room for %d characters" , askfor ); | |
750 | } | |
751 | charsleft = askfor; | |
752 | } | |
753 | newstring = nextchar; | |
754 | nextchar += lengthplus1; | |
755 | charsleft -= lengthplus1; | |
756 | return newstring; | |
757 | } | |
758 | ||
759 | /* | |
760 | * read an archive header for the next element | |
761 | * and find the offset of the one after this. | |
762 | */ | |
763 | BOOL | |
764 | nextelement( ofilep ) | |
765 | struct fileinfo *ofilep; | |
766 | { | |
767 | register char *cp; | |
768 | register long red; | |
769 | register off_t arsize; | |
770 | struct ar_hdr archdr; | |
771 | ||
772 | fseek( ofilep -> file , ofilep -> nextoffset , 0 ); | |
773 | red = fread( (char *) &archdr , 1 , sizeof archdr , ofilep -> file ); | |
774 | if ( red != sizeof archdr ) { | |
775 | return FALSE; | |
776 | } | |
777 | /* null terminate the blank-padded name */ | |
778 | cp = &archdr.ar_name[ ( sizeof archdr.ar_name ) - 1 ]; | |
779 | *cp = '\0'; | |
780 | while ( *--cp == ' ' ) { | |
781 | *cp = '\0'; | |
782 | } | |
783 | /* set up the address of the beginning of next element */ | |
784 | arsize = atol( archdr.ar_size ); | |
785 | /* archive elements are aligned on 0 mod 2 boundaries */ | |
786 | if ( arsize & 1 ) { | |
787 | arsize += 1; | |
788 | } | |
789 | ofilep -> nextoffset = ftell( ofilep -> file ) + arsize; | |
790 | /* say we had one */ | |
791 | return TRUE; | |
792 | } | |
793 | ||
794 | /* | |
795 | * variable number of arguments to error, like printf. | |
796 | */ | |
a65b6a9e | 797 | error( type , message , arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 ) |
f54dd2f6 | 798 | int type; |
893f2bd0 PK |
799 | char *message; |
800 | { | |
f54dd2f6 PK |
801 | errors = type > errors ? type : errors; |
802 | if ( wflag && type == WARNING ) { | |
803 | return; | |
804 | } | |
893f2bd0 | 805 | fprintf( stderr , "%s: " , program ); |
f54dd2f6 PK |
806 | switch ( type ) { |
807 | case WARNING: | |
808 | fprintf( stderr , "Warning: " ); | |
809 | break; | |
810 | case ERROR: | |
811 | fprintf( stderr , "Error: " ); | |
812 | break; | |
813 | case FATAL: | |
814 | fprintf( stderr , "Fatal: " ); | |
815 | break; | |
816 | default: | |
817 | fprintf( stderr , "Ooops: " ); | |
818 | break; | |
819 | } | |
a65b6a9e | 820 | fprintf( stderr , message , arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 ); |
893f2bd0 | 821 | fprintf( stderr , "\n" ); |
f54dd2f6 PK |
822 | if ( type == FATAL ) { |
823 | exit( FATAL ); | |
893f2bd0 | 824 | } |
893f2bd0 PK |
825 | } |
826 | ||
893f2bd0 PK |
827 | char * |
828 | classify( type ) | |
829 | unsigned char type; | |
830 | { | |
831 | switch ( type ) { | |
832 | case N_PSO: | |
833 | return "source file"; | |
834 | case N_PSOL: | |
835 | return "include file"; | |
99f6998f | 836 | case N_PGLABEL: |
893f2bd0 | 837 | return "label"; |
99f6998f | 838 | case N_PGCONST: |
893f2bd0 | 839 | return "constant"; |
99f6998f | 840 | case N_PGTYPE: |
893f2bd0 PK |
841 | return "type"; |
842 | case N_PGVAR: | |
843 | return "variable"; | |
99f6998f | 844 | case N_PGFUNC: |
893f2bd0 | 845 | return "function"; |
99f6998f | 846 | case N_PGPROC: |
893f2bd0 | 847 | return "procedure"; |
99f6998f | 848 | case N_PEFUNC: |
893f2bd0 | 849 | return "external function"; |
99f6998f | 850 | case N_PEPROC: |
893f2bd0 | 851 | return "external procedure"; |
a65b6a9e PK |
852 | case N_PLDATA: |
853 | return "library variable"; | |
854 | case N_PLTEXT: | |
855 | return "library routine"; | |
893f2bd0 PK |
856 | default: |
857 | return "unknown symbol"; | |
858 | } | |
859 | } | |
a65b6a9e PK |
860 | |
861 | char * | |
862 | article( type ) | |
863 | unsigned char type; | |
864 | { | |
865 | switch ( type ) { | |
866 | case N_PSO: | |
867 | return "a source file"; | |
868 | case N_PSOL: | |
869 | return "an include file"; | |
870 | case N_PGLABEL: | |
871 | return "a label"; | |
872 | case N_PGCONST: | |
873 | return "a constant"; | |
874 | case N_PGTYPE: | |
875 | return "a type"; | |
876 | case N_PGVAR: | |
877 | return "a variable"; | |
878 | case N_PGFUNC: | |
879 | return "a function"; | |
880 | case N_PGPROC: | |
881 | return "a procedure"; | |
882 | case N_PEFUNC: | |
883 | return "an external function"; | |
884 | case N_PEPROC: | |
885 | return "an external procedure"; | |
886 | case N_PLDATA: | |
887 | return "a library variable"; | |
888 | case N_PLTEXT: | |
889 | return "a library routine"; | |
890 | default: | |
891 | return "an unknown symbol"; | |
892 | } | |
893 | } |