1//===- RpnEvaluator.cpp ---------------------------------------------------===//
2//
3//                     The MCLinker Project
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include <mcld/Support/MsgHandling.h>
10#include <mcld/LD/LDSymbol.h>
11#include <mcld/Script/RpnExpr.h>
12#include <mcld/Script/RpnEvaluator.h>
13#include <mcld/Script/ExprToken.h>
14#include <mcld/Script/Operator.h>
15#include <mcld/Script/Operand.h>
16#include <mcld/Module.h>
17#include <llvm/Support/Casting.h>
18#include <llvm/Support/DataTypes.h>
19#include <stack>
20#include <cassert>
21
22using namespace mcld;
23
24RpnEvaluator::RpnEvaluator(const Module& pModule,
25                           const TargetLDBackend& pBackend)
26  : m_Module(pModule),
27    m_Backend(pBackend)
28{
29}
30
31bool RpnEvaluator::eval(const RpnExpr& pExpr, uint64_t& pResult)
32{
33  std::stack<Operand*> operandStack;
34  for (RpnExpr::const_iterator it = pExpr.begin(), ie = pExpr.end(); it != ie;
35    ++it) {
36    switch((*it)->kind()) {
37    case ExprToken::OPERATOR: {
38      Operator* op = llvm::cast<Operator>(*it);
39      switch (op->arity()) {
40      case Operator::NULLARY: {
41        operandStack.push(op->eval(m_Module, m_Backend));
42        break;
43      }
44      case Operator::UNARY: {
45        Operand* opd = operandStack.top();
46        operandStack.pop();
47        op->appendOperand(opd);
48        operandStack.push(op->eval(m_Module, m_Backend));
49        break;
50      }
51      case Operator::BINARY: {
52        Operand* opd2 = operandStack.top();
53        operandStack.pop();
54        Operand* opd1 = operandStack.top();
55        operandStack.pop();
56        op->appendOperand(opd1);
57        op->appendOperand(opd2);
58        operandStack.push(op->eval(m_Module, m_Backend));
59        break;
60      }
61      case Operator::TERNARY: {
62        Operand* opd3 = operandStack.top();
63        operandStack.pop();
64        Operand* opd2 = operandStack.top();
65        operandStack.pop();
66        Operand* opd1 = operandStack.top();
67        operandStack.pop();
68        op->appendOperand(opd1);
69        op->appendOperand(opd2);
70        op->appendOperand(opd3);
71        operandStack.push(op->eval(m_Module, m_Backend));
72        break;
73      }
74      } // end of switch operator arity
75      break;
76    }
77
78    case ExprToken::OPERAND: {
79      Operand* opd = llvm::cast<Operand>(*it);
80      switch (opd->type()) {
81      case Operand::SYMBOL: {
82        // It's possible that there are no operators in an expression, so
83        // we set up symbol operand here.
84        if (!opd->isDot()) {
85          SymOperand* sym_opd = llvm::cast<SymOperand>(opd);
86          const LDSymbol* symbol =
87            m_Module.getNamePool().findSymbol(sym_opd->name());
88          if (symbol == NULL) {
89            fatal(diag::fail_sym_resolution) << __FILE__ << __LINE__
90                                             << "mclinker@googlegroups.com";
91          }
92          sym_opd->setValue(symbol->value());
93        }
94        operandStack.push(opd);
95        break;
96      }
97      default:
98        operandStack.push(opd);
99        break;
100      } // end of switch operand type
101      break;
102    }
103
104    } // end of switch
105  } // end of for
106
107  // stack top is result
108  assert(operandStack.top()->type() == Operand::SYMBOL ||
109         operandStack.top()->type() == Operand::INTEGER ||
110         operandStack.top()->type() == Operand::FRAGMENT);
111  pResult = operandStack.top()->value();
112  return true;
113}
114
115