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