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