inheritance analysis
This commit is contained in:
parent
8fe45fc17c
commit
67b8d25d85
37
assignments/PA4/bad_inherit.cl
Normal file
37
assignments/PA4/bad_inherit.cl
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
(* The inheritance analysis has 2 stages, graph construction & cyclic checking.
|
||||||
|
it will abort if duplicate or undefined class definitions are found before do cyclic checking *)
|
||||||
|
-- uncomment the lines below to get convinced that 1st stage works
|
||||||
|
(*
|
||||||
|
class DupDef {};
|
||||||
|
|
||||||
|
class DupDef {};
|
||||||
|
|
||||||
|
class DupDef1 {};
|
||||||
|
|
||||||
|
class DupDef1 {};
|
||||||
|
|
||||||
|
class A inherits SCHEISSE{};
|
||||||
|
*)
|
||||||
|
(*
|
||||||
|
class D inherits D {};
|
||||||
|
|
||||||
|
class Cycle1 inherits Cycle2 {};
|
||||||
|
class Cycle2 inherits Cycle3 {};
|
||||||
|
class Cycle3 inherits Cycle1 {};
|
||||||
|
|
||||||
|
class Cycle4 inherits Cycle3 {};
|
||||||
|
*)
|
||||||
|
class Ok1{};
|
||||||
|
class Ok2_1 inherits Ok1 {};
|
||||||
|
class Ok2_2 inherits Ok1 {};
|
||||||
|
class Ok3 inherits Ok2_1 {};
|
||||||
|
class Ok4 inherits Ok2_2 {};
|
||||||
|
|
||||||
|
|
||||||
|
class Main inherits IO {
|
||||||
|
main(): Object {
|
||||||
|
{
|
||||||
|
a();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -161,6 +161,9 @@ public:
|
|||||||
}
|
}
|
||||||
Class_ copy_Class_();
|
Class_ copy_Class_();
|
||||||
void dump(ostream& stream, int n);
|
void dump(ostream& stream, int n);
|
||||||
|
Symbol get_name() const { return name; }
|
||||||
|
Symbol get_parent() const { return parent; }
|
||||||
|
Features get_features() const { return features; }
|
||||||
|
|
||||||
#ifdef Class__SHARED_EXTRAS
|
#ifdef Class__SHARED_EXTRAS
|
||||||
Class__SHARED_EXTRAS
|
Class__SHARED_EXTRAS
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <utility>
|
||||||
|
#include "cool-tree.h"
|
||||||
#include "semant.h"
|
#include "semant.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
@ -84,9 +87,48 @@ static void initialize_constants(void)
|
|||||||
|
|
||||||
|
|
||||||
ClassTable::ClassTable(Classes classes) : semant_errors(0) , error_stream(cerr) {
|
ClassTable::ClassTable(Classes classes) : semant_errors(0) , error_stream(cerr) {
|
||||||
|
install_basic_classes();
|
||||||
|
for (auto i = classes->first(); classes->more(i); i = classes->next(i)) {
|
||||||
|
auto class_i = static_cast<class__class*>(classes->nth(i));
|
||||||
|
if (name_to_node.find(class_i->get_name()) != name_to_node.end()) {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto i = classes->first(); classes->more(i); i = classes->next(i)) {
|
||||||
|
auto class_i = static_cast<class__class*>(classes->nth(i));
|
||||||
|
if (name_to_node.find(class_i->get_parent()) == name_to_node.end()) {
|
||||||
|
semant_error(class_i) << "Class `" << class_i->get_name() << "` inherits from an undefined class `"
|
||||||
|
<< class_i->get_parent() << "`\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto class_parent = name_to_node[class_i->get_parent()];
|
||||||
|
assert(class_parent != nullptr);
|
||||||
|
class_parent->append_child(name_to_node[class_i->get_name()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Fill this in */
|
if (semant_errors) return;
|
||||||
|
// we abort here before check cyclic inheritence if error once occurred
|
||||||
|
|
||||||
|
// 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
|
||||||
|
class_root->traverse();
|
||||||
|
for (auto i : name_to_node) {
|
||||||
|
if (!i.second->reachable()) {
|
||||||
|
semant_error(i.second->get_class()) << "Class `" << i.first
|
||||||
|
<< "` or its ancestor, is involved in an inheritance cycle.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (semant_errors) return;
|
||||||
|
if (semant_debug) {
|
||||||
|
std::cout << "Class Inheritance Analysis done.\n";
|
||||||
|
class_root->traverse(std::cout, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassTable::install_basic_classes() {
|
void ClassTable::install_basic_classes() {
|
||||||
@ -188,6 +230,23 @@ void ClassTable::install_basic_classes() {
|
|||||||
Str,
|
Str,
|
||||||
no_expr()))),
|
no_expr()))),
|
||||||
filename);
|
filename);
|
||||||
|
auto object_class = static_cast<class__class*>(Object_class);
|
||||||
|
auto io_class = static_cast<class__class*>(IO_class);
|
||||||
|
auto bool_class = static_cast<class__class*>(Bool_class);
|
||||||
|
auto int_class = static_cast<class__class*>(Int_class);
|
||||||
|
auto str_class = static_cast<class__class*>(Str_class);
|
||||||
|
|
||||||
|
class_root = new ClassGraphNode(Object_class, nullptr);
|
||||||
|
name_to_node[object_class->get_name()] = class_root;
|
||||||
|
name_to_node[io_class->get_name()] = class_root->new_child(IO_class);
|
||||||
|
name_to_node[int_class->get_name()] = class_root->new_child(Int_class);
|
||||||
|
name_to_node[bool_class->get_name()] = class_root->new_child(Bool_class);
|
||||||
|
name_to_node[str_class->get_name()] = class_root->new_child(Str_class);
|
||||||
|
|
||||||
|
if (semant_debug) {
|
||||||
|
std::cout << "Basic classed installed\n";
|
||||||
|
class_root->traverse(std::cout, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@ -2,8 +2,12 @@
|
|||||||
#define SEMANT_H_
|
#define SEMANT_H_
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
#include "cool-tree.h"
|
#include "cool-tree.h"
|
||||||
|
#include "cool-tree.handcode.h"
|
||||||
#include "stringtab.h"
|
#include "stringtab.h"
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
@ -19,11 +23,98 @@ typedef ClassTable *ClassTableP;
|
|||||||
// you like: it is only here to provide a container for the supplied
|
// you like: it is only here to provide a container for the supplied
|
||||||
// methods.
|
// methods.
|
||||||
|
|
||||||
|
class ClassGraphNode {
|
||||||
|
private:
|
||||||
|
ClassGraphNode* parent;
|
||||||
|
std::vector<ClassGraphNode*> children;
|
||||||
|
Class_ self;
|
||||||
|
int mark = 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) { }
|
||||||
|
ClassGraphNode(const ClassGraphNode&) = delete;
|
||||||
|
ClassGraphNode& operator=(const ClassGraphNode) = delete;
|
||||||
|
~ ClassGraphNode() {
|
||||||
|
// Long time no C++, god knows if the destructor works or not...
|
||||||
|
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(std::ostream& stream, int n) const {
|
||||||
|
dump_Symbol(stream, n, dynamic_cast<class__class*>(self)->get_name());
|
||||||
|
for (auto child: children) {
|
||||||
|
child->traverse(stream, n + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* traverse and mark all reachable children
|
||||||
|
*/
|
||||||
|
void traverse() {
|
||||||
|
mark = 1;
|
||||||
|
for (auto child : children) {
|
||||||
|
child->traverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reachable() {
|
||||||
|
return !(mark == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Class_ get_class() {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 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 {
|
class ClassTable {
|
||||||
private:
|
private:
|
||||||
int semant_errors;
|
int semant_errors;
|
||||||
void install_basic_classes();
|
void install_basic_classes();
|
||||||
ostream& error_stream;
|
ostream& error_stream;
|
||||||
|
ClassGraphNode* class_root;
|
||||||
|
std::map<Symbol, ClassGraphNode*> name_to_node;
|
||||||
|
// again, the correctness of using ptr can be inferred from `Single Copy` of the symbol string
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ClassTable(Classes);
|
ClassTable(Classes);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user