Improve local variable scoping.
Until now we faked local variables -- they only worked correctly if
there was no overlap between local variables and global variables.
Use a symbol table stack instead of a string list.
Fix bug with looking up undefined symbols.
diff --git a/libacc/acc.cpp b/libacc/acc.cpp
index fb4f4f6..b07a1d8 100644
--- a/libacc/acc.cpp
+++ b/libacc/acc.cpp
@@ -1116,9 +1116,12 @@
mSize = 0;
}
- String(char* item, int len, bool adopt) {
+ String(const char* item, int len, bool adopt) {
+ if (len < 0) {
+ len = strlen(item);
+ }
if (adopt) {
- mpBase = item;
+ mpBase = (char*) item;
mUsed = len;
mSize = len + 1;
} else {
@@ -1129,16 +1132,30 @@
}
}
+ String(const String& other) {
+ mpBase = 0;
+ mUsed = 0;
+ mSize = 0;
+ appendBytes(other.getUnwrapped(), other.len());
+ }
+
~String() {
if (mpBase) {
free(mpBase);
}
}
- inline char* getUnwrapped() {
+ inline char* getUnwrapped() const {
return mpBase;
}
+ void clear() {
+ mUsed = 0;
+ if (mSize > 0) {
+ mpBase[0] = 0;
+ }
+ }
+
void appendCStr(const char* s) {
appendBytes(s, strlen(s));
}
@@ -1173,7 +1190,7 @@
free(temp);
}
- inline size_t len() {
+ inline size_t len() const {
return mUsed;
}
@@ -1214,8 +1231,12 @@
template<class V> class StringTable {
public:
+ StringTable() {
+ init(10);
+ }
+
StringTable(size_t initialCapacity) {
- mpMap = hashmapCreate(initialCapacity, hashFn, equalsFn);
+ init(initialCapacity);
}
~StringTable() {
@@ -1252,6 +1273,11 @@
}
protected:
+
+ void init(size_t initialCapacity) {
+ mpMap = hashmapCreate(initialCapacity, hashFn, equalsFn);
+ }
+
static int hashFn(void* pKey) {
String* pString = (String*) pKey;
return hashmapHash(pString->getUnwrapped(), pString->len());
@@ -1300,8 +1326,8 @@
hashmapFree(mpMap);
}
- int get(char* key) {
- return (int) hashmapGet(mpMap, key);
+ int get(String* key) {
+ return (int) hashmapGet(mpMap, key->getUnwrapped());
}
const char* lookupKeyFor(int value) {
@@ -1359,8 +1385,8 @@
}
E get(int i) {
- if (i < 0 || i > mUsed) {
- error("internal error: Index out of range");
+ if (i < 0 || i > (int) mUsed) {
+ // error("internal error: Index out of range");
return E();
}
return mpBase[i];
@@ -1374,7 +1400,7 @@
if (mUsed > 0) {
mUsed -= 1;
} else {
- error("internal error: Popped empty stack.");
+ // error("internal error: Popped empty stack.");
}
}
@@ -1413,10 +1439,101 @@
};
struct VariableInfo {
- void* pA;
- void* pB;
+ VariableInfo() {
+ pAddress = 0;
+ pForward = 0;
+ }
+ void* pAddress;
+ void* pForward; // For a forward direction, linked list of data to fix up
};
+ typedef StringTable<VariableInfo> SymbolTable;
+
+ class SymbolStack {
+ public:
+ SymbolStack() {
+ mLevel = 0;
+ addEntry();
+ }
+
+ void pushLevel() {
+ mLevel++;
+ }
+
+ void popLevel() {
+ mLevel--;
+ Entry e = mStack.get(mStack.len()-1);
+ if (mLevel < e.level) {
+ mStack.pop();
+ delete e.pTable;
+ }
+ }
+
+ VariableInfo* get(String* pName) {
+ int len = mStack.len();
+ VariableInfo* v = NULL;
+ int level = -1;
+ for (int i = len - 1; i >= 0; i--) {
+ Entry e = mStack.get(i);
+ v = e.pTable->get(pName);
+ if (v) {
+ level = e.level;
+ break;
+ }
+ }
+#if 0
+ fprintf(stderr, "Lookup %s %08x level %d\n", pName->getUnwrapped(), v, level);
+ if (v) {
+ fprintf(stderr, " %08x %08x\n", v->pAddress, v->pForward);
+ }
+#endif
+ return v;
+ }
+
+ VariableInfo* addLocal(String* pName) {
+ int len = mStack.len();
+ if (mStack.get(len-1).level != mLevel) {
+ addEntry();
+ len++;
+ }
+ return addImp(len-1, pName);
+ }
+
+ VariableInfo* addGlobal(String* pName) {
+ return addImp(0, pName);
+ }
+
+ private:
+ VariableInfo* addImp(int entryIndex, String* pName) {
+ Entry e = mStack.get(entryIndex);
+ SymbolTable* pTable = e.pTable;
+ VariableInfo* v = new VariableInfo();
+ delete pTable->put(pName, v);
+#if 0
+ fprintf(stderr, "Add \"%s\" %08x level %d\n", pName->getUnwrapped(), v, e.level);
+#endif
+ return v;
+ }
+
+ void addEntry() {
+ Entry e;
+ e.level = mLevel;
+ e.pTable = new SymbolTable();
+ mStack.push(e);
+ }
+
+ struct Entry {
+ Entry() {
+ level = 0;
+ pTable = NULL;
+ }
+ int level;
+ SymbolTable* pTable;
+ };
+
+ int mLevel;
+ Array<Entry> mStack;
+ };
int ch; // Current input character, or EOF
intptr_t tok; // token
@@ -1425,15 +1542,12 @@
intptr_t rsym; // return symbol
intptr_t loc; // local variable index
char* glo; // global variable index
- char* sym_stk;
- char* dstk; // Define stack
+ String mTokenString;
char* dptr; // Macro state: Points to macro text during macro playback.
int dch; // Macro state: Saves old value of ch during a macro playback.
- char* last_id;
char* pGlobalBase;
- VariableInfo* pVarsBase; // Value of variables
KeywordTable mKeywords;
-
+ SymbolStack mSymbolTable;
InputStream* file;
CodeBuf codeBuf;
@@ -1449,6 +1563,11 @@
static const int ALLOC_SIZE = 99999;
+ static const int TOK_DUMMY = 1;
+ static const int TOK_NUM = 2;
+
+ // 3..255 are character and/or operators
+
// Keywords start at 0x100 and increase by 1
static const int TOK_KEYWORD = 0x100;
static const int TOK_INT = TOK_KEYWORD + 0;
@@ -1463,11 +1582,11 @@
static const int TOK_PRAGMA = TOK_KEYWORD + 9;
static const int TOK_DEFINE = TOK_KEYWORD + 10;
- // Symbols start at 0x200
- static const int TOK_SYMBOL = 0x200;
+ static const int TOK_UNDEFINED_SYMBOL = 0x200;
- static const int TOK_DUMMY = 1;
- static const int TOK_NUM = 2;
+ // Symbols start at 0x300, but are really pointers to VariableInfo structs.
+ static const int TOK_SYMBOL = 0x300;
+
static const int LOCAL = 0x200;
@@ -1509,11 +1628,7 @@
static const char operatorLevel[];
void pdef(int t) {
- if (dstk - sym_stk >= ALLOC_SIZE) {
- error("Symbol table exhausted");
- return;
- }
- *dstk++ = t;
+ mTokenString.append(t);
}
void inp() {
@@ -1555,7 +1670,8 @@
} else if (tok == TOK_PRAGMA) {
doPragma();
} else {
- error("Unsupported preprocessor directive \"%s\"", last_id);
+ error("Unsupported preprocessor directive \"%s\"",
+ mTokenString.getUnwrapped());
}
}
inp();
@@ -1564,43 +1680,34 @@
tok = ch;
/* encode identifiers & numbers */
if (isid()) {
- pdef(TAG_TOK);
- last_id = dstk;
+ mTokenString.clear();
while (isid()) {
pdef(ch);
inp();
}
if (isdigit(tok)) {
- tokc = strtol(last_id, 0, 0);
+ tokc = strtol(mTokenString.getUnwrapped(), 0, 0);
tok = TOK_NUM;
} else {
- if (dstk - sym_stk + 1 > ALLOC_SIZE) {
- error("symbol stack overflow");
- }
- FakeString token(last_id, dstk-last_id);
// Is this a macro?
- String* pValue = mMacros.get(&token);
+ String* pValue = mMacros.get(&mTokenString);
if (pValue) {
// Yes, it is a macro
- dstk = last_id-1;
dptr = pValue->getUnwrapped();
dch = ch;
inp();
next();
} else {
// Is this a keyword?
- * dstk = 0;
- int kwtok = mKeywords.get(last_id);
+ int kwtok = mKeywords.get(&mTokenString);
if (kwtok) {
tok = kwtok;
// fprintf(stderr, "tok= keyword %s %x\n", last_id, tok);
} else {
- * dstk = TAG_TOK; /* no need to mark end of string (we
- suppose data is initialized to zero by calloc) */
- tok = (intptr_t) (strstr(sym_stk, (last_id - 1))
- - sym_stk);
- * dstk = 0; /* mark real end of ident for dlsym() */
- tok = (intptr_t) & (pVarsBase[tok]);
+ tok = (intptr_t) mSymbolTable.get(&mTokenString);
+ if (!tok) {
+ tok = TOK_UNDEFINED_SYMBOL;
+ }
// fprintf(stderr, "tok= symbol %s %x\n", last_id, tok);
}
}
@@ -1831,11 +1938,21 @@
} else if (t == '&') {
pGen->leaR0(*(int *) tok);
next();
+ } else if (t == EOF ) {
+ error("Unexpected EOF.");
+ } else if (t < TOK_UNDEFINED_SYMBOL) {
+ error("Unexpected symbol or keyword");
} else {
+ if (t == TOK_UNDEFINED_SYMBOL) {
+ t = (intptr_t) mSymbolTable.addGlobal(
+ new String(mTokenString));
+ }
+
n = *(int *) t;
/* forward reference: try dlsym */
if (!n) {
- n = (intptr_t) dlsym(RTLD_DEFAULT, last_id);
+ n = (intptr_t) dlsym(RTLD_DEFAULT,
+ mTokenString.getUnwrapped());
}
if ((tok == '=') & l) {
/* assignment */
@@ -1979,12 +2096,14 @@
pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */
pGen->gsym(a);
} else if (tok == '{') {
+ mSymbolTable.pushLevel();
next();
/* declarations */
localDeclarations();
- while (tok != '}')
+ while (tok != '}' && tok != EOF)
block(l);
- next();
+ skip('}');
+ mSymbolTable.popLevel();
} else {
if (tok == TOK_RETURN) {
next();
@@ -2064,6 +2183,20 @@
}
}
+ void defineGlobalSymbol() {
+ if (tok == TOK_UNDEFINED_SYMBOL) {
+ // TODO: don't allow multiple definitions at same level.
+ tok = (intptr_t) mSymbolTable.addGlobal(
+ new String(mTokenString));
+ }
+ }
+
+ void defineLocalSymbol() {
+ // TODO: don't allow multiple definitions at same level.
+ tok = (intptr_t) mSymbolTable.addLocal(
+ new String(mTokenString));
+ }
+
void localDeclarations() {
intptr_t a;
Type base;
@@ -2071,7 +2204,7 @@
while (acceptType(base)) {
while (tok != ';') {
Type t = acceptPointerDeclaration(t);
- checkSymbol();
+ defineLocalSymbol();
loc = loc + 4;
*(int *) tok = -loc;
@@ -2088,37 +2221,38 @@
Type base;
expectType(base);
Type t = acceptPointerDeclaration(t);
- checkSymbol();
- int name = tok;
+ defineGlobalSymbol();
+ VariableInfo* name = (VariableInfo*) tok;
next();
if (tok == ',' || tok == ';') {
// it's a variable declaration
for(;;) {
- *(int* *) name = (int*) allocGlobalSpace(4);
+ name->pAddress = (int*) allocGlobalSpace(4);
if (tok != ',') {
break;
}
- next();
+ skip(',');
t = acceptPointerDeclaration(t);
- checkSymbol();
- name = tok;
+ defineGlobalSymbol();
+ name = (VariableInfo*) tok;
next();
}
skip(';');
} else {
/* patch forward references (XXX: does not work for function
pointers) */
- pGen->gsym(*(int *) (name + 4));
+ pGen->gsym((int) name->pForward);
/* put function address */
- *(int *) name = codeBuf.getPC();
+ name->pAddress = (void*) codeBuf.getPC();
skip('(');
+ mSymbolTable.pushLevel();
intptr_t a = 8;
int argCount = 0;
- while (tok != ')') {
+ while (tok != ')' && tok != EOF) {
Type aType;
expectType(aType);
aType = acceptPointerDeclaration(aType);
- checkSymbol();
+ defineLocalSymbol();
/* read param name and compute offset */
*(int *) tok = a;
a = a + 4;
@@ -2127,12 +2261,13 @@
next();
argCount++;
}
- skip(')'); /* skip ')' */
+ skip(')');
rsym = loc = 0;
a = pGen->functionEntry(argCount);
block(0);
pGen->gsym(rsym);
pGen->functionExit(argCount, a, loc);
+ mSymbolTable.popLevel();
}
}
}
@@ -2148,18 +2283,10 @@
}
void cleanup() {
- if (sym_stk != 0) {
- free(sym_stk);
- sym_stk = 0;
- }
if (pGlobalBase != 0) {
free(pGlobalBase);
pGlobalBase = 0;
}
- if (pVarsBase != 0) {
- free(pVarsBase);
- pVarsBase = 0;
- }
if (pGen) {
delete pGen;
pGen = 0;
@@ -2175,18 +2302,13 @@
tokc = 0;
tokl = 0;
ch = 0;
- pVarsBase = 0;
rsym = 0;
loc = 0;
glo = 0;
- sym_stk = 0;
- dstk = 0;
dptr = 0;
dch = 0;
- last_id = 0;
file = 0;
pGlobalBase = 0;
- pVarsBase = 0;
pGen = 0;
mPragmaStringCount = 0;
}
@@ -2253,11 +2375,8 @@
}
pGen->init(&codeBuf);
file = new TextInputStream(text, textLength);
- sym_stk = (char*) calloc(1, ALLOC_SIZE);
- dstk = sym_stk;
pGlobalBase = (char*) calloc(1, ALLOC_SIZE);
glo = pGlobalBase;
- pVarsBase = (VariableInfo*) calloc(1, ALLOC_SIZE);
inp();
next();
globalDeclarations();
@@ -2283,26 +2402,10 @@
* If found, return its value.
*/
void* lookup(const char* name) {
- if (!sym_stk) {
- return NULL;
- }
- size_t nameLen = strlen(name);
- char* pSym = sym_stk;
- char c;
- for(;;) {
- c = *pSym++;
- if (c == 0) {
- break;
- }
- if (c == TAG_TOK) {
- if (memcmp(pSym, name, nameLen) == 0
- && pSym[nameLen] == TAG_TOK) {
- int tok = pSym - 1 - sym_stk;
- tok = tok * sizeof(VariableInfo);
- tok = (intptr_t) ((intptr_t) pVarsBase + tok);
- return * (void**) tok;
- }
- }
+ String string(name, -1, false);
+ VariableInfo* pVariableInfo = mSymbolTable.get(&string);
+ if (pVariableInfo) {
+ return pVariableInfo->pAddress;
}
return NULL;
}