163 lines
4.8 KiB
C++
163 lines
4.8 KiB
C++
#ifndef SEMANT_H_
|
|
#define SEMANT_H_
|
|
|
|
#include <assert.h>
|
|
#include <cstddef>
|
|
#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 {
|
|
public:
|
|
// tree-shape relation maintainer
|
|
ClassGraphNode* parent;
|
|
std::vector<ClassGraphNode*> 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<class__class*>(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<class__class*>(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<Symbol, ClassGraphNode*> name_to_node;
|
|
|
|
// The symbol table only stores pointers, so DATA type defined here dont need a ptr
|
|
std::map<Symbol, SymbolTable<Symbol, Entry>* > _symtab_obj;
|
|
std::map<Symbol, SymbolTable<Symbol, method_class>*> _symtab_met;
|
|
|
|
// Actually, it makes things easier to keep a list-shape copy of classes
|
|
std::vector<class__class*> _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__class*>(class_item)->get_name(); }
|
|
|
|
/* wrappers */
|
|
std::vector<class__class*>& class_vec() { return _class_vec; }
|
|
SymbolTable<Symbol, Entry>* 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
|
|
|