1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2008 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci 25bf215546Sopenharmony_ci#include "main/errors.h" 26bf215546Sopenharmony_ci#include "symbol_table.h" 27bf215546Sopenharmony_ci#include "util/hash_table.h" 28bf215546Sopenharmony_ci#include "util/u_string.h" 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_cistruct symbol { 31bf215546Sopenharmony_ci /** Symbol name. */ 32bf215546Sopenharmony_ci char *name; 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci /** 35bf215546Sopenharmony_ci * Link to the next symbol in the table with the same name 36bf215546Sopenharmony_ci * 37bf215546Sopenharmony_ci * The linked list of symbols with the same name is ordered by scope 38bf215546Sopenharmony_ci * from inner-most to outer-most. 39bf215546Sopenharmony_ci */ 40bf215546Sopenharmony_ci struct symbol *next_with_same_name; 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci /** 43bf215546Sopenharmony_ci * Link to the next symbol in the table with the same scope 44bf215546Sopenharmony_ci * 45bf215546Sopenharmony_ci * The linked list of symbols with the same scope is unordered. Symbols 46bf215546Sopenharmony_ci * in this list my have unique names. 47bf215546Sopenharmony_ci */ 48bf215546Sopenharmony_ci struct symbol *next_with_same_scope; 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci /** Scope depth where this symbol was defined. */ 51bf215546Sopenharmony_ci unsigned depth; 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_ci /** 54bf215546Sopenharmony_ci * Arbitrary user supplied data. 55bf215546Sopenharmony_ci */ 56bf215546Sopenharmony_ci void *data; 57bf215546Sopenharmony_ci}; 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci/** 61bf215546Sopenharmony_ci * Element of the scope stack. 62bf215546Sopenharmony_ci */ 63bf215546Sopenharmony_cistruct scope_level { 64bf215546Sopenharmony_ci /** Link to next (inner) scope level. */ 65bf215546Sopenharmony_ci struct scope_level *next; 66bf215546Sopenharmony_ci 67bf215546Sopenharmony_ci /** Linked list of symbols with the same scope. */ 68bf215546Sopenharmony_ci struct symbol *symbols; 69bf215546Sopenharmony_ci}; 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci/** 73bf215546Sopenharmony_ci * 74bf215546Sopenharmony_ci */ 75bf215546Sopenharmony_cistruct _mesa_symbol_table { 76bf215546Sopenharmony_ci /** Hash table containing all symbols in the symbol table. */ 77bf215546Sopenharmony_ci struct hash_table *ht; 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci /** Top of scope stack. */ 80bf215546Sopenharmony_ci struct scope_level *current_scope; 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci /** Current scope depth. */ 83bf215546Sopenharmony_ci unsigned depth; 84bf215546Sopenharmony_ci}; 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_civoid 87bf215546Sopenharmony_ci_mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table) 88bf215546Sopenharmony_ci{ 89bf215546Sopenharmony_ci struct scope_level *const scope = table->current_scope; 90bf215546Sopenharmony_ci struct symbol *sym = scope->symbols; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci table->current_scope = scope->next; 93bf215546Sopenharmony_ci table->depth--; 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci free(scope); 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci while (sym != NULL) { 98bf215546Sopenharmony_ci struct symbol *const next = sym->next_with_same_scope; 99bf215546Sopenharmony_ci struct hash_entry *hte = _mesa_hash_table_search(table->ht, 100bf215546Sopenharmony_ci sym->name); 101bf215546Sopenharmony_ci if (sym->next_with_same_name) { 102bf215546Sopenharmony_ci /* If there is a symbol with this name in an outer scope update 103bf215546Sopenharmony_ci * the hash table to point to it. 104bf215546Sopenharmony_ci */ 105bf215546Sopenharmony_ci hte->key = sym->next_with_same_name->name; 106bf215546Sopenharmony_ci hte->data = sym->next_with_same_name; 107bf215546Sopenharmony_ci } else { 108bf215546Sopenharmony_ci _mesa_hash_table_remove(table->ht, hte); 109bf215546Sopenharmony_ci free(sym->name); 110bf215546Sopenharmony_ci } 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci free(sym); 113bf215546Sopenharmony_ci sym = next; 114bf215546Sopenharmony_ci } 115bf215546Sopenharmony_ci} 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_civoid 119bf215546Sopenharmony_ci_mesa_symbol_table_push_scope(struct _mesa_symbol_table *table) 120bf215546Sopenharmony_ci{ 121bf215546Sopenharmony_ci struct scope_level *const scope = calloc(1, sizeof(*scope)); 122bf215546Sopenharmony_ci if (scope == NULL) { 123bf215546Sopenharmony_ci _mesa_error_no_memory(__func__); 124bf215546Sopenharmony_ci return; 125bf215546Sopenharmony_ci } 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci scope->next = table->current_scope; 128bf215546Sopenharmony_ci table->current_scope = scope; 129bf215546Sopenharmony_ci table->depth++; 130bf215546Sopenharmony_ci} 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_cistatic struct symbol * 134bf215546Sopenharmony_cifind_symbol(struct _mesa_symbol_table *table, const char *name) 135bf215546Sopenharmony_ci{ 136bf215546Sopenharmony_ci struct hash_entry *entry = _mesa_hash_table_search(table->ht, name); 137bf215546Sopenharmony_ci return entry ? (struct symbol *) entry->data : NULL; 138bf215546Sopenharmony_ci} 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci/** 142bf215546Sopenharmony_ci * Determine the scope "distance" of a symbol from the current scope 143bf215546Sopenharmony_ci * 144bf215546Sopenharmony_ci * \return 145bf215546Sopenharmony_ci * A non-negative number for the number of scopes between the current scope 146bf215546Sopenharmony_ci * and the scope where a symbol was defined. A value of zero means the current 147bf215546Sopenharmony_ci * scope. A negative number if the symbol does not exist. 148bf215546Sopenharmony_ci */ 149bf215546Sopenharmony_ciint 150bf215546Sopenharmony_ci_mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table, 151bf215546Sopenharmony_ci const char *name) 152bf215546Sopenharmony_ci{ 153bf215546Sopenharmony_ci struct symbol *const sym = find_symbol(table, name); 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci if (sym) { 156bf215546Sopenharmony_ci assert(sym->depth <= table->depth); 157bf215546Sopenharmony_ci return table->depth - sym->depth; 158bf215546Sopenharmony_ci } 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci return -1; 161bf215546Sopenharmony_ci} 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_civoid * 165bf215546Sopenharmony_ci_mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table, 166bf215546Sopenharmony_ci const char *name) 167bf215546Sopenharmony_ci{ 168bf215546Sopenharmony_ci struct symbol *const sym = find_symbol(table, name); 169bf215546Sopenharmony_ci if (sym) 170bf215546Sopenharmony_ci return sym->data; 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci return NULL; 173bf215546Sopenharmony_ci} 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ciint 177bf215546Sopenharmony_ci_mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table, 178bf215546Sopenharmony_ci const char *name, void *declaration) 179bf215546Sopenharmony_ci{ 180bf215546Sopenharmony_ci struct symbol *new_sym; 181bf215546Sopenharmony_ci struct symbol *sym = find_symbol(table, name); 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_ci if (sym && sym->depth == table->depth) 184bf215546Sopenharmony_ci return -1; 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci new_sym = calloc(1, sizeof(*sym)); 187bf215546Sopenharmony_ci if (new_sym == NULL) { 188bf215546Sopenharmony_ci _mesa_error_no_memory(__func__); 189bf215546Sopenharmony_ci return -1; 190bf215546Sopenharmony_ci } 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci if (sym) { 193bf215546Sopenharmony_ci /* Store link to symbol in outer scope with the same name */ 194bf215546Sopenharmony_ci new_sym->next_with_same_name = sym; 195bf215546Sopenharmony_ci new_sym->name = sym->name; 196bf215546Sopenharmony_ci } else { 197bf215546Sopenharmony_ci new_sym->name = strdup(name); 198bf215546Sopenharmony_ci if (new_sym->name == NULL) { 199bf215546Sopenharmony_ci free(new_sym); 200bf215546Sopenharmony_ci _mesa_error_no_memory(__func__); 201bf215546Sopenharmony_ci return -1; 202bf215546Sopenharmony_ci } 203bf215546Sopenharmony_ci } 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci new_sym->next_with_same_scope = table->current_scope->symbols; 206bf215546Sopenharmony_ci new_sym->data = declaration; 207bf215546Sopenharmony_ci new_sym->depth = table->depth; 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci table->current_scope->symbols = new_sym; 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci _mesa_hash_table_insert(table->ht, new_sym->name, new_sym); 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci return 0; 214bf215546Sopenharmony_ci} 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ciint 217bf215546Sopenharmony_ci_mesa_symbol_table_replace_symbol(struct _mesa_symbol_table *table, 218bf215546Sopenharmony_ci const char *name, 219bf215546Sopenharmony_ci void *declaration) 220bf215546Sopenharmony_ci{ 221bf215546Sopenharmony_ci struct symbol *sym = find_symbol(table, name); 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci /* If the symbol doesn't exist, it cannot be replaced. */ 224bf215546Sopenharmony_ci if (sym == NULL) 225bf215546Sopenharmony_ci return -1; 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci sym->data = declaration; 228bf215546Sopenharmony_ci return 0; 229bf215546Sopenharmony_ci} 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ciint 232bf215546Sopenharmony_ci_mesa_symbol_table_add_global_symbol(struct _mesa_symbol_table *table, 233bf215546Sopenharmony_ci const char *name, void *declaration) 234bf215546Sopenharmony_ci{ 235bf215546Sopenharmony_ci struct scope_level *top_scope; 236bf215546Sopenharmony_ci struct symbol *inner_sym = NULL; 237bf215546Sopenharmony_ci struct symbol *sym = find_symbol(table, name); 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci while (sym) { 240bf215546Sopenharmony_ci if (sym->depth == 0) 241bf215546Sopenharmony_ci return -1; 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci inner_sym = sym; 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci /* Get symbol from the outer scope with the same name */ 246bf215546Sopenharmony_ci sym = sym->next_with_same_name; 247bf215546Sopenharmony_ci } 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_ci /* Find the top-level scope */ 250bf215546Sopenharmony_ci for (top_scope = table->current_scope; top_scope->next != NULL; 251bf215546Sopenharmony_ci top_scope = top_scope->next) { 252bf215546Sopenharmony_ci /* empty */ 253bf215546Sopenharmony_ci } 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci sym = calloc(1, sizeof(*sym)); 256bf215546Sopenharmony_ci if (sym == NULL) { 257bf215546Sopenharmony_ci _mesa_error_no_memory(__func__); 258bf215546Sopenharmony_ci return -1; 259bf215546Sopenharmony_ci } 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci if (inner_sym) { 262bf215546Sopenharmony_ci /* In case we add the global out of order store a link to the global 263bf215546Sopenharmony_ci * symbol in global. 264bf215546Sopenharmony_ci */ 265bf215546Sopenharmony_ci inner_sym->next_with_same_name = sym; 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ci sym->name = inner_sym->name; 268bf215546Sopenharmony_ci } else { 269bf215546Sopenharmony_ci sym->name = strdup(name); 270bf215546Sopenharmony_ci if (sym->name == NULL) { 271bf215546Sopenharmony_ci free(sym); 272bf215546Sopenharmony_ci _mesa_error_no_memory(__func__); 273bf215546Sopenharmony_ci return -1; 274bf215546Sopenharmony_ci } 275bf215546Sopenharmony_ci } 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci sym->next_with_same_scope = top_scope->symbols; 278bf215546Sopenharmony_ci sym->data = declaration; 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_ci top_scope->symbols = sym; 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci _mesa_hash_table_insert(table->ht, sym->name, sym); 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci return 0; 285bf215546Sopenharmony_ci} 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_cistruct _mesa_symbol_table * 290bf215546Sopenharmony_ci_mesa_symbol_table_ctor(void) 291bf215546Sopenharmony_ci{ 292bf215546Sopenharmony_ci struct _mesa_symbol_table *table = calloc(1, sizeof(*table)); 293bf215546Sopenharmony_ci 294bf215546Sopenharmony_ci if (table != NULL) { 295bf215546Sopenharmony_ci table->ht = _mesa_hash_table_create(NULL, _mesa_hash_string, 296bf215546Sopenharmony_ci _mesa_key_string_equal); 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci _mesa_symbol_table_push_scope(table); 299bf215546Sopenharmony_ci } 300bf215546Sopenharmony_ci 301bf215546Sopenharmony_ci return table; 302bf215546Sopenharmony_ci} 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_civoid 306bf215546Sopenharmony_ci_mesa_symbol_table_dtor(struct _mesa_symbol_table *table) 307bf215546Sopenharmony_ci{ 308bf215546Sopenharmony_ci while (table->current_scope != NULL) { 309bf215546Sopenharmony_ci _mesa_symbol_table_pop_scope(table); 310bf215546Sopenharmony_ci } 311bf215546Sopenharmony_ci 312bf215546Sopenharmony_ci _mesa_hash_table_destroy(table->ht, NULL); 313bf215546Sopenharmony_ci free(table); 314bf215546Sopenharmony_ci} 315