189e07bf2c75e3a91abddde3219e1108c75059985jimblandy// -*- mode: c++ -*-
289e07bf2c75e3a91abddde3219e1108c75059985jimblandy
383e085b7a331c96237cf8e814f97b3ef4c36a70fjimblandy// Copyright (c) 2010 Google Inc.
47e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// All rights reserved.
5b934bb974afdc018252e15248455c4cc7730caa0mmentovai//
67e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// Redistribution and use in source and binary forms, with or without
77e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// modification, are permitted provided that the following conditions are
87e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// met:
9b934bb974afdc018252e15248455c4cc7730caa0mmentovai//
107e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai//     * Redistributions of source code must retain the above copyright
117e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// notice, this list of conditions and the following disclaimer.
127e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai//     * Redistributions in binary form must reproduce the above
137e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// copyright notice, this list of conditions and the following disclaimer
147e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// in the documentation and/or other materials provided with the
157e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// distribution.
167e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai//     * Neither the name of Google Inc. nor the names of its
177e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// contributors may be used to endorse or promote products derived from
187e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// this software without specific prior written permission.
19b934bb974afdc018252e15248455c4cc7730caa0mmentovai//
207e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
217e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
227e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
237e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
247e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
257e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
267e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
277e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
287e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
297e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
307e2b64f5fd168cde31257c6ee01436bdbc8dc599mmentovai// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31b934bb974afdc018252e15248455c4cc7730caa0mmentovai
32b934bb974afdc018252e15248455c4cc7730caa0mmentovai// postfix_evaluator-inl.h: Postfix (reverse Polish) notation expression
33b934bb974afdc018252e15248455c4cc7730caa0mmentovai// evaluator.
34b934bb974afdc018252e15248455c4cc7730caa0mmentovai//
35b934bb974afdc018252e15248455c4cc7730caa0mmentovai// Documentation in postfix_evaluator.h.
36b934bb974afdc018252e15248455c4cc7730caa0mmentovai//
37b934bb974afdc018252e15248455c4cc7730caa0mmentovai// Author: Mark Mentovai
38b934bb974afdc018252e15248455c4cc7730caa0mmentovai
39b934bb974afdc018252e15248455c4cc7730caa0mmentovai#ifndef PROCESSOR_POSTFIX_EVALUATOR_INL_H__
40b934bb974afdc018252e15248455c4cc7730caa0mmentovai#define PROCESSOR_POSTFIX_EVALUATOR_INL_H__
41b934bb974afdc018252e15248455c4cc7730caa0mmentovai
42e1930985430ce289f4fe8525f51050e5d78cc44eted.mielczarek#include "processor/postfix_evaluator.h"
43e1930985430ce289f4fe8525f51050e5d78cc44eted.mielczarek
44e1930985430ce289f4fe8525f51050e5d78cc44eted.mielczarek#include <stdio.h>
45b934bb974afdc018252e15248455c4cc7730caa0mmentovai
46b934bb974afdc018252e15248455c4cc7730caa0mmentovai#include <sstream>
47b934bb974afdc018252e15248455c4cc7730caa0mmentovai
48e5dc60822e5938fea2ae892ccddb906641ba174emmentovai#include "google_breakpad/processor/memory_region.h"
4965571f17edb82d122b5f6dc741bd7d4b9e315e1bmmentovai#include "processor/logging.h"
50b934bb974afdc018252e15248455c4cc7730caa0mmentovai
51e5dc60822e5938fea2ae892ccddb906641ba174emmentovainamespace google_breakpad {
52b934bb974afdc018252e15248455c4cc7730caa0mmentovai
53b934bb974afdc018252e15248455c4cc7730caa0mmentovaiusing std::istringstream;
54b934bb974afdc018252e15248455c4cc7730caa0mmentovaiusing std::ostringstream;
55b934bb974afdc018252e15248455c4cc7730caa0mmentovai
56b934bb974afdc018252e15248455c4cc7730caa0mmentovai
57b934bb974afdc018252e15248455c4cc7730caa0mmentovai// A small class used in Evaluate to make sure to clean up the stack
58b934bb974afdc018252e15248455c4cc7730caa0mmentovai// before returning failure.
59b934bb974afdc018252e15248455c4cc7730caa0mmentovaiclass AutoStackClearer {
60b934bb974afdc018252e15248455c4cc7730caa0mmentovai public:
6180e98391dc7ff361355e72c24c0fb222518bcdfcmmentovai  explicit AutoStackClearer(vector<string> *stack) : stack_(stack) {}
62b934bb974afdc018252e15248455c4cc7730caa0mmentovai  ~AutoStackClearer() { stack_->clear(); }
63b934bb974afdc018252e15248455c4cc7730caa0mmentovai
64b934bb974afdc018252e15248455c4cc7730caa0mmentovai private:
65b934bb974afdc018252e15248455c4cc7730caa0mmentovai  vector<string> *stack_;
66b934bb974afdc018252e15248455c4cc7730caa0mmentovai};
67b934bb974afdc018252e15248455c4cc7730caa0mmentovai
68b934bb974afdc018252e15248455c4cc7730caa0mmentovai
69b934bb974afdc018252e15248455c4cc7730caa0mmentovaitemplate<typename ValueType>
70824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.orgbool PostfixEvaluator<ValueType>::EvaluateToken(
71824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    const string &token,
7289e07bf2c75e3a91abddde3219e1108c75059985jimblandy    const string &expression,
7389e07bf2c75e3a91abddde3219e1108c75059985jimblandy    DictionaryValidityType *assigned) {
74824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  // There are enough binary operations that do exactly the same thing
75824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  // (other than the specific operation, of course) that it makes sense
76824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  // to share as much code as possible.
77824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  enum BinaryOperation {
78824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    BINARY_OP_NONE = 0,
79824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    BINARY_OP_ADD,
80824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    BINARY_OP_SUBTRACT,
81824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    BINARY_OP_MULTIPLY,
82824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    BINARY_OP_DIVIDE_QUOTIENT,
83824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    BINARY_OP_DIVIDE_MODULUS,
84824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    BINARY_OP_ALIGN
85824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  };
86b934bb974afdc018252e15248455c4cc7730caa0mmentovai
87824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  BinaryOperation operation = BINARY_OP_NONE;
88824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  if (token == "+")
89824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    operation = BINARY_OP_ADD;
90824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  else if (token == "-")
91824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    operation = BINARY_OP_SUBTRACT;
92824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  else if (token == "*")
93824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    operation = BINARY_OP_MULTIPLY;
94824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  else if (token == "/")
95824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    operation = BINARY_OP_DIVIDE_QUOTIENT;
96824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  else if (token == "%")
97824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    operation = BINARY_OP_DIVIDE_MODULUS;
98824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  else if (token == "@")
99824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    operation = BINARY_OP_ALIGN;
100b934bb974afdc018252e15248455c4cc7730caa0mmentovai
101824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  if (operation != BINARY_OP_NONE) {
102824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // Get the operands.
103824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    ValueType operand1 = ValueType();
104824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    ValueType operand2 = ValueType();
105824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    if (!PopValues(&operand1, &operand2)) {
106824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      BPLOG(ERROR) << "Could not PopValues to get two values for binary "
107824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org                      "operation " << token << ": " << expression;
108824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      return false;
109824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    }
110b934bb974afdc018252e15248455c4cc7730caa0mmentovai
111824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // Perform the operation.
112824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    ValueType result;
113824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    switch (operation) {
114824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      case BINARY_OP_ADD:
115824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        result = operand1 + operand2;
116824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        break;
117824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      case BINARY_OP_SUBTRACT:
118824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        result = operand1 - operand2;
119824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        break;
120824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      case BINARY_OP_MULTIPLY:
121824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        result = operand1 * operand2;
122824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        break;
123824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      case BINARY_OP_DIVIDE_QUOTIENT:
124824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        result = operand1 / operand2;
125824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        break;
126824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      case BINARY_OP_DIVIDE_MODULUS:
127824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        result = operand1 % operand2;
128824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        break;
129824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      case BINARY_OP_ALIGN:
130824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org	result =
131824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org	  operand1 & (static_cast<ValueType>(-1) ^ (operand2 - 1));
132824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        break;
133824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      case BINARY_OP_NONE:
134824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        // This will not happen, but compilers will want a default or
135824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        // BINARY_OP_NONE case.
136824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        BPLOG(ERROR) << "Not reached!";
137b934bb974afdc018252e15248455c4cc7730caa0mmentovai        return false;
138824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org        break;
139824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    }
140b934bb974afdc018252e15248455c4cc7730caa0mmentovai
141824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // Save the result.
142824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    PushValue(result);
143824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  } else if (token == "^") {
144824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // ^ for unary dereference.  Can't dereference without memory.
145824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    if (!memory_) {
146824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      BPLOG(ERROR) << "Attempt to dereference without memory: " <<
147824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org                      expression;
148824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      return false;
149824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    }
150b934bb974afdc018252e15248455c4cc7730caa0mmentovai
151824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    ValueType address;
152824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    if (!PopValue(&address)) {
153824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      BPLOG(ERROR) << "Could not PopValue to get value to derefence: " <<
154824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org                      expression;
155824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      return false;
156824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    }
157824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org
158824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    ValueType value;
159824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    if (!memory_->GetMemoryAtAddress(address, &value)) {
160824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      BPLOG(ERROR) << "Could not dereference memory at address " <<
161824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org                      HexString(address) << ": " << expression;
162824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      return false;
163824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    }
164824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org
165824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    PushValue(value);
166824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  } else if (token == "=") {
167824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // = for assignment.
168824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    ValueType value;
169824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    if (!PopValue(&value)) {
170824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      BPLOG(INFO) << "Could not PopValue to get value to assign: " <<
171824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org                     expression;
172824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      return false;
173824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    }
174824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org
175824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // Assignment is only meaningful when assigning into an identifier.
176824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // The identifier must name a variable, not a constant.  Variables
177824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // begin with '$'.
178824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    string identifier;
179824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    if (PopValueOrIdentifier(NULL, &identifier) != POP_RESULT_IDENTIFIER) {
180824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      BPLOG(ERROR) << "PopValueOrIdentifier returned a value, but an "
181824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org                      "identifier is needed to assign " <<
182824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org                      HexString(value) << ": " << expression;
183824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      return false;
184824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    }
185824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    if (identifier.empty() || identifier[0] != '$') {
186824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      BPLOG(ERROR) << "Can't assign " << HexString(value) << " to " <<
187824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org                      identifier << ": " << expression;
188824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      return false;
189824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    }
190824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org
191824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    (*dictionary_)[identifier] = value;
192824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    if (assigned)
193824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      (*assigned)[identifier] = true;
194824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  } else {
195824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // The token is not an operator, it's a literal value or an identifier.
196824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // Push it onto the stack as-is.  Use push_back instead of PushValue
197824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // because PushValue pushes ValueType as a string, but token is already
198824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // a string.
199824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    stack_.push_back(token);
200824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  }
201824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  return true;
202824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org}
203b934bb974afdc018252e15248455c4cc7730caa0mmentovai
204824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.orgtemplate<typename ValueType>
205824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.orgbool PostfixEvaluator<ValueType>::EvaluateInternal(
206824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    const string &expression,
207824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    DictionaryValidityType *assigned) {
208824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  // Tokenize, splitting on whitespace.
209824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  istringstream stream(expression);
210824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  string token;
211824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org  while (stream >> token) {
212824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // Normally, tokens are whitespace-separated, but occasionally, the
213824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // assignment operator is smashed up against the next token, i.e.
214824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // $T0 $ebp 128 + =$eip $T0 4 + ^ =$ebp $T0 ^ =
215824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // This has been observed in program strings produced by MSVS 2010 in LTO
216824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    // mode.
217824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    if (token.size() > 1 && token[0] == '=') {
218824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      if (!EvaluateToken("=", expression, assigned)) {
219b934bb974afdc018252e15248455c4cc7730caa0mmentovai        return false;
22065571f17edb82d122b5f6dc741bd7d4b9e315e1bmmentovai      }
221824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org
222824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      if (!EvaluateToken(token.substr(1), expression, assigned)) {
223b934bb974afdc018252e15248455c4cc7730caa0mmentovai        return false;
22465571f17edb82d122b5f6dc741bd7d4b9e315e1bmmentovai      }
225824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org    } else if (!EvaluateToken(token, expression, assigned)) {
226824802fd0776c5fb7d6ca861e282ab4f63de86e6mark@chromium.org      return false;
227b934bb974afdc018252e15248455c4cc7730caa0mmentovai    }
228b934bb974afdc018252e15248455c4cc7730caa0mmentovai  }
229b934bb974afdc018252e15248455c4cc7730caa0mmentovai
23089e07bf2c75e3a91abddde3219e1108c75059985jimblandy  return true;
23189e07bf2c75e3a91abddde3219e1108c75059985jimblandy}
23289e07bf2c75e3a91abddde3219e1108c75059985jimblandy
23389e07bf2c75e3a91abddde3219e1108c75059985jimblandytemplate<typename ValueType>
23489e07bf2c75e3a91abddde3219e1108c75059985jimblandybool PostfixEvaluator<ValueType>::Evaluate(const string &expression,
23589e07bf2c75e3a91abddde3219e1108c75059985jimblandy                                           DictionaryValidityType *assigned) {
23689e07bf2c75e3a91abddde3219e1108c75059985jimblandy  // Ensure that the stack is cleared before returning.
23789e07bf2c75e3a91abddde3219e1108c75059985jimblandy  AutoStackClearer clearer(&stack_);
23889e07bf2c75e3a91abddde3219e1108c75059985jimblandy
23989e07bf2c75e3a91abddde3219e1108c75059985jimblandy  if (!EvaluateInternal(expression, assigned))
24089e07bf2c75e3a91abddde3219e1108c75059985jimblandy    return false;
24189e07bf2c75e3a91abddde3219e1108c75059985jimblandy
242b934bb974afdc018252e15248455c4cc7730caa0mmentovai  // If there's anything left on the stack, it indicates incomplete execution.
243b934bb974afdc018252e15248455c4cc7730caa0mmentovai  // This is a failure case.  If the stack is empty, evalution was complete
244b934bb974afdc018252e15248455c4cc7730caa0mmentovai  // and successful.
24589e07bf2c75e3a91abddde3219e1108c75059985jimblandy  if (stack_.empty())
24689e07bf2c75e3a91abddde3219e1108c75059985jimblandy    return true;
247bb87ebd809e4437c953e9008a73927cd7e1c05efjessicag.feedback@gmail.com
24889e07bf2c75e3a91abddde3219e1108c75059985jimblandy  BPLOG(ERROR) << "Incomplete execution: " << expression;
24989e07bf2c75e3a91abddde3219e1108c75059985jimblandy  return false;
250b934bb974afdc018252e15248455c4cc7730caa0mmentovai}
251b934bb974afdc018252e15248455c4cc7730caa0mmentovai
25289e07bf2c75e3a91abddde3219e1108c75059985jimblandytemplate<typename ValueType>
25389e07bf2c75e3a91abddde3219e1108c75059985jimblandybool PostfixEvaluator<ValueType>::EvaluateForValue(const string &expression,
25489e07bf2c75e3a91abddde3219e1108c75059985jimblandy                                                   ValueType *result) {
25589e07bf2c75e3a91abddde3219e1108c75059985jimblandy  // Ensure that the stack is cleared before returning.
25689e07bf2c75e3a91abddde3219e1108c75059985jimblandy  AutoStackClearer clearer(&stack_);
25789e07bf2c75e3a91abddde3219e1108c75059985jimblandy
25889e07bf2c75e3a91abddde3219e1108c75059985jimblandy  if (!EvaluateInternal(expression, NULL))
25989e07bf2c75e3a91abddde3219e1108c75059985jimblandy    return false;
26089e07bf2c75e3a91abddde3219e1108c75059985jimblandy
26189e07bf2c75e3a91abddde3219e1108c75059985jimblandy  // A successful execution should leave exactly one value on the stack.
26289e07bf2c75e3a91abddde3219e1108c75059985jimblandy  if (stack_.size() != 1) {
26389e07bf2c75e3a91abddde3219e1108c75059985jimblandy    BPLOG(ERROR) << "Expression yielded bad number of results: "
26489e07bf2c75e3a91abddde3219e1108c75059985jimblandy                 << "'" << expression << "'";
26589e07bf2c75e3a91abddde3219e1108c75059985jimblandy    return false;
266bb87ebd809e4437c953e9008a73927cd7e1c05efjessicag.feedback@gmail.com  }
26789e07bf2c75e3a91abddde3219e1108c75059985jimblandy
26889e07bf2c75e3a91abddde3219e1108c75059985jimblandy  return PopValue(result);
26989e07bf2c75e3a91abddde3219e1108c75059985jimblandy}
270b934bb974afdc018252e15248455c4cc7730caa0mmentovai
271b934bb974afdc018252e15248455c4cc7730caa0mmentovaitemplate<typename ValueType>
272b934bb974afdc018252e15248455c4cc7730caa0mmentovaitypename PostfixEvaluator<ValueType>::PopResult
273b934bb974afdc018252e15248455c4cc7730caa0mmentovaiPostfixEvaluator<ValueType>::PopValueOrIdentifier(
274b934bb974afdc018252e15248455c4cc7730caa0mmentovai    ValueType *value, string *identifier) {
275b934bb974afdc018252e15248455c4cc7730caa0mmentovai  // There needs to be at least one element on the stack to pop.
276b934bb974afdc018252e15248455c4cc7730caa0mmentovai  if (!stack_.size())
277b934bb974afdc018252e15248455c4cc7730caa0mmentovai    return POP_RESULT_FAIL;
278b934bb974afdc018252e15248455c4cc7730caa0mmentovai
279b934bb974afdc018252e15248455c4cc7730caa0mmentovai  string token = stack_.back();
280b934bb974afdc018252e15248455c4cc7730caa0mmentovai  stack_.pop_back();
281b934bb974afdc018252e15248455c4cc7730caa0mmentovai
2825cf2e760b602686c9a757e3978179f47b451c111jimblandy  // First, try to treat the value as a literal. Literals may have leading
2835cf2e760b602686c9a757e3978179f47b451c111jimblandy  // '-' sign, and the entire remaining string must be parseable as
2845cf2e760b602686c9a757e3978179f47b451c111jimblandy  // ValueType. If this isn't possible, it can't be a literal, so treat it
2855cf2e760b602686c9a757e3978179f47b451c111jimblandy  // as an identifier instead.
2865cf2e760b602686c9a757e3978179f47b451c111jimblandy  //
2875cf2e760b602686c9a757e3978179f47b451c111jimblandy  // Some versions of the libstdc++, the GNU standard C++ library, have
2885cf2e760b602686c9a757e3978179f47b451c111jimblandy  // stream extractors for unsigned integer values that permit a leading
2895cf2e760b602686c9a757e3978179f47b451c111jimblandy  // '-' sign (6.0.13); others do not (6.0.9). Since we require it, we
2905cf2e760b602686c9a757e3978179f47b451c111jimblandy  // handle it explicitly here.
291b934bb974afdc018252e15248455c4cc7730caa0mmentovai  istringstream token_stream(token);
292df9901a45dac4b5162943f631168296f9d05ee20jessicag.feedback@gmail.com  ValueType literal = ValueType();
2935cf2e760b602686c9a757e3978179f47b451c111jimblandy  bool negative;
2945cf2e760b602686c9a757e3978179f47b451c111jimblandy  if (token_stream.peek() == '-') {
2955cf2e760b602686c9a757e3978179f47b451c111jimblandy    negative = true;
2965cf2e760b602686c9a757e3978179f47b451c111jimblandy    token_stream.get();
2975cf2e760b602686c9a757e3978179f47b451c111jimblandy  } else {
2985cf2e760b602686c9a757e3978179f47b451c111jimblandy    negative = false;
2995cf2e760b602686c9a757e3978179f47b451c111jimblandy  }
300b934bb974afdc018252e15248455c4cc7730caa0mmentovai  if (token_stream >> literal && token_stream.peek() == EOF) {
301b934bb974afdc018252e15248455c4cc7730caa0mmentovai    if (value) {
302b934bb974afdc018252e15248455c4cc7730caa0mmentovai      *value = literal;
303b934bb974afdc018252e15248455c4cc7730caa0mmentovai    }
3045cf2e760b602686c9a757e3978179f47b451c111jimblandy    if (negative)
3055cf2e760b602686c9a757e3978179f47b451c111jimblandy      *value = -*value;
306b934bb974afdc018252e15248455c4cc7730caa0mmentovai    return POP_RESULT_VALUE;
307b934bb974afdc018252e15248455c4cc7730caa0mmentovai  } else {
308b934bb974afdc018252e15248455c4cc7730caa0mmentovai    if (identifier) {
309b934bb974afdc018252e15248455c4cc7730caa0mmentovai      *identifier = token;
310b934bb974afdc018252e15248455c4cc7730caa0mmentovai    }
311b934bb974afdc018252e15248455c4cc7730caa0mmentovai    return POP_RESULT_IDENTIFIER;
312b934bb974afdc018252e15248455c4cc7730caa0mmentovai  }
313b934bb974afdc018252e15248455c4cc7730caa0mmentovai}
314b934bb974afdc018252e15248455c4cc7730caa0mmentovai
315b934bb974afdc018252e15248455c4cc7730caa0mmentovai
316b934bb974afdc018252e15248455c4cc7730caa0mmentovaitemplate<typename ValueType>
317b934bb974afdc018252e15248455c4cc7730caa0mmentovaibool PostfixEvaluator<ValueType>::PopValue(ValueType *value) {
318df9901a45dac4b5162943f631168296f9d05ee20jessicag.feedback@gmail.com  ValueType literal = ValueType();
319b934bb974afdc018252e15248455c4cc7730caa0mmentovai  string token;
320b934bb974afdc018252e15248455c4cc7730caa0mmentovai  PopResult result;
321b934bb974afdc018252e15248455c4cc7730caa0mmentovai  if ((result = PopValueOrIdentifier(&literal, &token)) == POP_RESULT_FAIL) {
322b934bb974afdc018252e15248455c4cc7730caa0mmentovai    return false;
323b934bb974afdc018252e15248455c4cc7730caa0mmentovai  } else if (result == POP_RESULT_VALUE) {
324b934bb974afdc018252e15248455c4cc7730caa0mmentovai    // This is the easy case.
325b934bb974afdc018252e15248455c4cc7730caa0mmentovai    *value = literal;
326b934bb974afdc018252e15248455c4cc7730caa0mmentovai  } else {  // result == POP_RESULT_IDENTIFIER
327b934bb974afdc018252e15248455c4cc7730caa0mmentovai    // There was an identifier at the top of the stack.  Resolve it to a
328b934bb974afdc018252e15248455c4cc7730caa0mmentovai    // value by looking it up in the dictionary.
329b934bb974afdc018252e15248455c4cc7730caa0mmentovai    typename DictionaryType::const_iterator iterator =
330b934bb974afdc018252e15248455c4cc7730caa0mmentovai        dictionary_->find(token);
331b934bb974afdc018252e15248455c4cc7730caa0mmentovai    if (iterator == dictionary_->end()) {
332b934bb974afdc018252e15248455c4cc7730caa0mmentovai      // The identifier wasn't found in the dictionary.  Don't imply any
333b934bb974afdc018252e15248455c4cc7730caa0mmentovai      // default value, just fail.
334bb87ebd809e4437c953e9008a73927cd7e1c05efjessicag.feedback@gmail.com      BPLOG(INFO) << "Identifier " << token << " not in dictionary";
335b934bb974afdc018252e15248455c4cc7730caa0mmentovai      return false;
336b934bb974afdc018252e15248455c4cc7730caa0mmentovai    }
337b934bb974afdc018252e15248455c4cc7730caa0mmentovai
338b934bb974afdc018252e15248455c4cc7730caa0mmentovai    *value = iterator->second;
339b934bb974afdc018252e15248455c4cc7730caa0mmentovai  }
340b934bb974afdc018252e15248455c4cc7730caa0mmentovai
341b934bb974afdc018252e15248455c4cc7730caa0mmentovai  return true;
342b934bb974afdc018252e15248455c4cc7730caa0mmentovai}
343b934bb974afdc018252e15248455c4cc7730caa0mmentovai
344b934bb974afdc018252e15248455c4cc7730caa0mmentovai
345b934bb974afdc018252e15248455c4cc7730caa0mmentovaitemplate<typename ValueType>
346b934bb974afdc018252e15248455c4cc7730caa0mmentovaibool PostfixEvaluator<ValueType>::PopValues(ValueType *value1,
347b934bb974afdc018252e15248455c4cc7730caa0mmentovai                                            ValueType *value2) {
348b934bb974afdc018252e15248455c4cc7730caa0mmentovai  return PopValue(value2) && PopValue(value1);
349b934bb974afdc018252e15248455c4cc7730caa0mmentovai}
350b934bb974afdc018252e15248455c4cc7730caa0mmentovai
351b934bb974afdc018252e15248455c4cc7730caa0mmentovai
352b934bb974afdc018252e15248455c4cc7730caa0mmentovaitemplate<typename ValueType>
353b934bb974afdc018252e15248455c4cc7730caa0mmentovaivoid PostfixEvaluator<ValueType>::PushValue(const ValueType &value) {
354b934bb974afdc018252e15248455c4cc7730caa0mmentovai  ostringstream token_stream;
355b934bb974afdc018252e15248455c4cc7730caa0mmentovai  token_stream << value;
356b934bb974afdc018252e15248455c4cc7730caa0mmentovai  stack_.push_back(token_stream.str());
357b934bb974afdc018252e15248455c4cc7730caa0mmentovai}
358b934bb974afdc018252e15248455c4cc7730caa0mmentovai
359b934bb974afdc018252e15248455c4cc7730caa0mmentovai
360e5dc60822e5938fea2ae892ccddb906641ba174emmentovai}  // namespace google_breakpad
361b934bb974afdc018252e15248455c4cc7730caa0mmentovai
362b934bb974afdc018252e15248455c4cc7730caa0mmentovai
363b934bb974afdc018252e15248455c4cc7730caa0mmentovai#endif  // PROCESSOR_POSTFIX_EVALUATOR_INL_H__
364