""" | |
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() |
This comment has been minimized.
This comment has been minimized.
Fixed. |
This comment has been minimized.
This comment has been minimized.
Should it not be |
This comment has been minimized.
This comment has been minimized.
...
while True:
tokens = re.findall(r'[\d.]+|[+-/*()]', input('> ').replace(' ', ''))
print Calculator(tokens).exp() |
This comment has been minimized.
This comment has been minimized.
It cannot handle with things like 12 x 21 / 13 |
This comment has been minimized.
This comment has been minimized.
This code failed with expressions like |
This comment has been minimized.
This comment has been minimized.
Not in the grammar.
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 :) |
This comment has been minimized.
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.