/* * Symbol Table Management * by Tom Epperly * Version: $Revision: 1.10 $ * Version control file: $RCSfile: symtab.c,v $ * Date last modified: $Date: 1998/03/17 12:36:52 $ * Last modified by: $Author: ballan $ * * This file is part of the Ascend Language Interpreter. * * Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly * * The Ascend Language Interpreter is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * The Ascend Language Interpreter is distributed in hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "symtab.h" #include /* * For various reasons which are still unclear to me, it is best to chose * a symbol table size which is a prime number. */ #define SYMTABSIZE 1021 struct StringSpaceRec { struct StringSpaceRec *next; unsigned long used; char data[MAXIMUM_STRING_LENGTH]; }; struct symbol_entry { symchar *entry; /* pointer to char*. entry - (sizeof(int))bytes is the * address of the length of the string. */ struct symbol_entry *next; }; /*********************************************************************\ Global Variables \*********************************************************************/ static struct StringSpaceRec *g_string_space=NULL; struct symbol_entry *g_symbol_table[SYMTABSIZE]; static unsigned long g_symbol_size = 0; static unsigned long g_symbol_collisions = 0; static struct symbol_entry *g_big_strings = NULL; /* linked list for oversize*/ static int g_big_strings_cnt = 0; /* linked list for oversize*/ /*********************************************************************\ String Space Management. Support routines for the symbol table. \*********************************************************************/ /*********************************************************************\ Makes space for oversized strings. The extra item overhead is cheap enough. \*********************************************************************/ static symchar *AddBigString(CONST char *str) { struct symbol_entry *item; char *sptr; int *lenptr; int slen; item = ASC_NEW(struct symbol_entry); item->next = g_big_strings; g_big_strings = item; slen = strlen(str); lenptr = (int *)ascmalloc(sizeof(int)+slen+1); lenptr[0] = slen; sptr = (char *)(&(lenptr[1])); strcpy(sptr,str); item->entry = (symchar *)sptr; g_big_strings_cnt++; return item->entry; } /* clears big strings, leaving the global NULL */ void DestroyBigStrings(void) { struct symbol_entry *item; item = g_big_strings; while (item != NULL) { g_big_strings = item->next; ascfree((void *)(((char *)item->entry)-(char *)sizeof(int))); ascfree(item); item = g_big_strings; } g_big_strings_cnt = 0; } /*********************************************************************\ const char *CopyString(str) const char *str; Make a copy of "str" in the string space. If string is too large, makes free copy rather than one stuffed in string space. \*********************************************************************/ static symchar *CopyString(CONST char *str,int userlen) { register unsigned long length; register struct StringSpaceRec *ptr; register char *result; int *lenptr; assert(userlen == (int)strlen(str)); length = (unsigned long)userlen+1; if (length > MAXIMUM_STRING_LENGTH) { return AddBigString(str); } ptr = g_string_space; if (ptr != NULL){ while ((ptr != NULL) && ((length+ptr->used+sizeof(int)) >= MAXIMUM_STRING_LENGTH)) { ptr = ptr->next; } if (ptr != NULL){ /* ptr must sit next symchar on a word boundary. */ assert((ptr->used & (sizeof(int)-1)) == 0); lenptr = (int *)&(ptr->data[ptr->used]); lenptr[0] = userlen; result = (char *)(&lenptr[1]); strcpy(result,str); ptr->used += (length+sizeof(int)); while((ptr->used & (unsigned long)(sizeof(int)-1)) != 0 && ptr->used < MAXIMUM_STRING_LENGTH) { /* pad string to next word boundary after nul with 0xFF */ ptr->data[ptr->used] = (char)UCHAR_MAX; (ptr->used)++; } return (symchar *)result; } ptr = g_string_space; } if ((g_string_space = ASC_NEW(struct StringSpaceRec))==NULL){ ASC_PANIC("Unable to allocate string space.\n"); } g_string_space->next = ptr; g_string_space->used = length + sizeof(int); strcpy((g_string_space->data + sizeof(int)),str); ((int *)g_string_space->data)[0] = userlen; while(((g_string_space->used) & (sizeof(int)-1)) != 0 && g_string_space->used < MAXIMUM_STRING_LENGTH) { /* pad string to next word boundary after nul with 0xFF */ g_string_space->data[g_string_space->used] = (char)UCHAR_MAX; (g_string_space->used)++; } return (symchar *)(g_string_space->data+sizeof(int)); } void DestroyStringSpace(void) { register struct StringSpaceRec *ptr,*next; ptr = g_string_space; while (ptr != NULL){ next = ptr->next; #ifndef NDEBUG ascbzero((char *)ptr,(int)sizeof(struct StringSpaceRec)); #endif ascfree((char *)ptr); ptr = next; } g_string_space = NULL; DestroyBigStrings(); } static void StringSpaceReport(FILE *fp) { register unsigned long num_blocks=0,used_memory=0; register struct StringSpaceRec *ptr; ptr = g_string_space; while(ptr != NULL){ num_blocks++; used_memory += ptr->used; ptr = ptr->next; } FPRINTF(fp,"Oversized string : %d\n",g_big_strings_cnt); FPRINTF(fp,"Number of blocks : %lu\n",num_blocks); FPRINTF(fp,"Total Memory use : %lu\n", num_blocks*sizeof(struct StringSpaceRec)); FPRINTF(fp,"String memory use: %lu\n",num_blocks*MAXIMUM_STRING_LENGTH); FPRINTF(fp,"Actual usage : %lu\n",used_memory); FPRINTF(fp,"Fraction filled : %f\n",(double)used_memory/ ((double)num_blocks*(double)sizeof(struct StringSpaceRec))); } /*********************************************************************\ Real Symbol Table Routines \*********************************************************************/ void InitSymbolTable(void) { register int c; for(c=0;cnext = NULL; item->entry = CopyString(c,l); g_symbol_table[hv] = item; g_symbol_size++; } else { item = g_symbol_table[hv]; if ((cmp = strcmp(SCP(item->entry),c))>0) { item = ASC_NEW(struct symbol_entry); item->next = g_symbol_table[hv]; item->entry = CopyString(c,l); g_symbol_table[hv] = item; g_symbol_size++; g_symbol_collisions++; } else if (cmp<0) { for(next = item->next; next != NULL; item = next, next = next->next) { if ((cmp=strcmp(SCP(next->entry),c))>=0) { if (cmp==0) return next->entry; break; } } item->next = ASC_NEW(struct symbol_entry); item = item->next; item->next = next; item->entry = CopyString(c,l); g_symbol_size++; g_symbol_collisions++; } } return item->entry; } symchar *AddSymbol(CONST char *c) { return AddSymbolL(c,strlen(c)); } /* * this function tests whether an alleged symchar is in the table. */ symchar *AscFindSymbol(symchar *c) { register unsigned long hv; register struct symbol_entry *next; hv = SymHashFunction(c); for (next = g_symbol_table[hv]; next != NULL; next = next->next) { if (next->entry == c) { return c; } } return NULL; } static void PrintTabF(int noisy,FILE *fp) { unsigned long c,counts[SYMTABSIZE]; struct symbol_entry *item; for(c=0; c < SYMTABSIZE; counts[c++]=0); FPRINTF(fp,"Symbol table contains %lu entries with %lu collisions.\n", g_symbol_size,g_symbol_collisions); if (noisy) { for(c = 0; c < SYMTABSIZE; c++) { for(item=g_symbol_table[c]; item!=NULL; item=item->next) { FPRINTF(fp,"%lu %s (%d)\n",c,SCP(item->entry),SCLEN(item->entry)); counts[c]++; } } if ((item=g_big_strings) != NULL) { FPRINTF(fp,"Oversized string information\n"); while(item !=NULL) { FPRINTF(fp,"%d %s (%d)\n",1,SCP(item->entry),SCLEN(item->entry)); item = item->next; } } FPRINTF(fp,"Distribution information\n"); for(c=0;cnext; ascfree((char *)item); } } }