Skip to content

Instantly share code, notes, and snippets.

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

Embed
What would you like to do?
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[0]
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[0].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[0] 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

This comment has been minimized.

Copy link

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.

@ascv

This comment has been minimized.

Copy link
Owner Author

ascv commented Feb 21, 2014

Fixed.

@cdpm

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

felix-d commented Jun 22, 2016

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

This comment has been minimized.

Copy link

dannytranit commented Mar 25, 2018

It cannot handle with things like 12 x 21 / 13

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.