CS143-Lab/assignments/PA4/semant.h
2023-03-24 15:46:11 +00:00

143 lines
3.8 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:
// 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 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) { }
// 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(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;
// 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;
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