Compare commits

...

7 Commits

@ -1,318 +1,686 @@
// 当前只支撑 i32、i32*、void 以及最小的内存/算术指令,演示用。
//
// 当前已经实现:
// 1. 基础类型系统void / i32 / i32*
// 2. Value 体系Value / ConstantValue / ConstantInt / Function / BasicBlock / User / GlobalValue / Instruction
// 3. 最小指令集Add / Alloca / Load / Store / Ret
// 4. BasicBlock / Function / Module 三层组织结构
// 5. IRBuilder便捷创建常量和最小指令
// 6. def-use 关系的轻量实现:
// - Instruction 保存 operand 列表
// - Value 保存 uses
// - 支持 ReplaceAllUsesWith 的简化实现
//
// 当前尚未实现或只做了最小占位:
// 1. 完整类型系统数组、函数类型、label 类型等
// 2. 更完整的指令系统br / condbr / call / phi / gep 等
// 3. 更成熟的 Use 管理(例如 LLVM 风格的双向链式结构)
// 4. 更完整的 IR verifier 和优化基础设施
//
// 当前需要特别说明的两个简化点:
// 1. BasicBlock 虽然已经纳入 Value 体系,但其类型目前仍用 void 作为占位,
// 后续如果补 label type可以再改成更合理的块标签类型。
// 2. ConstantValue 体系目前只实现了 ConstantInt后续可以继续补 ConstantFloat、
// ConstantArray等更完整的常量种类。
//
// 建议的扩展顺序:
// 1. 先补更多指令和类型
// 2. 再补控制流相关 IR
// 3. 最后再考虑把 Value/User/Use 进一步抽象成更完整的框架
// IR_try.h (修正版)
#pragma once
#include "utils.h"
#include <iostream>
#include <iosfwd>
#include <memory>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include <type_traits>
#include <vector>
#include <map>
namespace ir {
class Type;
// 前向声明
class Value;
class User;
class ConstantValue;
class ConstantInt;
class GlobalValue;
class Instruction;
class BasicBlock;
class Function;
class Instruction;
class ConstantInt;
class ConstantFloat;
class ConstantI1;
class ConstantArrayValue;
class Type;
// Use 表示一个 Value 的一次使用记录。
// 当前实现设计:
// - value被使用的值
// - user使用该值的 User
// - operand_index该值在 user 操作数列表中的位置
// -----------------------------------------------------------------------------
// Use
// -----------------------------------------------------------------------------
class Use {
public:
Use() = default;
Use(Value* value, User* user, size_t operand_index)
: value_(value), user_(user), operand_index_(operand_index) {}
Value* GetValue() const { return value_; }
User* GetUser() const { return user_; }
size_t GetOperandIndex() const { return operand_index_; }
void SetValue(Value* value) { value_ = value; }
void SetUser(User* user) { user_ = user; }
void SetOperandIndex(size_t operand_index) { operand_index_ = operand_index; }
private:
Value* value_ = nullptr;
User* user_ = nullptr;
size_t operand_index_ = 0;
public:
Use() = default;
Use(Value* value, User* user, size_t operand_index)
: value_(value), user_(user), operand_index_(operand_index) {}
Value* GetValue() const { return value_; }
User* GetUser() const { return user_; }
size_t GetOperandIndex() const { return operand_index_; }
void SetValue(Value* value) { value_ = value; }
void SetUser(User* user) { user_ = user; }
void SetOperandIndex(size_t operand_index) { operand_index_ = operand_index; }
private:
Value* value_ = nullptr;
User* user_ = nullptr;
size_t operand_index_ = 0;
};
// IR 上下文:集中管理类型、常量等共享资源,便于复用与扩展。
// -----------------------------------------------------------------------------
// Context
// -----------------------------------------------------------------------------
class Context {
public:
Context() = default;
~Context();
// 去重创建 i32 常量。
ConstantInt* GetConstInt(int v);
public:
Context() = default;
~Context();
std::string NextTemp();
ConstantInt* GetConstInt(int v);
std::string NextTemp();
private:
std::unordered_map<int, std::unique_ptr<ConstantInt>> const_ints_;
int temp_index_ = -1;
private:
std::unordered_map<int, std::unique_ptr<ConstantInt>> const_ints_;
int temp_index_ = -1;
};
// -----------------------------------------------------------------------------
// Type
// -----------------------------------------------------------------------------
class Type {
public:
enum class Kind { Void, Int32, PtrInt32 };
explicit Type(Kind k);
// 使用静态共享对象获取类型。
// 同一类型可直接比较返回值是否相等,例如:
// Type::GetInt32Type() == Type::GetInt32Type()
static const std::shared_ptr<Type>& GetVoidType();
static const std::shared_ptr<Type>& GetInt32Type();
static const std::shared_ptr<Type>& GetPtrInt32Type();
Kind GetKind() const;
bool IsVoid() const;
bool IsInt32() const;
bool IsPtrInt32() const;
private:
Kind kind_;
public:
enum class Kind { Void, Int1, Int32, Float, Label, Function, PtrInt32, Array };
explicit Type(Kind k);
static const std::shared_ptr<Type>& GetVoidType();
static const std::shared_ptr<Type>& GetInt1Type();
static const std::shared_ptr<Type>& GetInt32Type();
static const std::shared_ptr<Type>& GetFloatType();
static const std::shared_ptr<Type>& GetLabelType();
static const std::shared_ptr<Type>& GetFunctionType();
static const std::shared_ptr<Type>& GetBoolType();
static const std::shared_ptr<Type>& GetPtrInt32Type();
static const std::shared_ptr<Type>& GetArrayType();
Kind GetKind() const { return kind_; }
bool IsVoid() const { return kind_ == Kind::Void; }
bool IsInt1() const { return kind_ == Kind::Int1; }
bool IsInt32() const { return kind_ == Kind::Int32; }
bool IsFloat() const { return kind_ == Kind::Float; }
bool IsLabel() const { return kind_ == Kind::Label; }
bool IsFunction() const { return kind_ == Kind::Function; }
bool IsBool() const { return kind_ == Kind::Int1; } // 通常与 Int1 相同
bool IsPtrInt32() const { return kind_ == Kind::PtrInt32; }
bool IsArray() const { return kind_ == Kind::Array; }
int GetSize() const;
void Print(std::ostream& os) const;
template <typename T>
std::enable_if_t<std::is_base_of_v<Type, T>, T*> As() const {
return dynamic_cast<T*>(const_cast<Type*>(this));
}
private:
Kind kind_;
};
// -----------------------------------------------------------------------------
// Value
// -----------------------------------------------------------------------------
class Value {
public:
Value(std::shared_ptr<Type> ty, std::string name);
virtual ~Value() = default;
const std::shared_ptr<Type>& GetType() const;
const std::string& GetName() const;
void SetName(std::string n);
bool IsVoid() const;
bool IsInt32() const;
bool IsPtrInt32() const;
bool IsConstant() const;
bool IsInstruction() const;
bool IsUser() const;
bool IsFunction() const;
void AddUse(User* user, size_t operand_index);
void RemoveUse(User* user, size_t operand_index);
const std::vector<Use>& GetUses() const;
void ReplaceAllUsesWith(Value* new_value);
protected:
std::shared_ptr<Type> type_;
std::string name_;
std::vector<Use> uses_;
};
// ConstantValue 是常量体系的基类。
// 当前只实现了 ConstantInt后续可继续扩展更多常量种类。
public:
Value(std::shared_ptr<Type> ty, std::string name);
virtual ~Value() = default;
const std::shared_ptr<Type>& GetType() const { return type_; }
const std::string& GetName() const { return name_; }
void SetName(std::string n) { name_ = std::move(n); }
bool IsVoid() const { return type_->IsVoid(); }
bool IsInt32() const { return type_->IsInt32(); }
bool IsPtrInt32() const { return type_->IsPtrInt32(); }
bool IsFloat() const { return type_->IsFloat(); }
bool IsBool() const { return type_->IsBool(); }
bool IsArray() const { return type_->IsArray(); }
bool IsLabel() const { return type_->IsLabel(); }
// 派生类身份判断(通过虚函数或枚举,这里使用虚函数)
virtual bool IsConstant() const { return false; }
virtual bool IsInstruction() const { return false; }
virtual bool IsUser() const { return false; }
virtual bool IsFunction() const { return false; }
void AddUse(User* user, size_t operand_index);
void RemoveUse(User* user, size_t operand_index);
const std::vector<Use>& GetUses() const { return uses_; }
void ReplaceAllUsesWith(Value* new_value);
void Print(std::ostream& os) const;
protected:
std::shared_ptr<Type> type_;
std::string name_;
std::vector<Use> uses_;
};
// -----------------------------------------------------------------------------
// isa / dyncast 辅助函数
// -----------------------------------------------------------------------------
template <typename T>
inline std::enable_if_t<std::is_base_of_v<Value, T>, bool> isa(const Value* value) {
return T::classof(value);
}
template <typename T>
inline std::enable_if_t<std::is_base_of_v<Value, T>, T*> dyncast(Value* value) {
return isa<T>(value) ? static_cast<T*>(value) : nullptr;
}
template <typename T>
inline std::enable_if_t<std::is_base_of_v<Value, T>, const T*> dyncast(const Value* value) {
return isa<T>(value) ? static_cast<const T*>(value) : nullptr;
}
// -----------------------------------------------------------------------------
// ConstantValue 系列
// -----------------------------------------------------------------------------
class ConstantValue : public Value {
public:
ConstantValue(std::shared_ptr<Type> ty, std::string name = "");
public:
ConstantValue(std::shared_ptr<Type> ty, std::string name = "");
bool IsConstant() const override final { return true; }
};
class ConstantInt : public ConstantValue {
public:
ConstantInt(std::shared_ptr<Type> ty, int v);
int GetValue() const { return value_; }
public:
ConstantInt(std::shared_ptr<Type> ty, int v);
int GetValue() const { return value_; }
static bool classof(const Value* v) { return v->IsConstant() && dynamic_cast<const ConstantInt*>(v) != nullptr; }
private:
int value_;
};
private:
int value_{};
class ConstantFloat : public ConstantValue {
public:
ConstantFloat(std::shared_ptr<Type> ty, float v);
float GetValue() const { return value_; }
static bool classof(const Value* v) { return v->IsConstant() && dynamic_cast<const ConstantFloat*>(v) != nullptr; }
private:
float value_;
};
// 后续还需要扩展更多指令类型。
enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret };
class ConstantI1 : public ConstantValue {
public:
ConstantI1(std::shared_ptr<Type> ty, bool v);
bool GetValue() const { return value_; }
static bool classof(const Value* v) { return v->IsConstant() && dynamic_cast<const ConstantI1*>(v) != nullptr; }
private:
bool value_;
};
// User 是所有“会使用其他 Value 作为输入”的 IR 对象的抽象基类。
// 当前实现中只有 Instruction 继承自 User。
class ConstantArrayValue : public Value {
public:
ConstantArrayValue(std::shared_ptr<Type> elemType,
const std::vector<Value*>& elements,
const std::vector<size_t>& dims,
const std::string& name = "");
const std::vector<Value*>& GetElements() const { return elements_; }
const std::vector<size_t>& GetDims() const { return dims_; }
void Print(std::ostream& os) const;
static bool classof(const Value* v) { return v->IsConstant() && dynamic_cast<const ConstantArrayValue*>(v) != nullptr; }
private:
std::vector<Value*> elements_;
std::vector<size_t> dims_;
};
// -----------------------------------------------------------------------------
// Opcode 枚举
// -----------------------------------------------------------------------------
enum class Opcode {
Add, Sub, Mul, Div, Rem, FAdd, FSub, FMul, FDiv, FRem,
And, Or, Xor, Shl, AShr, LShr,
ICmpEQ, ICmpNE, ICmpLT, ICmpGT, ICmpLE, ICmpGE,
FCmpEQ, FCmpNE, FCmpLT, FCmpGT, FCmpLE, FCmpGE,
Neg, Not, FNeg, FtoI, IToF,
Call, CondBr, Br, Return, Unreachable,
Alloca, Load, Store, Memset,
GetElementPtr, Phi, Zext
};
// -----------------------------------------------------------------------------
// User
// -----------------------------------------------------------------------------
class User : public Value {
public:
User(std::shared_ptr<Type> ty, std::string name);
size_t GetNumOperands() const;
Value* GetOperand(size_t index) const;
void SetOperand(size_t index, Value* value);
public:
User(std::shared_ptr<Type> ty, std::string name);
bool IsUser() const override final { return true; }
protected:
// 统一的 operand 入口。
void AddOperand(Value* value);
size_t GetNumOperands() const { return operands_.size(); }
Value* GetOperand(size_t index) const;
void SetOperand(size_t index, Value* value);
private:
std::vector<Value*> operands_;
void AddOperand(Value* value);
void AddOperands(const std::vector<Value*>& values);
void RemoveOperand(size_t index);
void ClearAllOperands();
protected:
std::vector<Use> operands_;
};
// GlobalValue 是全局值/全局变量体系的空壳占位类。
// 当前只补齐类层次,具体初始化器、打印和链接语义后续再补。
// -----------------------------------------------------------------------------
// GlobalValue
// -----------------------------------------------------------------------------
class GlobalValue : public User {
public:
GlobalValue(std::shared_ptr<Type> ty, std::string name);
public:
GlobalValue(std::shared_ptr<Type> type, const std::string& name,
bool isConst = false, Value* init = nullptr);
GlobalValue(std::shared_ptr<Type> type, const std::string& name,
const std::vector<Value*>& dims,
bool isConst = false, Value* init = nullptr);
bool IsConstant() const { return isConst_; }
bool HasInitializer() const { return init_ != nullptr; }
Value* GetInitializer() const { return init_; }
size_t GetNumDims() const { return dims_.size(); }
Value* GetDim(size_t i) const { return dims_[i]; }
void SetConstant(bool c) { isConst_ = c; }
void SetInitializer(Value* v) { init_ = v; }
static bool classof(const Value* v) { return v->IsUser() && dynamic_cast<const GlobalValue*>(v) != nullptr; }
private:
bool isConst_;
Value* init_;
std::vector<Value*> dims_;
};
// -----------------------------------------------------------------------------
// Instruction 及其子类
// -----------------------------------------------------------------------------
class Instruction : public User {
public:
Instruction(Opcode op, std::shared_ptr<Type> ty, std::string name = "");
Opcode GetOpcode() const;
bool IsTerminator() const;
BasicBlock* GetParent() const;
void SetParent(BasicBlock* parent);
public:
Instruction(Opcode op, std::shared_ptr<Type> ty,
BasicBlock* parent = nullptr, const std::string& name = "");
bool IsInstruction() const override final { return true; }
Opcode GetOpcode() const { return opcode_; }
bool IsTerminator() const {
return opcode_ == Opcode::Br || opcode_ == Opcode::CondBr ||
opcode_ == Opcode::Return || opcode_ == Opcode::Unreachable;
}
BasicBlock* GetParent() const { return parent_; }
void SetParent(BasicBlock* parent) { parent_ = parent; }
private:
Opcode opcode_;
BasicBlock* parent_ = nullptr;
static bool classof(const Value* v) { return v->IsInstruction(); }
private:
Opcode opcode_;
BasicBlock* parent_;
};
class BinaryInst : public Instruction {
public:
BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs, Value* rhs,
std::string name);
Value* GetLhs() const;
Value* GetRhs() const;
public:
BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs, Value* rhs,
BasicBlock* parent = nullptr, const std::string& name = "");
Value* GetLhs() const { return GetOperand(0); }
Value* GetRhs() const { return GetOperand(1); }
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() >= Opcode::Add &&
static_cast<const Instruction*>(v)->GetOpcode() <= Opcode::FCmpGE;
}
};
class UnaryInst : public Instruction {
public:
UnaryInst(Opcode op, std::shared_ptr<Type> ty, Value* operand,
BasicBlock* parent = nullptr, const std::string& name = "");
Value* GetOprd() const { return GetOperand(0); }
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() >= Opcode::Neg &&
static_cast<const Instruction*>(v)->GetOpcode() <= Opcode::IToF;
}
};
class ReturnInst : public Instruction {
public:
ReturnInst(std::shared_ptr<Type> void_ty, Value* val);
Value* GetValue() const;
public:
ReturnInst(Value* val = nullptr, BasicBlock* parent = nullptr);
bool HasReturnValue() const { return GetNumOperands() > 0; }
Value* GetReturnValue() const { return HasReturnValue() ? GetOperand(0) : nullptr; }
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() == Opcode::Return;
}
};
class AllocaInst : public Instruction {
public:
AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name);
public:
AllocaInst(std::shared_ptr<Type> elemType, BasicBlock* parent = nullptr,
const std::string& name = "");
AllocaInst(std::shared_ptr<Type> elemType, const std::vector<Value*>& dims,
BasicBlock* parent = nullptr, const std::string& name = "");
size_t GetNumDims() const { return dims_.size(); }
Value* GetDim(size_t i) const { return dims_[i]; }
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() == Opcode::Alloca;
}
private:
std::vector<Value*> dims_;
};
class LoadInst : public Instruction {
public:
LoadInst(std::shared_ptr<Type> val_ty, Value* ptr, std::string name);
Value* GetPtr() const;
public:
LoadInst(Value* ptr, BasicBlock* parent = nullptr, const std::string& name = "");
Value* GetPtr() const { return GetOperand(0); }
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() == Opcode::Load;
}
};
class StoreInst : public Instruction {
public:
StoreInst(std::shared_ptr<Type> void_ty, Value* val, Value* ptr);
Value* GetValue() const;
Value* GetPtr() const;
public:
StoreInst(Value* val, Value* ptr, BasicBlock* parent = nullptr);
Value* GetValue() const { return GetOperand(0); }
Value* GetPtr() const { return GetOperand(1); }
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() == Opcode::Store;
}
};
class UncondBrInst : public Instruction {
public:
UncondBrInst(BasicBlock* dest, const std::vector<Value*>& args = {},
BasicBlock* parent = nullptr);
BasicBlock* GetDest() const { return dyncast<BasicBlock>(GetOperand(0)); }
std::vector<Value*> GetArguments() const {
std::vector<Value*> result;
for (size_t i = 1; i < GetNumOperands(); ++i)
result.push_back(GetOperand(i));
return result;
}
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() == Opcode::Br;
}
};
class CondBrInst : public Instruction {
public:
CondBrInst(Value* cond, BasicBlock* thenBlock, BasicBlock* elseBlock,
const std::vector<Value*>& thenArgs = {},
const std::vector<Value*>& elseArgs = {},
BasicBlock* parent = nullptr);
Value* GetCondition() const { return GetOperand(0); }
BasicBlock* GetThenBlock() const { return dyncast<BasicBlock>(GetOperand(1)); }
BasicBlock* GetElseBlock() const { return dyncast<BasicBlock>(GetOperand(2)); }
std::vector<Value*> GetThenArguments() const {
std::vector<Value*> result;
size_t num = GetThenBlock()->GetNumArguments();
for (size_t i = 0; i < num; ++i)
result.push_back(GetOperand(3 + i));
return result;
}
std::vector<Value*> GetElseArguments() const {
std::vector<Value*> result;
size_t num = GetThenBlock()->GetNumArguments();
size_t start = 3 + num;
for (size_t i = 0; i < GetElseBlock()->GetNumArguments(); ++i)
result.push_back(GetOperand(start + i));
return result;
}
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() == Opcode::CondBr;
}
};
class UnreachableInst : public Instruction {
public:
explicit UnreachableInst(BasicBlock* parent = nullptr);
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() == Opcode::Unreachable;
}
};
// BasicBlock 已纳入 Value 体系,便于后续向更完整 IR 类图靠拢。
// 当前其类型仍使用 void 作为占位,后续可替换为专门的 label type。
class CallInst : public Instruction {
public:
CallInst(Function* callee, const std::vector<Value*>& args = {},
BasicBlock* parent = nullptr, const std::string& name = "");
Function* GetCallee() const { return dyncast<Function>(GetOperand(0)); }
std::vector<Value*> GetArguments() const {
std::vector<Value*> result;
for (size_t i = 1; i < GetNumOperands(); ++i)
result.push_back(GetOperand(i));
return result;
}
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() == Opcode::Call;
}
};
class GetElementPtrInst : public Instruction {
public:
GetElementPtrInst(Value* ptr, const std::vector<Value*>& indices,
const std::vector<size_t>& dims = {},
const std::vector<size_t>& curDims = {},
BasicBlock* parent = nullptr, const std::string& name = "");
Value* GetPointer() const { return GetOperand(0); }
size_t GetNumIndices() const { return GetNumOperands() - 1; }
Value* GetIndex(size_t i) const { return GetOperand(i + 1); }
const std::vector<size_t>& GetDims() const { return dims_; }
const std::vector<size_t>& GetCurDims() const { return curDims_; }
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() == Opcode::GetElementPtr;
}
private:
std::vector<size_t> dims_;
std::vector<size_t> curDims_;
};
class PhiInst : public Instruction {
public:
PhiInst(std::shared_ptr<Type> type, BasicBlock* parent = nullptr,
const std::string& name = "");
void AddIncoming(Value* value, BasicBlock* block);
int GetNumIncomings() const { return static_cast<int>(GetNumOperands() / 2); }
Value* GetIncomingValue(int i) const { return GetOperand(2 * i); }
BasicBlock* GetIncomingBlock(int i) const { return dyncast<BasicBlock>(GetOperand(2 * i + 1)); }
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() == Opcode::Phi;
}
};
class ZextInst : public Instruction {
public:
ZextInst(Value* val, std::shared_ptr<Type> targetType,
BasicBlock* parent = nullptr, const std::string& name = "");
Value* GetValue() const { return GetOperand(0); }
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() == Opcode::Zext;
}
};
class MemsetInst : public Instruction {
public:
MemsetInst(Value* dst, Value* val, Value* len, Value* isVolatile,
BasicBlock* parent = nullptr);
Value* GetDest() const { return GetOperand(0); }
Value* GetValue() const { return GetOperand(1); }
Value* GetLength() const { return GetOperand(2); }
Value* GetIsVolatile() const { return GetOperand(3); }
static bool classof(const Value* v) {
return Instruction::classof(v) && static_cast<const Instruction*>(v)->GetOpcode() == Opcode::Memset;
}
};
// -----------------------------------------------------------------------------
// BasicBlock
// -----------------------------------------------------------------------------
class BasicBlock : public Value {
public:
explicit BasicBlock(std::string name);
Function* GetParent() const;
void SetParent(Function* parent);
bool HasTerminator() const;
const std::vector<std::unique_ptr<Instruction>>& GetInstructions() const;
const std::vector<BasicBlock*>& GetPredecessors() const;
const std::vector<BasicBlock*>& GetSuccessors() const;
template <typename T, typename... Args>
T* Append(Args&&... args) {
if (HasTerminator()) {
throw std::runtime_error("BasicBlock 已有 terminator不能继续追加指令: " +
name_);
public:
explicit BasicBlock(const std::string& name);
BasicBlock(Function* parent, const std::string& name);
Function* GetParent() const { return parent_; }
void SetParent(Function* parent) { parent_ = parent; }
bool HasTerminator() const;
const std::vector<std::unique_ptr<Instruction>>& GetInstructions() const { return instructions_; }
void AddPredecessor(BasicBlock* pred);
void AddSuccessor(BasicBlock* succ);
void RemovePredecessor(BasicBlock* pred);
void RemoveSuccessor(BasicBlock* succ);
const std::vector<BasicBlock*>& GetPredecessors() const { return predecessors_; }
const std::vector<BasicBlock*>& GetSuccessors() const { return successors_; }
template <typename T, typename... Args>
T* Append(Args&&... args) {
if (HasTerminator()) {
throw std::runtime_error("BasicBlock already has terminator");
}
auto inst = std::make_unique<T>(std::forward<Args>(args)...);
auto* ptr = inst.get();
ptr->SetParent(this);
instructions_.push_back(std::move(inst));
return ptr;
}
auto inst = std::make_unique<T>(std::forward<Args>(args)...);
auto* ptr = inst.get();
ptr->SetParent(this);
instructions_.push_back(std::move(inst));
return ptr;
}
private:
Function* parent_ = nullptr;
std::vector<std::unique_ptr<Instruction>> instructions_;
std::vector<BasicBlock*> predecessors_;
std::vector<BasicBlock*> successors_;
};
// Function 当前也采用了最小实现。
// 需要特别注意:由于项目里还没有单独的 FunctionType
// Function 继承自 Value 后,其 type_ 目前只保存“返回类型”,
// 并不能完整表达“返回类型 + 形参列表”这一整套函数签名。
// 这对当前只支持 int main() 的最小 IR 足够,但后续若补普通函数、
// 形参和调用,通常需要引入专门的函数类型表示。
static bool classof(const Value* v) { return dynamic_cast<const BasicBlock*>(v) != nullptr; }
size_t GetNumArguments() const { return 0; } // 当前版本无参数
private:
Function* parent_;
std::vector<std::unique_ptr<Instruction>> instructions_;
std::vector<BasicBlock*> predecessors_;
std::vector<BasicBlock*> successors_;
};
// -----------------------------------------------------------------------------
// Function
// -----------------------------------------------------------------------------
class Function : public Value {
public:
// 当前构造函数接收的也是返回类型,而不是完整函数类型。
Function(std::string name, std::shared_ptr<Type> ret_type);
BasicBlock* CreateBlock(const std::string& name);
BasicBlock* GetEntry();
const BasicBlock* GetEntry() const;
const std::vector<std::unique_ptr<BasicBlock>>& GetBlocks() const;
public:
Function(std::string name, std::shared_ptr<Type> ret_type);
Function(std::string name, std::shared_ptr<Type> ret_type,
const std::vector<std::shared_ptr<Type>>& param_types);
bool IsFunction() const override final { return true; }
std::shared_ptr<Type> GetReturnType() const { return GetType(); }
const std::vector<std::shared_ptr<Type>>& GetParamTypes() const { return param_types_; }
private:
BasicBlock* entry_ = nullptr;
std::vector<std::unique_ptr<BasicBlock>> blocks_;
BasicBlock* GetEntryBlock() const { return entry_; }
void SetEntryBlock(BasicBlock* bb);
BasicBlock* CreateBlock(const std::string& name);
BasicBlock* AddBlock(std::unique_ptr<BasicBlock> block);
const std::vector<std::unique_ptr<BasicBlock>>& GetBlocks() const { return blocks_; }
static bool classof(const Value* v) { return v->IsFunction(); }
private:
std::vector<std::shared_ptr<Type>> param_types_;
BasicBlock* entry_;
std::vector<std::unique_ptr<BasicBlock>> blocks_;
};
// -----------------------------------------------------------------------------
// Module
// -----------------------------------------------------------------------------
class Module {
public:
Module() = default;
Context& GetContext();
const Context& GetContext() const;
// 创建函数时当前只显式传入返回类型,尚未接入完整的 FunctionType。
Function* CreateFunction(const std::string& name,
std::shared_ptr<Type> ret_type);
const std::vector<std::unique_ptr<Function>>& GetFunctions() const;
private:
Context context_;
std::vector<std::unique_ptr<Function>> functions_;
public:
Module() = default;
Context& GetContext() { return context_; }
const Context& GetContext() const { return context_; }
Function* CreateFunction(const std::string& name, std::shared_ptr<Type> ret_type);
Function* CreateFunction(const std::string& name, std::shared_ptr<Type> ret_type,
const std::vector<std::shared_ptr<Type>>& param_types);
Function* GetFunction(const std::string& name) const;
const std::vector<std::unique_ptr<Function>>& GetFunctions() const { return functions_; }
GlobalValue* CreateGlobalValue(const std::string& name, std::shared_ptr<Type> type,
bool isConst = false, Value* init = nullptr);
GlobalValue* GetGlobalValue(const std::string& name) const;
const std::vector<std::unique_ptr<GlobalValue>>& GetGlobalValues() const { return globals_; }
private:
Context context_;
std::vector<std::unique_ptr<Function>> functions_;
std::map<std::string, Function*> function_map_;
std::vector<std::unique_ptr<GlobalValue>> globals_;
std::map<std::string, GlobalValue*> global_map_;
};
// -----------------------------------------------------------------------------
// IRBuilder
// -----------------------------------------------------------------------------
class IRBuilder {
public:
IRBuilder(Context& ctx, BasicBlock* bb);
void SetInsertPoint(BasicBlock* bb);
BasicBlock* GetInsertBlock() const;
// 构造常量、二元运算、返回指令的最小集合。
ConstantInt* CreateConstInt(int v);
BinaryInst* CreateBinary(Opcode op, Value* lhs, Value* rhs,
const std::string& name);
BinaryInst* CreateAdd(Value* lhs, Value* rhs, const std::string& name);
AllocaInst* CreateAllocaI32(const std::string& name);
LoadInst* CreateLoad(Value* ptr, const std::string& name);
StoreInst* CreateStore(Value* val, Value* ptr);
ReturnInst* CreateRet(Value* v);
private:
Context& ctx_;
BasicBlock* insert_block_;
public:
IRBuilder(Context& ctx, BasicBlock* bb);
void SetInsertPoint(BasicBlock* bb);
BasicBlock* GetInsertBlock() const { return insert_block_; }
ConstantInt* CreateConstInt(int v);
ConstantFloat* CreateConstFloat(float v);
ConstantI1* CreateConstBool(bool v);
ConstantArrayValue* CreateConstArray(std::shared_ptr<Type> elem_type,
const std::vector<Value*>& elements,
const std::vector<size_t>& dims,
const std::string& name = "");
BinaryInst* CreateBinary(Opcode op, Value* lhs, Value* rhs,
const std::string& name = "");
BinaryInst* CreateAdd(Value* lhs, Value* rhs, const std::string& name = "");
BinaryInst* CreateSub(Value* lhs, Value* rhs, const std::string& name = "");
BinaryInst* CreateMul(Value* lhs, Value* rhs, const std::string& name = "");
BinaryInst* CreateDiv(Value* lhs, Value* rhs, const std::string& name = "");
BinaryInst* CreateRem(Value* lhs, Value* rhs, const std::string& name = "");
BinaryInst* CreateAnd(Value* lhs, Value* rhs, const std::string& name = "");
BinaryInst* CreateOr(Value* lhs, Value* rhs, const std::string& name = "");
BinaryInst* CreateXor(Value* lhs, Value* rhs, const std::string& name = "");
BinaryInst* CreateShl(Value* lhs, Value* rhs, const std::string& name = "");
BinaryInst* CreateAShr(Value* lhs, Value* rhs, const std::string& name = "");
BinaryInst* CreateLShr(Value* lhs, Value* rhs, const std::string& name = "");
BinaryInst* CreateICmp(Opcode op, Value* lhs, Value* rhs, const std::string& name = "");
BinaryInst* CreateFCmp(Opcode op, Value* lhs, Value* rhs, const std::string& name = "");
UnaryInst* CreateNeg(Value* operand, const std::string& name = "");
UnaryInst* CreateNot(Value* operand, const std::string& name = "");
UnaryInst* CreateFNeg(Value* operand, const std::string& name = "");
UnaryInst* CreateFtoI(Value* operand, const std::string& name = "");
UnaryInst* CreateIToF(Value* operand, const std::string& name = "");
AllocaInst* CreateAlloca(std::shared_ptr<Type> elem_type, const std::string& name = "");
AllocaInst* CreateAllocaArray(std::shared_ptr<Type> elem_type, const std::vector<Value*>& dims,
const std::string& name = "");
LoadInst* CreateLoad(Value* ptr, const std::string& name = "");
StoreInst* CreateStore(Value* val, Value* ptr);
UncondBrInst* CreateBr(BasicBlock* dest, const std::vector<Value*>& args = {});
CondBrInst* CreateCondBr(Value* cond, BasicBlock* then_bb, BasicBlock* else_bb,
const std::vector<Value*>& then_args = {},
const std::vector<Value*>& else_args = {});
ReturnInst* CreateRet(Value* val = nullptr);
UnreachableInst* CreateUnreachable();
CallInst* CreateCall(Function* callee, const std::vector<Value*>& args,
const std::string& name = "");
GetElementPtrInst* CreateGEP(Value* ptr, const std::vector<Value*>& indices,
const std::vector<size_t>& dims = {},
const std::vector<size_t>& cur_dims = {},
const std::string& name = "");
PhiInst* CreatePhi(std::shared_ptr<Type> type, const std::string& name = "");
ZextInst* CreateZext(Value* val, std::shared_ptr<Type> target_type, const std::string& name = "");
MemsetInst* CreateMemset(Value* dst, Value* val, Value* len, Value* is_volatile);
private:
Context& ctx_;
BasicBlock* insert_block_;
};
// -----------------------------------------------------------------------------
// IRPrinter
// -----------------------------------------------------------------------------
class IRPrinter {
public:
void Print(const Module& module, std::ostream& os);
public:
void Print(const Module& module, std::ostream& os);
};
} // namespace ir
// -----------------------------------------------------------------------------
// 输出运算符重载
// -----------------------------------------------------------------------------
inline std::ostream& operator<<(std::ostream& os, const Type& type) {
type.Print(os);
return os;
}
inline std::ostream& operator<<(std::ostream& os, const Value& value) {
value.Print(os);
return os;
}
} // namespace ir

@ -0,0 +1,373 @@
// 当前只支撑 i32、i32*、void 以及最小的内存/算术指令,演示用。
//
// 当前已经实现:
// 1. 基础类型系统void / i32 / i32*
// 2. Value 体系Value / ConstantValue / ConstantInt / Function / BasicBlock / User / GlobalValue / Instruction
// 3. 最小指令集Add / Alloca / Load / Store / Ret
// 4. BasicBlock / Function / Module 三层组织结构
// 5. IRBuilder便捷创建常量和最小指令
// 6. def-use 关系的轻量实现:
// - Instruction 保存 operand 列表
// - Value 保存 uses
// - 支持 ReplaceAllUsesWith 的简化实现
//
// 当前尚未实现或只做了最小占位:
// 1. 完整类型系统数组、函数类型、label 类型等
// 2. 更完整的指令系统br / condbr / call / phi / gep 等
// 3. 更成熟的 Use 管理(例如 LLVM 风格的双向链式结构)
// 4. 更完整的 IR verifier 和优化基础设施
//
// 当前需要特别说明的两个简化点:
// 1. BasicBlock 虽然已经纳入 Value 体系,但其类型目前仍用 void 作为占位,
// 后续如果补 label type可以再改成更合理的块标签类型。
// 2. ConstantValue 体系目前只实现了 ConstantInt后续可以继续补 ConstantFloat、
// ConstantArray等更完整的常量种类。
//
// 建议的扩展顺序:
// 1. 先补更多指令和类型
// 2. 再补控制流相关 IR
// 3. 最后再考虑把 Value/User/Use 进一步抽象成更完整的框架
#pragma once
#include <iosfwd>
#include <memory>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
namespace ir {
class Type;
class Value;
class User;
class ConstantValue;
class ConstantInt;
class GlobalValue;
class Instruction;
class BasicBlock;
class Function;
// Use 表示一个 Value 的一次使用记录。
// 当前实现设计:
// - value被使用的值
// - user使用该值的 User
// - operand_index该值在 user 操作数列表中的位置
class Use {
public:
Use() = default;
Use(Value* value, User* user, size_t operand_index)
: value_(value), user_(user), operand_index_(operand_index) {}
Value* GetValue() const { return value_; }
User* GetUser() const { return user_; }
size_t GetOperandIndex() const { return operand_index_; }
void SetValue(Value* value) { value_ = value; }
void SetUser(User* user) { user_ = user; }
void SetOperandIndex(size_t operand_index) { operand_index_ = operand_index; }
private:
Value* value_ = nullptr;
User* user_ = nullptr;
size_t operand_index_ = 0;
};
// IR 上下文:集中管理类型、常量等共享资源,便于复用与扩展。
class Context {
public:
Context() = default;
~Context();
// 去重创建 i32 常量。
ConstantInt* GetConstInt(int v);
std::string NextTemp();
private:
std::unordered_map<int, std::unique_ptr<ConstantInt>> const_ints_;
int temp_index_ = -1;
};
class Type {
public:
enum class Kind { Void, Int1, Int32, Float, Label, Function, PtrInt32, Array };
explicit Type(Kind k);
// 静态工厂方法:返回对应类型的共享单例
static const std::shared_ptr<Type>& GetVoidType();
static const std::shared_ptr<Type>& GetInt1Type();
static const std::shared_ptr<Type>& GetInt32Type();
static const std::shared_ptr<Type>& GetFloatType();
static const std::shared_ptr<Type>& GetLabelType();
static const std::shared_ptr<Type>& GetFunctionType();
static const std::shared_ptr<Type>& GetBoolType();
static const std::shared_ptr<Type>& GetPtrInt32Type();
static const std::shared_ptr<Type>& GetArrayType();
Kind GetKind() const;
// 便捷类型判断
bool IsVoid() const;
bool IsInt1() const;
bool IsInt32() const;
bool IsFloat() const;
bool IsLabel() const;
bool IsFunction() const;
bool IsBool() const;
bool IsPtrInt32() const;
bool IsArray() const;
private:
Kind kind_;
};
class Value {
public:
Value(std::shared_ptr<Type> ty, std::string name);
virtual ~Value() = default;
const std::shared_ptr<Type>& GetType() const;
const std::string& GetName() const;
void SetName(std::string n);
bool IsVoid() const;
bool IsInt32() const;
bool IsPtrInt32() const;
bool IsConstant() const;
bool IsInstruction() const;
bool IsUser() const;
bool IsFunction() const;
void AddUse(User* user, size_t operand_index);
void RemoveUse(User* user, size_t operand_index);
const std::vector<Use>& GetUses() const;
void ReplaceAllUsesWith(Value* new_value);
protected:
std::shared_ptr<Type> type_;
std::string name_;
std::vector<Use> uses_;
};
// ConstantValue 是常量体系的基类。
// 当前只实现了 ConstantInt后续可继续扩展更多常量种类。
class ConstantValue : public Value {
public:
ConstantValue(std::shared_ptr<Type> ty, std::string name = "");
};
class ConstantInt : public ConstantValue {
public:
ConstantInt(std::shared_ptr<Type> ty, int v);
int GetValue() const { return value_; }
private:
int value_{};
};
class ConstantFloat : public ConstantValue {
public:
ConstantFloat(std::shared_ptr<Type> ty, float v);
float GetValue() const { return value_; }
private:
float value_{};
};
class ConstantI1 : public ConstantValue {
public:
ConstantI1(std::shared_ptr<Type> ty, bool v);
int GetValue() const { return value_; }
private:
bool value_{};
};
class ConstantArrayValue : public Value {
public:
ConstantArrayValue()
};
//暂时先设计这些
enum class Opcode {
// 二元算术
Add,Sub,Mul,Div,Rem,FAdd,FSub,FMul,FDiv,FRem,
// 位运算
And,Or,Xor,Shl,AShr,LShr,
// 整数比较
ICmpEQ,ICmpNE,ICmpLT,ICmpGT,ICmpLE,ICmpGE,
// 浮点比较
FCmpEQ,FCmpNE,FCmpLT,FCmpGT,FCmpLE,FCmpGE,
// 一元运算
Neg,Not,FNeg,FtoI,IToF,
// 调用与终止
Call,CondBr,Br,Return,Unreachable,
// 内存操作
Alloca,Load,Store,Memset,
// 其他
GetElementPtr,Phi,Zext
};
// User 是所有“会使用其他 Value 作为输入”的 IR 对象的抽象基类。
// 当前实现中只有 Instruction 继承自 User。
class User : public Value {
public:
User(std::shared_ptr<Type> ty, std::string name);
size_t GetNumOperands() const;
Value* GetOperand(size_t index) const;
void SetOperand(size_t index, Value* value);
protected:
void AddOperand(Value* value);
private:
std::vector<Value*> operands_;
};
// GlobalValue 是全局值/全局变量体系的空壳占位类。
// 当前只补齐类层次,具体初始化器、打印和链接语义后续再补。
class GlobalValue : public User {
public:
GlobalValue(std::shared_ptr<Type> ty, std::string name);
};
class Instruction : public User {
public:
Instruction(Opcode op, std::shared_ptr<Type> ty, std::string name = "");
Opcode GetOpcode() const;
bool IsTerminator() const;
BasicBlock* GetParent() const;
void SetParent(BasicBlock* parent);
private:
Opcode opcode_;
BasicBlock* parent_ = nullptr;
};
class BinaryInst : public Instruction {
public:
BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs, Value* rhs,
std::string name);
Value* GetLhs() const;
Value* GetRhs() const;
};
class ReturnInst : public Instruction {
public:
ReturnInst(std::shared_ptr<Type> void_ty, Value* val);
Value* GetValue() const;
};
class AllocaInst : public Instruction {
public:
AllocaInst(std::shared_ptr<Type> ptr_ty, std::string name);
};
class LoadInst : public Instruction {
public:
LoadInst(std::shared_ptr<Type> val_ty, Value* ptr, std::string name);
Value* GetPtr() const;
};
class StoreInst : public Instruction {
public:
StoreInst(std::shared_ptr<Type> void_ty, Value* val, Value* ptr);
Value* GetValue() const;
Value* GetPtr() const;
};
// BasicBlock 已纳入 Value 体系,便于后续向更完整 IR 类图靠拢。
// 当前其类型仍使用 void 作为占位,后续可替换为专门的 label type。
class BasicBlock : public Value {
public:
explicit BasicBlock(std::string name);
Function* GetParent() const;
void SetParent(Function* parent);
bool HasTerminator() const;
const std::vector<std::unique_ptr<Instruction>>& GetInstructions() const;
const std::vector<BasicBlock*>& GetPredecessors() const;
const std::vector<BasicBlock*>& GetSuccessors() const;
template <typename T, typename... Args>
T* Append(Args&&... args) {
if (HasTerminator()) {
throw std::runtime_error("BasicBlock 已有 terminator不能继续追加指令: " +
name_);
}
auto inst = std::make_unique<T>(std::forward<Args>(args)...);
auto* ptr = inst.get();
ptr->SetParent(this);
instructions_.push_back(std::move(inst));
return ptr;
}
private:
Function* parent_ = nullptr;
std::vector<std::unique_ptr<Instruction>> instructions_;
std::vector<BasicBlock*> predecessors_;
std::vector<BasicBlock*> successors_;
};
// Function 当前也采用了最小实现。
// 需要特别注意:由于项目里还没有单独的 FunctionType
// Function 继承自 Value 后,其 type_ 目前只保存“返回类型”,
// 并不能完整表达“返回类型 + 形参列表”这一整套函数签名。
// 这对当前只支持 int main() 的最小 IR 足够,但后续若补普通函数、
// 形参和调用,通常需要引入专门的函数类型表示。
class Function : public Value {
public:
// 当前构造函数接收的也是返回类型,而不是完整函数类型。
Function(std::string name, std::shared_ptr<Type> ret_type);
BasicBlock* CreateBlock(const std::string& name);
BasicBlock* GetEntry();
const BasicBlock* GetEntry() const;
const std::vector<std::unique_ptr<BasicBlock>>& GetBlocks() const;
private:
BasicBlock* entry_ = nullptr;
std::vector<std::unique_ptr<BasicBlock>> blocks_;
};
class Module {
public:
Module() = default;
Context& GetContext();
const Context& GetContext() const;
// 创建函数时当前只显式传入返回类型,尚未接入完整的 FunctionType。
Function* CreateFunction(const std::string& name,
std::shared_ptr<Type> ret_type);
const std::vector<std::unique_ptr<Function>>& GetFunctions() const;
private:
Context context_;
std::vector<std::unique_ptr<Function>> functions_;
};
class IRBuilder {
public:
IRBuilder(Context& ctx, BasicBlock* bb);
void SetInsertPoint(BasicBlock* bb);
BasicBlock* GetInsertBlock() const;
// 构造常量、二元运算、返回指令的最小集合。
ConstantInt* CreateConstInt(int v);
BinaryInst* CreateBinary(Opcode op, Value* lhs, Value* rhs,
const std::string& name);
BinaryInst* CreateAdd(Value* lhs, Value* rhs, const std::string& name);
AllocaInst* CreateAllocaI32(const std::string& name);
LoadInst* CreateLoad(Value* ptr, const std::string& name);
StoreInst* CreateStore(Value* val, Value* ptr);
ReturnInst* CreateRet(Value* v);
private:
Context& ctx_;
BasicBlock* insert_block_;
};
class IRPrinter {
public:
void Print(const Module& module, std::ostream& os);
};
} // namespace ir

@ -0,0 +1,41 @@
#pragma once
#include <iterator>
namespace ir {
template <typename IterT> struct range {
using iterator = IterT;
using value_type = typename std::iterator_traits<iterator>::value_type;
using reference = typename std::iterator_traits<iterator>::reference;
private:
iterator b;
iterator e;
public:
explicit range(iterator b, iterator e) : b(b), e(e) {}
iterator begin() { return b; }
iterator end() { return e; }
iterator begin() const { return b; }
iterator end() const { return e; }
auto size() const { return std::distance(b, e); }
auto empty() const { return b == e; }
};
//! create `range` object from iterator pair [begin, end)
template <typename IterT> range<IterT> make_range(IterT b, IterT e) {
return range<IterT>(b, e);
}
//! create `range` object from a container who has `begin()` and `end()` methods
template <typename ContainerT>
range<typename ContainerT::iterator> make_range(ContainerT &c) {
return make_range(c.begin(), c.end());
}
//! create `range` object from a container who has `begin()` and `end()` methods
template <typename ContainerT>
range<typename ContainerT::const_iterator> make_range(const ContainerT &c) {
return make_range(c.begin(), c.end());
}
} // 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_;
};

@ -1,30 +1,48 @@
// 基于语法树的语义检查与名称绑定。
#pragma once
#include <list>
#include <unordered_map>
#include "SysYParser.h"
#include "sem/SymbolTable.h"
class SemanticContext {
public:
void BindVarUse(SysYParser::VarContext* use,
SysYParser::VarDefContext* decl) {
var_uses_[use] = decl;
SymbolEntry* RegisterSymbol(SymbolEntry symbol) {
symbols_.push_back(std::move(symbol));
return &symbols_.back();
}
SysYParser::VarDefContext* ResolveVarUse(
const SysYParser::VarContext* use) const {
auto it = var_uses_.find(use);
return it == var_uses_.end() ? nullptr : it->second;
void BindLValUse(SysYParser::LValContext* use, const SymbolEntry* symbol) {
lval_uses_[use] = symbol;
}
const SymbolEntry* ResolveLValUse(const SysYParser::LValContext* use) const {
auto it = lval_uses_.find(use);
return it == lval_uses_.end() ? nullptr : it->second;
}
void BindCallUse(SysYParser::UnaryExpContext* call,
const SymbolEntry* symbol) {
call_uses_[call] = symbol;
}
const SymbolEntry* ResolveCallUse(
const SysYParser::UnaryExpContext* call) const {
auto it = call_uses_.find(call);
return it == call_uses_.end() ? nullptr : it->second;
}
const std::list<SymbolEntry>& GetSymbols() const { return symbols_; }
private:
std::unordered_map<const SysYParser::VarContext*,
SysYParser::VarDefContext*>
var_uses_;
std::list<SymbolEntry> symbols_;
std::unordered_map<const SysYParser::LValContext*, const SymbolEntry*>
lval_uses_;
std::unordered_map<const SysYParser::UnaryExpContext*, const SymbolEntry*>
call_uses_;
};
// 目前仅检查:
// - 变量先声明后使用
// - 局部变量不允许重复定义
// 基于 SysY.g4 规则进行语义分析,构建 IR 导向的符号绑定结果。
SemanticContext RunSema(SysYParser::CompUnitContext& comp_unit);

@ -1,17 +1,76 @@
// 极简符号表:记录局部变量定义点
// IR 导向符号表:符号条目可直接挂接 IR 实体
#pragma once
#include <cstdint>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include "SysYParser.h"
namespace antlr4 {
class ParserRuleContext;
} // namespace antlr4
namespace ir {
class Type;
class Value;
class Function;
} // namespace ir
enum class SymbolKind {
Variable,
Constant,
Function,
Parameter,
};
enum class SymbolDataType {
Unknown,
Void,
Int,
Float,
Bool,
};
struct SymbolEntry {
std::string name;
SymbolKind kind = SymbolKind::Variable;
SymbolDataType data_type = SymbolDataType::Unknown;
std::shared_ptr<ir::Type> type;
ir::Value* ir_value = nullptr;
ir::Function* ir_function = nullptr;
bool is_const = false;
bool is_global = false;
bool has_initializer = false;
bool is_array = false;
std::vector<int64_t> array_dims;
bool has_constexpr_value = false;
int64_t const_int_value = 0;
double const_float_value = 0.0;
std::vector<int64_t> const_int_init;
std::vector<double> const_float_init;
std::vector<SymbolDataType> param_types;
std::vector<bool> param_is_array;
const antlr4::ParserRuleContext* decl_ctx = nullptr;
};
class SymbolTable {
public:
void Add(const std::string& name, SysYParser::VarDefContext* decl);
SymbolTable();
void EnterScope();
void ExitScope();
bool Insert(const SymbolEntry* symbol);
bool Contains(const std::string& name) const;
SysYParser::VarDefContext* Lookup(const std::string& name) const;
bool ContainsCurrentScope(const std::string& name) const;
const SymbolEntry* Lookup(const std::string& name) const;
const SymbolEntry* LookupCurrentScope(const std::string& name) const;
private:
std::unordered_map<std::string, SysYParser::VarDefContext*> table_;
using Scope = std::unordered_map<std::string, const SymbolEntry*>;
std::vector<Scope> scopes_;
};

@ -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

@ -0,0 +1,136 @@
#!/usr/bin/env bash
# Lab1 自动化构建 + 解析测评脚本(使用 COMPILER_PARSE_ONLY 构建)
# 用法:
# bash scripts/lab1_build_test.sh [--save-tree] [测试目录...]
#
# 选项:
# --save-tree 保存每个测试用例的语法树到 build/trees/ 目录
# 默认只进行通过/失败统计,不保存语法树
#
# 退出码:
# 0 全部用例解析通过
# 1 存在解析失败用例
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
COMPILER="$REPO_ROOT/build/bin/compiler"
ANTLR_JAR="$REPO_ROOT/third_party/antlr-4.13.2-complete.jar"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# 默认不保存语法树
SAVE_TREE=false
# 解析命令行参数
TEST_DIRS=()
while [[ $# -gt 0 ]]; do
case "$1" in
--save-tree)
SAVE_TREE=true
shift
;;
*)
TEST_DIRS+=("$1")
shift
;;
esac
done
# 如果没有指定测试目录,使用默认
if [[ ${#TEST_DIRS[@]} -eq 0 ]]; then
TEST_DIRS=(
"$REPO_ROOT/test/test_case/functional"
"$REPO_ROOT/test/test_case/performance"
)
fi
# ─── Step 1生成 ANTLR Lexer/Parser ────────────────────────────────────────────────
echo "==> [1/3] 生成 ANTLR Lexer/Parser ..."
mkdir -p "$REPO_ROOT/build/generated/antlr4"
java -jar "$ANTLR_JAR" \
-Dlanguage=Cpp \
-visitor -no-listener \
-Xexact-output-dir \
-o "$REPO_ROOT/build/generated/antlr4" \
"$REPO_ROOT/src/antlr4/SysY.g4"
echo " Lexer/Parser 生成完毕"
# ─── Step 2CMake 构建(使用 COMPILER_PARSE_ONLY────────────────────────────────
echo "==> [2/3] CMake 构建COMPILER_PARSE_ONLY=ON..."
cmake -S "$REPO_ROOT" -B "$REPO_ROOT/build" \
-DCMAKE_BUILD_TYPE=Release \
-DCOMPILER_PARSE_ONLY=ON \
> /dev/null
cmake --build "$REPO_ROOT/build" -j "$(nproc)" 2>&1 | grep -E "error:|warning:|Built target|Linking" || true
echo " 构建完毕:$COMPILER"
# ─── Step 3批量解析测试 ─────────────────────────────────────────────────────
echo "==> [3/3] 批量解析测试 ..."
# 如果需要保存语法树,创建输出目录
if $SAVE_TREE; then
TREE_OUTPUT_DIR="$REPO_ROOT/build/trees"
mkdir -p "$TREE_OUTPUT_DIR"
echo " 语法树将保存到: $TREE_OUTPUT_DIR"
fi
PASS=0
FAIL=0
FAIL_LIST=()
for TEST_DIR in "${TEST_DIRS[@]}"; do
if [[ ! -d "$TEST_DIR" ]]; then
echo -e " ${YELLOW}警告:目录不存在,跳过:$TEST_DIR${NC}"
continue
fi
while IFS= read -r -d '' sy_file; do
rel="$(realpath --relative-to="$REPO_ROOT" "$sy_file")"
if $SAVE_TREE; then
# 将路径中的 '/' 替换为 '_',避免子目录冲突
safe_name="${rel//\//_}"
tree_file="$TREE_OUTPUT_DIR/${safe_name}.tree"
# 运行编译器并保存输出
if "$COMPILER" --emit-parse-tree "$sy_file" > "$tree_file" 2>&1; then
echo -e " ${GREEN}PASS${NC} $rel (tree saved to $tree_file)"
((PASS++)) || true
else
echo -e " ${RED}FAIL${NC} $rel"
FAIL_LIST+=("$rel")
((FAIL++)) || true
fi
else
if "$COMPILER" --emit-parse-tree "$sy_file" > "./output/lab1/$(basename "$sy_file" .sy).tree" 2>&1; then
echo -e " ${GREEN}PASS${NC} $rel"
((PASS++)) || true
else
echo -e " ${RED}FAIL${NC} $rel"
FAIL_LIST+=("$rel")
((FAIL++)) || true
fi
fi
done < <(find "$TEST_DIR" -name "*.sy" -print0 | sort -z)
done
# ─── 汇总 ─────────────────────────────────────────────────────────────────────
echo ""
echo "──────────────────────────────────────────"
echo -e " 测试结果:${GREEN}${PASS} PASS${NC} / ${RED}${FAIL} FAIL${NC} / 总计 $((PASS + FAIL))"
if [[ ${#FAIL_LIST[@]} -gt 0 ]]; then
echo ""
echo " 失败用例:"
for f in "${FAIL_LIST[@]}"; do
echo -e " ${RED}- $f${NC}"
done
fi
echo "──────────────────────────────────────────"
[[ $FAIL -eq 0 ]]

@ -0,0 +1,201 @@
#!/usr/bin/env bash
# Lab2 自动化构建 + IR 验证测评脚本
# 用法:
# bash scripts/lab2_build_test.sh [--save-ir] [测试目录...]
#
# 选项:
# --save-ir 保存每个测试用例生成的 IR 到 output/lab2/ 目录
# 默认只进行通过/失败统计,不保存 IR
#
# 退出码:
# 0 全部用例验证通过
# 1 存在验证失败用例
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
COMPILER="$REPO_ROOT/build/bin/compiler"
ANTLR_JAR="$REPO_ROOT/third_party/antlr-4.13.2-complete.jar"
VERIFY_SCRIPT="$REPO_ROOT/scripts/verify_ir.sh"
# 输出目录
OUTPUT_DIR="$REPO_ROOT/output/lab2"
LOG_DIR="$REPO_ROOT/output/logs/lab2"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# 默认不保存 IR
SAVE_IR=false
# 解析命令行参数
TEST_DIRS=()
while [[ $# -gt 0 ]]; do
case "$1" in
--save-ir)
SAVE_IR=true
shift
;;
*)
TEST_DIRS+=("$1")
shift
;;
esac
done
# 如果没有指定测试目录,使用默认
if [[ ${#TEST_DIRS[@]} -eq 0 ]]; then
TEST_DIRS=(
"$REPO_ROOT/test/test_case/functional"
"$REPO_ROOT/test/test_case/performance"
)
fi
# 检查必要文件是否存在
if [ ! -f "$VERIFY_SCRIPT" ]; then
echo -e "${RED}错误: 验证脚本 $VERIFY_SCRIPT 不存在${NC}"
exit 1
fi
# 创建输出目录
mkdir -p "$OUTPUT_DIR" "$LOG_DIR"
# ─── Step 1生成 ANTLR Lexer/Parser ────────────────────────────────────────────────
echo "==> [1/3] 生成 ANTLR Lexer/Parser ..."
mkdir -p "$REPO_ROOT/build/generated/antlr4"
java -jar "$ANTLR_JAR" \
-Dlanguage=Cpp \
-visitor -no-listener \
-Xexact-output-dir \
-o "$REPO_ROOT/build/generated/antlr4" \
"$REPO_ROOT/src/antlr4/SysY.g4"
echo " Lexer/Parser 生成完毕"
# ─── Step 2CMake 完整构建(不启用 PARSE_ONLY────────────────────────────────────
echo "==> [2/3] CMake 构建完整编译器..."
cmake -S "$REPO_ROOT" -B "$REPO_ROOT/build" \
-DCMAKE_BUILD_TYPE=Release \
> /dev/null
cmake --build "$REPO_ROOT/build" -j "$(nproc)" 2>&1 | grep -E "error:|warning:|Built target|Linking" || true
echo " 构建完毕:$COMPILER"
# ─── Step 3批量验证 IR 生成与运行 ─────────────────────────────────────────────────
echo "==> [3/3] 批量验证 IR 生成与运行 ..."
PASS=0
FAIL=0
FAIL_LIST=()
# 定义测试单个文件的函数,便于统一错误处理
test_one() {
local sy_file="$1"
local rel="$2"
local basename="$(basename "$sy_file" .sy)"
local safe_name="${rel//\//_}" # 将路径中的 '/' 替换为 '_'
local result_dir="$OUTPUT_DIR/$basename"
local log_file="$LOG_DIR/${safe_name}.log"
# 创建结果目录
mkdir -p "$result_dir"
if $SAVE_IR; then
# 生成 IR 文件到指定目录
local ir_file="$OUTPUT_DIR/${safe_name}.ir"
mkdir -p "$(dirname "$ir_file")"
# 尝试生成 IR
if ! "$COMPILER" --emit-ir "$sy_file" > "$ir_file" 2>&1; then
# 编译失败,记录日志
{
echo "IR generation failed for $rel"
echo "Command: $COMPILER --emit-ir $sy_file"
echo "--- Output ---"
cat "$ir_file"
} > "$log_file" 2>&1
return 1
fi
# 运行验证脚本(不再重复生成 IR直接使用生成的 IR但 verify_ir.sh 内部会重新编译,所以我们仍调用它验证运行)
# 这里我们希望验证脚本将中间文件放到 result_dir 中
if ! "$VERIFY_SCRIPT" "$sy_file" "$result_dir" --run > /dev/null 2>&1; then
# 验证失败,记录日志
{
echo "Verification failed for $rel"
echo "Command: $VERIFY_SCRIPT $sy_file $result_dir --run"
# 可能还需要捕获验证脚本的输出,但 verify_ir.sh 已经将错误打印到 stderr我们无法直接捕获
# 这里我们只能记录一些基本信息,并建议查看 result_dir 中的输出
echo "Check result directory: $result_dir"
# 如果 result_dir 中有输出文件,可以尝试附加
if [ -f "$result_dir/out" ]; then
echo "--- Program output ---"
cat "$result_dir/out"
fi
if [ -f "$result_dir/err" ]; then
echo "--- Program error ---"
cat "$result_dir/err"
fi
} > "$log_file" 2>&1
return 1
fi
else
# 不保存 IR直接运行验证脚本
if ! "$VERIFY_SCRIPT" "$sy_file" "$result_dir" --run > /dev/null 2>&1; then
{
echo "Verification failed for $rel"
echo "Command: $VERIFY_SCRIPT $sy_file $result_dir --run"
echo "Check result directory: $result_dir"
if [ -f "$result_dir/out" ]; then
echo "--- Program output ---"
cat "$result_dir/out"
fi
if [ -f "$result_dir/err" ]; then
echo "--- Program error ---"
cat "$result_dir/err"
fi
} > "$log_file" 2>&1
return 1
fi
fi
return 0
}
for TEST_DIR in "${TEST_DIRS[@]}"; do
if [[ ! -d "$TEST_DIR" ]]; then
echo -e " ${YELLOW}警告:目录不存在,跳过:$TEST_DIR${NC}"
continue
fi
while IFS= read -r -d '' sy_file; do
rel="$(realpath --relative-to="$REPO_ROOT" "$sy_file")"
echo -n "测试 $rel ... "
if test_one "$sy_file" "$rel"; then
echo -e "${GREEN}PASS${NC}"
((PASS++)) || true
else
echo -e "${RED}FAIL${NC}"
FAIL_LIST+=("$rel")
((FAIL++)) || true
fi
done < <(find "$TEST_DIR" -name "*.sy" -print0 | sort -z)
done
# ─── 汇总 ─────────────────────────────────────────────────────────────────────
echo ""
echo "──────────────────────────────────────────"
echo -e " 测试结果:${GREEN}${PASS} PASS${NC} / ${RED}${FAIL} FAIL${NC} / 总计 $((PASS + FAIL))"
if [[ ${#FAIL_LIST[@]} -gt 0 ]]; then
echo ""
echo " 失败用例:"
for f in "${FAIL_LIST[@]}"; do
echo -e " ${RED}- $f${NC}"
echo " 日志文件: $LOG_DIR/${f//\//_}.log"
done
fi
echo "──────────────────────────────────────────"
[[ $FAIL -eq 0 ]]

@ -0,0 +1,591 @@
// Generated from /root/sysy2026/nudt-compiler-cpp/src/antlr4/SysY.g4 by ANTLR 4.13.1
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode;
/**
* This class provides an empty implementation of {@link SysYListener},
* which can be extended to create a listener which only needs to handle a subset
* of the available methods.
*/
@SuppressWarnings("CheckReturnValue")
public class SysYBaseListener implements SysYListener {
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterCompUnit(SysYParser.CompUnitContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitCompUnit(SysYParser.CompUnitContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterDecl(SysYParser.DeclContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitDecl(SysYParser.DeclContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterConstDecl(SysYParser.ConstDeclContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitConstDecl(SysYParser.ConstDeclContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterBType(SysYParser.BTypeContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitBType(SysYParser.BTypeContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterConstDef(SysYParser.ConstDefContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitConstDef(SysYParser.ConstDefContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterConstInitVal(SysYParser.ConstInitValContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitConstInitVal(SysYParser.ConstInitValContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterVarDecl(SysYParser.VarDeclContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitVarDecl(SysYParser.VarDeclContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterVarDef(SysYParser.VarDefContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitVarDef(SysYParser.VarDefContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterInitVal(SysYParser.InitValContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitInitVal(SysYParser.InitValContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterFuncDef(SysYParser.FuncDefContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitFuncDef(SysYParser.FuncDefContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterFuncType(SysYParser.FuncTypeContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitFuncType(SysYParser.FuncTypeContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterFuncFParams(SysYParser.FuncFParamsContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitFuncFParams(SysYParser.FuncFParamsContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterFuncFParam(SysYParser.FuncFParamContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitFuncFParam(SysYParser.FuncFParamContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterBlock(SysYParser.BlockContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitBlock(SysYParser.BlockContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterBlockItem(SysYParser.BlockItemContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitBlockItem(SysYParser.BlockItemContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterAssignStmt(SysYParser.AssignStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitAssignStmt(SysYParser.AssignStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterExpStmt(SysYParser.ExpStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitExpStmt(SysYParser.ExpStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterBlockStmt(SysYParser.BlockStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitBlockStmt(SysYParser.BlockStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterIfStmt(SysYParser.IfStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitIfStmt(SysYParser.IfStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterWhileStmt(SysYParser.WhileStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitWhileStmt(SysYParser.WhileStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterBreakStmt(SysYParser.BreakStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitBreakStmt(SysYParser.BreakStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterContinueStmt(SysYParser.ContinueStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitContinueStmt(SysYParser.ContinueStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterReturnStmt(SysYParser.ReturnStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitReturnStmt(SysYParser.ReturnStmtContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterExp(SysYParser.ExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitExp(SysYParser.ExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterCond(SysYParser.CondContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitCond(SysYParser.CondContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterLVal(SysYParser.LValContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitLVal(SysYParser.LValContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterPrimaryExp(SysYParser.PrimaryExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitPrimaryExp(SysYParser.PrimaryExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterNumber(SysYParser.NumberContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitNumber(SysYParser.NumberContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterPrimaryUnaryExp(SysYParser.PrimaryUnaryExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitPrimaryUnaryExp(SysYParser.PrimaryUnaryExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterCallUnaryExp(SysYParser.CallUnaryExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitCallUnaryExp(SysYParser.CallUnaryExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterOpUnaryExp(SysYParser.OpUnaryExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitOpUnaryExp(SysYParser.OpUnaryExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterUnaryOp(SysYParser.UnaryOpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitUnaryOp(SysYParser.UnaryOpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterFuncRParams(SysYParser.FuncRParamsContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitFuncRParams(SysYParser.FuncRParamsContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterBinaryMulExp(SysYParser.BinaryMulExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitBinaryMulExp(SysYParser.BinaryMulExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterUnaryMulExp(SysYParser.UnaryMulExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitUnaryMulExp(SysYParser.UnaryMulExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterBinaryAddExp(SysYParser.BinaryAddExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitBinaryAddExp(SysYParser.BinaryAddExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterMulAddExp(SysYParser.MulAddExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitMulAddExp(SysYParser.MulAddExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterAddRelExp(SysYParser.AddRelExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitAddRelExp(SysYParser.AddRelExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterBinaryRelExp(SysYParser.BinaryRelExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitBinaryRelExp(SysYParser.BinaryRelExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterBinaryEqExp(SysYParser.BinaryEqExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitBinaryEqExp(SysYParser.BinaryEqExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterRelEqExp(SysYParser.RelEqExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitRelEqExp(SysYParser.RelEqExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterEqLAndExp(SysYParser.EqLAndExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitEqLAndExp(SysYParser.EqLAndExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterBinaryLAndExp(SysYParser.BinaryLAndExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitBinaryLAndExp(SysYParser.BinaryLAndExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterAndLOrExp(SysYParser.AndLOrExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitAndLOrExp(SysYParser.AndLOrExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterBinaryLOrExp(SysYParser.BinaryLOrExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitBinaryLOrExp(SysYParser.BinaryLOrExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterConstExp(SysYParser.ConstExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitConstExp(SysYParser.ConstExpContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterEveryRule(ParserRuleContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitEveryRule(ParserRuleContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void visitTerminal(TerminalNode node) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void visitErrorNode(ErrorNode node) { }
}

@ -0,0 +1,358 @@
// Generated from /root/sysy2026/nudt-compiler-cpp/src/antlr4/SysY.g4 by ANTLR 4.13.1
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.*;
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"})
public class SysYLexer extends Lexer {
static { RuntimeMetaData.checkVersion("4.13.1", RuntimeMetaData.VERSION); }
protected static final DFA[] _decisionToDFA;
protected static final PredictionContextCache _sharedContextCache =
new PredictionContextCache();
public static final int
CONST=1, INT=2, FLOAT=3, VOID=4, IF=5, ELSE=6, WHILE=7, BREAK=8, CONTINUE=9,
RETURN=10, ADD=11, SUB=12, MUL=13, DIV=14, MOD=15, ASSIGN=16, EQ=17, NE=18,
LT=19, LE=20, GT=21, GE=22, NOT=23, AND=24, OR=25, LPAREN=26, RPAREN=27,
LBRACK=28, RBRACK=29, LBRACE=30, RBRACE=31, COMMA=32, SEMI=33, Ident=34,
IntConst=35, FloatConst=36, WS=37, LINE_COMMENT=38, BLOCK_COMMENT=39;
public static String[] channelNames = {
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
};
public static String[] modeNames = {
"DEFAULT_MODE"
};
private static String[] makeRuleNames() {
return new String[] {
"CONST", "INT", "FLOAT", "VOID", "IF", "ELSE", "WHILE", "BREAK", "CONTINUE",
"RETURN", "ADD", "SUB", "MUL", "DIV", "MOD", "ASSIGN", "EQ", "NE", "LT",
"LE", "GT", "GE", "NOT", "AND", "OR", "LPAREN", "RPAREN", "LBRACK", "RBRACK",
"LBRACE", "RBRACE", "COMMA", "SEMI", "Ident", "Digit", "NonzeroDigit",
"OctDigit", "HexDigit", "DecInteger", "OctInteger", "HexInteger", "DecFraction",
"DecExponent", "DecFloat", "HexFraction", "BinExponent", "HexFloat",
"IntConst", "FloatConst", "WS", "LINE_COMMENT", "BLOCK_COMMENT"
};
}
public static final String[] ruleNames = makeRuleNames();
private static String[] makeLiteralNames() {
return new String[] {
null, "'const'", "'int'", "'float'", "'void'", "'if'", "'else'", "'while'",
"'break'", "'continue'", "'return'", "'+'", "'-'", "'*'", "'/'", "'%'",
"'='", "'=='", "'!='", "'<'", "'<='", "'>'", "'>='", "'!'", "'&&'", "'||'",
"'('", "')'", "'['", "']'", "'{'", "'}'", "','", "';'"
};
}
private static final String[] _LITERAL_NAMES = makeLiteralNames();
private static String[] makeSymbolicNames() {
return new String[] {
null, "CONST", "INT", "FLOAT", "VOID", "IF", "ELSE", "WHILE", "BREAK",
"CONTINUE", "RETURN", "ADD", "SUB", "MUL", "DIV", "MOD", "ASSIGN", "EQ",
"NE", "LT", "LE", "GT", "GE", "NOT", "AND", "OR", "LPAREN", "RPAREN",
"LBRACK", "RBRACK", "LBRACE", "RBRACE", "COMMA", "SEMI", "Ident", "IntConst",
"FloatConst", "WS", "LINE_COMMENT", "BLOCK_COMMENT"
};
}
private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
/**
* @deprecated Use {@link #VOCABULARY} instead.
*/
@Deprecated
public static final String[] tokenNames;
static {
tokenNames = new String[_SYMBOLIC_NAMES.length];
for (int i = 0; i < tokenNames.length; i++) {
tokenNames[i] = VOCABULARY.getLiteralName(i);
if (tokenNames[i] == null) {
tokenNames[i] = VOCABULARY.getSymbolicName(i);
}
if (tokenNames[i] == null) {
tokenNames[i] = "<INVALID>";
}
}
}
@Override
@Deprecated
public String[] getTokenNames() {
return tokenNames;
}
@Override
public Vocabulary getVocabulary() {
return VOCABULARY;
}
public SysYLexer(CharStream input) {
super(input);
_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
}
@Override
public String getGrammarFileName() { return "SysY.g4"; }
@Override
public String[] getRuleNames() { return ruleNames; }
@Override
public String getSerializedATN() { return _serializedATN; }
@Override
public String[] getChannelNames() { return channelNames; }
@Override
public String[] getModeNames() { return modeNames; }
@Override
public ATN getATN() { return _ATN; }
public static final String _serializedATN =
"\u0004\u0000\'\u0171\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001"+
"\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004"+
"\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007"+
"\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b"+
"\u0007\u000b\u0002\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002"+
"\u000f\u0007\u000f\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011\u0002"+
"\u0012\u0007\u0012\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014\u0002"+
"\u0015\u0007\u0015\u0002\u0016\u0007\u0016\u0002\u0017\u0007\u0017\u0002"+
"\u0018\u0007\u0018\u0002\u0019\u0007\u0019\u0002\u001a\u0007\u001a\u0002"+
"\u001b\u0007\u001b\u0002\u001c\u0007\u001c\u0002\u001d\u0007\u001d\u0002"+
"\u001e\u0007\u001e\u0002\u001f\u0007\u001f\u0002 \u0007 \u0002!\u0007"+
"!\u0002\"\u0007\"\u0002#\u0007#\u0002$\u0007$\u0002%\u0007%\u0002&\u0007"+
"&\u0002\'\u0007\'\u0002(\u0007(\u0002)\u0007)\u0002*\u0007*\u0002+\u0007"+
"+\u0002,\u0007,\u0002-\u0007-\u0002.\u0007.\u0002/\u0007/\u00020\u0007"+
"0\u00021\u00071\u00022\u00072\u00023\u00073\u0001\u0000\u0001\u0000\u0001"+
"\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001"+
"\u0001\u0001\u0001\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001"+
"\u0002\u0001\u0002\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001"+
"\u0003\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001"+
"\u0005\u0001\u0005\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001"+
"\u0006\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007\u0001\u0007\u0001"+
"\u0007\u0001\u0007\u0001\u0007\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b"+
"\u0001\b\u0001\b\u0001\b\u0001\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001"+
"\t\u0001\t\u0001\t\u0001\n\u0001\n\u0001\u000b\u0001\u000b\u0001\f\u0001"+
"\f\u0001\r\u0001\r\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001"+
"\u0010\u0001\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0011\u0001"+
"\u0012\u0001\u0012\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0014\u0001"+
"\u0014\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001"+
"\u0017\u0001\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0001"+
"\u0019\u0001\u0019\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001"+
"\u001c\u0001\u001c\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001"+
"\u001f\u0001\u001f\u0001 \u0001 \u0001!\u0001!\u0005!\u00d9\b!\n!\f!\u00dc"+
"\t!\u0001\"\u0001\"\u0001#\u0001#\u0001$\u0001$\u0001%\u0001%\u0001&\u0001"+
"&\u0005&\u00e8\b&\n&\f&\u00eb\t&\u0001\'\u0001\'\u0005\'\u00ef\b\'\n\'"+
"\f\'\u00f2\t\'\u0001(\u0001(\u0001(\u0004(\u00f7\b(\u000b(\f(\u00f8\u0001"+
")\u0004)\u00fc\b)\u000b)\f)\u00fd\u0001)\u0001)\u0005)\u0102\b)\n)\f)"+
"\u0105\t)\u0001)\u0001)\u0004)\u0109\b)\u000b)\f)\u010a\u0003)\u010d\b"+
")\u0001*\u0001*\u0003*\u0111\b*\u0001*\u0004*\u0114\b*\u000b*\f*\u0115"+
"\u0001+\u0001+\u0003+\u011a\b+\u0001+\u0001+\u0001+\u0003+\u011f\b+\u0001"+
",\u0005,\u0122\b,\n,\f,\u0125\t,\u0001,\u0001,\u0004,\u0129\b,\u000b,"+
"\f,\u012a\u0001,\u0004,\u012e\b,\u000b,\f,\u012f\u0001,\u0001,\u0003,"+
"\u0134\b,\u0001-\u0001-\u0003-\u0138\b-\u0001-\u0004-\u013b\b-\u000b-"+
"\f-\u013c\u0001.\u0001.\u0001.\u0001.\u0001.\u0001.\u0001.\u0001.\u0003"+
".\u0147\b.\u0001/\u0001/\u0001/\u0003/\u014c\b/\u00010\u00010\u00030\u0150"+
"\b0\u00011\u00041\u0153\b1\u000b1\f1\u0154\u00011\u00011\u00012\u0001"+
"2\u00012\u00012\u00052\u015d\b2\n2\f2\u0160\t2\u00012\u00012\u00013\u0001"+
"3\u00013\u00013\u00053\u0168\b3\n3\f3\u016b\t3\u00013\u00013\u00013\u0001"+
"3\u00013\u0001\u0169\u00004\u0001\u0001\u0003\u0002\u0005\u0003\u0007"+
"\u0004\t\u0005\u000b\u0006\r\u0007\u000f\b\u0011\t\u0013\n\u0015\u000b"+
"\u0017\f\u0019\r\u001b\u000e\u001d\u000f\u001f\u0010!\u0011#\u0012%\u0013"+
"\'\u0014)\u0015+\u0016-\u0017/\u00181\u00193\u001a5\u001b7\u001c9\u001d"+
";\u001e=\u001f? A!C\"E\u0000G\u0000I\u0000K\u0000M\u0000O\u0000Q\u0000"+
"S\u0000U\u0000W\u0000Y\u0000[\u0000]\u0000_#a$c%e&g\'\u0001\u0000\f\u0003"+
"\u0000AZ__az\u0004\u000009AZ__az\u0001\u000009\u0001\u000019\u0001\u0000"+
"07\u0003\u000009AFaf\u0002\u0000XXxx\u0002\u0000EEee\u0002\u0000++--\u0002"+
"\u0000PPpp\u0003\u0000\t\n\r\r \u0002\u0000\n\n\r\r\u017c\u0000\u0001"+
"\u0001\u0000\u0000\u0000\u0000\u0003\u0001\u0000\u0000\u0000\u0000\u0005"+
"\u0001\u0000\u0000\u0000\u0000\u0007\u0001\u0000\u0000\u0000\u0000\t\u0001"+
"\u0000\u0000\u0000\u0000\u000b\u0001\u0000\u0000\u0000\u0000\r\u0001\u0000"+
"\u0000\u0000\u0000\u000f\u0001\u0000\u0000\u0000\u0000\u0011\u0001\u0000"+
"\u0000\u0000\u0000\u0013\u0001\u0000\u0000\u0000\u0000\u0015\u0001\u0000"+
"\u0000\u0000\u0000\u0017\u0001\u0000\u0000\u0000\u0000\u0019\u0001\u0000"+
"\u0000\u0000\u0000\u001b\u0001\u0000\u0000\u0000\u0000\u001d\u0001\u0000"+
"\u0000\u0000\u0000\u001f\u0001\u0000\u0000\u0000\u0000!\u0001\u0000\u0000"+
"\u0000\u0000#\u0001\u0000\u0000\u0000\u0000%\u0001\u0000\u0000\u0000\u0000"+
"\'\u0001\u0000\u0000\u0000\u0000)\u0001\u0000\u0000\u0000\u0000+\u0001"+
"\u0000\u0000\u0000\u0000-\u0001\u0000\u0000\u0000\u0000/\u0001\u0000\u0000"+
"\u0000\u00001\u0001\u0000\u0000\u0000\u00003\u0001\u0000\u0000\u0000\u0000"+
"5\u0001\u0000\u0000\u0000\u00007\u0001\u0000\u0000\u0000\u00009\u0001"+
"\u0000\u0000\u0000\u0000;\u0001\u0000\u0000\u0000\u0000=\u0001\u0000\u0000"+
"\u0000\u0000?\u0001\u0000\u0000\u0000\u0000A\u0001\u0000\u0000\u0000\u0000"+
"C\u0001\u0000\u0000\u0000\u0000_\u0001\u0000\u0000\u0000\u0000a\u0001"+
"\u0000\u0000\u0000\u0000c\u0001\u0000\u0000\u0000\u0000e\u0001\u0000\u0000"+
"\u0000\u0000g\u0001\u0000\u0000\u0000\u0001i\u0001\u0000\u0000\u0000\u0003"+
"o\u0001\u0000\u0000\u0000\u0005s\u0001\u0000\u0000\u0000\u0007y\u0001"+
"\u0000\u0000\u0000\t~\u0001\u0000\u0000\u0000\u000b\u0081\u0001\u0000"+
"\u0000\u0000\r\u0086\u0001\u0000\u0000\u0000\u000f\u008c\u0001\u0000\u0000"+
"\u0000\u0011\u0092\u0001\u0000\u0000\u0000\u0013\u009b\u0001\u0000\u0000"+
"\u0000\u0015\u00a2\u0001\u0000\u0000\u0000\u0017\u00a4\u0001\u0000\u0000"+
"\u0000\u0019\u00a6\u0001\u0000\u0000\u0000\u001b\u00a8\u0001\u0000\u0000"+
"\u0000\u001d\u00aa\u0001\u0000\u0000\u0000\u001f\u00ac\u0001\u0000\u0000"+
"\u0000!\u00ae\u0001\u0000\u0000\u0000#\u00b1\u0001\u0000\u0000\u0000%"+
"\u00b4\u0001\u0000\u0000\u0000\'\u00b6\u0001\u0000\u0000\u0000)\u00b9"+
"\u0001\u0000\u0000\u0000+\u00bb\u0001\u0000\u0000\u0000-\u00be\u0001\u0000"+
"\u0000\u0000/\u00c0\u0001\u0000\u0000\u00001\u00c3\u0001\u0000\u0000\u0000"+
"3\u00c6\u0001\u0000\u0000\u00005\u00c8\u0001\u0000\u0000\u00007\u00ca"+
"\u0001\u0000\u0000\u00009\u00cc\u0001\u0000\u0000\u0000;\u00ce\u0001\u0000"+
"\u0000\u0000=\u00d0\u0001\u0000\u0000\u0000?\u00d2\u0001\u0000\u0000\u0000"+
"A\u00d4\u0001\u0000\u0000\u0000C\u00d6\u0001\u0000\u0000\u0000E\u00dd"+
"\u0001\u0000\u0000\u0000G\u00df\u0001\u0000\u0000\u0000I\u00e1\u0001\u0000"+
"\u0000\u0000K\u00e3\u0001\u0000\u0000\u0000M\u00e5\u0001\u0000\u0000\u0000"+
"O\u00ec\u0001\u0000\u0000\u0000Q\u00f3\u0001\u0000\u0000\u0000S\u010c"+
"\u0001\u0000\u0000\u0000U\u010e\u0001\u0000\u0000\u0000W\u011e\u0001\u0000"+
"\u0000\u0000Y\u0133\u0001\u0000\u0000\u0000[\u0135\u0001\u0000\u0000\u0000"+
"]\u0146\u0001\u0000\u0000\u0000_\u014b\u0001\u0000\u0000\u0000a\u014f"+
"\u0001\u0000\u0000\u0000c\u0152\u0001\u0000\u0000\u0000e\u0158\u0001\u0000"+
"\u0000\u0000g\u0163\u0001\u0000\u0000\u0000ij\u0005c\u0000\u0000jk\u0005"+
"o\u0000\u0000kl\u0005n\u0000\u0000lm\u0005s\u0000\u0000mn\u0005t\u0000"+
"\u0000n\u0002\u0001\u0000\u0000\u0000op\u0005i\u0000\u0000pq\u0005n\u0000"+
"\u0000qr\u0005t\u0000\u0000r\u0004\u0001\u0000\u0000\u0000st\u0005f\u0000"+
"\u0000tu\u0005l\u0000\u0000uv\u0005o\u0000\u0000vw\u0005a\u0000\u0000"+
"wx\u0005t\u0000\u0000x\u0006\u0001\u0000\u0000\u0000yz\u0005v\u0000\u0000"+
"z{\u0005o\u0000\u0000{|\u0005i\u0000\u0000|}\u0005d\u0000\u0000}\b\u0001"+
"\u0000\u0000\u0000~\u007f\u0005i\u0000\u0000\u007f\u0080\u0005f\u0000"+
"\u0000\u0080\n\u0001\u0000\u0000\u0000\u0081\u0082\u0005e\u0000\u0000"+
"\u0082\u0083\u0005l\u0000\u0000\u0083\u0084\u0005s\u0000\u0000\u0084\u0085"+
"\u0005e\u0000\u0000\u0085\f\u0001\u0000\u0000\u0000\u0086\u0087\u0005"+
"w\u0000\u0000\u0087\u0088\u0005h\u0000\u0000\u0088\u0089\u0005i\u0000"+
"\u0000\u0089\u008a\u0005l\u0000\u0000\u008a\u008b\u0005e\u0000\u0000\u008b"+
"\u000e\u0001\u0000\u0000\u0000\u008c\u008d\u0005b\u0000\u0000\u008d\u008e"+
"\u0005r\u0000\u0000\u008e\u008f\u0005e\u0000\u0000\u008f\u0090\u0005a"+
"\u0000\u0000\u0090\u0091\u0005k\u0000\u0000\u0091\u0010\u0001\u0000\u0000"+
"\u0000\u0092\u0093\u0005c\u0000\u0000\u0093\u0094\u0005o\u0000\u0000\u0094"+
"\u0095\u0005n\u0000\u0000\u0095\u0096\u0005t\u0000\u0000\u0096\u0097\u0005"+
"i\u0000\u0000\u0097\u0098\u0005n\u0000\u0000\u0098\u0099\u0005u\u0000"+
"\u0000\u0099\u009a\u0005e\u0000\u0000\u009a\u0012\u0001\u0000\u0000\u0000"+
"\u009b\u009c\u0005r\u0000\u0000\u009c\u009d\u0005e\u0000\u0000\u009d\u009e"+
"\u0005t\u0000\u0000\u009e\u009f\u0005u\u0000\u0000\u009f\u00a0\u0005r"+
"\u0000\u0000\u00a0\u00a1\u0005n\u0000\u0000\u00a1\u0014\u0001\u0000\u0000"+
"\u0000\u00a2\u00a3\u0005+\u0000\u0000\u00a3\u0016\u0001\u0000\u0000\u0000"+
"\u00a4\u00a5\u0005-\u0000\u0000\u00a5\u0018\u0001\u0000\u0000\u0000\u00a6"+
"\u00a7\u0005*\u0000\u0000\u00a7\u001a\u0001\u0000\u0000\u0000\u00a8\u00a9"+
"\u0005/\u0000\u0000\u00a9\u001c\u0001\u0000\u0000\u0000\u00aa\u00ab\u0005"+
"%\u0000\u0000\u00ab\u001e\u0001\u0000\u0000\u0000\u00ac\u00ad\u0005=\u0000"+
"\u0000\u00ad \u0001\u0000\u0000\u0000\u00ae\u00af\u0005=\u0000\u0000\u00af"+
"\u00b0\u0005=\u0000\u0000\u00b0\"\u0001\u0000\u0000\u0000\u00b1\u00b2"+
"\u0005!\u0000\u0000\u00b2\u00b3\u0005=\u0000\u0000\u00b3$\u0001\u0000"+
"\u0000\u0000\u00b4\u00b5\u0005<\u0000\u0000\u00b5&\u0001\u0000\u0000\u0000"+
"\u00b6\u00b7\u0005<\u0000\u0000\u00b7\u00b8\u0005=\u0000\u0000\u00b8("+
"\u0001\u0000\u0000\u0000\u00b9\u00ba\u0005>\u0000\u0000\u00ba*\u0001\u0000"+
"\u0000\u0000\u00bb\u00bc\u0005>\u0000\u0000\u00bc\u00bd\u0005=\u0000\u0000"+
"\u00bd,\u0001\u0000\u0000\u0000\u00be\u00bf\u0005!\u0000\u0000\u00bf."+
"\u0001\u0000\u0000\u0000\u00c0\u00c1\u0005&\u0000\u0000\u00c1\u00c2\u0005"+
"&\u0000\u0000\u00c20\u0001\u0000\u0000\u0000\u00c3\u00c4\u0005|\u0000"+
"\u0000\u00c4\u00c5\u0005|\u0000\u0000\u00c52\u0001\u0000\u0000\u0000\u00c6"+
"\u00c7\u0005(\u0000\u0000\u00c74\u0001\u0000\u0000\u0000\u00c8\u00c9\u0005"+
")\u0000\u0000\u00c96\u0001\u0000\u0000\u0000\u00ca\u00cb\u0005[\u0000"+
"\u0000\u00cb8\u0001\u0000\u0000\u0000\u00cc\u00cd\u0005]\u0000\u0000\u00cd"+
":\u0001\u0000\u0000\u0000\u00ce\u00cf\u0005{\u0000\u0000\u00cf<\u0001"+
"\u0000\u0000\u0000\u00d0\u00d1\u0005}\u0000\u0000\u00d1>\u0001\u0000\u0000"+
"\u0000\u00d2\u00d3\u0005,\u0000\u0000\u00d3@\u0001\u0000\u0000\u0000\u00d4"+
"\u00d5\u0005;\u0000\u0000\u00d5B\u0001\u0000\u0000\u0000\u00d6\u00da\u0007"+
"\u0000\u0000\u0000\u00d7\u00d9\u0007\u0001\u0000\u0000\u00d8\u00d7\u0001"+
"\u0000\u0000\u0000\u00d9\u00dc\u0001\u0000\u0000\u0000\u00da\u00d8\u0001"+
"\u0000\u0000\u0000\u00da\u00db\u0001\u0000\u0000\u0000\u00dbD\u0001\u0000"+
"\u0000\u0000\u00dc\u00da\u0001\u0000\u0000\u0000\u00dd\u00de\u0007\u0002"+
"\u0000\u0000\u00deF\u0001\u0000\u0000\u0000\u00df\u00e0\u0007\u0003\u0000"+
"\u0000\u00e0H\u0001\u0000\u0000\u0000\u00e1\u00e2\u0007\u0004\u0000\u0000"+
"\u00e2J\u0001\u0000\u0000\u0000\u00e3\u00e4\u0007\u0005\u0000\u0000\u00e4"+
"L\u0001\u0000\u0000\u0000\u00e5\u00e9\u0003G#\u0000\u00e6\u00e8\u0003"+
"E\"\u0000\u00e7\u00e6\u0001\u0000\u0000\u0000\u00e8\u00eb\u0001\u0000"+
"\u0000\u0000\u00e9\u00e7\u0001\u0000\u0000\u0000\u00e9\u00ea\u0001\u0000"+
"\u0000\u0000\u00eaN\u0001\u0000\u0000\u0000\u00eb\u00e9\u0001\u0000\u0000"+
"\u0000\u00ec\u00f0\u00050\u0000\u0000\u00ed\u00ef\u0003I$\u0000\u00ee"+
"\u00ed\u0001\u0000\u0000\u0000\u00ef\u00f2\u0001\u0000\u0000\u0000\u00f0"+
"\u00ee\u0001\u0000\u0000\u0000\u00f0\u00f1\u0001\u0000\u0000\u0000\u00f1"+
"P\u0001\u0000\u0000\u0000\u00f2\u00f0\u0001\u0000\u0000\u0000\u00f3\u00f4"+
"\u00050\u0000\u0000\u00f4\u00f6\u0007\u0006\u0000\u0000\u00f5\u00f7\u0003"+
"K%\u0000\u00f6\u00f5\u0001\u0000\u0000\u0000\u00f7\u00f8\u0001\u0000\u0000"+
"\u0000\u00f8\u00f6\u0001\u0000\u0000\u0000\u00f8\u00f9\u0001\u0000\u0000"+
"\u0000\u00f9R\u0001\u0000\u0000\u0000\u00fa\u00fc\u0003E\"\u0000\u00fb"+
"\u00fa\u0001\u0000\u0000\u0000\u00fc\u00fd\u0001\u0000\u0000\u0000\u00fd"+
"\u00fb\u0001\u0000\u0000\u0000\u00fd\u00fe\u0001\u0000\u0000\u0000\u00fe"+
"\u00ff\u0001\u0000\u0000\u0000\u00ff\u0103\u0005.\u0000\u0000\u0100\u0102"+
"\u0003E\"\u0000\u0101\u0100\u0001\u0000\u0000\u0000\u0102\u0105\u0001"+
"\u0000\u0000\u0000\u0103\u0101\u0001\u0000\u0000\u0000\u0103\u0104\u0001"+
"\u0000\u0000\u0000\u0104\u010d\u0001\u0000\u0000\u0000\u0105\u0103\u0001"+
"\u0000\u0000\u0000\u0106\u0108\u0005.\u0000\u0000\u0107\u0109\u0003E\""+
"\u0000\u0108\u0107\u0001\u0000\u0000\u0000\u0109\u010a\u0001\u0000\u0000"+
"\u0000\u010a\u0108\u0001\u0000\u0000\u0000\u010a\u010b\u0001\u0000\u0000"+
"\u0000\u010b\u010d\u0001\u0000\u0000\u0000\u010c\u00fb\u0001\u0000\u0000"+
"\u0000\u010c\u0106\u0001\u0000\u0000\u0000\u010dT\u0001\u0000\u0000\u0000"+
"\u010e\u0110\u0007\u0007\u0000\u0000\u010f\u0111\u0007\b\u0000\u0000\u0110"+
"\u010f\u0001\u0000\u0000\u0000\u0110\u0111\u0001\u0000\u0000\u0000\u0111"+
"\u0113\u0001\u0000\u0000\u0000\u0112\u0114\u0003E\"\u0000\u0113\u0112"+
"\u0001\u0000\u0000\u0000\u0114\u0115\u0001\u0000\u0000\u0000\u0115\u0113"+
"\u0001\u0000\u0000\u0000\u0115\u0116\u0001\u0000\u0000\u0000\u0116V\u0001"+
"\u0000\u0000\u0000\u0117\u0119\u0003S)\u0000\u0118\u011a\u0003U*\u0000"+
"\u0119\u0118\u0001\u0000\u0000\u0000\u0119\u011a\u0001\u0000\u0000\u0000"+
"\u011a\u011f\u0001\u0000\u0000\u0000\u011b\u011c\u0003M&\u0000\u011c\u011d"+
"\u0003U*\u0000\u011d\u011f\u0001\u0000\u0000\u0000\u011e\u0117\u0001\u0000"+
"\u0000\u0000\u011e\u011b\u0001\u0000\u0000\u0000\u011fX\u0001\u0000\u0000"+
"\u0000\u0120\u0122\u0003K%\u0000\u0121\u0120\u0001\u0000\u0000\u0000\u0122"+
"\u0125\u0001\u0000\u0000\u0000\u0123\u0121\u0001\u0000\u0000\u0000\u0123"+
"\u0124\u0001\u0000\u0000\u0000\u0124\u0126\u0001\u0000\u0000\u0000\u0125"+
"\u0123\u0001\u0000\u0000\u0000\u0126\u0128\u0005.\u0000\u0000\u0127\u0129"+
"\u0003K%\u0000\u0128\u0127\u0001\u0000\u0000\u0000\u0129\u012a\u0001\u0000"+
"\u0000\u0000\u012a\u0128\u0001\u0000\u0000\u0000\u012a\u012b\u0001\u0000"+
"\u0000\u0000\u012b\u0134\u0001\u0000\u0000\u0000\u012c\u012e\u0003K%\u0000"+
"\u012d\u012c\u0001\u0000\u0000\u0000\u012e\u012f\u0001\u0000\u0000\u0000"+
"\u012f\u012d\u0001\u0000\u0000\u0000\u012f\u0130\u0001\u0000\u0000\u0000"+
"\u0130\u0131\u0001\u0000\u0000\u0000\u0131\u0132\u0005.\u0000\u0000\u0132"+
"\u0134\u0001\u0000\u0000\u0000\u0133\u0123\u0001\u0000\u0000\u0000\u0133"+
"\u012d\u0001\u0000\u0000\u0000\u0134Z\u0001\u0000\u0000\u0000\u0135\u0137"+
"\u0007\t\u0000\u0000\u0136\u0138\u0007\b\u0000\u0000\u0137\u0136\u0001"+
"\u0000\u0000\u0000\u0137\u0138\u0001\u0000\u0000\u0000\u0138\u013a\u0001"+
"\u0000\u0000\u0000\u0139\u013b\u0003E\"\u0000\u013a\u0139\u0001\u0000"+
"\u0000\u0000\u013b\u013c\u0001\u0000\u0000\u0000\u013c\u013a\u0001\u0000"+
"\u0000\u0000\u013c\u013d\u0001\u0000\u0000\u0000\u013d\\\u0001\u0000\u0000"+
"\u0000\u013e\u013f\u00050\u0000\u0000\u013f\u0140\u0007\u0006\u0000\u0000"+
"\u0140\u0141\u0003Y,\u0000\u0141\u0142\u0003[-\u0000\u0142\u0147\u0001"+
"\u0000\u0000\u0000\u0143\u0144\u0003Q(\u0000\u0144\u0145\u0003[-\u0000"+
"\u0145\u0147\u0001\u0000\u0000\u0000\u0146\u013e\u0001\u0000\u0000\u0000"+
"\u0146\u0143\u0001\u0000\u0000\u0000\u0147^\u0001\u0000\u0000\u0000\u0148"+
"\u014c\u0003M&\u0000\u0149\u014c\u0003O\'\u0000\u014a\u014c\u0003Q(\u0000"+
"\u014b\u0148\u0001\u0000\u0000\u0000\u014b\u0149\u0001\u0000\u0000\u0000"+
"\u014b\u014a\u0001\u0000\u0000\u0000\u014c`\u0001\u0000\u0000\u0000\u014d"+
"\u0150\u0003W+\u0000\u014e\u0150\u0003].\u0000\u014f\u014d\u0001\u0000"+
"\u0000\u0000\u014f\u014e\u0001\u0000\u0000\u0000\u0150b\u0001\u0000\u0000"+
"\u0000\u0151\u0153\u0007\n\u0000\u0000\u0152\u0151\u0001\u0000\u0000\u0000"+
"\u0153\u0154\u0001\u0000\u0000\u0000\u0154\u0152\u0001\u0000\u0000\u0000"+
"\u0154\u0155\u0001\u0000\u0000\u0000\u0155\u0156\u0001\u0000\u0000\u0000"+
"\u0156\u0157\u00061\u0000\u0000\u0157d\u0001\u0000\u0000\u0000\u0158\u0159"+
"\u0005/\u0000\u0000\u0159\u015a\u0005/\u0000\u0000\u015a\u015e\u0001\u0000"+
"\u0000\u0000\u015b\u015d\b\u000b\u0000\u0000\u015c\u015b\u0001\u0000\u0000"+
"\u0000\u015d\u0160\u0001\u0000\u0000\u0000\u015e\u015c\u0001\u0000\u0000"+
"\u0000\u015e\u015f\u0001\u0000\u0000\u0000\u015f\u0161\u0001\u0000\u0000"+
"\u0000\u0160\u015e\u0001\u0000\u0000\u0000\u0161\u0162\u00062\u0000\u0000"+
"\u0162f\u0001\u0000\u0000\u0000\u0163\u0164\u0005/\u0000\u0000\u0164\u0165"+
"\u0005*\u0000\u0000\u0165\u0169\u0001\u0000\u0000\u0000\u0166\u0168\t"+
"\u0000\u0000\u0000\u0167\u0166\u0001\u0000\u0000\u0000\u0168\u016b\u0001"+
"\u0000\u0000\u0000\u0169\u016a\u0001\u0000\u0000\u0000\u0169\u0167\u0001"+
"\u0000\u0000\u0000\u016a\u016c\u0001\u0000\u0000\u0000\u016b\u0169\u0001"+
"\u0000\u0000\u0000\u016c\u016d\u0005*\u0000\u0000\u016d\u016e\u0005/\u0000"+
"\u0000\u016e\u016f\u0001\u0000\u0000\u0000\u016f\u0170\u00063\u0000\u0000"+
"\u0170h\u0001\u0000\u0000\u0000\u0019\u0000\u00da\u00e9\u00f0\u00f8\u00fd"+
"\u0103\u010a\u010c\u0110\u0115\u0119\u011e\u0123\u012a\u012f\u0133\u0137"+
"\u013c\u0146\u014b\u014f\u0154\u015e\u0169\u0001\u0006\u0000\u0000";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {
_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
}
}
}

@ -0,0 +1,515 @@
// Generated from /root/sysy2026/nudt-compiler-cpp/src/antlr4/SysY.g4 by ANTLR 4.13.1
import org.antlr.v4.runtime.tree.ParseTreeListener;
/**
* This interface defines a complete listener for a parse tree produced by
* {@link SysYParser}.
*/
public interface SysYListener extends ParseTreeListener {
/**
* Enter a parse tree produced by {@link SysYParser#compUnit}.
* @param ctx the parse tree
*/
void enterCompUnit(SysYParser.CompUnitContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#compUnit}.
* @param ctx the parse tree
*/
void exitCompUnit(SysYParser.CompUnitContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#decl}.
* @param ctx the parse tree
*/
void enterDecl(SysYParser.DeclContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#decl}.
* @param ctx the parse tree
*/
void exitDecl(SysYParser.DeclContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#constDecl}.
* @param ctx the parse tree
*/
void enterConstDecl(SysYParser.ConstDeclContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#constDecl}.
* @param ctx the parse tree
*/
void exitConstDecl(SysYParser.ConstDeclContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#bType}.
* @param ctx the parse tree
*/
void enterBType(SysYParser.BTypeContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#bType}.
* @param ctx the parse tree
*/
void exitBType(SysYParser.BTypeContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#constDef}.
* @param ctx the parse tree
*/
void enterConstDef(SysYParser.ConstDefContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#constDef}.
* @param ctx the parse tree
*/
void exitConstDef(SysYParser.ConstDefContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#constInitVal}.
* @param ctx the parse tree
*/
void enterConstInitVal(SysYParser.ConstInitValContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#constInitVal}.
* @param ctx the parse tree
*/
void exitConstInitVal(SysYParser.ConstInitValContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#varDecl}.
* @param ctx the parse tree
*/
void enterVarDecl(SysYParser.VarDeclContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#varDecl}.
* @param ctx the parse tree
*/
void exitVarDecl(SysYParser.VarDeclContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#varDef}.
* @param ctx the parse tree
*/
void enterVarDef(SysYParser.VarDefContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#varDef}.
* @param ctx the parse tree
*/
void exitVarDef(SysYParser.VarDefContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#initVal}.
* @param ctx the parse tree
*/
void enterInitVal(SysYParser.InitValContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#initVal}.
* @param ctx the parse tree
*/
void exitInitVal(SysYParser.InitValContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#funcDef}.
* @param ctx the parse tree
*/
void enterFuncDef(SysYParser.FuncDefContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#funcDef}.
* @param ctx the parse tree
*/
void exitFuncDef(SysYParser.FuncDefContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#funcType}.
* @param ctx the parse tree
*/
void enterFuncType(SysYParser.FuncTypeContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#funcType}.
* @param ctx the parse tree
*/
void exitFuncType(SysYParser.FuncTypeContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#funcFParams}.
* @param ctx the parse tree
*/
void enterFuncFParams(SysYParser.FuncFParamsContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#funcFParams}.
* @param ctx the parse tree
*/
void exitFuncFParams(SysYParser.FuncFParamsContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#funcFParam}.
* @param ctx the parse tree
*/
void enterFuncFParam(SysYParser.FuncFParamContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#funcFParam}.
* @param ctx the parse tree
*/
void exitFuncFParam(SysYParser.FuncFParamContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#block}.
* @param ctx the parse tree
*/
void enterBlock(SysYParser.BlockContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#block}.
* @param ctx the parse tree
*/
void exitBlock(SysYParser.BlockContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#blockItem}.
* @param ctx the parse tree
*/
void enterBlockItem(SysYParser.BlockItemContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#blockItem}.
* @param ctx the parse tree
*/
void exitBlockItem(SysYParser.BlockItemContext ctx);
/**
* Enter a parse tree produced by the {@code assignStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void enterAssignStmt(SysYParser.AssignStmtContext ctx);
/**
* Exit a parse tree produced by the {@code assignStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void exitAssignStmt(SysYParser.AssignStmtContext ctx);
/**
* Enter a parse tree produced by the {@code expStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void enterExpStmt(SysYParser.ExpStmtContext ctx);
/**
* Exit a parse tree produced by the {@code expStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void exitExpStmt(SysYParser.ExpStmtContext ctx);
/**
* Enter a parse tree produced by the {@code blockStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void enterBlockStmt(SysYParser.BlockStmtContext ctx);
/**
* Exit a parse tree produced by the {@code blockStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void exitBlockStmt(SysYParser.BlockStmtContext ctx);
/**
* Enter a parse tree produced by the {@code ifStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void enterIfStmt(SysYParser.IfStmtContext ctx);
/**
* Exit a parse tree produced by the {@code ifStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void exitIfStmt(SysYParser.IfStmtContext ctx);
/**
* Enter a parse tree produced by the {@code whileStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void enterWhileStmt(SysYParser.WhileStmtContext ctx);
/**
* Exit a parse tree produced by the {@code whileStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void exitWhileStmt(SysYParser.WhileStmtContext ctx);
/**
* Enter a parse tree produced by the {@code breakStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void enterBreakStmt(SysYParser.BreakStmtContext ctx);
/**
* Exit a parse tree produced by the {@code breakStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void exitBreakStmt(SysYParser.BreakStmtContext ctx);
/**
* Enter a parse tree produced by the {@code continueStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void enterContinueStmt(SysYParser.ContinueStmtContext ctx);
/**
* Exit a parse tree produced by the {@code continueStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void exitContinueStmt(SysYParser.ContinueStmtContext ctx);
/**
* Enter a parse tree produced by the {@code returnStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void enterReturnStmt(SysYParser.ReturnStmtContext ctx);
/**
* Exit a parse tree produced by the {@code returnStmt}
* labeled alternative in {@link SysYParser#stmt}.
* @param ctx the parse tree
*/
void exitReturnStmt(SysYParser.ReturnStmtContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#exp}.
* @param ctx the parse tree
*/
void enterExp(SysYParser.ExpContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#exp}.
* @param ctx the parse tree
*/
void exitExp(SysYParser.ExpContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#cond}.
* @param ctx the parse tree
*/
void enterCond(SysYParser.CondContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#cond}.
* @param ctx the parse tree
*/
void exitCond(SysYParser.CondContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#lVal}.
* @param ctx the parse tree
*/
void enterLVal(SysYParser.LValContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#lVal}.
* @param ctx the parse tree
*/
void exitLVal(SysYParser.LValContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#primaryExp}.
* @param ctx the parse tree
*/
void enterPrimaryExp(SysYParser.PrimaryExpContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#primaryExp}.
* @param ctx the parse tree
*/
void exitPrimaryExp(SysYParser.PrimaryExpContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#number}.
* @param ctx the parse tree
*/
void enterNumber(SysYParser.NumberContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#number}.
* @param ctx the parse tree
*/
void exitNumber(SysYParser.NumberContext ctx);
/**
* Enter a parse tree produced by the {@code primaryUnaryExp}
* labeled alternative in {@link SysYParser#unaryExp}.
* @param ctx the parse tree
*/
void enterPrimaryUnaryExp(SysYParser.PrimaryUnaryExpContext ctx);
/**
* Exit a parse tree produced by the {@code primaryUnaryExp}
* labeled alternative in {@link SysYParser#unaryExp}.
* @param ctx the parse tree
*/
void exitPrimaryUnaryExp(SysYParser.PrimaryUnaryExpContext ctx);
/**
* Enter a parse tree produced by the {@code callUnaryExp}
* labeled alternative in {@link SysYParser#unaryExp}.
* @param ctx the parse tree
*/
void enterCallUnaryExp(SysYParser.CallUnaryExpContext ctx);
/**
* Exit a parse tree produced by the {@code callUnaryExp}
* labeled alternative in {@link SysYParser#unaryExp}.
* @param ctx the parse tree
*/
void exitCallUnaryExp(SysYParser.CallUnaryExpContext ctx);
/**
* Enter a parse tree produced by the {@code opUnaryExp}
* labeled alternative in {@link SysYParser#unaryExp}.
* @param ctx the parse tree
*/
void enterOpUnaryExp(SysYParser.OpUnaryExpContext ctx);
/**
* Exit a parse tree produced by the {@code opUnaryExp}
* labeled alternative in {@link SysYParser#unaryExp}.
* @param ctx the parse tree
*/
void exitOpUnaryExp(SysYParser.OpUnaryExpContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#unaryOp}.
* @param ctx the parse tree
*/
void enterUnaryOp(SysYParser.UnaryOpContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#unaryOp}.
* @param ctx the parse tree
*/
void exitUnaryOp(SysYParser.UnaryOpContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#funcRParams}.
* @param ctx the parse tree
*/
void enterFuncRParams(SysYParser.FuncRParamsContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#funcRParams}.
* @param ctx the parse tree
*/
void exitFuncRParams(SysYParser.FuncRParamsContext ctx);
/**
* Enter a parse tree produced by the {@code binaryMulExp}
* labeled alternative in {@link SysYParser#mulExp}.
* @param ctx the parse tree
*/
void enterBinaryMulExp(SysYParser.BinaryMulExpContext ctx);
/**
* Exit a parse tree produced by the {@code binaryMulExp}
* labeled alternative in {@link SysYParser#mulExp}.
* @param ctx the parse tree
*/
void exitBinaryMulExp(SysYParser.BinaryMulExpContext ctx);
/**
* Enter a parse tree produced by the {@code unaryMulExp}
* labeled alternative in {@link SysYParser#mulExp}.
* @param ctx the parse tree
*/
void enterUnaryMulExp(SysYParser.UnaryMulExpContext ctx);
/**
* Exit a parse tree produced by the {@code unaryMulExp}
* labeled alternative in {@link SysYParser#mulExp}.
* @param ctx the parse tree
*/
void exitUnaryMulExp(SysYParser.UnaryMulExpContext ctx);
/**
* Enter a parse tree produced by the {@code binaryAddExp}
* labeled alternative in {@link SysYParser#addExp}.
* @param ctx the parse tree
*/
void enterBinaryAddExp(SysYParser.BinaryAddExpContext ctx);
/**
* Exit a parse tree produced by the {@code binaryAddExp}
* labeled alternative in {@link SysYParser#addExp}.
* @param ctx the parse tree
*/
void exitBinaryAddExp(SysYParser.BinaryAddExpContext ctx);
/**
* Enter a parse tree produced by the {@code mulAddExp}
* labeled alternative in {@link SysYParser#addExp}.
* @param ctx the parse tree
*/
void enterMulAddExp(SysYParser.MulAddExpContext ctx);
/**
* Exit a parse tree produced by the {@code mulAddExp}
* labeled alternative in {@link SysYParser#addExp}.
* @param ctx the parse tree
*/
void exitMulAddExp(SysYParser.MulAddExpContext ctx);
/**
* Enter a parse tree produced by the {@code addRelExp}
* labeled alternative in {@link SysYParser#relExp}.
* @param ctx the parse tree
*/
void enterAddRelExp(SysYParser.AddRelExpContext ctx);
/**
* Exit a parse tree produced by the {@code addRelExp}
* labeled alternative in {@link SysYParser#relExp}.
* @param ctx the parse tree
*/
void exitAddRelExp(SysYParser.AddRelExpContext ctx);
/**
* Enter a parse tree produced by the {@code binaryRelExp}
* labeled alternative in {@link SysYParser#relExp}.
* @param ctx the parse tree
*/
void enterBinaryRelExp(SysYParser.BinaryRelExpContext ctx);
/**
* Exit a parse tree produced by the {@code binaryRelExp}
* labeled alternative in {@link SysYParser#relExp}.
* @param ctx the parse tree
*/
void exitBinaryRelExp(SysYParser.BinaryRelExpContext ctx);
/**
* Enter a parse tree produced by the {@code binaryEqExp}
* labeled alternative in {@link SysYParser#eqExp}.
* @param ctx the parse tree
*/
void enterBinaryEqExp(SysYParser.BinaryEqExpContext ctx);
/**
* Exit a parse tree produced by the {@code binaryEqExp}
* labeled alternative in {@link SysYParser#eqExp}.
* @param ctx the parse tree
*/
void exitBinaryEqExp(SysYParser.BinaryEqExpContext ctx);
/**
* Enter a parse tree produced by the {@code relEqExp}
* labeled alternative in {@link SysYParser#eqExp}.
* @param ctx the parse tree
*/
void enterRelEqExp(SysYParser.RelEqExpContext ctx);
/**
* Exit a parse tree produced by the {@code relEqExp}
* labeled alternative in {@link SysYParser#eqExp}.
* @param ctx the parse tree
*/
void exitRelEqExp(SysYParser.RelEqExpContext ctx);
/**
* Enter a parse tree produced by the {@code eqLAndExp}
* labeled alternative in {@link SysYParser#lAndExp}.
* @param ctx the parse tree
*/
void enterEqLAndExp(SysYParser.EqLAndExpContext ctx);
/**
* Exit a parse tree produced by the {@code eqLAndExp}
* labeled alternative in {@link SysYParser#lAndExp}.
* @param ctx the parse tree
*/
void exitEqLAndExp(SysYParser.EqLAndExpContext ctx);
/**
* Enter a parse tree produced by the {@code binaryLAndExp}
* labeled alternative in {@link SysYParser#lAndExp}.
* @param ctx the parse tree
*/
void enterBinaryLAndExp(SysYParser.BinaryLAndExpContext ctx);
/**
* Exit a parse tree produced by the {@code binaryLAndExp}
* labeled alternative in {@link SysYParser#lAndExp}.
* @param ctx the parse tree
*/
void exitBinaryLAndExp(SysYParser.BinaryLAndExpContext ctx);
/**
* Enter a parse tree produced by the {@code andLOrExp}
* labeled alternative in {@link SysYParser#lOrExp}.
* @param ctx the parse tree
*/
void enterAndLOrExp(SysYParser.AndLOrExpContext ctx);
/**
* Exit a parse tree produced by the {@code andLOrExp}
* labeled alternative in {@link SysYParser#lOrExp}.
* @param ctx the parse tree
*/
void exitAndLOrExp(SysYParser.AndLOrExpContext ctx);
/**
* Enter a parse tree produced by the {@code binaryLOrExp}
* labeled alternative in {@link SysYParser#lOrExp}.
* @param ctx the parse tree
*/
void enterBinaryLOrExp(SysYParser.BinaryLOrExpContext ctx);
/**
* Exit a parse tree produced by the {@code binaryLOrExp}
* labeled alternative in {@link SysYParser#lOrExp}.
* @param ctx the parse tree
*/
void exitBinaryLOrExp(SysYParser.BinaryLOrExpContext ctx);
/**
* Enter a parse tree produced by {@link SysYParser#constExp}.
* @param ctx the parse tree
*/
void enterConstExp(SysYParser.ConstExpContext ctx);
/**
* Exit a parse tree produced by {@link SysYParser#constExp}.
* @param ctx the parse tree
*/
void exitConstExp(SysYParser.ConstExpContext ctx);
}

File diff suppressed because it is too large Load Diff

@ -1,98 +1,178 @@
// SysY 子集语法:支持形如
// int main() { int a = 1; int b = 2; return a + b; }
// 的最小返回表达式编译。
grammar SysY;
// 后续需要自行添加
////Grammer
grammar SysY;
module: compUnit EOF;
compUnit: (decl | funcDef)+;
decl: constDecl | varDecl;
constDecl: CONST bType constDef (COMMA constDef)* SEMI;
bType: INT | FLOAT;
constDef: Ident (LBRACK constExp RBRACK)* ASSIGN constInitVal;
constInitVal:
constExp
| LBRACE (constInitVal (COMMA constInitVal)*)? RBRACE;
varDecl: bType varDef (COMMA varDef)* SEMI;
varDef:
Ident (LBRACK constExp RBRACK)*
| Ident (LBRACK constExp RBRACK)* ASSIGN initVal;
initVal: exp | LBRACE (initVal (COMMA initVal)*)? RBRACE;
funcDef: funcType Ident LPAREN funcFParams? RPAREN block;
funcType: VOID | INT | FLOAT;
funcFParams: funcFParam (COMMA funcFParam)*;
funcFParam:
bType Ident
| bType Ident LBRACK RBRACK (LBRACK exp RBRACK)*;
block: LBRACE blockItem* RBRACE;
blockItem: decl | stmt;
stmt:
lVal ASSIGN exp SEMI
| exp? SEMI
| block
| IF LPAREN cond RPAREN stmt (ELSE stmt)?
| WHILE LPAREN cond RPAREN stmt
| BREAK SEMI
| CONTINUE SEMI
| RETURN exp? SEMI;
/*===-------------------------------------------===*/
/* Lexer rules */
/*===-------------------------------------------===*/
exp: addExp;
cond: lOrExp;
lVal: Ident (LBRACK exp RBRACK)*;
primaryExp: LPAREN exp RPAREN | lVal | number;
number: IntConst | FloatConst;
unaryExp:
primaryExp
| Ident LPAREN funcRParams? RPAREN
| unaryOp unaryExp;
unaryOp: ADD | SUB | NOT;
funcRParams: exp (COMMA exp)*;
mulExp:
unaryExp
| mulExp op = (MUL | DIV | MOD) unaryExp;
addExp:
mulExp
| addExp op = (ADD | SUB) mulExp;
relExp:
addExp
| relExp op = (LT | GT | LE | GE) addExp;
eqExp:
relExp
| eqExp op = (EQ | NE) relExp;
lAndExp: eqExp | lAndExp AND eqExp ;
lOrExp: lAndExp | lOrExp OR lAndExp ;
constExp: addExp;
////Lexer
//keywords
CONST: 'const';
INT: 'int';
FLOAT: 'float';
VOID: 'void';
IF: 'if';
ELSE: 'else';
WHILE: 'while';
BREAK: 'break';
CONTINUE: 'continue';
RETURN: 'return';
ASSIGN: '=';
//operators
ADD: '+';
SUB: '-';
MUL: '*';
DIV: '/';
MOD: '%';
ASSIGN: '=';
EQ: '==';
NE: '!=';
LT: '<';
LE: '<=';
GT: '>';
GE: '>=';
NOT: '!';
AND: '&&';
OR: '||';
//括号
LPAREN: '(';
RPAREN: ')';
LBRACK: '[';
RBRACK: ']';
LBRACE: '{';
RBRACE: '}';
SEMICOLON: ';';
ID: [a-zA-Z_][a-zA-Z_0-9]*;
ILITERAL: [0-9]+;
WS: [ \t\r\n] -> skip;
LINECOMMENT: '//' ~[\r\n]* -> skip;
BLOCKCOMMENT: '/*' .*? '*/' -> skip;
/*===-------------------------------------------===*/
/* Syntax rules */
/*===-------------------------------------------===*/
compUnit
: funcDef EOF
;
decl
: btype varDef SEMICOLON
;
btype
: INT
;
varDef
: lValue (ASSIGN initValue)?
;
initValue
: exp
;
funcDef
: funcType ID LPAREN RPAREN blockStmt
;
funcType
: INT
;
blockStmt
: LBRACE blockItem* RBRACE
;
blockItem
: decl
| stmt
;
stmt
: returnStmt
;
returnStmt
: RETURN exp SEMICOLON
;
exp
: LPAREN exp RPAREN # parenExp
| var # varExp
| number # numberExp
| exp ADD exp # additiveExp
;
var
: ID
;
lValue
: ID
;
number
: ILITERAL
;
COMMA: ',';
SEMI: ';';
//标识符
Ident: [a-zA-Z_] [a-zA-Z_0-9]*;
//数字常量片段
// 十进制数字
fragment Digit: [0-9];
// 非零十进制数字
fragment NonzeroDigit: [1-9];
// 八进制数字
fragment OctDigit: [0-7];
// 十六进制数字
fragment HexDigit: [0-9a-fA-F];
// 十进制整数:非零开头,后接若干十进制数字
fragment DecInteger: NonzeroDigit Digit*;
// 八进制整数:以 0 开头
fragment OctInteger: '0' OctDigit*;
// 十六进制整数:以 0x 或 0X 开头
fragment HexInteger: '0' [xX] HexDigit+;
// 十进制小数部分
fragment DecFraction: Digit+ '.' Digit* | '.' Digit+;
// 十进制指数部分
fragment DecExponent: [eE] [+\-]? Digit+;
// 十进制浮点数
fragment DecFloat:
DecFraction DecExponent?
| DecInteger DecExponent;
// 十六进制小数部分
fragment HexFraction: HexDigit* '.' HexDigit+ | HexDigit+ '.';
// 十六进制浮点数的二进制指数部分
fragment BinExponent: [pP] [+\-]? Digit+;
// 十六进制浮点数
fragment HexFloat:
'0' [xX] HexFraction BinExponent
| HexInteger BinExponent;
//整型常量
IntConst: DecInteger | OctInteger | HexInteger;
//浮点常量
FloatConst: DecFloat | HexFloat;
//空白符规则
WS: [ \t\r\n]+ -> skip;
// 单行注释
LINE_COMMENT: '//' ~[\r\n]* -> skip;
// 跨行注释
BLOCK_COMMENT: '/*' .*? '*/' -> skip;

@ -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;
}

File diff suppressed because it is too large Load Diff

@ -2,16 +2,54 @@
#include "sem/SymbolTable.h"
void SymbolTable::Add(const std::string& name,
SysYParser::VarDefContext* decl) {
table_[name] = decl;
#include <stdexcept>
SymbolTable::SymbolTable() { EnterScope(); }
void SymbolTable::EnterScope() { scopes_.emplace_back(); }
void SymbolTable::ExitScope() {
if (scopes_.size() <= 1) {
throw std::runtime_error("symbol table scope underflow");
}
scopes_.pop_back();
}
bool SymbolTable::Insert(const SymbolEntry* symbol) {
if (!symbol) {
return false;
}
if (scopes_.empty()) {
EnterScope();
}
auto& current = scopes_.back();
auto [it, inserted] = current.emplace(symbol->name, symbol);
return inserted;
}
bool SymbolTable::Contains(const std::string& name) const {
return table_.find(name) != table_.end();
return Lookup(name) != nullptr;
}
bool SymbolTable::ContainsCurrentScope(const std::string& name) const {
return LookupCurrentScope(name) != nullptr;
}
const SymbolEntry* SymbolTable::Lookup(const std::string& name) const {
for (auto it = scopes_.rbegin(); it != scopes_.rend(); ++it) {
auto symbol_it = it->find(name);
if (symbol_it != it->end()) {
return symbol_it->second;
}
}
return nullptr;
}
SysYParser::VarDefContext* SymbolTable::Lookup(const std::string& name) const {
auto it = table_.find(name);
return it == table_.end() ? nullptr : it->second;
const SymbolEntry* SymbolTable::LookupCurrentScope(
const std::string& name) const {
if (scopes_.empty()) {
return nullptr;
}
auto it = scopes_.back().find(name);
return it == scopes_.back().end() ? nullptr : it->second;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save