C++程序  |  115行  |  3.44 KB

//===- RpnEvaluator.cpp ---------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/Support/MsgHandling.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/Script/RpnExpr.h>
#include <mcld/Script/RpnEvaluator.h>
#include <mcld/Script/ExprToken.h>
#include <mcld/Script/Operator.h>
#include <mcld/Script/Operand.h>
#include <mcld/Module.h>
#include <llvm/Support/Casting.h>
#include <llvm/Support/DataTypes.h>
#include <stack>
#include <cassert>

using 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;
}