class Racc::SymbolTable

def [](id)

def [](id)
  @symbols[id]
end

def check_terminals

def check_terminals
  return unless @symbols.any? {|s| s.should_terminal? }
  @anchor.should_terminal
  @error.should_terminal
  each_terminal do |t|
    t.should_terminal if t.string_symbol?
  end
  each do |s|
    s.should_terminal if s.assoc
  end
  terminals().reject {|t| t.should_terminal? }.each do |t|
    raise CompileError, "terminal #{t} not declared as terminal"
  end
  nonterminals().select {|n| n.should_terminal? }.each do |n|
    raise CompileError, "symbol #{n} declared as terminal but is not terminal"
  end
end

def delete(sym)

def delete(sym)
  @symbols.delete sym
  @cache.delete sym.value
end

def each(&block)

def each(&block)
  @symbols.each(&block)
end

def each_nonterminal(&block)

def each_nonterminal(&block)
  @nterms.each(&block)
end

def each_terminal(&block)

def each_terminal(&block)
  @terms.each(&block)
end

def fix

def fix
  terms, nterms = @symbols.partition {|s| s.terminal? }
  @symbols = terms + nterms
  @terms = terms
  @nterms = nterms
  @nt_base = terms.size
  fix_ident
  check_terminals
end

def fix_ident

def fix_ident
  @symbols.each_with_index do |t, i|
    t.ident = i
  end
end

def initialize

def initialize
  @symbols = []   # :: [Racc::Sym]
  @cache   = {}   # :: {(String|Symbol) => Racc::Sym}
  @dummy  = intern(:$start, true)
  @anchor = intern(false, true)     # Symbol ID = 0
  @error  = intern(:error, false)   # Symbol ID = 1
end

def intern(val, dummy = false)

def intern(val, dummy = false)
  @cache[val] ||=
      begin
        sym = Sym.new(val, dummy)
        @symbols.push sym
        sym
      end
end

def nonterminals

def nonterminals
  @symbols[@nt_base, @symbols.size - @nt_base]
end

def nt_max

def nt_max
  @symbols.size
end

def terminals(&block)

def terminals(&block)
  @symbols[0, @nt_base]
end