#drinc:util.g
#toy.g
#externs.g

/*
 * symbol.d: routines for maintaining symbol tables.
 */

ulong SYMBOL_TABLE_SIZE = 1023;

ulong EntryCount;
[SYMBOL_TABLE_SIZE]SymbolEntry_t SymbolTable;

/*
 * symbolInit - initialize the symbol table.
 */

proc symbolInit()void:
    register *SymbolEntry_t se;
    register uint i;

    se := &SymbolTable[0];
    for i from 0 upto SYMBOL_TABLE_SIZE - 1 do
	se*.se_kind := sk_empty;
	se := se + sizeof(SymbolEntry_t);
    od;
    EntryCount := 0;
corp;

/*
 * symbolTerm - clean up the symbol table stuff.
 */

proc symbolTerm()void:
    register *SymbolEntry_t se;
    register uint i;

    se := &SymbolTable[0];
    for i from 0 upto SYMBOL_TABLE_SIZE - 1 do
	if se*.se_kind ~= sk_empty then
	    se*.se_kind := sk_empty;
	    memFree(se*.se_name, se*.se_length * sizeof(char));
	fi;
	se := se + sizeof(SymbolEntry_t);
    od;
corp;

/*
 * symbolPurge - purge all local symbols from the symbol table.
 */

proc symbolPurge()void:
    register *SymbolEntry_t se;
    register uint i;

    se := &SymbolTable[0];
    for i from 0 upto SYMBOL_TABLE_SIZE - 1 do
	if se*.se_kind = sk_parameter or se*.se_kind = sk_localVariable then
	    se*.se_kind := sk_empty;
	    memFree(se*.se_name, se*.se_length * sizeof(char));
	    EntryCount := EntryCount - 1;
	fi;
	se := se + sizeof(SymbolEntry_t);
    od;
corp;

/*
 * enter - enter/lookup a symbol in the table. If the symbol is not found,
 *	we enter it, but leave its entry type as sk_empty. When we enter
 *	it, we copy the string over.
 */

proc enter(register *char name; register ulong length)*SymbolEntry_t:
    register *SymbolEntry_t se;

    se := &SymbolTable[0] +
	    ((make(name* - '\e', uint) << 6) |
	      make((name + (length - 2) * sizeof(char))* - '\e', uint)) %
	    SYMBOL_TABLE_SIZE * sizeof(SymbolEntry_t);
    while se*.se_kind ~= sk_empty and
	(se*.se_length ~= length or not CharsEqual(se*.se_name, name))
    do
	se :=
	    if se = &SymbolTable[0] then
		se + (SYMBOL_TABLE_SIZE - 1) * sizeof(SymbolEntry_t)
	    else
		se - sizeof(SymbolEntry_t)
	    fi
    od;
    if se*.se_kind = sk_empty then
	if EntryCount = SYMBOL_TABLE_SIZE - 1 then
	    abort("symbol table overflow");
	fi;
	EntryCount := EntryCount + 1;
	se*.se_name := memAlloc(length * sizeof(char));
	BlockCopy(se*.se_name, name, length * sizeof(char));
	se*.se_length := length;
    fi;
    se
corp;

/*
 * fixLocals - add an offset to all local symbols.
 */

proc fixLocals(int extraOffset)void:
    register *SymbolEntry_t se;
    register uint i;

    se := &SymbolTable[0];
    for i from 0 upto SYMBOL_TABLE_SIZE - 1 do
	if se*.se_kind = sk_parameter or se*.se_kind = sk_localVariable then
	    se*.se_value := se*.se_value + extraOffset;
	fi;
	se := se + sizeof(SymbolEntry_t);
    od;
corp;
