#ifndef __SYMBOL_HPP__
#define __SYMBOL_HPP__

enum Type { TYPE_int, TYPE_bool };

struct STEntry {
  Type type;
  int  offset;
  STEntry() {}
  STEntry(Type t, int o) : type(t), offset(o) {}
};

class Scope {
 public:
  Scope() {}
  Scope(int o) : offset(o) {}
  void insert(char v, Type t) {
    if (locals.find(v) != locals.end())
      yyerror("Duplicate variable declaration");
    locals[v] = STEntry(t, offset++);
  }
  STEntry *lookup(char v) {
    if (locals.find(v) == locals.end()) return nullptr;
    return &(locals[v]);
  }
  int get_offset() { return offset; }
 private:
  std::map<char, STEntry> locals;
  int offset;
};

class SymbolTable {
 public:
  void insert(char v, Type t) {
    scopes.back().insert(v, t);
  }
  STEntry *lookup(char v) {
    for (auto s = scopes.rbegin(); s != scopes.rend(); ++s) {
      STEntry *e = s->lookup(v);
      if (e != nullptr) return e;
    }
    yyerror("Variable not found");
    return nullptr;
  }
  void enterScope() {
    int o = scopes.empty() ? 0 : scopes.back().get_offset();
    scopes.push_back(Scope(o));
  }
  void exitScope() {
    scopes.pop_back();
  }
 private:
  std::vector<Scope> scopes;
};

extern SymbolTable st;

#endif
