Created
June 28, 2013 18:53
-
-
Save technillogue/5887092 to your computer and use it in GitHub Desktop.
A more complicated recursive python calculator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import OrderedDict | |
#reverse order of operations | |
#I didn't have to use an OrderedDict, but it's cute | |
operations = OrderedDict([ | |
("+", lambda x, y: x + y), | |
("-", lambda x, y: x - y), | |
("/", lambda x, y: x / y), | |
("*", lambda x, y: x * y), | |
("^", lambda x, y: x ^ y) | |
]) | |
symbols = operations.keys() | |
def lex(expr): | |
""" | |
seperates numbers from symbols, recursively nests parens | |
""" | |
tokens = [] | |
while expr: | |
char, *expr = expr | |
#char is equal to the first charecter of the expression, expr is equal | |
#to the rest of it | |
if char == "#": | |
#the rest of the line is a comment | |
break | |
if char == "(": | |
try: | |
paren, expr = lex(expr) | |
tokens.append(paren) | |
#expr is what's after the end of the paren, we'll just continue | |
#lexing after that'' | |
except ValueError: | |
raise Exception("paren mismatch") | |
elif char == ")": | |
return tokens, expr | |
#returns the tokens leading up to the to the paren and the rest of | |
#the expression after it | |
elif char.isdigit() or char == ".": | |
#number | |
try: | |
if tokens[-1] in symbols: | |
tokens.append(char) #start a new num | |
elif type(tokens[-1]) is list: | |
raise Exception("parens cannot be followed by numbers") | |
#no support for 5(1+1) yet | |
else: | |
tokens[-1] += char #add to last num | |
except IndexError: | |
#if tokens is empty | |
tokens.append(char) #start first num | |
elif char in symbols: | |
tokens.append(char) | |
elif char.isspace(): | |
pass | |
else: | |
raise Exception("invalid charecter: " + char) | |
return tokens | |
def evaluate(tokens): | |
for symbol, func in operations.items(): | |
#try to find an operation to eval in order | |
try: | |
pos = tokens.index(symbol) | |
#split the tokens by the operation and eval that | |
leftTerm = evaluate(tokens[:pos]) | |
rightTerm = evaluate(tokens[pos + 1:]) | |
return func(leftTerm, rightTerm) | |
#incidentially, return immediatly breaks all loops within the | |
# function | |
except ValueError: | |
pass | |
#index raises ValueError when it's not found | |
if len(tokens) is 1: | |
try: | |
#it must be a number | |
return float(tokens[0]) | |
except TypeError: | |
#if it's not a number | |
return evaluate(tokens[0]) | |
else: | |
raise Exception("bad expression: " + tokens) | |
def calc(expr): | |
return evaluate(lex(expr)) | |
while 1: | |
print(calc(input("Input? "))) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ python3 calc.py | |
Input? 1 + 1 #simple operations, comments | |
2.0 | |
Input? 0.1-0.5#floats and negatives, irrelevant whitespace | |
-0.4 | |
Input? 4 + 4 / 2 - 1 #order of operations is respected | |
5.0 | |
Input? (4-4 + (3-2) * (((((((7)))))))) # complex parens | |
7.0 |
thanks for your code very much
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello, i have fixed your project. There was a issue with exponential calculation:
In python we use ** for exponential calculations. This should fix it:
BTW i shortened your project a bit.