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.
116 lines
3.7 KiB
116 lines
3.7 KiB
//===- RpnEvaluator.cpp ---------------------------------------------------===//
|
|
//
|
|
// The MCLinker Project
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "mcld/Script/RpnEvaluator.h"
|
|
|
|
#include "mcld/LD/LDSymbol.h"
|
|
#include "mcld/Script/ExprToken.h"
|
|
#include "mcld/Script/Operand.h"
|
|
#include "mcld/Script/Operator.h"
|
|
#include "mcld/Script/RpnExpr.h"
|
|
#include "mcld/Support/MsgHandling.h"
|
|
#include "mcld/Module.h"
|
|
|
|
#include <llvm/Support/Casting.h>
|
|
#include <llvm/Support/DataTypes.h>
|
|
|
|
#include <stack>
|
|
|
|
#include <cassert>
|
|
|
|
namespace mcld {
|
|
|
|
RpnEvaluator::RpnEvaluator(const Module& pModule,
|
|
const TargetLDBackend& pBackend)
|
|
: m_Module(pModule), m_Backend(pBackend) {
|
|
}
|
|
|
|
bool RpnEvaluator::eval(const RpnExpr& pExpr, uint64_t& pResult) {
|
|
std::stack<Operand*> operandStack;
|
|
for (RpnExpr::const_iterator it = pExpr.begin(), ie = pExpr.end(); it != ie;
|
|
++it) {
|
|
switch ((*it)->kind()) {
|
|
case ExprToken::OPERATOR: {
|
|
Operator* op = llvm::cast<Operator>(*it);
|
|
switch (op->arity()) {
|
|
case Operator::NULLARY: {
|
|
operandStack.push(op->eval(m_Module, m_Backend));
|
|
break;
|
|
}
|
|
case Operator::UNARY: {
|
|
Operand* opd = operandStack.top();
|
|
operandStack.pop();
|
|
op->appendOperand(opd);
|
|
operandStack.push(op->eval(m_Module, m_Backend));
|
|
break;
|
|
}
|
|
case Operator::BINARY: {
|
|
Operand* opd2 = operandStack.top();
|
|
operandStack.pop();
|
|
Operand* opd1 = operandStack.top();
|
|
operandStack.pop();
|
|
op->appendOperand(opd1);
|
|
op->appendOperand(opd2);
|
|
operandStack.push(op->eval(m_Module, m_Backend));
|
|
break;
|
|
}
|
|
case Operator::TERNARY: {
|
|
Operand* opd3 = operandStack.top();
|
|
operandStack.pop();
|
|
Operand* opd2 = operandStack.top();
|
|
operandStack.pop();
|
|
Operand* opd1 = operandStack.top();
|
|
operandStack.pop();
|
|
op->appendOperand(opd1);
|
|
op->appendOperand(opd2);
|
|
op->appendOperand(opd3);
|
|
operandStack.push(op->eval(m_Module, m_Backend));
|
|
break;
|
|
}
|
|
} // end of switch operator arity
|
|
break;
|
|
}
|
|
|
|
case ExprToken::OPERAND: {
|
|
Operand* opd = llvm::cast<Operand>(*it);
|
|
switch (opd->type()) {
|
|
case Operand::SYMBOL: {
|
|
// It's possible that there are no operators in an expression, so
|
|
// we set up symbol operand here.
|
|
if (!opd->isDot()) {
|
|
SymOperand* sym_opd = llvm::cast<SymOperand>(opd);
|
|
const LDSymbol* symbol =
|
|
m_Module.getNamePool().findSymbol(sym_opd->name());
|
|
if (symbol == NULL) {
|
|
fatal(diag::fail_sym_resolution) << __FILE__ << __LINE__
|
|
<< "mclinker@googlegroups.com";
|
|
}
|
|
sym_opd->setValue(symbol->value());
|
|
}
|
|
operandStack.push(opd);
|
|
break;
|
|
}
|
|
default:
|
|
operandStack.push(opd);
|
|
break;
|
|
} // end of switch operand type
|
|
break;
|
|
}
|
|
} // end of switch
|
|
} // end of for
|
|
|
|
// stack top is result
|
|
assert(operandStack.top()->type() == Operand::SYMBOL ||
|
|
operandStack.top()->type() == Operand::INTEGER ||
|
|
operandStack.top()->type() == Operand::FRAGMENT);
|
|
pResult = operandStack.top()->value();
|
|
return true;
|
|
}
|
|
|
|
} // namespace mcld
|