#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";
}