Created a small utility program to generate JSON files for testing the main input.
This commit is contained in:
@@ -55,7 +55,6 @@ class Factor:
|
|||||||
print(self.complex_four)
|
print(self.complex_four)
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
|
||||||
def clear_factors_lists(self):
|
def clear_factors_lists(self):
|
||||||
self.simple_one = []
|
self.simple_one = []
|
||||||
self.simple_two = []
|
self.simple_two = []
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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]
|
||||||
@@ -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)
|
||||||
Executable
+64
@@ -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]
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -1,12 +1,17 @@
|
|||||||
import token
|
import token
|
||||||
import tokenizer
|
import tokenizer
|
||||||
import calc_engine
|
import calc_engine
|
||||||
|
import json
|
||||||
|
|
||||||
userInput = input('Enter your formula: ')
|
fileLocation = input('File Path to JSON: ')
|
||||||
tokens = tokenizer.get_tokens_from_expression_string(userInput)
|
#json = json.loads(open(fileLocation).read())
|
||||||
results = calc_engine.calculate_results(tokens)
|
|
||||||
print(results)
|
|
||||||
|
|
||||||
#for t in tokens:
|
|
||||||
# print("%s (%s) " %(t.value, token.TokenType.get_token_type_name(t.type)), end = "")
|
#userInput = input('Enter your formula: ')
|
||||||
#print()
|
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()
|
||||||
|
|||||||
Reference in New Issue
Block a user