{{ message }}

Instantly share code, notes, and snippets.

# ascv/calc.py

Last active Mar 4, 2020
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.

 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

### theoden-dd commented Mar 4, 2020

 This code failed with expressions like `(2 / (2 + 3.33) * 4) - -6`. Had to merge with https://effbot.org/zone/simple-top-down-parsing.htm to make it working.

### ascv commented Mar 4, 2020 • edited

 It cannot handle with things like 12 x 21 / 13 Not in the grammar. This code failed with expressions like `(2 / (2 + 3.33) * 4) - -6`. Had to merge with https://effbot.org/zone/simple-top-down-parsing.htm to make it working. Not in the grammar. To clarify, this is not a general purpose calculator, it's just a simple demo to show how to do recursive descent parsing. The grammar is intentionally limited. If I recall correctly, at the time I wrote it, I was trying to keep the number of lines to <= 60. Modify to support your needs :)