CS143-Lab/assignments/PA4/semant.h
2023-03-27 19:12:54 +08:00

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