// Programm: calc-simple.C
// Parser fuer einfache arithmetische Ausdruecke.
// Benutzt folgende kontextfreie Grammatik:
// add_expr: number add_expr_aux
// add_expr_aux: '+' number add_expr_aux
// '-' number add_expr_aux
// epsilon
//
// number: digit digits
//
// digits: digit digits
// epsilon
//
// digit: '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
#include
#include
#include
#include
// Parse-Functionen fuer die Nichtterminale:
// -----------------------------------------
// Zu jedem Nichtterminal N der Grammatik gibt es genau eine Funktion
// desselben Namens, die folgende Pre- und Postconditions hat:
//
// PRE: [b,e) ist ein gueltiger range.
// POST: Wenn sich ein Praefix P=[b,f) der durch den range [b,e)
// beschriebenen Zeichenfolge aus dem Nichtterminal N ableiten laesst,
// so ist b==f und Rueckgabewert ist der numerische Wert des durch P
// beschriebenen arithmetischen Ausdrucks. Andernfalls wirft die
// Funktion eine exception vom Typ std::invalid_argument.
// Zahlentyp fuer alle Berechnungen
typedef int NT;
// Iteratortyp fuer alle Funktionen
typedef std::string::const_iterator SSCI;
NT digit(SSCI& b, SSCI e)
// PRE: b ist dereferenzierbar.
{
return *(b++) - '0';
}
NT digits(SSCI& b, SSCI e, const NT& left_op)
{
if (b == e || !std::isdigit(*b))
return left_op;
NT val = left_op * 10 + digit(b, e);
return digits(b, e, val);
}
NT number(SSCI& b, SSCI e)
{
if (b == e || !std::isdigit(*b))
throw std::invalid_argument("digit expected.");
NT val = digit(b, e);
return digits(b, e, val);
}
NT add_expr_aux(SSCI& b, SSCI e, const NT& left_op)
{
if (b == e) return left_op;
if (*b == '+') {
NT right_op = number(++b, e);
return add_expr_aux(b, e, left_op + right_op);
}
if (*b == '-') {
NT right_op = number(++b, e);
return add_expr_aux(b, e, left_op - right_op);
}
return left_op;
}
NT add_expr(SSCI& b, SSCI e)
{
NT value = number(b, e);
return add_expr_aux(b, e, value);
}
int main()
{
std::cout << "Eingabe: ";
std::string input;
std::cin >> input;
SSCI beg = input.begin();
SSCI end = input.end();
SSCI cur = beg;
try {
std::cout << add_expr(cur, end) << std::endl;
if (cur != end)
throw std::invalid_argument("Unexpected character.");
} catch (std::invalid_argument err) {
std::cerr << "Parse error: " << err.what() << "\n"
<< std::string(beg, cur)
<< "|-here->"
<< std::string(cur, end) << std::endl;
return 1;
}
return 0;
}