LCOV - code coverage report
Current view: top level - src - symbol.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 179 190 94.2 %
Date: 2015-04-20 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /* This file is part of GNU cflow
       2             :    Copyright (C) 1997, 2005, 2006, 2007, 2009, 2010 Sergey Poznyakoff
       3             : 
       4             :    GNU cflow is free software; you can redistribute it and/or modify
       5             :    it under the terms of the GNU General Public License as published by
       6             :    the Free Software Foundation; either version 3 of the License, or
       7             :    (at your option) any later version.
       8             : 
       9             :    GNU cflow is distributed in the hope that it will be useful,
      10             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :    GNU General Public License for more details.
      13             : 
      14             :    You should have received a copy of the GNU General Public
      15             :    License along with GNU cflow; if not, write to the Free Software
      16             :    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
      17             :    MA 02110-1301 USA */
      18             : 
      19             : #include <cflow.h>
      20             : #include <parser.h>
      21             : #include <hash.h>
      22             : 
      23             : static Hash_table *symbol_table;
      24             : 
      25             : static struct linked_list *static_symbol_list;
      26             : static struct linked_list *auto_symbol_list;
      27             : static struct linked_list *static_func_list;
      28             : 
      29             : static void
      30       10369 : append_symbol(struct linked_list **plist, Symbol *sp)
      31             : {
      32       10369 :      if (sp->entry) {
      33         112 :           linked_list_unlink(sp->entry->list, sp->entry);
      34         112 :           sp->entry = NULL;
      35             :      }
      36       10369 :      if (!data_in_list(sp, *plist)) {
      37       10369 :           linked_list_append(plist, sp);
      38       10369 :           sp->entry = (*plist)->tail;
      39             :      }
      40       10369 : }
      41             : 
      42             : struct table_entry {
      43             :      Symbol *sym;
      44             : };
      45             : 
      46             : /* Calculate the hash of a string.  */
      47             : static size_t
      48      285574 : hash_symbol_hasher(void const *data, unsigned n_buckets)
      49             : {
      50      285574 :      struct table_entry const *t = data;
      51      285574 :      if (!t->sym)
      52       19544 :           return ((size_t) data) % n_buckets;
      53      266030 :      return hash_string(t->sym->name, n_buckets);
      54             : }
      55             : 
      56             : /* Compare two strings for equality.  */
      57             : static bool
      58      418873 : hash_symbol_compare(void const *data1, void const *data2)
      59             : {
      60      418873 :      struct table_entry const *t1 = data1;
      61      418873 :      struct table_entry const *t2 = data2;
      62      418873 :      return t1->sym && t2->sym && strcmp(t1->sym->name, t2->sym->name) == 0;
      63             : }
      64             : 
      65             : Symbol *
      66      223733 : lookup(const char *name)
      67             : {
      68             :      Symbol s, *sym;
      69             :      struct table_entry t, *tp;
      70             :      
      71      223733 :      if (!symbol_table)
      72           0 :           return NULL;
      73      223733 :      s.name = (char*) name;
      74      223733 :      t.sym = &s;
      75      223733 :      tp = hash_lookup(symbol_table, &t);
      76      223733 :      if (tp) {
      77      188245 :           sym = tp->sym;
      78      376490 :           while (sym->type == SymToken && sym->flag == symbol_alias)
      79           0 :                sym = sym->alias;
      80             :      } else
      81       35488 :           sym = NULL;
      82      223733 :      return sym;
      83             : }
      84             : 
      85             : /* Install a new symbol `NAME'.  If UNIT_LOCAL is set, this symbol can
      86             :    be local to the current compilation unit. */
      87             : Symbol *
      88       18302 : install(char *name, int flags)
      89             : {
      90             :      Symbol *sym;
      91             :      struct table_entry *tp, *ret;
      92             :      
      93       18302 :      sym = xmalloc(sizeof(*sym));
      94       18302 :      memset(sym, 0, sizeof(*sym));
      95       18302 :      sym->type = SymUndefined;
      96       18302 :      sym->name = name;
      97             : 
      98       18302 :      tp = xmalloc(sizeof(*tp));
      99       18302 :      tp->sym = sym;
     100             :      
     101       18302 :      if (((flags & INSTALL_CHECK_LOCAL) &&
     102       27223 :           canonical_filename && strcmp(filename, canonical_filename)) ||
     103       16954 :          (flags & INSTALL_UNIT_LOCAL)) {
     104        1556 :           sym->flag = symbol_temp;
     105        1556 :           append_symbol(&static_symbol_list, sym);
     106             :      } else
     107       16746 :           sym->flag = symbol_none;
     108             :      
     109       36604 :      if (! ((symbol_table
     110          21 :              || (symbol_table = hash_initialize (0, 0, 
     111             :                                                  hash_symbol_hasher,
     112             :                                                  hash_symbol_compare, 0)))
     113       18302 :             && (ret = hash_insert (symbol_table, tp))))
     114           0 :           xalloc_die ();
     115             : 
     116       18302 :      if (ret != tp) {
     117        1423 :           if (flags & INSTALL_OVERWRITE) {
     118           0 :                free(sym);
     119           0 :                free(tp);
     120           0 :                return ret->sym;
     121             :           }
     122        1423 :           if (ret->sym->type != SymUndefined) 
     123        1423 :                sym->next = ret->sym;
     124        1423 :           ret->sym = sym;
     125        1423 :           free(tp);
     126             :      }
     127       18302 :      sym->owner = ret;
     128       18302 :      return sym;
     129             : }
     130             : 
     131             : void
     132       22484 : ident_change_storage(Symbol *sp, enum storage storage)
     133             : {
     134       22484 :      if (sp->storage == storage)
     135       36149 :           return;
     136        8819 :      if (sp->storage == StaticStorage)
     137             :           /* FIXME */;
     138             : 
     139        8819 :      switch (storage) {
     140             :      case StaticStorage:
     141        1581 :           append_symbol(&static_symbol_list, sp);
     142        1581 :           break;
     143             :      case AutoStorage:
     144        7232 :           append_symbol(&auto_symbol_list, sp);
     145        7232 :           break;
     146             :      default:
     147           6 :           break;
     148             :      }
     149        8819 :      sp->storage = storage;
     150             : }
     151             : 
     152             : Symbol *
     153       17501 : install_ident(char *name, enum storage storage)
     154             : {
     155             :      Symbol *sp;
     156             : 
     157       17501 :      sp = install(name, 
     158             :                   storage != AutoStorage ? 
     159             :                      INSTALL_CHECK_LOCAL : INSTALL_DEFAULT);
     160       17501 :      sp->type = SymIdentifier;
     161       17501 :      sp->arity = -1;
     162       17501 :      sp->storage = ExternStorage;
     163       17501 :      sp->decl = NULL;
     164       17501 :      sp->source = NULL;
     165       17501 :      sp->def_line = -1;
     166       17501 :      sp->ref_line = NULL;
     167       17501 :      sp->caller = sp->callee = NULL;
     168       17501 :      sp->level = -1;
     169       17501 :      ident_change_storage(sp, storage);
     170       17501 :      return sp;
     171             : }
     172             : 
     173             : /* Unlink the symbol from the table entry */
     174             : static void
     175       10257 : unlink_symbol(Symbol *sym)
     176             : {
     177       10257 :      Symbol *s, *prev = NULL;
     178       10257 :      struct table_entry *tp = sym->owner;
     179       20514 :      for (s = tp->sym; s; ) {
     180       10257 :           Symbol *next = s->next;
     181       10257 :           if (s == sym) {
     182       10257 :                if (prev)
     183           0 :                     prev->next = next;
     184             :                else
     185       10257 :                     tp->sym = next;
     186       10257 :                break;
     187             :           } else
     188           0 :                prev = s;
     189           0 :           s = next;
     190             :      }
     191             :                
     192       10257 :      sym->owner = NULL;
     193       10257 : }     
     194             : 
     195             : /* Unlink and free the first symbol from the table entry */
     196             : static void
     197        8788 : delete_symbol(Symbol *sym)
     198             : {
     199        8788 :      unlink_symbol(sym);
     200             :      /* The symbol could have been referenced even if it is static
     201             :         in -i^s mode. See tests/static.at for details. */
     202        8788 :      if (sym->ref_line == NULL && !(reverse_tree && sym->callee)) {
     203        7538 :           linked_list_destroy(&sym->ref_line);
     204        7538 :           linked_list_destroy(&sym->caller);
     205        7538 :           linked_list_destroy(&sym->callee);
     206        7538 :           free(sym);
     207             :      }
     208        8788 : }     
     209             : 
     210             : /* Delete from the symbol table all static symbols defined in the current
     211             :    source.
     212             :    If the user requested static symbols in the listing, the symbol is
     213             :    not deleted, as it may have been referenced by other symbols. Instead,
     214             :    it is unlinked from its table entry.
     215             :    NOTE: This takes advantage of the fact that install() uses LIFO strategy,
     216             :    so we don't have to check the name of the source where the symbol was
     217             :    defined. */
     218             : 
     219             : static void
     220        3009 : static_free(void *data)
     221             : {
     222        3009 :      Symbol *sym = data;
     223        3009 :      struct table_entry *t = sym->owner;
     224             : 
     225        3009 :      if (!t)
     226        3009 :           return;
     227        3009 :      if (sym->flag == symbol_temp) 
     228        1556 :           delete_symbol(sym);
     229             :      else {
     230        1453 :           unlink_symbol(sym);
     231        1453 :           if (symbol_is_function(sym))
     232         892 :                linked_list_append(&static_func_list, sym);
     233             :      }
     234             : }
     235             : 
     236             : void
     237         229 : delete_statics()
     238             : {
     239         229 :      if (static_symbol_list) {
     240         177 :           static_symbol_list->free_data = static_free;
     241         177 :           linked_list_destroy(&static_symbol_list);
     242             :      }
     243         229 : }
     244             : 
     245             : /* See NOTE above */
     246             : 
     247             : /* Delete from the symbol table all auto variables with given nesting
     248             :    level. */
     249             : int
     250       19982 : delete_level_autos(void *data, void *call_data)
     251             : {
     252       19982 :      int level = *(int*)call_data;
     253       19982 :      Symbol *s = data;
     254       19982 :      if (s->level == level) {
     255        6650 :           delete_symbol(s);
     256        6650 :           return 1;
     257             :      }
     258       13332 :      return 0;
     259             : }
     260             : 
     261             : int
     262      211177 : delete_level_statics(void *data, void *call_data)
     263             : {
     264      211177 :      int level = *(int*)call_data;
     265      211177 :      Symbol *s = data;
     266      211177 :      if (s->level == level) {
     267          16 :           unlink_symbol(s);
     268          16 :           return 1;
     269             :      }
     270      211161 :      return 0;
     271             : }
     272             : 
     273             : void
     274        8401 : delete_autos(int level)
     275             : {
     276        8401 :      linked_list_iterate(&auto_symbol_list, delete_level_autos, &level);
     277        8401 :      linked_list_iterate(&static_symbol_list, delete_level_statics, &level);
     278        8401 : }
     279             : 
     280             : struct collect_data {
     281             :      Symbol **sym;
     282             :      int (*sel)(Symbol *p);
     283             :      size_t index;
     284             : };
     285             : 
     286             : static bool
     287       57118 : collect_processor(void *data, void *proc_data)
     288             : {
     289       57118 :      struct table_entry *t = data;
     290       57118 :      struct collect_data *cd = proc_data;
     291             :      Symbol *s;
     292       84378 :      for (s = t->sym; s; s = s->next) {
     293       27260 :           if (cd->sel(s)) {
     294       17232 :                if (cd->sym)
     295        8616 :                     cd->sym[cd->index] = s;
     296       17232 :                cd->index++;
     297             :           }
     298             :      }
     299       57118 :      return true;
     300             : }
     301             : 
     302             : size_t
     303          37 : collect_symbols(Symbol ***return_sym, int (*sel)(Symbol *p),
     304             :                 size_t reserved_slots)
     305             : {
     306             :      struct collect_data cdata;
     307             : 
     308          37 :      cdata.sym = NULL;
     309          37 :      cdata.index = 0;
     310          37 :      cdata.sel = sel;
     311          37 :      hash_do_for_each (symbol_table, collect_processor, &cdata);
     312          37 :      cdata.sym = calloc(cdata.index + reserved_slots, sizeof(*cdata.sym));
     313          37 :      if (!cdata.sym)
     314           0 :           xalloc_die();
     315          37 :      cdata.index = 0;
     316          37 :      hash_do_for_each (symbol_table, collect_processor, &cdata);
     317          37 :      *return_sym = cdata.sym;
     318          37 :      return cdata.index;
     319             : }
     320             : 
     321             : size_t
     322          16 : collect_functions(Symbol ***return_sym)
     323             : {
     324             :      Symbol **symbols;
     325             :      size_t num, snum;
     326             :      struct linked_list_entry *p;
     327             : 
     328             :      /* Count static functions */
     329          16 :      snum = 0;
     330          16 :      if (static_func_list)
     331         627 :           for (p = linked_list_head(static_func_list); p; p = p->next)
     332         615 :                snum++;
     333             :      
     334             :      /* Collect global functions */
     335          16 :      num = collect_symbols(&symbols, symbol_is_function, snum);
     336             : 
     337             :      /* Collect static functions */
     338          16 :      if (snum) 
     339         627 :           for (p = linked_list_head(static_func_list); p; p = p->next)
     340         615 :                symbols[num++] = p->data;
     341          16 :      *return_sym = symbols;
     342          16 :      return num;
     343             : }
     344             : 
     345             : 
     346             : 
     347             : /* Special handling for function parameters */
     348             : 
     349             : int
     350        8286 : delete_parms_itr(void *data, void *call_data)
     351             : {
     352        8286 :      int level = *(int*)call_data;
     353        8286 :      Symbol *s = data;
     354        8286 :      struct table_entry *t = s->owner;
     355             :           
     356        8286 :      if (!t)
     357           0 :           return 1;
     358        8286 :      if (s->type == SymIdentifier && s->storage == AutoStorage
     359        8286 :          && s->flag == symbol_parm && s->level > level) {
     360         582 :           delete_symbol(s);
     361         582 :           return 1;
     362             :      }
     363        7704 :      return 0;
     364             : }
     365             : 
     366             : /* Delete all parameters with parameter nesting level greater than LEVEL */
     367             : void
     368       11854 : delete_parms(int level)
     369             : {
     370       11854 :      linked_list_iterate(&auto_symbol_list, delete_parms_itr, &level);
     371       11854 : }
     372             : 
     373             : /* Redeclare all saved parameters as automatic variables with the
     374             :    given nesting level */
     375             : void
     376        3039 : move_parms(int level)
     377             : {
     378             :      struct linked_list_entry *p;
     379             : 
     380        7027 :      for (p = linked_list_head(auto_symbol_list); p; p = p->next) {
     381        3988 :           Symbol *s = p->data;
     382             : 
     383        3988 :           if (s->type == SymIdentifier && s->storage == AutoStorage
     384        3988 :               && s->flag == symbol_parm) {
     385        3988 :                s->level = level;
     386        3988 :                s->flag = symbol_none;
     387             :           }
     388             :      }
     389        3039 : }
     390             : 

Generated by: LCOV version 1.10