symbol_table.c revision af69d88d
1/* 2 * Copyright © 2008 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24#include "main/imports.h" 25#include "symbol_table.h" 26#include "hash_table.h" 27 28struct symbol { 29 /** 30 * Link to the next symbol in the table with the same name 31 * 32 * The linked list of symbols with the same name is ordered by scope 33 * from inner-most to outer-most. 34 */ 35 struct symbol *next_with_same_name; 36 37 38 /** 39 * Link to the next symbol in the table with the same scope 40 * 41 * The linked list of symbols with the same scope is unordered. Symbols 42 * in this list my have unique names. 43 */ 44 struct symbol *next_with_same_scope; 45 46 47 /** 48 * Header information for the list of symbols with the same name. 49 */ 50 struct symbol_header *hdr; 51 52 53 /** 54 * Name space of the symbol 55 * 56 * Name space are arbitrary user assigned integers. No two symbols can 57 * exist in the same name space at the same scope level. 58 */ 59 int name_space; 60 61 /** Scope depth where this symbol was defined. */ 62 unsigned depth; 63 64 /** 65 * Arbitrary user supplied data. 66 */ 67 void *data; 68}; 69 70 71/** 72 */ 73struct symbol_header { 74 /** Linkage in list of all headers in a given symbol table. */ 75 struct symbol_header *next; 76 77 /** Symbol name. */ 78 char *name; 79 80 /** Linked list of symbols with the same name. */ 81 struct symbol *symbols; 82}; 83 84 85/** 86 * Element of the scope stack. 87 */ 88struct scope_level { 89 /** Link to next (inner) scope level. */ 90 struct scope_level *next; 91 92 /** Linked list of symbols with the same scope. */ 93 struct symbol *symbols; 94}; 95 96 97/** 98 * 99 */ 100struct _mesa_symbol_table { 101 /** Hash table containing all symbols in the symbol table. */ 102 struct hash_table *ht; 103 104 /** Top of scope stack. */ 105 struct scope_level *current_scope; 106 107 /** List of all symbol headers in the table. */ 108 struct symbol_header *hdr; 109 110 /** Current scope depth. */ 111 unsigned depth; 112}; 113 114 115static void 116check_symbol_table(struct _mesa_symbol_table *table) 117{ 118#if !defined(NDEBUG) 119 struct scope_level *scope; 120 121 for (scope = table->current_scope; scope != NULL; scope = scope->next) { 122 struct symbol *sym; 123 124 for (sym = scope->symbols 125 ; sym != NULL 126 ; sym = sym->next_with_same_name) { 127 const struct symbol_header *const hdr = sym->hdr; 128 struct symbol *sym2; 129 130 for (sym2 = hdr->symbols 131 ; sym2 != NULL 132 ; sym2 = sym2->next_with_same_name) { 133 assert(sym2->hdr == hdr); 134 } 135 } 136 } 137#else 138 (void) table; 139#endif /* !defined(NDEBUG) */ 140} 141 142void 143_mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table) 144{ 145 struct scope_level *const scope = table->current_scope; 146 struct symbol *sym = scope->symbols; 147 148 table->current_scope = scope->next; 149 table->depth--; 150 151 free(scope); 152 153 while (sym != NULL) { 154 struct symbol *const next = sym->next_with_same_scope; 155 struct symbol_header *const hdr = sym->hdr; 156 157 assert(hdr->symbols == sym); 158 159 hdr->symbols = sym->next_with_same_name; 160 161 free(sym); 162 163 sym = next; 164 } 165 166 check_symbol_table(table); 167} 168 169 170void 171_mesa_symbol_table_push_scope(struct _mesa_symbol_table *table) 172{ 173 struct scope_level *const scope = calloc(1, sizeof(*scope)); 174 175 scope->next = table->current_scope; 176 table->current_scope = scope; 177 table->depth++; 178} 179 180 181static struct symbol_header * 182find_symbol(struct _mesa_symbol_table *table, const char *name) 183{ 184 return (struct symbol_header *) hash_table_find(table->ht, name); 185} 186 187 188/** 189 * Determine the scope "distance" of a symbol from the current scope 190 * 191 * \return 192 * A non-negative number for the number of scopes between the current scope 193 * and the scope where a symbol was defined. A value of zero means the current 194 * scope. A negative number if the symbol does not exist. 195 */ 196int 197_mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table, 198 int name_space, const char *name) 199{ 200 struct symbol_header *const hdr = find_symbol(table, name); 201 struct symbol *sym; 202 203 if (hdr != NULL) { 204 for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) { 205 assert(sym->hdr == hdr); 206 207 if ((name_space == -1) || (sym->name_space == name_space)) { 208 assert(sym->depth <= table->depth); 209 return sym->depth - table->depth; 210 } 211 } 212 } 213 214 return -1; 215} 216 217 218void * 219_mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table, 220 int name_space, const char *name) 221{ 222 struct symbol_header *const hdr = find_symbol(table, name); 223 224 if (hdr != NULL) { 225 struct symbol *sym; 226 227 228 for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) { 229 assert(sym->hdr == hdr); 230 231 if ((name_space == -1) || (sym->name_space == name_space)) { 232 return sym->data; 233 } 234 } 235 } 236 237 return NULL; 238} 239 240 241int 242_mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table, 243 int name_space, const char *name, 244 void *declaration) 245{ 246 struct symbol_header *hdr; 247 struct symbol *sym; 248 249 check_symbol_table(table); 250 251 hdr = find_symbol(table, name); 252 253 check_symbol_table(table); 254 255 if (hdr == NULL) { 256 hdr = calloc(1, sizeof(*hdr)); 257 hdr->name = strdup(name); 258 259 hash_table_insert(table->ht, hdr, hdr->name); 260 hdr->next = table->hdr; 261 table->hdr = hdr; 262 } 263 264 check_symbol_table(table); 265 266 /* If the symbol already exists in this namespace at this scope, it cannot 267 * be added to the table. 268 */ 269 for (sym = hdr->symbols 270 ; (sym != NULL) && (sym->name_space != name_space) 271 ; sym = sym->next_with_same_name) { 272 /* empty */ 273 } 274 275 if (sym && (sym->depth == table->depth)) 276 return -1; 277 278 sym = calloc(1, sizeof(*sym)); 279 sym->next_with_same_name = hdr->symbols; 280 sym->next_with_same_scope = table->current_scope->symbols; 281 sym->hdr = hdr; 282 sym->name_space = name_space; 283 sym->data = declaration; 284 sym->depth = table->depth; 285 286 assert(sym->hdr == hdr); 287 288 hdr->symbols = sym; 289 table->current_scope->symbols = sym; 290 291 check_symbol_table(table); 292 return 0; 293} 294 295 296int 297_mesa_symbol_table_add_global_symbol(struct _mesa_symbol_table *table, 298 int name_space, const char *name, 299 void *declaration) 300{ 301 struct symbol_header *hdr; 302 struct symbol *sym; 303 struct symbol *curr; 304 struct scope_level *top_scope; 305 306 check_symbol_table(table); 307 308 hdr = find_symbol(table, name); 309 310 check_symbol_table(table); 311 312 if (hdr == NULL) { 313 hdr = calloc(1, sizeof(*hdr)); 314 hdr->name = strdup(name); 315 316 hash_table_insert(table->ht, hdr, hdr->name); 317 hdr->next = table->hdr; 318 table->hdr = hdr; 319 } 320 321 check_symbol_table(table); 322 323 /* If the symbol already exists in this namespace at this scope, it cannot 324 * be added to the table. 325 */ 326 for (sym = hdr->symbols 327 ; (sym != NULL) && (sym->name_space != name_space) 328 ; sym = sym->next_with_same_name) { 329 /* empty */ 330 } 331 332 if (sym && sym->depth == 0) 333 return -1; 334 335 /* Find the top-level scope */ 336 for (top_scope = table->current_scope 337 ; top_scope->next != NULL 338 ; top_scope = top_scope->next) { 339 /* empty */ 340 } 341 342 sym = calloc(1, sizeof(*sym)); 343 sym->next_with_same_scope = top_scope->symbols; 344 sym->hdr = hdr; 345 sym->name_space = name_space; 346 sym->data = declaration; 347 348 assert(sym->hdr == hdr); 349 350 /* Since next_with_same_name is ordered by scope, we need to append the 351 * new symbol to the _end_ of the list. 352 */ 353 if (hdr->symbols == NULL) { 354 hdr->symbols = sym; 355 } else { 356 for (curr = hdr->symbols 357 ; curr->next_with_same_name != NULL 358 ; curr = curr->next_with_same_name) { 359 /* empty */ 360 } 361 curr->next_with_same_name = sym; 362 } 363 top_scope->symbols = sym; 364 365 check_symbol_table(table); 366 return 0; 367} 368 369 370 371struct _mesa_symbol_table * 372_mesa_symbol_table_ctor(void) 373{ 374 struct _mesa_symbol_table *table = calloc(1, sizeof(*table)); 375 376 if (table != NULL) { 377 table->ht = hash_table_ctor(32, hash_table_string_hash, 378 hash_table_string_compare); 379 380 _mesa_symbol_table_push_scope(table); 381 } 382 383 return table; 384} 385 386 387void 388_mesa_symbol_table_dtor(struct _mesa_symbol_table *table) 389{ 390 struct symbol_header *hdr; 391 struct symbol_header *next; 392 393 while (table->current_scope != NULL) { 394 _mesa_symbol_table_pop_scope(table); 395 } 396 397 for (hdr = table->hdr; hdr != NULL; hdr = next) { 398 next = hdr->next; 399 free(hdr->name); 400 free(hdr); 401 } 402 403 hash_table_dtor(table->ht); 404 free(table); 405} 406