forked from NUDT-compiler/nudt-compiler-cpp
Compare commits
1 Commits
master
...
zwz-compil
| Author | SHA1 | Date |
|---|---|---|
|
|
12c217e5f9 | 7 days ago |
File diff suppressed because it is too large
Load Diff
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace ir {
|
||||
|
||||
class Module;
|
||||
|
||||
void RunMem2Reg(Module& module);
|
||||
void RunIRPassPipeline(Module& module);
|
||||
|
||||
} // namespace ir
|
||||
@ -0,0 +1,80 @@
|
||||
// 编译期常量求值与常量初始化展开。
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "SysYParser.h"
|
||||
#include "sem/SymbolTable.h"
|
||||
|
||||
struct ConstValue {
|
||||
SymbolDataType type = SymbolDataType::Unknown;
|
||||
int64_t int_value = 0;
|
||||
double float_value = 0.0;
|
||||
bool bool_value = false;
|
||||
|
||||
static ConstValue FromInt(int64_t value);
|
||||
static ConstValue FromFloat(double value);
|
||||
static ConstValue FromBool(bool value);
|
||||
|
||||
bool IsScalar() const;
|
||||
bool IsNumeric() const;
|
||||
int64_t AsInt() const;
|
||||
double AsFloat() const;
|
||||
bool AsBool() const;
|
||||
};
|
||||
|
||||
struct ConstArrayValue {
|
||||
SymbolDataType elem_type = SymbolDataType::Unknown;
|
||||
std::vector<int64_t> dims;
|
||||
std::vector<ConstValue> elements;
|
||||
};
|
||||
|
||||
class ConstEvalContext {
|
||||
public:
|
||||
ConstEvalContext();
|
||||
|
||||
void EnterScope();
|
||||
void ExitScope();
|
||||
|
||||
bool DefineScalar(const std::string& name, ConstValue value);
|
||||
bool DefineArray(const std::string& name, ConstArrayValue value);
|
||||
|
||||
const ConstValue* LookupScalar(const std::string& name) const;
|
||||
const ConstArrayValue* LookupArray(const std::string& name) const;
|
||||
|
||||
private:
|
||||
struct Binding {
|
||||
bool is_array = false;
|
||||
ConstValue scalar;
|
||||
ConstArrayValue array;
|
||||
};
|
||||
|
||||
using Scope = std::unordered_map<std::string, Binding>;
|
||||
|
||||
const Binding* LookupBinding(const std::string& name) const;
|
||||
|
||||
std::vector<Scope> scopes_;
|
||||
};
|
||||
|
||||
class ConstEvaluator {
|
||||
public:
|
||||
ConstEvaluator(const SymbolTable& table, const ConstEvalContext& ctx);
|
||||
|
||||
ConstValue EvaluateConstExp(SysYParser::ConstExpContext& ctx) const;
|
||||
ConstValue EvaluateExp(SysYParser::ExpContext& ctx) const;
|
||||
|
||||
// 数组维度必须是正整数。
|
||||
int64_t EvaluateArrayDim(SysYParser::ConstExpContext& ctx) const;
|
||||
|
||||
// 展平 const 初始化列表,结果按行优先顺序存放。
|
||||
std::vector<ConstValue> EvaluateConstInitList(
|
||||
SysYParser::ConstInitValContext& init, SymbolDataType elem_type,
|
||||
const std::vector<int64_t>& dims) const;
|
||||
|
||||
private:
|
||||
const SymbolTable& table_;
|
||||
const ConstEvalContext& ctx_;
|
||||
};
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -0,0 +1 @@
|
||||
./scripts/lab1_build_test.sh: line 111: /home/zhangwanzheng/nudt-compiler-cpp/build/bin/compiler: No such file or directory
|
||||
@ -1,12 +1,11 @@
|
||||
// GlobalValue 占位实现:
|
||||
// - 具体的全局初始化器、打印和链接语义需要自行补全
|
||||
|
||||
#include "ir/IR.h"
|
||||
|
||||
namespace ir {
|
||||
|
||||
GlobalValue::GlobalValue(std::shared_ptr<Type> object_type,
|
||||
const std::string& name, bool is_const, Value* init)
|
||||
: User(Type::GetPointerType(object_type), name),
|
||||
object_type_(std::move(object_type)),
|
||||
is_const_(is_const),
|
||||
init_(init) {}
|
||||
GlobalValue::GlobalValue(std::shared_ptr<Type> ty, std::string name)
|
||||
: User(std::move(ty), std::move(name)) {}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@ -1,213 +1,89 @@
|
||||
// IR 构建工具:
|
||||
// - 管理插入点(当前基本块/位置)
|
||||
// - 提供创建各类指令的便捷接口,降低 IRGen 复杂度
|
||||
|
||||
#include "ir/IR.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace ir {
|
||||
namespace {
|
||||
|
||||
BasicBlock* RequireInsertBlock(BasicBlock* block) {
|
||||
if (!block) {
|
||||
throw std::runtime_error("IRBuilder has no insert block");
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
bool IsFloatBinaryOp(Opcode op) {
|
||||
return op == Opcode::FAdd || op == Opcode::FSub || op == Opcode::FMul ||
|
||||
op == Opcode::FDiv || op == Opcode::FRem || op == Opcode::FCmpEQ ||
|
||||
op == Opcode::FCmpNE || op == Opcode::FCmpLT || op == Opcode::FCmpGT ||
|
||||
op == Opcode::FCmpLE || op == Opcode::FCmpGE;
|
||||
}
|
||||
|
||||
bool IsCompareOp(Opcode op) {
|
||||
return (op >= Opcode::ICmpEQ && op <= Opcode::ICmpGE) ||
|
||||
(op >= Opcode::FCmpEQ && op <= Opcode::FCmpGE);
|
||||
}
|
||||
|
||||
std::shared_ptr<Type> ResultTypeForBinary(Opcode op, Value* lhs) {
|
||||
if (IsCompareOp(op)) {
|
||||
return Type::GetInt1Type();
|
||||
}
|
||||
if (IsFloatBinaryOp(op)) {
|
||||
return Type::GetFloatType();
|
||||
}
|
||||
return lhs->GetType();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#include "utils/Log.h"
|
||||
|
||||
IRBuilder::IRBuilder(Context& ctx, BasicBlock* bb) : ctx_(ctx), insert_block_(bb) {}
|
||||
namespace ir {
|
||||
IRBuilder::IRBuilder(Context& ctx, BasicBlock* bb)
|
||||
: ctx_(ctx), insert_block_(bb) {}
|
||||
|
||||
void IRBuilder::SetInsertPoint(BasicBlock* bb) { insert_block_ = bb; }
|
||||
|
||||
ConstantInt* IRBuilder::CreateConstInt(int v) { return ctx_.GetConstInt(v); }
|
||||
|
||||
ConstantFloat* IRBuilder::CreateConstFloat(float v) {
|
||||
return new ConstantFloat(Type::GetFloatType(), v);
|
||||
}
|
||||
|
||||
ConstantI1* IRBuilder::CreateConstBool(bool v) { return ctx_.GetConstBool(v); }
|
||||
BasicBlock* IRBuilder::GetInsertBlock() const { return insert_block_; }
|
||||
|
||||
ConstantArrayValue* IRBuilder::CreateConstArray(std::shared_ptr<Type> array_type,
|
||||
const std::vector<Value*>& elements,
|
||||
const std::vector<size_t>& dims,
|
||||
const std::string& name) {
|
||||
return new ConstantArrayValue(std::move(array_type), elements, dims, name);
|
||||
ConstantInt* IRBuilder::CreateConstInt(int v) {
|
||||
// 常量不需要挂在基本块里,由 Context 负责去重与生命周期。
|
||||
return ctx_.GetConstInt(v);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateBinary(Opcode op, Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<BinaryInst>(op, ResultTypeForBinary(op, lhs), lhs, rhs,
|
||||
nullptr, name);
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
if (!lhs) {
|
||||
throw std::runtime_error(
|
||||
FormatError("ir", "IRBuilder::CreateBinary 缺少 lhs"));
|
||||
}
|
||||
if (!rhs) {
|
||||
throw std::runtime_error(
|
||||
FormatError("ir", "IRBuilder::CreateBinary 缺少 rhs"));
|
||||
}
|
||||
return insert_block_->Append<BinaryInst>(op, lhs->GetType(), lhs, rhs, name);
|
||||
}
|
||||
|
||||
BinaryInst* IRBuilder::CreateAdd(Value* lhs, Value* rhs, const std::string& name) {
|
||||
BinaryInst* IRBuilder::CreateAdd(Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
return CreateBinary(Opcode::Add, lhs, rhs, 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::CreateRem(Value* lhs, Value* rhs, const std::string& name) {
|
||||
return CreateBinary(Opcode::Rem, lhs, rhs, name);
|
||||
}
|
||||
BinaryInst* IRBuilder::CreateAnd(Value* lhs, Value* rhs, const std::string& name) {
|
||||
return CreateBinary(Opcode::And, lhs, rhs, name);
|
||||
}
|
||||
BinaryInst* IRBuilder::CreateOr(Value* lhs, Value* rhs, const std::string& name) {
|
||||
return CreateBinary(Opcode::Or, lhs, rhs, name);
|
||||
}
|
||||
BinaryInst* IRBuilder::CreateXor(Value* lhs, Value* rhs, const std::string& name) {
|
||||
return CreateBinary(Opcode::Xor, lhs, rhs, name);
|
||||
}
|
||||
BinaryInst* IRBuilder::CreateShl(Value* lhs, Value* rhs, const std::string& name) {
|
||||
return CreateBinary(Opcode::Shl, lhs, rhs, name);
|
||||
}
|
||||
BinaryInst* IRBuilder::CreateAShr(Value* lhs, Value* rhs, const std::string& name) {
|
||||
return CreateBinary(Opcode::AShr, lhs, rhs, name);
|
||||
}
|
||||
BinaryInst* IRBuilder::CreateLShr(Value* lhs, Value* rhs, const std::string& name) {
|
||||
return CreateBinary(Opcode::LShr, lhs, rhs, name);
|
||||
}
|
||||
BinaryInst* IRBuilder::CreateICmp(Opcode op, Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
return CreateBinary(op, lhs, rhs, name);
|
||||
}
|
||||
BinaryInst* IRBuilder::CreateFCmp(Opcode op, Value* lhs, Value* rhs,
|
||||
const std::string& name) {
|
||||
return CreateBinary(op, lhs, rhs, name);
|
||||
}
|
||||
|
||||
UnaryInst* IRBuilder::CreateNeg(Value* operand, const std::string& name) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<UnaryInst>(Opcode::Neg, operand->GetType(), operand, nullptr,
|
||||
name);
|
||||
}
|
||||
UnaryInst* IRBuilder::CreateNot(Value* operand, const std::string& name) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<UnaryInst>(Opcode::Not, operand->GetType(), operand, nullptr,
|
||||
name);
|
||||
}
|
||||
UnaryInst* IRBuilder::CreateFNeg(Value* operand, const std::string& name) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<UnaryInst>(Opcode::FNeg, operand->GetType(), operand,
|
||||
nullptr, name);
|
||||
}
|
||||
UnaryInst* IRBuilder::CreateFtoI(Value* operand, const std::string& name) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<UnaryInst>(Opcode::FtoI, Type::GetInt32Type(), operand,
|
||||
nullptr, name);
|
||||
}
|
||||
UnaryInst* IRBuilder::CreateIToF(Value* operand, const std::string& name) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<UnaryInst>(Opcode::IToF, Type::GetFloatType(), operand,
|
||||
nullptr, name);
|
||||
}
|
||||
|
||||
AllocaInst* IRBuilder::CreateAlloca(std::shared_ptr<Type> allocated_type,
|
||||
const std::string& name) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<AllocaInst>(std::move(allocated_type), nullptr, name);
|
||||
AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
return insert_block_->Append<AllocaInst>(Type::GetPtrInt32Type(), name);
|
||||
}
|
||||
|
||||
LoadInst* IRBuilder::CreateLoad(Value* ptr, std::shared_ptr<Type> value_type,
|
||||
const std::string& name) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<LoadInst>(std::move(value_type), ptr, nullptr, name);
|
||||
LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) {
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
if (!ptr) {
|
||||
throw std::runtime_error(
|
||||
FormatError("ir", "IRBuilder::CreateLoad 缺少 ptr"));
|
||||
}
|
||||
return insert_block_->Append<LoadInst>(Type::GetInt32Type(), ptr, name);
|
||||
}
|
||||
|
||||
StoreInst* IRBuilder::CreateStore(Value* val, Value* ptr) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<StoreInst>(val, ptr, nullptr);
|
||||
}
|
||||
|
||||
UncondBrInst* IRBuilder::CreateBr(BasicBlock* dest) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
auto* inst = block->Append<UncondBrInst>(dest, nullptr);
|
||||
block->AddSuccessor(dest);
|
||||
dest->AddPredecessor(block);
|
||||
return inst;
|
||||
}
|
||||
|
||||
CondBrInst* IRBuilder::CreateCondBr(Value* cond, BasicBlock* then_bb,
|
||||
BasicBlock* else_bb) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
auto* inst = block->Append<CondBrInst>(cond, then_bb, else_bb, nullptr);
|
||||
block->AddSuccessor(then_bb);
|
||||
block->AddSuccessor(else_bb);
|
||||
then_bb->AddPredecessor(block);
|
||||
else_bb->AddPredecessor(block);
|
||||
return inst;
|
||||
}
|
||||
|
||||
ReturnInst* IRBuilder::CreateRet(Value* val) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<ReturnInst>(val, nullptr);
|
||||
}
|
||||
|
||||
UnreachableInst* IRBuilder::CreateUnreachable() {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<UnreachableInst>(nullptr);
|
||||
}
|
||||
|
||||
CallInst* IRBuilder::CreateCall(Function* callee, const std::vector<Value*>& args,
|
||||
const std::string& name) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
std::string real_name = callee->GetReturnType()->IsVoid() ? std::string() : name;
|
||||
return block->Append<CallInst>(callee, args, nullptr, real_name);
|
||||
}
|
||||
|
||||
GetElementPtrInst* IRBuilder::CreateGEP(Value* ptr,
|
||||
std::shared_ptr<Type> source_type,
|
||||
const std::vector<Value*>& indices,
|
||||
const std::string& name) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<GetElementPtrInst>(std::move(source_type), ptr, indices,
|
||||
nullptr, name);
|
||||
}
|
||||
|
||||
PhiInst* IRBuilder::CreatePhi(std::shared_ptr<Type> type,
|
||||
const std::string& name) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<PhiInst>(std::move(type), nullptr, name);
|
||||
}
|
||||
|
||||
ZextInst* IRBuilder::CreateZext(Value* val, std::shared_ptr<Type> target_type,
|
||||
const std::string& name) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<ZextInst>(val, std::move(target_type), nullptr, name);
|
||||
if (!insert_block_) {
|
||||
throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点"));
|
||||
}
|
||||
if (!val) {
|
||||
throw std::runtime_error(
|
||||
FormatError("ir", "IRBuilder::CreateStore 缺少 val"));
|
||||
}
|
||||
if (!ptr) {
|
||||
throw std::runtime_error(
|
||||
FormatError("ir", "IRBuilder::CreateStore 缺少 ptr"));
|
||||
}
|
||||
return insert_block_->Append<StoreInst>(Type::GetVoidType(), val, ptr);
|
||||
}
|
||||
|
||||
MemsetInst* IRBuilder::CreateMemset(Value* dst, Value* val, Value* len,
|
||||
Value* is_volatile) {
|
||||
auto* block = RequireInsertBlock(insert_block_);
|
||||
return block->Append<MemsetInst>(dst, val, len, is_volatile, nullptr);
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@ -1,45 +1,21 @@
|
||||
// 保存函数列表并提供模块级上下文访问。
|
||||
|
||||
#include "ir/IR.h"
|
||||
|
||||
namespace ir {
|
||||
|
||||
Function* Module::CreateFunction(
|
||||
const std::string& name, std::shared_ptr<Type> ret_type,
|
||||
const std::vector<std::shared_ptr<Type>>& param_types,
|
||||
const std::vector<std::string>& param_names, bool is_external) {
|
||||
if (auto* existing = GetFunction(name)) {
|
||||
existing->SetExternal(existing->IsExternal() && is_external);
|
||||
return existing;
|
||||
}
|
||||
auto func = std::make_unique<Function>(name, std::move(ret_type), param_types,
|
||||
param_names, is_external);
|
||||
auto* ptr = func.get();
|
||||
functions_.push_back(std::move(func));
|
||||
function_map_[name] = ptr;
|
||||
return ptr;
|
||||
}
|
||||
Context& Module::GetContext() { return context_; }
|
||||
|
||||
Function* Module::GetFunction(const std::string& name) const {
|
||||
auto it = function_map_.find(name);
|
||||
return it == function_map_.end() ? nullptr : it->second;
|
||||
}
|
||||
const Context& Module::GetContext() const { return context_; }
|
||||
|
||||
GlobalValue* Module::CreateGlobalValue(const std::string& name,
|
||||
std::shared_ptr<Type> object_type,
|
||||
bool is_const, Value* init) {
|
||||
if (auto* existing = GetGlobalValue(name)) {
|
||||
return existing;
|
||||
}
|
||||
auto global =
|
||||
std::make_unique<GlobalValue>(std::move(object_type), name, is_const, init);
|
||||
auto* ptr = global.get();
|
||||
globals_.push_back(std::move(global));
|
||||
global_map_[name] = ptr;
|
||||
return ptr;
|
||||
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)));
|
||||
return functions_.back().get();
|
||||
}
|
||||
|
||||
GlobalValue* Module::GetGlobalValue(const std::string& name) const {
|
||||
auto it = global_map_.find(name);
|
||||
return it == global_map_.end() ? nullptr : it->second;
|
||||
const std::vector<std::unique_ptr<Function>>& Module::GetFunctions() const {
|
||||
return functions_;
|
||||
}
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@ -1,111 +1,31 @@
|
||||
// 当前仅支持 void、i32 和 i32*。
|
||||
#include "ir/IR.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace ir {
|
||||
|
||||
Type::Type(Kind kind) : kind_(kind) {}
|
||||
|
||||
Type::Type(Kind kind, std::shared_ptr<Type> element_type, size_t num_elements)
|
||||
: kind_(kind),
|
||||
element_type_(std::move(element_type)),
|
||||
num_elements_(num_elements) {}
|
||||
Type::Type(Kind k) : kind_(k) {}
|
||||
|
||||
const std::shared_ptr<Type>& Type::GetVoidType() {
|
||||
static const auto type = std::make_shared<Type>(Kind::Void);
|
||||
return type;
|
||||
}
|
||||
|
||||
const std::shared_ptr<Type>& Type::GetInt1Type() {
|
||||
static const auto type = std::make_shared<Type>(Kind::Int1);
|
||||
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Void);
|
||||
return type;
|
||||
}
|
||||
|
||||
const std::shared_ptr<Type>& Type::GetInt32Type() {
|
||||
static const auto type = std::make_shared<Type>(Kind::Int32);
|
||||
return type;
|
||||
}
|
||||
|
||||
const std::shared_ptr<Type>& Type::GetFloatType() {
|
||||
static const auto type = std::make_shared<Type>(Kind::Float);
|
||||
return type;
|
||||
}
|
||||
|
||||
const std::shared_ptr<Type>& Type::GetLabelType() {
|
||||
static const auto type = std::make_shared<Type>(Kind::Label);
|
||||
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::Int32);
|
||||
return type;
|
||||
}
|
||||
|
||||
const std::shared_ptr<Type>& Type::GetBoolType() { return GetInt1Type(); }
|
||||
|
||||
std::shared_ptr<Type> Type::GetPointerType(std::shared_ptr<Type> pointee) {
|
||||
return std::make_shared<Type>(Kind::Pointer, std::move(pointee));
|
||||
}
|
||||
|
||||
const std::shared_ptr<Type>& Type::GetPtrInt32Type() {
|
||||
static const auto type = std::make_shared<Type>(Kind::Pointer);
|
||||
static const std::shared_ptr<Type> type = std::make_shared<Type>(Kind::PtrInt32);
|
||||
return type;
|
||||
}
|
||||
|
||||
std::shared_ptr<Type> Type::GetArrayType(std::shared_ptr<Type> element_type,
|
||||
size_t num_elements) {
|
||||
return std::make_shared<Type>(Kind::Array, std::move(element_type), num_elements);
|
||||
}
|
||||
Type::Kind Type::GetKind() const { return kind_; }
|
||||
|
||||
int Type::GetSize() const {
|
||||
switch (kind_) {
|
||||
case Kind::Void:
|
||||
case Kind::Label:
|
||||
case Kind::Function:
|
||||
return 0;
|
||||
case Kind::Int1:
|
||||
return 1;
|
||||
case Kind::Int32:
|
||||
case Kind::Float:
|
||||
return 4;
|
||||
case Kind::Pointer:
|
||||
return 8;
|
||||
case Kind::Array:
|
||||
return static_cast<int>(num_elements_) *
|
||||
(element_type_ ? element_type_->GetSize() : 0);
|
||||
}
|
||||
throw std::runtime_error("unknown IR type kind");
|
||||
}
|
||||
bool Type::IsVoid() const { return kind_ == Kind::Void; }
|
||||
|
||||
void Type::Print(std::ostream& os) const {
|
||||
switch (kind_) {
|
||||
case Kind::Void:
|
||||
os << "void";
|
||||
return;
|
||||
case Kind::Int1:
|
||||
os << "i1";
|
||||
return;
|
||||
case Kind::Int32:
|
||||
os << "i32";
|
||||
return;
|
||||
case Kind::Float:
|
||||
os << "float";
|
||||
return;
|
||||
case Kind::Label:
|
||||
os << "label";
|
||||
return;
|
||||
case Kind::Function:
|
||||
os << "fn";
|
||||
return;
|
||||
case Kind::Pointer:
|
||||
os << "ptr";
|
||||
return;
|
||||
case Kind::Array:
|
||||
os << "[" << num_elements_ << " x ";
|
||||
if (element_type_) {
|
||||
element_type_->Print(os);
|
||||
} else {
|
||||
os << "void";
|
||||
}
|
||||
os << "]";
|
||||
return;
|
||||
}
|
||||
}
|
||||
bool Type::IsInt32() const { return kind_ == Kind::Int32; }
|
||||
|
||||
bool Type::IsPtrInt32() const { return kind_ == Kind::PtrInt32; }
|
||||
|
||||
} // namespace ir
|
||||
|
||||
@ -1,4 +1,752 @@
|
||||
// 常量求值:
|
||||
// - 处理数组维度、全局初始化、const 表达式等编译期可计算场景
|
||||
// - 为语义分析与 IR 生成提供常量折叠/常量值信息
|
||||
#include "sem/ConstEval.h"
|
||||
|
||||
#include <any>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "SysYBaseVisitor.h"
|
||||
#include "utils/Log.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using DataType = SymbolDataType;
|
||||
|
||||
bool IsNumericType(DataType type) {
|
||||
return type == DataType::Int || type == DataType::Float ||
|
||||
type == DataType::Bool;
|
||||
}
|
||||
|
||||
ConstValue MakeZeroValue(DataType type) {
|
||||
switch (type) {
|
||||
case DataType::Float:
|
||||
return ConstValue::FromFloat(0.0);
|
||||
case DataType::Int:
|
||||
return ConstValue::FromInt(0);
|
||||
case DataType::Bool:
|
||||
return ConstValue::FromBool(false);
|
||||
default:
|
||||
return ConstValue{};
|
||||
}
|
||||
}
|
||||
|
||||
ConstValue CastToType(ConstValue value, DataType target_type) {
|
||||
switch (target_type) {
|
||||
case DataType::Int:
|
||||
return ConstValue::FromInt(value.AsInt());
|
||||
case DataType::Float:
|
||||
return ConstValue::FromFloat(value.AsFloat());
|
||||
case DataType::Bool:
|
||||
return ConstValue::FromBool(value.AsBool());
|
||||
default:
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "不支持的常量目标类型转换"));
|
||||
}
|
||||
}
|
||||
|
||||
int64_t ParseIntLiteral(const std::string& text) {
|
||||
char* end = nullptr;
|
||||
const long long value = std::strtoll(text.c_str(), &end, 0);
|
||||
if (end == text.c_str() || *end != '\0') {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "整数字面量解析失败: " + text));
|
||||
}
|
||||
return static_cast<int64_t>(value);
|
||||
}
|
||||
|
||||
double ParseFloatLiteral(const std::string& text) {
|
||||
char* end = nullptr;
|
||||
const double value = std::strtod(text.c_str(), &end);
|
||||
if (end == text.c_str() || *end != '\0') {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "浮点数字面量解析失败: " + text));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
size_t Product(const std::vector<int64_t>& dims, size_t begin) {
|
||||
size_t result = 1;
|
||||
for (size_t i = begin; i < dims.size(); ++i) {
|
||||
if (dims[i] <= 0) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "数组维度必须为正整数"));
|
||||
}
|
||||
const size_t dim = static_cast<size_t>(dims[i]);
|
||||
if (result > std::numeric_limits<size_t>::max() / dim) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "数组维度乘积溢出"));
|
||||
}
|
||||
result *= dim;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
class ConstEvalVisitor final : public SysYBaseVisitor {
|
||||
public:
|
||||
ConstEvalVisitor(const SymbolTable& table, const ConstEvalContext& values)
|
||||
: table_(table), values_(values) {}
|
||||
|
||||
ConstValue EvaluateConstExp(SysYParser::ConstExpContext& ctx) {
|
||||
return Evaluate(ctx.addExp());
|
||||
}
|
||||
|
||||
ConstValue EvaluateExp(SysYParser::ExpContext& ctx) {
|
||||
return Evaluate(ctx.addExp());
|
||||
}
|
||||
|
||||
std::any visitExp(SysYParser::ExpContext* ctx) override {
|
||||
if (!ctx || !ctx->addExp()) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法表达式"));
|
||||
}
|
||||
return Evaluate(ctx->addExp());
|
||||
}
|
||||
|
||||
std::any visitConstExp(SysYParser::ConstExpContext* ctx) override {
|
||||
if (!ctx || !ctx->addExp()) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法 constExp"));
|
||||
}
|
||||
return Evaluate(ctx->addExp());
|
||||
}
|
||||
|
||||
std::any visitCond(SysYParser::CondContext* ctx) override {
|
||||
if (!ctx || !ctx->lOrExp()) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法条件表达式"));
|
||||
}
|
||||
return Evaluate(ctx->lOrExp());
|
||||
}
|
||||
|
||||
std::any visitLVal(SysYParser::LValContext* ctx) override {
|
||||
if (!ctx || !ctx->Ident()) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法左值"));
|
||||
}
|
||||
const std::string name = ctx->Ident()->getText();
|
||||
const SymbolEntry* symbol = table_.Lookup(name);
|
||||
if (!symbol) {
|
||||
throw std::runtime_error(FormatError("consteval", "未定义符号: " + name));
|
||||
}
|
||||
if (!symbol->is_const && symbol->kind != SymbolKind::Constant) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "常量表达式中使用了非常量符号: " + name));
|
||||
}
|
||||
|
||||
const size_t index_count = ctx->exp().size();
|
||||
if (index_count == 0) {
|
||||
if (const ConstValue* scalar = values_.LookupScalar(name)) {
|
||||
return *scalar;
|
||||
}
|
||||
if (values_.LookupArray(name)) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "数组名不能作为标量常量参与求值: " + name));
|
||||
}
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "常量符号缺少编译期值: " + name));
|
||||
}
|
||||
|
||||
const ConstArrayValue* array = values_.LookupArray(name);
|
||||
if (!array) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "下标访问目标不是常量数组: " + name));
|
||||
}
|
||||
if (index_count != array->dims.size()) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "常量数组索引维度不匹配: " + name));
|
||||
}
|
||||
|
||||
size_t linear_index = 0;
|
||||
for (size_t i = 0; i < index_count; ++i) {
|
||||
const ConstValue index_value = Evaluate(ctx->exp(i));
|
||||
const int64_t index = index_value.AsInt();
|
||||
const int64_t dim = array->dims[i];
|
||||
if (index < 0 || index >= dim) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "常量数组访问越界: " + name));
|
||||
}
|
||||
linear_index = linear_index * static_cast<size_t>(dim) +
|
||||
static_cast<size_t>(index);
|
||||
}
|
||||
|
||||
if (linear_index >= array->elements.size()) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "常量数组线性索引越界: " + name));
|
||||
}
|
||||
return array->elements[linear_index];
|
||||
}
|
||||
|
||||
std::any visitPrimaryExp(SysYParser::PrimaryExpContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法 primaryExp"));
|
||||
}
|
||||
if (ctx->exp()) {
|
||||
return Evaluate(ctx->exp());
|
||||
}
|
||||
if (ctx->lVal()) {
|
||||
return Evaluate(ctx->lVal());
|
||||
}
|
||||
if (ctx->number()) {
|
||||
return Evaluate(ctx->number());
|
||||
}
|
||||
throw std::runtime_error(FormatError("consteval", "无法识别的 primaryExp"));
|
||||
}
|
||||
|
||||
std::any visitNumber(SysYParser::NumberContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法数字节点"));
|
||||
}
|
||||
if (ctx->IntConst()) {
|
||||
return ConstValue::FromInt(ParseIntLiteral(ctx->IntConst()->getText()));
|
||||
}
|
||||
if (ctx->FloatConst()) {
|
||||
return ConstValue::FromFloat(
|
||||
ParseFloatLiteral(ctx->FloatConst()->getText()));
|
||||
}
|
||||
throw std::runtime_error(FormatError("consteval", "未知数字字面量类型"));
|
||||
}
|
||||
|
||||
std::any visitUnaryExp(SysYParser::UnaryExpContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法 unaryExp"));
|
||||
}
|
||||
if (ctx->primaryExp()) {
|
||||
return Evaluate(ctx->primaryExp());
|
||||
}
|
||||
if (ctx->Ident()) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "常量表达式中不允许函数调用: " +
|
||||
ctx->Ident()->getText()));
|
||||
}
|
||||
|
||||
if (!ctx->unaryOp() || !ctx->unaryExp()) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法一元表达式结构"));
|
||||
}
|
||||
const ConstValue operand = Evaluate(ctx->unaryExp());
|
||||
|
||||
if (ctx->unaryOp()->ADD()) {
|
||||
if (!operand.IsNumeric()) {
|
||||
throw std::runtime_error(FormatError("consteval", "一元加仅支持数值类型"));
|
||||
}
|
||||
if (operand.type == DataType::Float) {
|
||||
return ConstValue::FromFloat(+operand.AsFloat());
|
||||
}
|
||||
return ConstValue::FromInt(+operand.AsInt());
|
||||
}
|
||||
if (ctx->unaryOp()->SUB()) {
|
||||
if (!operand.IsNumeric()) {
|
||||
throw std::runtime_error(FormatError("consteval", "一元减仅支持数值类型"));
|
||||
}
|
||||
if (operand.type == DataType::Float) {
|
||||
return ConstValue::FromFloat(-operand.AsFloat());
|
||||
}
|
||||
return ConstValue::FromInt(-operand.AsInt());
|
||||
}
|
||||
if (ctx->unaryOp()->NOT()) {
|
||||
return ConstValue::FromBool(!operand.AsBool());
|
||||
}
|
||||
|
||||
throw std::runtime_error(FormatError("consteval", "未知一元运算符"));
|
||||
}
|
||||
|
||||
std::any visitMulExp(SysYParser::MulExpContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法 mulExp"));
|
||||
}
|
||||
if (!ctx->mulExp()) {
|
||||
return Evaluate(ctx->unaryExp());
|
||||
}
|
||||
|
||||
const ConstValue lhs = Evaluate(ctx->mulExp());
|
||||
const ConstValue rhs = Evaluate(ctx->unaryExp());
|
||||
if (!lhs.IsNumeric() || !rhs.IsNumeric()) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "乘除模运算只支持数值类型"));
|
||||
}
|
||||
|
||||
const int op = ctx->op ? ctx->op->getType() : 0;
|
||||
if (op == SysYParser::MUL) {
|
||||
if (lhs.type == DataType::Float || rhs.type == DataType::Float) {
|
||||
return ConstValue::FromFloat(lhs.AsFloat() * rhs.AsFloat());
|
||||
}
|
||||
return ConstValue::FromInt(lhs.AsInt() * rhs.AsInt());
|
||||
}
|
||||
if (op == SysYParser::DIV) {
|
||||
if (lhs.type == DataType::Float || rhs.type == DataType::Float) {
|
||||
const double divisor = rhs.AsFloat();
|
||||
if (divisor == 0.0) {
|
||||
throw std::runtime_error(FormatError("consteval", "浮点除零"));
|
||||
}
|
||||
return ConstValue::FromFloat(lhs.AsFloat() / divisor);
|
||||
}
|
||||
const int64_t divisor = rhs.AsInt();
|
||||
if (divisor == 0) {
|
||||
throw std::runtime_error(FormatError("consteval", "整数除零"));
|
||||
}
|
||||
return ConstValue::FromInt(lhs.AsInt() / divisor);
|
||||
}
|
||||
if (op == SysYParser::MOD) {
|
||||
if (lhs.type == DataType::Float || rhs.type == DataType::Float) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "取模运算不支持浮点类型"));
|
||||
}
|
||||
const int64_t divisor = rhs.AsInt();
|
||||
if (divisor == 0) {
|
||||
throw std::runtime_error(FormatError("consteval", "整数取模除零"));
|
||||
}
|
||||
return ConstValue::FromInt(lhs.AsInt() % divisor);
|
||||
}
|
||||
|
||||
throw std::runtime_error(FormatError("consteval", "未知乘法类运算符"));
|
||||
}
|
||||
|
||||
std::any visitAddExp(SysYParser::AddExpContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法 addExp"));
|
||||
}
|
||||
if (!ctx->addExp()) {
|
||||
return Evaluate(ctx->mulExp());
|
||||
}
|
||||
|
||||
const ConstValue lhs = Evaluate(ctx->addExp());
|
||||
const ConstValue rhs = Evaluate(ctx->mulExp());
|
||||
if (!lhs.IsNumeric() || !rhs.IsNumeric()) {
|
||||
throw std::runtime_error(FormatError("consteval", "加减运算只支持数值类型"));
|
||||
}
|
||||
|
||||
const int op = ctx->op ? ctx->op->getType() : 0;
|
||||
if (op == SysYParser::ADD) {
|
||||
if (lhs.type == DataType::Float || rhs.type == DataType::Float) {
|
||||
return ConstValue::FromFloat(lhs.AsFloat() + rhs.AsFloat());
|
||||
}
|
||||
return ConstValue::FromInt(lhs.AsInt() + rhs.AsInt());
|
||||
}
|
||||
if (op == SysYParser::SUB) {
|
||||
if (lhs.type == DataType::Float || rhs.type == DataType::Float) {
|
||||
return ConstValue::FromFloat(lhs.AsFloat() - rhs.AsFloat());
|
||||
}
|
||||
return ConstValue::FromInt(lhs.AsInt() - rhs.AsInt());
|
||||
}
|
||||
|
||||
throw std::runtime_error(FormatError("consteval", "未知加法类运算符"));
|
||||
}
|
||||
|
||||
std::any visitRelExp(SysYParser::RelExpContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法 relExp"));
|
||||
}
|
||||
if (!ctx->relExp()) {
|
||||
return Evaluate(ctx->addExp());
|
||||
}
|
||||
|
||||
const ConstValue lhs = Evaluate(ctx->relExp());
|
||||
const ConstValue rhs = Evaluate(ctx->addExp());
|
||||
if (!lhs.IsNumeric() || !rhs.IsNumeric()) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "关系比较仅支持数值类型"));
|
||||
}
|
||||
|
||||
const int op = ctx->op ? ctx->op->getType() : 0;
|
||||
if (lhs.type == DataType::Float || rhs.type == DataType::Float) {
|
||||
const double left = lhs.AsFloat();
|
||||
const double right = rhs.AsFloat();
|
||||
if (op == SysYParser::LT) {
|
||||
return ConstValue::FromBool(left < right);
|
||||
}
|
||||
if (op == SysYParser::GT) {
|
||||
return ConstValue::FromBool(left > right);
|
||||
}
|
||||
if (op == SysYParser::LE) {
|
||||
return ConstValue::FromBool(left <= right);
|
||||
}
|
||||
if (op == SysYParser::GE) {
|
||||
return ConstValue::FromBool(left >= right);
|
||||
}
|
||||
} else {
|
||||
const int64_t left = lhs.AsInt();
|
||||
const int64_t right = rhs.AsInt();
|
||||
if (op == SysYParser::LT) {
|
||||
return ConstValue::FromBool(left < right);
|
||||
}
|
||||
if (op == SysYParser::GT) {
|
||||
return ConstValue::FromBool(left > right);
|
||||
}
|
||||
if (op == SysYParser::LE) {
|
||||
return ConstValue::FromBool(left <= right);
|
||||
}
|
||||
if (op == SysYParser::GE) {
|
||||
return ConstValue::FromBool(left >= right);
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error(FormatError("consteval", "未知关系比较运算符"));
|
||||
}
|
||||
|
||||
std::any visitEqExp(SysYParser::EqExpContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法 eqExp"));
|
||||
}
|
||||
if (!ctx->eqExp()) {
|
||||
return Evaluate(ctx->relExp());
|
||||
}
|
||||
|
||||
const ConstValue lhs = Evaluate(ctx->eqExp());
|
||||
const ConstValue rhs = Evaluate(ctx->relExp());
|
||||
|
||||
const int op = ctx->op ? ctx->op->getType() : 0;
|
||||
bool result = false;
|
||||
if (lhs.type == DataType::Float || rhs.type == DataType::Float) {
|
||||
const double left = lhs.AsFloat();
|
||||
const double right = rhs.AsFloat();
|
||||
if (op == SysYParser::EQ) {
|
||||
result = (left == right);
|
||||
} else if (op == SysYParser::NE) {
|
||||
result = (left != right);
|
||||
} else {
|
||||
throw std::runtime_error(FormatError("consteval", "未知相等比较运算符"));
|
||||
}
|
||||
} else {
|
||||
const int64_t left = lhs.AsInt();
|
||||
const int64_t right = rhs.AsInt();
|
||||
if (op == SysYParser::EQ) {
|
||||
result = (left == right);
|
||||
} else if (op == SysYParser::NE) {
|
||||
result = (left != right);
|
||||
} else {
|
||||
throw std::runtime_error(FormatError("consteval", "未知相等比较运算符"));
|
||||
}
|
||||
}
|
||||
return ConstValue::FromBool(result);
|
||||
}
|
||||
|
||||
std::any visitLAndExp(SysYParser::LAndExpContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法 lAndExp"));
|
||||
}
|
||||
if (!ctx->lAndExp()) {
|
||||
return ConstValue::FromBool(Evaluate(ctx->eqExp()).AsBool());
|
||||
}
|
||||
|
||||
const ConstValue lhs = Evaluate(ctx->lAndExp());
|
||||
if (!lhs.AsBool()) {
|
||||
return ConstValue::FromBool(false);
|
||||
}
|
||||
const ConstValue rhs = Evaluate(ctx->eqExp());
|
||||
return ConstValue::FromBool(rhs.AsBool());
|
||||
}
|
||||
|
||||
std::any visitLOrExp(SysYParser::LOrExpContext* ctx) override {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("consteval", "非法 lOrExp"));
|
||||
}
|
||||
if (!ctx->lOrExp()) {
|
||||
return ConstValue::FromBool(Evaluate(ctx->lAndExp()).AsBool());
|
||||
}
|
||||
|
||||
const ConstValue lhs = Evaluate(ctx->lOrExp());
|
||||
if (lhs.AsBool()) {
|
||||
return ConstValue::FromBool(true);
|
||||
}
|
||||
const ConstValue rhs = Evaluate(ctx->lAndExp());
|
||||
return ConstValue::FromBool(rhs.AsBool());
|
||||
}
|
||||
|
||||
private:
|
||||
ConstValue Evaluate(antlr4::ParserRuleContext* ctx) {
|
||||
if (!ctx) {
|
||||
throw std::runtime_error(FormatError("consteval", "空表达式节点"));
|
||||
}
|
||||
std::any result = ctx->accept(this);
|
||||
try {
|
||||
return std::any_cast<ConstValue>(result);
|
||||
} catch (const std::bad_any_cast&) {
|
||||
throw std::runtime_error(FormatError("consteval", "常量求值类型转换失败"));
|
||||
}
|
||||
}
|
||||
|
||||
const SymbolTable& table_;
|
||||
const ConstEvalContext& values_;
|
||||
};
|
||||
|
||||
ConstValue EvaluateScalarInit(SysYParser::ConstInitValContext& init,
|
||||
DataType elem_type,
|
||||
ConstEvalVisitor& evaluator) {
|
||||
if (init.constExp()) {
|
||||
return CastToType(evaluator.EvaluateConstExp(*init.constExp()), elem_type);
|
||||
}
|
||||
if (init.constInitVal().empty()) {
|
||||
return MakeZeroValue(elem_type);
|
||||
}
|
||||
if (init.constInitVal().size() == 1) {
|
||||
return EvaluateScalarInit(*init.constInitVal().front(), elem_type,
|
||||
evaluator);
|
||||
}
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "标量初始化含有过多元素"));
|
||||
}
|
||||
|
||||
void FillConstArrayObject(SysYParser::ConstInitValContext& init,
|
||||
size_t depth, size_t base, size_t span,
|
||||
const std::vector<int64_t>& dims, DataType elem_type,
|
||||
std::vector<ConstValue>& out,
|
||||
ConstEvalVisitor& evaluator) {
|
||||
if (depth >= dims.size()) {
|
||||
out[base] = EvaluateScalarInit(init, elem_type, evaluator);
|
||||
return;
|
||||
}
|
||||
|
||||
if (init.constExp()) {
|
||||
out[base] = CastToType(evaluator.EvaluateConstExp(*init.constExp()),
|
||||
elem_type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (init.constInitVal().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t end = base + span;
|
||||
size_t cursor = base;
|
||||
const size_t subspan = (depth + 1 < dims.size()) ? Product(dims, depth + 1)
|
||||
: static_cast<size_t>(1);
|
||||
|
||||
for (auto* child : init.constInitVal()) {
|
||||
if (!child) {
|
||||
continue;
|
||||
}
|
||||
if (cursor >= end) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "数组初始化元素过多"));
|
||||
}
|
||||
|
||||
if (depth + 1 >= dims.size()) {
|
||||
out[cursor] = EvaluateScalarInit(*child, elem_type, evaluator);
|
||||
++cursor;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (child->constExp()) {
|
||||
out[cursor] = CastToType(evaluator.EvaluateConstExp(*child->constExp()),
|
||||
elem_type);
|
||||
++cursor;
|
||||
continue;
|
||||
}
|
||||
|
||||
const size_t rel = cursor - base;
|
||||
if (subspan > 1 && rel % subspan != 0) {
|
||||
cursor += (subspan - (rel % subspan));
|
||||
}
|
||||
if (cursor >= end) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "数组初始化嵌套层级与维度不匹配"));
|
||||
}
|
||||
|
||||
FillConstArrayObject(*child, depth + 1, cursor, subspan, dims, elem_type,
|
||||
out, evaluator);
|
||||
cursor += subspan;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ConstValue ConstValue::FromInt(int64_t value) {
|
||||
ConstValue result;
|
||||
result.type = SymbolDataType::Int;
|
||||
result.int_value = value;
|
||||
result.float_value = static_cast<double>(value);
|
||||
result.bool_value = (value != 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
ConstValue ConstValue::FromFloat(double value) {
|
||||
ConstValue result;
|
||||
result.type = SymbolDataType::Float;
|
||||
result.int_value = static_cast<int64_t>(value);
|
||||
result.float_value = value;
|
||||
result.bool_value = (value != 0.0);
|
||||
return result;
|
||||
}
|
||||
|
||||
ConstValue ConstValue::FromBool(bool value) {
|
||||
ConstValue result;
|
||||
result.type = SymbolDataType::Bool;
|
||||
result.int_value = value ? 1 : 0;
|
||||
result.float_value = value ? 1.0 : 0.0;
|
||||
result.bool_value = value;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ConstValue::IsScalar() const { return type != SymbolDataType::Unknown; }
|
||||
|
||||
bool ConstValue::IsNumeric() const {
|
||||
return type == SymbolDataType::Int || type == SymbolDataType::Float ||
|
||||
type == SymbolDataType::Bool;
|
||||
}
|
||||
|
||||
int64_t ConstValue::AsInt() const {
|
||||
if (type == SymbolDataType::Int) {
|
||||
return int_value;
|
||||
}
|
||||
if (type == SymbolDataType::Float) {
|
||||
return static_cast<int64_t>(float_value);
|
||||
}
|
||||
if (type == SymbolDataType::Bool) {
|
||||
return bool_value ? 1 : 0;
|
||||
}
|
||||
throw std::runtime_error(FormatError("consteval", "当前值不能转为整数"));
|
||||
}
|
||||
|
||||
double ConstValue::AsFloat() const {
|
||||
if (type == SymbolDataType::Float) {
|
||||
return float_value;
|
||||
}
|
||||
if (type == SymbolDataType::Int) {
|
||||
return static_cast<double>(int_value);
|
||||
}
|
||||
if (type == SymbolDataType::Bool) {
|
||||
return bool_value ? 1.0 : 0.0;
|
||||
}
|
||||
throw std::runtime_error(FormatError("consteval", "当前值不能转为浮点数"));
|
||||
}
|
||||
|
||||
bool ConstValue::AsBool() const {
|
||||
if (type == SymbolDataType::Bool) {
|
||||
return bool_value;
|
||||
}
|
||||
if (type == SymbolDataType::Int) {
|
||||
return int_value != 0;
|
||||
}
|
||||
if (type == SymbolDataType::Float) {
|
||||
return float_value != 0.0;
|
||||
}
|
||||
throw std::runtime_error(FormatError("consteval", "当前值不能转为布尔值"));
|
||||
}
|
||||
|
||||
ConstEvalContext::ConstEvalContext() { EnterScope(); }
|
||||
|
||||
void ConstEvalContext::EnterScope() { scopes_.emplace_back(); }
|
||||
|
||||
void ConstEvalContext::ExitScope() {
|
||||
if (scopes_.size() <= 1) {
|
||||
throw std::runtime_error("const eval scope underflow");
|
||||
}
|
||||
scopes_.pop_back();
|
||||
}
|
||||
|
||||
bool ConstEvalContext::DefineScalar(const std::string& name, ConstValue value) {
|
||||
if (scopes_.empty()) {
|
||||
EnterScope();
|
||||
}
|
||||
auto& current = scopes_.back();
|
||||
if (current.find(name) != current.end()) {
|
||||
return false;
|
||||
}
|
||||
Binding binding;
|
||||
binding.is_array = false;
|
||||
binding.scalar = std::move(value);
|
||||
current.emplace(name, std::move(binding));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConstEvalContext::DefineArray(const std::string& name,
|
||||
ConstArrayValue value) {
|
||||
if (scopes_.empty()) {
|
||||
EnterScope();
|
||||
}
|
||||
auto& current = scopes_.back();
|
||||
if (current.find(name) != current.end()) {
|
||||
return false;
|
||||
}
|
||||
Binding binding;
|
||||
binding.is_array = true;
|
||||
binding.array = std::move(value);
|
||||
current.emplace(name, std::move(binding));
|
||||
return true;
|
||||
}
|
||||
|
||||
const ConstValue* ConstEvalContext::LookupScalar(const std::string& name) const {
|
||||
const Binding* binding = LookupBinding(name);
|
||||
if (!binding || binding->is_array) {
|
||||
return nullptr;
|
||||
}
|
||||
return &binding->scalar;
|
||||
}
|
||||
|
||||
const ConstArrayValue* ConstEvalContext::LookupArray(
|
||||
const std::string& name) const {
|
||||
const Binding* binding = LookupBinding(name);
|
||||
if (!binding || !binding->is_array) {
|
||||
return nullptr;
|
||||
}
|
||||
return &binding->array;
|
||||
}
|
||||
|
||||
const ConstEvalContext::Binding* ConstEvalContext::LookupBinding(
|
||||
const std::string& name) const {
|
||||
for (auto it = scopes_.rbegin(); it != scopes_.rend(); ++it) {
|
||||
auto found = it->find(name);
|
||||
if (found != it->end()) {
|
||||
return &found->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ConstEvaluator::ConstEvaluator(const SymbolTable& table,
|
||||
const ConstEvalContext& ctx)
|
||||
: table_(table), ctx_(ctx) {}
|
||||
|
||||
ConstValue ConstEvaluator::EvaluateConstExp(
|
||||
SysYParser::ConstExpContext& ctx) const {
|
||||
ConstEvalVisitor visitor(table_, ctx_);
|
||||
return visitor.EvaluateConstExp(ctx);
|
||||
}
|
||||
|
||||
ConstValue ConstEvaluator::EvaluateExp(SysYParser::ExpContext& ctx) const {
|
||||
ConstEvalVisitor visitor(table_, ctx_);
|
||||
return visitor.EvaluateExp(ctx);
|
||||
}
|
||||
|
||||
int64_t ConstEvaluator::EvaluateArrayDim(
|
||||
SysYParser::ConstExpContext& ctx) const {
|
||||
const ConstValue value = EvaluateConstExp(ctx);
|
||||
if (!IsNumericType(value.type)) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "数组维度必须是数值类型"));
|
||||
}
|
||||
|
||||
if (value.type == DataType::Float) {
|
||||
const double as_float = value.AsFloat();
|
||||
if (std::trunc(as_float) != as_float) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "数组维度必须是整数"));
|
||||
}
|
||||
}
|
||||
|
||||
const int64_t dim = value.AsInt();
|
||||
if (dim <= 0) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "数组维度必须是正整数"));
|
||||
}
|
||||
return dim;
|
||||
}
|
||||
|
||||
std::vector<ConstValue> ConstEvaluator::EvaluateConstInitList(
|
||||
SysYParser::ConstInitValContext& init, SymbolDataType elem_type,
|
||||
const std::vector<int64_t>& dims) const {
|
||||
if (elem_type != DataType::Int && elem_type != DataType::Float &&
|
||||
elem_type != DataType::Bool) {
|
||||
throw std::runtime_error(
|
||||
FormatError("consteval", "仅支持标量类型的常量初始化"));
|
||||
}
|
||||
|
||||
ConstEvalVisitor visitor(table_, ctx_);
|
||||
if (dims.empty()) {
|
||||
return {EvaluateScalarInit(init, elem_type, visitor)};
|
||||
}
|
||||
|
||||
const size_t total = Product(dims, 0);
|
||||
std::vector<ConstValue> flattened(total, MakeZeroValue(elem_type));
|
||||
FillConstArrayObject(init, 0, 0, total, dims, elem_type, flattened, visitor);
|
||||
return flattened;
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
int main(){
|
||||
const int a[4][2] = {{1, 2}, {3, 4}, {}, 7};
|
||||
const int N = 3;
|
||||
int b[4][2] = {};
|
||||
int c[4][2] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
int d[N + 1][2] = {1, 2, {3}, {5}, a[3][0], 8};
|
||||
int e[4][2][1] = {{d[2][1], {c[2][1]}}, {3, 4}, {5, 6}, {7, 8}};
|
||||
return e[3][1][0] + e[0][0][0] + e[0][1][0] + d[3][0];
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
int main(){
|
||||
return 3;
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
10
|
||||
@ -1,8 +0,0 @@
|
||||
//test domain of global var define and local define
|
||||
int a = 3;
|
||||
int b = 5;
|
||||
|
||||
int main(){
|
||||
int a = 5;
|
||||
return a + b;
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
5
|
||||
@ -1,8 +0,0 @@
|
||||
//test local var define
|
||||
int main(){
|
||||
int a, b0, _c;
|
||||
a = 1;
|
||||
b0 = 2;
|
||||
_c = 3;
|
||||
return b0 + _c;
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
int a[10][10];
|
||||
int main(){
|
||||
return 0;
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
14
|
||||
@ -1,9 +0,0 @@
|
||||
//test array define
|
||||
int main(){
|
||||
int a[4][2] = {};
|
||||
int b[4][2] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
int c[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
|
||||
int d[4][2] = {1, 2, {3}, {5}, 7 , 8};
|
||||
int e[4][2] = {{d[2][1], c[2][1]}, {3, 4}, {5, 6}, {7, 8}};
|
||||
return e[3][1] + e[0][0] + e[0][1] + a[2][0];
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
int main(){
|
||||
const int a[4][2] = {{1, 2}, {3, 4}, {}, 7};
|
||||
|
||||
const int N = 3;
|
||||
int b[4][2] = {};
|
||||
int c[4][2] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
int d[3 + 1][2] = {1, 2, {3}, {5}, a[3][0], 8};
|
||||
int d[N + 1][2] = {1, 2, {3}, {5}, a[3][0], 8};
|
||||
int e[4][2][1] = {{d[2][1], {c[2][1]}}, {3, 4}, {5, 6}, {7, 8}};
|
||||
return e[3][1][0] + e[0][0][0] + e[0][1][0] + d[3][0];
|
||||
}
|
||||
|
||||
@ -1 +0,0 @@
|
||||
5
|
||||
@ -1,6 +0,0 @@
|
||||
//test const gloal var define
|
||||
const int a = 10, b = 5;
|
||||
|
||||
int main(){
|
||||
return b;
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
5
|
||||
@ -1,5 +0,0 @@
|
||||
//test const local var define
|
||||
int main(){
|
||||
const int a = 10, b = 5;
|
||||
return b;
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
4
|
||||
@ -1,5 +0,0 @@
|
||||
const int a[5]={0,1,2,3,4};
|
||||
|
||||
int main(){
|
||||
return a[4];
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
9
|
||||
@ -1 +0,0 @@
|
||||
4
|
||||
@ -1,8 +0,0 @@
|
||||
int defn(){
|
||||
return 4;
|
||||
}
|
||||
|
||||
int main(){
|
||||
int a=defn();
|
||||
return a;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
9
|
||||
@ -1 +0,0 @@
|
||||
15
|
||||
@ -1,5 +0,0 @@
|
||||
//test addc
|
||||
const int a = 10;
|
||||
int main(){
|
||||
return a + 5;
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
248
|
||||
@ -1 +0,0 @@
|
||||
8
|
||||
@ -1,6 +0,0 @@
|
||||
//test subc
|
||||
int main(){
|
||||
int a;
|
||||
a = 10;
|
||||
return a - 2;
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
50
|
||||
@ -1,7 +0,0 @@
|
||||
//test mul
|
||||
int main(){
|
||||
int a, b;
|
||||
a = 10;
|
||||
b = 5;
|
||||
return a * b;
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
25
|
||||
@ -1,5 +0,0 @@
|
||||
//test mulc
|
||||
const int a = 5;
|
||||
int main(){
|
||||
return a * 5;
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
2
|
||||
@ -1,7 +0,0 @@
|
||||
//test div
|
||||
int main(){
|
||||
int a, b;
|
||||
a = 10;
|
||||
b = 5;
|
||||
return a / b;
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
2
|
||||
@ -1,5 +0,0 @@
|
||||
//test divc
|
||||
const int a = 10;
|
||||
int main(){
|
||||
return a / 5;
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
3
|
||||
@ -1,6 +0,0 @@
|
||||
//test mod
|
||||
int main(){
|
||||
int a;
|
||||
a = 10;
|
||||
return a / 3;
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
//test rem
|
||||
int main(){
|
||||
int a;
|
||||
a = 10;
|
||||
return a % 3;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue