From 6ba341436761b0a2edd5480495f5665fd05b0b11 Mon Sep 17 00:00:00 2001 From: Garritt McCune Date: Mon, 27 Apr 2020 11:01:27 -0500 Subject: [PATCH] Added comments in the code to provide a little bit more insight into what's happening. --- calc_engine.py | 16 +++++++++++++++- ptoken.py | 9 ++++++--- tokenizer.py | 19 ++++++++++++++----- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/calc_engine.py b/calc_engine.py index 28364e5..fe3af66 100644 --- a/calc_engine.py +++ b/calc_engine.py @@ -6,12 +6,18 @@ from collections import deque debug = False 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) def process_tokens(tokens, top_level = False): pending_operations = [] 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: if not tokens: @@ -95,6 +101,9 @@ def process_tokens(tokens, top_level = False): return running_total #handle add/sub 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 previous_token = None @@ -119,6 +128,8 @@ def handle_pending(tokens): return running_total 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() for tk in tokens: @@ -128,6 +139,8 @@ def convert_to_deque(tokens): 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) n2 = float(n2) @@ -150,6 +163,7 @@ def operate(n1, n2, tokenType): raise TypeError("Invalid operator value " + str(tokenType) + ".", tokenType) def print_t(tokens): + # Prints to standard out a flattened representation of a Deque object. tmp = copy.deepcopy(tokens) while True: diff --git a/ptoken.py b/ptoken.py index ae4187c..d09f963 100755 --- a/ptoken.py +++ b/ptoken.py @@ -1,4 +1,6 @@ class Token: + # Represents the single smallest unit that makes up an expression. + def __init__(self, value, type, is_negative_variable = False): self.value = value self.type = type @@ -47,19 +49,20 @@ class TokenType: @staticmethod 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: raise ValueError("An operator verb could not be found.", "token") return TokenType.OPERATOR_VERBS[token] @staticmethod def get_operator(character): - # - #Accepts an individual character and returns either the math operator TokenType or unknown. - # + # Accepts an individual character and returns either the mathmatical operator TokenType or unknown. if not character in TokenType.OPERATORS: return TokenType.unknown return TokenType.OPERATORS[character] @staticmethod def get_token_type_name(tokenType): + # Returns the token's full name based on the TokenType value. return TokenType.TOKEN_NAMES[tokenType] diff --git a/tokenizer.py b/tokenizer.py index ca4c4bf..61b6ea6 100644 --- a/tokenizer.py +++ b/tokenizer.py @@ -1,11 +1,10 @@ import ptoken as token def get_tokens_from_expression_string(expression_string): - - #Takes user input of an actuarial formula and parses the formula to id its components. - #:return: tokens (List of objects of CToken class). + # Takes user input (in the format of a string) of an actuarial formula and parses the formula to its components. + # Returns the list of Token objects that represent the string expression. - tokens = [] # List of objects of CToken class + tokens = [] # List of objects of Token class tmp = "" parsing_number = False 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 tmp = "" elif expression_string[i + 1].isalpha(): - #Must be a variable. + # Must be a variable. if tokens[-1].type == token.TokenType.exp_start: variable_is_negative = True 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: tokens.append(token.Token(tmp, token.TokenType.constant)) 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(): symbols_dic[c] += 1 else: 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)) variable_is_negative = False parsing_number = False @@ -106,12 +109,16 @@ def get_tokens_from_expression_string(expression_string): return tokens def peek_list(tokens): + # Returns the last Token object in the list, else throws an error. if tokens: return tokens[-1] else: raise IndexError("The token list is empty.", tokens) 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 = [] for t in tokens: if t.type == token.TokenType.variable: @@ -125,6 +132,7 @@ def replace_variables(tokens, new_constants): return newTokenList def print_token_list(tokens): + # Prints the list of Tokens to standard out. for tk in tokens: if tk.type == token.TokenType.variable: if tk.is_negative_variable: @@ -136,6 +144,7 @@ def print_token_list(tokens): print() def stringify_token_list(tokens): + # Returns a string that represents the list of Tokens. text = '' for tk in tokens: text += str(tk.value)