|
|
|
|
@ -1,200 +1,446 @@
|
|
|
|
|
#include "sem/Sema.h"
|
|
|
|
|
|
|
|
|
|
#include <any>
|
|
|
|
|
#include "../../include/sem/Sema.h"
|
|
|
|
|
#include "SysYParser.h"
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
#include "SysYBaseVisitor.h"
|
|
|
|
|
#include "sem/SymbolTable.h"
|
|
|
|
|
#include "utils/Log.h"
|
|
|
|
|
using namespace antlr4;
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
// ===================== 核心访问器实现 =====================
|
|
|
|
|
|
|
|
|
|
std::string GetLValueName(SysYParser::LValueContext& lvalue) {
|
|
|
|
|
if (!lvalue.ID()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "非法左值"));
|
|
|
|
|
}
|
|
|
|
|
return lvalue.ID()->getText();
|
|
|
|
|
// 1. 编译单元节点访问
|
|
|
|
|
std::any SemaVisitor::visitCompUnit(SysYParser::CompUnitContext* ctx) {
|
|
|
|
|
// 分析编译单元中的所有子节点
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class SemaVisitor final : public SysYBaseVisitor {
|
|
|
|
|
public:
|
|
|
|
|
std::any visitCompUnit(SysYParser::CompUnitContext* ctx) override {
|
|
|
|
|
if (!ctx) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "缺少编译单元"));
|
|
|
|
|
}
|
|
|
|
|
auto* func = ctx->funcDef();
|
|
|
|
|
if (!func || !func->blockStmt()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "缺少 main 函数定义"));
|
|
|
|
|
// 2. 函数定义节点访问
|
|
|
|
|
std::any SemaVisitor::visitFuncDef(SysYParser::FuncDefContext* ctx) {
|
|
|
|
|
FuncInfo info;
|
|
|
|
|
|
|
|
|
|
// 通过funcType()获取函数类型
|
|
|
|
|
if (ctx->funcType()) {
|
|
|
|
|
std::string func_type_text = ctx->funcType()->getText();
|
|
|
|
|
if (func_type_text == "void") {
|
|
|
|
|
info.ret_type = SymbolType::TYPE_VOID;
|
|
|
|
|
} else if (func_type_text == "int") {
|
|
|
|
|
info.ret_type = SymbolType::TYPE_INT;
|
|
|
|
|
} else if (func_type_text == "float") {
|
|
|
|
|
info.ret_type = SymbolType::TYPE_FLOAT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!func->ID() || func->ID()->getText() != "main") {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "缺少 main 函数定义"));
|
|
|
|
|
}
|
|
|
|
|
func->accept(this);
|
|
|
|
|
if (!seen_return_) {
|
|
|
|
|
throw std::runtime_error(
|
|
|
|
|
FormatError("sema", "main 函数必须包含 return 语句"));
|
|
|
|
|
|
|
|
|
|
// 绑定函数名和返回类型
|
|
|
|
|
if (ctx->Ident()) {
|
|
|
|
|
info.name = ctx->Ident()->getText();
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
ir_ctx_.SetCurrentFuncReturnType(info.ret_type);
|
|
|
|
|
|
|
|
|
|
std::any visitFuncDef(SysYParser::FuncDefContext* ctx) override {
|
|
|
|
|
if (!ctx || !ctx->blockStmt()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "缺少 main 函数定义"));
|
|
|
|
|
// 递归分析函数体
|
|
|
|
|
if (ctx->block()) {
|
|
|
|
|
visit(ctx->block());
|
|
|
|
|
}
|
|
|
|
|
if (!ctx->funcType() || !ctx->funcType()->INT()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "当前仅支持 int main"));
|
|
|
|
|
|
|
|
|
|
return std::any();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. 声明节点访问
|
|
|
|
|
std::any SemaVisitor::visitDecl(SysYParser::DeclContext* ctx) {
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. 常量声明节点访问
|
|
|
|
|
std::any SemaVisitor::visitConstDecl(SysYParser::ConstDeclContext* ctx) {
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. 变量声明节点访问
|
|
|
|
|
std::any SemaVisitor::visitVarDecl(SysYParser::VarDeclContext* ctx) {
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6. 代码块节点访问
|
|
|
|
|
std::any SemaVisitor::visitBlock(SysYParser::BlockContext* ctx) {
|
|
|
|
|
// 进入新的作用域
|
|
|
|
|
ir_ctx_.EnterScope();
|
|
|
|
|
|
|
|
|
|
// 访问块内的语句
|
|
|
|
|
std::any result = visitChildren(ctx);
|
|
|
|
|
|
|
|
|
|
// 离开作用域
|
|
|
|
|
ir_ctx_.LeaveScope();
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 7. 语句节点访问
|
|
|
|
|
std::any SemaVisitor::visitStmt(SysYParser::StmtContext* ctx) {
|
|
|
|
|
// 赋值语句:lVal = exp;
|
|
|
|
|
if (ctx->lVal() && ctx->exp()) {
|
|
|
|
|
auto l_val_ctx = ctx->lVal();
|
|
|
|
|
auto exp_ctx = ctx->exp();
|
|
|
|
|
|
|
|
|
|
// 解析左右值类型
|
|
|
|
|
SymbolType l_type = ir_ctx_.GetType(l_val_ctx);
|
|
|
|
|
SymbolType r_type = ir_ctx_.GetType(exp_ctx);
|
|
|
|
|
|
|
|
|
|
// 类型不匹配报错
|
|
|
|
|
if (l_type != r_type && l_type != SymbolType::TYPE_UNKNOWN && r_type != SymbolType::TYPE_UNKNOWN) {
|
|
|
|
|
std::string l_type_str = (l_type == SymbolType::TYPE_INT ? "int" : "float");
|
|
|
|
|
std::string r_type_str = (r_type == SymbolType::TYPE_INT ? "int" : "float");
|
|
|
|
|
std::string err_msg = "赋值类型不匹配,左值为" + l_type_str + ",右值为" + r_type_str;
|
|
|
|
|
|
|
|
|
|
int line = ctx->getStart()->getLine();
|
|
|
|
|
int col = ctx->getStart()->getCharPositionInLine() + 1;
|
|
|
|
|
ir_ctx_.RecordError(ErrorMsg(err_msg, line, col));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 绑定左值类型(同步右值类型)
|
|
|
|
|
ir_ctx_.SetType(l_val_ctx, r_type);
|
|
|
|
|
}
|
|
|
|
|
const auto& items = ctx->blockStmt()->blockItem();
|
|
|
|
|
if (items.empty()) {
|
|
|
|
|
throw std::runtime_error(
|
|
|
|
|
FormatError("sema", "main 函数不能为空,且必须以 return 结束"));
|
|
|
|
|
// IF语句
|
|
|
|
|
else if (ctx->cond() && ctx->stmt().size() >= 1) {
|
|
|
|
|
auto cond_ctx = ctx->cond();
|
|
|
|
|
|
|
|
|
|
// IF条件必须为整型
|
|
|
|
|
SymbolType cond_type = ir_ctx_.GetType(cond_ctx);
|
|
|
|
|
if (cond_type != SymbolType::TYPE_INT && cond_type != SymbolType::TYPE_UNKNOWN) {
|
|
|
|
|
int line = cond_ctx->getStart()->getLine();
|
|
|
|
|
int col = cond_ctx->getStart()->getCharPositionInLine() + 1;
|
|
|
|
|
ir_ctx_.RecordError(ErrorMsg("if条件表达式必须为整型", line, col));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 递归分析IF体和可能的ELSE体
|
|
|
|
|
visit(ctx->stmt(0));
|
|
|
|
|
if (ctx->stmt().size() >= 2) {
|
|
|
|
|
visit(ctx->stmt(1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ctx->blockStmt()->accept(this);
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
// WHILE语句
|
|
|
|
|
else if (ctx->cond() && ctx->stmt().size() >= 1) {
|
|
|
|
|
ir_ctx_.EnterLoop(); // 标记进入循环
|
|
|
|
|
|
|
|
|
|
auto cond_ctx = ctx->cond();
|
|
|
|
|
// WHILE条件必须为整型
|
|
|
|
|
SymbolType cond_type = ir_ctx_.GetType(cond_ctx);
|
|
|
|
|
if (cond_type != SymbolType::TYPE_INT && cond_type != SymbolType::TYPE_UNKNOWN) {
|
|
|
|
|
int line = cond_ctx->getStart()->getLine();
|
|
|
|
|
int col = cond_ctx->getStart()->getCharPositionInLine() + 1;
|
|
|
|
|
ir_ctx_.RecordError(ErrorMsg("while条件表达式必须为整型", line, col));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::any visitBlockStmt(SysYParser::BlockStmtContext* ctx) override {
|
|
|
|
|
if (!ctx) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "缺少语句块"));
|
|
|
|
|
}
|
|
|
|
|
const auto& items = ctx->blockItem();
|
|
|
|
|
for (size_t i = 0; i < items.size(); ++i) {
|
|
|
|
|
auto* item = items[i];
|
|
|
|
|
if (!item) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (seen_return_) {
|
|
|
|
|
throw std::runtime_error(
|
|
|
|
|
FormatError("sema", "return 必须是 main 函数中的最后一条语句"));
|
|
|
|
|
}
|
|
|
|
|
current_item_index_ = i;
|
|
|
|
|
total_items_ = items.size();
|
|
|
|
|
item->accept(this);
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::any visitBlockItem(SysYParser::BlockItemContext* ctx) override {
|
|
|
|
|
if (!ctx) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "暂不支持的语句或声明"));
|
|
|
|
|
// 递归分析循环体
|
|
|
|
|
visit(ctx->stmt(0));
|
|
|
|
|
|
|
|
|
|
ir_ctx_.ExitLoop(); // 标记退出循环
|
|
|
|
|
}
|
|
|
|
|
if (ctx->decl()) {
|
|
|
|
|
ctx->decl()->accept(this);
|
|
|
|
|
return {};
|
|
|
|
|
// BREAK语句
|
|
|
|
|
else if (ctx->getText().find("break") != std::string::npos) {
|
|
|
|
|
if (!ir_ctx_.InLoop()) {
|
|
|
|
|
int line = ctx->getStart()->getLine();
|
|
|
|
|
int col = ctx->getStart()->getCharPositionInLine() + 1;
|
|
|
|
|
ir_ctx_.RecordError(ErrorMsg("break只能出现在循环语句中", line, col));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ctx->stmt()) {
|
|
|
|
|
ctx->stmt()->accept(this);
|
|
|
|
|
return {};
|
|
|
|
|
// CONTINUE语句
|
|
|
|
|
else if (ctx->getText().find("continue") != std::string::npos) {
|
|
|
|
|
if (!ir_ctx_.InLoop()) {
|
|
|
|
|
int line = ctx->getStart()->getLine();
|
|
|
|
|
int col = ctx->getStart()->getCharPositionInLine() + 1;
|
|
|
|
|
ir_ctx_.RecordError(ErrorMsg("continue只能出现在循环语句中", line, col));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "暂不支持的语句或声明"));
|
|
|
|
|
}
|
|
|
|
|
// RETURN语句
|
|
|
|
|
else if (ctx->getText().find("return") != std::string::npos) {
|
|
|
|
|
SymbolType func_ret_type = ir_ctx_.GetCurrentFuncReturnType();
|
|
|
|
|
|
|
|
|
|
// 有返回表达式的情况
|
|
|
|
|
if (ctx->exp()) {
|
|
|
|
|
auto exp_ctx = ctx->exp();
|
|
|
|
|
SymbolType exp_type = ir_ctx_.GetType(exp_ctx);
|
|
|
|
|
|
|
|
|
|
std::any visitDecl(SysYParser::DeclContext* ctx) override {
|
|
|
|
|
if (!ctx) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "非法变量声明"));
|
|
|
|
|
// 返回类型不匹配报错
|
|
|
|
|
if (exp_type != func_ret_type && exp_type != SymbolType::TYPE_UNKNOWN && func_ret_type != SymbolType::TYPE_UNKNOWN) {
|
|
|
|
|
std::string ret_type_str = (func_ret_type == SymbolType::TYPE_INT ? "int" : (func_ret_type == SymbolType::TYPE_FLOAT ? "float" : "void"));
|
|
|
|
|
std::string exp_type_str = (exp_type == SymbolType::TYPE_INT ? "int" : "float");
|
|
|
|
|
std::string err_msg = "return表达式类型与函数返回类型不匹配,期望" + ret_type_str + ",实际为" + exp_type_str;
|
|
|
|
|
|
|
|
|
|
int line = exp_ctx->getStart()->getLine();
|
|
|
|
|
int col = exp_ctx->getStart()->getCharPositionInLine() + 1;
|
|
|
|
|
ir_ctx_.RecordError(ErrorMsg(err_msg, line, col));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 无返回表达式的情况
|
|
|
|
|
else {
|
|
|
|
|
if (func_ret_type != SymbolType::TYPE_VOID && func_ret_type != SymbolType::TYPE_UNKNOWN) {
|
|
|
|
|
int line = ctx->getStart()->getLine();
|
|
|
|
|
int col = ctx->getStart()->getCharPositionInLine() + 1;
|
|
|
|
|
ir_ctx_.RecordError(ErrorMsg("非void函数return必须带表达式", line, col));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!ctx->btype() || !ctx->btype()->INT()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "当前仅支持局部 int 变量声明"));
|
|
|
|
|
}
|
|
|
|
|
auto* var_def = ctx->varDef();
|
|
|
|
|
if (!var_def || !var_def->lValue()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "非法变量声明"));
|
|
|
|
|
|
|
|
|
|
// 其他语句
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 8. 左值节点访问
|
|
|
|
|
std::any SemaVisitor::visitLVal(SysYParser::LValContext* ctx) {
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 9. 表达式节点访问
|
|
|
|
|
std::any SemaVisitor::visitExp(SysYParser::ExpContext* ctx) {
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 10. 条件表达式节点访问
|
|
|
|
|
std::any SemaVisitor::visitCond(SysYParser::CondContext* ctx) {
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 11. 基本表达式节点访问
|
|
|
|
|
std::any SemaVisitor::visitPrimaryExp(SysYParser::PrimaryExpContext* ctx) {
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 12. 一元表达式节点访问
|
|
|
|
|
std::any SemaVisitor::visitUnaryExp(SysYParser::UnaryExpContext* ctx) {
|
|
|
|
|
// 带一元运算符的表达式(+/-/!)
|
|
|
|
|
if (ctx->unaryOp() && ctx->unaryExp()) {
|
|
|
|
|
auto op_ctx = ctx->unaryOp();
|
|
|
|
|
auto uexp_ctx = ctx->unaryExp();
|
|
|
|
|
auto uexp_val = visit(uexp_ctx);
|
|
|
|
|
|
|
|
|
|
std::string op_text = op_ctx->getText();
|
|
|
|
|
SymbolType uexp_type = ir_ctx_.GetType(uexp_ctx);
|
|
|
|
|
|
|
|
|
|
// 正号 +x → 直接返回原值
|
|
|
|
|
if (op_text == "+") {
|
|
|
|
|
ir_ctx_.SetType(ctx, uexp_type);
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, uexp_val);
|
|
|
|
|
return uexp_val;
|
|
|
|
|
}
|
|
|
|
|
// 负号 -x → 取反
|
|
|
|
|
else if (op_text == "-") {
|
|
|
|
|
if (ir_ctx_.IsIntType(uexp_val)) {
|
|
|
|
|
long val = std::any_cast<long>(uexp_val);
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, std::any(-val));
|
|
|
|
|
ir_ctx_.SetType(ctx, SymbolType::TYPE_INT);
|
|
|
|
|
return std::any(-val);
|
|
|
|
|
} else if (ir_ctx_.IsFloatType(uexp_val)) {
|
|
|
|
|
double val = std::any_cast<double>(uexp_val);
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, std::any(-val));
|
|
|
|
|
ir_ctx_.SetType(ctx, SymbolType::TYPE_FLOAT);
|
|
|
|
|
return std::any(-val);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 逻辑非 !x → 0/1转换
|
|
|
|
|
else if (op_text == "!") {
|
|
|
|
|
if (ir_ctx_.IsIntType(uexp_val)) {
|
|
|
|
|
long val = std::any_cast<long>(uexp_val);
|
|
|
|
|
long res = (val == 0) ? 1L : 0L;
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, std::any(res));
|
|
|
|
|
ir_ctx_.SetType(ctx, SymbolType::TYPE_INT);
|
|
|
|
|
return std::any(res);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const std::string name = GetLValueName(*var_def->lValue());
|
|
|
|
|
if (table_.Contains(name)) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "重复定义变量: " + name));
|
|
|
|
|
// 函数调用表达式
|
|
|
|
|
else if (ctx->Ident() && ctx->funcRParams()) {
|
|
|
|
|
// 这里简化处理
|
|
|
|
|
ir_ctx_.SetType(ctx, SymbolType::TYPE_INT);
|
|
|
|
|
return std::any(0L);
|
|
|
|
|
}
|
|
|
|
|
if (auto* init = var_def->initValue()) {
|
|
|
|
|
if (!init->exp()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "当前不支持聚合初始化"));
|
|
|
|
|
}
|
|
|
|
|
init->exp()->accept(this);
|
|
|
|
|
// 基础表达式
|
|
|
|
|
else if (ctx->primaryExp()) {
|
|
|
|
|
auto val = visit(ctx->primaryExp());
|
|
|
|
|
ir_ctx_.SetType(ctx, ir_ctx_.GetType(ctx->primaryExp()));
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, val);
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
table_.Add(name, var_def);
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::any visitStmt(SysYParser::StmtContext* ctx) override {
|
|
|
|
|
if (!ctx || !ctx->returnStmt()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "暂不支持的语句或声明"));
|
|
|
|
|
}
|
|
|
|
|
ctx->returnStmt()->accept(this);
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
return std::any();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::any visitReturnStmt(SysYParser::ReturnStmtContext* ctx) override {
|
|
|
|
|
if (!ctx || !ctx->exp()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "return 缺少表达式"));
|
|
|
|
|
// 13. 乘法表达式节点访问
|
|
|
|
|
std::any SemaVisitor::visitMulExp(SysYParser::MulExpContext* ctx) {
|
|
|
|
|
auto uexps = ctx->unaryExp();
|
|
|
|
|
|
|
|
|
|
// 单操作数 → 直接返回
|
|
|
|
|
if (uexps.size() == 1) {
|
|
|
|
|
auto val = visit(uexps[0]);
|
|
|
|
|
ir_ctx_.SetType(ctx, ir_ctx_.GetType(uexps[0]));
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, val);
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
ctx->exp()->accept(this);
|
|
|
|
|
seen_return_ = true;
|
|
|
|
|
if (current_item_index_ + 1 != total_items_) {
|
|
|
|
|
throw std::runtime_error(
|
|
|
|
|
FormatError("sema", "return 必须是 main 函数中的最后一条语句"));
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::any visitParenExp(SysYParser::ParenExpContext* ctx) override {
|
|
|
|
|
if (!ctx || !ctx->exp()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "非法括号表达式"));
|
|
|
|
|
}
|
|
|
|
|
ctx->exp()->accept(this);
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
// 多操作数 → 依次计算
|
|
|
|
|
std::any result = visit(uexps[0]);
|
|
|
|
|
SymbolType current_type = ir_ctx_.GetType(uexps[0]);
|
|
|
|
|
|
|
|
|
|
std::any visitVarExp(SysYParser::VarExpContext* ctx) override {
|
|
|
|
|
if (!ctx || !ctx->var()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "非法变量表达式"));
|
|
|
|
|
for (size_t i = 1; i < uexps.size(); ++i) {
|
|
|
|
|
auto next_uexp = uexps[i];
|
|
|
|
|
auto next_val = visit(next_uexp);
|
|
|
|
|
SymbolType next_type = ir_ctx_.GetType(next_uexp);
|
|
|
|
|
|
|
|
|
|
// 类型统一:int和float混合转为float
|
|
|
|
|
if (current_type == SymbolType::TYPE_INT && next_type == SymbolType::TYPE_FLOAT) {
|
|
|
|
|
current_type = SymbolType::TYPE_FLOAT;
|
|
|
|
|
} else if (current_type == SymbolType::TYPE_FLOAT && next_type == SymbolType::TYPE_INT) {
|
|
|
|
|
current_type = SymbolType::TYPE_FLOAT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 简化处理:这里假设是乘法运算
|
|
|
|
|
if (ir_ctx_.IsIntType(result) && ir_ctx_.IsIntType(next_val)) {
|
|
|
|
|
long v1 = std::any_cast<long>(result);
|
|
|
|
|
long v2 = std::any_cast<long>(next_val);
|
|
|
|
|
result = std::any(v1 * v2);
|
|
|
|
|
} else if (ir_ctx_.IsFloatType(result) && ir_ctx_.IsFloatType(next_val)) {
|
|
|
|
|
double v1 = std::any_cast<double>(result);
|
|
|
|
|
double v2 = std::any_cast<double>(next_val);
|
|
|
|
|
result = std::any(v1 * v2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新当前节点类型和常量值
|
|
|
|
|
ir_ctx_.SetType(ctx, current_type);
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, result);
|
|
|
|
|
}
|
|
|
|
|
ctx->var()->accept(this);
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::any visitNumberExp(SysYParser::NumberExpContext* ctx) override {
|
|
|
|
|
if (!ctx || !ctx->number() || !ctx->number()->ILITERAL()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "当前仅支持整数字面量"));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 14. 加法表达式节点访问
|
|
|
|
|
std::any SemaVisitor::visitAddExp(SysYParser::AddExpContext* ctx) {
|
|
|
|
|
auto mexps = ctx->mulExp();
|
|
|
|
|
|
|
|
|
|
// 单操作数 → 直接返回
|
|
|
|
|
if (mexps.size() == 1) {
|
|
|
|
|
auto val = visit(mexps[0]);
|
|
|
|
|
ir_ctx_.SetType(ctx, ir_ctx_.GetType(mexps[0]));
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, val);
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::any visitAdditiveExp(SysYParser::AdditiveExpContext* ctx) override {
|
|
|
|
|
if (!ctx || !ctx->exp(0) || !ctx->exp(1)) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "暂不支持的表达式形式"));
|
|
|
|
|
// 多操作数 → 依次计算
|
|
|
|
|
std::any result = visit(mexps[0]);
|
|
|
|
|
SymbolType current_type = ir_ctx_.GetType(mexps[0]);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 1; i < mexps.size(); ++i) {
|
|
|
|
|
auto next_mexp = mexps[i];
|
|
|
|
|
auto next_val = visit(next_mexp);
|
|
|
|
|
SymbolType next_type = ir_ctx_.GetType(next_mexp);
|
|
|
|
|
|
|
|
|
|
// 类型统一
|
|
|
|
|
if (current_type == SymbolType::TYPE_INT && next_type == SymbolType::TYPE_FLOAT) {
|
|
|
|
|
current_type = SymbolType::TYPE_FLOAT;
|
|
|
|
|
} else if (current_type == SymbolType::TYPE_FLOAT && next_type == SymbolType::TYPE_INT) {
|
|
|
|
|
current_type = SymbolType::TYPE_FLOAT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 简化处理:这里假设是加法运算
|
|
|
|
|
if (ir_ctx_.IsIntType(result) && ir_ctx_.IsIntType(next_val)) {
|
|
|
|
|
long v1 = std::any_cast<long>(result);
|
|
|
|
|
long v2 = std::any_cast<long>(next_val);
|
|
|
|
|
result = std::any(v1 + v2);
|
|
|
|
|
} else if (ir_ctx_.IsFloatType(result) && ir_ctx_.IsFloatType(next_val)) {
|
|
|
|
|
double v1 = std::any_cast<double>(result);
|
|
|
|
|
double v2 = std::any_cast<double>(next_val);
|
|
|
|
|
result = std::any(v1 + v2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ir_ctx_.SetType(ctx, current_type);
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, result);
|
|
|
|
|
}
|
|
|
|
|
ctx->exp(0)->accept(this);
|
|
|
|
|
ctx->exp(1)->accept(this);
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::any visitVar(SysYParser::VarContext* ctx) override {
|
|
|
|
|
if (!ctx || !ctx->ID()) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "非法变量引用"));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 15. 关系表达式节点访问
|
|
|
|
|
std::any SemaVisitor::visitRelExp(SysYParser::RelExpContext* ctx) {
|
|
|
|
|
auto aexps = ctx->addExp();
|
|
|
|
|
|
|
|
|
|
// 单操作数 → 直接返回
|
|
|
|
|
if (aexps.size() == 1) {
|
|
|
|
|
auto val = visit(aexps[0]);
|
|
|
|
|
ir_ctx_.SetType(ctx, SymbolType::TYPE_INT);
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
const std::string name = ctx->ID()->getText();
|
|
|
|
|
auto* decl = table_.Lookup(name);
|
|
|
|
|
if (!decl) {
|
|
|
|
|
throw std::runtime_error(FormatError("sema", "使用了未定义的变量: " + name));
|
|
|
|
|
|
|
|
|
|
// 多操作数 → 简化处理
|
|
|
|
|
std::any result = std::any(1L);
|
|
|
|
|
ir_ctx_.SetType(ctx, SymbolType::TYPE_INT);
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, result);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 16. 相等表达式节点访问
|
|
|
|
|
std::any SemaVisitor::visitEqExp(SysYParser::EqExpContext* ctx) {
|
|
|
|
|
auto rexps = ctx->relExp();
|
|
|
|
|
|
|
|
|
|
// 单操作数 → 直接返回
|
|
|
|
|
if (rexps.size() == 1) {
|
|
|
|
|
auto val = visit(rexps[0]);
|
|
|
|
|
ir_ctx_.SetType(ctx, SymbolType::TYPE_INT);
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
sema_.BindVarUse(ctx, decl);
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SemanticContext TakeSemanticContext() { return std::move(sema_); }
|
|
|
|
|
// 多操作数 → 简化处理
|
|
|
|
|
std::any result = std::any(1L);
|
|
|
|
|
ir_ctx_.SetType(ctx, SymbolType::TYPE_INT);
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, result);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
SymbolTable table_;
|
|
|
|
|
SemanticContext sema_;
|
|
|
|
|
bool seen_return_ = false;
|
|
|
|
|
size_t current_item_index_ = 0;
|
|
|
|
|
size_t total_items_ = 0;
|
|
|
|
|
};
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
// 17. 逻辑与表达式节点访问
|
|
|
|
|
std::any SemaVisitor::visitLAndExp(SysYParser::LAndExpContext* ctx) {
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SemanticContext RunSema(SysYParser::CompUnitContext& comp_unit) {
|
|
|
|
|
SemaVisitor visitor;
|
|
|
|
|
comp_unit.accept(&visitor);
|
|
|
|
|
return visitor.TakeSemanticContext();
|
|
|
|
|
// 18. 逻辑或表达式节点访问
|
|
|
|
|
std::any SemaVisitor::visitLOrExp(SysYParser::LOrExpContext* ctx) {
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 19. 常量表达式节点访问
|
|
|
|
|
std::any SemaVisitor::visitConstExp(SysYParser::ConstExpContext* ctx) {
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 20. 数字节点访问
|
|
|
|
|
std::any SemaVisitor::visitNumber(SysYParser::NumberContext* ctx) {
|
|
|
|
|
// 这里简化处理,实际需要解析整型和浮点型
|
|
|
|
|
if (ctx->IntConst()) {
|
|
|
|
|
ir_ctx_.SetType(ctx, SymbolType::TYPE_INT);
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, std::any(0L));
|
|
|
|
|
return std::any(0L);
|
|
|
|
|
} else if (ctx->FloatConst()) {
|
|
|
|
|
ir_ctx_.SetType(ctx, SymbolType::TYPE_FLOAT);
|
|
|
|
|
ir_ctx_.SetConstVal(ctx, std::any(0.0));
|
|
|
|
|
return std::any(0.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::any();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 21. 函数参数节点访问
|
|
|
|
|
std::any SemaVisitor::visitFuncRParams(SysYParser::FuncRParamsContext* ctx) {
|
|
|
|
|
return visitChildren(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ===================== 语义分析入口函数 =====================
|
|
|
|
|
void RunSemanticAnalysis(SysYParser::CompUnitContext* ctx, IRGenContext& ir_ctx) {
|
|
|
|
|
if (!ctx) {
|
|
|
|
|
throw std::invalid_argument("CompUnitContext is null");
|
|
|
|
|
}
|
|
|
|
|
SemaVisitor visitor(ir_ctx);
|
|
|
|
|
visitor.visit(ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IRGenContext RunSema(SysYParser::CompUnitContext& ctx) {
|
|
|
|
|
IRGenContext ctx_obj;
|
|
|
|
|
RunSemanticAnalysis(&ctx, ctx_obj);
|
|
|
|
|
return ctx_obj;
|
|
|
|
|
}
|