diff --git a/assignments/PA4/bad_inherit.cl b/assignments/PA4/bad_inherit.cl index 7d28689..ba6b40f 100644 --- a/assignments/PA4/bad_inherit.cl +++ b/assignments/PA4/bad_inherit.cl @@ -29,17 +29,20 @@ class Ok4 inherits Ok2_2 {}; (* Cool has restrictions on inheriting from basic classes *) -class Err1 inherits Int {}; +(*class Err1 inherits Int {}; class Err3 inherits String {}; class Err3 inherits Bool {}; -class Err4 inherits Err3 {}; -class Err4 inherits NOEXIST {}; +class Err4 inherits Err3 {};*) +class Err4 inherits Ok1 { + bye: SS <- 10; + hello(a: TT) : NOEXIST { new Object }; +}; class Main inherits IO { main(): Object { { - a(); + (new Err4).hell(); } }; }; \ No newline at end of file diff --git a/assignments/PA4/cool-tree.h b/assignments/PA4/cool-tree.h index 6c4223d..79f93bf 100644 --- a/assignments/PA4/cool-tree.h +++ b/assignments/PA4/cool-tree.h @@ -164,6 +164,7 @@ public: Symbol get_name() const { return name; } Symbol get_parent() const { return parent; } Features get_features() const { return features; } + void semant(); #ifdef Class__SHARED_EXTRAS Class__SHARED_EXTRAS @@ -191,6 +192,11 @@ public: Feature copy_Feature(); void dump(ostream& stream, int n); + Symbol get_name() const { return name; }; + Formals get_formals() const { return formals; }; + Symbol get_return_type() const { return return_type; }; + Expression get_expr() const { return expr; }; + #ifdef Feature_SHARED_EXTRAS Feature_SHARED_EXTRAS #endif @@ -215,6 +221,10 @@ public: Feature copy_Feature(); void dump(ostream& stream, int n); + Symbol get_name() const { return name; }; + Symbol get_type_decl() const { return type_decl; }; + Expression get_init() const { return init; }; + #ifdef Feature_SHARED_EXTRAS Feature_SHARED_EXTRAS #endif diff --git a/assignments/PA4/semant.cc b/assignments/PA4/semant.cc index 56cf5ac..c4a9fbd 100644 --- a/assignments/PA4/semant.cc +++ b/assignments/PA4/semant.cc @@ -86,9 +86,14 @@ static void initialize_constants(void) } - +/* +* In ClassTable's constructor, the inheritance graph is built and checked, +* with all defined classes recorded for later check. +* In addition, scan attribute and method definition into global Symbol Table +*/ ClassTable::ClassTable(Classes classes) : semant_errors(0) , error_stream(cerr) { install_basic_classes(); + /* first scan: de-duplicate class definitions*/ std::vector class_vec; for (auto i = classes->first(); classes->more(i); i = classes->next(i)) { auto class_i = static_cast(classes->nth(i)); @@ -96,12 +101,14 @@ ClassTable::ClassTable(Classes classes) : semant_errors(0) , error_stream(cerr) semant_error(class_i) << "Class " << class_i->get_name() << " was previously defined.\n"; } else { - name_to_node[class_i->get_name()] = new ClassGraphNode(class_i, nullptr); // null means we have this class, but not yet build inheritence graph for it + name_to_node[class_i->get_name()] = new ClassGraphNode(class_i, nullptr); + // discard redefined classes by constructing a new vector of classes class_vec.push_back(class_i); } } + /* second scan: check base class inheritable */ auto sym_Bool = idtable.lookup_string("Bool"); auto sym_Int = idtable.lookup_string("Int"); auto sym_String = idtable.lookup_string("String"); @@ -130,6 +137,8 @@ ClassTable::ClassTable(Classes classes) : semant_errors(0) , error_stream(cerr) // In COOL's case, every class could have only one base class // One simple judgement is that, if it cannot go up to object, then the class or its ancestor involves in a cycle // Thus, we can start from object and mark all reachable nodes, error report those unreachable nodes + + /* third scan: check cyclic inheritance */ class_root->traverse(); for (auto i : name_to_node) { if (!i.second->reachable()) { @@ -139,9 +148,41 @@ ClassTable::ClassTable(Classes classes) : semant_errors(0) , error_stream(cerr) } if (semant_errors) return; if (semant_debug) { - std::cout << "Class Inheritance Analysis done.\n"; + std::cerr<< "Class Inheritance Analysis done.\n"; class_root->traverse(std::cout, 0); } + /* fourth scan: gather attr and method definition */ + for (auto class_i : class_vec) { + auto features_i = class_i->get_features(); + auto name_i = class_i->get_name(); + symtab_met[name_i] = new SymbolTable; + symtab_obj[name_i] = new SymbolTable; + symtab_met[name_i]->enterscope(); + symtab_obj[name_i]->enterscope(); + for (auto j = features_i->first(); features_i->more(j); j = features_i->next(j)) { + auto feature_j = features_i->nth(j); + if (typeid(*feature_j) == typeid(attr_class)) { + auto attr_j = static_cast(feature_j); + symtab_obj[name_i]->addid(attr_j->get_name(), attr_j->get_type_decl()); + } + else if (typeid(*feature_j) == typeid(method_class)) { + auto method_j = static_cast(feature_j); + symtab_met[name_i]->addid(method_j->get_name(), method_j); + } + else assert(0); + } + } + if (semant_debug) { + std::cerr << "Attr & Methods Collection done.\n"; + for (auto class_i : class_vec) { + auto name_i = class_i->get_name(); + std::cerr << "M(" << name_i << ") ="; + symtab_met[name_i]->dump(); + std::cerr << "O(" << name_i << ") ="; + symtab_obj[name_i]->dump(); + std::cerr << "--------\n\n"; + } + } } void ClassTable::install_basic_classes() { @@ -316,6 +357,15 @@ void program_class::semant() /* ClassTable constructor may do some semantic analysis */ ClassTable *classtable = new ClassTable(classes); + /* Without confidence in inheritance consistency, abort before type checking*/ + if (classtable->errors()) { + cerr << "Compilation halted due to static semantic errors." << endl; + exit(1); + } + for (auto i = classes->first(); classes->more(i); i = classes->next(i)) { + auto class_i = static_cast(classes->nth(i)); + class_i->semant(); + } /* some semantic analysis code may go here */ if (classtable->errors()) { @@ -324,4 +374,7 @@ void program_class::semant() } } - +void class__class::semant() +{ + +} diff --git a/assignments/PA4/semant.h b/assignments/PA4/semant.h index e8c6694..c66946d 100644 --- a/assignments/PA4/semant.h +++ b/assignments/PA4/semant.h @@ -125,6 +125,10 @@ private: // 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; + public: ClassTable(Classes); int errors() { return semant_errors; }