/****************************************************************************/
/*                                                                          */
/*  Copyright (c) 1996-2002                                                 */
/*  Jeremy Levitt                                                           */
/*  All Rights Reserved                                                     */
/*                                                                          */
/*  File:  symbol.h                                                         */
/*                                                                          */
/****************************************************************************/

#ifndef _symbol_h_
#define _symbol_h_

#include <iostream.h>
#include "misc.h"

class TableElem;
const int SYMBOL_TABLE_SIZE = 1000;

class Symbol_Table {
 private:
  TableElem* _hashEntry[SYMBOL_TABLE_SIZE];
  int HashFunction(const char*);
  static TableElem* _nullSymbol;

 public:
  Symbol_Table(const char*);
  ~Symbol_Table();
  TableElem* Insert(const char*);
  TableElem* Null_Symbol() { return _nullSymbol; }
  friend ostream& operator<< (ostream&, const Symbol_Table&);
};


class TableElem {
 private:
  int _numRefs;
  TableElem** _prev;
  TableElem* _next;
  char *_chars;

 public:
  friend ostream& operator<< (ostream&, const TableElem&);
  friend ostream& operator<< (ostream&, const Symbol_Table&);
  friend TableElem* Symbol_Table::Insert(const char*);
  TableElem(const char*, TableElem**, TableElem*);
  ~TableElem();
  const char *Chars() const { return _chars; }
  void AddReference() { _numRefs += 1; }
  void RemoveReference() { if(--_numRefs == 0) delete this; }
};


class Symbol {
  friend class Symbol_Init;
 private:
  TableElem* _tableElem;
  static Symbol_Table *_Symbol_Table;

 public:
  Symbol();
  Symbol(const char*);
  Symbol(const Symbol& symbol) : _tableElem(symbol._tableElem)
    { _tableElem->AddReference(); }
  ~Symbol() { _tableElem->RemoveReference(); }
  const char *Chars() const { return _tableElem->Chars(); }
  int operator== (const Symbol& rhs) const
    { return(_tableElem == rhs._tableElem); }
  int operator!= (const Symbol& rhs) const
    { return(_tableElem != rhs._tableElem); }
  Symbol& operator= (const Symbol&);
  int operator! () const { return _tableElem == _Symbol_Table->Null_Symbol(); }

  static int Hash(const Symbol s) { return stringhash(s.Chars()); }
  static int Match(const Symbol x, const Symbol y) { return (x._tableElem == y._tableElem); }
  static int HashCase(const Symbol s) { return stringhashcase(s.Chars()); }
  static int MatchCase(const Symbol, const Symbol);

  friend ostream& operator<< (ostream&, const Symbol);
};

ostream& operator<<(ostream&, const Symbol);

class Symbol_Init {
private:
  static unsigned _count;
public:
  Symbol_Init();
  ~Symbol_Init();
};

static Symbol_Init symbolInit;

#endif
