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 :
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 ] = ' '
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 ( )