Strings / Expression Parsing
3.7.1 Recursive Descent Parsing (Simple)
3-Strings/3.7.1_Recursive_Descent_Parsing_(Simple).cpp
Evaluate an expression in accordance to the order of operations (parentheses, unary plus and minus signs, multiplication/division, addition/subtraction). The following is a minimalistic recursive descent implementation using iterators. Each precedence level is parsed by its own function that obtains operands by calling the next-tighter level, so the call structure itself enforces the order of operations.
eval(s)returns an evaluation of the arithmetic expressions.
Implementation
#include <string>
template<class It>
int eval(It &it, int prec) {
if (prec == 0) {
int sign = 1, res = 0;
for (; *it == '-'; it++) {
sign *= -1;
}
if (*it == '(') {
res = eval(++it, 2);
it++;
} else
while (*it >= '0' && *it <= '9') {
res = 10 * res + (*(it++) - '0');
}
return sign * res;
}
int num = eval(it, prec - 1);
while (!((prec == 2 && *it != '+' && *it != '-') || (prec == 1 && *it != '*' && *it != '/'))) {
switch (*(it++)) {
case '+':
num += eval(it, prec - 1);
break;
case '-':
num -= eval(it, prec - 1);
break;
case '*':
num *= eval(it, prec - 1);
break;
case '/':
num /= eval(it, prec - 1);
break;
}
}
return num;
}
int eval(const std::string &s) {
std::string expr = s + '\0';
auto it = expr.begin();
return eval(it, 2);
}
Example Usage
#include <cassert>
int main() {
assert(eval("1++1") == 2);
assert(eval("1+2*3*4+3*(2+2)-100") == -63);
return 0;
}
/*
Evaluate an expression in accordance to the order of operations (parentheses, unary plus and minus
signs, multiplication/division, addition/subtraction). The following is a minimalistic recursive
descent implementation using iterators. Each precedence level is parsed by its own function that
obtains operands by calling the next-tighter level, so the call structure itself enforces the order
of operations.
- `eval(s)` returns an evaluation of the arithmetic expression `s`.
Time Complexity:
- O(n) per call to `eval(s)`, where $n$ is the length of `s`.
Space Complexity:
- O(n) auxiliary stack space for `eval(s)`, where $n$ is the length of `s`.
*/
#include <string>
template<class It>
int eval(It &it, int prec) {
if (prec == 0) {
int sign = 1, res = 0;
for (; *it == '-'; it++) {
sign *= -1;
}
if (*it == '(') {
res = eval(++it, 2);
it++;
} else
while (*it >= '0' && *it <= '9') {
res = 10 * res + (*(it++) - '0');
}
return sign * res;
}
int num = eval(it, prec - 1);
while (!((prec == 2 && *it != '+' && *it != '-') || (prec == 1 && *it != '*' && *it != '/'))) {
switch (*(it++)) {
case '+':
num += eval(it, prec - 1);
break;
case '-':
num -= eval(it, prec - 1);
break;
case '*':
num *= eval(it, prec - 1);
break;
case '/':
num /= eval(it, prec - 1);
break;
}
}
return num;
}
int eval(const std::string &s) {
std::string expr = s + '\0';
auto it = expr.begin();
return eval(it, 2);
}
/*** Example Usage ***/
#include <cassert>
int main() {
assert(eval("1++1") == 2);
assert(eval("1+2*3*4+3*(2+2)-100") == -63);
return 0;
}