Home | History | Annotate | Download | only in program
      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 "../../util/hash_table.h"
     27 #include "util/u_string.h"
     28 
     29 struct symbol {
     30    /** Symbol name. */
     31    char *name;
     32 
     33     /**
     34      * Link to the next symbol in the table with the same name
     35      *
     36      * The linked list of symbols with the same name is ordered by scope
     37      * from inner-most to outer-most.
     38      */
     39     struct symbol *next_with_same_name;
     40 
     41     /**
     42      * Link to the next symbol in the table with the same scope
     43      *
     44      * The linked list of symbols with the same scope is unordered.  Symbols
     45      * in this list my have unique names.
     46      */
     47     struct symbol *next_with_same_scope;
     48 
     49     /** Scope depth where this symbol was defined. */
     50     unsigned depth;
     51 
     52     /**
     53      * Arbitrary user supplied data.
     54      */
     55     void *data;
     56 };
     57 
     58 
     59 /**
     60  * Element of the scope stack.
     61  */
     62 struct scope_level {
     63     /** Link to next (inner) scope level. */
     64     struct scope_level *next;
     65 
     66     /** Linked list of symbols with the same scope. */
     67     struct symbol *symbols;
     68 };
     69 
     70 
     71 /**
     72  *
     73  */
     74 struct _mesa_symbol_table {
     75     /** Hash table containing all symbols in the symbol table. */
     76     struct hash_table *ht;
     77 
     78     /** Top of scope stack. */
     79     struct scope_level *current_scope;
     80 
     81     /** Current scope depth. */
     82     unsigned depth;
     83 };
     84 
     85 void
     86 _mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table)
     87 {
     88     struct scope_level *const scope = table->current_scope;
     89     struct symbol *sym = scope->symbols;
     90 
     91     table->current_scope = scope->next;
     92     table->depth--;
     93 
     94     free(scope);
     95 
     96     while (sym != NULL) {
     97         struct symbol *const next = sym->next_with_same_scope;
     98         struct hash_entry *hte = _mesa_hash_table_search(table->ht,
     99                                                          sym->name);
    100         if (sym->next_with_same_name) {
    101            /* If there is a symbol with this name in an outer scope update
    102             * the hash table to point to it.
    103             */
    104            hte->key = sym->next_with_same_name->name;
    105            hte->data = sym->next_with_same_name;
    106         } else {
    107            _mesa_hash_table_remove(table->ht, hte);
    108            free(sym->name);
    109         }
    110 
    111         free(sym);
    112         sym = next;
    113     }
    114 }
    115 
    116 
    117 void
    118 _mesa_symbol_table_push_scope(struct _mesa_symbol_table *table)
    119 {
    120     struct scope_level *const scope = calloc(1, sizeof(*scope));
    121     if (scope == NULL) {
    122        _mesa_error_no_memory(__func__);
    123        return;
    124     }
    125 
    126     scope->next = table->current_scope;
    127     table->current_scope = scope;
    128     table->depth++;
    129 }
    130 
    131 
    132 static struct symbol *
    133 find_symbol(struct _mesa_symbol_table *table, const char *name)
    134 {
    135    struct hash_entry *entry = _mesa_hash_table_search(table->ht, name);
    136    return entry ? (struct symbol *) entry->data : NULL;
    137 }
    138 
    139 
    140 /**
    141  * Determine the scope "distance" of a symbol from the current scope
    142  *
    143  * \return
    144  * A non-negative number for the number of scopes between the current scope
    145  * and the scope where a symbol was defined.  A value of zero means the current
    146  * scope.  A negative number if the symbol does not exist.
    147  */
    148 int
    149 _mesa_symbol_table_symbol_scope(struct _mesa_symbol_table *table,
    150                                 const char *name)
    151 {
    152    struct symbol *const sym = find_symbol(table, name);
    153 
    154    if (sym) {
    155       assert(sym->depth <= table->depth);
    156       return sym->depth - table->depth;
    157    }
    158 
    159    return -1;
    160 }
    161 
    162 
    163 void *
    164 _mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table,
    165                                const char *name)
    166 {
    167    struct symbol *const sym = find_symbol(table, name);
    168    if (sym)
    169       return sym->data;
    170 
    171    return NULL;
    172 }
    173 
    174 
    175 int
    176 _mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table,
    177                               const char *name, void *declaration)
    178 {
    179    struct symbol *new_sym;
    180    struct symbol *sym = find_symbol(table, name);
    181 
    182    if (sym && sym->depth == table->depth)
    183       return -1;
    184 
    185    new_sym = calloc(1, sizeof(*sym));
    186    if (new_sym == NULL) {
    187       _mesa_error_no_memory(__func__);
    188       return -1;
    189    }
    190 
    191    if (sym) {
    192       /* Store link to symbol in outer scope with the same name */
    193       new_sym->next_with_same_name = sym;
    194       new_sym->name = sym->name;
    195    } else {
    196       new_sym->name = util_strdup(name);
    197       if (new_sym->name == NULL) {
    198          free(new_sym);
    199          _mesa_error_no_memory(__func__);
    200          return -1;
    201       }
    202    }
    203 
    204    new_sym->next_with_same_scope = table->current_scope->symbols;
    205    new_sym->data = declaration;
    206    new_sym->depth = table->depth;
    207 
    208    table->current_scope->symbols = new_sym;
    209 
    210    _mesa_hash_table_insert(table->ht, new_sym->name, new_sym);
    211 
    212    return 0;
    213 }
    214 
    215 int
    216 _mesa_symbol_table_replace_symbol(struct _mesa_symbol_table *table,
    217                                   const char *name,
    218                                   void *declaration)
    219 {
    220     struct symbol *sym = find_symbol(table, name);
    221 
    222     /* If the symbol doesn't exist, it cannot be replaced. */
    223     if (sym == NULL)
    224        return -1;
    225 
    226     sym->data = declaration;
    227     return 0;
    228 }
    229 
    230 int
    231 _mesa_symbol_table_add_global_symbol(struct _mesa_symbol_table *table,
    232                                      const char *name, void *declaration)
    233 {
    234    struct scope_level *top_scope;
    235    struct symbol *inner_sym = NULL;
    236    struct symbol *sym = find_symbol(table, name);
    237 
    238    while (sym) {
    239       if (sym->depth == 0)
    240          return -1;
    241 
    242       inner_sym = sym;
    243 
    244       /* Get symbol from the outer scope with the same name */
    245       sym = sym->next_with_same_name;
    246    }
    247 
    248    /* Find the top-level scope */
    249    for (top_scope = table->current_scope; top_scope->next != NULL;
    250         top_scope = top_scope->next) {
    251       /* empty */
    252    }
    253 
    254    sym = calloc(1, sizeof(*sym));
    255    if (sym == NULL) {
    256       _mesa_error_no_memory(__func__);
    257       return -1;
    258    }
    259 
    260    if (inner_sym) {
    261       /* In case we add the global out of order store a link to the global
    262        * symbol in global.
    263        */
    264       inner_sym->next_with_same_name = sym;
    265 
    266       sym->name = inner_sym->name;
    267    } else {
    268       sym->name = util_strdup(name);
    269       if (sym->name == NULL) {
    270          free(sym);
    271          _mesa_error_no_memory(__func__);
    272          return -1;
    273       }
    274    }
    275 
    276    sym->next_with_same_scope = top_scope->symbols;
    277    sym->data = declaration;
    278 
    279    top_scope->symbols = sym;
    280 
    281    _mesa_hash_table_insert(table->ht, sym->name, sym);
    282 
    283    return 0;
    284 }
    285 
    286 
    287 
    288 struct _mesa_symbol_table *
    289 _mesa_symbol_table_ctor(void)
    290 {
    291     struct _mesa_symbol_table *table = calloc(1, sizeof(*table));
    292 
    293     if (table != NULL) {
    294        table->ht = _mesa_hash_table_create(NULL, _mesa_key_hash_string,
    295                                            _mesa_key_string_equal);
    296 
    297        _mesa_symbol_table_push_scope(table);
    298     }
    299 
    300     return table;
    301 }
    302 
    303 
    304 void
    305 _mesa_symbol_table_dtor(struct _mesa_symbol_table *table)
    306 {
    307    while (table->current_scope != NULL) {
    308       _mesa_symbol_table_pop_scope(table);
    309    }
    310 
    311    _mesa_hash_table_destroy(table->ht, NULL);
    312    free(table);
    313 }
    314