You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
5.4 KiB

#include "irgen/IRGen.h"
#include <cmath>
#include <cstdlib>
#include <stdexcept>
#include <string>
#include "SysYParser.h"
#include "utils/Log.h"
// 内部辅助:不依赖类成员,只需 ConstEnv。
namespace {
double EvalAddExp(SysYParser::AddExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env);
double EvalMulExp(SysYParser::MulExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env);
double EvalUnaryExp(SysYParser::UnaryExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env);
int ParseIntLiteral(const std::string& text) {
if (text.size() >= 2 && text[0] == '0' &&
(text[1] == 'x' || text[1] == 'X')) {
return std::stoi(text, nullptr, 16);
}
if (text.size() > 1 && text[0] == '0') {
return std::stoi(text, nullptr, 8);
}
return std::stoi(text);
}
double EvalPrimary(SysYParser::PrimaryExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env) {
if (!ctx) throw std::runtime_error(FormatError("consteval", "空主表达式"));
if (ctx->number()) {
if (ctx->number()->ILITERAL()) {
return static_cast<double>(ParseIntLiteral(ctx->number()->getText()));
}
if (ctx->number()->FLITERAL()) {
return static_cast<double>(std::strtof(ctx->number()->getText().c_str(), nullptr));
}
throw std::runtime_error(FormatError("consteval", "非法数字字面量"));
}
if (ctx->exp()) return EvalAddExp(ctx->exp()->addExp(), int_env, float_env);
if (ctx->lValue()) {
if (!ctx->lValue()->ID())
throw std::runtime_error(FormatError("consteval", "非法 lValue"));
const std::string name = ctx->lValue()->ID()->getText();
auto it_int = int_env.find(name);
if (it_int != int_env.end()) return static_cast<double>(it_int->second);
auto it_float = float_env.find(name);
if (it_float != float_env.end()) return static_cast<double>(it_float->second);
throw std::runtime_error(
FormatError("consteval", "constExp 引用非 const 变量: " + name));
}
throw std::runtime_error(FormatError("consteval", "不支持的主表达式形式"));
}
double EvalUnaryExp(SysYParser::UnaryExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env) {
if (!ctx) throw std::runtime_error(FormatError("consteval", "空一元表达式"));
if (ctx->primaryExp()) return EvalPrimary(ctx->primaryExp(), int_env, float_env);
if (ctx->unaryOp() && ctx->unaryExp()) {
double v = EvalUnaryExp(ctx->unaryExp(), int_env, float_env);
if (ctx->unaryOp()->SUB()) return -v;
if (ctx->unaryOp()->ADD()) return v;
if (ctx->unaryOp()->NOT()) return (v == 0.0) ? 1.0 : 0.0;
}
throw std::runtime_error(
FormatError("consteval", "函数调用不能出现在 constExp 中"));
}
double EvalMulExp(SysYParser::MulExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env) {
if (!ctx) throw std::runtime_error(FormatError("consteval", "空乘法表达式"));
if (ctx->mulExp()) {
double lhs = EvalMulExp(ctx->mulExp(), int_env, float_env);
double rhs = EvalUnaryExp(ctx->unaryExp(), int_env, float_env);
if (ctx->MUL()) return lhs * rhs;
if (ctx->DIV()) {
if (rhs == 0.0) throw std::runtime_error("除以零");
return lhs / rhs;
}
if (ctx->MOD()) {
if (rhs == 0.0) throw std::runtime_error("模零");
return std::fmod(lhs, rhs);
}
throw std::runtime_error(FormatError("consteval", "未知乘法运算符"));
}
return EvalUnaryExp(ctx->unaryExp(), int_env, float_env);
}
double EvalAddExp(SysYParser::AddExpContext* ctx,
const IRGenImpl::ConstEnv& int_env,
const IRGenImpl::ConstFloatEnv& float_env) {
if (!ctx) throw std::runtime_error(FormatError("consteval", "空加法表达式"));
if (ctx->addExp()) {
double lhs = EvalAddExp(ctx->addExp(), int_env, float_env);
double rhs = EvalMulExp(ctx->mulExp(), int_env, float_env);
if (ctx->ADD()) return lhs + rhs;
if (ctx->SUB()) return lhs - rhs;
throw std::runtime_error(FormatError("consteval", "未知加法运算符"));
}
return EvalMulExp(ctx->mulExp(), int_env, float_env);
}
} // namespace
int IRGenImpl::EvalConstExpr(SysYParser::ConstExpContext* ctx) const {
if (!ctx || !ctx->addExp())
throw std::runtime_error(FormatError("consteval", "空 constExp"));
return static_cast<int>(EvalAddExp(ctx->addExp(), const_env_, const_float_env_));
}
float IRGenImpl::EvalConstExprAsFloat(SysYParser::ConstExpContext* ctx) const {
if (!ctx || !ctx->addExp())
throw std::runtime_error(FormatError("consteval", "空 constExp"));
return static_cast<float>(EvalAddExp(ctx->addExp(), const_env_, const_float_env_));
}
int IRGenImpl::EvalExpAsConst(SysYParser::ExpContext* ctx) const {
if (!ctx || !ctx->addExp())
throw std::runtime_error(FormatError("consteval", "空 exp"));
return static_cast<int>(EvalAddExp(ctx->addExp(), const_env_, const_float_env_));
}
float IRGenImpl::EvalExpAsConstFloat(SysYParser::ExpContext* ctx) const {
if (!ctx || !ctx->addExp())
throw std::runtime_error(FormatError("consteval", "空 exp"));
return static_cast<float>(EvalAddExp(ctx->addExp(), const_env_, const_float_env_));
}