Complete Lab2 IR generation and document process

This commit is contained in:
2026-04-16 00:21:35 +08:00
parent 6fc0c89072
commit 979d271ebe
23 changed files with 2583 additions and 471 deletions

View File

@@ -15,7 +15,7 @@ namespace ir {
// 当前 BasicBlock 还没有专门的 label type因此先用 void 作为占位类型。
BasicBlock::BasicBlock(std::string name)
: Value(Type::GetVoidType(), std::move(name)) {}
: Value(Type::GetLabelType(), std::move(name)) {}
Function* BasicBlock::GetParent() const { return parent_; }

View File

@@ -3,7 +3,6 @@ add_library(ir_core STATIC
Module.cpp
Function.cpp
BasicBlock.cpp
GlobalValue.cpp
Type.cpp
Value.cpp
Instruction.cpp

View File

@@ -15,10 +15,18 @@ ConstantInt* Context::GetConstInt(int v) {
return inserted->second.get();
}
ConstantFloat* Context::GetConstFloat(float v) {
auto it = const_floats_.find(v);
if (it != const_floats_.end()) return it->second.get();
auto inserted =
const_floats_
.emplace(v, std::make_unique<ConstantFloat>(Type::GetFloatType(), v))
.first;
return inserted->second.get();
}
std::string Context::NextTemp() {
std::ostringstream oss;
oss << "%" << ++temp_index_;
return oss.str();
return "t" + std::to_string(++temp_index_);
}
} // namespace ir

View File

@@ -5,9 +5,14 @@
namespace ir {
Function::Function(std::string name, std::shared_ptr<Type> ret_type)
Function::Function(std::string name, std::shared_ptr<Type> ret_type,
std::vector<std::shared_ptr<Type>> param_types)
: Value(std::move(ret_type), std::move(name)) {
entry_ = CreateBlock("entry");
for (size_t i = 0; i < param_types.size(); ++i) {
arguments_.push_back(std::make_unique<Argument>(
param_types[i], "a" + std::to_string(i), this,
static_cast<unsigned>(i)));
}
}
BasicBlock* Function::CreateBlock(const std::string& name) {
@@ -29,4 +34,8 @@ const std::vector<std::unique_ptr<BasicBlock>>& Function::GetBlocks() const {
return blocks_;
}
const std::vector<std::unique_ptr<Argument>>& Function::GetArguments() const {
return arguments_;
}
} // namespace ir

View File

@@ -5,7 +5,7 @@
namespace ir {
GlobalValue::GlobalValue(std::shared_ptr<Type> ty, std::string name)
: User(std::move(ty), std::move(name)) {}
GlobalValue::GlobalValue(std::shared_ptr<Type> ty, std::string name, ConstantValue* init)
: User(std::move(ty), std::move(name)), init_(init) {}
} // namespace ir

View File

@@ -21,6 +21,11 @@ ConstantInt* IRBuilder::CreateConstInt(int v) {
return ctx_.GetConstInt(v);
}
ConstantFloat* IRBuilder::CreateConstFloat(float v) {
// 常量不需要挂在基本块里,由 Context 负责去重与生命周期。
return ctx_.GetConstFloat(v);
}
BinaryInst* IRBuilder::CreateBinary(Opcode op, Value* lhs, Value* rhs,
const std::string& name) {
if (!insert_block_) {
@@ -42,11 +47,74 @@ BinaryInst* IRBuilder::CreateAdd(Value* lhs, Value* rhs,
return CreateBinary(Opcode::Add, lhs, rhs, name);
}
AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) {
BinaryInst* IRBuilder::CreateSub(Value* lhs, Value* rhs,
const std::string& name) {
return CreateBinary(Opcode::Sub, lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateMul(Value* lhs, Value* rhs,
const std::string& name) {
return CreateBinary(Opcode::Mul, lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateDiv(Value* lhs, Value* rhs,
const std::string& name) {
return CreateBinary(Opcode::Div, lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateMod(Value* lhs, Value* rhs,
const std::string& name) {
return CreateBinary(Opcode::Mod, lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateFAdd(Value* lhs, Value* rhs,
const std::string& name) {
return CreateBinary(Opcode::FAdd, lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateFSub(Value* lhs, Value* rhs,
const std::string& name) {
return CreateBinary(Opcode::FSub, lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateFMul(Value* lhs, Value* rhs,
const std::string& name) {
return CreateBinary(Opcode::FMul, lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateFDiv(Value* lhs, Value* rhs,
const std::string& name) {
return CreateBinary(Opcode::FDiv, lhs, rhs, name);
}
BinaryInst* IRBuilder::CreateICmp(Opcode op, Value* lhs, Value* rhs,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<AllocaInst>(Type::GetPtrInt32Type(), name);
return insert_block_->Append<BinaryInst>(op, Type::GetInt32Type(), lhs, rhs,
name);
}
BinaryInst* IRBuilder::CreateFCmp(Opcode op, Value* lhs, Value* rhs,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<BinaryInst>(op, Type::GetInt32Type(), lhs, rhs,
name);
}
AllocaInst* IRBuilder::CreateAlloca(std::shared_ptr<Type> ty,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<AllocaInst>(ty, name);
}
AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) {
return CreateAlloca(Type::GetPtrInt32Type(), name);
}
LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) {
@@ -57,7 +125,15 @@ LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateLoad 缺少 ptr"));
}
return insert_block_->Append<LoadInst>(Type::GetInt32Type(), ptr, name);
std::shared_ptr<Type> val_ty;
if (ptr->GetType()->IsPtrInt32()) {
val_ty = Type::GetInt32Type();
} else if (ptr->GetType()->IsPtrFloat()) {
val_ty = Type::GetFloatType();
} else {
throw std::runtime_error(FormatError("ir", "LoadInst 不支持的指针类型"));
}
return insert_block_->Append<LoadInst>(val_ty, ptr, name);
}
StoreInst* IRBuilder::CreateStore(Value* val, Value* ptr) {
@@ -79,11 +155,63 @@ ReturnInst* IRBuilder::CreateRet(Value* v) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
if (!v) {
throw std::runtime_error(
FormatError("ir", "IRBuilder::CreateRet 缺少返回值"));
}
return insert_block_->Append<ReturnInst>(Type::GetVoidType(), v);
}
BranchInst* IRBuilder::CreateBr(BasicBlock* dest) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<BranchInst>(dest);
}
BranchInst* IRBuilder::CreateCondBr(Value* cond, BasicBlock* if_true,
BasicBlock* if_false) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<BranchInst>(cond, if_true, if_false);
}
CallInst* IRBuilder::CreateCall(Function* func, const std::vector<Value*>& args,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<CallInst>(func, args, name);
}
GetElementPtrInst* IRBuilder::CreateGEP(std::shared_ptr<Type> ptr_ty, Value* ptr,
const std::vector<Value*>& indices,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<GetElementPtrInst>(ptr_ty, ptr, indices, name);
}
CastInst* IRBuilder::CreateZExt(Value* val, std::shared_ptr<Type> ty,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<CastInst>(Opcode::ZExt, ty, val, name);
}
CastInst* IRBuilder::CreateSIToFP(Value* val, std::shared_ptr<Type> ty,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<CastInst>(Opcode::SIToFP, ty, val, name);
}
CastInst* IRBuilder::CreateFPToSI(Value* val, std::shared_ptr<Type> ty,
const std::string& name) {
if (!insert_block_) {
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
}
return insert_block_->Append<CastInst>(Opcode::FPToSI, ty, val, name);
}
} // namespace ir

View File

@@ -4,7 +4,11 @@
#include "ir/IR.h"
#include <cstdio>
#include <iomanip>
#include <sstream>
#include <ostream>
#include <cstring>
#include <stdexcept>
#include <string>
@@ -12,7 +16,7 @@
namespace ir {
static const char* TypeToString(const Type& ty) {
static std::string TypeToString(const Type& ty) {
switch (ty.GetKind()) {
case Type::Kind::Void:
return "void";
@@ -20,11 +24,22 @@ static const char* TypeToString(const Type& ty) {
return "i32";
case Type::Kind::PtrInt32:
return "i32*";
case Type::Kind::Float:
return "float";
case Type::Kind::PtrFloat:
return "float*";
case Type::Kind::Label:
return "label";
case Type::Kind::Array: {
const auto* arr_ty = static_cast<const ArrayType*>(&ty);
return "[" + std::to_string(arr_ty->GetNumElements()) + " x " +
TypeToString(*arr_ty->GetElementType()) + "]";
}
}
throw std::runtime_error(FormatError("ir", "未知类型"));
return "unknown";
}
static const char* OpcodeToString(Opcode op) {
static std::string OpcodeToString(Opcode op) {
switch (op) {
case Opcode::Add:
return "add";
@@ -32,6 +47,42 @@ static const char* OpcodeToString(Opcode op) {
return "sub";
case Opcode::Mul:
return "mul";
case Opcode::Div:
return "sdiv";
case Opcode::Mod:
return "srem";
case Opcode::FAdd:
return "fadd";
case Opcode::FSub:
return "fsub";
case Opcode::FMul:
return "fmul";
case Opcode::FDiv:
return "fdiv";
case Opcode::ICmpEQ:
return "icmp eq";
case Opcode::ICmpNE:
return "icmp ne";
case Opcode::ICmpLT:
return "icmp slt";
case Opcode::ICmpGT:
return "icmp sgt";
case Opcode::ICmpLE:
return "icmp sle";
case Opcode::ICmpGE:
return "icmp sge";
case Opcode::FCmpEQ:
return "fcmp oeq";
case Opcode::FCmpNE:
return "fcmp une";
case Opcode::FCmpLT:
return "fcmp olt";
case Opcode::FCmpGT:
return "fcmp ogt";
case Opcode::FCmpLE:
return "fcmp ole";
case Opcode::FCmpGE:
return "fcmp oge";
case Opcode::Alloca:
return "alloca";
case Opcode::Load:
@@ -40,21 +91,114 @@ static const char* OpcodeToString(Opcode op) {
return "store";
case Opcode::Ret:
return "ret";
case Opcode::Br:
return "br";
case Opcode::Call:
return "call";
case Opcode::GEP:
return "getelementptr";
case Opcode::ZExt:
return "zext";
case Opcode::SIToFP:
return "sitofp";
case Opcode::FPToSI:
return "fptosi";
}
return "?";
}
static std::string ValueToString(const Value* v) {
if (!v) return "<null>";
if (auto* ci = dynamic_cast<const ConstantInt*>(v)) {
return std::to_string(ci->GetValue());
}
return v ? v->GetName() : "<null>";
if (auto* cf = dynamic_cast<const ConstantFloat*>(v)) {
const double as_double = static_cast<double>(cf->GetValue());
uint64_t bits = 0;
std::memcpy(&bits, &as_double, sizeof(bits));
std::ostringstream oss;
oss << "0x" << std::hex << std::uppercase << std::setw(16)
<< std::setfill('0') << bits;
return oss.str();
}
if (v->IsGlobalValue() || v->IsFunction()) {
return "@" + v->GetName();
}
if (v->IsInstruction() || v->IsArgument() || v->GetType()->IsLabel()) {
return "%" + v->GetName();
}
return v->GetName();
}
static bool IsBoolLikeValue(const Value* v) {
if (auto* inst = dynamic_cast<const Instruction*>(v)) {
switch (inst->GetOpcode()) {
case Opcode::ICmpEQ:
case Opcode::ICmpNE:
case Opcode::ICmpLT:
case Opcode::ICmpGT:
case Opcode::ICmpLE:
case Opcode::ICmpGE:
case Opcode::FCmpEQ:
case Opcode::FCmpNE:
case Opcode::FCmpLT:
case Opcode::FCmpGT:
case Opcode::FCmpLE:
case Opcode::FCmpGE:
return true;
default:
break;
}
}
return false;
}
static std::string PrintedValueType(const Value* v) {
if (IsBoolLikeValue(v)) return "i1";
return TypeToString(*v->GetType());
}
void IRPrinter::Print(const Module& module, std::ostream& os) {
// Print global variables
for (const auto& gv : module.GetGlobalValues()) {
os << "@" << gv->GetName() << " = global ";
if (gv->GetType()->IsPtrInt32()) {
os << "i32";
} else if (gv->GetType()->IsPtrFloat()) {
os << "float";
} else {
os << TypeToString(*gv->GetType());
}
if (gv->GetInitializer()) {
os << " " << ValueToString(gv->GetInitializer());
} else {
os << " zeroinitializer";
}
os << "\n";
}
if (!module.GetGlobalValues().empty()) os << "\n";
for (const auto& func : module.GetFunctions()) {
if (func->GetBlocks().empty()) {
os << "declare " << TypeToString(*func->GetType()) << " @" << func->GetName()
<< "(";
// For declarations, we just need types. But Argument objects might exist.
const auto& args = func->GetArguments();
for (size_t i = 0; i < args.size(); ++i) {
os << TypeToString(*args[i]->GetType());
if (i + 1 < args.size()) os << ", ";
}
os << ")\n\n";
continue;
}
os << "define " << TypeToString(*func->GetType()) << " @" << func->GetName()
<< "() {\n";
<< "(";
const auto& args = func->GetArguments();
for (size_t i = 0; i < args.size(); ++i) {
os << TypeToString(*args[i]->GetType()) << " %" << args[i]->GetName();
if (i + 1 < args.size()) os << ", ";
}
os << ") {\n";
for (const auto& bb : func->GetBlocks()) {
if (!bb) {
continue;
@@ -65,36 +209,142 @@ void IRPrinter::Print(const Module& module, std::ostream& os) {
switch (inst->GetOpcode()) {
case Opcode::Add:
case Opcode::Sub:
case Opcode::Mul: {
case Opcode::Mul:
case Opcode::Div:
case Opcode::Mod:
case Opcode::FAdd:
case Opcode::FSub:
case Opcode::FMul:
case Opcode::FDiv: {
auto* bin = static_cast<const BinaryInst*>(inst);
os << " " << bin->GetName() << " = "
os << " %" << bin->GetName() << " = "
<< OpcodeToString(bin->GetOpcode()) << " "
<< TypeToString(*bin->GetLhs()->GetType()) << " "
<< PrintedValueType(bin->GetLhs()) << " "
<< ValueToString(bin->GetLhs()) << ", "
<< ValueToString(bin->GetRhs()) << "\n";
break;
}
case Opcode::ICmpEQ:
case Opcode::ICmpNE:
case Opcode::ICmpLT:
case Opcode::ICmpGT:
case Opcode::ICmpLE:
case Opcode::ICmpGE:
case Opcode::FCmpEQ:
case Opcode::FCmpNE:
case Opcode::FCmpLT:
case Opcode::FCmpGT:
case Opcode::FCmpLE:
case Opcode::FCmpGE: {
auto* bin = static_cast<const BinaryInst*>(inst);
os << " %" << bin->GetName() << " = "
<< OpcodeToString(bin->GetOpcode()) << " "
<< PrintedValueType(bin->GetLhs()) << " "
<< ValueToString(bin->GetLhs()) << ", "
<< ValueToString(bin->GetRhs()) << "\n";
break;
}
case Opcode::Alloca: {
auto* alloca = static_cast<const AllocaInst*>(inst);
os << " " << alloca->GetName() << " = alloca i32\n";
os << " %" << alloca->GetName() << " = alloca ";
if (alloca->GetType()->IsPtrInt32())
os << "i32";
else if (alloca->GetType()->IsPtrFloat())
os << "float";
else
os << TypeToString(*alloca->GetType());
os << "\n";
break;
}
case Opcode::Load: {
auto* load = static_cast<const LoadInst*>(inst);
os << " " << load->GetName() << " = load i32, i32* "
os << " %" << load->GetName() << " = load "
<< TypeToString(*load->GetType()) << ", "
<< TypeToString(*load->GetPtr()->GetType()) << " "
<< ValueToString(load->GetPtr()) << "\n";
break;
}
case Opcode::Store: {
auto* store = static_cast<const StoreInst*>(inst);
os << " store i32 " << ValueToString(store->GetValue())
<< ", i32* " << ValueToString(store->GetPtr()) << "\n";
os << " store " << TypeToString(*store->GetValue()->GetType())
<< " " << ValueToString(store->GetValue()) << ", "
<< TypeToString(*store->GetPtr()->GetType()) << " "
<< ValueToString(store->GetPtr()) << "\n";
break;
}
case Opcode::Ret: {
auto* ret = static_cast<const ReturnInst*>(inst);
os << " ret " << TypeToString(*ret->GetValue()->GetType()) << " "
<< ValueToString(ret->GetValue()) << "\n";
os << " ret ";
if (ret->GetValue()) {
os << TypeToString(*ret->GetValue()->GetType()) << " "
<< ValueToString(ret->GetValue());
} else {
os << "void";
}
os << "\n";
break;
}
case Opcode::Br: {
auto* br = static_cast<const BranchInst*>(inst);
if (br->IsConditional()) {
os << " br i1 " << ValueToString(br->GetCondition())
<< ", label " << ValueToString(br->GetIfTrue()) << ", label "
<< ValueToString(br->GetIfFalse()) << "\n";
} else {
os << " br label " << ValueToString(br->GetDest()) << "\n";
}
break;
}
case Opcode::Call: {
auto* call = static_cast<const CallInst*>(inst);
auto* func = call->GetFunction();
if (!call->GetType()->IsVoid()) {
os << " %" << call->GetName() << " = ";
} else {
os << " ";
}
os << "call " << TypeToString(*call->GetType()) << " "
<< ValueToString(func) << "(";
for (size_t i = 1; i < call->GetNumOperands(); ++i) {
auto* arg = call->GetOperand(i);
os << PrintedValueType(arg) << " " << ValueToString(arg);
if (i + 1 < call->GetNumOperands()) os << ", ";
}
os << ")\n";
break;
}
case Opcode::GEP: {
auto* gep = static_cast<const GetElementPtrInst*>(inst);
os << " %" << gep->GetName() << " = getelementptr ";
if (gep->GetPtr()->GetType()->IsPtrInt32())
os << "i32";
else if (gep->GetPtr()->GetType()->IsPtrFloat())
os << "float";
else
os << TypeToString(*gep->GetPtr()->GetType());
os << ", ";
if (gep->GetPtr()->GetType()->IsArray()) {
os << TypeToString(*gep->GetPtr()->GetType()) << "* ";
} else {
os << TypeToString(*gep->GetPtr()->GetType()) << " ";
}
os << ValueToString(gep->GetPtr());
for (size_t i = 1; i < gep->GetNumOperands(); ++i) {
os << ", " << TypeToString(*gep->GetOperand(i)->GetType()) << " "
<< ValueToString(gep->GetOperand(i));
}
os << "\n";
break;
}
case Opcode::ZExt:
case Opcode::SIToFP:
case Opcode::FPToSI: {
auto* cast = static_cast<const CastInst*>(inst);
os << " %" << cast->GetName() << " = "
<< OpcodeToString(cast->GetOpcode()) << " "
<< PrintedValueType(cast->GetValue()) << " "
<< ValueToString(cast->GetValue()) << " to "
<< TypeToString(*cast->GetType()) << "\n";
break;
}
}

View File

@@ -52,7 +52,9 @@ Instruction::Instruction(Opcode op, std::shared_ptr<Type> ty, std::string name)
Opcode Instruction::GetOpcode() const { return opcode_; }
bool Instruction::IsTerminator() const { return opcode_ == Opcode::Ret; }
bool Instruction::IsTerminator() const {
return opcode_ == Opcode::Ret || opcode_ == Opcode::Br;
}
BasicBlock* Instruction::GetParent() const { return parent_; }
@@ -61,22 +63,9 @@ void Instruction::SetParent(BasicBlock* parent) { parent_ = parent; }
BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs,
Value* rhs, std::string name)
: Instruction(op, std::move(ty), std::move(name)) {
if (op != Opcode::Add) {
throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 Add"));
}
if (!lhs || !rhs) {
throw std::runtime_error(FormatError("ir", "BinaryInst 缺少操作数"));
}
if (!type_ || !lhs->GetType() || !rhs->GetType()) {
throw std::runtime_error(FormatError("ir", "BinaryInst 缺少类型信息"));
}
if (lhs->GetType()->GetKind() != rhs->GetType()->GetKind() ||
type_->GetKind() != lhs->GetType()->GetKind()) {
throw std::runtime_error(FormatError("ir", "BinaryInst 类型不匹配"));
}
if (!type_->IsInt32()) {
throw std::runtime_error(FormatError("ir", "BinaryInst 当前只支持 i32"));
}
AddOperand(lhs);
AddOperand(rhs);
}
@@ -85,38 +74,85 @@ Value* BinaryInst::GetLhs() const { return GetOperand(0); }
Value* BinaryInst::GetRhs() const { return GetOperand(1); }
ReturnInst::ReturnInst(std::shared_ptr<Type> void_ty, Value* val)
: Instruction(Opcode::Ret, std::move(void_ty), "") {
if (!val) {
throw std::runtime_error(FormatError("ir", "ReturnInst 缺少返回值"));
BranchInst::BranchInst(BasicBlock* dest)
: Instruction(Opcode::Br, Type::GetVoidType(), "") {
AddOperand(dest);
}
BranchInst::BranchInst(Value* cond, BasicBlock* if_true, BasicBlock* if_false)
: Instruction(Opcode::Br, Type::GetVoidType(), "") {
AddOperand(cond);
AddOperand(if_true);
AddOperand(if_false);
}
bool BranchInst::IsConditional() const { return GetNumOperands() == 3; }
Value* BranchInst::GetCondition() const {
return IsConditional() ? GetOperand(0) : nullptr;
}
BasicBlock* BranchInst::GetIfTrue() const {
return IsConditional() ? static_cast<BasicBlock*>(GetOperand(1)) : nullptr;
}
BasicBlock* BranchInst::GetIfFalse() const {
return IsConditional() ? static_cast<BasicBlock*>(GetOperand(2)) : nullptr;
}
BasicBlock* BranchInst::GetDest() const {
return !IsConditional() ? static_cast<BasicBlock*>(GetOperand(0)) : nullptr;
}
CallInst::CallInst(Function* func, const std::vector<Value*>& args,
std::string name)
: Instruction(Opcode::Call, func->GetType(), std::move(name)) {
AddOperand(func);
for (auto* arg : args) {
AddOperand(arg);
}
if (!type_ || !type_->IsVoid()) {
throw std::runtime_error(FormatError("ir", "ReturnInst 返回类型必须为 void"));
}
Function* CallInst::GetFunction() const {
return static_cast<Function*>(GetOperand(0));
}
GetElementPtrInst::GetElementPtrInst(std::shared_ptr<Type> ptr_ty, Value* ptr,
const std::vector<Value*>& indices,
std::string name)
: Instruction(Opcode::GEP, std::move(ptr_ty), std::move(name)) {
AddOperand(ptr);
for (auto* idx : indices) {
AddOperand(idx);
}
}
Value* GetElementPtrInst::GetPtr() const { return GetOperand(0); }
CastInst::CastInst(Opcode op, std::shared_ptr<Type> ty, Value* val,
std::string name)
: Instruction(op, std::move(ty), std::move(name)) {
AddOperand(val);
}
Value* ReturnInst::GetValue() const { return GetOperand(0); }
Value* CastInst::GetValue() const { return GetOperand(0); }
AllocaInst::AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name)
: Instruction(Opcode::Alloca, std::move(ptr_ty), std::move(name)) {
if (!type_ || !type_->IsPtrInt32()) {
throw std::runtime_error(FormatError("ir", "AllocaInst 当前只支持 i32*"));
ReturnInst::ReturnInst(std::shared_ptr<Type> void_ty, Value* val)
: Instruction(Opcode::Ret, std::move(void_ty), "") {
if (val) {
AddOperand(val);
}
}
Value* ReturnInst::GetValue() const {
return GetNumOperands() > 0 ? GetOperand(0) : nullptr;
}
AllocaInst::AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name)
: Instruction(Opcode::Alloca, std::move(ptr_ty), std::move(name)) {}
LoadInst::LoadInst(std::shared_ptr<Type> val_ty, Value* ptr, std::string name)
: Instruction(Opcode::Load, std::move(val_ty), std::move(name)) {
if (!ptr) {
throw std::runtime_error(FormatError("ir", "LoadInst 缺少 ptr"));
}
if (!type_ || !type_->IsInt32()) {
throw std::runtime_error(FormatError("ir", "LoadInst 当前只支持加载 i32"));
}
if (!ptr->GetType() || !ptr->GetType()->IsPtrInt32()) {
throw std::runtime_error(
FormatError("ir", "LoadInst 当前只支持从 i32* 加载"));
}
AddOperand(ptr);
}
@@ -124,22 +160,6 @@ Value* LoadInst::GetPtr() const { return GetOperand(0); }
StoreInst::StoreInst(std::shared_ptr<Type> void_ty, Value* val, Value* ptr)
: Instruction(Opcode::Store, std::move(void_ty), "") {
if (!val) {
throw std::runtime_error(FormatError("ir", "StoreInst 缺少 value"));
}
if (!ptr) {
throw std::runtime_error(FormatError("ir", "StoreInst 缺少 ptr"));
}
if (!type_ || !type_->IsVoid()) {
throw std::runtime_error(FormatError("ir", "StoreInst 返回类型必须为 void"));
}
if (!val->GetType() || !val->GetType()->IsInt32()) {
throw std::runtime_error(FormatError("ir", "StoreInst 当前只支持存储 i32"));
}
if (!ptr->GetType() || !ptr->GetType()->IsPtrInt32()) {
throw std::runtime_error(
FormatError("ir", "StoreInst 当前只支持写入 i32*"));
}
AddOperand(val);
AddOperand(ptr);
}

View File

@@ -9,8 +9,10 @@ Context& Module::GetContext() { return context_; }
const Context& Module::GetContext() const { return context_; }
Function* Module::CreateFunction(const std::string& name,
std::shared_ptr<Type> ret_type) {
functions_.push_back(std::make_unique<Function>(name, std::move(ret_type)));
std::shared_ptr<Type> ret_type,
std::vector<std::shared_ptr<Type>> param_types) {
functions_.push_back(std::make_unique<Function>(name, std::move(ret_type),
std::move(param_types)));
return functions_.back().get();
}
@@ -18,4 +20,15 @@ const std::vector<std::unique_ptr<Function>>& Module::GetFunctions() const {
return functions_;
}
GlobalValue* Module::CreateGlobalValue(const std::string& name,
std::shared_ptr<Type> ty,
ConstantValue* init) {
global_values_.push_back(std::make_unique<GlobalValue>(std::move(ty), name, init));
return global_values_.back().get();
}
const std::vector<std::unique_ptr<GlobalValue>>& Module::GetGlobalValues() const {
return global_values_;
}
} // namespace ir

View File

@@ -20,6 +20,21 @@ const std::shared_ptr<Type>& Type::GetPtrInt32Type() {
return type;
}
const std::shared_ptr<Type>& Type::GetFloatType() {
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Float);
return type;
}
const std::shared_ptr<Type>& Type::GetPtrFloatType() {
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::PtrFloat);
return type;
}
const std::shared_ptr<Type>& Type::GetLabelType() {
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Label);
return type;
}
Type::Kind Type::GetKind() const { return kind_; }
bool Type::IsVoid() const { return kind_ == Kind::Void; }
@@ -28,4 +43,29 @@ bool Type::IsInt32() const { return kind_ == Kind::Int32; }
bool Type::IsPtrInt32() const { return kind_ == Kind::PtrInt32; }
bool Type::IsFloat() const { return kind_ == Kind::Float; }
bool Type::IsPtrFloat() const { return kind_ == Kind::PtrFloat; }
bool Type::IsLabel() const { return kind_ == Kind::Label; }
bool Type::IsArray() const { return kind_ == Kind::Array; }
std::shared_ptr<class ArrayType> Type::GetAsArrayType() {
if (IsArray()) {
return std::static_pointer_cast<ArrayType>(shared_from_this());
}
return nullptr;
}
ArrayType::ArrayType(std::shared_ptr<Type> element_type, uint32_t num_elements)
: Type(Kind::Array),
element_type_(std::move(element_type)),
num_elements_(num_elements) {}
std::shared_ptr<ArrayType> ArrayType::Get(std::shared_ptr<Type> element_type,
uint32_t num_elements) {
return std::make_shared<ArrayType>(std::move(element_type), num_elements);
}
} // namespace ir

View File

@@ -22,6 +22,12 @@ bool Value::IsInt32() const { return type_ && type_->IsInt32(); }
bool Value::IsPtrInt32() const { return type_ && type_->IsPtrInt32(); }
bool Value::IsFloat() const { return type_ && type_->IsFloat(); }
bool Value::IsPtrFloat() const { return type_ && type_->IsPtrFloat(); }
bool Value::IsLabel() const { return type_ && type_->IsLabel(); }
bool Value::IsConstant() const {
return dynamic_cast<const ConstantValue*>(this) != nullptr;
}
@@ -38,6 +44,14 @@ bool Value::IsFunction() const {
return dynamic_cast<const Function*>(this) != nullptr;
}
bool Value::IsGlobalValue() const {
return dynamic_cast<const GlobalValue*>(this) != nullptr;
}
bool Value::IsArgument() const {
return dynamic_cast<const Argument*>(this) != nullptr;
}
void Value::AddUse(User* user, size_t operand_index) {
if (!user) return;
uses_.push_back(Use(this, user, operand_index));
@@ -74,10 +88,27 @@ void Value::ReplaceAllUsesWith(Value* new_value) {
}
}
Argument::Argument(std::shared_ptr<Type> ty, std::string name, Function* parent,
unsigned arg_no)
: Value(std::move(ty), std::move(name)),
parent_(parent),
arg_no_(arg_no) {}
ConstantValue::ConstantValue(std::shared_ptr<Type> ty, std::string name)
: Value(std::move(ty), std::move(name)) {}
ConstantInt::ConstantInt(std::shared_ptr<Type> ty, int v)
: ConstantValue(std::move(ty), ""), value_(v) {}
ConstantFloat::ConstantFloat(std::shared_ptr<Type> ty, float v)
: ConstantValue(std::move(ty), ""), value_(v) {}
GlobalValue::GlobalValue(std::shared_ptr<Type> ty, std::string name,
ConstantValue* init)
: User(std::move(ty), std::move(name)), init_(init) {
if (init_) {
AddOperand(init_);
}
}
} // namespace ir

View File

@@ -1,6 +1,7 @@
#include "irgen/IRGen.h"
#include <stdexcept>
#include <vector>
#include "SysYParser.h"
#include "ir/IR.h"
@@ -8,100 +9,209 @@
namespace {
std::string GetLValueName(SysYParser::LValueContext& lvalue) {
if (!lvalue.ID()) {
throw std::runtime_error(FormatError("irgen", "非法左值"));
}
return lvalue.ID()->getText();
std::shared_ptr<ir::Type> BaseTypeFromDecl(SysYParser::BtypeContext* btype) {
return (btype && btype->FLOAT()) ? ir::Type::GetFloatType() : ir::Type::GetInt32Type();
}
std::shared_ptr<ir::Type> StorageType(std::shared_ptr<ir::Type> ty) {
if (ty->IsInt32()) return ir::Type::GetPtrInt32Type();
if (ty->IsFloat()) return ir::Type::GetPtrFloatType();
return ty;
}
size_t CountScalars(const std::shared_ptr<ir::Type>& ty) {
if (!ty->IsArray()) return 1;
auto arr_ty = ty->GetAsArrayType();
return arr_ty->GetNumElements() * CountScalars(arr_ty->GetElementType());
}
} // namespace
std::any IRGenImpl::visitBlockStmt(SysYParser::BlockStmtContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句块"));
void IRGenImpl::ZeroInitializeLocal(ir::Value* ptr, std::shared_ptr<ir::Type> ty) {
if (ty->IsArray()) {
auto arr_ty = ty->GetAsArrayType();
for (uint32_t i = 0; i < arr_ty->GetNumElements(); ++i) {
auto* elem_ptr = builder_.CreateGEP(StorageType(arr_ty->GetElementType()), ptr,
{builder_.CreateConstInt(0),
builder_.CreateConstInt(static_cast<int>(i))},
module_.GetContext().NextTemp());
ZeroInitializeLocal(elem_ptr, arr_ty->GetElementType());
}
return;
}
for (auto* item : ctx->blockItem()) {
if (item) {
if (VisitBlockItemResult(*item) == BlockFlow::Terminated) {
// 当前语法要求 return 为块内最后一条语句;命中后可停止生成。
break;
ir::Value* zero = ty->IsFloat() ? static_cast<ir::Value*>(builder_.CreateConstFloat(0.0f))
: static_cast<ir::Value*>(builder_.CreateConstInt(0));
builder_.CreateStore(zero, ptr);
}
void IRGenImpl::EmitLocalInitValue(ir::Value* ptr, std::shared_ptr<ir::Type> ty,
SysYParser::InitValueContext* init) {
if (!init) return;
auto build_flat_scalar_ptr = [&](ir::Value* base_ptr,
const std::shared_ptr<ir::Type>& base_ty,
size_t flat_index) -> ir::Value* {
if (!base_ty->IsArray()) return base_ptr;
std::vector<ir::Value*> indices;
indices.push_back(builder_.CreateConstInt(0));
auto cur_ty = base_ty;
size_t offset = flat_index;
while (cur_ty->IsArray()) {
auto arr_ty = cur_ty->GetAsArrayType();
const size_t step = CountScalars(arr_ty->GetElementType());
const size_t idx = step == 0 ? 0 : offset / step;
offset = step == 0 ? 0 : offset % step;
indices.push_back(builder_.CreateConstInt(static_cast<int>(idx)));
cur_ty = arr_ty->GetElementType();
}
return builder_.CreateGEP(StorageType(cur_ty), base_ptr, indices,
module_.GetContext().NextTemp());
};
if (ty->IsArray()) {
auto arr_ty = ty->GetAsArrayType();
const auto elem_ty = arr_ty->GetElementType();
const size_t elem_step = CountScalars(elem_ty);
if (init->exp()) {
auto* elem_ptr = build_flat_scalar_ptr(ptr, ty, 0);
EmitLocalInitValue(elem_ptr, elem_ty, init);
return;
}
const auto& children = init->initValue();
size_t scalar_cursor = 0;
for (auto* child : children) {
if (scalar_cursor >= CountScalars(ty)) break;
if (child->exp()) {
auto* elem_ptr = build_flat_scalar_ptr(ptr, ty, scalar_cursor);
auto scalar_ty = elem_ty;
while (scalar_ty->IsArray()) {
scalar_ty = scalar_ty->GetAsArrayType()->GetElementType();
}
EmitLocalInitValue(elem_ptr, scalar_ty, child);
++scalar_cursor;
continue;
}
const size_t elem_index = elem_step == 0 ? 0 : scalar_cursor / elem_step;
if (elem_index >= arr_ty->GetNumElements()) break;
auto* elem_ptr = builder_.CreateGEP(StorageType(elem_ty), ptr,
{builder_.CreateConstInt(0),
builder_.CreateConstInt(static_cast<int>(elem_index))},
module_.GetContext().NextTemp());
EmitLocalInitValue(elem_ptr, elem_ty, child);
scalar_cursor = (elem_index + 1) * elem_step;
}
return;
}
if (!init->exp()) {
return;
}
ir::Value* value = EvalExpr(*init->exp());
if (ty->IsFloat() && value->GetType()->IsInt32()) {
value = builder_.CreateSIToFP(value, ty, module_.GetContext().NextTemp());
} else if (ty->IsInt32() && value->GetType()->IsFloat()) {
value = builder_.CreateFPToSI(value, ty, module_.GetContext().NextTemp());
}
builder_.CreateStore(value, ptr);
}
std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) {
if (ctx->constDecl()) return ctx->constDecl()->accept(this);
if (ctx->varDecl()) return ctx->varDecl()->accept(this);
return {};
}
std::any IRGenImpl::visitConstDecl(SysYParser::ConstDeclContext* ctx) {
for (auto* def : ctx->constDef()) {
def->accept(this);
}
return {};
}
std::any IRGenImpl::visitVarDecl(SysYParser::VarDeclContext* ctx) {
for (auto* def : ctx->varDef()) {
def->accept(this);
}
return {};
}
std::any IRGenImpl::visitConstDef(SysYParser::ConstDefContext* ctx) {
const std::string name = ctx->ID()->getText();
auto ty = BaseTypeFromDecl(
dynamic_cast<SysYParser::ConstDeclContext*>(ctx->parent)->btype());
const auto dims = ctx->exp();
for (auto it = dims.rbegin(); it != dims.rend(); ++it) {
auto* dim = EvalConstExpr(**it);
if (auto* ci = dynamic_cast<ir::ConstantInt*>(dim)) {
ty = ir::ArrayType::Get(ty, ci->GetValue());
continue;
}
throw std::runtime_error(FormatError("irgen", "数组维度必须是整型常量"));
}
ir::Value* slot = nullptr;
if (is_global_scope_) {
ir::ConstantValue* init = nullptr;
if (ctx->initValue() && ctx->initValue()->exp()) {
init = EvalConstExpr(*ctx->initValue()->exp());
if (ty->IsInt32() && init->GetType()->IsFloat()) {
init = module_.GetContext().GetConstInt(
static_cast<int>(static_cast<ir::ConstantFloat*>(init)->GetValue()));
} else if (ty->IsFloat() && init->GetType()->IsInt32()) {
init = module_.GetContext().GetConstFloat(
static_cast<float>(static_cast<ir::ConstantInt*>(init)->GetValue()));
}
}
}
return {};
}
IRGenImpl::BlockFlow IRGenImpl::VisitBlockItemResult(
SysYParser::BlockItemContext& item) {
return std::any_cast<BlockFlow>(item.accept(this));
}
std::any IRGenImpl::visitBlockItem(SysYParser::BlockItemContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少块内项"));
}
if (ctx->decl()) {
ctx->decl()->accept(this);
return BlockFlow::Continue;
}
if (ctx->stmt()) {
return ctx->stmt()->accept(this);
}
throw std::runtime_error(FormatError("irgen", "暂不支持的语句或声明"));
}
// 变量声明的 IR 生成目前也是最小实现:
// - 先检查声明的基础类型,当前仅支持局部 int
// - 再把 Decl 中的变量定义交给 visitVarDef 继续处理。
//
// 和更完整的版本相比,这里还没有:
// - 一个 Decl 中多个变量定义的顺序处理;
// - const、数组、全局变量等不同声明形态
// - 更丰富的类型系统。
std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少变量声明"));
}
if (!ctx->btype() || !ctx->btype()->INT()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持局部 int 变量声明"));
}
auto* var_def = ctx->varDef();
if (!var_def) {
throw std::runtime_error(FormatError("irgen", "非法变量声明"));
}
var_def->accept(this);
return {};
}
// 当前仍是教学用的最小版本,因此这里只支持:
// - 局部 int 变量;
// - 标量初始化;
// - 一个 VarDef 对应一个槽位。
std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少变量定义"));
}
if (!ctx->lValue()) {
throw std::runtime_error(FormatError("irgen", "变量声明缺少名称"));
}
GetLValueName(*ctx->lValue());
if (storage_map_.find(ctx) != storage_map_.end()) {
throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位"));
}
auto* slot = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
storage_map_[ctx] = slot;
ir::Value* init = nullptr;
if (auto* init_value = ctx->initValue()) {
if (!init_value->exp()) {
throw std::runtime_error(FormatError("irgen", "当前不支持聚合初始化"));
}
init = EvalExpr(*init_value->exp());
slot = module_.CreateGlobalValue(name, StorageType(ty), init);
} else {
init = builder_.CreateConstInt(0);
slot = builder_.CreateAlloca(StorageType(ty), name);
ZeroInitializeLocal(slot, ty);
EmitLocalInitValue(slot, ty, ctx->initValue());
}
builder_.CreateStore(init, slot);
storage_map_[ctx] = slot;
return {};
}
std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
const std::string name = ctx->ID()->getText();
auto ty = BaseTypeFromDecl(
dynamic_cast<SysYParser::VarDeclContext*>(ctx->parent)->btype());
const auto dims = ctx->exp();
for (auto it = dims.rbegin(); it != dims.rend(); ++it) {
auto* dim = EvalConstExpr(**it);
if (auto* ci = dynamic_cast<ir::ConstantInt*>(dim)) {
ty = ir::ArrayType::Get(ty, ci->GetValue());
continue;
}
throw std::runtime_error(FormatError("irgen", "数组维度必须是整型常量"));
}
ir::Value* slot = nullptr;
if (is_global_scope_) {
ir::ConstantValue* init = nullptr;
if (ctx->initValue() && ctx->initValue()->exp()) {
init = EvalConstExpr(*ctx->initValue()->exp());
if (ty->IsInt32() && init->GetType()->IsFloat()) {
init = module_.GetContext().GetConstInt(
static_cast<int>(static_cast<ir::ConstantFloat*>(init)->GetValue()));
} else if (ty->IsFloat() && init->GetType()->IsInt32()) {
init = module_.GetContext().GetConstFloat(
static_cast<float>(static_cast<ir::ConstantInt*>(init)->GetValue()));
}
}
slot = module_.CreateGlobalValue(name, StorageType(ty), init);
} else {
slot = builder_.CreateAlloca(StorageType(ty), name);
ZeroInitializeLocal(slot, ty);
if (ctx->initValue()) EmitLocalInitValue(slot, ty, ctx->initValue());
}
storage_map_[ctx] = slot;
return {};
}

View File

@@ -6,9 +6,27 @@
#include "ir/IR.h"
#include "utils/Log.h"
static void PredeclareLibraryFunctions(ir::Module& module) {
module.CreateFunction("getint", ir::Type::GetInt32Type(), {});
module.CreateFunction("getch", ir::Type::GetInt32Type(), {});
module.CreateFunction("getfloat", ir::Type::GetFloatType(), {});
module.CreateFunction("getarray", ir::Type::GetInt32Type(), {ir::Type::GetPtrInt32Type()});
module.CreateFunction("getfarray", ir::Type::GetInt32Type(), {ir::Type::GetPtrFloatType()});
module.CreateFunction("putint", ir::Type::GetVoidType(), {ir::Type::GetInt32Type()});
module.CreateFunction("putch", ir::Type::GetVoidType(), {ir::Type::GetInt32Type()});
module.CreateFunction("putfloat", ir::Type::GetVoidType(), {ir::Type::GetFloatType()});
module.CreateFunction("putarray", ir::Type::GetVoidType(), {ir::Type::GetInt32Type(), ir::Type::GetPtrInt32Type()});
module.CreateFunction("putfarray", ir::Type::GetVoidType(), {ir::Type::GetInt32Type(), ir::Type::GetPtrFloatType()});
module.CreateFunction("starttime", ir::Type::GetVoidType(), {});
module.CreateFunction("stoptime", ir::Type::GetVoidType(), {});
// putf is special, but for now we might not support it fully or just declare it simply
// module.CreateFunction("putf", ...);
}
std::unique_ptr<ir::Module> GenerateIR(SysYParser::CompUnitContext& tree,
const SemanticContext& sema) {
auto module = std::make_unique<ir::Module>();
PredeclareLibraryFunctions(*module);
IRGenImpl gen(*module, sema);
tree.accept(&gen);
return module;

View File

@@ -1,80 +1,724 @@
#include "irgen/IRGen.h"
#include <cmath>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include "SysYParser.h"
#include "ir/IR.h"
#include "utils/Log.h"
// 表达式生成当前也只实现了很小的一个子集。
// 目前支持:
// - 整数字面量
// - 普通局部变量读取
// - 括号表达式
// - 二元加法
//
// 还未支持:
// - 减乘除与一元运算
// - 赋值表达式
// - 函数调用
// - 数组、指针、下标访问
// - 条件与比较表达式
// - ...
namespace {
bool IsZero(const ir::ConstantValue* value) {
if (auto* ci = dynamic_cast<const ir::ConstantInt*>(value)) {
return ci->GetValue() == 0;
}
if (auto* cf = dynamic_cast<const ir::ConstantFloat*>(value)) {
return cf->GetValue() == 0.0f;
}
return false;
}
bool IsTruthy(const ir::ConstantValue* value) {
return !IsZero(value);
}
int AsInt(const ir::ConstantValue* value) {
if (auto* ci = dynamic_cast<const ir::ConstantInt*>(value)) {
return ci->GetValue();
}
if (auto* cf = dynamic_cast<const ir::ConstantFloat*>(value)) {
return static_cast<int>(cf->GetValue());
}
throw std::runtime_error(FormatError("irgen", "无法将常量转换为 int"));
}
float AsFloat(const ir::ConstantValue* value) {
if (auto* cf = dynamic_cast<const ir::ConstantFloat*>(value)) {
return cf->GetValue();
}
if (auto* ci = dynamic_cast<const ir::ConstantInt*>(value)) {
return static_cast<float>(ci->GetValue());
}
throw std::runtime_error(FormatError("irgen", "无法将常量转换为 float"));
}
std::shared_ptr<ir::Type> ScalarPointerType(std::shared_ptr<ir::Type> ty) {
if (ty->IsInt32()) return ir::Type::GetPtrInt32Type();
if (ty->IsFloat()) return ir::Type::GetPtrFloatType();
return ty;
}
std::shared_ptr<ir::Type> CommonArithType(ir::Value* lhs, ir::Value* rhs) {
if (lhs->GetType()->IsFloat() || rhs->GetType()->IsFloat()) {
return ir::Type::GetFloatType();
}
return ir::Type::GetInt32Type();
}
} // namespace
ir::Value* IRGenImpl::EvalExpr(SysYParser::ExpContext& expr) {
return std::any_cast<ir::Value*>(expr.accept(this));
}
ir::ConstantValue* IRGenImpl::EvalConstExpr(SysYParser::ExpContext& expr) {
class ConstExprVisitor final : public SysYBaseVisitor {
public:
ConstExprVisitor(ir::Module& module, const SemanticContext& sema)
: module_(module), sema_(sema) {}
std::any visitParenExp(SysYParser::ParenExpContext* ctx) override {
return Eval(*ctx->exp());
}
std::any visitNumberExp(SysYParser::NumberExpContext* ctx) override {
if (ctx->number()->ILITERAL()) {
const std::string text = ctx->number()->ILITERAL()->getText();
int value = 0;
if (text.size() > 2 && (text[1] == 'x' || text[1] == 'X')) {
value = std::stoi(text, nullptr, 16);
} else if (text.size() > 1 && text[0] == '0') {
value = std::stoi(text, nullptr, 8);
} else {
value = std::stoi(text, nullptr, 10);
}
return static_cast<ir::ConstantValue*>(module_.GetContext().GetConstInt(value));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstFloat(std::stof(ctx->number()->FLITERAL()->getText())));
}
std::any visitLValueExp(SysYParser::LValueExpContext* ctx) override {
auto* def = sema_.ResolveLValue(ctx->lValue());
if (!def) {
throw std::runtime_error(FormatError("irgen", "常量表达式引用了未绑定左值"));
}
if (!ctx->lValue()->exp().empty()) {
throw std::runtime_error(
FormatError("irgen", "暂不支持在常量表达式中访问数组元素"));
}
if (auto* const_def = dynamic_cast<SysYParser::ConstDefContext*>(def)) {
if (!const_def->initValue() || !const_def->initValue()->exp()) {
throw std::runtime_error(
FormatError("irgen", "常量缺少标量初始化表达式"));
}
return Eval(*const_def->initValue()->exp());
}
throw std::runtime_error(
FormatError("irgen", "全局/常量表达式必须是编译期常量"));
}
std::any visitUnaryAddExp(SysYParser::UnaryAddExpContext* ctx) override {
return Eval(*ctx->exp());
}
std::any visitUnarySubExp(SysYParser::UnarySubExpContext* ctx) override {
auto* value = Eval(*ctx->exp());
if (value->GetType()->IsFloat()) {
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstFloat(-AsFloat(value)));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(-AsInt(value)));
}
std::any visitNotExp(SysYParser::NotExpContext* ctx) override {
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(IsTruthy(Eval(*ctx->exp())) ? 0 : 1));
}
std::any visitAddExp(SysYParser::AddExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
auto* rhs = Eval(*ctx->exp(1));
if (lhs->GetType()->IsFloat() || rhs->GetType()->IsFloat()) {
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstFloat(AsFloat(lhs) + AsFloat(rhs)));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(AsInt(lhs) + AsInt(rhs)));
}
std::any visitSubExp(SysYParser::SubExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
auto* rhs = Eval(*ctx->exp(1));
if (lhs->GetType()->IsFloat() || rhs->GetType()->IsFloat()) {
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstFloat(AsFloat(lhs) - AsFloat(rhs)));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(AsInt(lhs) - AsInt(rhs)));
}
std::any visitMulExp(SysYParser::MulExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
auto* rhs = Eval(*ctx->exp(1));
if (lhs->GetType()->IsFloat() || rhs->GetType()->IsFloat()) {
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstFloat(AsFloat(lhs) * AsFloat(rhs)));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(AsInt(lhs) * AsInt(rhs)));
}
std::any visitDivExp(SysYParser::DivExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
auto* rhs = Eval(*ctx->exp(1));
if (lhs->GetType()->IsFloat() || rhs->GetType()->IsFloat()) {
const float rv = AsFloat(rhs);
return static_cast<ir::ConstantValue*>(module_.GetContext().GetConstFloat(
rv == 0.0f ? 0.0f : AsFloat(lhs) / rv));
}
const int rv = AsInt(rhs);
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(rv == 0 ? 0 : AsInt(lhs) / rv));
}
std::any visitModExp(SysYParser::ModExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
auto* rhs = Eval(*ctx->exp(1));
return static_cast<ir::ConstantValue*>(module_.GetContext().GetConstInt(
AsInt(rhs) == 0 ? 0 : AsInt(lhs) % AsInt(rhs)));
}
std::any visitLtExp(SysYParser::LtExpContext* ctx) override {
return EvalCmpImpl(*ctx->exp(0), *ctx->exp(1), ir::Opcode::ICmpLT);
}
std::any visitLeExp(SysYParser::LeExpContext* ctx) override {
return EvalCmpImpl(*ctx->exp(0), *ctx->exp(1), ir::Opcode::ICmpLE);
}
std::any visitGtExp(SysYParser::GtExpContext* ctx) override {
return EvalCmpImpl(*ctx->exp(0), *ctx->exp(1), ir::Opcode::ICmpGT);
}
std::any visitGeExp(SysYParser::GeExpContext* ctx) override {
return EvalCmpImpl(*ctx->exp(0), *ctx->exp(1), ir::Opcode::ICmpGE);
}
std::any visitEqExp(SysYParser::EqExpContext* ctx) override {
return EvalCmpImpl(*ctx->exp(0), *ctx->exp(1), ir::Opcode::ICmpEQ);
}
std::any visitNeExp(SysYParser::NeExpContext* ctx) override {
return EvalCmpImpl(*ctx->exp(0), *ctx->exp(1), ir::Opcode::ICmpNE);
}
std::any visitAndExp(SysYParser::AndExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
if (!IsTruthy(lhs)) {
return static_cast<ir::ConstantValue*>(module_.GetContext().GetConstInt(0));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(IsTruthy(Eval(*ctx->exp(1))) ? 1 : 0));
}
std::any visitOrExp(SysYParser::OrExpContext* ctx) override {
auto* lhs = Eval(*ctx->exp(0));
if (IsTruthy(lhs)) {
return static_cast<ir::ConstantValue*>(module_.GetContext().GetConstInt(1));
}
return static_cast<ir::ConstantValue*>(
module_.GetContext().GetConstInt(IsTruthy(Eval(*ctx->exp(1))) ? 1 : 0));
}
ir::ConstantValue* Eval(SysYParser::ExpContext& ctx) {
return std::any_cast<ir::ConstantValue*>(ctx.accept(this));
}
private:
ir::ConstantValue* EvalCmpImpl(SysYParser::ExpContext& lhs_ctx,
SysYParser::ExpContext& rhs_ctx,
ir::Opcode op) {
auto* lhs = Eval(lhs_ctx);
auto* rhs = Eval(rhs_ctx);
bool result = false;
if (lhs->GetType()->IsFloat() || rhs->GetType()->IsFloat()) {
const float a = AsFloat(lhs);
const float b = AsFloat(rhs);
switch (op) {
case ir::Opcode::ICmpLT: result = a < b; break;
case ir::Opcode::ICmpLE: result = a <= b; break;
case ir::Opcode::ICmpGT: result = a > b; break;
case ir::Opcode::ICmpGE: result = a >= b; break;
case ir::Opcode::ICmpEQ: result = a == b; break;
case ir::Opcode::ICmpNE: result = a != b; break;
default: break;
}
} else {
const int a = AsInt(lhs);
const int b = AsInt(rhs);
switch (op) {
case ir::Opcode::ICmpLT: result = a < b; break;
case ir::Opcode::ICmpLE: result = a <= b; break;
case ir::Opcode::ICmpGT: result = a > b; break;
case ir::Opcode::ICmpGE: result = a >= b; break;
case ir::Opcode::ICmpEQ: result = a == b; break;
case ir::Opcode::ICmpNE: result = a != b; break;
default: break;
}
}
return module_.GetContext().GetConstInt(result ? 1 : 0);
}
ir::Module& module_;
const SemanticContext& sema_;
};
ConstExprVisitor visitor(module_, sema_);
return visitor.Eval(expr);
}
static ir::Value* CastValue(IRGenImpl& gen, ir::IRBuilder& builder, ir::Module& module,
ir::Value* value, std::shared_ptr<ir::Type> target_ty) {
if (value->GetType() == target_ty) return value;
if (target_ty->IsFloat() && value->GetType()->IsInt32()) {
if (auto* ci = dynamic_cast<ir::ConstantInt*>(value)) {
return module.GetContext().GetConstFloat(static_cast<float>(ci->GetValue()));
}
return builder.CreateSIToFP(value, target_ty, module.GetContext().NextTemp());
}
if (target_ty->IsInt32() && value->GetType()->IsFloat()) {
if (auto* cf = dynamic_cast<ir::ConstantFloat*>(value)) {
return module.GetContext().GetConstInt(static_cast<int>(cf->GetValue()));
}
return builder.CreateFPToSI(value, target_ty, module.GetContext().NextTemp());
}
return value;
}
std::any IRGenImpl::visitParenExp(SysYParser::ParenExpContext* ctx) {
if (!ctx || !ctx->exp()) {
throw std::runtime_error(FormatError("irgen", "非法括号表达式"));
}
return EvalExpr(*ctx->exp());
}
std::any IRGenImpl::visitLValueExp(SysYParser::LValueExpContext* ctx) {
auto* def = sema_.ResolveLValue(ctx->lValue());
if (def && IsArrayLikeDef(def) && ctx->lValue()->exp().size() < GetArrayRank(def)) {
return DecayArrayPtr(ctx->lValue());
}
ir::Value* ptr = GetLValuePtr(ctx->lValue());
return static_cast<ir::Value*>(
builder_.CreateLoad(ptr, module_.GetContext().NextTemp()));
}
std::any IRGenImpl::visitNumberExp(SysYParser::NumberExpContext* ctx) {
if (!ctx || !ctx->number() || !ctx->number()->ILITERAL()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持整数字面量"));
}
return static_cast<ir::Value*>(
builder_.CreateConstInt(std::stoi(ctx->number()->getText())));
return static_cast<ir::Value*>(EvalConstExpr(*ctx));
}
// 变量使用的处理流程:
// 1. 先通过语义分析结果把变量使用绑定回声明;
// 2. 再通过 storage_map_ 找到该声明对应的栈槽位;
// 3. 最后生成 load把内存中的值读出来。
//
// 因此当前 IRGen 自己不再做名字查找,而是直接消费 Sema 的绑定结果。
std::any IRGenImpl::visitVarExp(SysYParser::VarExpContext* ctx) {
if (!ctx || !ctx->var() || !ctx->var()->ID()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量"));
std::any IRGenImpl::visitFuncCallExp(SysYParser::FuncCallExpContext* ctx) {
ir::Function* target_func = nullptr;
if (auto* def = sema_.ResolveFuncCall(ctx)) {
const std::string func_name = def->ID()->getText();
for (const auto& f : module_.GetFunctions()) {
if (f->GetName() == func_name) {
target_func = f.get();
break;
}
}
} else {
const std::string func_name = ctx->ID()->getText();
for (const auto& f : module_.GetFunctions()) {
if (f->GetName() == func_name) {
target_func = f.get();
break;
}
}
}
auto* decl = sema_.ResolveVarUse(ctx->var());
if (!decl) {
throw std::runtime_error(
FormatError("irgen",
"变量使用缺少语义绑定: " + ctx->var()->ID()->getText()));
if (!target_func) {
throw std::runtime_error(FormatError("irgen", "找不到函数: " + ctx->ID()->getText()));
}
auto it = storage_map_.find(decl);
std::vector<ir::Value*> args;
const auto& arg_types = target_func->GetArguments();
if (ctx->funcRParams()) {
const auto& exps = ctx->funcRParams()->exp();
for (size_t i = 0; i < exps.size(); ++i) {
ir::Value* arg = EvalExpr(*exps[i]);
if (i < arg_types.size()) {
arg = CastValue(*this, builder_, module_, arg, arg_types[i]->GetType());
}
args.push_back(arg);
}
}
return static_cast<ir::Value*>(
builder_.CreateCall(target_func, args,
target_func->GetType()->IsVoid()
? ""
: module_.GetContext().NextTemp()));
}
std::any IRGenImpl::visitNotExp(SysYParser::NotExpContext* ctx) {
ir::Value* val = EvalExpr(*ctx->exp());
if (auto* cv = dynamic_cast<ir::ConstantValue*>(val)) {
return static_cast<ir::Value*>(
module_.GetContext().GetConstInt(IsTruthy(cv) ? 0 : 1));
}
ir::Value* cond = ToI1(val);
ir::Value* res =
builder_.CreateICmp(ir::Opcode::ICmpEQ, cond, builder_.CreateConstInt(0),
module_.GetContext().NextTemp());
return ToI32(res);
}
std::any IRGenImpl::visitUnaryAddExp(SysYParser::UnaryAddExpContext* ctx) {
return EvalExpr(*ctx->exp());
}
std::any IRGenImpl::visitUnarySubExp(SysYParser::UnarySubExpContext* ctx) {
ir::Value* val = EvalExpr(*ctx->exp());
if (auto* ci = dynamic_cast<ir::ConstantInt*>(val)) {
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(-ci->GetValue()));
}
if (auto* cf = dynamic_cast<ir::ConstantFloat*>(val)) {
return static_cast<ir::Value*>(module_.GetContext().GetConstFloat(-cf->GetValue()));
}
if (val->GetType()->IsFloat()) {
return static_cast<ir::Value*>(builder_.CreateFSub(
builder_.CreateConstFloat(0.0f), val, module_.GetContext().NextTemp()));
}
return static_cast<ir::Value*>(builder_.CreateSub(
builder_.CreateConstInt(0), val, module_.GetContext().NextTemp()));
}
#define DEFINE_ARITH_VISITOR(name, int_opcode, float_opcode) \
std::any IRGenImpl::visit##name##Exp(SysYParser::name##ExpContext* ctx) { \
ir::Value* lhs = EvalExpr(*ctx->exp(0)); \
ir::Value* rhs = EvalExpr(*ctx->exp(1)); \
const auto common_ty = CommonArithType(lhs, rhs); \
lhs = CastValue(*this, builder_, module_, lhs, common_ty); \
rhs = CastValue(*this, builder_, module_, rhs, common_ty); \
if (auto* lconst = dynamic_cast<ir::ConstantValue*>(lhs)) { \
if (auto* rconst = dynamic_cast<ir::ConstantValue*>(rhs)) { \
if (common_ty->IsFloat()) { \
const float lv = AsFloat(lconst); \
const float rv = AsFloat(rconst); \
if constexpr (ir::Opcode::float_opcode == ir::Opcode::FAdd) \
return static_cast<ir::Value*>(module_.GetContext().GetConstFloat(lv + rv)); \
if constexpr (ir::Opcode::float_opcode == ir::Opcode::FSub) \
return static_cast<ir::Value*>(module_.GetContext().GetConstFloat(lv - rv)); \
if constexpr (ir::Opcode::float_opcode == ir::Opcode::FMul) \
return static_cast<ir::Value*>(module_.GetContext().GetConstFloat(lv * rv)); \
return static_cast<ir::Value*>(module_.GetContext().GetConstFloat(rv == 0.0f ? 0.0f : lv / rv)); \
} \
const int lv = AsInt(lconst); \
const int rv = AsInt(rconst); \
if constexpr (ir::Opcode::int_opcode == ir::Opcode::Add) \
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(lv + rv)); \
if constexpr (ir::Opcode::int_opcode == ir::Opcode::Sub) \
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(lv - rv)); \
if constexpr (ir::Opcode::int_opcode == ir::Opcode::Mul) \
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(lv * rv)); \
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(rv == 0 ? 0 : lv / rv)); \
} \
} \
if (common_ty->IsFloat()) { \
if constexpr (ir::Opcode::float_opcode == ir::Opcode::FAdd) \
return static_cast<ir::Value*>(builder_.CreateFAdd(lhs, rhs, module_.GetContext().NextTemp())); \
if constexpr (ir::Opcode::float_opcode == ir::Opcode::FSub) \
return static_cast<ir::Value*>(builder_.CreateFSub(lhs, rhs, module_.GetContext().NextTemp())); \
if constexpr (ir::Opcode::float_opcode == ir::Opcode::FMul) \
return static_cast<ir::Value*>(builder_.CreateFMul(lhs, rhs, module_.GetContext().NextTemp())); \
return static_cast<ir::Value*>(builder_.CreateFDiv(lhs, rhs, module_.GetContext().NextTemp())); \
} \
return static_cast<ir::Value*>(builder_.CreateBinary(ir::Opcode::int_opcode, lhs, rhs, module_.GetContext().NextTemp())); \
}
DEFINE_ARITH_VISITOR(Add, Add, FAdd)
DEFINE_ARITH_VISITOR(Sub, Sub, FSub)
DEFINE_ARITH_VISITOR(Mul, Mul, FMul)
DEFINE_ARITH_VISITOR(Div, Div, FDiv)
std::any IRGenImpl::visitModExp(SysYParser::ModExpContext* ctx) {
ir::Value* lhs = CastValue(*this, builder_, module_, EvalExpr(*ctx->exp(0)),
ir::Type::GetInt32Type());
ir::Value* rhs = CastValue(*this, builder_, module_, EvalExpr(*ctx->exp(1)),
ir::Type::GetInt32Type());
if (auto* lconst = dynamic_cast<ir::ConstantValue*>(lhs)) {
if (auto* rconst = dynamic_cast<ir::ConstantValue*>(rhs)) {
const int rv = AsInt(rconst);
return static_cast<ir::Value*>(
module_.GetContext().GetConstInt(rv == 0 ? 0 : AsInt(lconst) % rv));
}
}
return static_cast<ir::Value*>(
builder_.CreateMod(lhs, rhs, module_.GetContext().NextTemp()));
}
#define DEFINE_CMP_VISITOR(name, int_opcode, float_opcode, cmp_op) \
std::any IRGenImpl::visit##name##Exp(SysYParser::name##ExpContext* ctx) { \
ir::Value* lhs = EvalExpr(*ctx->exp(0)); \
ir::Value* rhs = EvalExpr(*ctx->exp(1)); \
const auto common_ty = CommonArithType(lhs, rhs); \
lhs = CastValue(*this, builder_, module_, lhs, common_ty); \
rhs = CastValue(*this, builder_, module_, rhs, common_ty); \
if (auto* lconst = dynamic_cast<ir::ConstantValue*>(lhs)) { \
if (auto* rconst = dynamic_cast<ir::ConstantValue*>(rhs)) { \
const bool result = common_ty->IsFloat() ? (AsFloat(lconst) cmp_op AsFloat(rconst)) \
: (AsInt(lconst) cmp_op AsInt(rconst)); \
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(result ? 1 : 0)); \
} \
} \
if (common_ty->IsFloat()) { \
return static_cast<ir::Value*>(builder_.CreateFCmp(ir::Opcode::float_opcode, lhs, rhs, module_.GetContext().NextTemp())); \
} \
return static_cast<ir::Value*>(builder_.CreateICmp(ir::Opcode::int_opcode, lhs, rhs, module_.GetContext().NextTemp())); \
}
DEFINE_CMP_VISITOR(Lt, ICmpLT, FCmpLT, <)
DEFINE_CMP_VISITOR(Le, ICmpLE, FCmpLE, <=)
DEFINE_CMP_VISITOR(Gt, ICmpGT, FCmpGT, >)
DEFINE_CMP_VISITOR(Ge, ICmpGE, FCmpGE, >=)
DEFINE_CMP_VISITOR(Eq, ICmpEQ, FCmpEQ, ==)
DEFINE_CMP_VISITOR(Ne, ICmpNE, FCmpNE, !=)
std::any IRGenImpl::visitAndExp(SysYParser::AndExpContext* ctx) {
if (!builder_.GetInsertBlock()) {
return static_cast<ir::Value*>(EvalConstExpr(*ctx));
}
ir::Value* lhs = EvalExpr(*ctx->exp(0));
if (auto* c = dynamic_cast<ir::ConstantValue*>(lhs); c && !IsTruthy(c)) {
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(0));
}
const std::string suffix = module_.GetContext().NextTemp();
ir::BasicBlock* rhs_bb = func_->CreateBlock("and.rhs." + suffix);
ir::BasicBlock* merge_bb = func_->CreateBlock("and.merge." + suffix);
auto* res_ptr = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
builder_.CreateStore(ToI32(ToI1(lhs)), res_ptr);
builder_.CreateCondBr(ToI1(lhs), rhs_bb, merge_bb);
builder_.SetInsertPoint(rhs_bb);
ir::Value* rhs = EvalExpr(*ctx->exp(1));
builder_.CreateStore(ToI32(ToI1(rhs)), res_ptr);
builder_.CreateBr(merge_bb);
builder_.SetInsertPoint(merge_bb);
return static_cast<ir::Value*>(
builder_.CreateLoad(res_ptr, module_.GetContext().NextTemp()));
}
std::any IRGenImpl::visitOrExp(SysYParser::OrExpContext* ctx) {
if (!builder_.GetInsertBlock()) {
return static_cast<ir::Value*>(EvalConstExpr(*ctx));
}
ir::Value* lhs = EvalExpr(*ctx->exp(0));
if (auto* c = dynamic_cast<ir::ConstantValue*>(lhs); c && IsTruthy(c)) {
return static_cast<ir::Value*>(module_.GetContext().GetConstInt(1));
}
const std::string suffix = module_.GetContext().NextTemp();
ir::BasicBlock* rhs_bb = func_->CreateBlock("or.rhs." + suffix);
ir::BasicBlock* merge_bb = func_->CreateBlock("or.merge." + suffix);
auto* res_ptr = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
builder_.CreateStore(ToI32(ToI1(lhs)), res_ptr);
builder_.CreateCondBr(ToI1(lhs), merge_bb, rhs_bb);
builder_.SetInsertPoint(rhs_bb);
ir::Value* rhs = EvalExpr(*ctx->exp(1));
builder_.CreateStore(ToI32(ToI1(rhs)), res_ptr);
builder_.CreateBr(merge_bb);
builder_.SetInsertPoint(merge_bb);
return static_cast<ir::Value*>(
builder_.CreateLoad(res_ptr, module_.GetContext().NextTemp()));
}
bool IRGenImpl::IsArrayLikeDef(antlr4::ParserRuleContext* def) const {
if (auto* const_def = dynamic_cast<SysYParser::ConstDefContext*>(def)) {
return !const_def->exp().empty();
}
if (auto* var_def = dynamic_cast<SysYParser::VarDefContext*>(def)) {
return !var_def->exp().empty();
}
if (auto* param = dynamic_cast<SysYParser::FuncFParamContext*>(def)) {
return !param->LBRACK().empty();
}
return false;
}
size_t IRGenImpl::GetArrayRank(antlr4::ParserRuleContext* def) const {
if (auto* const_def = dynamic_cast<SysYParser::ConstDefContext*>(def)) {
return const_def->exp().size();
}
if (auto* var_def = dynamic_cast<SysYParser::VarDefContext*>(def)) {
return var_def->exp().size();
}
if (auto* param = dynamic_cast<SysYParser::FuncFParamContext*>(def)) {
return param->LBRACK().size();
}
return 0;
}
std::shared_ptr<ir::Type> IRGenImpl::GetDefType(antlr4::ParserRuleContext* def) const {
std::shared_ptr<ir::Type> ty = ir::Type::GetInt32Type();
auto apply_dims = [&](const auto& dims) {
auto result = ty;
for (auto it = dims.rbegin(); it != dims.rend(); ++it) {
if constexpr (std::is_pointer_v<typename std::decay_t<decltype(*it)>>) {
auto* dim_val = const_cast<IRGenImpl*>(this)->EvalConstExpr(**it);
result = ir::ArrayType::Get(result, AsInt(dim_val));
} else {
auto* dim_val = const_cast<IRGenImpl*>(this)->EvalConstExpr(*it);
result = ir::ArrayType::Get(result, AsInt(dim_val));
}
}
return result;
};
if (auto* const_def = dynamic_cast<SysYParser::ConstDefContext*>(def)) {
auto* decl = dynamic_cast<SysYParser::ConstDeclContext*>(const_def->parent);
ty = (decl && decl->btype() && decl->btype()->FLOAT()) ? ir::Type::GetFloatType()
: ir::Type::GetInt32Type();
return apply_dims(const_def->exp());
}
if (auto* var_def = dynamic_cast<SysYParser::VarDefContext*>(def)) {
auto* decl = dynamic_cast<SysYParser::VarDeclContext*>(var_def->parent);
ty = (decl && decl->btype() && decl->btype()->FLOAT()) ? ir::Type::GetFloatType()
: ir::Type::GetInt32Type();
return apply_dims(var_def->exp());
}
if (auto* param = dynamic_cast<SysYParser::FuncFParamContext*>(def)) {
ty = param->btype()->FLOAT() ? ir::Type::GetFloatType() : ir::Type::GetInt32Type();
if (param->LBRACK().empty()) return ty;
for (int i = static_cast<int>(param->exp().size()) - 1; i >= 0; --i) {
auto* dim_val = const_cast<IRGenImpl*>(this)->EvalConstExpr(*param->exp(i));
ty = ir::ArrayType::Get(ty, AsInt(dim_val));
}
return ty;
}
return ty;
}
ir::Value* IRGenImpl::DecayArrayPtr(SysYParser::LValueContext* ctx) {
auto* def = sema_.ResolveLValue(ctx);
if (!def) {
throw std::runtime_error(FormatError("irgen", "数组退化失败: 未绑定定义"));
}
ir::Value* base_ptr = storage_map_.at(def);
const auto base_ty = GetDefType(def);
if (dynamic_cast<SysYParser::FuncFParamContext*>(def)) {
if (ctx->exp().empty()) return base_ptr;
ir::Value* offset = CastValue(*this, builder_, module_, EvalExpr(*ctx->exp(0)),
ir::Type::GetInt32Type());
auto cur_ty = base_ty;
for (size_t i = 1; i < ctx->exp().size(); ++i) {
if (!cur_ty->IsArray()) break;
auto arr_ty = cur_ty->GetAsArrayType();
ir::Value* stride = builder_.CreateConstInt(static_cast<int>(arr_ty->GetNumElements()));
offset = builder_.CreateMul(offset, stride, module_.GetContext().NextTemp());
offset = builder_.CreateAdd(
offset,
CastValue(*this, builder_, module_, EvalExpr(*ctx->exp(i)),
ir::Type::GetInt32Type()),
module_.GetContext().NextTemp());
cur_ty = arr_ty->GetElementType();
}
return builder_.CreateGEP(ScalarPointerType(cur_ty), base_ptr, {offset},
module_.GetContext().NextTemp());
}
std::vector<ir::Value*> indices;
indices.push_back(builder_.CreateConstInt(0));
for (auto* exp : ctx->exp()) {
indices.push_back(
CastValue(*this, builder_, module_, EvalExpr(*exp), ir::Type::GetInt32Type()));
}
auto cur_ty = base_ty;
while (cur_ty->IsArray()) {
cur_ty = cur_ty->GetAsArrayType()->GetElementType();
}
if (!ctx->exp().empty()) {
return builder_.CreateGEP(ScalarPointerType(cur_ty), base_ptr, indices,
module_.GetContext().NextTemp());
}
indices.push_back(builder_.CreateConstInt(0));
return builder_.CreateGEP(ScalarPointerType(cur_ty), base_ptr, indices,
module_.GetContext().NextTemp());
}
ir::Value* IRGenImpl::GetLValuePtr(SysYParser::LValueContext* ctx) {
auto* def = sema_.ResolveLValue(ctx);
if (!def) {
throw std::runtime_error(FormatError("irgen", "未定义的左值: " + ctx->ID()->getText()));
}
auto it = storage_map_.find(def);
if (it == storage_map_.end()) {
throw std::runtime_error(
FormatError("irgen",
"变量声明缺少存储槽位: " + ctx->var()->ID()->getText()));
FormatError("irgen", "左值缺少存储槽位: " + ctx->ID()->getText()));
}
return static_cast<ir::Value*>(
builder_.CreateLoad(it->second, module_.GetContext().NextTemp()));
ir::Value* base_ptr = it->second;
if (ctx->exp().empty()) return base_ptr;
if (dynamic_cast<SysYParser::FuncFParamContext*>(def)) {
return DecayArrayPtr(ctx);
}
const auto base_ty = GetDefType(def);
std::vector<ir::Value*> indices;
indices.push_back(builder_.CreateConstInt(0));
for (auto* exp : ctx->exp()) {
indices.push_back(
CastValue(*this, builder_, module_, EvalExpr(*exp), ir::Type::GetInt32Type()));
}
auto cur_ty = base_ty;
for (size_t i = 0; i < ctx->exp().size(); ++i) {
if (!cur_ty->IsArray()) {
throw std::runtime_error(FormatError("irgen", "数组下标层数超出定义"));
}
cur_ty = cur_ty->GetAsArrayType()->GetElementType();
}
return builder_.CreateGEP(ScalarPointerType(cur_ty), base_ptr, indices,
module_.GetContext().NextTemp());
}
std::any IRGenImpl::visitAdditiveExp(SysYParser::AdditiveExpContext* ctx) {
if (!ctx || !ctx->exp(0) || !ctx->exp(1)) {
throw std::runtime_error(FormatError("irgen", "非法加法表达式"));
ir::Value* IRGenImpl::ToI1(ir::Value* v) {
if (auto* cv = dynamic_cast<ir::ConstantValue*>(v)) {
return module_.GetContext().GetConstInt(IsTruthy(cv) ? 1 : 0);
}
ir::Value* lhs = EvalExpr(*ctx->exp(0));
ir::Value* rhs = EvalExpr(*ctx->exp(1));
return static_cast<ir::Value*>(
builder_.CreateBinary(ir::Opcode::Add, lhs, rhs,
module_.GetContext().NextTemp()));
if (auto* inst = dynamic_cast<ir::Instruction*>(v)) {
switch (inst->GetOpcode()) {
case ir::Opcode::ICmpEQ:
case ir::Opcode::ICmpNE:
case ir::Opcode::ICmpLT:
case ir::Opcode::ICmpGT:
case ir::Opcode::ICmpLE:
case ir::Opcode::ICmpGE:
case ir::Opcode::FCmpEQ:
case ir::Opcode::FCmpNE:
case ir::Opcode::FCmpLT:
case ir::Opcode::FCmpGT:
case ir::Opcode::FCmpLE:
case ir::Opcode::FCmpGE:
return v;
default:
break;
}
}
if (v->GetType()->IsFloat()) {
return builder_.CreateFCmp(ir::Opcode::FCmpNE, v, builder_.CreateConstFloat(0.0f),
module_.GetContext().NextTemp());
}
if (v->GetType()->IsInt32()) {
return builder_.CreateICmp(ir::Opcode::ICmpNE, v, builder_.CreateConstInt(0),
module_.GetContext().NextTemp());
}
return v;
}
ir::Value* IRGenImpl::ToI32(ir::Value* v) {
if (v->GetType()->IsInt32()) return v;
if (v->GetType()->IsFloat()) {
return builder_.CreateFPToSI(v, ir::Type::GetInt32Type(),
module_.GetContext().NextTemp());
}
return builder_.CreateZExt(v, ir::Type::GetInt32Type(),
module_.GetContext().NextTemp());
}

View File

@@ -8,10 +8,18 @@
namespace {
std::shared_ptr<ir::Type> StorageType(std::shared_ptr<ir::Type> ty) {
if (ty->IsInt32()) return ir::Type::GetPtrInt32Type();
if (ty->IsFloat()) return ir::Type::GetPtrFloatType();
return ty;
}
void VerifyFunctionStructure(const ir::Function& func) {
// 当前 IRGen 仍是单入口、顺序生成;这里在生成结束后补一层块终结校验。
for (const auto& bb : func.GetBlocks()) {
if (!bb || !bb->HasTerminator()) {
// If a block doesn't have a terminator, it might be an empty function or
// missing a return in a path. For SysY, we should at least have a default return for void.
// But IRGen should have handled it.
throw std::runtime_error(
FormatError("irgen", "基本块未正确终结: " +
(bb ? bb->GetName() : std::string("<null>"))));
@@ -25,63 +33,83 @@ IRGenImpl::IRGenImpl(ir::Module& module, const SemanticContext& sema)
: module_(module),
sema_(sema),
func_(nullptr),
builder_(module.GetContext(), nullptr) {}
builder_(module.GetContext(), nullptr),
is_global_scope_(true) {}
// 编译单元的 IR 生成当前只实现了最小功能:
// - Module 已在 GenerateIR 中创建,这里只负责继续生成其中的内容;
// - 当前会读取编译单元中的函数定义,并交给 visitFuncDef 生成函数 IR
//
// 当前还没有实现:
// - 多个函数定义的遍历与生成;
// - 全局变量、全局常量的 IR 生成。
std::any IRGenImpl::visitCompUnit(SysYParser::CompUnitContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少编译单元"));
if (!ctx) return {};
is_global_scope_ = true;
for (auto* decl : ctx->decl()) {
decl->accept(this);
}
auto* func = ctx->funcDef();
if (!func) {
throw std::runtime_error(FormatError("irgen", "缺少函数定义"));
for (auto* funcDef : ctx->funcDef()) {
funcDef->accept(this);
}
func->accept(this);
return {};
}
// 函数 IR 生成当前实现了:
// 1. 获取函数名;
// 2. 检查函数返回类型;
// 3. 在 Module 中创建 Function
// 4. 将 builder 插入点设置到入口基本块;
// 5. 继续生成函数体。
//
// 当前还没有实现:
// - 通用函数返回类型处理;
// - 形参列表遍历与参数类型收集;
// - FunctionType 这样的函数类型对象;
// - Argument/形式参数 IR 对象;
// - 入口块中的参数初始化逻辑。
// ...
// 因此这里目前只支持最小的“无参 int 函数”生成。
std::any IRGenImpl::visitFuncDef(SysYParser::FuncDefContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少函数定义"));
}
if (!ctx->blockStmt()) {
throw std::runtime_error(FormatError("irgen", "函数体为空"));
}
if (!ctx->ID()) {
throw std::runtime_error(FormatError("irgen", "缺少函数名"));
}
if (!ctx->funcType() || !ctx->funcType()->INT()) {
throw std::runtime_error(FormatError("irgen", "当前仅支持无参 int 函数"));
is_global_scope_ = false;
std::shared_ptr<ir::Type> ret_ty;
if (ctx->funcType()->INT()) {
ret_ty = ir::Type::GetInt32Type();
} else if (ctx->funcType()->FLOAT()) {
ret_ty = ir::Type::GetFloatType();
} else {
ret_ty = ir::Type::GetVoidType();
}
func_ = module_.CreateFunction(ctx->ID()->getText(), ir::Type::GetInt32Type());
builder_.SetInsertPoint(func_->GetEntry());
storage_map_.clear();
std::string func_name = ctx->ID()->getText();
std::vector<std::shared_ptr<ir::Type>> param_types;
if (ctx->funcFParams()) {
for (auto* fparam : ctx->funcFParams()->funcFParam()) {
if (fparam->LBRACK().empty()) {
param_types.push_back(fparam->btype()->INT() ? ir::Type::GetInt32Type() : ir::Type::GetFloatType());
} else {
// Array param is a pointer
param_types.push_back(fparam->btype()->INT() ? ir::Type::GetPtrInt32Type() : ir::Type::GetPtrFloatType());
}
}
}
func_ = module_.CreateFunction(func_name, ret_ty, param_types);
builder_.SetInsertPoint(func_->CreateBlock("entry"));
// Handle parameters: alloca and store
if (ctx->funcFParams()) {
const auto& fparams = ctx->funcFParams()->funcFParam();
const auto& args = func_->GetArguments();
for (size_t i = 0; i < fparams.size(); ++i) {
auto* fparam = fparams[i];
auto* arg = args[i].get();
auto* slot = builder_.CreateAlloca(StorageType(arg->GetType()), fparam->ID()->getText());
builder_.CreateStore(arg, slot);
storage_map_[fparam] = slot;
}
}
ctx->blockStmt()->accept(this);
// 语义正确性主要由 sema 保证,这里只兜底检查 IR 结构是否合法。
// Default return for void functions if not terminated
if (!builder_.GetInsertBlock()->HasTerminator()) {
if (ret_ty->IsVoid()) {
builder_.CreateRet(nullptr);
} else if (ret_ty->IsInt32()) {
builder_.CreateRet(builder_.CreateConstInt(0));
} else if (ret_ty->IsFloat()) {
builder_.CreateRet(builder_.CreateConstFloat(0.0f));
}
}
VerifyFunctionStructure(*func_);
is_global_scope_ = true;
return {};
}
std::any IRGenImpl::visitFuncFParam(SysYParser::FuncFParamContext* ctx) {
// We handle fparams in visitFuncDef directly.
return {};
}

View File

@@ -6,34 +6,146 @@
#include "ir/IR.h"
#include "utils/Log.h"
// 语句生成当前只实现了最小子集。
// 目前支持:
// - return <exp>;
//
// 还未支持:
// - 赋值语句
// - if / while 等控制流
// - 空语句、块语句嵌套分发之外的更多语句形态
// 语句生成
std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少语句"));
}
if (ctx->returnStmt()) {
return ctx->returnStmt()->accept(this);
}
throw std::runtime_error(FormatError("irgen", "暂不支持的语句类型"));
if (!ctx) return BlockFlow::Continue;
if (ctx->assignStmt()) return ctx->assignStmt()->accept(this);
if (ctx->returnStmt()) return ctx->returnStmt()->accept(this);
if (ctx->blockStmt()) return ctx->blockStmt()->accept(this);
if (ctx->ifStmt()) return ctx->ifStmt()->accept(this);
if (ctx->whileStmt()) return ctx->whileStmt()->accept(this);
if (ctx->breakStmt()) return ctx->breakStmt()->accept(this);
if (ctx->continueStmt()) return ctx->continueStmt()->accept(this);
if (ctx->expStmt()) return ctx->expStmt()->accept(this);
return BlockFlow::Continue;
}
std::any IRGenImpl::visitBlockStmt(SysYParser::BlockStmtContext* ctx) {
for (auto* item : ctx->blockItem()) {
if (std::any_cast<BlockFlow>(item->accept(this)) == BlockFlow::Terminated) {
return BlockFlow::Terminated;
}
}
return BlockFlow::Continue;
}
std::any IRGenImpl::visitBlockItem(SysYParser::BlockItemContext* ctx) {
if (ctx->decl()) {
ctx->decl()->accept(this);
return BlockFlow::Continue;
}
if (ctx->stmt()) {
return ctx->stmt()->accept(this);
}
return BlockFlow::Continue;
}
std::any IRGenImpl::visitAssignStmt(SysYParser::AssignStmtContext* ctx) {
ir::Value* ptr = GetLValuePtr(ctx->lValue());
ir::Value* val = EvalExpr(*ctx->exp());
if (ptr->GetType()->IsPtrFloat() && val->GetType()->IsInt32()) {
val = builder_.CreateSIToFP(val, ir::Type::GetFloatType(),
module_.GetContext().NextTemp());
} else if (ptr->GetType()->IsPtrInt32() && val->GetType()->IsFloat()) {
val = builder_.CreateFPToSI(val, ir::Type::GetInt32Type(),
module_.GetContext().NextTemp());
}
builder_.CreateStore(val, ptr);
return BlockFlow::Continue;
}
std::any IRGenImpl::visitReturnStmt(SysYParser::ReturnStmtContext* ctx) {
if (!ctx) {
throw std::runtime_error(FormatError("irgen", "缺少 return 语句"));
if (ctx->exp()) {
ir::Value* v = EvalExpr(*ctx->exp());
if (func_->GetType()->IsFloat() && v->GetType()->IsInt32()) {
v = builder_.CreateSIToFP(v, ir::Type::GetFloatType(),
module_.GetContext().NextTemp());
} else if (func_->GetType()->IsInt32() && v->GetType()->IsFloat()) {
v = builder_.CreateFPToSI(v, ir::Type::GetInt32Type(),
module_.GetContext().NextTemp());
}
builder_.CreateRet(v);
} else {
builder_.CreateRet(nullptr);
}
if (!ctx->exp()) {
throw std::runtime_error(FormatError("irgen", "return 缺少表达式"));
}
ir::Value* v = EvalExpr(*ctx->exp());
builder_.CreateRet(v);
return BlockFlow::Terminated;
}
std::any IRGenImpl::visitIfStmt(SysYParser::IfStmtContext* ctx) {
const std::string suffix = module_.GetContext().NextTemp();
ir::BasicBlock* true_bb = func_->CreateBlock("if.true." + suffix);
ir::BasicBlock* false_bb =
ctx->ELSE() ? func_->CreateBlock("if.false." + suffix) : nullptr;
ir::BasicBlock* merge_bb = func_->CreateBlock("if.merge." + suffix);
ir::Value* cond = EvalExpr(*ctx->exp());
builder_.CreateCondBr(ToI1(cond), true_bb, false_bb ? false_bb : merge_bb);
// True block
builder_.SetInsertPoint(true_bb);
if (std::any_cast<BlockFlow>(ctx->stmt(0)->accept(this)) == BlockFlow::Continue) {
builder_.CreateBr(merge_bb);
}
// False block
if (false_bb) {
builder_.SetInsertPoint(false_bb);
if (std::any_cast<BlockFlow>(ctx->stmt(1)->accept(this)) == BlockFlow::Continue) {
builder_.CreateBr(merge_bb);
}
}
builder_.SetInsertPoint(merge_bb);
return BlockFlow::Continue;
}
std::any IRGenImpl::visitWhileStmt(SysYParser::WhileStmtContext* ctx) {
const std::string suffix = module_.GetContext().NextTemp();
ir::BasicBlock* cond_bb = func_->CreateBlock("while.cond." + suffix);
ir::BasicBlock* body_bb = func_->CreateBlock("while.body." + suffix);
ir::BasicBlock* end_bb = func_->CreateBlock("while.end." + suffix);
builder_.CreateBr(cond_bb);
builder_.SetInsertPoint(cond_bb);
ir::Value* cond = EvalExpr(*ctx->exp());
builder_.CreateCondBr(ToI1(cond), body_bb, end_bb);
break_stack_.push(end_bb);
continue_stack_.push(cond_bb);
builder_.SetInsertPoint(body_bb);
if (std::any_cast<BlockFlow>(ctx->stmt()->accept(this)) == BlockFlow::Continue) {
builder_.CreateBr(cond_bb);
}
break_stack_.pop();
continue_stack_.pop();
builder_.SetInsertPoint(end_bb);
return BlockFlow::Continue;
}
std::any IRGenImpl::visitBreakStmt(SysYParser::BreakStmtContext* ctx) {
if (break_stack_.empty()) {
throw std::runtime_error(FormatError("irgen", "break 语句不在循环内"));
}
builder_.CreateBr(break_stack_.top());
return BlockFlow::Terminated;
}
std::any IRGenImpl::visitContinueStmt(SysYParser::ContinueStmtContext* ctx) {
if (continue_stack_.empty()) {
throw std::runtime_error(FormatError("irgen", "continue 语句不在循环内"));
}
builder_.CreateBr(continue_stack_.top());
return BlockFlow::Terminated;
}
std::any IRGenImpl::visitExpStmt(SysYParser::ExpStmtContext* ctx) {
if (ctx->exp()) {
EvalExpr(*ctx->exp());
}
return BlockFlow::Continue;
}

View File

@@ -10,185 +10,321 @@
namespace {
std::string GetLValueName(SysYParser::LValueContext& lvalue) {
if (!lvalue.ID()) {
throw std::runtime_error(FormatError("sema", "非法左值"));
}
return lvalue.ID()->getText();
}
class SemaVisitor final : public SysYBaseVisitor {
public:
explicit SemaVisitor() {
// 预填标准库函数
AddBuiltin("getint", Symbol::Kind::Function);
AddBuiltin("getch", Symbol::Kind::Function);
AddBuiltin("getfloat", Symbol::Kind::Function);
AddBuiltin("getarray", Symbol::Kind::Function);
AddBuiltin("getfarray", Symbol::Kind::Function);
AddBuiltin("putint", Symbol::Kind::Function);
AddBuiltin("putch", Symbol::Kind::Function);
AddBuiltin("putfloat", Symbol::Kind::Function);
AddBuiltin("putarray", Symbol::Kind::Function);
AddBuiltin("putfarray", Symbol::Kind::Function);
AddBuiltin("starttime", Symbol::Kind::Function);
AddBuiltin("stoptime", Symbol::Kind::Function);
AddBuiltin("putf", Symbol::Kind::Function);
}
private:
void AddBuiltin(const std::string& name, Symbol::Kind kind) {
Symbol sym;
sym.kind = kind;
sym.def_ctx = nullptr; // 内建函数没有语法树节点
table_.Add(name, sym);
}
std::any visitCompUnit(SysYParser::CompUnitContext* ctx) override {
if (!ctx) {
throw std::runtime_error(FormatError("sema", "缺少编译单元"));
if (!ctx) return {};
for (auto* child : ctx->children) {
if (auto* decl = dynamic_cast<SysYParser::DeclContext*>(child)) {
decl->accept(this);
} else if (auto* funcDef = dynamic_cast<SysYParser::FuncDefContext*>(child)) {
funcDef->accept(this);
}
}
auto* func = ctx->funcDef();
if (!func || !func->blockStmt()) {
throw std::runtime_error(FormatError("sema", "缺少 main 函数定义"));
return {};
}
std::any visitDecl(SysYParser::DeclContext* ctx) override {
if (ctx->constDecl()) return ctx->constDecl()->accept(this);
if (ctx->varDecl()) return ctx->varDecl()->accept(this);
return {};
}
std::any visitConstDecl(SysYParser::ConstDeclContext* ctx) override {
for (auto* def : ctx->constDef()) {
const std::string name = def->ID()->getText();
if (table_.IsInCurrentScope(name)) {
throw std::runtime_error(FormatError("sema", "重复定义常量: " + name));
}
Symbol sym;
sym.kind = Symbol::Kind::Constant;
sym.def_ctx = def;
sym.is_const = true;
sym.is_array = !def->exp().empty();
table_.Add(name, sym);
for (auto* exp : def->exp()) exp->accept(this);
def->initValue()->accept(this);
}
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 语句"));
return {};
}
std::any visitVarDecl(SysYParser::VarDeclContext* ctx) override {
for (auto* def : ctx->varDef()) {
const std::string name = def->ID()->getText();
if (table_.IsInCurrentScope(name)) {
throw std::runtime_error(FormatError("sema", "重复定义变量: " + name));
}
Symbol sym;
sym.kind = Symbol::Kind::Variable;
sym.def_ctx = def;
sym.is_const = false;
sym.is_array = !def->exp().empty();
table_.Add(name, sym);
for (auto* exp : def->exp()) exp->accept(this);
if (def->initValue()) def->initValue()->accept(this);
}
return {};
}
std::any visitFuncDef(SysYParser::FuncDefContext* ctx) override {
if (!ctx || !ctx->blockStmt()) {
throw std::runtime_error(FormatError("sema", "缺少 main 函数定义"));
const std::string name = ctx->ID()->getText();
if (table_.IsInCurrentScope(name)) {
throw std::runtime_error(FormatError("sema", "重复定义函数: " + name));
}
if (!ctx->funcType() || !ctx->funcType()->INT()) {
throw std::runtime_error(FormatError("sema", "当前仅支持 int main"));
Symbol sym;
sym.kind = Symbol::Kind::Function;
sym.def_ctx = ctx;
table_.Add(name, sym);
table_.PushScope();
if (ctx->funcFParams()) {
ctx->funcFParams()->accept(this);
}
const auto& items = ctx->blockStmt()->blockItem();
if (items.empty()) {
throw std::runtime_error(
FormatError("sema", "main 函数不能为空,且必须以 return 结束"));
if (ctx->blockStmt()) {
// Visit block items without pushing another scope to keep params in same scope
for (auto* item : ctx->blockStmt()->blockItem()) {
item->accept(this);
}
}
ctx->blockStmt()->accept(this);
table_.PopScope();
return {};
}
std::any visitFuncFParam(SysYParser::FuncFParamContext* ctx) override {
const std::string name = ctx->ID()->getText();
if (table_.IsInCurrentScope(name)) {
throw std::runtime_error(FormatError("sema", "函数参数名冲突: " + name));
}
Symbol sym;
sym.kind = Symbol::Kind::Parameter;
sym.def_ctx = ctx;
sym.is_array = !ctx->LBRACK().empty();
table_.Add(name, sym);
for (auto* exp : ctx->exp()) exp->accept(this);
return {};
}
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();
table_.PushScope();
for (auto* item : ctx->blockItem()) {
item->accept(this);
}
table_.PopScope();
return {};
}
std::any visitBlockItem(SysYParser::BlockItemContext* ctx) override {
if (!ctx) {
throw std::runtime_error(FormatError("sema", "暂不支持的语句或声明"));
}
if (ctx->decl()) {
ctx->decl()->accept(this);
return {};
}
if (ctx->stmt()) {
ctx->stmt()->accept(this);
return {};
}
throw std::runtime_error(FormatError("sema", "暂不支持的语句或声明"));
}
std::any visitDecl(SysYParser::DeclContext* ctx) override {
if (!ctx) {
throw std::runtime_error(FormatError("sema", "非法变量声明"));
}
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", "非法变量声明"));
}
const std::string name = GetLValueName(*var_def->lValue());
if (table_.Contains(name)) {
throw std::runtime_error(FormatError("sema", "重复定义变量: " + name));
}
if (auto* init = var_def->initValue()) {
if (!init->exp()) {
throw std::runtime_error(FormatError("sema", "当前不支持聚合初始化"));
}
init->exp()->accept(this);
}
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 {};
}
std::any visitReturnStmt(SysYParser::ReturnStmtContext* ctx) override {
if (!ctx || !ctx->exp()) {
throw std::runtime_error(FormatError("sema", "return 缺少表达式"));
std::any visitAssignStmt(SysYParser::AssignStmtContext* ctx) override {
ctx->lValue()->accept(this);
const std::string name = ctx->lValue()->ID()->getText();
Symbol* sym = table_.Lookup(name);
if (sym && sym->is_const) {
throw std::runtime_error(FormatError("sema", "试图给常量赋值: " + name));
}
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 visitLValue(SysYParser::LValueContext* ctx) override {
const std::string name = ctx->ID()->getText();
Symbol* sym = table_.Lookup(name);
if (!sym) {
throw std::runtime_error(FormatError("sema", "使用了未定义的标识符: " + name));
}
if (sym->kind == Symbol::Kind::Function) {
throw std::runtime_error(FormatError("sema", "函数名不能作为左值: " + name));
}
sema_.BindLValue(ctx, sym->def_ctx);
for (auto* exp : ctx->exp()) exp->accept(this);
return {};
}
std::any visitFuncCallExp(SysYParser::FuncCallExpContext* ctx) override {
const std::string name = ctx->ID()->getText();
Symbol* sym = table_.Lookup(name);
if (!sym) {
throw std::runtime_error(FormatError("sema", "调用未定义的函数: " + name));
}
if (sym->kind != Symbol::Kind::Function) {
throw std::runtime_error(FormatError("sema", "标识符不是函数: " + name));
}
sema_.BindFuncCall(ctx, dynamic_cast<SysYParser::FuncDefContext*>(sym->def_ctx));
if (ctx->funcRParams()) {
ctx->funcRParams()->accept(this);
}
return {};
}
// Visit expressions to ensure all sub-expressions are checked (e.g. for variable uses)
std::any visitParenExp(SysYParser::ParenExpContext* ctx) override {
if (!ctx || !ctx->exp()) {
throw std::runtime_error(FormatError("sema", "非法括号表达式"));
}
ctx->exp()->accept(this);
return {};
return ctx->exp()->accept(this);
}
std::any visitVarExp(SysYParser::VarExpContext* ctx) override {
if (!ctx || !ctx->var()) {
throw std::runtime_error(FormatError("sema", "非法变量表达式"));
}
ctx->var()->accept(this);
return {};
std::any visitLValueExp(SysYParser::LValueExpContext* ctx) override {
return ctx->lValue()->accept(this);
}
std::any visitNumberExp(SysYParser::NumberExpContext* ctx) override {
if (!ctx || !ctx->number() || !ctx->number()->ILITERAL()) {
throw std::runtime_error(FormatError("sema", "当前仅支持整数字面量"));
}
return ctx->number()->accept(this);
}
std::any visitNumber(SysYParser::NumberContext* ctx) override {
return {};
}
std::any visitAdditiveExp(SysYParser::AdditiveExpContext* ctx) override {
if (!ctx || !ctx->exp(0) || !ctx->exp(1)) {
throw std::runtime_error(FormatError("sema", "暂不支持的表达式形式"));
}
std::any visitNotExp(SysYParser::NotExpContext* ctx) override {
return ctx->exp()->accept(this);
}
std::any visitUnaryAddExp(SysYParser::UnaryAddExpContext* ctx) override {
return ctx->exp()->accept(this);
}
std::any visitUnarySubExp(SysYParser::UnarySubExpContext* ctx) override {
return ctx->exp()->accept(this);
}
std::any visitMulExp(SysYParser::MulExpContext* ctx) override {
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", "非法变量引用"));
}
const std::string name = ctx->ID()->getText();
auto* decl = table_.Lookup(name);
if (!decl) {
throw std::runtime_error(FormatError("sema", "使用了未定义的变量: " + name));
}
sema_.BindVarUse(ctx, decl);
std::any visitDivExp(SysYParser::DivExpContext* ctx) override {
ctx->exp(0)->accept(this);
ctx->exp(1)->accept(this);
return {};
}
SemanticContext TakeSemanticContext() { return std::move(sema_); }
std::any visitModExp(SysYParser::ModExpContext* ctx) override {
ctx->exp(0)->accept(this);
ctx->exp(1)->accept(this);
return {};
}
private:
std::any visitAddExp(SysYParser::AddExpContext* ctx) override {
ctx->exp(0)->accept(this);
ctx->exp(1)->accept(this);
return {};
}
std::any visitSubExp(SysYParser::SubExpContext* ctx) override {
ctx->exp(0)->accept(this);
ctx->exp(1)->accept(this);
return {};
}
std::any visitLtExp(SysYParser::LtExpContext* ctx) override {
ctx->exp(0)->accept(this);
ctx->exp(1)->accept(this);
return {};
}
std::any visitLeExp(SysYParser::LeExpContext* ctx) override {
ctx->exp(0)->accept(this);
ctx->exp(1)->accept(this);
return {};
}
std::any visitGtExp(SysYParser::GtExpContext* ctx) override {
ctx->exp(0)->accept(this);
ctx->exp(1)->accept(this);
return {};
}
std::any visitGeExp(SysYParser::GeExpContext* ctx) override {
ctx->exp(0)->accept(this);
ctx->exp(1)->accept(this);
return {};
}
std::any visitEqExp(SysYParser::EqExpContext* ctx) override {
ctx->exp(0)->accept(this);
ctx->exp(1)->accept(this);
return {};
}
std::any visitNeExp(SysYParser::NeExpContext* ctx) override {
ctx->exp(0)->accept(this);
ctx->exp(1)->accept(this);
return {};
}
std::any visitAndExp(SysYParser::AndExpContext* ctx) override {
ctx->exp(0)->accept(this);
ctx->exp(1)->accept(this);
return {};
}
std::any visitOrExp(SysYParser::OrExpContext* ctx) override {
ctx->exp(0)->accept(this);
ctx->exp(1)->accept(this);
return {};
}
std::any visitReturnStmt(SysYParser::ReturnStmtContext* ctx) override {
if (ctx->exp()) ctx->exp()->accept(this);
return {};
}
std::any visitIfStmt(SysYParser::IfStmtContext* ctx) override {
ctx->exp()->accept(this);
ctx->stmt(0)->accept(this);
if (ctx->stmt(1)) ctx->stmt(1)->accept(this);
return {};
}
std::any visitWhileStmt(SysYParser::WhileStmtContext* ctx) override {
ctx->exp()->accept(this);
ctx->stmt()->accept(this);
return {};
}
std::any visitBreakStmt(SysYParser::BreakStmtContext* ctx) override {
return {};
}
std::any visitContinueStmt(SysYParser::ContinueStmtContext* ctx) override {
return {};
}
std::any visitExpStmt(SysYParser::ExpStmtContext* ctx) override {
if (ctx->exp()) ctx->exp()->accept(this);
return {};
}
public:
SemanticContext TakeSemanticContext() { return std::move(sema_); }
private:
SymbolTable table_;
SemanticContext sema_;
bool seen_return_ = false;
size_t current_item_index_ = 0;
size_t total_items_ = 0;
};
} // namespace

View File

@@ -1,17 +1,40 @@
// 维护局部变量声明的注册与查找。
#include "sem/SymbolTable.h"
void SymbolTable::Add(const std::string& name,
SysYParser::VarDefContext* decl) {
table_[name] = decl;
SymbolTable::SymbolTable() {
// Push global scope
PushScope();
}
bool SymbolTable::Contains(const std::string& name) const {
return table_.find(name) != table_.end();
void SymbolTable::PushScope() {
scopes_.emplace_back();
}
SysYParser::VarDefContext* SymbolTable::Lookup(const std::string& name) const {
auto it = table_.find(name);
return it == table_.end() ? nullptr : it->second;
void SymbolTable::PopScope() {
if (scopes_.size() > 1) {
scopes_.pop_back();
}
}
bool SymbolTable::Add(const std::string& name, const Symbol& symbol) {
auto& current_scope = scopes_.back();
if (current_scope.find(name) != current_scope.end()) {
return false;
}
current_scope[name] = symbol;
return true;
}
Symbol* SymbolTable::Lookup(const std::string& name) {
for (auto it = scopes_.rbegin(); it != scopes_.rend(); ++it) {
auto search = it->find(name);
if (search != it->end()) {
return &search->second;
}
}
return nullptr;
}
bool SymbolTable::IsInCurrentScope(const std::string& name) const {
const auto& current_scope = scopes_.back();
return current_scope.find(name) != current_scope.end();
}