S
Also Werner!
Ein Auszug aus einem alten Projekt von mir, stell also keinerlei Ansprüche!
Ich weiß dass das alles anders vereinfacht werden könnte. Darum geht es jetzt auch nicht.
boost::ptr_vector<Object> TermLexer::Parser::tokenizeTerm(std::istream& is)
{
boost::ptr_vector<Object> rval;
size_t comma(0);
bool parsingInt(false);
Real::real_t current(0);
char c;
while(is.get(c) and c != '\n')
{
if(std::string(Operator::operatorChar).find(c) != std::string::npos)
{
if(parsingInt)
rval.push_back(new Real(current));
rval.push_back(new 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 When Space
throw Exceptions::parseException("Invalid Character in Term!");
}
if(parsingInt)
rval.push_back(new Real(current));
return rval;
}
Real::real_t TermLexer::Parser::solveTerm(boost::ptr_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;
break;
default: break;
}
}
boost::ptr_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, new Real(res));
obj_iter = before;
}
auto computeUnaryOperators = [&](std::map<Operator::operator_type, std::function<void(Real&)>> processes)
{
for(auto obj_iter(objects.end());obj_iter != objects.begin();)
{
--obj_iter;
for(auto pair : processes)
if(obj_iter[0].is(Object::type::Operator)
&& Opiter(0)->mOperatorType == pair.first)
{
if(obj_iter + 1 == objects.end() ///If the operator is before the end of the vector, or the next element is another operator
|| !obj_iter[1].is(Object::type::Real))
throw parseException("An unary Operator must occur before a real number!");
else if(obj_iter == objects.begin()///If the object before isn't a Real, compute
|| obj_iter[-1].is(Object::type::Operator))
{
pair.second(*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&, Real const&){})
{
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;
}
};
computeUnaryOperators({std::make_pair(Operator::operator_type::minus, [&](Real& r){r.mNumber = -r.mNumber;}),
std::make_pair(Operator::operator_type::plus, [&](Real&){}),
std::make_pair(Operator::operator_type::sine, [&](Real& r){r.mNumber = std::sin(TermLexer::Math::toRadian(r.mNumber));}),
std::make_pair(Operator::operator_type::cosine, [&](Real& r){r.mNumber = std::cos(TermLexer::Math::toRadian(r.mNumber));}),
std::make_pair(Operator::operator_type::tangent, [&](Real& r){r.mNumber = std::tan(TermLexer::Math::toRadian(r.mNumber));}),
std::make_pair(Operator::operator_type::sqrt, [&](Real& r){r.mNumber = std::sqrt(r.mNumber);})});
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;});
auto front = dynamic_cast<Real*>(&objects.front());
if(!front)
throw parseException("Unknown parse error occured!");
return front->mNumber;
}
Auf eine Erklärung habe ich erst Morgen Früh Lust.
Nur ganz kurz: Die beiden Token sind Real und Operator (also jeweils für Zahl und arithmetischen Operator), beide Kindklassen von Object, der abstrakten Basisklasse. Die erste Funktion oben ist der Lexer, die zweite der eigentliche semantische Parser. Der Rest dürfte sich vom Kontext erschließen.