207 lines
5.1 KiB
C++
207 lines
5.1 KiB
C++
#include "triton/lang/evaluator.h"
|
|
#include "triton/lang/ast.h"
|
|
#include "triton/lang/token.h"
|
|
|
|
|
|
template<typename T>
|
|
void Evaluator<T>::VisitBinaryOp(BinaryOp* binary) {
|
|
#define L Evaluator<T>().Eval(binary->lhs_)
|
|
#define R Evaluator<T>().Eval(binary->rhs_)
|
|
#define LL Evaluator<long>().Eval(binary->lhs_)
|
|
#define LR Evaluator<long>().Eval(binary->rhs_)
|
|
|
|
if (binary->Type()->ToPointer()) {
|
|
auto val = Evaluator<Addr>().Eval(binary);
|
|
if (val.label_.size()) {
|
|
Error(binary, "expect constant integer expression");
|
|
}
|
|
val_ = static_cast<T>(val.offset_);
|
|
return;
|
|
}
|
|
|
|
switch (binary->op_) {
|
|
case '+': val_ = L + R; break;
|
|
case '-': val_ = L - R; break;
|
|
case '*': val_ = L * R; break;
|
|
case '/': {
|
|
auto l = L, r = R;
|
|
if (r == 0)
|
|
Error(binary, "division by zero");
|
|
val_ = l / r;
|
|
} break;
|
|
case '%': {
|
|
auto l = LL, r = LR;
|
|
if (r == 0)
|
|
Error(binary, "division by zero");
|
|
val_ = l % r;
|
|
} break;
|
|
// Bitwise operators that do not accept float
|
|
case '|': val_ = LL | LR; break;
|
|
case '&': val_ = LL & LR; break;
|
|
case '^': val_ = LL ^ LR; break;
|
|
case Token::LEFT: val_ = LL << LR; break;
|
|
case Token::RIGHT: val_ = LL >> LR; break;
|
|
|
|
case '<': val_ = L < R; break;
|
|
case '>': val_ = L > R; break;
|
|
case Token::LOGICAL_AND: val_ = L && R; break;
|
|
case Token::LOGICAL_OR: val_ = L || R; break;
|
|
case Token::EQ: val_ = L == R; break;
|
|
case Token::NE: val_ = L != R; break;
|
|
case Token::LE: val_ = L <= R; break;
|
|
case Token::GE: val_ = L >= R; break;
|
|
case '=': case ',': val_ = R; break;
|
|
case '.': {
|
|
auto addr = Evaluator<Addr>().Eval(binary);
|
|
if (addr.label_.size())
|
|
Error(binary, "expect constant expression");
|
|
val_ = addr.offset_;
|
|
}
|
|
default: assert(false);
|
|
}
|
|
|
|
#undef L
|
|
#undef R
|
|
#undef LL
|
|
#undef LR
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
void Evaluator<T>::VisitUnaryOp(UnaryOp* unary) {
|
|
#define VAL Evaluator<T>().Eval(unary->operand_)
|
|
#define LVAL Evaluator<long>().Eval(unary->operand_)
|
|
|
|
switch (unary->op_) {
|
|
case Token::PLUS: val_ = VAL; break;
|
|
case Token::MINUS: val_ = -VAL; break;
|
|
case '~': val_ = ~LVAL; break;
|
|
case '!': val_ = !VAL; break;
|
|
case Token::CAST:
|
|
if (unary->Type()->IsInteger())
|
|
val_ = static_cast<long>(VAL);
|
|
else
|
|
val_ = VAL;
|
|
break;
|
|
case Token::ADDR: {
|
|
auto addr = Evaluator<Addr>().Eval(unary->operand_);
|
|
if (addr.label_.size())
|
|
Error(unary, "expect constant expression");
|
|
val_ = addr.offset_;
|
|
} break;
|
|
default: Error(unary, "expect constant expression");
|
|
}
|
|
|
|
#undef LVAL
|
|
#undef VAL
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
void Evaluator<T>::VisitConditionalOp(ConditionalOp* condOp) {
|
|
bool cond;
|
|
auto condType = condOp->cond_->Type();
|
|
if (condType->IsInteger()) {
|
|
auto val = Evaluator<long>().Eval(condOp->cond_);
|
|
cond = val != 0;
|
|
} else if (condType->IsFloat()) {
|
|
auto val = Evaluator<double>().Eval(condOp->cond_);
|
|
cond = val != 0.0;
|
|
} else if (condType->ToPointer()) {
|
|
auto val = Evaluator<Addr>().Eval(condOp->cond_);
|
|
cond = val.label_.size() || val.offset_;
|
|
} else {
|
|
assert(false);
|
|
}
|
|
|
|
if (cond) {
|
|
val_ = Evaluator<T>().Eval(condOp->exprTrue_);
|
|
} else {
|
|
val_ = Evaluator<T>().Eval(condOp->exprFalse_);
|
|
}
|
|
}
|
|
|
|
|
|
void Evaluator<Addr>::VisitBinaryOp(BinaryOp* binary) {
|
|
#define LR Evaluator<long>().Eval(binary->rhs_)
|
|
#define R Evaluator<Addr>().Eval(binary->rhs_)
|
|
|
|
auto l = Evaluator<Addr>().Eval(binary->lhs_);
|
|
|
|
int width = 1;
|
|
auto pointerType = binary->Type()->ToPointer();
|
|
if (pointerType)
|
|
width = pointerType->Derived()->Width();
|
|
|
|
switch (binary->op_) {
|
|
case '+':
|
|
assert(pointerType);
|
|
addr_.label_ = l.label_;
|
|
addr_.offset_ = l.offset_ + LR * width;
|
|
break;
|
|
case '-':
|
|
assert(pointerType);
|
|
addr_.label_ = l.label_;
|
|
addr_.offset_ = l.offset_ + LR * width;
|
|
break;
|
|
case '.': {
|
|
addr_.label_ = l.label_;
|
|
auto type = binary->lhs_->Type()->ToStruct();
|
|
auto offset = type->GetMember(binary->rhs_->tok_->str_)->Offset();
|
|
addr_.offset_ = l.offset_ + offset;
|
|
break;
|
|
}
|
|
default: assert(false);
|
|
}
|
|
#undef LR
|
|
#undef R
|
|
}
|
|
|
|
|
|
void Evaluator<Addr>::VisitUnaryOp(UnaryOp* unary) {
|
|
auto addr = Evaluator<Addr>().Eval(unary->operand_);
|
|
|
|
switch (unary->op_) {
|
|
case Token::CAST:
|
|
case Token::ADDR:
|
|
case Token::DEREF:
|
|
addr_ = addr; break;
|
|
default: assert(false);
|
|
}
|
|
}
|
|
|
|
|
|
void Evaluator<Addr>::VisitConditionalOp(ConditionalOp* condOp) {
|
|
bool cond;
|
|
auto condType = condOp->cond_->Type();
|
|
if (condType->IsInteger()) {
|
|
auto val = Evaluator<long>().Eval(condOp->cond_);
|
|
cond = val != 0;
|
|
} else if (condType->IsFloat()) {
|
|
auto val = Evaluator<double>().Eval(condOp->cond_);
|
|
cond = val != 0.0;
|
|
} else if (condType->ToPointer()) {
|
|
auto val = Evaluator<Addr>().Eval(condOp->cond_);
|
|
cond = val.label_.size() || val.offset_;
|
|
} else {
|
|
assert(false);
|
|
}
|
|
|
|
if (cond) {
|
|
addr_ = Evaluator<Addr>().Eval(condOp->exprTrue_);
|
|
} else {
|
|
addr_ = Evaluator<Addr>().Eval(condOp->exprFalse_);
|
|
}
|
|
}
|
|
|
|
|
|
void Evaluator<Addr>::VisitConstant(Constant* cons) {
|
|
if (cons->Type()->IsInteger()) {
|
|
addr_ = {"", static_cast<int>(cons->IVal())};
|
|
} else if (cons->Type()->ToArray()) {
|
|
assert(false);
|
|
} else {
|
|
assert(false);
|
|
}
|
|
}
|