147 lines
3.8 KiB
C
147 lines
3.8 KiB
C
// symtab.c -- DVX BASIC symbol table implementation
|
|
|
|
#include "symtab.h"
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
// ============================================================
|
|
// Case-insensitive name comparison
|
|
// ============================================================
|
|
|
|
static bool namesEqual(const char *a, const char *b) {
|
|
while (*a && *b) {
|
|
char ca = *a >= 'a' && *a <= 'z' ? *a - 32 : *a;
|
|
char cb = *b >= 'a' && *b <= 'z' ? *b - 32 : *b;
|
|
|
|
if (ca != cb) {
|
|
return false;
|
|
}
|
|
|
|
a++;
|
|
b++;
|
|
}
|
|
|
|
return *a == *b;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basSymTabAdd
|
|
// ============================================================
|
|
|
|
BasSymbolT *basSymTabAdd(BasSymTabT *tab, const char *name, BasSymKindE kind, uint8_t dataType) {
|
|
if (tab->count >= BAS_MAX_SYMBOLS) {
|
|
return NULL;
|
|
}
|
|
|
|
// Check for duplicate in current scope
|
|
BasScopeE scope = tab->inLocalScope ? SCOPE_LOCAL : SCOPE_GLOBAL;
|
|
|
|
for (int32_t i = 0; i < tab->count; i++) {
|
|
if (tab->symbols[i].scope == scope && namesEqual(tab->symbols[i].name, name)) {
|
|
return NULL; // duplicate
|
|
}
|
|
}
|
|
|
|
BasSymbolT *sym = &tab->symbols[tab->count++];
|
|
memset(sym, 0, sizeof(*sym));
|
|
strncpy(sym->name, name, BAS_MAX_SYMBOL_NAME - 1);
|
|
sym->name[BAS_MAX_SYMBOL_NAME - 1] = '\0';
|
|
sym->kind = kind;
|
|
sym->scope = scope;
|
|
sym->dataType = dataType;
|
|
sym->isDefined = true;
|
|
|
|
return sym;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basSymTabAllocSlot
|
|
// ============================================================
|
|
|
|
int32_t basSymTabAllocSlot(BasSymTabT *tab) {
|
|
if (tab->inLocalScope) {
|
|
return tab->nextLocalIdx++;
|
|
}
|
|
|
|
return tab->nextGlobalIdx++;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basSymTabEnterLocal
|
|
// ============================================================
|
|
|
|
void basSymTabEnterLocal(BasSymTabT *tab) {
|
|
tab->inLocalScope = true;
|
|
tab->nextLocalIdx = 0;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basSymTabFind
|
|
// ============================================================
|
|
|
|
BasSymbolT *basSymTabFind(BasSymTabT *tab, const char *name) {
|
|
// Search local scope first
|
|
if (tab->inLocalScope) {
|
|
for (int32_t i = tab->count - 1; i >= 0; i--) {
|
|
if (tab->symbols[i].scope == SCOPE_LOCAL && namesEqual(tab->symbols[i].name, name)) {
|
|
return &tab->symbols[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Search global scope
|
|
return basSymTabFindGlobal(tab, name);
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basSymTabFindGlobal
|
|
// ============================================================
|
|
|
|
BasSymbolT *basSymTabFindGlobal(BasSymTabT *tab, const char *name) {
|
|
for (int32_t i = 0; i < tab->count; i++) {
|
|
if (tab->symbols[i].scope == SCOPE_GLOBAL && namesEqual(tab->symbols[i].name, name)) {
|
|
return &tab->symbols[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basSymTabInit
|
|
// ============================================================
|
|
|
|
void basSymTabInit(BasSymTabT *tab) {
|
|
memset(tab, 0, sizeof(*tab));
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
// basSymTabLeaveLocal
|
|
// ============================================================
|
|
|
|
void basSymTabLeaveLocal(BasSymTabT *tab) {
|
|
// Remove all local symbols
|
|
int32_t newCount = 0;
|
|
|
|
for (int32_t i = 0; i < tab->count; i++) {
|
|
if (tab->symbols[i].scope != SCOPE_LOCAL) {
|
|
if (i != newCount) {
|
|
tab->symbols[newCount] = tab->symbols[i];
|
|
}
|
|
|
|
newCount++;
|
|
}
|
|
}
|
|
|
|
tab->count = newCount;
|
|
tab->inLocalScope = false;
|
|
tab->nextLocalIdx = 0;
|
|
}
|