symtab.c
上传用户:lengbin
上传日期:2010-03-31
资源大小:121k
文件大小:21k
开发平台:

C/C++

  1. /*----------------------------------------------------------------------
  2.   File    : symtab.c
  3.   Contents: symbol table management
  4.   Author  : Christian Borgelt
  5.   History : 22.10.1995 file created
  6.             30.10.1995 functions made independent of symbol data
  7.             26.11.1995 symbol types and visibility levels added
  8.             04.01.1996 st_clear added
  9.             27.02.1996 st_insert modified
  10.             28.06.1996 dynamic bucket vector enlargement added
  11.             04.07.1996 bug in bucket reorganization removed
  12.             01.04.1997 functions st_clear and st_remove combined
  13.             29.07.1997 minor improvements
  14.             05.08.1997 minor improvements
  15.             16.11.1997 some comments improved
  16.             06.02.1998 default table sizes changed
  17.             31.05.1998 list of all symbols removed
  18.             20.06.1998 deletion function moved to st_create
  19.             14.07.1998 minor improvements
  20.             01.09.1998 bug in function _sort removed, assertions added
  21.             25.09.1998 hash function improved
  22.             28.09.1998 types ULONG and CCHAR removed, st_stats added
  23.             04.02.1999 long int changed to int
  24.             10.11.1999 name/identifier map management added
  25.             15.08.2003 renamed new to nel in st_insert (C++ compat.)
  26.             15.12.2004 function nim_trunc added
  27.             28.12.2004 bug in function nim_trunc fixed
  28. ----------------------------------------------------------------------*/
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <limits.h>
  33. #include <assert.h>
  34. #include "symtab.h"
  35. #ifdef NIMAPFN
  36. #include "vecops.h"
  37. #endif
  38. #ifdef STORAGE
  39. #include "storage.h"
  40. #endif
  41. /*----------------------------------------------------------------------
  42.   Preprocessor Definitions
  43. ----------------------------------------------------------------------*/
  44. #define DFLT_INIT     1023      /* default initial hash table size */
  45. #if (INT_MAX > 32767)
  46. #define DFLT_MAX   1048575      /* default maximal hash table size */
  47. #else
  48. #define DFLT_MAX     16383      /* default maximal hash table size */
  49. #endif
  50. #define BLKSIZE        256      /* block size for identifier vector */
  51. /*----------------------------------------------------------------------
  52.   Default Hash Function
  53. ----------------------------------------------------------------------*/
  54. static unsigned _hdflt (const char *name, int type)
  55. {                               /* --- default hash function */
  56.   register unsigned h = type;   /* hash value */
  57.   while (*name) h ^= (h << 3) ^ (unsigned)(*name++);
  58.   return h;                     /* compute hash value */
  59. }  /* _hdflt() */
  60. /*----------------------------------------------------------------------
  61.   Auxiliary Functions
  62. ----------------------------------------------------------------------*/
  63. static void _delsym (SYMTAB *tab)
  64. {                               /* --- delete all symbols */
  65.   int i;                        /* loop variable */
  66.   STE *ste, *tmp;               /* to traverse the symbol list */
  67.   for (i = tab->size; --i >= 0; ) {  /* traverse bucket vector */
  68.     ste = tab->bvec[i];         /* get the next bucket list, */
  69.     tab->bvec[i] = NULL;        /* clear the bucket vector entry, */
  70.     while (ste) {               /* and traverse the bucket list */
  71.       tmp = ste;                /* note the symbol to delete */
  72.       ste = ste->succ;          /* and get the next symbol */
  73.       if (tab->delfn) tab->delfn(tmp +1);
  74.       free(tmp);                /* if a deletion function is given, */
  75.     }                           /* call it and then deallocate */
  76.   }                             /* the symbol table element */
  77. }  /* _delsym() */
  78. /*--------------------------------------------------------------------*/
  79. static STE** _merge (STE *in[], int cnt[], STE **out)
  80. {                               /* --- merge two lists into one */
  81.   int k;                        /* index of input list */
  82.   do {                          /* compare and merge loop */
  83.     k = (in[0]->level > in[1]->level) ? 0 : 1;
  84.     *out  = in[k];              /* append the element on the higher */
  85.     out   = &(*out)->succ;      /* level to the output list and */
  86.     in[k] = *out;               /* remove it from the input list */
  87.   } while (--cnt[k] > 0);       /* while both lists are not empty */
  88.   *out = in[k ^= 1];            /* append remaining elements */
  89.   while (--cnt[k] >= 0)         /* while not at the end of the list */
  90.     out = &(*out)->succ;        /* go to the successor element */
  91.   in[k] = *out;                 /* set new start of the input list */
  92.   *out  = NULL;                 /* terminate the output list and */
  93.   return out;                   /* return new end of the output list */
  94. }  /* _merge() */
  95. /*--------------------------------------------------------------------*/
  96. static STE* _sort (STE *list)
  97. {                               /* --- sort a hash bucket list */
  98.   STE *ste;                     /* to traverse the list, buffer */
  99.   STE *in[2], *out[2];          /* input and output lists */
  100.   STE **end[2];                 /* ends of output lists */
  101.   int cnt[2];                   /* number of elements to merge */
  102.   int run;                      /* run length in input lists */
  103.   int rem;                      /* elements in remainder collection */
  104.   int oid;                      /* index of output list */
  105.   if (!list) return list;       /* empty lists need not to be sorted */
  106.   oid = 0; out[0] = list;       /* traverse list elements */
  107.   for (ste = list->succ; ste; ste = ste->succ)
  108.     if ((oid ^= 1) == 0) list = list->succ;
  109.   out[1] = list->succ;          /* split list into two equal parts */
  110.   list   = list->succ = NULL;   /* initialize remainder collection */
  111.   run    = 1; rem = 0;          /* and run length */
  112.   while (out[1]) {              /* while there are two lists */
  113.     in [0] = out[0]; in [1] = out[1];  /* move output list to input */
  114.     end[0] = out;    end[1] = out+1;   /* reinitialize end pointers */
  115.     out[1] = NULL;   oid    = 0;       /* start with 1st output list */
  116.     do {                        /* merge loop */
  117.       cnt[0]   = cnt[1] = run;  /* merge run elements from the */
  118.       end[oid] = _merge(in, cnt, end[oid]);     /* input lists */
  119.       oid ^= 1;                 /* toggle index of output list */
  120.     } while (in[1]);            /* while both lists are not empty */
  121.     if (in[0]) {                /* if there is one input list left */
  122.       if (!list)                /* if there is no rem. collection, */
  123.         list = in[0];           /* just note the rem. input list */
  124.       else {                    /* if there is a rem. collection, */
  125.         cnt[0] = run; cnt[1] = rem; in[1] = list;
  126.         _merge(in, cnt, &list); /* merge it and the input list to */
  127.       }                         /* get the new renmainder collection */
  128.       rem += run;               /* there are now run more elements */
  129.     }                           /* in the remainder collection */
  130.     run <<= 1;                  /* double run length */
  131.   }  /* while (out[1]) .. */
  132.   if (rem > 0) {                /* if there is a rem. collection */
  133.     in[0] = out[0]; cnt[0] = run;
  134.     in[1] = list;   cnt[1] = rem;
  135.     _merge(in, cnt, out);       /* merge it to the output list */
  136.   }                             /* and store the result in out[0] */
  137.   return out[0];                /* return the sorted list */
  138. }  /* _sort() */
  139. /*--------------------------------------------------------------------*/
  140. static void _reorg (SYMTAB *tab)
  141. {                               /* --- reorganize a hash table */
  142.   int i;                        /* loop variable */
  143.   int size;                     /* new bucket vector size */
  144.   STE **p;                      /* new bucket vector, buffer */
  145.   STE *ste;                     /* to traverse symbol table elements */
  146.   STE *list = NULL;             /* list of all symbols */
  147.   size = (tab->size << 1) +1;   /* calculate new vector size */
  148.   if (size > tab->max)          /* if new size exceeds maximum, */
  149.     size = tab->max;            /* set the maximal size */
  150.   for (p = &list, i = tab->size; --i >= 0; ) {
  151.     *p = tab->bvec[i];          /* traverse the bucket vector and */
  152.     while (*p) p = &(*p)->succ; /* link all bucket lists together */
  153.   }                             /* (collect symbols) */
  154.   p = (STE**)realloc(tab->bvec, size *sizeof(STE*));
  155.   if (!p) return;               /* enlarge bucket vector */
  156.   tab->bvec = p;                /* set new bucket vector */
  157.   tab->size = size;             /* and its size */
  158.   for (p += i = size; --i >= 0; )
  159.     *--p = NULL;                /* clear the hash buckets */
  160.   while (list) {                /* traverse list of all symbols */
  161.     ste = list; list = list->succ;           /* get next symbol */
  162.     i   = tab->hash(ste->name, ste->type) %size;
  163.     ste->succ = tab->bvec[i];   /* compute the hash bucket index */
  164.     tab->bvec[i] = ste;         /* and insert the symbol at */
  165.   }                             /* the head of the bucket list */
  166.   for (i = size; --i >= 0; )    /* sort bucket lists according to */
  167.     tab->bvec[i] = _sort(tab->bvec[i]);   /* the visibility level */
  168. }  /* _reorg() */
  169. /*----------------------------------------------------------------------
  170.   Symbol Table Functions
  171. ----------------------------------------------------------------------*/
  172. SYMTAB* st_create (int init, int max, HASHFN hash, SYMFN delfn)
  173. {                               /* --- create a symbol table */
  174.   SYMTAB *tab;                  /* created symbol table */
  175.   if (init <= 0) init = DFLT_INIT;  /* check and adapt initial */
  176.   if (max  <= 0) max  = DFLT_MAX;   /* and maximal vector size */
  177.   tab = (SYMTAB*)malloc(sizeof(SYMTAB));
  178.   if (!tab) return NULL;        /* allocate symbol table body */
  179.   tab->bvec = (STE**)calloc(init, sizeof(STE*));
  180.   if (!tab->bvec) { free(tab); return NULL; }
  181.   tab->level = tab->cnt = 0;    /* allocate bucket vector */
  182.   tab->size  = init;            /* and initialize fields */
  183.   tab->max   = max;             /* of symbol table body */
  184.   tab->hash  = (hash) ? hash : _hdflt;
  185.   tab->delfn = delfn;
  186.   tab->vsz   = INT_MAX;
  187.   tab->ids   = NULL;
  188.   return tab;                   /* return created symbol table */
  189. }  /* st_create() */
  190. /*--------------------------------------------------------------------*/
  191. void st_delete (SYMTAB *tab)
  192. {                               /* --- delete a symbol table */
  193.   assert(tab && tab->bvec);     /* check argument */
  194.   _delsym(tab);                 /* delete all symbols, */
  195.   free(tab->bvec);              /* the bucket vector, */
  196.   if (tab->ids) free(tab->ids); /* the identifier vector, */
  197.   free(tab);                    /* and the symbol table body */
  198. }  /* st_delete() */
  199. /*--------------------------------------------------------------------*/
  200. void* st_insert (SYMTAB *tab, const char *name, int type,
  201.                  unsigned size)
  202. {                               /* --- insert a symbol */
  203.   unsigned h;                   /* hash value */
  204.   int i;                        /* index of hash bucket */
  205.   STE *ste;                     /* to traverse bucket list */
  206.   STE *nel;                     /* new symbol table element */
  207.   assert(tab && name            /* check the function arguments */
  208.       && ((size >= sizeof(int)) || (tab->vsz == INT_MAX)));
  209.   if ((tab->cnt /4 > tab->size) /* if buckets are rather full and */
  210.   &&  (tab->size   < tab->max)) /* table does not have maximal size, */
  211.     _reorg(tab);                /* reorganize the hash table */
  212.   h   = tab->hash(name, type);  /* compute the hash value and */
  213.   i   = h % tab->size;          /* the index of the hash bucket */
  214.   ste = tab->bvec[i];           /* get first element in bucket */
  215.   while (ste) {                 /* traverse the bucket list */
  216.     if ((type == ste->type)     /* if symbol found */
  217.     &&  (strcmp(name, ste->name) == 0))
  218.       break;                    /* abort the loop */
  219.     ste = ste->succ;            /* otherwise get the successor */
  220.   }                             /* element in the hash bucket */
  221.   if (ste                       /* if symbol found on current level */
  222.   && (ste->level == tab->level))
  223.     return EXISTS;              /* return 'symbol exists' */
  224.   #ifdef NIMAPFN                /* if name/identifier map management */
  225.   if (tab->cnt >= tab->vsz) {   /* if the identifier vector is full */
  226.     int vsz, **tmp;             /* (new) id vector and its size */
  227.     vsz = tab->vsz +((tab->vsz > BLKSIZE) ? tab->vsz >> 1 : BLKSIZE);
  228.     tmp = (int**)realloc(tab->ids, vsz *sizeof(int*));
  229.     if (!tmp) return NULL;      /* resize the identifier vector and */
  230.     tab->ids = tmp; tab->vsz = vsz;  /* set new vector and its size */
  231.   }                             /* (no resizing for symbol tables */
  232.   #endif                        /* since then tab->vsz = MAX_INT) */
  233.   nel = (STE*)malloc(sizeof(STE) +size +strlen(name) +1);
  234.   if (!nel) return NULL;        /* allocate memory for new symbol */
  235.   nel->name    = (char*)(nel+1) +size;         /* and organize it */
  236.   strcpy(nel->name, name);      /* note the symbol name, */
  237.   nel->type    = type;          /* the symbol type, and the */
  238.   nel->level   = tab->level;    /* current visibility level */
  239.   nel->succ    = tab->bvec[i];  /* insert new symbol at the head */
  240.   tab->bvec[i] = nel++;         /* of the bucket list */
  241.   #ifdef NIMAPFN                /* if name/identifier maps are */
  242.   if (tab->ids) {               /* supported and this is such a map */
  243.     tab->ids[tab->cnt] = (int*)nel;
  244.     *(int*)nel = tab->cnt;      /* store the new symbol */
  245.   }                             /* in the identifier vector */
  246.   #endif                        /* and set the symbol identifier */
  247.   tab->cnt++;                   /* increment the symbol counter */
  248.   return nel;                   /* return pointer to data field */
  249. }  /* st_insert() */
  250. /*--------------------------------------------------------------------*/
  251. int st_remove (SYMTAB *tab, const char *name, int type)
  252. {                               /* --- remove a symbol/all symbols */
  253.   int i;                        /* index of hash bucket */
  254.   STE **p, *ste;                /* to traverse bucket list */
  255.   assert(tab);                  /* check for a valid symbol table */
  256.   /* --- remove all symbols --- */
  257.   if (!name) {                  /* if no symbol name given */
  258.     _delsym(tab);               /* delete all symbols */
  259.     tab->cnt = tab->level = 0;  /* reset visibility level */
  260.     return 0;                   /* and symbol counter */
  261.   }                             /* and return 'ok' */
  262.   /* --- remove one symbol --- */
  263.   i = tab->hash(name, type) % tab->size;
  264.   p = tab->bvec +i;             /* compute index of hash bucket */
  265.   while (*p) {                  /* and traverse bucket list */
  266.     if (((*p)->type == type)    /* if symbol found */
  267.     &&  (strcmp(name, (*p)->name) == 0))
  268.       break;                    /* abort loop */
  269.     p = &(*p)->succ;            /* otherwise get successor */
  270.   }                             /* in hash bucket */
  271.   ste = *p;                     /* if the symbol does not exist, */
  272.   if (!ste) return -1;          /* abort the function */
  273.   *p = ste->succ;               /* remove symbol from hash bucket */
  274.   if (tab->delfn) tab->delfn(ste +1);   /* delete user data */
  275.   free(ste);                    /* and symbol table element */
  276.   tab->cnt--;                   /* decrement symbol counter */
  277.   return 0;                     /* return 'ok' */
  278. }  /* st_remove() */
  279. /*--------------------------------------------------------------------*/
  280. void* st_lookup (SYMTAB *tab, const char *name, int type)
  281. {                               /* --- look up a symbol */
  282.   int i;                        /* index of hash bucket */
  283.   STE *ste;                     /* to traverse bucket list */
  284.   assert(tab && name);          /* check arguments */
  285.   i   = tab->hash(name, type) % tab->size;
  286.   ste = tab->bvec[i];           /* compute index of hash bucket */
  287.   while (ste) {                 /* and traverse bucket list */
  288.     if ((ste->type == type)     /* if symbol found */
  289.     &&  (strcmp(name, ste->name) == 0))
  290.       return ste +1;            /* return pointer to assoc. data */
  291.     ste = ste->succ;            /* otherwise get successor */
  292.   }                             /* in hash bucket */
  293.   return NULL;                  /* return 'not found' */
  294. }  /* st_lookup() */
  295. /*--------------------------------------------------------------------*/
  296. void st_endblk (SYMTAB *tab)
  297. {                               /* --- remove one visibility level */
  298.   int i;                        /* loop variable */
  299.   STE *ste, *tmp;               /* to traverse bucket lists */
  300.   assert(tab);                  /* check for a valid symbol table */
  301.   if (tab->level <= 0) return;  /* if on level 0, abort */
  302.   for (i = tab->size; --i >= 0; ) {  /* traverse bucket vector */
  303.     ste = tab->bvec[i];         /* get next bucket list */
  304.     while (ste                  /* and remove all symbols */
  305.     &&    (ste->level >= tab->level)) {  /* of higher level */
  306.       tmp = ste;                /* note symbol and */
  307.       ste = ste->succ;          /* get successor */
  308.       if (tab->delfn) tab->delfn(tmp +1);
  309.       free(tmp);                /* delete user data and */
  310.       tab->cnt--;               /* symbol table element */
  311.     }                           /* and decrement symbol counter */
  312.     tab->bvec[i] = ste;         /* set new start of bucket list */
  313.   }
  314.   tab->level--;                 /* go up one level */
  315. }  /* st_endblk() */
  316. /*--------------------------------------------------------------------*/
  317. #ifndef NDEBUG
  318. void st_stats (const SYMTAB *tab)
  319. {                               /* --- compute and print statistics */
  320.   const STE *ste;               /* to traverse bucket lists */
  321.   int i;                        /* loop variable */
  322.   int used;                     /* number of used hash buckets */
  323.   int len;                      /* length of current bucket list */
  324.   int min, max;                 /* min. and max. bucket list length */
  325.   int cnts[10];                 /* counter for bucket list lengths */
  326.   assert(tab);                  /* check for a valid symbol table */
  327.   min = INT_MAX; max = used = 0;/* initialize variables */
  328.   for (i = 10; --i >= 0; ) cnts[i] = 0;
  329.   for (i = tab->size; --i >= 0; ) { /* traverse bucket vector */
  330.     len = 0;                    /* determine bucket list length */
  331.     for (ste = tab->bvec[i]; ste; ste = ste->succ) len++;
  332.     if (len > 0) used++;        /* count used hash buckets */
  333.     if (len < min) min = len;   /* determine minimal and */
  334.     if (len > max) max = len;   /* maximal list length */
  335.     cnts[(len >= 9) ? 9 : len]++;
  336.   }                             /* count list length */
  337.   printf("number of symbols     : %dn", tab->cnt);
  338.   printf("number of hash buckets: %dn", tab->size);
  339.   printf("used hash buckets     : %dn", used);
  340.   printf("minimal list length   : %dn", min);
  341.   printf("maximal list length   : %dn", max);
  342.   printf("average list length   : %gn", (double)tab->cnt/tab->size);
  343.   printf("ditto, of used buckets: %gn", (double)tab->cnt/used);
  344.   printf("length distribution   :n");
  345.   for (i = 0; i < 9; i++) printf("%3d ", i);
  346.   printf(" >8n");
  347.   for (i = 0; i < 9; i++) printf("%3d ", cnts[i]);
  348.   printf("%3dn", cnts[9]);
  349. }  /* st_stats() */
  350. #endif
  351. /*----------------------------------------------------------------------
  352.   Name/Identifier Map Functions
  353. ----------------------------------------------------------------------*/
  354. #ifdef NIMAPFN
  355. NIMAP* nim_create (int init, int max, HASHFN hash, SYMFN delfn)
  356. {                               /* --- create a name/identifier map */
  357.   NIMAP *nim;                   /* created name/identifier map */
  358.   nim = st_create(init, max, hash, delfn);
  359.   if (!nim) return NULL;        /* create a name/identifier map */
  360.   nim->vsz = 0;                 /* and clear the id. vector size */
  361.   return nim;                   /* return created name/id map */
  362. }  /* nim_create() */
  363. /*--------------------------------------------------------------------*/
  364. void nim_sort (NIMAP *nim, SYMCMPFN cmpfn, void *data,
  365.                int *map, int dir)
  366. {                               /* --- sort name/identifier map */
  367.   int i;                        /* loop variable */
  368.   int **p;                      /* to traverse the value vector */
  369.   assert(nim && cmpfn);         /* check the function arguments */
  370.   v_sort(nim->ids, nim->cnt, cmpfn, data);
  371.   if (!map) {                   /* if no conversion map is requested */
  372.     for (p = nim->ids +(i = nim->cnt); --i >= 0; )
  373.       **--p = i; }              /* just set new identifiers */
  374.   else {                        /* if a conversion map is requested, */
  375.     p = nim->ids +(i = nim->cnt);      /* traverse the sorted vector */
  376.     if (dir < 0)                /* if backward map (i.e. new -> old) */
  377.       while (--i >= 0) { map[i] = **--p; **p = i; }
  378.     else                        /* if forward  map (i.e. old -> new) */
  379.       while (--i >= 0) { map[**--p] = i; **p = i; }
  380.   }                             /* (build conversion map) */
  381. }  /* nim_sort() */
  382. /*--------------------------------------------------------------------*/
  383. void nim_trunc (NIMAP *nim, int n)
  384. {                               /* --- truncate name/identifier map */
  385.   int *id;                      /* to access the identifiers */
  386.   while (nim->cnt > n) {        /* while to remove mappings */
  387.     id = nim->ids[nim->cnt -1]; /* get the identifier object */
  388.     st_remove(nim, st_name(id), 0);
  389.   }                             /* remove the symbol table element */
  390. }  /* nim_trunc() */
  391. #endif