263 lines
9.0 KiB
Python
263 lines
9.0 KiB
Python
import 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.CToken("", 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.CToken(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.CToken("", 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.CToken("", 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)
|