import ptoken as token import copy debug = False 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: if debug: print("Adding %d and %d to get %d." %(n1, n2, n1 + n2)) return n1 + n2 elif tokenType == token.TokenType.subtract: if debug: print("Subtracting %d and %d to get %d." %(n1, n2, n1 - n2)) return n1 - n2 elif tokenType == token.TokenType.multiply: if debug: print("Multiplying %d and %d to get %d" %(n1, n2, n1 * n2)) return n1 * n2 elif tokenType == token.TokenType.divide: if debug: print("Dividing %d and %d to get %d" %(n1, n2, n1 / n2)) return n1 / n2 elif tokenType == token.TokenType.power: if debug: 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)