Fixed a negative number bug in the tokenizer; started work on a new calc_engine. Mostly working as of this commit.
This commit is contained in:
+123
-225
@@ -1,264 +1,162 @@
|
|||||||
import ptoken as token
|
import ptoken
|
||||||
|
import tokenizer
|
||||||
|
import queue
|
||||||
|
import deque
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
debug = False
|
debug = True
|
||||||
|
|
||||||
def calculate_results(tokens):
|
def calculate_results(tokens):
|
||||||
new_list = copy.deepcopy(tokens)
|
q = convert_to_queue(tokens)
|
||||||
new_list.reverse()
|
tokenizer.print_token_list(tokens)
|
||||||
return handle_add_and_subtract(new_list)
|
|
||||||
|
|
||||||
def handle_parenthesis(tokens, call_has_priority = False):
|
return process_tokens(q, True)
|
||||||
running_value = 0
|
|
||||||
previous_token = token.Token("", token.TokenType.unknown)
|
def process_tokens(tokens, top_level = False):
|
||||||
|
pending_operations = []#queue.Queue()
|
||||||
|
power = 0
|
||||||
|
running_total = 0
|
||||||
|
p_ops_ran = False
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if len(tokens) == 0:
|
if tokens.empty():
|
||||||
break
|
break
|
||||||
|
|
||||||
current_token = tokens.pop()
|
token = tokens.get()
|
||||||
|
|
||||||
if current_token.type == token.TokenType.constant:
|
if not top_level and token.type == ptoken.TokenType.exp_end:
|
||||||
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:
|
#if look_ahead.popleft().type == ptoken.TokenType.power:
|
||||||
look_ahead = tokens.pop()
|
# power = float(look_ahead.value)
|
||||||
|
|
||||||
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
|
break
|
||||||
|
|
||||||
return running_value
|
if token.type == ptoken.TokenType.exp_start:
|
||||||
|
tmp = process_tokens(tokens)
|
||||||
|
|
||||||
def handle_multiply_and_division(tokens):
|
pending_operations.append(ptoken.Token(tmp, ptoken.TokenType.constant))
|
||||||
running_value = 0
|
|
||||||
previous_token = token.Token("", token.TokenType.unknown)
|
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:
|
while True:
|
||||||
if len(tokens) == 0:
|
if tokens.empty():
|
||||||
break
|
break
|
||||||
|
|
||||||
current_token = peek_list(tokens)
|
tmp_token = tokens.get()
|
||||||
#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.
|
if tmp_token.type == ptoken.TokenType.constant:
|
||||||
current_token = tokens.pop()
|
previous_token = tmp_token
|
||||||
|
elif tmp_token.type == ptoken.TokenType.add or tmp_token.type == ptoken.TokenType.subtract:
|
||||||
|
look_ahead = tokens.get()
|
||||||
|
|
||||||
if current_token.type == token.TokenType.constant:
|
running_total = operate(previous_token.value, look_ahead.value, tmp_token.type)
|
||||||
previous_token = current_token
|
|
||||||
continue
|
|
||||||
|
|
||||||
elif current_token.type == token.TokenType.multiply or current_token.type == token.TokenType.divide:
|
previous_token = ptoken.Token(running_total, ptoken.TokenType.constant)
|
||||||
look_ahead = tokens.pop()
|
|
||||||
|
|
||||||
if look_ahead.type == token.TokenType.exp_start:
|
return running_total
|
||||||
tmp = handle_parenthesis(tokens, True)
|
|
||||||
|
|
||||||
if running_value == 0:
|
def convert_to_queue(tokens):
|
||||||
running_value = operate(previous_token.value, tmp, current_token.type)
|
q = queue.Queue()
|
||||||
else:
|
|
||||||
running_value = operate(running_value, tmp, current_token.type)
|
|
||||||
|
|
||||||
#Set the previous_token to an invalid state so its not used by mistake.
|
for tk in tokens:
|
||||||
previous_token.type = token.TokenType.unknown
|
q.put(ptoken.Token(tk.value, tk.type))
|
||||||
continue
|
|
||||||
|
|
||||||
if look_ahead.type == token.TokenType.constant:
|
return q
|
||||||
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):
|
def operate(n1, n2, tokenType):
|
||||||
n1 = float(n1)
|
n1 = float(n1)
|
||||||
n2 = float(n2)
|
n2 = float(n2)
|
||||||
|
|
||||||
if tokenType == token.TokenType.add:
|
if tokenType == ptoken.TokenType.add:
|
||||||
if debug: print("Adding %d and %d to get %d." %(n1, n2, n1 + n2))
|
if debug: print("Adding %f and %f to get %f." %(n1, n2, n1 + n2))
|
||||||
return n1 + n2
|
return n1 + n2
|
||||||
elif tokenType == token.TokenType.subtract:
|
elif tokenType == ptoken.TokenType.subtract:
|
||||||
if debug: print("Subtracting %d and %d to get %d." %(n1, n2, n1 - n2))
|
if debug: print("Subtracting %f and %f to get %f." %(n1, n2, n1 - n2))
|
||||||
return n1 - n2
|
return n1 - n2
|
||||||
elif tokenType == token.TokenType.multiply:
|
elif tokenType == ptoken.TokenType.multiply:
|
||||||
if debug: print("Multiplying %d and %d to get %d" %(n1, n2, n1 * n2))
|
if debug: print("Multiplying %f and %f to get %f" %(n1, n2, n1 * n2))
|
||||||
return n1 * n2
|
return n1 * n2
|
||||||
elif tokenType == token.TokenType.divide:
|
elif tokenType == ptoken.TokenType.divide:
|
||||||
if debug: print("Dividing %d and %d to get %d" %(n1, n2, n1 / n2))
|
if debug: print("Dividing %f and %f to get %f" %(n1, n2, n1 / n2))
|
||||||
return n1 / n2
|
return n1 / n2
|
||||||
elif tokenType == token.TokenType.power:
|
elif tokenType == ptoken.TokenType.power:
|
||||||
if debug: print("Raising %d to the power of %d to get %d" %(n1, n2, n1**n2))
|
if debug: print("Raising %f to the power of %f to get %f" %(n1, n2, n1**n2))
|
||||||
return n1 ** n2
|
return n1 ** n2
|
||||||
else:
|
else:
|
||||||
raise TypeError("Invalid operator value " + str(tokenType) + ".", tokenType)
|
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
|
||||||
|
|||||||
+9
-4
@@ -27,13 +27,18 @@ def get_tokens_from_expression_string(expression_string):
|
|||||||
|
|
||||||
elif c == '-' and not parsing_number:
|
elif c == '-' and not parsing_number:
|
||||||
if expression_string[i + 1] == '.' or expression_string[i + 1].isdigit():
|
if expression_string[i + 1] == '.' or expression_string[i + 1].isdigit():
|
||||||
tmp = "-"
|
if tokens[-1].type == token.TokenType.exp_end:
|
||||||
parsing_number = True
|
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:
|
else:
|
||||||
tokens.append(token.Token(c, token.TokenType.get_operator(c)))
|
tokens.append(token.Token(c, token.TokenType.get_operator(c)))
|
||||||
parsing_number = False
|
parsing_number = False
|
||||||
tmp = ""
|
tmp = ""
|
||||||
continue
|
|
||||||
|
|
||||||
elif c == '(':
|
elif c == '(':
|
||||||
if parsing_number:
|
if parsing_number:
|
||||||
@@ -102,5 +107,5 @@ def replace_variables(tokens, new_constants):
|
|||||||
|
|
||||||
def print_token_list(tokens):
|
def print_token_list(tokens):
|
||||||
for tk in 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()
|
print()
|
||||||
|
|||||||
Reference in New Issue
Block a user