Files
calc_engine/calc_engine.py
T

263 lines
9.0 KiB
Python

import ptoken as token
import copy
def calculate_results(tokens):
new_list = copy.deepcopy(tokens)
new_list.reverse()
return handle_add_and_subtract(new_list)
def handle_parenthesis(tokens, call_has_priority = False):
running_value = 0
previous_token = token.Token("", token.TokenType.unknown)
while True:
if len(tokens) == 0:
break
current_token = tokens.pop()
if current_token.type == token.TokenType.constant:
previous_token = current_token
elif current_token == token.TokenType.exp_start:
running_value = handle_parenthesis(tokens)
elif current_token.type == token.TokenType.add or current_token.type == token.TokenType.subtract:
look_ahead = tokens.pop()
if look_ahead.type == token.TokenType.exp_start:
tmp = handle_parenthesis(tokens)
if running_value == 0:
running_value = operate(previous_token.value, tmp, current_token.type)
else:
running_value = operate(running_value, tmp, current_token.type)
continue
tokens.append(look_ahead)
tokens.append(current_token)
if not previous_token.type == token.TokenType.unknown:
tokens.append(previous_token)
else:
tokens.append(token.Token(running_value, token.TokenType.constant))
running_value = handle_add_and_subtract(tokens)
#Set the previous_token to an invalid state so its not used by mistake.
previous_token.type = token.TokenType.unknown
elif current_token.type == token.TokenType.power:
look_ahead = tokens.pop()
if look_ahead.type == token.TokenType.exp_start:
power_of = handle_parenthesis(tokens, True)
running_value = operate(previous_token.value, power_of, current_token.type)
#Set the previous_token to an invalid state so its not used by mistake.
previous_token.type = token.TokenType.unknown
continue
running_value = operate(previous_token.value, look_ahead.value, current_token.type)
#Set the previous_token to an invalid state so its not used by mistake.
previous_token.type = token.TokenType.unknown
elif current_token.type == token.TokenType.multiply or current_token.type == token.TokenType.divide:
look_ahead = peek_list(tokens)
if look_ahead.type == token.TokenType.exp_start:
tokens.pop()
running_value = operate(previous_token.value, handle_parenthesis(tokens), current_token.type)
#Set the previous_token to an invalid state so its not used by mistake.
previous_token.type = token.TokenType.unknown
continue
tokens.append(current_token)
if not previous_token.type == token.TokenType.unknown:
tokens.append(previous_token)
else:
tokens.append(token.CToken(running_value, token.TokenType.constant))
running_value = handle_multiply_and_division(tokens)
#Set the previous_token to an invalid state so its not used by mistake.
previous_token.type = token.TokenType.unknown
elif current_token.type == token.TokenType.exp_end:
if len(tokens) > 0 and peek_list(tokens).type == token.TokenType.power:
tokens.pop()
running_value = operate(running_value, tokens.pop().value, token.TokenType.power)
if not call_has_priority and len(tokens) > 0 and (peek_list(tokens).type == token.TokenType.multiply or peek_list(tokens).type == token.TokenType.divide):
operator = tokens.pop()
two_ahead = tokens.pop()
if two_ahead.type == token.TokenType.exp_start:
running_value = operate(running_value, handle_parenthesis(tokens), operator.type)
else:
running_value = operate(running_value, two_ahead.value, operator.type)
break
return running_value
def handle_multiply_and_division(tokens):
running_value = 0
previous_token = token.Token("", token.TokenType.unknown)
while True:
if len(tokens) == 0:
break
current_token = peek_list(tokens)
#check to see if we want to deal with this token here, making sure not to consume it just incase we
#don't want to process it here.
if current_token.type != token.TokenType.multiply and current_token.type != token.TokenType.divide and current_token.type != token.TokenType.constant and current_token.type != token.TokenType.variable:
break
#"Commit" the current token.
current_token = tokens.pop()
if current_token.type == token.TokenType.constant:
previous_token = current_token
continue
elif current_token.type == token.TokenType.multiply or current_token.type == token.TokenType.divide:
look_ahead = tokens.pop()
if look_ahead.type == token.TokenType.exp_start:
tmp = handle_parenthesis(tokens, True)
if running_value == 0:
running_value = operate(previous_token.value, tmp, current_token.type)
else:
running_value = operate(running_value, tmp, current_token.type)
#Set the previous_token to an invalid state so its not used by mistake.
previous_token.type = token.TokenType.unknown
continue
if look_ahead.type == token.TokenType.constant:
if running_value == 0:
running_value = operate(previous_token.value, look_ahead.value, current_token.type)
else:
running_value = operate(running_value, look_ahead.value, current_token.type)
#Set the previous_token to an invalid state so its not used by mistake.
previous_token.type = token.TokenType.unknown
return running_value
def handle_add_and_subtract(tokens):
#
# Note: this is should be the first function called to calculate the result of the tokens.
# A bit hacky, and not the best name for this method, but it grew "orgranically" to be
# this way. For now this is fine, and for what the calc_engine does this may not
# need to change for the life of this project.
#
running_value = 0
previous_token = token.Token("", token.TokenType.unknown)
while True:
if len(tokens) == 0:
break
current_token = tokens.pop()
if current_token.type == token.TokenType.constant:
previous_token = current_token
continue
if current_token.type == token.TokenType.exp_end:
tokens.append(current_token)
break
if current_token.type == token.TokenType.exp_start:
running_value = handle_parenthesis(tokens)
elif current_token.type == token.TokenType.add or current_token.type == token.TokenType.subtract:
look_ahead = tokens.pop()
if look_ahead.type == token.TokenType.exp_start:
tmp = handle_parenthesis(tokens)
if running_value == 0:
running_value = operate(previous_token.value, tmp, current_token.type)
else:
running_value = operate(running_value, tmp, current_token.type)
#Set the previous_token to an invalid state so its not used by mistake.
previous_token.type = token.TokenType.unknown
continue
elif len(tokens) > 0:
two_ahead = peek_list(tokens)
if two_ahead.type == token.TokenType.multiply or two_ahead.type == token.TokenType.divide:
tokens.append(look_ahead)
tmp = handle_multiply_and_division(tokens)
if running_value == 0:
running_value = operate(previous_token.value, tmp, current_token.type)
else:
running_value = operate(running_value, tmp, current_token.type)
#Set the previous_token to an invalid state so its not used by mistake.
previous_token.type = token.TokenType.unknown
continue
if running_value == 0:
running_value = operate(previous_token.value, look_ahead.value, current_token.type)
else:
running_value = operate(running_value, look_ahead.value, current_token.type)
#Set the previous_token to an invalid state so its not used by mistake.
previous_token.type = token.TokenType.unknown
elif current_token.type == token.TokenType.multiply or current_token.type == token.TokenType.divide:
tokens.append(current_token)
if previous_token.type != token.TokenType.unknown:
tokens.append(previous_token)
else:
tokens.append(token.CToken(running_value, token.TokenType.constant))
running_value = handle_multiply_and_division(tokens)
#Set the previous_token to an invalid state so its not used by mistake.
previous_token.type = token.TokenType.unknown
#elif current_token.type == token.TokenType.power:
#In theory, if we hit this branch the expression wuld look something like this: a ^ b.
return running_value
def peek_list(tokens):
if tokens:
return tokens[-1]
else:
raise IndexError("The token list is empty.", tokens)
def operate(n1, n2, tokenType):
n1 = float(n1)
n2 = float(n2)
if tokenType == token.TokenType.add:
print("Adding %d and %d to get %d." %(n1, n2, n1 + n2))
return n1 + n2
elif tokenType == token.TokenType.subtract:
print("Subtracting %d and %d to get %d." %(n1, n2, n1 - n2))
return n1 - n2
elif tokenType == token.TokenType.multiply:
print("Multiplying %d and %d to get %d" %(n1, n2, n1 * n2))
return n1 * n2
elif tokenType == token.TokenType.divide:
print("Dividing %d and %d to get %d" %(n1, n2, n1 / n2))
return n1 / n2
elif tokenType == token.TokenType.power:
print("Raising %d to the power of %d to get %d" %(n1, n2, n1**n2))
return n1 ** n2
else:
raise TypeError("Invalid operator value " + str(tokenType) + ".", tokenType)