Code:
#include <iostream>
#include <string>
#include <cctype>
template <typename iterator>
int expression (iterator & begin, iterator end);
template <typename iterator>
int term (iterator & begin, iterator end);
template <typename iterator>
int factor (iterator & begin, iterator end);
template <typename iterator>
int number (iterator & begin, iterator end);
int main () {
std::cout << "expression: ";
std::string input;
getline (std::cin, input);
try {
auto begin = input.begin ();
auto end = input.end ();
int value = expression (begin, end);
std::cout << "value: " << value;
if (begin != end)
std::cout << "\ninput not completely parsed";
} catch (const char * exception) {
std::cout << "error: " << exception;
}
std::cout << '\n';
std::cin.get ();
}
template <typename iterator>
int expression (iterator & begin, iterator end) {
int sum = term (begin, end);
while (begin != end)
if (* begin == '+')
sum += term (++begin, end);
else if (* begin == '-')
sum -= term (++begin, end);
else
return sum;
return sum;
}
template <typename iterator>
int term (iterator & begin, iterator end) {
int product = factor (begin, end);
while (begin != end)
if (* begin == '*')
product *= factor (++begin, end);
else if (* begin == '/') {
int denominator = factor (++begin, end);
if (! denominator)
throw "division by zero";
product /= denominator;
} else
return product;
return product;
}
template <typename iterator>
int factor (iterator & begin, iterator end) {
if (begin == end)
throw "unexpected end of input";
if (* begin == '(') {
int value_inside = expression (++begin, end);
if (begin == end || * begin != ')')
throw "missing ')'";
++begin;
return value_inside;
}
return number (begin, end);
}
template <typename iterator>
int number (iterator & begin, iterator end) {
int value = 0;
if (begin == end || ! std::isdigit (* begin))
throw "expected a number";
do {
value *= 10;
value += * begin - '0';
++begin;
} while (begin != end && std::isdigit (* begin));
return value;
}
Korrektheit nicht bewiesen - das Programm stürzte bei zehn zufälligen Eingaben nicht ab, ist also korrekt.
Was die einzelnen Funktionen tun, darf gerne erraten werden.
Die Funktionen könnten in eine eigene Klasse kommen, wie auch der Rückgabetyp parametrisiert werden könnte oder stattdessen ein Syntaxbaum erstellt werden könnte (nach Möglichkeit gleich ein abstrakter). Weiterhin wäre es sinnvoll, noch eine eigene Fehlerklasse erstellen, ebenso das Erstellen eines eigenen Lexers und einer entsprechenden Token-Klasse. Aber dann wiederum wäre die Nutzung von Spirit vielleicht doch nicht verkehrt, sofern man weiß, wie man damit richtig umgeht.