// $Id: lookup.cpp,v 1.5 1999/02/12 14:39:13 shields Exp $
copyright notice

#include "config.h"
#include <iostream.h>
#include "lookup.h"
#include "symbol.h"
#include "code.h"
#include "ast.h"
#include "case.h"

int IntLiteralTable::int32_limit = 0x7FFFFFFF / 10;
LongInt LongLiteralTable::int64_limit = LongInt(0x7FFFFFFF, 0xFFFFFFFF) / 10;

int DirectoryTable::primes[] = {DEFAULT_HASH_SIZE, 2039, 4093, MAX_HASH_SIZE};

DirectoryTable::DirectoryTable(int estimate) : entry_pool(estimate),
                                               prime_index(0),
                                               hash_size(primes[0])
{
    base = (DirectoryEntry **) memset(new DirectoryEntry *[hash_size], 0, hash_size * sizeof(DirectoryEntry *));
}

DirectoryTable::~DirectoryTable()
{
/*
int n;
int num_slots = 0;
int total = 0;
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (Symbol *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
{
num_slots++;
total += num;
}
}

if (num_slots > 0)
{
cout << "\nDestroying the Name table with " << total
     << " elements and base size " << hash_size << " containing " << num_slots << " non-empty slots\n";
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (Symbol *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
cout << "    slot " << n << " contains " << num << " element(s)\n";
}
}
if (hash_size < total)
    total = total;
*/
#ifdef TEST
    for (int i = 0; i < entry_pool.Length(); i++)
        delete entry_pool[i];
    delete [] base;
#endif
}


time_t DirectoryEntry::Mtime()
{
    if (mtime_ == 0)
    {
        char *dirname = this -> directory -> DirectoryName();
        int length = this -> directory -> DirectoryNameLength() + this -> length + 1; // +1 for '/'
        char *file_name = new char[length + 1];
        strcpy(file_name, dirname);
        if (dirname[this -> directory -> DirectoryNameLength() - 1] != U_SLASH)
            strcat(file_name, StringConstant::U8S__SL_);
        strcat(file_name, this -> name);

        struct stat status;
        if (::SystemStat(file_name, &status) == 0)
            mtime_ = status.st_mtime;
else
assert("Cannot compute system time stamp\n");

        delete [] file_name;
    }

    return mtime_;
}


DirectoryEntry *DirectoryTable::FindEntry(char *str, int len)
{
    int k = Hash(str, len) % hash_size;
    DirectoryEntry *entry;
    for (entry = base[k]; entry; entry = entry -> next)
    {
        if (len == entry -> length && memcmp(entry -> name, str, len * sizeof(char)) == 0)
            return (entry -> IsDummy() ? (DirectoryEntry *) NULL : entry);
    }

    return NULL;
}


void DirectoryTable::Rehash()
{
    hash_size = primes[++prime_index];

    delete [] base;
    base = (DirectoryEntry **) memset(new DirectoryEntry *[hash_size], 0, hash_size * sizeof(DirectoryEntry *));

    for (int i = 0; i < entry_pool.Length(); i++)
    {
        DirectoryEntry *e = entry_pool[i];
        int k = Hash(e -> name, e -> length) % hash_size;
        e -> next = base[k];
        base[k] = e;
    }

    return;
}


DirectoryEntry *DirectoryTable::InsertEntry(DirectorySymbol *directory_symbol, char *str, int len)
{
    int k = Hash(str, len) % hash_size;
    DirectoryEntry *entry;
    for (entry = base[k]; entry; entry = entry -> next)
    {
        if (len == entry -> length && memcmp(entry -> name, str, len * sizeof(char)) == 0)
            return entry;
    }

    entry = new DirectoryEntry();
    entry_pool.Next() = entry;
    entry -> Initialize(directory_symbol, str, len);

    entry -> next = base[k];
    base[k] = entry;

    //
    // If the number of unique elements in the hash table exceeds 2 times
    // the size of the base, and we have not yet reached the maximum
    // allowable size for a base, reallocate a larger base and rehash
    // the elements.
    //
    if ((hash_size < MAX_HASH_SIZE) && (entry_pool.Length() > (hash_size << 1)))
        Rehash();

    return entry;
}


#ifdef WIN32_FILE_SYSTEM
DirectoryEntry *DirectoryTable::FindCaseInsensitiveEntry(char *name, int length)
{
    char *lower_name = new char[length + 1];
    for (int i = 0; i < length; i++)
        lower_name[i] = Case::ToAsciiLower(name[i]);
    lower_name[length] = U_NULL;

    DirectoryEntry *entry = FindEntry(lower_name, length);
    delete [] lower_name;

    return (entry ? entry -> Image() : entry);
}

void DirectoryTable::InsertCaseInsensitiveEntry(DirectoryEntry *image)
{
    int length = image -> length;
    char *lower_name = new char[length + 1];
    for (int i = 0; i < length; i++)
        lower_name[i] = Case::ToAsciiLower(image -> name[i]);
    lower_name[length] = U_NULL;

    int k = Hash(lower_name, length) % hash_size;
    DirectoryEntry *entry;
    for (entry = base[k]; entry; entry = entry -> next)
    {
        if (length == entry -> length && memcmp(entry -> name, lower_name, length * sizeof(char)) == 0)
            break;
    }

    if (! entry)
    {
        FoldedDirectoryEntry *folded_entry = new FoldedDirectoryEntry(image);
        entry_pool.Next() = folded_entry;
        folded_entry -> Initialize(image, lower_name, length);

        folded_entry -> next = base[k];
        base[k] = folded_entry;

        //
        // If the number of unique elements in the hash table exceeds 2 times
        // the size of the base, and we have not yet reached the maximum
        // allowable size for a base, reallocate a larger base and rehash
        // the elements.
        //
        if ((hash_size < MAX_HASH_SIZE) && (entry_pool.Length() > (hash_size << 1)))
            Rehash();
    }

    delete [] lower_name;

    return;
}
#endif

int NameLookupTable::primes[] = {DEFAULT_HASH_SIZE, 8191, 16411, MAX_HASH_SIZE};


NameLookupTable::NameLookupTable(int estimate) : symbol_pool(estimate),
                                                 prime_index(0),
                                                 hash_size(primes[0])
{
 base is an array of NameSymbol objects initialized to null
    base = (NameSymbol **) memset(new NameSymbol *[hash_size], 0, hash_size * sizeof(NameSymbol *));
}

NameLookupTable::~NameLookupTable()
{
/*
int n;
int num_slots = 0;
int total = 0;
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (Symbol *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
{
num_slots++;
total += num;
}
}

if (num_slots > 0)
{
cout << "\nDestroying the Name table with " << total
     << " elements and base size " << hash_size << " containing " << num_slots << " non-empty slots\n";
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (Symbol *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
cout << "    slot " << n << " contains " << num << " element(s)\n";
}
}
if (hash_size < total)
    total = total;
*/
#ifdef TEST
    for (int i = 0; i < symbol_pool.Length(); i++)
        delete symbol_pool[i];
    delete [] base;
#endif
}


int LiteralLookupTable::primes[] = {DEFAULT_HASH_SIZE, 2039, 4093, MAX_HASH_SIZE};

LiteralLookupTable::LiteralLookupTable() : symbol_pool(16384),
                                           prime_index(0),
                                           hash_size(primes[0])
{
    base = (LiteralSymbol **) memset(new LiteralSymbol *[hash_size], 0, hash_size * sizeof(LiteralSymbol *));
}

LiteralLookupTable::~LiteralLookupTable()
{
/*
int n;
int num_slots = 0;
int total = 0;
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (Symbol *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
{
num_slots++;
total += num;
}
}

if (num_slots > 0)
{
cout << "\nDestroying the Literal table with " << total
     << " elements and base size " << hash_size << " containing " << num_slots << " non-empty slots\n";
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (Symbol *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
cout << "    slot " << n << " contains " << num << " element(s)\n";
}
}
if (hash_size < total)
    total = total;
*/
#ifdef TEST
    for (int i = 0; i < symbol_pool.Length(); i++)
        delete symbol_pool[i];
    delete [] base;
#endif
}


int IntLiteralTable::primes[] = {DEFAULT_HASH_SIZE, 8191, 16411, MAX_HASH_SIZE};

IntLiteralTable::IntLiteralTable(LiteralValue *bad_value_) : symbol_pool(16384),
                                                             bad_value(bad_value_),
                                                             prime_index(0),
                                                             hash_size(primes[0])
{
    base = (IntLiteralValue **) memset(new IntLiteralValue *[hash_size], 0, hash_size * sizeof(IntLiteralValue *));
}

IntLiteralTable::~IntLiteralTable()
{
/*
int n;
int num_slots = 0;
int total = 0;
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (LiteralValue *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
{
num_slots++;
total += num;
}
}

if (num_slots > 0)
{
cout << "\nDestroying the integer table with " << total
     << " elements and base size " << hash_size << " containing " << num_slots << " non-empty slots\n";
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (LiteralValue *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
cout << "    slot " << n << " contains " << num << " element(s)\n";
}
}
if (hash_size < total)
    total = total;
*/

#ifdef TEST
    for (int i = 0; i < symbol_pool.Length(); i++)
        delete symbol_pool[i];
    delete [] base;
#endif
}


int LongLiteralTable::primes[] = {DEFAULT_HASH_SIZE, 2039, 4093, MAX_HASH_SIZE};

LongLiteralTable::LongLiteralTable(LiteralValue *bad_value_) : symbol_pool(16384),
                                                               bad_value(bad_value_),
                                                               prime_index(0),
                                                               hash_size(primes[0])
{
    base = (LongLiteralValue **) memset(new LongLiteralValue *[hash_size], 0, hash_size * sizeof(LongLiteralValue *));
}

LongLiteralTable::~LongLiteralTable()
{
/*
int n;
int num_slots = 0;
int total = 0;
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (LiteralValue *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
{
num_slots++;
total += num;
}
}

if (num_slots > 0)
{
cout << "\nDestroying the long table with " << total
     << " elements and base size " << hash_size << " containing " << num_slots << " non-empty slots\n";
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (LiteralValue *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
cout << "    slot " << n << " contains " << num << " element(s)\n";
}
}
if (hash_size < total)
    total = total;
*/

#ifdef TEST
    for (int i = 0; i < symbol_pool.Length(); i++)
        delete symbol_pool[i];
    delete [] base;
#endif
}


int FloatLiteralTable::primes[] = {DEFAULT_HASH_SIZE, 2039, 4093, MAX_HASH_SIZE};

FloatLiteralTable::FloatLiteralTable(LiteralValue *bad_value_) : symbol_pool(16384),
                                                                 bad_value(bad_value_),
                                                                 prime_index(0),
                                                                 hash_size(primes[0])
{
    base = (FloatLiteralValue **) memset(new FloatLiteralValue *[hash_size], 0, hash_size * sizeof(FloatLiteralValue *));
}

FloatLiteralTable::~FloatLiteralTable()
{
/*
int n;
int num_slots = 0;
int total = 0;
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (LiteralValue *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
{
num_slots++;
total += num;
}
}

if (num_slots > 0)
{
cout << "\nDestroying the float table with " << total
     << " elements and base size " << hash_size << " containing " << num_slots << " non-empty slots\n";
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (LiteralValue *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
cout << "    slot " << n << " contains " << num << " element(s)\n";
}
}
if (hash_size < total)
    total = total;
*/

#ifdef TEST
    for (int i = 0; i < symbol_pool.Length(); i++)
        delete symbol_pool[i];
    delete [] base;
#endif
}


int DoubleLiteralTable::primes[] = {DEFAULT_HASH_SIZE, 2039, 4093, MAX_HASH_SIZE};

DoubleLiteralTable::DoubleLiteralTable(LiteralValue *bad_value_) : symbol_pool(16384),
                                                                   bad_value(bad_value_),
                                                                   prime_index(0),
                                                                   hash_size(primes[0])
{
    base = (DoubleLiteralValue **) memset(new DoubleLiteralValue *[hash_size], 0, hash_size * sizeof(DoubleLiteralValue *));
}

DoubleLiteralTable::~DoubleLiteralTable()
{
/*
int n;
int num_slots = 0;
int total = 0;
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (LiteralValue *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
{
num_slots++;
total += num;
}
}

if (num_slots > 0)
{
cout << "\nDestroying the double table with " << total
     << " elements and base size " << hash_size << " containing " << num_slots << " non-empty slots\n";
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (LiteralValue *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
cout << "    slot " << n << " contains " << num << " element(s)\n";
}
}
if (hash_size < total)
    total = total;
*/
#ifdef TEST
    for (int i = 0; i < symbol_pool.Length(); i++)
        delete symbol_pool[i];
    delete [] base;
#endif
}


int Utf8LiteralTable::primes[] = {DEFAULT_HASH_SIZE, 8191, 16411, MAX_HASH_SIZE};

Utf8LiteralTable::Utf8LiteralTable(LiteralValue *bad_value_) : symbol_pool(16384),
                                                               bad_value(bad_value_),
                                                               prime_index(0),
                                                               hash_size(primes[0])
{
    base = (Utf8LiteralValue **) memset(new Utf8LiteralValue *[hash_size], 0, hash_size * sizeof(Utf8LiteralValue *));
}


Utf8LiteralTable::~Utf8LiteralTable()
{
/*
int n;
int num_slots = 0;
int total = 0;
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (LiteralValue *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
{
num_slots++;
total += num;
}
}

if (num_slots > 0)
{
cout << "\nDestroying the Utf8 table with " << total
     << " elements and base size " << hash_size << " containing " << num_slots << " non-empty slots\n";
for (n = 0; n < hash_size; n++)
{
int num = 0;
for (LiteralValue *s = base[n]; s; s = s -> next)
    num++;
if (num > 0)
cout << "    slot " << n << " contains " << num << " element(s)\n";
}
}
if (hash_size < total)
    total = total;
*/
#ifdef TEST
    for (int i = 0; i < symbol_pool.Length(); i++)
        delete symbol_pool[i];
    delete [] base;
#endif
}


void NameLookupTable::Rehash()
{
    hash_size = primes[++prime_index];

    delete [] base;
    base = (NameSymbol **) memset(new NameSymbol *[hash_size], 0, hash_size * sizeof(NameSymbol *));

    for (int i = 0; i < symbol_pool.Length(); i++)
    {
        NameSymbol *ns = symbol_pool[i];
        int k = ns -> hash_address % hash_size;
        ns -> next = base[k];
        base[k] = ns;
    }

    return;
}


NameSymbol *NameLookupTable::FindOrInsertName(wchar_t *str, int len)
{We compute the hash code for the symbol
    unsigned hash_address = Hash(str, len);
    int k = hash_address % hash_size;
    NameSymbol *symbol;
k is a bucket in the table. search all entries in the bucket
base is an array of NameSymbol
    for (symbol = base[k]; symbol; symbol = (NameSymbol *) symbol -> next)
    {
        if (len == symbol -> NameLength() && memcmp(symbol -> Name(), str, len * sizeof(wchar_t)) == 0)
            found it, return it
            return symbol;
    }
it's not there. allocate a new symbol
    int index = symbol_pool.Length(); // index of the next element
    symbol = new NameSymbol();
link it to the symbol table
    symbol_pool.Next() = symbol;
    symbol -> Initialize(str, len, hash_address, index);
add it to the proper bucket
    symbol -> next = base[k];
    base[k] = symbol;
and make sure that the table is less than 50% utilized
    //
    // If the number of unique elements in the hash table exceeds 2 times
    // the size of the base, and we have not yet reached the maximum
    // allowable size for a base, reallocate a larger base and rehash
    // the elements.
    //
    if ((hash_size < MAX_HASH_SIZE) && (symbol_pool.Length() > (hash_size << 1)))
        Rehash();
return the newly allocated symbol (now in the table)
    return symbol;
}


void LiteralLookupTable::Rehash()
{
    hash_size = primes[++prime_index];

    delete [] base;
    base = (LiteralSymbol **) memset(new LiteralSymbol *[hash_size], 0, hash_size * sizeof(LiteralSymbol *));

    for (int i = 0; i < symbol_pool.Length(); i++)
    {
        LiteralSymbol *ls = symbol_pool[i];
        int k = ls -> hash_address % hash_size;
        ls -> next = base[k];
        base[k] = ls;
    }

    return;
}


LiteralSymbol *LiteralLookupTable::FindOrInsertLiteral(wchar_t *str, int len)
{
    unsigned hash_address = Hash(str, len);
    int k = hash_address % hash_size;
    LiteralSymbol *symbol;
    for (symbol = base[k]; symbol; symbol = (LiteralSymbol *) symbol -> next)
    {
        if (len == symbol -> NameLength() && memcmp(symbol -> Name(), str, len * sizeof(wchar_t)) == 0)
            return symbol;
    }

    symbol = new LiteralSymbol();
    symbol_pool.Next() = symbol;
    symbol -> Initialize(str, hash_address, len);

    symbol -> next = base[k];
    base[k] = symbol;

    //
    // If the number of unique elements in the hash table exceeds 2 times
    // the size of the base, and we have not yet reached the maximum
    // allowable size for a base, reallocate a larger base and rehash
    // the elements.
    //
    if ((hash_size < MAX_HASH_SIZE) && (symbol_pool.Length() > (hash_size << 1)))
        Rehash();

    return symbol;
}


LiteralValue *IntLiteralTable::FindOrInsertChar(LiteralSymbol *literal)
{
    wchar_t *name = literal -> Name();

    if (literal -> NameLength() == 1) // an isolated quote
         return literal -> value = bad_value;
    else if (literal -> NameLength() <= 3) // a regular character of the form:  quote + char
                                           // or                                quote + char + quote
         return literal -> value = FindOrInsert((int) name[1]);

    int value;

    if (name[1] != U_BACKSLASH)
         value = -1;
    else if (name[2] == U_b && name[3] == U_SINGLE_QUOTE)
         value = U_BACKSPACE;
    else if (name[2] == U_t && name[3] == U_SINGLE_QUOTE)
         value = U_HORIZONTAL_TAB;
    else if (name[2] == U_n && name[3] == U_SINGLE_QUOTE)
         value = U_LINE_FEED;
    else if (name[2] == U_f && name[3] == U_SINGLE_QUOTE)
         value = U_FORM_FEED;
    else if (name[2] == U_r && name[3] == U_SINGLE_QUOTE)
         value = U_CARRIAGE_RETURN;
    else if (name[2] == U_DOUBLE_QUOTE && name[3] == U_SINGLE_QUOTE)
         value = U_DOUBLE_QUOTE;
    else if (name[2] == U_SINGLE_QUOTE && name[3] == U_SINGLE_QUOTE)
         value = U_SINGLE_QUOTE;
    else if (name[2] == U_BACKSLASH && name[3] == U_SINGLE_QUOTE)
         value = U_BACKSLASH;
    else if (Code::IsDigit(name[2]))
    {
        wchar_t *p = &name[2];

        int d1 = *p++ - U_0;
        value = (d1 < 8 ? d1 : -1);

        if (value >= 0 && Code::IsDigit(*p))
        {
            int d2 = *p++ - U_0;
            value = (d2 < 8 ? value * 8 + d2 : -1);

            if (value >= 0 && Code::IsDigit(*p))
            {
                int d3 = *p++ - U_0;
                value = (d3 < 8 && d1 < 4 ? value * 8 + d3 : -1);
            }
        }

        if (*p != U_NULL && *p != U_SINGLE_QUOTE)
            value = -1;
    }
    else value = -1;

    return literal -> value = (value < 0 || value > 65535 ? bad_value : FindOrInsert(value));
}


LiteralValue *IntLiteralTable::FindOrInsertHexInt(LiteralSymbol *literal)
{
    wchar_t *head = literal -> Name() + 1, // point to X
            *tail = &literal -> Name()[literal -> NameLength() - 1];

    u4 uvalue = 0;

    //
    // According to the JLS 3.10.1, "A compile-time error occurs if ... a
    // hexadecimal or octal int literal does not fit in 32 bits". 
    // So, strictly speaking, we should not skip leading zeroes. However,
    // there are many publicly available code out there with leading zeroes
    // that don't compile with jikes, if ...
    //
    {
        for (++head; tail > head && *head == U_0; head++) // skip leading zeroes
            ;
        head--;
    }

    for (int i = 0; i < 32 && tail > head; i += 4, tail--)
    {
        u4 d = *tail - (Code::IsDigit(*tail) ? U_0 : (Code::IsLower(*tail) ? U_a : U_A) - 10);
        uvalue |= (d << i);
    }

    return (tail > head ? bad_value : FindOrInsert((int) uvalue));
}


LiteralValue *IntLiteralTable::FindOrInsertOctalInt(LiteralSymbol *literal)
{
    wchar_t *head = literal -> Name(), // point to initial '0'
            *tail = &head[literal -> NameLength() - 1];

    u4 uvalue = 0;
    //
    // According to the JLS 3.10.1, "A compile-time error occurs if ... a
    // hexadecimal or octal int literal does not fit in 32 bits". 
    // So, strictly speaking, we should not skip leading zeroes. However,
    // there are many publicly available code out there with leading zeroes
    // that don't compile with jikes,...
    //
    {
        for (++head; tail > head && *head == U_0; head++) // skip leading zeroes
            ;
        head--;
    }

    for (int i = 0; i < 30 && tail > head; i += 3, tail--)
    {
        u4 d = *tail - U_0;
        uvalue |= (d << i);
    }

    if (tail > head)
    {
        u4 d = *tail - U_0;

        if (d <= 3) // max number that can fit in 2 bits
        {
            tail--;
            uvalue |= (d << 30);
        }
    }

    return (tail > head ? bad_value : FindOrInsert((int) uvalue));
}


LiteralValue *IntLiteralTable::FindOrInsertInt(LiteralSymbol *literal)
{
    wchar_t *name = literal -> Name();

    if (name[0] == U_0)
        literal -> value = (name[1] == U_x || name[1] == U_X ? FindOrInsertHexInt(literal) : FindOrInsertOctalInt(literal));
    else
    {
        int value = 0;

        wchar_t *p;
        for (p = name; *p; p++)
        {
            int digit = *p - U_0;
            if (value > int32_limit || (value == int32_limit && digit > 7))
                break;
            value = value * 10 + digit;
        }

        literal -> value = (*p ? bad_value : FindOrInsert(value));
    }

    return literal -> value;
}


LiteralValue *IntLiteralTable::FindOrInsertNegativeInt(LiteralSymbol *literal)
{
    if (literal -> value && literal -> value != bad_value) // a positive value already exists
    {
        IntLiteralValue *int_literal = (IntLiteralValue *) literal -> value;
        return FindOrInsert(- int_literal -> value);
    }

    wchar_t *name = literal -> Name();

    //
    // We can assert that the name of a literal contains at least two characters:
    // at least one digit and the terminating '\0'.
    //
    if (name[0] == U_0)
    {
        IntLiteralValue *int_literal = (IntLiteralValue *) (name[1] == U_x || name[1] == U_X
                                                                     ? FindOrInsertHexInt(literal)
                                                                     : FindOrInsertOctalInt(literal));
        return FindOrInsert(- int_literal -> value);
    }

    int value = 0;

    wchar_t *p;
    for (p = name; *p; p++)
    {
        int digit = *p - U_0;
        if (value > int32_limit || (value == int32_limit && digit > 8))
            break;
        value = value * 10 + digit;
    }

    return (*p ? bad_value : FindOrInsert(-value));
}


void IntLiteralTable::Rehash()
{
    hash_size = primes[++prime_index];

    delete [] base;
    base = (IntLiteralValue **) memset(new IntLiteralValue *[hash_size], 0, hash_size * sizeof(IntLiteralValue *));

    for (int i = 0; i < symbol_pool.Length(); i++)
    {
        IntLiteralValue *ilv = symbol_pool[i];
        int k = ((unsigned) ilv -> value) % hash_size; // The unsigned casting turns the negative values into positive values
        ilv -> next = base[k];
        base[k] = ilv;
    }

    return;
}


IntLiteralValue *IntLiteralTable::FindOrInsert(int value)
{
    int k = ((unsigned) value) % hash_size; // The unsigned casting turns the negative values into positive values

    IntLiteralValue *lit;
    for (lit = base[k]; lit; lit = (IntLiteralValue *) lit -> next)
    {
        if (lit -> value == value)
            return lit;
    }

    lit = new IntLiteralValue();
    symbol_pool.Next() = lit;
    lit -> Initialize(value);

    lit -> next = base[k];
    base[k] = lit;

    //
    // If the number of unique elements in the hash table exceeds 2 times
    // the size of the base, and we have not yet reached the maximum
    // allowable size for a base, reallocate a larger base and rehash
    // the elements.
    //
    if ((hash_size < MAX_HASH_SIZE) && (symbol_pool.Length() > (hash_size << 1)))
        Rehash();

    return lit;
}


LiteralValue *LongLiteralTable::FindOrInsertHexLong(LiteralSymbol *literal)
{
    u4 high = 0,
       low = 0;

    wchar_t *head = literal -> Name() + 1, // point to X
            *tail = &literal -> Name()[literal -> NameLength() - 2]; // -2 to skip the 'L' suffix

    //
    // According to the JLS 3.10.1, "A compile-time error occurs if ... a
    // hexadecimal or octal int literal does not fit in 32 bits". 
    // So, strictly speaking, we should not skip leading zeroes. However,
    // there are many publicly available code out there with leading zeroes
    // that don't compile with jikes,...
    //
    {
        for (++head; tail > head && *head == U_0; head++) // skip leading zeroes
            ;
        head--;
    }

    for (int i = 0; i < 32 && tail > head; i += 4, tail--)
    {
        u4 d = *tail - (Code::IsDigit(*tail) ? U_0 : (Code::IsLower(*tail) ? U_a : U_A) - 10);
        low |= (d << i);
    }

    for (int j = 0; j < 32 && tail > head; j += 4, tail--)
    {
        u4 d = *tail - (Code::IsDigit(*tail) ? U_0 : (Code::IsLower(*tail) ? U_a : U_A) - 10);
        high |= (d << j);
    }

    return (tail > head ? bad_value : FindOrInsert(LongInt(high, low)));
}


LiteralValue *LongLiteralTable::FindOrInsertOctalLong(LiteralSymbol *literal)
{
    wchar_t *head = literal -> Name(), // point to initial '0'
            *tail = &head[literal -> NameLength() - 2]; // -2 to skip the 'L' suffix

    ULongInt uvalue = 0;
    //
    // According to the JLS 3.10.1, "A compile-time error occurs if ... a
    // hexadecimal or octal int literal does not fit in 32 bits". 
    // So, strictly speaking, we should not skip leading zeroes. However,
    // there are many publicly available code out there with leading zeroes
    // that don't compile with jikes,...
    //
    {
        for (++head; tail > head && *head == U_0; head++) // skip leading zeroes
            ;
        head--;
    }

    for (int i = 0; i < 63 && tail > head; i += 3, tail--)
    {
        ULongInt d = (u4) (*tail - U_0);
        uvalue |= (d << i);
    }

    if (tail > head)
    {
        u4 d = *tail - U_0;

        if (d <= 1) // max number that can fit in 1 bit
        {
            tail--;
            uvalue.HighWord() |= (d << 31);
        }
    }

    return (tail > head ? bad_value : FindOrInsert((LongInt) uvalue));
}


LiteralValue *LongLiteralTable::FindOrInsertLong(LiteralSymbol *literal)
{
    wchar_t *name = literal -> Name();

    //
    // We can assert that the name of a literal contains at least two characters:
    // at least one digit and the terminating '\0'.
    //
    if (name[0] == U_0)
        literal -> value = (name[1] == U_x || name[1] == U_X ? FindOrInsertHexLong(literal) : FindOrInsertOctalLong(literal));
    else
    {
        LongInt value = 0;

        wchar_t *p;
        for (p = name; *p != U_L && *p != U_l; p++)
        {
            u4 digit = *p - U_0;
            if (value > int64_limit || (value == int64_limit && digit > 7))
                break;
            value = value * 10 + digit;
        }

        literal -> value = (*p != U_L && *p != U_l ? bad_value : FindOrInsert(value));
    }

    return literal -> value;
}


LiteralValue *LongLiteralTable::FindOrInsertNegativeLong(LiteralSymbol *literal)
{
    if (literal -> value && literal -> value != bad_value) // a positive value already exists
    {
        LongLiteralValue *long_literal = (LongLiteralValue *) literal -> value;
        return FindOrInsert(- long_literal -> value);
    }

    wchar_t *name = literal -> Name();
    //
    // We can assert that the name of a literal contains at least two characters:
    // at least one digit and the terminating '\0'.
    //
    if (name[0] == U_0)
    {
        LongLiteralValue *long_literal = (LongLiteralValue *) (name[1] == U_x || name[1] == U_X
                                                                               ? FindOrInsertHexLong(literal)
                                                                               : FindOrInsertOctalLong(literal));
        return FindOrInsert(- long_literal -> value);
    }

    LongInt value = 0;

    wchar_t *p;
    for (p = name; *p != U_L && *p != U_l && value >= 0; p++)
    {
        u4 digit = *p - U_0;
        if (value > int64_limit || (value == int64_limit && digit > 8))
            break;
        value = value * 10 + digit;
    }

    return (*p != U_L && *p != U_l ? bad_value : FindOrInsert(-value));
}


void LongLiteralTable::Rehash()
{
    hash_size = primes[++prime_index];

    delete [] base;
    base = (LongLiteralValue **) memset(new LongLiteralValue *[hash_size], 0, hash_size * sizeof(LongLiteralValue *));

    for (int i = 0; i < symbol_pool.Length(); i++)
    {
        LongLiteralValue *llv = symbol_pool[i];
        int k = (((ULongInt) llv -> value) % ULongInt(0, hash_size)).LowWord(); // The ULongInt turns negative values positive
        llv -> next = base[k];
        base[k] = llv;
    }

    return;
}


LongLiteralValue *LongLiteralTable::FindOrInsert(LongInt value)
{
    int k = (((ULongInt) value) % ULongInt(0, hash_size)).LowWord();  // The ULongInt cast turns negative values into positive values

    LongLiteralValue *lit;
    for (lit = base[k]; lit; lit = (LongLiteralValue *) lit -> next)
    {
        if (lit -> value == value)
            return lit;
    }

    lit = new LongLiteralValue();
    symbol_pool.Next() = lit;
    lit -> Initialize(value);

    lit -> next = base[k];
    base[k] = lit;

    //
    // If the number of unique elements in the hash table exceeds 2 times
    // the size of the base, and we have not yet reached the maximum
    // allowable size for a base, reallocate a larger base and rehash
    // the elements.
    //
    if ((hash_size < MAX_HASH_SIZE) && (symbol_pool.Length() > (hash_size << 1)))
        Rehash();

    return lit;
}


LiteralValue *FloatLiteralTable::FindOrInsertFloat(LiteralSymbol *literal)
{
    char *name = new char[literal -> NameLength() + 1];
    for (int i = 0; i < literal -> NameLength(); i++)
        name[i] = (char) literal -> Name()[i];
    name[literal -> NameLength()] = U_NULL;

    IEEEfloat value = IEEEfloat(name);

    literal -> value = FindOrInsert(value);

    delete [] name;

    return literal -> value;
}


void FloatLiteralTable::Rehash()
{
    hash_size = primes[++prime_index];

    delete [] base;
    base = (FloatLiteralValue **) memset(new FloatLiteralValue *[hash_size], 0, hash_size * sizeof(FloatLiteralValue *));

    for (int i = 0; i < symbol_pool.Length(); i++)
    {
        FloatLiteralValue *flv = symbol_pool[i];
        int k = Hash(flv -> value) % hash_size; // the hash function for float values is cheap so we don't need to save it.
        flv -> next = base[k];
        base[k] = flv;
    }

    return;
}


FloatLiteralValue *FloatLiteralTable::FindOrInsert(IEEEfloat value)
{
    int k = Hash(value) % hash_size;

    FloatLiteralValue *lit;
    for (lit = base[k]; lit; lit = (FloatLiteralValue *) lit -> next)
    {
        if (lit -> value == value)
            return lit;
    }

    lit = new FloatLiteralValue();
    symbol_pool.Next() = lit;
    lit -> Initialize(value);

    lit -> next = base[k];
    base[k] = lit;

    //
    // If the number of unique elements in the hash table exceeds 2 times
    // the size of the base, and we have not yet reached the maximum
    // allowable size for a base, reallocate a larger base and rehash
    // the elements.
    //
    if ((hash_size < MAX_HASH_SIZE) && (symbol_pool.Length() > (hash_size << 1)))
        Rehash();

    return lit;
}


LiteralValue *DoubleLiteralTable::FindOrInsertDouble(LiteralSymbol *literal)
{
    char *name = new char[literal -> NameLength() + 1];
    for (int i = 0; i < literal -> NameLength(); i++)
        name[i] = (char) literal -> Name()[i];
    name[literal -> NameLength()] = U_NULL;

    IEEEdouble value = IEEEdouble(name);

    literal -> value = FindOrInsert(value);

    delete [] name;

    return literal -> value;
}


void DoubleLiteralTable::Rehash()
{
    hash_size = primes[++prime_index];

    delete [] base;
    base = (DoubleLiteralValue **) memset(new DoubleLiteralValue *[hash_size], 0, hash_size * sizeof(DoubleLiteralValue *));

    for (int i = 0; i < symbol_pool.Length(); i++)
    {
        DoubleLiteralValue *dlv = symbol_pool[i];
        int k = Hash(dlv -> value) % hash_size; // the hash function for double values is cheap so we don't need to save it.
        dlv -> next = base[k];
        base[k] = dlv;
    }

    return;
}


DoubleLiteralValue *DoubleLiteralTable::FindOrInsert(IEEEdouble value)
{
    int k = Hash(value) % hash_size;

    DoubleLiteralValue *lit;
    for (lit = base[k]; lit; lit = (DoubleLiteralValue *) lit -> next)
    {
        if (lit -> value == value)
            return lit;
    }

    lit = new DoubleLiteralValue();
    symbol_pool.Next() = lit;
    lit -> Initialize(value);

    lit -> next = base[k];
    base[k] = lit;

    //
    // If the number of unique elements in the hash table exceeds 2 times
    // the size of the base, and we have not yet reached the maximum
    // allowable size for a base, reallocate a larger base and rehash
    // the elements.
    //
    if ((hash_size < MAX_HASH_SIZE) && (symbol_pool.Length() > (hash_size << 1)))
        Rehash();

    return lit;
}


LiteralValue *Utf8LiteralTable::FindOrInsertString(LiteralSymbol *literal)
{
    wchar_t *name = literal -> Name();

    int literal_length = literal -> NameLength();

    char *value = new char[literal_length * 3]; // should be big enough for the worst case
    int len = 0,
        i;
    for (i = 1; i < literal_length && name[i] != U_DOUBLE_QUOTE; i++)  // start at 1 to skip the initial \"
    {
        int ch = name[i];

        if (ch == U_BACKSLASH)
        {
            if (name[i + 1] == U_b)
            {
                i++;
                ch = U_BACKSPACE;
            }
            else if (name[i + 1] == U_t)
            {
                i++;
                ch = U_HORIZONTAL_TAB;
            }
            else if (name[i + 1] == U_n)
            {
                i++;
                ch = U_LINE_FEED;
            }
            else if (name[i + 1] == U_f)
            {
                i++;
                ch = U_FORM_FEED;
            }
            else if (name[i + 1] == U_r)
            {
                i++;
                ch = U_CARRIAGE_RETURN;
            }
            else if (name[i + 1] == U_DOUBLE_QUOTE)
            {          
                i++;
                ch = U_DOUBLE_QUOTE;
            }
            else if (name[i + 1] == U_SINGLE_QUOTE)
            {          
                i++;
                ch = U_SINGLE_QUOTE;
            }
            else if (name[i + 1] == U_BACKSLASH)
            {
                i++;
                ch = U_BACKSLASH;
            }
            else if (Code::IsDigit(name[i + 1]))
            {
                int digit = name[++i] - U_0;

                if (digit > 7) // The first digit must be an octal digit 
                    ch = -1;
                else
                {
                    ch = digit;
                    if (Code::IsDigit(name[i + 1]))
                    {
                        digit = name[i + 1] - U_0;
                        if (digit < 8)
                        {
                            ch = ch * 8 + digit;
                            i++;
                            if (Code::IsDigit(name[i + 1]))
                            {
                                digit = name[i + 1] - U_0;
                                if (ch <= 0x1F && digit < 8)
                                {
                                    ch = ch * 8 + digit;
                                    i++;
                                }
                            }
                        }
                    }
                }
            }
            else ch = -1;
        }

        if (ch < 0)
             break;
        else if (ch == 0)
        {
             value[len++] = (char) 0xC0;
             value[len++] = (char) 0x80;
        }
        else if (ch <= 0x007F)
             value[len++] = (char) ch;
        else if (ch <= 0x07FF)
        {
             value[len++] = (char) ((char) 0xC0 | (char) ((ch >> 6) & 0x001F)); // bits 6-10
             value[len++] = (char) ((char) 0x80 | (char) (ch & 0x003F));        // bits 0-5
        }
        else
        {
             value[len++] = (char) ((char) 0xE0 | (char) ((ch >> 12) & 0x000F));
             value[len++] = (char) ((char) 0x80 | (char) ((ch >> 6) & 0x003F));
             value[len++] = (char) ((char) 0x80 | (char) (ch & 0x3F));
        }
    }

    value[len] = U_NULL;
    literal -> value = (i < literal_length && name[i] != U_DOUBLE_QUOTE ? bad_value : FindOrInsert(value, len));

    delete [] value;
    return literal -> value;
}


Utf8LiteralValue *Utf8LiteralTable::FindOrInsert(wchar_t ch)
{
    int len = 0;
    char str[4];

    if (ch == 0)
    {
         str[len++] = (char) 0xC0;
         str[len++] = (char) 0x80;
    }
    else if (ch <= 0x007F)
         str[len++] = (char) ch;
    else if (ch <= 0x07FF)
    {
         str[len++] = (char) ((char) 0xC0 | (char) ((ch >> 6) & 0x001F)); // bits 6-10
         str[len++] = (char) ((char) 0x80 | (char) (ch & 0x003F));        // bits 0-5
    }
    else
    {
         str[len++] = (char) ((char) 0xE0 | (char) ((ch >> 12) & 0x000F));
         str[len++] = (char) ((char) 0x80 | (char) ((ch >> 6) & 0x003F));
         str[len++] = (char) ((char) 0x80 | (char) (ch & 0x3F));
    }

    str[len] = U_NULL;

    return FindOrInsert(str, len);
}


void Utf8LiteralTable::Rehash()
{
    hash_size = primes[++prime_index];

    delete [] base;
    base = (Utf8LiteralValue **) memset(new Utf8LiteralValue *[hash_size], 0, hash_size * sizeof(Utf8LiteralValue *));

    for (int i = 0; i < symbol_pool.Length(); i++)
    {
        Utf8LiteralValue *ulv = symbol_pool[i];
        int k = ulv -> hash_address % hash_size;
        ulv -> next = base[k];
        base[k] = ulv;
    }

    return;
}


Utf8LiteralValue *Utf8LiteralTable::FindOrInsert(char *str, int len)
{
    unsigned hash_address = Hash(str, len);
    int k = hash_address % hash_size;

    Utf8LiteralValue *lit;
    for (lit = base[k]; lit; lit = (Utf8LiteralValue *) lit -> next)
    {
        if (len == lit -> length)
        {
            if (memcmp(lit -> value, str, len * sizeof(char)) == 0)
                 return lit;
        }
    }

    lit = new Utf8LiteralValue();
    symbol_pool.Next() = lit;
    lit -> Initialize(str, len, hash_address);

    lit -> next = base[k];
    base[k] = lit;

    //
    // If the number of unique elements in the hash table exceeds 2 times
    // the size of the base, and we have not yet reached the maximum
    // allowable size for a base, reallocate a larger base and rehash
    // the elements.
    //
    if ((hash_size < MAX_HASH_SIZE) && (symbol_pool.Length() > (hash_size << 1)))
        Rehash();

    return lit;
}


bool Utf8LiteralTable::IsConstant(AstExpression *expression)
{
    //
    // Recall that addition if left-recursive
    //
    while (! expression -> IsConstant())
    {
        AstBinaryExpression *binary_expression;
        AstCastExpression *cast_expression;
        AstParenthesizedExpression *parenthesized_expression;

        if (binary_expression = expression -> BinaryExpressionCast())
        {
             AstExpression *right = binary_expression -> right_expression;
             if (! IsConstant(right))
                 return false;
             expression = binary_expression -> left_expression;
        }
        else if (cast_expression = expression -> CastExpressionCast())
             expression = cast_expression -> expression;
        else if (parenthesized_expression = expression -> ParenthesizedExpressionCast())
             expression = parenthesized_expression -> expression;
        else return false; // Not a constant String expression
    }

    if (expression -> IsConstant())
        expr -> Next() = expression;

    return expression -> IsConstant();
}


void Utf8LiteralTable::CheckStringConstant(AstExpression *expression)
{
    expr = new Tuple<AstExpression *>(256);

    if (IsConstant(expression))
    {
        Utf8LiteralValue *literal;
        int length = 0;
        for (int i = 0; i < expr -> Length(); i++)
        {
            literal = (Utf8LiteralValue *) (*expr)[i] -> value;
            length += literal -> length;
        }
        char *str = new char[length + 1]; // +1 for '\0'

        //
        // Since we started on the right, we have to run over the list in reverse order.
        //
        int index = 0;
        for (int k = expr -> Length() - 1; k >= 0; k--)
        {
            literal = (Utf8LiteralValue *) (*expr)[k] -> value;
            memmove(&str[index], literal -> value, literal -> length * sizeof(char));
            index += literal -> length;
        }
        str[length] = U_NULL;

        expression -> value = FindOrInsert(str, length);

        delete [] str;
    }

    delete expr;

    return;
}