import re from parse import * # List of valid operators opers = ['+', '-', '*', '/', '='] # Regular expression that checks for valid characters in an expression valid_chars = '[ 0-9a-z.\(\)+-\/*=]' variables = {} def print_error(error_code): # List of error codes: # 1 - Invalid characters found in expression # 2 - Unclosed parantheses # 3 - Two operators next to each other # 4 - Wrong number formatting (multiple periods) match error_code: case 1: print("You have invalid characters in your expression.") case 2: print("You have an unclosed parantheses in your expression.") case 3: print("You have two operators next to each other.") case 4: print("One of your values is improperly formatted.") case 5: print("Uninitialized variable.") def check_errors(expr): expr_small = expr.replace(" ", "") # Remove spaces from the string, to make it easier to parse # Check if number of opening parantheses is equal to number of closing parantheses num_open_pars = 0 num_close_pars = 0 for index,val in enumerate(expr_small): if not re.match(valid_chars, val): return 1 num_open_pars = num_open_pars+1 if val == '(' else num_open_pars num_close_pars = num_close_pars+1 if val == ')' else num_close_pars if val in opers: if expr_small[index + 1] in opers: # Two consecutive operators return 3 if val == '.': if not expr_small[index + 1].isdigit(): # If you have a period, you must have a number after it return 4 if num_open_pars != num_close_pars: return 2 expr = parse(expr) for val in expr: if val.count('.') > 1: # A value can have at most 1 period return 4 if val.isalpha() and not val in variables and val != expr[0]: # If the token is a string, and isn't in the dictionary, and isn't the variable at index 0 (e.g. 'x' in 'x = 4') return 5 return 0 def evaluate(subexpr): # Evaluate a tokenized expression, that contains no parantheses subexpr = [element for element in subexpr if element != ''] # Remove empty characters in the expression print(subexpr) for index, val in enumerate(subexpr): # Replace variables with their values if str(val).isalpha(): subexpr[index] = variables[val] print(subexpr) if (len(subexpr) == 1): return float(subexpr[0]) if '/' in subexpr: index = subexpr.index('/') subexpr[index] = float(subexpr[index-1]) / float(subexpr[index+1]) subexpr[index-1] = '' subexpr[index+1] = '' elif '*' in subexpr: index = subexpr.index('*') subexpr[index] = float(subexpr[index-1]) * float(subexpr[index+1]) subexpr[index-1] = '' subexpr[index+1] = '' elif '+' in subexpr or '-' in subexpr: # Addition and subtraction have the same precedence index_plus, index_minus = float('inf'), float('inf') # Set both values to infinity if '+' in subexpr: index_plus = subexpr.index('+') if '-' in subexpr: index_minus = subexpr.index('-') index = index_plus if index_plus < index_minus else index_minus # Set the index to the index of the operator that occurs first subexpr[index] = float(subexpr[index-1]) + float(subexpr[index+1]) if index_plus < index_minus else float(subexpr[index-1]) - float(subexpr[index+1]) # If addition occured first, add the previous and next tokens. If subtraction occured first, subtract them. subexpr[index-1] = '' subexpr[index+1] = '' print(subexpr) return evaluate(subexpr) def find_inner(subexpr): print("expr: " + subexpr) subexpr = parse(subexpr) for index,val in enumerate(subexpr): if '(' in val or ')' in val: subexpr[index] = find_inner(val[1:len(val)-1]) subexpr_string = ''.join(subexpr) print("New expr: " + subexpr_string) if not '(' in subexpr_string and not ')' in subexpr_string: return str(evaluate(subexpr)) def main(): while True: variable = '' expr = input() errno = check_errors(expr) if errno != 0: print_error(errno) continue # If an error was generated, print an error message and continue on to the next iteration of the loop expr_tokenized = parse(expr) if expr_tokenized[0].isalpha() and expr_tokenized[1] == '=': # If the expression assigns a value to a variable variable = expr_tokenized[0] # The first token is the variable expr_tokenized.pop(0) # Remove the first and second tokens expr_tokenized.pop(0) expr = find_inner(''.join(expr_tokenized)) variables.update({variable: expr}) else: expr = find_inner(expr) print(expr) print(variables) main()