1848b8605Smrg/* 2848b8605Smrg * Copyright © 2008 Intel Corporation 3848b8605Smrg * 4848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5848b8605Smrg * copy of this software and associated documentation files (the "Software"), 6848b8605Smrg * to deal in the Software without restriction, including without limitation 7848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 9848b8605Smrg * Software is furnished to do so, subject to the following conditions: 10848b8605Smrg * 11848b8605Smrg * The above copyright notice and this permission notice (including the next 12848b8605Smrg * paragraph) shall be included in all copies or substantial portions of the 13848b8605Smrg * Software. 14848b8605Smrg * 15848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19848b8605Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20848b8605Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21848b8605Smrg * DEALINGS IN THE SOFTWARE. 22848b8605Smrg */ 23848b8605Smrg 24848b8605Smrg#include "main/imports.h" 25b8e80941Smrg#include "main/errors.h" 26848b8605Smrg#include "symbol_table.h" 27b8e80941Smrg#include "../../util/hash_table.h" 28b8e80941Smrg#include "util/u_string.h" 29848b8605Smrg 30848b8605Smrgstruct symbol { 31b8e80941Smrg /** Symbol name. */ 32b8e80941Smrg char *name; 33b8e80941Smrg 34848b8605Smrg /** 35848b8605Smrg * Link to the next symbol in the table with the same name 36848b8605Smrg * 37848b8605Smrg * The linked list of symbols with the same name is ordered by scope 38848b8605Smrg * from inner-most to outer-most. 39848b8605Smrg */ 40848b8605Smrg struct symbol *next_with_same_name; 41848b8605Smrg 42848b8605Smrg /** 43848b8605Smrg * Link to the next symbol in the table with the same scope 44848b8605Smrg * 45848b8605Smrg * The linked list of symbols with the same scope is unordered. Symbols 46848b8605Smrg * in this list my have unique names. 47848b8605Smrg */ 48848b8605Smrg struct symbol *next_with_same_scope; 49848b8605Smrg 50848b8605Smrg /** Scope depth where this symbol was defined. */ 51848b8605Smrg unsigned depth; 52848b8605Smrg 53848b8605Smrg /** 54848b8605Smrg * Arbitrary user supplied data. 55848b8605Smrg */ 56848b8605Smrg void *data; 57848b8605Smrg}; 58848b8605Smrg 59848b8605Smrg 60848b8605Smrg/** 61848b8605Smrg * Element of the scope stack. 62848b8605Smrg */ 63848b8605Smrgstruct scope_level { 64848b8605Smrg /** Link to next (inner) scope level. */ 65848b8605Smrg struct scope_level *next; 66848b8605Smrg 67848b8605Smrg /** Linked list of symbols with the same scope. */ 68848b8605Smrg struct symbol *symbols; 69848b8605Smrg}; 70848b8605Smrg 71848b8605Smrg 72848b8605Smrg/** 73848b8605Smrg * 74848b8605Smrg */ 75848b8605Smrgstruct _mesa_symbol_table { 76848b8605Smrg /** Hash table containing all symbols in the symbol table. */ 77848b8605Smrg struct hash_table *ht; 78848b8605Smrg 79848b8605Smrg /** Top of scope stack. */ 80848b8605Smrg struct scope_level *current_scope; 81848b8605Smrg 82848b8605Smrg /** Current scope depth. */ 83848b8605Smrg unsigned depth; 84848b8605Smrg}; 85848b8605Smrg 86848b8605Smrgvoid 87848b8605Smrg_mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table) 88848b8605Smrg{ 89848b8605Smrg struct scope_level *const scope = table->current_scope; 90848b8605Smrg struct symbol *sym = scope->symbols; 91848b8605Smrg 92848b8605Smrg table->current_scope = scope->next; 93848b8605Smrg table->depth--; 94848b8605Smrg 95848b8605Smrg free(scope); 96848b8605Smrg 97848b8605Smrg while (sym != NULL) { 98848b8605Smrg struct symbol *const next = sym->next_with_same_scope; 99b8e80941Smrg struct hash_entry *hte = _mesa_hash_table_search(table->ht, 100b8e80941Smrg sym->name); 101b8e80941Smrg if (sym->next_with_same_name) { 102b8e80941Smrg /* If there is a symbol with this name in an outer scope update 103b8e80941Smrg * the hash table to point to it. 104b8e80941Smrg */ 105b8e80941Smrg hte->key = sym->next_with_same_name->name; 106b8e80941Smrg hte->data = sym->next_with_same_name; 107b8e80941Smrg } else { 108b8e80941Smrg _mesa_hash_table_remove(table->ht, hte); 109b8e80941Smrg free(sym->name); 110b8e80941Smrg } 111848b8605Smrg 112848b8605Smrg free(sym); 113848b8605Smrg sym = next; 114848b8605Smrg } 115848b8605Smrg} 116848b8605Smrg 117848b8605Smrg 118848b8605Smrgvoid 119848b8605Smrg_mesa_symbol_table_push_scope(struct _mesa_symbol_table *table) 120848b8605Smrg{ 121848b8605Smrg struct scope_level *const scope = calloc(1, sizeof(*scope)); 122b8e80941Smrg if (scope == NULL) { 123b8e80941Smrg _mesa_error_no_memory(__func__); 124b8e80941Smrg return; 125b8e80941Smrg } 126b8e80941Smrg 127848b8605Smrg scope->next = table->current_scope; 128848b8605Smrg table->current_scope = scope; 129848b8605Smrg table->depth++; 130848b8605Smrg} 131848b8605Smrg 132848b8605Smrg 133b8e80941Smrgstatic struct symbol * 134848b8605Smrgfind_symbol(struct _mesa_symbol_table *table, const char *name) 135848b8605Smrg{ 136b8e80941Smrg struct hash_entry *entry = _mesa_hash_table_search(table->ht, name); 137b8e80941Smrg return entry ? (struct symbol *) entry->data : NULL; 138848b8605Smrg} 139848b8605Smrg 140848b8605Smrg 141848b8605Smrg/** 142848b8605Smrg * Determine the scope "distance" of a symbol from the current scope 143848b8605Smrg * 144848b8605Smrg * \return 145848b8605Smrg * A non-negative number for the number of scopes between the current scope 146848b8605Smrg * and the scope where a symbol was defined. A value of zero means the current 147848b8605Smrg * scope. A negative number if the symbol does not exist. 148848b8605Smrg */ 149848b8605Smrgint 150848b8605Smrg_mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table, 151b8e80941Smrg const char *name) 152848b8605Smrg{ 153b8e80941Smrg struct symbol *const sym = find_symbol(table, name); 154b8e80941Smrg 155b8e80941Smrg if (sym) { 156b8e80941Smrg assert(sym->depth <= table->depth); 157b8e80941Smrg return sym->depth - table->depth; 158b8e80941Smrg } 159848b8605Smrg 160b8e80941Smrg return -1; 161848b8605Smrg} 162848b8605Smrg 163848b8605Smrg 164848b8605Smrgvoid * 165848b8605Smrg_mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table, 166b8e80941Smrg const char *name) 167848b8605Smrg{ 168b8e80941Smrg struct symbol *const sym = find_symbol(table, name); 169b8e80941Smrg if (sym) 170b8e80941Smrg return sym->data; 171848b8605Smrg 172b8e80941Smrg return NULL; 173848b8605Smrg} 174848b8605Smrg 175848b8605Smrg 176848b8605Smrgint 177848b8605Smrg_mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table, 178b8e80941Smrg const char *name, void *declaration) 179848b8605Smrg{ 180b8e80941Smrg struct symbol *new_sym; 181b8e80941Smrg struct symbol *sym = find_symbol(table, name); 182848b8605Smrg 183b8e80941Smrg if (sym && sym->depth == table->depth) 184b8e80941Smrg return -1; 185848b8605Smrg 186b8e80941Smrg new_sym = calloc(1, sizeof(*sym)); 187b8e80941Smrg if (new_sym == NULL) { 188b8e80941Smrg _mesa_error_no_memory(__func__); 189b8e80941Smrg return -1; 190b8e80941Smrg } 191848b8605Smrg 192b8e80941Smrg if (sym) { 193b8e80941Smrg /* Store link to symbol in outer scope with the same name */ 194b8e80941Smrg new_sym->next_with_same_name = sym; 195b8e80941Smrg new_sym->name = sym->name; 196b8e80941Smrg } else { 197b8e80941Smrg new_sym->name = util_strdup(name); 198b8e80941Smrg if (new_sym->name == NULL) { 199b8e80941Smrg free(new_sym); 200b8e80941Smrg _mesa_error_no_memory(__func__); 201b8e80941Smrg return -1; 202b8e80941Smrg } 203b8e80941Smrg } 204848b8605Smrg 205b8e80941Smrg new_sym->next_with_same_scope = table->current_scope->symbols; 206b8e80941Smrg new_sym->data = declaration; 207b8e80941Smrg new_sym->depth = table->depth; 208848b8605Smrg 209b8e80941Smrg table->current_scope->symbols = new_sym; 210848b8605Smrg 211b8e80941Smrg _mesa_hash_table_insert(table->ht, new_sym->name, new_sym); 212848b8605Smrg 213b8e80941Smrg return 0; 214b8e80941Smrg} 215848b8605Smrg 216b8e80941Smrgint 217b8e80941Smrg_mesa_symbol_table_replace_symbol(struct _mesa_symbol_table *table, 218b8e80941Smrg const char *name, 219b8e80941Smrg void *declaration) 220b8e80941Smrg{ 221b8e80941Smrg struct symbol *sym = find_symbol(table, name); 222b8e80941Smrg 223b8e80941Smrg /* If the symbol doesn't exist, it cannot be replaced. */ 224b8e80941Smrg if (sym == NULL) 225848b8605Smrg return -1; 226848b8605Smrg 227848b8605Smrg sym->data = declaration; 228848b8605Smrg return 0; 229848b8605Smrg} 230848b8605Smrg 231848b8605Smrgint 232848b8605Smrg_mesa_symbol_table_add_global_symbol(struct _mesa_symbol_table *table, 233b8e80941Smrg const char *name, void *declaration) 234848b8605Smrg{ 235b8e80941Smrg struct scope_level *top_scope; 236b8e80941Smrg struct symbol *inner_sym = NULL; 237b8e80941Smrg struct symbol *sym = find_symbol(table, name); 238848b8605Smrg 239b8e80941Smrg while (sym) { 240b8e80941Smrg if (sym->depth == 0) 241b8e80941Smrg return -1; 242848b8605Smrg 243b8e80941Smrg inner_sym = sym; 244848b8605Smrg 245b8e80941Smrg /* Get symbol from the outer scope with the same name */ 246b8e80941Smrg sym = sym->next_with_same_name; 247b8e80941Smrg } 248848b8605Smrg 249b8e80941Smrg /* Find the top-level scope */ 250b8e80941Smrg for (top_scope = table->current_scope; top_scope->next != NULL; 251b8e80941Smrg top_scope = top_scope->next) { 252b8e80941Smrg /* empty */ 253b8e80941Smrg } 254848b8605Smrg 255b8e80941Smrg sym = calloc(1, sizeof(*sym)); 256b8e80941Smrg if (sym == NULL) { 257b8e80941Smrg _mesa_error_no_memory(__func__); 258b8e80941Smrg return -1; 259b8e80941Smrg } 260848b8605Smrg 261b8e80941Smrg if (inner_sym) { 262b8e80941Smrg /* In case we add the global out of order store a link to the global 263b8e80941Smrg * symbol in global. 264b8e80941Smrg */ 265b8e80941Smrg inner_sym->next_with_same_name = sym; 266b8e80941Smrg 267b8e80941Smrg sym->name = inner_sym->name; 268b8e80941Smrg } else { 269b8e80941Smrg sym->name = util_strdup(name); 270b8e80941Smrg if (sym->name == NULL) { 271b8e80941Smrg free(sym); 272b8e80941Smrg _mesa_error_no_memory(__func__); 273b8e80941Smrg return -1; 274b8e80941Smrg } 275b8e80941Smrg } 276848b8605Smrg 277b8e80941Smrg sym->next_with_same_scope = top_scope->symbols; 278b8e80941Smrg sym->data = declaration; 279848b8605Smrg 280b8e80941Smrg top_scope->symbols = sym; 281848b8605Smrg 282b8e80941Smrg _mesa_hash_table_insert(table->ht, sym->name, sym); 283848b8605Smrg 284b8e80941Smrg return 0; 285848b8605Smrg} 286848b8605Smrg 287848b8605Smrg 288848b8605Smrg 289848b8605Smrgstruct _mesa_symbol_table * 290848b8605Smrg_mesa_symbol_table_ctor(void) 291848b8605Smrg{ 292848b8605Smrg struct _mesa_symbol_table *table = calloc(1, sizeof(*table)); 293848b8605Smrg 294848b8605Smrg if (table != NULL) { 295b8e80941Smrg table->ht = _mesa_hash_table_create(NULL, _mesa_key_hash_string, 296b8e80941Smrg _mesa_key_string_equal); 297848b8605Smrg 298848b8605Smrg _mesa_symbol_table_push_scope(table); 299848b8605Smrg } 300848b8605Smrg 301848b8605Smrg return table; 302848b8605Smrg} 303848b8605Smrg 304848b8605Smrg 305848b8605Smrgvoid 306848b8605Smrg_mesa_symbol_table_dtor(struct _mesa_symbol_table *table) 307848b8605Smrg{ 308848b8605Smrg while (table->current_scope != NULL) { 309848b8605Smrg _mesa_symbol_table_pop_scope(table); 310848b8605Smrg } 311848b8605Smrg 312b8e80941Smrg _mesa_hash_table_destroy(table->ht, NULL); 313848b8605Smrg free(table); 314848b8605Smrg} 315