#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 reachable = 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 */ void traverse_reachable() { reachable = 1; for (auto child : children) { child->traverse_reachable(); } } class__class* get_class() { return static_cast(self); } // static void traverse_iter(ClassGraphNode* root) { // auto cur_node = root; // std::vector stk; // stk.push_back(0); // std::cout << pad((stk.size()-1) * 4) << cur_node->get_class()->get_name() << "\n"; // while (!stk.empty()) { // if (cur_node->children.size() == stk.back()) { // // we have finished all the children // stk.pop_back(); // cur_node = cur_node->parent; // continue; // } // auto next_idx = stk.back(); // stk.pop_back(); // stk.push_back(next_idx + 1); // cur_node = cur_node->children[next_idx]; // std::cout << pad((stk.size()) * 2) << cur_node->get_class()->get_name() << "\n"; // stk.push_back(0); // } // } }; // First we need a tree-like struct to store inheritence relationship // Since class doesn't need to be defined before used, I guess first 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); void install_all_features(); void symtab_dump(Symbol); Symbol symtab_object_lookup_parent(Symbol, Symbol); method_class* symtab_method_lookup_parent(Symbol, Symbol); std::vector& class_vec() { return _class_vec; } int errors() { return semant_errors; } ostream& semant_error(); ostream& semant_error(Class_ c); ostream& semant_error(Symbol filename, tree_node *t); }; #endif