ready to restructure for more complecated check:
This commit is contained in:
@ -16,6 +16,7 @@ class ASTNodeVisitorBase {
|
|||||||
|
|
||||||
class ASTNodeBase {
|
class ASTNodeBase {
|
||||||
friend Visitor;
|
friend Visitor;
|
||||||
|
friend std::shared_ptr<Program_ASTNode> CheckAndDecorate(std::shared_ptr<Program_ASTNode> src);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<ScopeBase> current_scope;
|
std::shared_ptr<ScopeBase> current_scope;
|
||||||
|
@ -32,6 +32,13 @@ class LocalScope : public ScopeBase {
|
|||||||
if (!VariableNameAvailable(name, 0)) {
|
if (!VariableNameAvailable(name, 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (std::holds_alternative<IdentifierType>(type) && std::get<IdentifierType>(type) == "void") {
|
||||||
|
throw SemanticError("Variable cannot be void", 1);
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<ArrayType>(type) && std::get<ArrayType>(type).has_base_type &&
|
||||||
|
std::get<ArrayType>(type).basetype == "void") {
|
||||||
|
throw SemanticError("Variable cannot be void", 1);
|
||||||
|
}
|
||||||
local_variables[name] = type;
|
local_variables[name] = type;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -53,6 +60,7 @@ struct FunctionSchema {
|
|||||||
std::vector<std::pair<ExprTypeInfo, std::string>> arguments;
|
std::vector<std::pair<ExprTypeInfo, std::string>> arguments;
|
||||||
};
|
};
|
||||||
class FunctionScope : public ScopeBase {
|
class FunctionScope : public ScopeBase {
|
||||||
|
friend std::shared_ptr<class Program_ASTNode> CheckAndDecorate(std::shared_ptr<class Program_ASTNode> src);
|
||||||
friend class Visitor;
|
friend class Visitor;
|
||||||
FunctionSchema schema;
|
FunctionSchema schema;
|
||||||
bool add_variable([[maybe_unused]] const std::string &name, [[maybe_unused]] const ExprTypeInfo &type) override {
|
bool add_variable([[maybe_unused]] const std::string &name, [[maybe_unused]] const ExprTypeInfo &type) override {
|
||||||
@ -80,6 +88,13 @@ class ClassDefScope : public ScopeBase {
|
|||||||
if (!VariableNameAvailable(name, 0)) {
|
if (!VariableNameAvailable(name, 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (std::holds_alternative<IdentifierType>(type) && std::get<IdentifierType>(type) == "void") {
|
||||||
|
throw SemanticError("Variable cannot be void", 1);
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<ArrayType>(type) && std::get<ArrayType>(type).has_base_type &&
|
||||||
|
std::get<ArrayType>(type).basetype == "void") {
|
||||||
|
throw SemanticError("Variable cannot be void", 1);
|
||||||
|
}
|
||||||
member_variables[name] = type;
|
member_variables[name] = type;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -111,6 +126,7 @@ class ClassDefScope : public ScopeBase {
|
|||||||
};
|
};
|
||||||
class GlobalScope : public ScopeBase {
|
class GlobalScope : public ScopeBase {
|
||||||
friend class Visitor;
|
friend class Visitor;
|
||||||
|
friend std::shared_ptr<class Program_ASTNode> CheckAndDecorate(std::shared_ptr<class Program_ASTNode> src);
|
||||||
std::unordered_map<std::string, ExprTypeInfo> global_variables;
|
std::unordered_map<std::string, ExprTypeInfo> global_variables;
|
||||||
std::unordered_map<std::string, std::shared_ptr<FunctionScope>> global_functions;
|
std::unordered_map<std::string, std::shared_ptr<FunctionScope>> global_functions;
|
||||||
std::unordered_map<std::string, std::shared_ptr<ClassDefScope>> classes;
|
std::unordered_map<std::string, std::shared_ptr<ClassDefScope>> classes;
|
||||||
@ -146,6 +162,13 @@ class GlobalScope : public ScopeBase {
|
|||||||
if (!VariableNameAvailable(name, 0)) {
|
if (!VariableNameAvailable(name, 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (std::holds_alternative<IdentifierType>(type) && std::get<IdentifierType>(type) == "void") {
|
||||||
|
throw SemanticError("Variable cannot be void", 1);
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<ArrayType>(type) && std::get<ArrayType>(type).has_base_type &&
|
||||||
|
std::get<ArrayType>(type).basetype == "void") {
|
||||||
|
throw SemanticError("Variable cannot be void", 1);
|
||||||
|
}
|
||||||
global_variables[name] = type;
|
global_variables[name] = type;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,19 @@ class MXErrorListener : public antlr4::BaseErrorListener {
|
|||||||
std::shared_ptr<Program_ASTNode> BuildAST(Visitor *visitor, antlr4::tree::ParseTree *tree) {
|
std::shared_ptr<Program_ASTNode> BuildAST(Visitor *visitor, antlr4::tree::ParseTree *tree) {
|
||||||
return std::any_cast<std::shared_ptr<Program_ASTNode>>(visitor->visit(tree));
|
return std::any_cast<std::shared_ptr<Program_ASTNode>>(visitor->visit(tree));
|
||||||
}
|
}
|
||||||
std::shared_ptr<Program_ASTNode> CheckAndDecorate(std::shared_ptr<Program_ASTNode> src) { return nullptr; }
|
std::shared_ptr<Program_ASTNode> CheckAndDecorate(std::shared_ptr<Program_ASTNode> src) {
|
||||||
|
auto global_scope = std::dynamic_pointer_cast<GlobalScope>(src->current_scope);
|
||||||
|
if (global_scope->global_functions.find("main") == global_scope->global_functions.end()) {
|
||||||
|
throw SemanticError("No main() function", 1);
|
||||||
|
} else {
|
||||||
|
const auto &main_schema = global_scope->global_functions["main"]->schema;
|
||||||
|
if ((!std::holds_alternative<IdentifierType>(main_schema.return_type)) ||
|
||||||
|
std::get<IdentifierType>(main_schema.return_type) != "int" || main_schema.arguments.size() != 0) {
|
||||||
|
throw SemanticError("main() function should be int main()", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
void SemanticCheck(std::istream &fin, std::shared_ptr<Program_ASTNode> &ast_out) {
|
void SemanticCheck(std::istream &fin, std::shared_ptr<Program_ASTNode> &ast_out) {
|
||||||
antlr4::ANTLRInputStream input(fin);
|
antlr4::ANTLRInputStream input(fin);
|
||||||
|
@ -629,15 +629,25 @@ std::any Visitor::visitNew_array_expression(MXParser::New_array_expressionContex
|
|||||||
std::string base_type = context->type()->getText();
|
std::string base_type = context->type()->getText();
|
||||||
new_array->expr_type_info = ArrayType{true, base_type, total_dimensions};
|
new_array->expr_type_info = ArrayType{true, base_type, total_dimensions};
|
||||||
size_t total_dim_count = 0;
|
size_t total_dim_count = 0;
|
||||||
|
bool dim_size_specified = false;
|
||||||
|
bool dim_with_size_end = false;
|
||||||
new_array->dim_size.resize(total_dimensions);
|
new_array->dim_size.resize(total_dimensions);
|
||||||
for (size_t i = 3; i < context->children.size() && total_dim_count < total_dimensions; i++) {
|
for (size_t i = 3; i < context->children.size() && total_dim_count < total_dimensions; i++) {
|
||||||
if (dynamic_cast<antlr4::tree::TerminalNode *>(context->children[i]) != nullptr &&
|
if (dynamic_cast<antlr4::tree::TerminalNode *>(context->children[i]) != nullptr &&
|
||||||
dynamic_cast<antlr4::tree::TerminalNode *>(context->children[i])->getSymbol()->getType() ==
|
dynamic_cast<antlr4::tree::TerminalNode *>(context->children[i])->getSymbol()->getType() ==
|
||||||
MXParser::RBRACKET) {
|
MXParser::RBRACKET) {
|
||||||
total_dim_count++;
|
total_dim_count++;
|
||||||
|
if (!dim_size_specified) {
|
||||||
|
dim_with_size_end = true;
|
||||||
|
}
|
||||||
|
dim_size_specified = false;
|
||||||
} else if (dynamic_cast<MXParser::ExprContext *>(context->children[i]) != nullptr) {
|
} else if (dynamic_cast<MXParser::ExprContext *>(context->children[i]) != nullptr) {
|
||||||
new_array->dim_size[total_dim_count] = std::any_cast<std::shared_ptr<Expr_ASTNode>>(visit(context->children[i]));
|
new_array->dim_size[total_dim_count] = std::any_cast<std::shared_ptr<Expr_ASTNode>>(visit(context->children[i]));
|
||||||
std::cerr << std::string(nodetype_stk.size() * 2, ' ') << "dim " << total_dim_count << " has size " << std::endl;
|
std::cerr << std::string(nodetype_stk.size() * 2, ' ') << "dim " << total_dim_count << " has size " << std::endl;
|
||||||
|
dim_size_specified = true;
|
||||||
|
if (dim_with_size_end) {
|
||||||
|
throw SemanticError("The shape of multidimensional array must be specified from left to right.", 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (context->constant() != nullptr) {
|
if (context->constant() != nullptr) {
|
||||||
|
Reference in New Issue
Block a user