| //===- 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__ |
| << "[email protected]"; |
| } |
| 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 |