]> git.saurik.com Git - bison.git/blame_incremental - src/symtab.c
Use size_t (not unsigned int) for hashes, since the gnulib hash module
[bison.git] / src / symtab.c
... / ...
CommitLineData
1/* Symbol table manager for Bison.
2
3 Copyright (C) 1984, 1989, 2000, 2001, 2002, 2004 Free Software
4 Foundation, Inc.
5
6 This file is part of Bison, the GNU Compiler Compiler.
7
8 Bison is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 Bison is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Bison; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
22
23
24#include "system.h"
25
26#include <hash.h>
27#include <quotearg.h>
28
29#include "complain.h"
30#include "gram.h"
31#include "symtab.h"
32
33/*------------------------.
34| Distinguished symbols. |
35`------------------------*/
36
37symbol *errtoken = NULL;
38symbol *undeftoken = NULL;
39symbol *endtoken = NULL;
40symbol *accept = NULL;
41symbol *startsymbol = NULL;
42location startsymbol_location;
43
44/*---------------------------------.
45| Create a new symbol, named TAG. |
46`---------------------------------*/
47
48static symbol *
49symbol_new (uniqstr tag, location loc)
50{
51 symbol *res = MALLOC (res, 1);
52
53 uniqstr_assert (tag);
54 res->tag = tag;
55 res->location = loc;
56
57 res->type_name = NULL;
58 res->destructor = NULL;
59 res->printer = NULL;
60
61 res->number = NUMBER_UNDEFINED;
62 res->prec = 0;
63 res->assoc = undef_assoc;
64 res->user_token_number = USER_NUMBER_UNDEFINED;
65
66 res->alias = NULL;
67 res->class = unknown_sym;
68
69 nsyms++;
70 return res;
71}
72
73
74/*-----------------------------------------------------------------.
75| Set the TYPE_NAME associated with SYM. Does nothing if passed 0 |
76| as TYPE_NAME. |
77`-----------------------------------------------------------------*/
78
79void
80symbol_type_set (symbol *sym, uniqstr type_name, location loc)
81{
82 if (type_name)
83 {
84 if (sym->type_name)
85 complain_at (loc, _("type redeclaration for %s"), sym->tag);
86 uniqstr_assert (type_name);
87 sym->type_name = type_name;
88 }
89}
90
91
92/*------------------------------------------------------------------.
93| Set the DESTRUCTOR associated with SYM. Do nothing if passed 0. |
94`------------------------------------------------------------------*/
95
96void
97symbol_destructor_set (symbol *sym, char *destructor, location loc)
98{
99 if (destructor)
100 {
101 if (sym->destructor)
102 complain_at (loc, _("%s redeclaration for %s"),
103 "%destructor", sym->tag);
104 sym->destructor = destructor;
105 sym->destructor_location = loc;
106 }
107}
108
109
110/*---------------------------------------------------------------.
111| Set the PRINTER associated with SYM. Do nothing if passed 0. |
112`---------------------------------------------------------------*/
113
114void
115symbol_printer_set (symbol *sym, char *printer, location loc)
116{
117 if (printer)
118 {
119 if (sym->printer)
120 complain_at (loc, _("%s redeclaration for %s"),
121 "%printer", sym->tag);
122 sym->printer = printer;
123 sym->printer_location = loc;
124 }
125}
126
127
128/*-----------------------------------------------------------------.
129| Set the PRECEDENCE associated with SYM. Does nothing if invoked |
130| with UNDEF_ASSOC as ASSOC. |
131`-----------------------------------------------------------------*/
132
133void
134symbol_precedence_set (symbol *sym, int prec, assoc a, location loc)
135{
136 if (a != undef_assoc)
137 {
138 if (sym->prec != 0)
139 complain_at (loc, _("redefining precedence of %s"), sym->tag);
140 sym->prec = prec;
141 sym->assoc = a;
142 }
143
144 /* Only terminals have a precedence. */
145 symbol_class_set (sym, token_sym, loc);
146}
147
148
149/*------------------------------------.
150| Set the CLASS associated with SYM. |
151`------------------------------------*/
152
153void
154symbol_class_set (symbol *sym, symbol_class class, location loc)
155{
156 if (sym->class != unknown_sym && sym->class != class)
157 complain_at (loc, _("symbol %s redefined"), sym->tag);
158
159 if (class == nterm_sym && sym->class != nterm_sym)
160 sym->number = nvars++;
161 else if (class == token_sym && sym->number == NUMBER_UNDEFINED)
162 sym->number = ntokens++;
163
164 sym->class = class;
165}
166
167
168/*------------------------------------------------.
169| Set the USER_TOKEN_NUMBER associated with SYM. |
170`------------------------------------------------*/
171
172void
173symbol_user_token_number_set (symbol *sym, int user_token_number, location loc)
174{
175 if (sym->class != token_sym)
176 abort ();
177
178 if (sym->user_token_number != USER_NUMBER_UNDEFINED
179 && sym->user_token_number != user_token_number)
180 complain_at (loc, _("redefining user token number of %s"), sym->tag);
181
182 sym->user_token_number = user_token_number;
183 /* User defined $end token? */
184 if (user_token_number == 0)
185 {
186 endtoken = sym;
187 endtoken->number = 0;
188 /* It is always mapped to 0, so it was already counted in
189 NTOKENS. */
190 --ntokens;
191 }
192}
193
194
195/*----------------------------------------------------------.
196| If SYM is not defined, report an error, and consider it a |
197| nonterminal. |
198`----------------------------------------------------------*/
199
200static inline bool
201symbol_check_defined (symbol *sym)
202{
203 if (sym->class == unknown_sym)
204 {
205 complain_at
206 (sym->location,
207 _("symbol %s is used, but is not defined as a token and has no rules"),
208 sym->tag);
209 sym->class = nterm_sym;
210 sym->number = nvars++;
211 }
212
213 return true;
214}
215
216static bool
217symbol_check_defined_processor (void *sym, void *null ATTRIBUTE_UNUSED)
218{
219 return symbol_check_defined (sym);
220}
221
222
223/*------------------------------------------------------------------.
224| Declare the new symbol SYM. Make it an alias of SYMVAL, and type |
225| SYMVAL with SYM's type. |
226`------------------------------------------------------------------*/
227
228void
229symbol_make_alias (symbol *sym, symbol *symval, location loc)
230{
231 if (symval->alias)
232 warn_at (loc, _("symbol `%s' used more than once as a literal string"),
233 symval->tag);
234 else if (sym->alias)
235 warn_at (loc, _("symbol `%s' given more than one literal string"),
236 sym->tag);
237 else
238 {
239 symval->class = token_sym;
240 symval->user_token_number = sym->user_token_number;
241 sym->user_token_number = USER_NUMBER_ALIAS;
242 symval->alias = sym;
243 sym->alias = symval;
244 /* sym and symval combined are only one symbol. */
245 nsyms--;
246 ntokens--;
247 if (ntokens != sym->number && ntokens != symval->number)
248 abort ();
249 sym->number = symval->number =
250 (symval->number < sym->number) ? symval->number : sym->number;
251 symbol_type_set (symval, sym->type_name, loc);
252 }
253}
254
255
256/*---------------------------------------------------------.
257| Check that THIS, and its alias, have same precedence and |
258| associativity. |
259`---------------------------------------------------------*/
260
261static inline bool
262symbol_check_alias_consistency (symbol *this)
263{
264 /* Check only those who _are_ the aliases. */
265 if (this->alias && this->user_token_number == USER_NUMBER_ALIAS)
266 {
267 if (this->prec != this->alias->prec)
268 {
269 if (this->prec != 0 && this->alias->prec != 0)
270 complain_at (this->alias->location,
271 _("conflicting precedences for %s and %s"),
272 this->tag, this->alias->tag);
273 if (this->prec != 0)
274 this->alias->prec = this->prec;
275 else
276 this->prec = this->alias->prec;
277 }
278
279 if (this->assoc != this->alias->assoc)
280 {
281 if (this->assoc != undef_assoc && this->alias->assoc != undef_assoc)
282 complain_at (this->alias->location,
283 _("conflicting associativities for %s (%s) and %s (%s)"),
284 this->tag, assoc_to_string (this->assoc),
285 this->alias->tag, assoc_to_string (this->alias->assoc));
286 if (this->assoc != undef_assoc)
287 this->alias->assoc = this->assoc;
288 else
289 this->assoc = this->alias->assoc;
290 }
291 }
292 return true;
293}
294
295static bool
296symbol_check_alias_consistency_processor (void *this,
297 void *null ATTRIBUTE_UNUSED)
298{
299 return symbol_check_alias_consistency (this);
300}
301
302
303/*-------------------------------------------------------------------.
304| Assign a symbol number, and write the definition of the token name |
305| into FDEFINES. Put in SYMBOLS. |
306`-------------------------------------------------------------------*/
307
308static inline bool
309symbol_pack (symbol *this)
310{
311 if (this->class == nterm_sym)
312 {
313 this->number += ntokens;
314 }
315 else if (this->alias)
316 {
317 /* This symbol and its alias are a single token defn.
318 Allocate a tokno, and assign to both check agreement of
319 prec and assoc fields and make both the same */
320 if (this->number == NUMBER_UNDEFINED)
321 {
322 if (this == endtoken || this->alias == endtoken)
323 this->number = this->alias->number = 0;
324 else
325 {
326 if (this->alias->number == NUMBER_UNDEFINED)
327 abort ();
328 this->number = this->alias->number;
329 }
330 }
331 /* Do not do processing below for USER_NUMBER_ALIASes. */
332 if (this->user_token_number == USER_NUMBER_ALIAS)
333 return true;
334 }
335 else /* this->class == token_sym */
336 {
337 if (this->number == NUMBER_UNDEFINED)
338 abort ();
339 }
340
341 symbols[this->number] = this;
342 return true;
343}
344
345static bool
346symbol_pack_processor (void *this, void *null ATTRIBUTE_UNUSED)
347{
348 return symbol_pack (this);
349}
350
351
352
353
354/*--------------------------------------------------.
355| Put THIS in TOKEN_TRANSLATIONS if it is a token. |
356`--------------------------------------------------*/
357
358static inline bool
359symbol_translation (symbol *this)
360{
361 /* Non-terminal? */
362 if (this->class == token_sym
363 && this->user_token_number != USER_NUMBER_ALIAS)
364 {
365 /* A token which translation has already been set? */
366 if (token_translations[this->user_token_number] != undeftoken->number)
367 complain_at (this->location,
368 _("tokens %s and %s both assigned number %d"),
369 symbols[token_translations[this->user_token_number]]->tag,
370 this->tag, this->user_token_number);
371
372 token_translations[this->user_token_number] = this->number;
373 }
374
375 return true;
376}
377
378static bool
379symbol_translation_processor (void *this, void *null ATTRIBUTE_UNUSED)
380{
381 return symbol_translation (this);
382}
383
384
385/*----------------------.
386| A symbol hash table. |
387`----------------------*/
388
389/* Initial capacity of symbols hash table. */
390#define HT_INITIAL_CAPACITY 257
391
392static struct hash_table *symbol_table = NULL;
393
394static inline bool
395hash_compare_symbol (const symbol *m1, const symbol *m2)
396{
397 /* Since tags are unique, we can compare the pointers themselves. */
398 return UNIQSTR_EQ (m1->tag, m2->tag);
399}
400
401static bool
402hash_symbol_comparator (void const *m1, void const *m2)
403{
404 return hash_compare_symbol (m1, m2);
405}
406
407static inline size_t
408hash_symbol (const symbol *m, size_t tablesize)
409{
410 /* Since tags are unique, we can hash the pointer itself. */
411 return ((uintptr_t) m->tag) % tablesize;
412}
413
414static size_t
415hash_symbol_hasher (void const *m, size_t tablesize)
416{
417 return hash_symbol (m, tablesize);
418}
419
420
421/*-------------------------------.
422| Create the symbol hash table. |
423`-------------------------------*/
424
425void
426symbols_new (void)
427{
428 symbol_table = hash_initialize (HT_INITIAL_CAPACITY,
429 NULL,
430 hash_symbol_hasher,
431 hash_symbol_comparator,
432 free);
433}
434
435
436/*----------------------------------------------------------------.
437| Find the symbol named KEY, and return it. If it does not exist |
438| yet, create it. |
439`----------------------------------------------------------------*/
440
441symbol *
442symbol_get (const char *key, location loc)
443{
444 symbol probe;
445 symbol *entry;
446
447 /* Keep the symbol in a printable form. */
448 key = uniqstr_new (quotearg_style (escape_quoting_style, key));
449 probe.tag = key;
450 entry = hash_lookup (symbol_table, &probe);
451
452 if (!entry)
453 {
454 /* First insertion in the hash. */
455 entry = symbol_new (key, loc);
456 hash_insert (symbol_table, entry);
457 }
458 return entry;
459}
460
461
462/*------------------------------------------------------------------.
463| Generate a dummy nonterminal, whose name cannot conflict with the |
464| user's names. |
465`------------------------------------------------------------------*/
466
467symbol *
468dummy_symbol_get (location loc)
469{
470 /* Incremented for each generated symbol. */
471 static int dummy_count = 0;
472 static char buf[256];
473
474 symbol *sym;
475
476 sprintf (buf, "@%d", ++dummy_count);
477 sym = symbol_get (buf, loc);
478 sym->class = nterm_sym;
479 sym->number = nvars++;
480 return sym;
481}
482
483
484/*-------------------.
485| Free the symbols. |
486`-------------------*/
487
488void
489symbols_free (void)
490{
491 hash_free (symbol_table);
492 free (symbols);
493}
494
495
496/*---------------------------------------------------------------.
497| Look for undefined symbols, report an error, and consider them |
498| terminals. |
499`---------------------------------------------------------------*/
500
501static void
502symbols_do (Hash_processor processor, void *processor_data)
503{
504 hash_do_for_each (symbol_table, processor, processor_data);
505}
506
507
508/*--------------------------------------------------------------.
509| Check that all the symbols are defined. Report any undefined |
510| symbols and consider them nonterminals. |
511`--------------------------------------------------------------*/
512
513void
514symbols_check_defined (void)
515{
516 symbols_do (symbol_check_defined_processor, NULL);
517}
518
519/*------------------------------------------------------------------.
520| Set TOKEN_TRANSLATIONS. Check that no two symbols share the same |
521| number. |
522`------------------------------------------------------------------*/
523
524static void
525symbols_token_translations_init (void)
526{
527 bool num_256_available_p = true;
528 int i;
529
530 /* Find the highest user token number, and whether 256, the POSIX
531 preferred user token number for the error token, is used. */
532 max_user_token_number = 0;
533 for (i = 0; i < ntokens; ++i)
534 {
535 symbol *this = symbols[i];
536 if (this->user_token_number != USER_NUMBER_UNDEFINED)
537 {
538 if (this->user_token_number > max_user_token_number)
539 max_user_token_number = this->user_token_number;
540 if (this->user_token_number == 256)
541 num_256_available_p = false;
542 }
543 }
544
545 /* If 256 is not used, assign it to error, to follow POSIX. */
546 if (num_256_available_p
547 && errtoken->user_token_number == USER_NUMBER_UNDEFINED)
548 errtoken->user_token_number = 256;
549
550 /* Set the missing user numbers. */
551 if (max_user_token_number < 256)
552 max_user_token_number = 256;
553
554 for (i = 0; i < ntokens; ++i)
555 {
556 symbol *this = symbols[i];
557 if (this->user_token_number == USER_NUMBER_UNDEFINED)
558 this->user_token_number = ++max_user_token_number;
559 if (this->user_token_number > max_user_token_number)
560 max_user_token_number = this->user_token_number;
561 }
562
563 CALLOC (token_translations, max_user_token_number + 1);
564
565 /* Initialize all entries for literal tokens to 2, the internal
566 token number for $undefined, which represents all invalid inputs.
567 */
568 for (i = 0; i < max_user_token_number + 1; i++)
569 token_translations[i] = undeftoken->number;
570 symbols_do (symbol_translation_processor, NULL);
571}
572
573
574/*----------------------------------------------------------------.
575| Assign symbol numbers, and write definition of token names into |
576| FDEFINES. Set up vectors SYMBOL_TABLE, TAGS of symbols. |
577`----------------------------------------------------------------*/
578
579void
580symbols_pack (void)
581{
582 CALLOC (symbols, nsyms);
583
584 symbols_do (symbol_check_alias_consistency_processor, NULL);
585 symbols_do (symbol_pack_processor, NULL);
586
587 symbols_token_translations_init ();
588
589 if (startsymbol->class == unknown_sym)
590 fatal_at (startsymbol_location,
591 _("the start symbol %s is undefined"),
592 startsymbol->tag);
593 else if (startsymbol->class == token_sym)
594 fatal_at (startsymbol_location,
595 _("the start symbol %s is a token"),
596 startsymbol->tag);
597}