/*************************************************************************** table.c Symbol tables management (c) 2000-2007 Benoit Minisini This program 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 1, or (at your option) any later version. This program is distributed in the 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, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************/ #define __TABLE_C #include #include #include #include #include "gb_common.h" #include "gb_error.h" #include "gb_alloc.h" #include "gb_limit.h" #include "gb_table.h" #define SYM(table, ind) (TABLE_get_symbol(table, ind)) #define SSYM(_symbol, _pos, _size) ((SYMBOL *)((char *)_symbol + _pos * _size)) static char _buffer[MAX_SYMBOL_LEN + 1]; PUBLIC int TABLE_compare(const char *s1, int len1, const char *s2, int len2) { int i; int len = (len1 < len2) ? len1 : len2; register char c1; register char c2; for (i = 0; i < len; i++) { c1 = s1[i]; c2 = s2[i]; if (c1 > c2) return 1; if (c1 < c2) return -1; } if (len1 < len2) return -1; else if (len1 > len2) return 1; else return 0; } PUBLIC int TABLE_compare_ignore_case(const char *s1, int len1, const char *s2, int len2) { unsigned int len = (len1 < len2) ? len1 : len2; unsigned int i; int result; for(i = 0;;i++) { result = toupper(s1[i]) - toupper(s2[i]); if (result) return result; // < 0 ? -1 : 1; if (--len == 0) break; } if (len1 < len2) return -1; else if (len1 > len2) return 1; else return 0; } PUBLIC int TABLE_compare_ignore_case_len(const char *s1, int len1, const char *s2, int len2) { int result; if (len1 < len2) return -1; else if (len1 > len2) return 1; while (len1) { result = tolower(*s1++) - tolower(*s2++); if (result) return result; // < 0 ? -1 : 1; --len1; } return 0; } static boolean search(void *symbol, int n_symbol, size_t size, int flag, const char *name, int len, int *index) { int pos, deb, fin; SYMBOL *sym; int slen, l; pos = 0; deb = 0; fin = n_symbol; //ARRAY_count(table->symbol); if (flag == TF_IGNORE_CASE) { for(;;) { if (deb >= fin) { *index = deb; return FALSE; } pos = (deb + fin) >> 1; //sym = SYM(table, SYM(table, pos)->sort); /*&table->symbol[table->symbol[pos].sort];*/ sym = SSYM(symbol, pos, size); sym = SSYM(symbol, sym->sort, size); slen = sym->len; if (len < slen) goto __T_LOWER; else if (len > slen) goto __T_GREATER; { const char *s1 = name; const char *s2 = sym->name; char result; l = len; for(;;) { result = tolower(*s1++) - tolower(*s2++); if (result < 0) goto __T_LOWER; else if (result > 0) goto __T_GREATER; if (--l == 0) break; } *index = pos; return TRUE; } __T_LOWER: fin = pos; continue; __T_GREATER: deb = pos + 1; continue; } } else { for(;;) { if (deb >= fin) { *index = deb; return FALSE; } pos = (deb + fin) >> 1; sym = SSYM(symbol, pos, size); sym = SSYM(symbol, sym->sort, size); slen = sym->len; if (len < slen) goto __B_LOWER; else if (len > slen) goto __B_GREATER; { const char *s1 = name; const char *s2 = sym->name; char result; l = len; for(;;) { result = *s1++ - *s2++; if (result < 0) goto __B_LOWER; else if (result > 0) goto __B_GREATER; if (--l == 0) break; } *index = pos; return TRUE; } __B_LOWER: fin = pos; continue; __B_GREATER: deb = pos + 1; continue; } } } PUBLIC boolean SYMBOL_find(void *symbol, int n_symbol, size_t s_symbol, int flag, const char *name, int len, const char *prefix, int *result) { int index; int len_prefix; if (prefix) { len_prefix = strlen(prefix); if ((len + len_prefix) > MAX_SYMBOL_LEN) ERROR_panic("SYMBOL_find: prefixed symbol too long"); strcpy(_buffer, prefix); strcpy(&_buffer[len_prefix], name); len += len_prefix; name = _buffer; } if (search(symbol, n_symbol, s_symbol, flag, name, len, &index)) { //*result = ((SYMBOL *)((char *)symbol + s_symbol * index))->sort; *result = SSYM(symbol, index, s_symbol)->sort; return TRUE; } else { *result = NO_SYMBOL; return FALSE; } } PUBLIC boolean SYMBOL_find_old(void *symbol, int n_symbol, size_t s_symbol, int flag, const char *name, int len, const char *prefix, int *result) { int pos, deb, fin; int cmp; int (*cmp_func)(const char *, int, const char *, int); SYMBOL *sym; int index; int len_prefix; cmp_func = ((flag == TF_IGNORE_CASE) ? TABLE_compare_ignore_case : TABLE_compare); pos = 0; deb = 0; fin = n_symbol; if (prefix) { len_prefix = strlen(prefix); if ((len + len_prefix) > MAX_SYMBOL_LEN) ERROR_panic("SYMBOL_find: prefixed symbol too long"); strcpy(_buffer, prefix); strcpy(&_buffer[len_prefix], name); len += len_prefix; name = _buffer; } for(;;) { if (deb >= fin) { *result = NO_SYMBOL; return FALSE; } pos = (deb + fin) >> 1; index = ((SYMBOL *)((char *)symbol + s_symbol * pos))->sort; sym = (SYMBOL *)((char *)symbol + s_symbol * index); cmp = (*cmp_func)(name, len, sym->name, sym->len); if (cmp == 0) { *result = index; return TRUE; } if (cmp < 0) fin = pos; else deb = pos + 1; } } PUBLIC const char *TABLE_get_symbol_name(TABLE *table, int index) { SYMBOL *sym; if ((index < 0) || (index >= ARRAY_count(table->symbol))) strcpy(_buffer, "?"); else { sym = SYM(table, index); memcpy(_buffer, sym->name, Min(MAX_SYMBOL_LEN, sym->len)); _buffer[sym->len] = 0; } return _buffer; } PUBLIC const char *TABLE_get_symbol_name_suffix(TABLE *table, int index, const char* suffix) { TABLE_get_symbol_name(table, index); strcat(_buffer, suffix); return _buffer; } PUBLIC void TABLE_create_static(TABLE *table, size_t size, TABLE_FLAG flag) { ARRAY_create_with_size(&table->symbol, Max(size, sizeof(SYMBOL)), 16); table->flag = flag; } PUBLIC void TABLE_create(TABLE **result, size_t size, TABLE_FLAG flag) { TABLE *table; ALLOC(&table, sizeof(TABLE), "TABLE_create"); TABLE_create_static(table, size, flag); *result = table; } PUBLIC void TABLE_create_from(TABLE **result, size_t size, const char *sym_list[], TABLE_FLAG flag) { TABLE *table; TABLE_create(&table, size, flag); while (*sym_list) { TABLE_add_symbol(table, *sym_list, strlen(*sym_list), NULL, NULL); sym_list++; } *result = table; } PUBLIC void TABLE_delete_static(TABLE *table) { ARRAY_delete(&table->symbol); } PUBLIC void TABLE_delete(TABLE **p_table) { if (*p_table) { TABLE_delete_static(*p_table); FREE(p_table, "TABLE_delete"); } } PUBLIC int TABLE_count(TABLE *table) { return ARRAY_count(table->symbol); } PUBLIC boolean TABLE_find_symbol(TABLE *table, const char *name, int len, SYMBOL **symbol, int *index) { int ind; boolean result; SYMBOL *tsym, *sym; int count; size_t size; tsym = table->symbol; count = ARRAY_count(tsym); size = ARRAY_size(tsym); result = search(tsym, count, size, table->flag, name, len, &ind); if (result) { sym = SSYM(tsym, ind, size); ind = sym->sort; if (index) *index = ind; if (symbol) { sym = SSYM(tsym, ind, size); *symbol = sym; } } return result; } PUBLIC void TABLE_add_new_symbol_without_sort(TABLE *table, const char *name, int len, int sort, SYMBOL **symbol, int *index) { SYMBOL *sym; int count; len = Min(len, MAX_SYMBOL_LEN); count = ARRAY_count(table->symbol); sym = (SYMBOL *)ARRAY_add_void(&table->symbol); sym->name = (char *)name; sym->len = len; sym->sort = sort; if (symbol) *symbol = sym; /*&table->symbol[ind];*/ if (index) *index = count; } PUBLIC boolean TABLE_add_symbol(TABLE *table, const char *name, int len, SYMBOL **symbol, int *index) { int ind; int i; boolean result; SYMBOL *sym; int count; SYMBOL *s1, *s2; size_t size; /*len = Min(len, MAX_SYMBOL_LEN);*/ len = Min(len, 65535); count = ARRAY_count(table->symbol); size = ARRAY_size(table->symbol); result = search(table->symbol, count, size, table->flag, name, len, &ind); if (!result) { sym = (SYMBOL *)ARRAY_add_void(&table->symbol); sym->name = (char *)name; sym->len = (ushort)len; /* printf("TABLE_add_symbol: %.*s %d %d\n", len, name, ((CLASS_SYMBOL *)sym)->global.type, ((CLASS_SYMBOL *)sym)->local.type); */ //s1 = (SYMBOL *)((char *)table->symbol + count * size); s1 = SSYM(table->symbol, count, size); s2 = (SYMBOL *)((char *)s1 - size); for (i = count; i > ind; i--) { s1->sort = s2->sort; s1 = s2; s2 = (SYMBOL *)((char *)s2 - size); } //SYM(table, ind)->sort = (ushort)count; s1->sort = (ushort)count; ind = count; } else ind = SYM(table, ind)->sort; /*table->symbol[ind].sort;*/ if (symbol) *symbol = SYM(table, ind); /*&table->symbol[ind];*/ if (index) *index = ind; return result; } PUBLIC void TABLE_print(TABLE *table, boolean sort) { int i; SYMBOL *sym; fprintf(stderr, "capacity %i\n", ARRAY_count(table->symbol)); /* for (i = 0; i < ARRAY_count(table->symbol); i++) { sym = SYM(table, i); printf("%*s (%li) ", (int)sym->len, sym->name, sym->sort); } printf("\n"); */ for (i = 0; i < ARRAY_count(table->symbol); i++) { if (sort) { sym = SYM(table, SYM(table, i)->sort); fprintf(stderr, "%.*s ", (int)sym->len, sym->name); } else { sym = SYM(table, i); fprintf(stderr, "%d %.*s ", (int)sym->sort, (int)sym->len, sym->name); } //if ((i > 0) && (!(i & 0xF))) // fprintf(stderr, "\n"); } fprintf(stderr, "\n\n"); } PUBLIC void TABLE_copy_symbol_with_prefix(TABLE *table, int ind_src, char prefix, SYMBOL **symbol, int *index) { SYMBOL *sym; char *ptr; sym = TABLE_get_symbol(table, ind_src); ptr = (char *)sym->name - 1; if (!isspace(*ptr)) ERROR_panic("Cannot add prefix to symbol"); *ptr = prefix; TABLE_add_symbol(table, ptr, sym->len + 1, symbol, index); } PUBLIC SYMBOL *TABLE_get_symbol_sort(TABLE *table, int index) { SYMBOL *sym = TABLE_get_symbol(table, index); return TABLE_get_symbol(table, sym->sort); }