diff --git a/factors.py b/factors.py index 2e8efee..56ec40a 100644 --- a/factors.py +++ b/factors.py @@ -55,7 +55,6 @@ class Factor: print(self.complex_four) print() - def clear_factors_lists(self): self.simple_one = [] self.simple_two = [] diff --git a/json_generator/data.json b/json_generator/data.json new file mode 100644 index 0000000..1166f00 --- /dev/null +++ b/json_generator/data.json @@ -0,0 +1,17 @@ +{ + "expression": "i + 2 + n", + "variables": { + "n1": { + "name": "n1", + "type": "Unknown", + "starting_point": 0, + "ending_point": 0 + }, + "i1": { + "name": "i1", + "type": "Unknown", + "starting_point": 0, + "ending_point": 0 + } + } +} \ No newline at end of file diff --git a/json_generator/expression.py b/json_generator/expression.py new file mode 100644 index 0000000..1c7a3f6 --- /dev/null +++ b/json_generator/expression.py @@ -0,0 +1,27 @@ +class Expression: + expression = "" + variables = [] + + def __init__(self, expression_string, variables): + self.expression = expression_string + self.variables = variables + +class Variable: + VARIABLE_TYPES = { + "i" : "Interest", + "I" : "Interest", + "n" : "Time", + "N" : "Time" + } + + def __init__(self, name, type, starting_point = 0, ending_point = 0): + self.name = name + self.type = type + self.starting_point = starting_point + self.ending_point = ending_point + + @staticmethod + def get_variable_type(variable_name): + if not variable_name in Variable.VARIABLE_TYPES: + return "Unknown" + return Variable.VARIABLE_TYPES[variable_name] diff --git a/json_generator/main.py b/json_generator/main.py new file mode 100644 index 0000000..4419eb0 --- /dev/null +++ b/json_generator/main.py @@ -0,0 +1,96 @@ +import tokenizer +import token +import expression +import json + +variables = {} +def print_vars(vars): + i = 0 + for key in vars.keys(): + var = vars[key] + if i != 0: + print(", %s" %(var.name), end = "") + else: + print("%s " %(var.name), end = "") + i += 1 + print() + +def modify_variable(var, vars): + print("%s is now selected." %(var.name)) + print("The following properties are avaliable: Variable Type, Starting Point and Ending Point.") + print('Commands are "type", "start" and "end", respectly.') + + while True: + response = input("Select a property to modify for %s or q to exit property modifying: " %(var.name)) + + if response == "type": + response = input("Enter the type of variable this is (currently %s): " %(expression.Variable.get_variable_type(var.type))) + vars[var.name].type = response + print("Updated to %s." %(response)) + + elif response == "start": + response = input("Enter the variable's starting point (currently %f): " %(var.starting_point)) + + try: + vars[var.name].starting_point = float(response) + print("Updated to %f." %(float(response))) + except ValueError: + print("The starting point must be a number.") + + elif response == "end": + response = input("Enter the variable's ending point (currently %f): " %(var.ending_point)) + + try: + vars[var.name].ending_point = float(response) + print("Updated to %f." %(float(response))) + except ValueError: + print("The ending point must be a number.") + + pass + + elif response == "q": + return + + else: + print('Invalid property "%s".' %(response)) + print('Commands are "type", "start" and "end".') + +def transform(object): + + if isinstance(object, expression.Expression) or isinstance(object, expression.Variable): + + return object.__dict__ + + else: + + raise TypeError("Only Books and Index will be JSON serialized!") + +exp = input("Enter the expression the student will use: ") +tokens = tokenizer.get_tokens_from_expression_string(exp) + +for t in tokens: + if t.type == token.TokenType.variable: + variables[t.value] = expression.Variable(t.value, expression.Variable.get_variable_type(t.value)) + +selected_variable = None + +while True: + print("Variables in expression:") + print_vars(variables) + response = input("Enter a variable name to modify its properties or continue (default): ") + + if response == "continue" or response == "": + break + + if response in variables: + selected_variable = variables[response] + + if selected_variable != None: + modify_variable(selected_variable, variables) + + else: + print("Invalid selection %s." %(response)) + continue + +with open("data.json", "w", encoding="utf-8") as f: + json.dump(expression.Expression(exp, variables), f, default=transform, indent = 4) diff --git a/json_generator/token.py b/json_generator/token.py new file mode 100755 index 0000000..879d829 --- /dev/null +++ b/json_generator/token.py @@ -0,0 +1,64 @@ +class CToken: + def __init__(self, value, type): + self.value = value + self.type = type + +class TokenType: + add = 0 + subtract = 1 + multiply = 2 + divide = 3 + power = 4 + variable = 5 + constant = 6 + exp_start = 7 + exp_end = 8 + unknown = 9 + + OPERATOR_VERBS = { + 0 : "Adding", + 1 : "Subtracting", + 2 : "Multiplying", + 3 : "Dividing", + 4 : "Raising" + } + + TOKEN_NAMES = { + 0 : "Addition", + 1 : "Subtraction", + 2 : "Multiplication", + 3 : "Division", + 4 : "Power", + 5 : "Variable", + 6 : "Constant", + 7 : "Expression Start", + 8 : "Expression End", + 9 : "Unknown" + } + + OPERATORS = { + '+' : add, + '-' : subtract, + '*' : multiply, + '^' : power, + '/' : divide + } + + @staticmethod + def get_operator_verb(token): + 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. + # + if not character in TokenType.OPERATORS: + return TokenType.unknown + return TokenType.OPERATORS[character] + + @staticmethod + def get_token_type_name(tokenType): + return TokenType.TOKEN_NAMES[tokenType] diff --git a/json_generator/tokenizer.py b/json_generator/tokenizer.py new file mode 100644 index 0000000..51e1aa6 --- /dev/null +++ b/json_generator/tokenizer.py @@ -0,0 +1,78 @@ +import 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). + + tokens = [] # List of objects of CToken class + tmp = "" + parsing_number = False + symbols_dic = {} # Dictionary to keep track of the no. of times each variable appears. + + for i in range(0, len(expression_string)): + c = expression_string[i] + if c == '.' or c.isdigit(): + if tmp.count('.') == 1: + raise SyntaxError("Invalid grammar, to many periods in number. Found at position " + str (i) + ".") + if len(tokens) > 1: + lookBehind = tokens[-1] + if lookBehind.type == token.TokenType.exp_end: + tokens.append(token.CToken("^", token.TokenType.power)) + if (i + 1) == len(expression_string): + tokens.append(token.CToken(tmp + c, token.TokenType.constant)) + parsing_number = True + tmp = tmp + c + continue + elif c == '(': + if parsing_number: + tokens.append(token.CToken(tmp, token.TokenType.constant)) + tokens.append(token.CToken("*", token.TokenType.multiply)) + tokens.append(token.CToken("(", token.TokenType.exp_start)) + parsing_number = False + tmp = "" + continue + elif c == ')': + if parsing_number: + tokens.append(token.CToken(tmp, token.TokenType.constant)) + tokens.append(token.CToken(")", token.TokenType.exp_end)) + parsing_number = False + tmp = "" + continue + elif token.TokenType.get_operator(c) != token.TokenType.unknown: + if parsing_number: + tokens.append(token.CToken(tmp, token.TokenType.constant)) + tokens.append(token.CToken(c, token.TokenType.get_operator(c))) + parsing_number = False + tmp = "" + continue + elif c != ' ': + if len(tokens) > 1: + lookBehind = tokens[-1] + if lookBehind.type == token.TokenType.exp_end: + tokens.append(token.CToken("^", token.TokenType.power)) + if (i + 1) < len(expression_string): + lookAHead = expression_string[i + 1] + if lookAHead == '(': + tokens.append(token.CToken(c, token.TokenType.variable)) + tokens.append(token.CToken("*", token.TokenType.multiply)) + tmp = "" + parsing_number = False + continue + if parsing_number: + tokens.append(token.CToken(tmp, token.TokenType.constant)) + tokens.append(token.CToken("*", token.TokenType.multiply)) + if c in symbols_dic.keys(): + symbols_dic[c] += 1 + else: + symbols_dic[c] = 1 + tokens.append(token.CToken(c + str(symbols_dic[c]), token.TokenType.variable)) + parsing_number = False + tmp = "" + #When building this list we've effectively ordered the tokens in reverse order from how we want to + #process them. So, reverse the order of the list before returning them to the caller, we don't want + #the caller to have to worry about such a minor detail. + tokens.reverse() + + return tokens + diff --git a/main.py b/main.py index 921da61..f1b4482 100755 --- a/main.py +++ b/main.py @@ -1,12 +1,17 @@ import token import tokenizer import calc_engine +import json -userInput = input('Enter your formula: ') -tokens = tokenizer.get_tokens_from_expression_string(userInput) -results = calc_engine.calculate_results(tokens) -print(results) +fileLocation = input('File Path to JSON: ') +#json = json.loads(open(fileLocation).read()) -#for t in tokens: -# print("%s (%s) " %(t.value, token.TokenType.get_token_type_name(t.type)), end = "") -#print() + +#userInput = input('Enter your formula: ') +tokens = tokenizer.get_tokens_from_expression_string("2 + 6 / 2") +#results = calc_engine.calculate_results(tokens.copy()) +#print(results) + +for t in tokens: + print("%s (%s) " %(t.value, token.TokenType.get_token_type_name(t.type)), end = "") +print()