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
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_));
|
|
}
|