/** * \file annotator.cpp * \brief Symbol Management * \author Stefan Reuther * * This contains the symbol table and the basic symbol type. */ INTERFACE: #include #include #include #include #include "type_rep.h" class Abstract_scope; /// A symbol. class Symbol { std::string name; std::string::size_type base_len; public: const std::string& get_name() const { return name; } void set_name(const std::string& n, std::string::size_type bl) { name = n; base_len = bl; } enum Kind { // this list must match the array in Symbol::dump k_Variable, k_Namespace, k_Typedef, k_Function, k_Enum, k_ClassOrStruct, k_Union, k_ClassTemplate }; enum Status { /* Symbol has been used indirectly, but not yet defined. For example, "extern int errno" in a function. Must be first so that it converts to false. */ st_Undefined, /* Symbol has been declared but not defined */ st_Declared, /* Symbol has been defined */ st_Defined }; static bool is_tagged(Kind k) { return k >= k_Enum; } bool is_tagged() const { return is_tagged(get_kind()); } Status get_status() const { return status; } bool is_defined() const { return status == st_Defined; } bool is_declared() const { return status >= st_Declared; } virtual Kind get_kind() const = 0; private: Status status; }; /// A symbol table entry. struct Symbol_pair { Symbol* untag; Symbol* tag; Symbol_pair(Symbol* u, Symbol* t) : untag(u), tag(t) { } Symbol_pair() : untag(0), tag(0) { } operator bool() const { return untag != 0; } }; /// A symbol table. class Symbol_table { static Symbol_table instance; typedef std::map content_type; content_type content; public: typedef content_type::const_iterator Sym_it; static Symbol_table& get_instance() { return instance; } static const char* dump_flags; Sym_it begin() const { return content.begin(); } Sym_it end() const { return content.end(); } }; /// A type symbol. Here for simplicity. class Type_symbol : public Symbol { public: void set_defined() { set_status(st_Defined); } }; IMPLEMENTATION: #include #include #include "except.h" #include "scope.h" #include "symbol_name.h" /****************************** Symbol_table *****************************/ Symbol_table Symbol_table::instance; const char* Symbol_table::dump_flags = ""; /** Create new, empty symbol table. Generally, you should use Symbol_table::get_instance() instead of creating new symbol tables. */ PUBLIC Symbol_table::Symbol_table() { } PUBLIC virtual Symbol_table::~Symbol_table() { } /** Add a symbol. Throws exception on error. */ PUBLIC void Symbol_table::add_symbol(std::string name, std::string::size_type base_len, Symbol* sym) { content_type::iterator i = content.find(name); if (i != content.end()) { /* symbol already there; for example, `int stat(...)' and `struct stat' */ if (sym->is_tagged()) { if (!i->second.tag || i->second.tag == i->second.untag) /* function there, structure being added. I guess the second part can't happen */ i->second.tag = sym; else compile_error("redeclaration of `" + name + "' not allowed"); } else { if (i->second.tag == i->second.untag) /* structure already there, function being added */ i->second.untag = sym; else compile_error("redeclaration of `" + name + "' not allowed"); } } else { /* symbol does not exist yet */ if (sym->is_tagged()) content[name] = Symbol_pair(sym, sym); else content[name] = Symbol_pair(sym, 0); } sym->set_name(name, base_len); } /** Set "peer" of a symbol. This is used for the construction "typedef class A {} B;". In that case, "B" becomes an alternate name for A. Hence, the "untag" slot of the symbol B contains the typedef, the "tag" slot becomes the base type. */ PUBLIC void Symbol_table::set_peer(Symbol* orig, Symbol* faelschung) { assert(!orig->is_tagged()); assert(faelschung->is_tagged()); content[orig->get_name()].tag = faelschung; } /** Fetch a symbol. Returns the symbol table entry. */ PUBLIC Symbol_pair Symbol_table::get_symbol(std::string name) const { content_type::const_iterator i = content.find(name); if (i != content.end()) return i->second; else return Symbol_pair(0, 0); } /** Dump symbol table to /out/. */ PUBLIC void Symbol_table::dump(std::ostream& out) { for (content_type::const_iterator i = content.begin(); i != content.end(); ++i) { out << i->first << ":\n"; i->second.untag->dump(out); out << "\n"; if (i->second.tag && i->second.tag != i->second.untag) i->second.tag->dump(out), out << "\n"; } } PUBLIC static bool Symbol_table::has_dump_flag(char c) { const char* p = dump_flags; while (*p) if (*p++ == c) return true; return false; } PUBLIC void Symbol_table::clear() { content_type().swap(content); } /********************************* Symbol ********************************/ PUBLIC inline Symbol::Symbol() : name(), base_len(0), status(st_Undefined) { // std::cout << "make " << (void*)this << "\n"; } PUBLIC virtual Symbol::~Symbol() { // std::cout << "destroy " << (void*)this << "\n"; } /** If this symbol names a scope, return that scope. Otherwise, return 0 */ PUBLIC virtual Abstract_scope* Symbol::get_scope() { return 0; } /** Set status of this symbol. */ PUBLIC void Symbol::set_status(Status st) { assert(st >= status); // we can only raise the status, // there's no way to undefine // something status = st; } PUBLIC std::string Symbol::get_basename() const { // return name.substr(name.length() - base_len); return Symbol_name::get_basename_from_symbol(name, base_len); } /** Dump symbol on /out/. Derived classes can override this to add own information. */ PUBLIC virtual void Symbol::dump(std::ostream& out) { static const char*const names[] = { "variable", "namespace", "typedef", "function", "enum", "class", "union", "class template" }; const char* st = is_defined() ? "" : is_declared() ? "undefined " : "undeclared "; out << "- " << st << names[get_kind()]; } /**************************** Type_symbol ****************************/ PUBLIC Type_symbol::Type_symbol() : Symbol() { } PUBLIC Type_symbol::~Type_symbol() { } /** Get this type's internal representation. */ PUBLIC Type Type_symbol::get_type() const { return Type::get_named_type(get_name()); }