Instantly share code, notes, and snippets.

# ascv/calc.py Last active Oct 6, 2019

A simple python calculator to demo recursive descent parsing. Execute the script to use the calculator. It accepts only well formed input. Use parentheses to specify operator precedence.
 """ exp ::= term | exp + term | exp - term term ::= factor | factor * term | factor / term factor ::= number | ( exp ) """ class Calculator(): def __init__(self, tokens): self._tokens = tokens self._current = tokens def exp(self): result = self.term() while self._current in ('+', '-'): if self._current == '+': self.next() result += self.term() if self._current == '-': self.next() result -= self.term() return result def factor(self): result = None if self._current.isdigit() or self._current[-1].isdigit(): result = float(self._current) self.next() elif self._current is '(': self.next() result = self.exp() self.next() return result def next(self): self._tokens = self._tokens[1:] self._current = self._tokens if len(self._tokens) > 0 else None def term(self): result = self.factor() while self._current in ('*', '/'): if self._current == '*': self.next() result *= self.term() if self._current == '/': self.next() result /= self.term() return result if __name__ == '__main__': while True: lst = list(raw_input('> ').replace(' ', '')) tokens = [] for i in range(len(lst)): if lst[i].isdigit() and i > 0 and (tokens[-1].isdigit() or tokens[-1][-1] is '.'): tokens[-1] += lst[i] elif lst[i] is '.' and i > 0 and tokens[-1].isdigit(): tokens[-1] += lst[i] else: tokens.append(lst[i]) print Calculator(tokens).exp()

### 6502 commented Jul 14, 2013

 I didn't try it, but looking at the code I'd say that it cannot handle things like "1+2-3+4-5" because expects a sequences of zero or more "+" followed by a sequence of zero or more "-". Ditto for "*" and "/". Instead of two consecutive while loops should do one while loop accepting all operators of the same precedence.
Owner Author

 Fixed.

### cdpm commented May 30, 2014

 Should it not be "exp ::= term | term + term | term - term" instead of "exp ::= term | exp + term | exp - term" in the docstring?

### felix-d commented Jun 22, 2016 • edited

 ``` ... while True: tokens = re.findall(r'[\d.]+|[+-/*()]', input('> ').replace(' ', '')) print Calculator(tokens).exp() ```

### dannytranit commented Mar 25, 2018

 It cannot handle with things like 12 x 21 / 13