/* * Copyright © 2008 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "main/imports.h" #include "symbol_table.h" #include "../../util/hash_table.h" struct symbol { /** * Link to the next symbol in the table with the same name * * The linked list of symbols with the same name is ordered by scope * from inner-most to outer-most. */ struct symbol *next_with_same_name; /** * Link to the next symbol in the table with the same scope * * The linked list of symbols with the same scope is unordered. Symbols * in this list my have unique names. */ struct symbol *next_with_same_scope; /** * Header information for the list of symbols with the same name. */ struct symbol_header *hdr; /** * Name space of the symbol * * Name space are arbitrary user assigned integers. No two symbols can * exist in the same name space at the same scope level. */ int name_space; /** Scope depth where this symbol was defined. */ unsigned depth; /** * Arbitrary user supplied data. */ void *data; }; /** */ struct symbol_header { /** Linkage in list of all headers in a given symbol table. */ struct symbol_header *next; /** Symbol name. */ char *name; /** Linked list of symbols with the same name. */ struct symbol *symbols; }; /** * Element of the scope stack. */ struct scope_level { /** Link to next (inner) scope level. */ struct scope_level *next; /** Linked list of symbols with the same scope. */ struct symbol *symbols; }; /** * */ struct _mesa_symbol_table { /** Hash table containing all symbols in the symbol table. */ struct hash_table *ht; /** Top of scope stack. */ struct scope_level *current_scope; /** List of all symbol headers in the table. */ struct symbol_header *hdr; /** Current scope depth. */ unsigned depth; }; static void check_symbol_table(struct _mesa_symbol_table *table) { #if !defined(NDEBUG) struct scope_level *scope; for (scope = table->current_scope; scope != NULL; scope = scope->next) { struct symbol *sym; for (sym = scope->symbols ; sym != NULL ; sym = sym->next_with_same_name) { const struct symbol_header *const hdr = sym->hdr; struct symbol *sym2; for (sym2 = hdr->symbols ; sym2 != NULL ; sym2 = sym2->next_with_same_name) { assert(sym2->hdr == hdr); } } } #else (void) table; #endif /* !defined(NDEBUG) */ } void _mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table) { struct scope_level *const scope = table->current_scope; struct symbol *sym = scope->symbols; table->current_scope = scope->next; table->depth--; free(scope); while (sym != NULL) { struct symbol *const next = sym->next_with_same_scope; struct symbol_header *const hdr = sym->hdr; assert(hdr->symbols == sym); hdr->symbols = sym->next_with_same_name; free(sym); sym = next; } check_symbol_table(table); } void _mesa_symbol_table_push_scope(struct _mesa_symbol_table *table) { struct scope_level *const scope = calloc(1, sizeof(*scope)); if (scope == NULL) { _mesa_error_no_memory(__func__); return; } scope->next = table->current_scope; table->current_scope = scope; table->depth++; } static struct symbol_header * find_symbol(struct _mesa_symbol_table *table, const char *name) { struct hash_entry *entry = _mesa_hash_table_search(table->ht, name); return entry ? (struct symbol_header *) entry->data : NULL; } /** * Determine the scope "distance" of a symbol from the current scope * * \return * A non-negative number for the number of scopes between the current scope * and the scope where a symbol was defined. A value of zero means the current * scope. A negative number if the symbol does not exist. */ int _mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table, int name_space, const char *name) { struct symbol_header *const hdr = find_symbol(table, name); struct symbol *sym; if (hdr != NULL) { for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) { assert(sym->hdr == hdr); if ((name_space == -1) || (sym->name_space == name_space)) { assert(sym->depth <= table->depth); return sym->depth - table->depth; } } } return -1; } void * _mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table, int name_space, const char *name) { struct symbol_header *const hdr = find_symbol(table, name); if (hdr != NULL) { struct symbol *sym; for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) { assert(sym->hdr == hdr); if ((name_space == -1) || (sym->name_space == name_space)) { return sym->data; } } } return NULL; } int _mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table, int name_space, const char *name, void *declaration) { struct symbol_header *hdr; struct symbol *sym; check_symbol_table(table); hdr = find_symbol(table, name); check_symbol_table(table); if (hdr == NULL) { hdr = calloc(1, sizeof(*hdr)); if (hdr == NULL) { _mesa_error_no_memory(__func__); return -1; } hdr->name = strdup(name); if (hdr->name == NULL) { free(hdr); _mesa_error_no_memory(__func__); return -1; } _mesa_hash_table_insert(table->ht, hdr->name, hdr); hdr->next = table->hdr; table->hdr = hdr; } check_symbol_table(table); /* If the symbol already exists in this namespace at this scope, it cannot * be added to the table. */ for (sym = hdr->symbols ; (sym != NULL) && (sym->name_space != name_space) ; sym = sym->next_with_same_name) { /* empty */ } if (sym && (sym->depth == table->depth)) return -1; sym = calloc(1, sizeof(*sym)); if (sym == NULL) { _mesa_error_no_memory(__func__); return -1; } sym->next_with_same_name = hdr->symbols; sym->next_with_same_scope = table->current_scope->symbols; sym->hdr = hdr; sym->name_space = name_space; sym->data = declaration; sym->depth = table->depth; assert(sym->hdr == hdr); hdr->symbols = sym; table->current_scope->symbols = sym; check_symbol_table(table); return 0; } int _mesa_symbol_table_add_global_symbol(struct _mesa_symbol_table *table, int name_space, const char *name, void *declaration) { struct symbol_header *hdr; struct symbol *sym; struct symbol *curr; struct scope_level *top_scope; check_symbol_table(table); hdr = find_symbol(table, name); check_symbol_table(table); if (hdr == NULL) { hdr = calloc(1, sizeof(*hdr)); if (hdr == NULL) { _mesa_error_no_memory(__func__); return -1; } hdr->name = strdup(name); _mesa_hash_table_insert(table->ht, hdr->name, hdr); hdr->next = table->hdr; table->hdr = hdr; } check_symbol_table(table); /* If the symbol already exists in this namespace at this scope, it cannot * be added to the table. */ for (sym = hdr->symbols ; (sym != NULL) && (sym->name_space != name_space) ; sym = sym->next_with_same_name) { /* empty */ } if (sym && sym->depth == 0) return -1; /* Find the top-level scope */ for (top_scope = table->current_scope ; top_scope->next != NULL ; top_scope = top_scope->next) { /* empty */ } sym = calloc(1, sizeof(*sym)); if (sym == NULL) { _mesa_error_no_memory(__func__); return -1; } sym->next_with_same_scope = top_scope->symbols; sym->hdr = hdr; sym->name_space = name_space; sym->data = declaration; assert(sym->hdr == hdr); /* Since next_with_same_name is ordered by scope, we need to append the * new symbol to the _end_ of the list. */ if (hdr->symbols == NULL) { hdr->symbols = sym; } else { for (curr = hdr->symbols ; curr->next_with_same_name != NULL ; curr = curr->next_with_same_name) { /* empty */ } curr->next_with_same_name = sym; } top_scope->symbols = sym; check_symbol_table(table); return 0; } struct _mesa_symbol_table * _mesa_symbol_table_ctor(void) { struct _mesa_symbol_table *table = calloc(1, sizeof(*table)); if (table != NULL) { table->ht = _mesa_hash_table_create(NULL, _mesa_key_hash_string, _mesa_key_string_equal); _mesa_symbol_table_push_scope(table); } return table; } void _mesa_symbol_table_dtor(struct _mesa_symbol_table *table) { struct symbol_header *hdr; struct symbol_header *next; while (table->current_scope != NULL) { _mesa_symbol_table_pop_scope(table); } for (hdr = table->hdr; hdr != NULL; hdr = next) { next = hdr->next; free(hdr->name); free(hdr); } _mesa_hash_table_destroy(table->ht, NULL); free(table); }