130 lines
3.2 KiB
C++
130 lines
3.2 KiB
C++
#ifndef SEMANT_H_
|
|
#define SEMANT_H_
|
|
|
|
#include <assert.h>
|
|
#include <iostream>
|
|
#include <ostream>
|
|
#include <vector>
|
|
#include <map>
|
|
#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 {
|
|
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 {
|
|
private:
|
|
int semant_errors;
|
|
void install_basic_classes();
|
|
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:
|
|
ClassTable(Classes);
|
|
int errors() { return semant_errors; }
|
|
ostream& semant_error();
|
|
ostream& semant_error(Class_ c);
|
|
ostream& semant_error(Symbol filename, tree_node *t);
|
|
};
|
|
|
|
|
|
#endif
|
|
|