Alex's Anthology of Algorithms Common Code for Contests in Concise C++
Strings / Expression Parsing

3.7.1 Recursive Descent Parsing (Simple)

3-Strings/3.7.1_Recursive_Descent_Parsing_(Simple).cpp

View on GitHub

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.

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