X-Git-Url: https://git.saurik.com/bison.git/blobdiff_plain/31b2b07ef765e9e8734ca273308094804fcc9763..b2a0b7ca70f9490693d517d10c9c4a64c9fc1af0:/src/symtab.c diff --git a/src/symtab.c b/src/symtab.c index ae0993ee..4470f3a1 100644 --- a/src/symtab.c +++ b/src/symtab.c @@ -41,6 +41,15 @@ symbol *accept = NULL; symbol *startsymbol = NULL; location startsymbol_location; +/*-----------------------------------. +| Default %destructor and %printer. | +`-----------------------------------*/ + +static const char *default_destructor = NULL; +static location default_destructor_location; +static const char *default_printer = NULL; +static location default_printer_location; + /*---------------------------------. | Create a new symbol, named TAG. | `---------------------------------*/ @@ -74,6 +83,23 @@ symbol_new (uniqstr tag, location loc) return res; } +/*----------------------------------------. +| Create a new semantic type, named TAG. | +`----------------------------------------*/ + +static semantic_type * +semantic_type_new (uniqstr tag) +{ + semantic_type *res = xmalloc (sizeof *res); + + uniqstr_assert (tag); + res->tag = tag; + res->destructor = NULL; + res->printer = NULL; + + return res; +} + /*-----------------. | Print a symbol. | @@ -105,10 +131,19 @@ symbol_print (symbol *s, FILE *f) `------------------------------------------------------------------*/ static void -redeclaration (symbol* s, const char *what, location first, location second) +symbol_redeclaration (symbol *s, const char *what, location first, + location second) { complain_at (second, _("%s redeclaration for %s"), what, s->tag); - complain_at (first, _("first declaration")); + complain_at (first, _("previous declaration")); +} + +static void +semantic_type_redeclaration (semantic_type *s, const char *what, location first, + location second) +{ + complain_at (second, _("%s redeclaration for <%s>"), what, s->tag); + complain_at (first, _("previous declaration")); } @@ -123,7 +158,7 @@ symbol_type_set (symbol *sym, uniqstr type_name, location loc) if (type_name) { if (sym->type_name) - redeclaration (sym, "%type", sym->type_location, loc); + symbol_redeclaration (sym, "%type", sym->type_location, loc); uniqstr_assert (type_name); sym->type_name = type_name; sym->type_location = loc; @@ -141,12 +176,73 @@ symbol_destructor_set (symbol *sym, const char *destructor, location loc) if (destructor) { if (sym->destructor) - redeclaration (sym, "%destructor", sym->destructor_location, loc); + symbol_redeclaration (sym, "%destructor", sym->destructor_location, + loc); sym->destructor = destructor; sym->destructor_location = loc; } } +/*-------------------------------------------------------------------. +| Set the DESTRUCTOR associated with TYPE. Do nothing if passed 0. | +`-------------------------------------------------------------------*/ + +void +semantic_type_destructor_set (semantic_type *type, const char *destructor, + location loc) +{ + if (destructor) + { + if (type->destructor) + semantic_type_redeclaration (type, "%destructor", + type->destructor_location, loc); + type->destructor = destructor; + type->destructor_location = loc; + } +} + +/*---------------------------------------. +| Get the computed %destructor for SYM. | +`---------------------------------------*/ + +const char * +symbol_destructor_get (symbol *sym) +{ + /* Per-symbol %destructor. */ + if (sym->destructor != NULL) + return sym->destructor; + + /* Per-type %destructor. */ + if (sym->type_name) + { + semantic_type *type = semantic_type_get (sym->type_name); + if (type->destructor) + return type->destructor; + } + + /* Apply the default %destructor only to user-defined symbols. */ + if (sym->tag[0] == '$' || sym == errtoken) + return NULL; + return default_destructor; +} + +/*---------------------------------------------------------------. +| Get the grammar location of the %destructor computed for SYM. | +`---------------------------------------------------------------*/ + +location +symbol_destructor_location_get (symbol *sym) +{ + if (sym->destructor != NULL) + return sym->destructor_location; + if (sym->type_name) + { + semantic_type *type = semantic_type_get (sym->type_name); + if (type->destructor) + return type->destructor_location; + } + return default_destructor_location; +} /*---------------------------------------------------------------. | Set the PRINTER associated with SYM. Do nothing if passed 0. | @@ -158,12 +254,73 @@ symbol_printer_set (symbol *sym, const char *printer, location loc) if (printer) { if (sym->printer) - redeclaration (sym, "%printer", sym->printer_location, loc); + symbol_redeclaration (sym, "%printer", sym->printer_location, loc); sym->printer = printer; sym->printer_location = loc; } } +/*----------------------------------------------------------------. +| Set the PRINTER associated with TYPE. Do nothing if passed 0. | +`----------------------------------------------------------------*/ + +void +semantic_type_printer_set (semantic_type *type, const char *printer, + location loc) +{ + if (printer) + { + if (type->printer) + semantic_type_redeclaration (type, "%printer", type->printer_location, + loc); + type->printer = printer; + type->printer_location = loc; + } +} + +/*------------------------------------. +| Get the computed %printer for SYM. | +`------------------------------------*/ + +const char * +symbol_printer_get (symbol *sym) +{ + /* Per-symbol %printer. */ + if (sym->printer != NULL) + return sym->printer; + + /* Per-type %printer. */ + if (sym->type_name) + { + semantic_type *type = semantic_type_get (sym->type_name); + if (type->printer) + return type->printer; + } + + /* Apply the default %printer only to user-defined symbols. */ + if (sym->tag[0] == '$' || sym == errtoken) + return NULL; + return default_printer; +} + +/*------------------------------------------------------------. +| Get the grammar location of the %printer computed for SYM. | +`------------------------------------------------------------*/ + +location +symbol_printer_location_get (symbol *sym) +{ + if (sym->printer != NULL) + return sym->printer_location; + if (sym->type_name) + { + semantic_type *type = semantic_type_get (sym->type_name); + if (type->printer) + return type->printer_location; + } + return default_printer_location; +} + /*-----------------------------------------------------------------. | Set the PRECEDENCE associated with SYM. Does nothing if invoked | @@ -176,7 +333,8 @@ symbol_precedence_set (symbol *sym, int prec, assoc a, location loc) if (a != undef_assoc) { if (sym->prec != 0) - redeclaration (sym, assoc_to_string (a), sym->prec_location, loc); + symbol_redeclaration (sym, assoc_to_string (a), sym->prec_location, + loc); sym->prec = prec; sym->assoc = a; sym->prec_location = loc; @@ -223,13 +381,19 @@ symbol_class_set (symbol *sym, symbol_class class, location loc, bool declaring) void symbol_user_token_number_set (symbol *sym, int user_token_number, location loc) { + int *user_token_numberp; + assert (sym->class == token_sym); - if (sym->user_token_number != USER_NUMBER_UNDEFINED - && sym->user_token_number != user_token_number) + if (sym->user_token_number != USER_NUMBER_ALIAS) + user_token_numberp = &sym->user_token_number; + else + user_token_numberp = &sym->alias->user_token_number; + if (*user_token_numberp != USER_NUMBER_UNDEFINED + && *user_token_numberp != user_token_number) complain_at (loc, _("redefining user token number of %s"), sym->tag); - sym->user_token_number = user_token_number; + *user_token_numberp = user_token_number; /* User defined $end token? */ if (user_token_number == 0) { @@ -291,12 +455,7 @@ symbol_make_alias (symbol *sym, symbol *symval, location loc) sym->user_token_number = USER_NUMBER_ALIAS; symval->alias = sym; sym->alias = symval; - /* sym and symval combined are only one symbol. */ - nsyms--; - ntokens--; - assert (ntokens == sym->number || ntokens == symval->number); - sym->number = symval->number = - (symval->number < sym->number) ? symval->number : sym->number; + symval->number = sym->number; symbol_type_set (symval, sym->type_name, loc); } } @@ -442,14 +601,15 @@ symbol_translation_processor (void *this, void *null ATTRIBUTE_UNUSED) } -/*----------------------. -| A symbol hash table. | -`----------------------*/ +/*---------------------------------------. +| Symbol and semantic type hash tables. | +`---------------------------------------*/ -/* Initial capacity of symbols hash table. */ +/* Initial capacity of symbol and semantic type hash table. */ #define HT_INITIAL_CAPACITY 257 static struct hash_table *symbol_table = NULL; +static struct hash_table *semantic_type_table = NULL; static inline bool hash_compare_symbol (const symbol *m1, const symbol *m2) @@ -458,12 +618,25 @@ hash_compare_symbol (const symbol *m1, const symbol *m2) return UNIQSTR_EQ (m1->tag, m2->tag); } +static inline bool +hash_compare_semantic_type (const semantic_type *m1, const semantic_type *m2) +{ + /* Since names are unique, we can compare the pointers themselves. */ + return UNIQSTR_EQ (m1->tag, m2->tag); +} + static bool hash_symbol_comparator (void const *m1, void const *m2) { return hash_compare_symbol (m1, m2); } +static bool +hash_semantic_type_comparator (void const *m1, void const *m2) +{ + return hash_compare_semantic_type (m1, m2); +} + static inline size_t hash_symbol (const symbol *m, size_t tablesize) { @@ -471,12 +644,24 @@ hash_symbol (const symbol *m, size_t tablesize) return ((uintptr_t) m->tag) % tablesize; } +static inline size_t +hash_semantic_type (const semantic_type *m, size_t tablesize) +{ + /* Since names are unique, we can hash the pointer itself. */ + return ((uintptr_t) m->tag) % tablesize; +} + static size_t hash_symbol_hasher (void const *m, size_t tablesize) { return hash_symbol (m, tablesize); } +static size_t +hash_semantic_type_hasher (void const *m, size_t tablesize) +{ + return hash_semantic_type (m, tablesize); +} /*-------------------------------. | Create the symbol hash table. | @@ -490,6 +675,11 @@ symbols_new (void) hash_symbol_hasher, hash_symbol_comparator, free); + semantic_type_table = hash_initialize (HT_INITIAL_CAPACITY, + NULL, + hash_semantic_type_hasher, + hash_semantic_type_comparator, + free); } @@ -517,6 +707,30 @@ symbol_from_uniqstr (const uniqstr key, location loc) } +/*-----------------------------------------------------------------------. +| Find the semantic type named KEY, and return it. If it does not exist | +| yet, create it. | +`-----------------------------------------------------------------------*/ + +semantic_type * +semantic_type_from_uniqstr (const uniqstr key) +{ + semantic_type probe; + semantic_type *entry; + + probe.tag = key; + entry = hash_lookup (semantic_type_table, &probe); + + if (!entry) + { + /* First insertion in the hash. */ + entry = semantic_type_new (key); + hash_insert (semantic_type_table, entry); + } + return entry; +} + + /*----------------------------------------------------------------. | Find the symbol named KEY, and return it. If it does not exist | | yet, create it. | @@ -529,6 +743,18 @@ symbol_get (const char *key, location loc) } +/*-----------------------------------------------------------------------. +| Find the semantic type named KEY, and return it. If it does not exist | +| yet, create it. | +`-----------------------------------------------------------------------*/ + +semantic_type * +semantic_type_get (const char *key) +{ + return semantic_type_from_uniqstr (uniqstr_new (key)); +} + + /*------------------------------------------------------------------. | Generate a dummy nonterminal, whose name cannot conflict with the | | user's names. | @@ -550,6 +776,11 @@ dummy_symbol_get (location loc) return sym; } +bool +symbol_is_dummy (const symbol *sym) +{ + return sym->tag[0] == '@'; +} /*-------------------. | Free the symbols. | @@ -559,6 +790,7 @@ void symbols_free (void) { hash_free (symbol_table); + hash_free (semantic_type_table); free (symbols); } @@ -650,11 +882,35 @@ symbols_token_translations_init (void) void symbols_pack (void) { - symbols = xcalloc (nsyms, sizeof *symbols); - symbols_do (symbol_check_alias_consistency_processor, NULL); + + symbols = xcalloc (nsyms, sizeof *symbols); symbols_do (symbol_pack_processor, NULL); + /* Aliases leave empty slots in symbols, so remove them. */ + { + int writei; + int readi; + int nsyms_old = nsyms; + for (writei = 0, readi = 0; readi < nsyms_old; readi += 1) + { + if (symbols[readi] == NULL) + { + nsyms -= 1; + ntokens -= 1; + } + else + { + symbols[writei] = symbols[readi]; + symbols[writei]->number = writei; + if (symbols[writei]->alias) + symbols[writei]->alias->number = writei; + writei += 1; + } + } + } + symbols = xnrealloc (symbols, nsyms, sizeof *symbols); + symbols_token_translations_init (); if (startsymbol->class == unknown_sym) @@ -666,3 +922,32 @@ symbols_pack (void) _("the start symbol %s is a token"), startsymbol->tag); } + + +/*-----------------------------------. +| Set default %destructor/%printer. | +`-----------------------------------*/ + +void +default_destructor_set (const char *destructor, location loc) +{ + if (default_destructor != NULL) + { + complain_at (loc, _("redeclaration for default %%destructor")); + complain_at (default_destructor_location, _("previous declaration")); + } + default_destructor = destructor; + default_destructor_location = loc; +} + +void +default_printer_set (const char *printer, location loc) +{ + if (default_printer != NULL) + { + complain_at (loc, _("redeclaration for default %%printer")); + complain_at (default_printer_location, _("previous declaration")); + } + default_printer = printer; + default_printer_location = loc; +}