Added comments in the code to provide a little bit more insight into what's happening.
This commit is contained in:
+15
-1
@@ -6,12 +6,18 @@ from collections import deque
|
|||||||
debug = False
|
debug = False
|
||||||
|
|
||||||
def calculate_results(tokens):
|
def calculate_results(tokens):
|
||||||
|
# Main entry into the calc_engine.
|
||||||
|
# Returns the result of arthmetic as described by the token list.
|
||||||
return process_tokens(convert_to_deque(tokens), True)
|
return process_tokens(convert_to_deque(tokens), True)
|
||||||
|
|
||||||
def process_tokens(tokens, top_level = False):
|
def process_tokens(tokens, top_level = False):
|
||||||
pending_operations = []
|
pending_operations = []
|
||||||
running_total = 0
|
running_total = 0
|
||||||
p_ops_ran = False
|
# Flag that inidicates a high priority set of mathmatical operations have occurred.
|
||||||
|
# High priority (mulitplation, division, power for instance) act as a pivot on which we can
|
||||||
|
# determine whether or not lower priority operations can safely be performed without violating
|
||||||
|
# the order of operations.
|
||||||
|
p_ops_ran = False
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if not tokens:
|
if not tokens:
|
||||||
@@ -95,6 +101,9 @@ def process_tokens(tokens, top_level = False):
|
|||||||
return running_total
|
return running_total
|
||||||
#handle add/sub
|
#handle add/sub
|
||||||
def handle_pending(tokens):
|
def handle_pending(tokens):
|
||||||
|
# Effectively, this function handles adding and subtracting as all higher priority mathmatical operations
|
||||||
|
# would have already been processed.
|
||||||
|
# Returns the result of the addition or subtraction of the provided token list.
|
||||||
running_total = 0
|
running_total = 0
|
||||||
previous_token = None
|
previous_token = None
|
||||||
|
|
||||||
@@ -119,6 +128,8 @@ def handle_pending(tokens):
|
|||||||
return running_total
|
return running_total
|
||||||
|
|
||||||
def convert_to_deque(tokens):
|
def convert_to_deque(tokens):
|
||||||
|
# Converts a list into a Deque collection object.
|
||||||
|
# Returns a Deque object with the contents of the supplied list or array.
|
||||||
deq = deque()
|
deq = deque()
|
||||||
|
|
||||||
for tk in tokens:
|
for tk in tokens:
|
||||||
@@ -128,6 +139,8 @@ def convert_to_deque(tokens):
|
|||||||
|
|
||||||
|
|
||||||
def operate(n1, n2, tokenType):
|
def operate(n1, n2, tokenType):
|
||||||
|
# Utility function to handle dealing with the various mathmatical operations that the engine can process.
|
||||||
|
# Returns the result of any one of five mathmatical operations, else throws an error for unrecognized operations.
|
||||||
n1 = float(n1)
|
n1 = float(n1)
|
||||||
n2 = float(n2)
|
n2 = float(n2)
|
||||||
|
|
||||||
@@ -150,6 +163,7 @@ def operate(n1, n2, tokenType):
|
|||||||
raise TypeError("Invalid operator value " + str(tokenType) + ".", tokenType)
|
raise TypeError("Invalid operator value " + str(tokenType) + ".", tokenType)
|
||||||
|
|
||||||
def print_t(tokens):
|
def print_t(tokens):
|
||||||
|
# Prints to standard out a flattened representation of a Deque object.
|
||||||
tmp = copy.deepcopy(tokens)
|
tmp = copy.deepcopy(tokens)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
class Token:
|
class Token:
|
||||||
|
# Represents the single smallest unit that makes up an expression.
|
||||||
|
|
||||||
def __init__(self, value, type, is_negative_variable = False):
|
def __init__(self, value, type, is_negative_variable = False):
|
||||||
self.value = value
|
self.value = value
|
||||||
self.type = type
|
self.type = type
|
||||||
@@ -47,19 +49,20 @@ class TokenType:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_operator_verb(token):
|
def get_operator_verb(token):
|
||||||
|
# Returns the verb that corresponds to the supplied Token object's value field, or
|
||||||
|
# throws an error if the Token object isn't a mathmatical operator.
|
||||||
if not token in TokenType.OPERATOR_VERBS:
|
if not token in TokenType.OPERATOR_VERBS:
|
||||||
raise ValueError("An operator verb could not be found.", "token")
|
raise ValueError("An operator verb could not be found.", "token")
|
||||||
return TokenType.OPERATOR_VERBS[token]
|
return TokenType.OPERATOR_VERBS[token]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_operator(character):
|
def get_operator(character):
|
||||||
#
|
# Accepts an individual character and returns either the mathmatical operator TokenType or unknown.
|
||||||
#Accepts an individual character and returns either the math operator TokenType or unknown.
|
|
||||||
#
|
|
||||||
if not character in TokenType.OPERATORS:
|
if not character in TokenType.OPERATORS:
|
||||||
return TokenType.unknown
|
return TokenType.unknown
|
||||||
return TokenType.OPERATORS[character]
|
return TokenType.OPERATORS[character]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_token_type_name(tokenType):
|
def get_token_type_name(tokenType):
|
||||||
|
# Returns the token's full name based on the TokenType value.
|
||||||
return TokenType.TOKEN_NAMES[tokenType]
|
return TokenType.TOKEN_NAMES[tokenType]
|
||||||
|
|||||||
+14
-5
@@ -1,11 +1,10 @@
|
|||||||
import ptoken as token
|
import ptoken as token
|
||||||
|
|
||||||
def get_tokens_from_expression_string(expression_string):
|
def get_tokens_from_expression_string(expression_string):
|
||||||
|
# Takes user input (in the format of a string) of an actuarial formula and parses the formula to its components.
|
||||||
#Takes user input of an actuarial formula and parses the formula to id its components.
|
# Returns the list of Token objects that represent the string expression.
|
||||||
#:return: tokens (List of objects of CToken class).
|
|
||||||
|
|
||||||
tokens = [] # List of objects of CToken class
|
tokens = [] # List of objects of Token class
|
||||||
tmp = ""
|
tmp = ""
|
||||||
parsing_number = False
|
parsing_number = False
|
||||||
symbols_dic = {} # Dictionary to keep track of the no. of times each variable appears.
|
symbols_dic = {} # Dictionary to keep track of the no. of times each variable appears.
|
||||||
@@ -41,7 +40,7 @@ def get_tokens_from_expression_string(expression_string):
|
|||||||
parsing_number = False
|
parsing_number = False
|
||||||
tmp = ""
|
tmp = ""
|
||||||
elif expression_string[i + 1].isalpha():
|
elif expression_string[i + 1].isalpha():
|
||||||
#Must be a variable.
|
# Must be a variable.
|
||||||
if tokens[-1].type == token.TokenType.exp_start:
|
if tokens[-1].type == token.TokenType.exp_start:
|
||||||
variable_is_negative = True
|
variable_is_negative = True
|
||||||
elif token.TokenType.get_operator(tokens[-1].value) != token.TokenType.unknown:
|
elif token.TokenType.get_operator(tokens[-1].value) != token.TokenType.unknown:
|
||||||
@@ -94,10 +93,14 @@ def get_tokens_from_expression_string(expression_string):
|
|||||||
if parsing_number:
|
if parsing_number:
|
||||||
tokens.append(token.Token(tmp, token.TokenType.constant))
|
tokens.append(token.Token(tmp, token.TokenType.constant))
|
||||||
tokens.append(token.Token("*", token.TokenType.multiply))
|
tokens.append(token.Token("*", token.TokenType.multiply))
|
||||||
|
# Check to see if the encountered variable, which is effectively a single character,
|
||||||
|
# has been seen before. If it has been then simply increment the number that represents how many times it's been seen
|
||||||
|
# else, add a new entry for it in the dictonary 'symbols_dic'.
|
||||||
if c in symbols_dic.keys():
|
if c in symbols_dic.keys():
|
||||||
symbols_dic[c] += 1
|
symbols_dic[c] += 1
|
||||||
else:
|
else:
|
||||||
symbols_dic[c] = 1
|
symbols_dic[c] = 1
|
||||||
|
# Afterwards, add the variable with the count of the times it's been seen as a token object to the list of tokens.
|
||||||
tokens.append(token.Token(c + str(symbols_dic[c]), token.TokenType.variable, variable_is_negative))
|
tokens.append(token.Token(c + str(symbols_dic[c]), token.TokenType.variable, variable_is_negative))
|
||||||
variable_is_negative = False
|
variable_is_negative = False
|
||||||
parsing_number = False
|
parsing_number = False
|
||||||
@@ -106,12 +109,16 @@ def get_tokens_from_expression_string(expression_string):
|
|||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
def peek_list(tokens):
|
def peek_list(tokens):
|
||||||
|
# Returns the last Token object in the list, else throws an error.
|
||||||
if tokens:
|
if tokens:
|
||||||
return tokens[-1]
|
return tokens[-1]
|
||||||
else:
|
else:
|
||||||
raise IndexError("The token list is empty.", tokens)
|
raise IndexError("The token list is empty.", tokens)
|
||||||
|
|
||||||
def replace_variables(tokens, new_constants):
|
def replace_variables(tokens, new_constants):
|
||||||
|
# Searches and replaces variable Tokens with Constant TokenType Token objects. Doing so enables the calc_engine to never have
|
||||||
|
# to even know variable token types exist.
|
||||||
|
# Returns a list of Token objects with the variables replaced by the supplied list of new constants.
|
||||||
newTokenList = []
|
newTokenList = []
|
||||||
for t in tokens:
|
for t in tokens:
|
||||||
if t.type == token.TokenType.variable:
|
if t.type == token.TokenType.variable:
|
||||||
@@ -125,6 +132,7 @@ def replace_variables(tokens, new_constants):
|
|||||||
return newTokenList
|
return newTokenList
|
||||||
|
|
||||||
def print_token_list(tokens):
|
def print_token_list(tokens):
|
||||||
|
# Prints the list of Tokens to standard out.
|
||||||
for tk in tokens:
|
for tk in tokens:
|
||||||
if tk.type == token.TokenType.variable:
|
if tk.type == token.TokenType.variable:
|
||||||
if tk.is_negative_variable:
|
if tk.is_negative_variable:
|
||||||
@@ -136,6 +144,7 @@ def print_token_list(tokens):
|
|||||||
print()
|
print()
|
||||||
|
|
||||||
def stringify_token_list(tokens):
|
def stringify_token_list(tokens):
|
||||||
|
# Returns a string that represents the list of Tokens.
|
||||||
text = ''
|
text = ''
|
||||||
for tk in tokens:
|
for tk in tokens:
|
||||||
text += str(tk.value)
|
text += str(tk.value)
|
||||||
|
|||||||
Reference in New Issue
Block a user