#include <iostream>
#include <iomanip>
#include <unordered_set>
#include <memory>
#include <sstream>
#include <algorithm>
#include <functional>
#include <cctype>
#include <iterator>
#include <stdexcept>

namespace MemoryManagement
{
      template<typename type, typename allocator_t = std::allocator<type> >
      class Allocator
      {
            std::unordered_set<type*> mSet;
            allocator_t mAllocator;

      public:

            type* allocate(type const& val = type());

            ~Allocator();
      };

      template<typename type, typename allocator_t>
      type* Allocator<type, allocator_t>::allocate(type const& val)
      {
            type* rval = mAllocator.allocate(1);
            mAllocator.construct(rval, val);
            mSet.insert(rval);
            return rval;
      }

      template<typename type, typename allocator_t>
      Allocator<type, allocator_t>::~Allocator()
      {
            for(auto iter(mSet.begin());iter != mSet.end();++iter)
            {
                  mAllocator.destroy(*iter);
                  mAllocator.deallocate(*iter, 1);
            }

            mSet.clear();
      }

      template<typename type, typename allocator_t = std::allocator<type> >
      type* allocate(type const& val = type())
      {
            static Allocator<type, allocator_t> all;
            return all.allocate(val);
      }
}

namespace TermLexer
{
	struct Object
	{
		virtual ~Object();
		
		enum class type
		{
			Real,
			Operator
		} const mObjectType;
		
		Object(type);
		
		bool is(type a)
		{
			return a == mObjectType;
		}
	};
      
	Object::~Object() {}

	Object::Object(Object::type a):
	mObjectType(a) {}
	
	struct Real : public Object
      {
            typedef long double real_t;

            real_t mNumber;

            Real(real_t);
      };

      struct Operator : public Object
      {
            enum operator_type
            {
                  plus,
                  minus,
                  multiply,
                  divide,
                  power,
                  openBrace,
                  closeBrace,
            } mOperatorType;

            static const std::string operatorChar;

            Operator(operator_type);
      };

      Operator::operator_type fromChar(char const a)
      {
            return static_cast<Operator::operator_type>(Operator::operatorChar.find(a));
      }

      char toChar(Operator::operator_type a)
      {
            return Operator::operatorChar[a];
      }
      
      const std::string Operator::operatorChar("+-*/e()");

	Real::Real(Real::real_t t):
	Object(Object::type::Real),
	mNumber(t) {}
	
	Operator::Operator(Operator::operator_type t):
	Object(Object::type::Operator),
	mOperatorType(t) {}
	
	
	    struct parseException : public std::logic_error
	    {
	          parseException(std::string const&);
	    };
            
      namespace Parser
      {
            std::vector<Object*> parseTerm(std::string const&);
            Real::real_t solveTerm(std::vector<Object*>);
      }
	
	parseException::parseException(std::string const& w):
	std::logic_error(w) {}
	
	std::vector<Object*> TermLexer::Parser::parseTerm(std::string const& str)
	{
	      std::vector<Object*> rval;
	      size_t comma(0);
	      bool parsingInt(false);
	      Real::real_t current(0);
	
	      for(auto c(str.begin());c != str.end();++c)
	      {
	            if(std::string(Operator::operatorChar).find(*c) != std::string::npos)
	            {
	                  if(parsingInt)
	                        rval.push_back(MemoryManagement::allocate<Real>(current));
	                  rval.push_back(MemoryManagement::allocate<Operator>(fromChar(*c)));
	                  comma = current = parsingInt = 0;
	            }
	            else if(std::isdigit(*c) || *c == '.')
	            {
	                  if(*c == '.')
	                        ++comma;
	                  else if(!parsingInt)
	                        current = *c - '0';
	                  else if(!comma)
	                        current = current * 10 + *c - '0';
	                  else
	                        current += (*c - '0') / (Real::real_t)std::pow(10, comma++);
	
	                  parsingInt = true;
	            }
	            else if(*c != ' ')///Skip
	                  throw parseException("Invalid Character in Term!");
	      }
	
	      if(parsingInt)
	            rval.push_back(MemoryManagement::allocate<Real>(current));
	
	      return rval;
	}
	
	Real::real_t TermLexer::Parser::solveTerm(std::vector<Object*> objects)
	{
	      #define Opiter(x) dynamic_cast<Operator*>(obj_iter[x])
	      #define Realiter(x) dynamic_cast<Real*>(obj_iter[x])
	
	      for(auto obj_iter(objects.begin());obj_iter != objects.end();++obj_iter)
	            if((*obj_iter)->is(Object::type::Operator)
	            && Opiter(0)->mOperatorType == Operator::operator_type::openBrace)
	            {
	                  auto closeBraceiter = obj_iter + 1;
	                  for(size_t ct(1);ct;++closeBraceiter)
	                  {
	                        if(closeBraceiter == objects.end())
	                              throw parseException("An open brace wasn't closed!");
	                        else if((*closeBraceiter)->is(Object::type::Operator))
	                              switch(dynamic_cast<Operator*>(*closeBraceiter)->mOperatorType)
	                              {
	                                    case Operator::operator_type::closeBrace:
	                                          --ct;
	                                    break;
	                                    case Operator::operator_type::openBrace:
	                                          ++ct;
	                              }
	                  }
	
	                  std::vector<Object*> braceEnclosedObjects(obj_iter + 1, closeBraceiter - 1);
	                  Real::real_t res(solveTerm(braceEnclosedObjects));
	                  auto before = obj_iter - 1;
	                  objects.erase(obj_iter, closeBraceiter);
	                  objects.insert(before + 1, MemoryManagement::allocate<Real>(Real(res)));
	                  obj_iter = before;
	            }
	
	      auto computeUnaryOperator = [&](Operator::operator_type op_Type, std::function<void(Real&)> process)
	      {
	            for(auto obj_iter(objects.begin());obj_iter != objects.end();++obj_iter)
	                  if((*obj_iter)->is(Object::type::Operator)
	                  && Opiter(0)->mOperatorType == op_Type)
	                  {
	                        if(obj_iter + 1 == objects.end()
	                        || !obj_iter[1]->is(Object::type::Real))
	                              throw parseException("An unary Operator must occur before a real number!");
	                        else if(Opiter(0)->mOperatorType == op_Type
	                             && (obj_iter == objects.begin()
	                              || obj_iter[-1]->is(Object::type::Operator)))
	                        {
	                              process(*Realiter(1));
	                              objects.erase(obj_iter);
	                        }
	                  }
	      };
	
	      auto computeOperator = [&](Operator::operator_type op_Type1, std::function<void(Real&, Real const&)> process1,
	                                 Operator::operator_type op_Type2  = static_cast<Operator::operator_type>(-1), std::function<void(Real&, Real const&)> process2 = [](Real& r, Real const& r2){})
	      {
	            for(auto obj_iter(objects.begin());obj_iter != objects.end();++obj_iter)
	                  if((*obj_iter)->is(Object::type::Operator))
	                  {
	                        if(obj_iter + 1 == objects.end()
	                        || !obj_iter[1]->is(Object::type::Real)
	                        || obj_iter == objects.begin()
	                        || !obj_iter[-1]->is(Object::type::Real))
	                              throw parseException("Invalid use of binary operator!");
	
	                        if(Opiter(0)->mOperatorType == op_Type1)
	                              process1(*Realiter(-1), *Realiter(1));
	                        else if(Opiter(0)->mOperatorType == op_Type2)
	                              process2(*Realiter(-1), *Realiter(1));
	                        else continue;
	
	                        auto tmpiter = obj_iter - 1;
	                        objects.erase(obj_iter + 1);
	                        objects.erase(obj_iter);
	                        obj_iter = tmpiter;
	                  }
	      };
	
	
	      computeUnaryOperator(Operator::operator_type::minus, [&](Real& r){r.mNumber = -r.mNumber;});
	      computeUnaryOperator(Operator::operator_type::plus, [&](Real& r){});
	
	      computeOperator(Operator::power, [&](Real& r, Real const& r2){r.mNumber = std::pow(r.mNumber, r2.mNumber);});
	
	      computeOperator(Operator::multiply, [](Real& r, Real const& r2){r.mNumber *= r2.mNumber;},
	                      Operator::divide, [](Real& r, Real const& r2)
	                      {
	                            if(!r2.mNumber)
	                               throw std::logic_error("It is not allowed to divide by zero!");
	                            r.mNumber /= r2.mNumber;
	                      });
	
	      computeOperator(Operator::plus, [](Real& r, Real const& r2){r.mNumber += r2.mNumber;},
	                      Operator::minus,[](Real& r, Real const& r2){r.mNumber -= r2.mNumber;});
	
	      return dynamic_cast<Real*>(objects.front())->mNumber;
	}
}

int main() try
{
     auto res = TermLexer::Parser::solveTerm(TermLexer::Parser::parseTerm("10*5e-7"));

      std::cout << res << '\n';
}
catch(TermLexer::parseException& e)
{
      std::cerr << "A parse error occured (corresponding to your syntax):\n"
                << e.what() << '\n';
}
catch(std::exception &e)
{
      std::cerr << "\nAn error occured:\n"
                << e.what() << "!\n";
}
catch(...)
{
      std::cerr << "\nAn (!)unknown(!) error occured! Please check your syntax and/or report as bug!\n";
}
