#ifndef SEMANT_H_ #define SEMANT_H_ #include #include #include #include #include #include #include "cool-tree.h" #include "cool-tree.handcode.h" #include "stringtab.h" #include "symtab.h" #include "list.h" #define TRUE 1 #define FALSE 0 class ClassTable; typedef ClassTable *ClassTableP; // This is a structure that may be used to contain the semantic // information such as the inheritance graph. You may use it or not as // you like: it is only here to provide a container for the supplied // methods. class ClassGraphNode { public: // tree-shape relation maintainer ClassGraphNode* parent; std::vector children; // the `class__class` object for which it builds graph Class_ self; // for cycle detection int depth = 0; public: // Note that, Class_ = Class__class*, itself is a ptr type, so just use it ClassGraphNode(Class_ self_class, ClassGraphNode* parent_class = nullptr) : parent(parent_class), self(self_class) { } // Explicitly disable copy constructor ClassGraphNode(const ClassGraphNode&) = delete; ClassGraphNode& operator=(const ClassGraphNode) = delete; // Long time no C++, god knows if the destructor works or not... ~ ClassGraphNode() { while (!children.empty()) { auto child = children[children.size() - 1]; children.pop_back(); assert(child != nullptr); delete child; } } /* * Create a child node and set child points to child_class */ ClassGraphNode* new_child(Class_ child_class) { for (auto i = children.begin(); i != children.end(); ++ i) { if ((*i)->self == child_class) { // it is okay to judge class by compare node address // because a class cannot be redefined, the AST node is identical return *i; } } ClassGraphNode * newnode = new ClassGraphNode(child_class, this); children.push_back(newnode); return newnode; } /* * Set child_node as this's child, without any memory allocation */ void append_child(ClassGraphNode * child_node) { for (auto i = children.begin(); i != children.end(); ++ i) { if ((*i) == child_node) { return; } } child_node->parent = this; children.push_back(child_node); } /* * traverse and print class name */ void traverse_dump_name(std::ostream& stream, int n) const { dump_Symbol(stream, n, dynamic_cast(self)->get_name()); for (auto child: children) { child->traverse_dump_name(stream, n + 2); } } /* * traverse and mark all reachable children, get their depth as well */ void traverse_reachable(int depth) { this->depth = depth + 1; for (auto child : children) { child->traverse_reachable(depth + 1); } } class__class* get_class() { return static_cast(self); } }; class ClassTable { private: int semant_errors; void install_basic_classes(); void recursive_all_features(); ostream& error_stream; // Root of the Inheritance Graph (hopefully it is a tree if the program is correct) ClassGraphNode* class_root; // again, the correctness of using ptr can be inferred from `Single Copy` of the symbol string // Actually, we could use the provided symbol table instead of a stl map for this // anyways we don't need name shadowing here, I just save my effort std::map name_to_node; // The symbol table only stores pointers, so DATA type defined here dont need a ptr std::map* > _symtab_obj; std::map*> _symtab_met; // Actually, it makes things easier to keep a list-shape copy of classes std::vector _class_vec; public: ClassTable(Classes); /* helpers */ void install_all_features(); void symtab_dump(Symbol); Symbol symtab_object_lookup_parent(Symbol, Symbol) const; Symbol symtab_object_lookup_parent(Class_, Symbol) const; method_class* symtab_method_lookup_parent(Symbol, Symbol) const; method_class* symtab_method_lookup_parent(Class_, Symbol) const; bool conform(Symbol, Symbol) const; bool conform_self(Symbol, Symbol, Symbol) const; bool conform_self(Symbol, Symbol, Class_) const; bool class_defined(Symbol) const; bool class_defined_self(Symbol) const; Symbol lub(Symbol, Symbol) const; Symbol lub(Symbol, Symbol, Symbol) const; static Symbol class_to_name(Class_ class_item) { return static_cast(class_item)->get_name(); } /* wrappers */ std::vector& class_vec() { return _class_vec; } SymbolTable* symtab_obj(Class_ class_i) const; int errors() { return semant_errors; } ostream& semant_error(); ostream& semant_error(Class_ c); ostream& semant_error(Symbol filename, tree_node *t); }; #endif