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
28 struct 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 */
73 struct 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 */
88 struct 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 */
100 struct _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
115 struct _mesa_symbol_table_iterator {
116 /**
117 * Name space of symbols returned by this iterator.
118 */
119 int name_space;
120
121
122 /**
123 * Currently iterated symbol
124 *
125 * The next call to \c _mesa_symbol_table_iterator_get will return this
126 * value. It will also update this value to the value that should be
127 * returned by the next call.
128 */
129 struct symbol *curr;
130 };
131
132
133 static void
check_symbol_table(struct _mesa_symbol_table * table)134 check_symbol_table(struct _mesa_symbol_table *table)
135 {
136 #if 1
137 struct scope_level *scope;
138
139 for (scope = table->current_scope; scope != NULL; scope = scope->next) {
140 struct symbol *sym;
141
142 for (sym = scope->symbols
143 ; sym != NULL
144 ; sym = sym->next_with_same_name) {
145 const struct symbol_header *const hdr = sym->hdr;
146 struct symbol *sym2;
147
148 for (sym2 = hdr->symbols
149 ; sym2 != NULL
150 ; sym2 = sym2->next_with_same_name) {
151 assert(sym2->hdr == hdr);
152 }
153 }
154 }
155 #endif
156 }
157
158 void
_mesa_symbol_table_pop_scope(struct _mesa_symbol_table * table)159 _mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table)
160 {
161 struct scope_level *const scope = table->current_scope;
162 struct symbol *sym = scope->symbols;
163
164 table->current_scope = scope->next;
165 table->depth--;
166
167 free(scope);
168
169 while (sym != NULL) {
170 struct symbol *const next = sym->next_with_same_scope;
171 struct symbol_header *const hdr = sym->hdr;
172
173 assert(hdr->symbols == sym);
174
175 hdr->symbols = sym->next_with_same_name;
176
177 free(sym);
178
179 sym = next;
180 }
181
182 check_symbol_table(table);
183 }
184
185
186 void
_mesa_symbol_table_push_scope(struct _mesa_symbol_table * table)187 _mesa_symbol_table_push_scope(struct _mesa_symbol_table *table)
188 {
189 struct scope_level *const scope = calloc(1, sizeof(*scope));
190
191 scope->next = table->current_scope;
192 table->current_scope = scope;
193 table->depth++;
194 }
195
196
197 static struct symbol_header *
find_symbol(struct _mesa_symbol_table * table,const char * name)198 find_symbol(struct _mesa_symbol_table *table, const char *name)
199 {
200 return (struct symbol_header *) hash_table_find(table->ht, name);
201 }
202
203
204 struct _mesa_symbol_table_iterator *
_mesa_symbol_table_iterator_ctor(struct _mesa_symbol_table * table,int name_space,const char * name)205 _mesa_symbol_table_iterator_ctor(struct _mesa_symbol_table *table,
206 int name_space, const char *name)
207 {
208 struct _mesa_symbol_table_iterator *iter = calloc(1, sizeof(*iter));
209 struct symbol_header *const hdr = find_symbol(table, name);
210
211 iter->name_space = name_space;
212
213 if (hdr != NULL) {
214 struct symbol *sym;
215
216 for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) {
217 assert(sym->hdr == hdr);
218
219 if ((name_space == -1) || (sym->name_space == name_space)) {
220 iter->curr = sym;
221 break;
222 }
223 }
224 }
225
226 return iter;
227 }
228
229
230 void
_mesa_symbol_table_iterator_dtor(struct _mesa_symbol_table_iterator * iter)231 _mesa_symbol_table_iterator_dtor(struct _mesa_symbol_table_iterator *iter)
232 {
233 free(iter);
234 }
235
236
237 void *
_mesa_symbol_table_iterator_get(struct _mesa_symbol_table_iterator * iter)238 _mesa_symbol_table_iterator_get(struct _mesa_symbol_table_iterator *iter)
239 {
240 return (iter->curr == NULL) ? NULL : iter->curr->data;
241 }
242
243
244 int
_mesa_symbol_table_iterator_next(struct _mesa_symbol_table_iterator * iter)245 _mesa_symbol_table_iterator_next(struct _mesa_symbol_table_iterator *iter)
246 {
247 struct symbol_header *hdr;
248
249 if (iter->curr == NULL) {
250 return 0;
251 }
252
253 hdr = iter->curr->hdr;
254 iter->curr = iter->curr->next_with_same_name;
255
256 while (iter->curr != NULL) {
257 assert(iter->curr->hdr == hdr);
258 (void)hdr;
259
260 if ((iter->name_space == -1)
261 || (iter->curr->name_space == iter->name_space)) {
262 return 1;
263 }
264
265 iter->curr = iter->curr->next_with_same_name;
266 }
267
268 return 0;
269 }
270
271
272 /**
273 * Determine the scope "distance" of a symbol from the current scope
274 *
275 * \return
276 * A non-negative number for the number of scopes between the current scope
277 * and the scope where a symbol was defined. A value of zero means the current
278 * scope. A negative number if the symbol does not exist.
279 */
280 int
_mesa_symbol_table_symbol_scope(struct _mesa_symbol_table * table,int name_space,const char * name)281 _mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table,
282 int name_space, const char *name)
283 {
284 struct symbol_header *const hdr = find_symbol(table, name);
285 struct symbol *sym;
286
287 if (hdr != NULL) {
288 for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) {
289 assert(sym->hdr == hdr);
290
291 if ((name_space == -1) || (sym->name_space == name_space)) {
292 assert(sym->depth <= table->depth);
293 return sym->depth - table->depth;
294 }
295 }
296 }
297
298 return -1;
299 }
300
301
302 void *
_mesa_symbol_table_find_symbol(struct _mesa_symbol_table * table,int name_space,const char * name)303 _mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table,
304 int name_space, const char *name)
305 {
306 struct symbol_header *const hdr = find_symbol(table, name);
307
308 if (hdr != NULL) {
309 struct symbol *sym;
310
311
312 for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) {
313 assert(sym->hdr == hdr);
314
315 if ((name_space == -1) || (sym->name_space == name_space)) {
316 return sym->data;
317 }
318 }
319 }
320
321 return NULL;
322 }
323
324
325 int
_mesa_symbol_table_add_symbol(struct _mesa_symbol_table * table,int name_space,const char * name,void * declaration)326 _mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table,
327 int name_space, const char *name,
328 void *declaration)
329 {
330 struct symbol_header *hdr;
331 struct symbol *sym;
332
333 check_symbol_table(table);
334
335 hdr = find_symbol(table, name);
336
337 check_symbol_table(table);
338
339 if (hdr == NULL) {
340 hdr = calloc(1, sizeof(*hdr));
341 hdr->name = strdup(name);
342
343 hash_table_insert(table->ht, hdr, hdr->name);
344 hdr->next = table->hdr;
345 table->hdr = hdr;
346 }
347
348 check_symbol_table(table);
349
350 /* If the symbol already exists in this namespace at this scope, it cannot
351 * be added to the table.
352 */
353 for (sym = hdr->symbols
354 ; (sym != NULL) && (sym->name_space != name_space)
355 ; sym = sym->next_with_same_name) {
356 /* empty */
357 }
358
359 if (sym && (sym->depth == table->depth))
360 return -1;
361
362 sym = calloc(1, sizeof(*sym));
363 sym->next_with_same_name = hdr->symbols;
364 sym->next_with_same_scope = table->current_scope->symbols;
365 sym->hdr = hdr;
366 sym->name_space = name_space;
367 sym->data = declaration;
368 sym->depth = table->depth;
369
370 assert(sym->hdr == hdr);
371
372 hdr->symbols = sym;
373 table->current_scope->symbols = sym;
374
375 check_symbol_table(table);
376 return 0;
377 }
378
379
380 int
_mesa_symbol_table_add_global_symbol(struct _mesa_symbol_table * table,int name_space,const char * name,void * declaration)381 _mesa_symbol_table_add_global_symbol(struct _mesa_symbol_table *table,
382 int name_space, const char *name,
383 void *declaration)
384 {
385 struct symbol_header *hdr;
386 struct symbol *sym;
387 struct symbol *curr;
388 struct scope_level *top_scope;
389
390 check_symbol_table(table);
391
392 hdr = find_symbol(table, name);
393
394 check_symbol_table(table);
395
396 if (hdr == NULL) {
397 hdr = calloc(1, sizeof(*hdr));
398 hdr->name = strdup(name);
399
400 hash_table_insert(table->ht, hdr, hdr->name);
401 hdr->next = table->hdr;
402 table->hdr = hdr;
403 }
404
405 check_symbol_table(table);
406
407 /* If the symbol already exists in this namespace at this scope, it cannot
408 * be added to the table.
409 */
410 for (sym = hdr->symbols
411 ; (sym != NULL) && (sym->name_space != name_space)
412 ; sym = sym->next_with_same_name) {
413 /* empty */
414 }
415
416 if (sym && sym->depth == 0)
417 return -1;
418
419 /* Find the top-level scope */
420 for (top_scope = table->current_scope
421 ; top_scope->next != NULL
422 ; top_scope = top_scope->next) {
423 /* empty */
424 }
425
426 sym = calloc(1, sizeof(*sym));
427 sym->next_with_same_scope = top_scope->symbols;
428 sym->hdr = hdr;
429 sym->name_space = name_space;
430 sym->data = declaration;
431
432 assert(sym->hdr == hdr);
433
434 /* Since next_with_same_name is ordered by scope, we need to append the
435 * new symbol to the _end_ of the list.
436 */
437 if (hdr->symbols == NULL) {
438 hdr->symbols = sym;
439 } else {
440 for (curr = hdr->symbols
441 ; curr->next_with_same_name != NULL
442 ; curr = curr->next_with_same_name) {
443 /* empty */
444 }
445 curr->next_with_same_name = sym;
446 }
447 top_scope->symbols = sym;
448
449 check_symbol_table(table);
450 return 0;
451 }
452
453
454
455 struct _mesa_symbol_table *
_mesa_symbol_table_ctor(void)456 _mesa_symbol_table_ctor(void)
457 {
458 struct _mesa_symbol_table *table = calloc(1, sizeof(*table));
459
460 if (table != NULL) {
461 table->ht = hash_table_ctor(32, hash_table_string_hash,
462 hash_table_string_compare);
463
464 _mesa_symbol_table_push_scope(table);
465 }
466
467 return table;
468 }
469
470
471 void
_mesa_symbol_table_dtor(struct _mesa_symbol_table * table)472 _mesa_symbol_table_dtor(struct _mesa_symbol_table *table)
473 {
474 struct symbol_header *hdr;
475 struct symbol_header *next;
476
477 while (table->current_scope != NULL) {
478 _mesa_symbol_table_pop_scope(table);
479 }
480
481 for (hdr = table->hdr; hdr != NULL; hdr = next) {
482 next = hdr->next;
483 free(hdr->name);
484 free(hdr);
485 }
486
487 hash_table_dtor(table->ht);
488 free(table);
489 }
490