From 4750bed9299573a61ad0bd1659bf36968f50530f Mon Sep 17 00:00:00 2001 From: Garritt McCune Date: Thu, 23 Apr 2020 14:12:17 -0500 Subject: [PATCH] Fixed a negative number bug in the tokenizer; started work on a new calc_engine. Mostly working as of this commit. --- calc_engine.py | 356 ++++++++++++++++++------------------------------- tokenizer.py | 15 ++- 2 files changed, 137 insertions(+), 234 deletions(-) diff --git a/calc_engine.py b/calc_engine.py index c4c1fba..c2162b5 100644 --- a/calc_engine.py +++ b/calc_engine.py @@ -1,264 +1,162 @@ -import ptoken as token +import ptoken +import tokenizer +import queue +import deque import copy -debug = False +debug = True def calculate_results(tokens): - new_list = copy.deepcopy(tokens) - new_list.reverse() - return handle_add_and_subtract(new_list) + q = convert_to_queue(tokens) + tokenizer.print_token_list(tokens) -def handle_parenthesis(tokens, call_has_priority = False): - running_value = 0 - previous_token = token.Token("", token.TokenType.unknown) + return process_tokens(q, True) + +def process_tokens(tokens, top_level = False): + pending_operations = []#queue.Queue() + power = 0 + running_total = 0 + p_ops_ran = False while True: - if len(tokens) == 0: + if tokens.empty(): break - current_token = tokens.pop() + token = tokens.get() - if current_token.type == token.TokenType.constant: - previous_token = current_token + if not top_level and token.type == ptoken.TokenType.exp_end: - 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) + #if look_ahead.popleft().type == ptoken.TokenType.power: + # power = float(look_ahead.value) break - - return running_value - -def handle_multiply_and_division(tokens): - running_value = 0 - previous_token = token.Token("", token.TokenType.unknown) + + if token.type == ptoken.TokenType.exp_start: + tmp = process_tokens(tokens) + + pending_operations.append(ptoken.Token(tmp, ptoken.TokenType.constant)) + + elif token.type == ptoken.TokenType.power: + look_ahead = tokens.get() + + pending_operations.append(ptoken.Token(operate(pending_operations.pop().value, look_ahead.value, token.type), ptoken.TokenType.constant)) + + elif token.type == ptoken.TokenType.add or token.type == ptoken.TokenType.subtract: + if len(pending_operations) > 0 and p_ops_ran: + tmp = convert_to_queue(pending_operations) + previous_token = None + + while True: + if tmp.empty(): + break + + tmp_token = tmp.get() + + if tmp_token.type == ptoken.TokenType.constant: + previous_token = tmp_token + elif tmp_token.type == ptoken.TokenType.add or tmp_token.type == ptoken.TokenType.subtract: + look_ahead = tmp.get() + + running_total = operate(previous_token.value, look_ahead.value, tmp_token.type) + + previous_token = ptoken.Token(running_total, ptoken.TokenType.constant) + + pending_operations = [] + pending_operations.append(previous_token) + pending_operations.append(token) + tokenizer.print_token_list(pending_operations) + p_ops_ran = False + + elif token.type == ptoken.TokenType.constant: + pending_operations.append(token) + p_ops_ran = False + + elif token.type == ptoken.TokenType.multiply or token.type == ptoken.TokenType.divide: + look_ahead = tokens.get() + + if look_ahead.type == ptoken.TokenType.exp_start: + look_ahead = ptoken.Token(process_tokens(tokens), ptoken.TokenType.constant) + + look_behind = pending_operations.pop() + + running_total = operate(look_behind.value, look_ahead.value, token.type) + + pending_operations.append(ptoken.Token(running_total, ptoken.TokenType.constant)) + p_ops_ran = True + + tokenizer.print_token_list(pending_operations) + + if power > 0: + running_total = handle_pending(convert_to_queue(pending_operations)) + + running_total = operate(running_total, power, ptoken.TokenType.power) + elif len(pending_operations) > 0: + running_total = handle_pending(convert_to_queue(pending_operations)) + + return running_total + +def handle_pending(tokens): + running_total = 0 + previous_token = None while True: - if len(tokens) == 0: + if tokens.empty(): 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 + tmp_token = tokens.get() - #"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 tmp_token.type == ptoken.TokenType.constant: + previous_token = tmp_token + elif tmp_token.type == ptoken.TokenType.add or tmp_token.type == ptoken.TokenType.subtract: + look_ahead = tokens.get() - 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 + running_total = operate(previous_token.value, look_ahead.value, tmp_token.type) - return running_value + previous_token = ptoken.Token(running_total, ptoken.TokenType.constant) + + return running_total -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) +def convert_to_queue(tokens): + q = queue.Queue() - while True: - - if len(tokens) == 0: - break + for tk in tokens: + q.put(ptoken.Token(tk.value, tk.type)) - 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) - + return q + 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)) + if tokenType == ptoken.TokenType.add: + if debug: print("Adding %f and %f to get %f." %(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)) + elif tokenType == ptoken.TokenType.subtract: + if debug: print("Subtracting %f and %f to get %f." %(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)) + elif tokenType == ptoken.TokenType.multiply: + if debug: print("Multiplying %f and %f to get %f" %(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)) + elif tokenType == ptoken.TokenType.divide: + if debug: print("Dividing %f and %f to get %f" %(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)) + elif tokenType == ptoken.TokenType.power: + if debug: print("Raising %f to the power of %f to get %f" %(n1, n2, n1**n2)) return n1 ** n2 else: raise TypeError("Invalid operator value " + str(tokenType) + ".", tokenType) + +def print_t(tokens): + tmp = queue.Queue() + + while True: + if tokens.empty(): + break + token = tokens.get() + + print("%s" %(token.value), end = "") + tmp.put(token) + print() + + return tmp diff --git a/tokenizer.py b/tokenizer.py index b4c4a72..a76119e 100644 --- a/tokenizer.py +++ b/tokenizer.py @@ -27,13 +27,18 @@ def get_tokens_from_expression_string(expression_string): elif c == '-' and not parsing_number: if expression_string[i + 1] == '.' or expression_string[i + 1].isdigit(): - tmp = "-" - parsing_number = True + if tokens[-1].type == token.TokenType.exp_end: + tokens.append(token.Token(c, token.TokenType.get_operator(c))) + parsing_number = False + tmp = "" + else: + tokens.append(token.Token('+', token.TokenType.add)) + tmp = "-" + parsing_number = True else: tokens.append(token.Token(c, token.TokenType.get_operator(c))) parsing_number = False tmp = "" - continue elif c == '(': if parsing_number: @@ -44,7 +49,7 @@ def get_tokens_from_expression_string(expression_string): tmp = "" continue elif c == ')': - if parsing_number: + if parsing_number: tokens.append(token.Token(tmp, token.TokenType.constant)) tokens.append(token.Token(")", token.TokenType.exp_end)) parsing_number = False @@ -102,5 +107,5 @@ def replace_variables(tokens, new_constants): def print_token_list(tokens): for tk in tokens: - print("%s" %(tk.value), end = "")#, token.TokenType.get_token_type_name(tk.type)), end = "") + print("%s " %(tk.value), end = "")#, token.TokenType.get_token_type_name(tk.type)), end = "") print()