Compare commits
10 Commits
88902d9066
...
master
Author | SHA1 | Date | |
---|---|---|---|
d5f0c95c8c | |||
40f51658d8 | |||
5efb58b226 | |||
716dbac01f | |||
516e917086 | |||
87f5c49bbb | |||
a7bd4f6c6e | |||
7793c49f1c | |||
1e28a6f756 | |||
1caf8044ff |
@@ -20,5 +20,5 @@ The reason I chose to do this, is that my parsing algorithm considers everything
|
|||||||
- Simple error checking
|
- Simple error checking
|
||||||
|
|
||||||
## To-do
|
## To-do
|
||||||
- Simple algebraic parsing (assign values to variables, etc.)
|
- ~~Simple algebraic parsing (assign values to variables, etc.)~~
|
||||||
- More robust error-checking
|
- More robust error-checking
|
||||||
|
114
calculator.py
114
calculator.py
@@ -1,11 +1,51 @@
|
|||||||
|
"""
|
||||||
|
===============================================================================
|
||||||
|
ENGR 13300 Fall 2023
|
||||||
|
|
||||||
|
Program Description
|
||||||
|
An algebraic expression calculator. This program can evaluate expressions, assign values to variables, and use variables in additional expressions.
|
||||||
|
|
||||||
|
The program consists of three main parts:
|
||||||
|
1. Parsing the expression. This is accomplished using the 'parse' function, defined in parse.py. The expression is parsed, and a list of 'tokens' is produced, with each token bein a part of the expression. For example '5 + 7 * 3' is parsed into '['5', '+', '7', '*', '3'].
|
||||||
|
2. Find the inner-most expression. This only applies to expressions that have parantheses. The 'find_inner' function is called recursively, until the inner expression is found. For example, given the expression '3 + (7 * (4 + 8))', the 'find_inner' function is called once, to produce '7 * (4 + 8)', and then called again, to produce '4 + 8'.
|
||||||
|
3. Evaluate the expression. The 'evaluate' function searches for operators, and then evaluates the operator with the preceding and succeeding token (if one of the tokens is a variable, the value of the variable replaces the variable). The result of the evaluation replaces the expression. Example: Given the expression '3 + (7 * (4 + 8))', the inner expression is evaluated first. This produces '3 + (7 * 12)'. The inner expression is evaluated again, producing '3 + 84'. Finally, the rest of the expression is evaluated, to produce 87.
|
||||||
|
4. If the expression consists of an assignment, the evaluated expression is stored into the variable on the left. The list of variables is maintained as a dictionary.
|
||||||
|
|
||||||
|
Assignment Information
|
||||||
|
Assignment: Individual Project
|
||||||
|
Author: Aadhavan Srinivasan, srini193@purdue.edu
|
||||||
|
Team ID: LC3 - 19
|
||||||
|
|
||||||
|
|
||||||
|
Contributor: Name, login@purdue [repeat for each]
|
||||||
|
My contributor(s) helped me:
|
||||||
|
[ ] understand the assignment expectations without
|
||||||
|
telling me how they will approach it.
|
||||||
|
[ ] understand different ways to think about a solution
|
||||||
|
without helping me plan my solution.
|
||||||
|
[ ] think through the meaning of a specific error or
|
||||||
|
bug present in my code without looking at my code.
|
||||||
|
Note that if you helped somebody else with their code, you
|
||||||
|
have to list that person as a contributor here as well.
|
||||||
|
|
||||||
|
ACADEMIC INTEGRITY STATEMENT
|
||||||
|
I have not used source code obtained from any other unauthorized
|
||||||
|
source, either modified or unmodified. Neither have I provided
|
||||||
|
access to my code to another. The project I am submitting
|
||||||
|
is my own original work.
|
||||||
|
===============================================================================
|
||||||
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from parse import *
|
from parse import *
|
||||||
|
|
||||||
# List of valid operators
|
# List of valid operators
|
||||||
opers = ['+', '-', '*', '/']
|
opers = ['+', '-', '*', '/', '=']
|
||||||
|
|
||||||
# Regular expression that checks for valid characters in an expression
|
# Regular expression that checks for valid characters in an expression
|
||||||
valid_chars = '[ 0-9.\(\)+-\/*]'
|
valid_chars = '[ 0-9a-z.\(\)+-\/*=]'
|
||||||
|
|
||||||
|
variables = {}
|
||||||
|
|
||||||
def print_error(error_code):
|
def print_error(error_code):
|
||||||
|
|
||||||
@@ -24,8 +64,18 @@ def print_error(error_code):
|
|||||||
print("You have two operators next to each other.")
|
print("You have two operators next to each other.")
|
||||||
case 4:
|
case 4:
|
||||||
print("One of your values is improperly formatted.")
|
print("One of your values is improperly formatted.")
|
||||||
|
case 5:
|
||||||
|
print("Uninitialized variable.")
|
||||||
|
case 6:
|
||||||
|
print("Invalid expression.")
|
||||||
|
|
||||||
|
print("")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
def check_errors(expr):
|
def check_errors(expr):
|
||||||
|
|
||||||
|
# Check for errors before parsing the expression
|
||||||
expr_small = expr.replace(" ", "") # Remove spaces from the string, to make it easier to parse
|
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
|
# Check if number of opening parantheses is equal to number of closing parantheses
|
||||||
@@ -52,10 +102,17 @@ def check_errors(expr):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Check for errors after parsing the expression
|
||||||
expr = parse(expr)
|
expr = parse(expr)
|
||||||
|
|
||||||
|
if expr[0].isalpha() and (len(expr) == 1 or expr[1] != '='): # If you just have an expression with a letter eg. 'x', or you use a variable without an assignment (e.g. 'x 5')
|
||||||
|
return 6
|
||||||
|
|
||||||
for val in expr:
|
for val in expr:
|
||||||
if val.count('.') > 1:
|
if val.count('.') > 1: # A value can have at most 1 period
|
||||||
return 4
|
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
|
return 0
|
||||||
|
|
||||||
@@ -64,7 +121,13 @@ def evaluate(subexpr): # Evaluate a tokenized expression, that contains no paran
|
|||||||
|
|
||||||
subexpr = [element for element in subexpr if element != ''] # Remove empty characters in the expression
|
subexpr = [element for element in subexpr if element != ''] # Remove empty characters in the expression
|
||||||
|
|
||||||
print(subexpr)
|
# 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):
|
if (len(subexpr) == 1):
|
||||||
return float(subexpr[0])
|
return float(subexpr[0])
|
||||||
@@ -79,23 +142,24 @@ def evaluate(subexpr): # Evaluate a tokenized expression, that contains no paran
|
|||||||
subexpr[index] = float(subexpr[index-1]) * float(subexpr[index+1])
|
subexpr[index] = float(subexpr[index-1]) * float(subexpr[index+1])
|
||||||
subexpr[index-1] = ''
|
subexpr[index-1] = ''
|
||||||
subexpr[index+1] = ''
|
subexpr[index+1] = ''
|
||||||
elif '+' in subexpr:
|
elif '+' in subexpr or '-' in subexpr: # Addition and subtraction have the same precedence
|
||||||
index = subexpr.index('+')
|
index_plus, index_minus = float('inf'), float('inf') # Set both values to infinity
|
||||||
subexpr[index] = float(subexpr[index-1]) + float(subexpr[index+1])
|
if '+' in subexpr:
|
||||||
subexpr[index-1] = ''
|
index_plus = subexpr.index('+')
|
||||||
subexpr[index+1] = ''
|
if '-' in subexpr:
|
||||||
elif '-' in subexpr:
|
index_minus = subexpr.index('-')
|
||||||
index = subexpr.index('-')
|
|
||||||
subexpr[index] = float(subexpr[index-1]) - float(subexpr[index+1])
|
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] = ''
|
||||||
subexpr[index+1] = ''
|
subexpr[index+1] = ''
|
||||||
|
|
||||||
print(subexpr)
|
# print(subexpr)
|
||||||
|
|
||||||
return evaluate(subexpr)
|
return evaluate(subexpr)
|
||||||
|
|
||||||
def find_inner(subexpr):
|
def find_inner(subexpr):
|
||||||
print("expr: " + subexpr)
|
# print("expr: " + subexpr)
|
||||||
|
|
||||||
subexpr = parse(subexpr)
|
subexpr = parse(subexpr)
|
||||||
|
|
||||||
@@ -105,7 +169,7 @@ def find_inner(subexpr):
|
|||||||
|
|
||||||
|
|
||||||
subexpr_string = ''.join(subexpr)
|
subexpr_string = ''.join(subexpr)
|
||||||
print("New expr: " + subexpr_string)
|
# print("New expr: " + subexpr_string)
|
||||||
if not '(' in subexpr_string and not ')' in subexpr_string:
|
if not '(' in subexpr_string and not ')' in subexpr_string:
|
||||||
return str(evaluate(subexpr))
|
return str(evaluate(subexpr))
|
||||||
|
|
||||||
@@ -113,12 +177,30 @@ def find_inner(subexpr):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
while True:
|
while True:
|
||||||
|
variable = ''
|
||||||
expr = input()
|
expr = input()
|
||||||
errno = check_errors(expr)
|
errno = check_errors(expr)
|
||||||
if errno != 0:
|
if errno != 0:
|
||||||
print_error(errno)
|
print_error(errno)
|
||||||
continue # If an error was generated, print an error message and continue on to the next iteration of the loop
|
continue # If an error was generated, print an error message and continue on to the next iteration of the loop
|
||||||
expr = find_inner(expr)
|
|
||||||
|
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(expr)
|
||||||
|
if (len(variables) > 0):
|
||||||
|
print(variables)
|
||||||
|
print("")
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
49
parse.py
49
parse.py
@@ -1,6 +1,36 @@
|
|||||||
|
"""
|
||||||
|
===============================================================================
|
||||||
|
ENGR 13300 Fall 2023
|
||||||
|
|
||||||
|
Program Description
|
||||||
|
This is the function that parses the expression. It goes through the expression, and produces a list of 'tokens', where each token represents a part of the expression. For example, '3 + 2' would yield the tokens '3', '+' and '2'. It then returns the list of tokens.
|
||||||
|
Assignment Information
|
||||||
|
Assignment: Individual Project
|
||||||
|
Author: Aadhavan Srinivasan, srini193@purdue.edu
|
||||||
|
Team ID: LC3 - 19
|
||||||
|
|
||||||
|
|
||||||
|
Contributor: Name, login@purdue [repeat for each]
|
||||||
|
My contributor(s) helped me:
|
||||||
|
[ ] understand the assignment expectations without
|
||||||
|
telling me how they will approach it.
|
||||||
|
[ ] understand different ways to think about a solution
|
||||||
|
without helping me plan my solution.
|
||||||
|
[ ] think through the meaning of a specific error or
|
||||||
|
bug present in my code without looking at my code.
|
||||||
|
Note that if you helped somebody else with their code, you
|
||||||
|
have to list that person as a contributor here as well.
|
||||||
|
|
||||||
|
ACADEMIC INTEGRITY STATEMENT
|
||||||
|
I have not used source code obtained from any other unauthorized
|
||||||
|
source, either modified or unmodified. Neither have I provided
|
||||||
|
access to my code to another. The project I am submitting
|
||||||
|
is my own original work.
|
||||||
|
===============================================================================
|
||||||
|
"""
|
||||||
def parse(expr):
|
def parse(expr):
|
||||||
|
|
||||||
opers = ['+', '-', '*', '/']
|
opers = ['+', '-', '*', '/', '=']
|
||||||
|
|
||||||
num_par = 0
|
num_par = 0
|
||||||
tokenized = []
|
tokenized = []
|
||||||
@@ -9,19 +39,19 @@ def parse(expr):
|
|||||||
while index < len(expr):
|
while index < len(expr):
|
||||||
if expr[index] in opers:
|
if expr[index] in opers:
|
||||||
tokenized.append(expr[index])
|
tokenized.append(expr[index])
|
||||||
|
index += 1
|
||||||
|
|
||||||
elif expr[index].isdigit() or expr[index] == '.':
|
elif expr[index].isdigit() or expr[index] == '.':
|
||||||
while (index < len(expr)) and (expr[index].isdigit() or expr[index] == '.'):
|
while (index < len(expr)) and (expr[index].isdigit() or expr[index] == '.'):
|
||||||
temp_string += expr[index]
|
temp_string += expr[index]
|
||||||
index += 1
|
index += 1
|
||||||
tokenized.append(temp_string)
|
tokenized.append(temp_string)
|
||||||
temp_string = ""
|
|
||||||
|
|
||||||
elif expr[index] == '(':
|
elif expr[index] == '(':
|
||||||
num_par = 1
|
num_par = 1
|
||||||
temp_string += expr[index]
|
temp_string += expr[index]
|
||||||
index += 1
|
index += 1
|
||||||
while num_par != 0 and index < len(expr):
|
while index < len(expr) and num_par != 0:
|
||||||
temp_string += expr[index]
|
temp_string += expr[index]
|
||||||
if expr[index] == '(':
|
if expr[index] == '(':
|
||||||
num_par += 1
|
num_par += 1
|
||||||
@@ -30,9 +60,18 @@ def parse(expr):
|
|||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
tokenized.append(temp_string)
|
tokenized.append(temp_string)
|
||||||
temp_string = ""
|
|
||||||
|
|
||||||
|
elif expr[index].isalpha(): # If you encounter a variable
|
||||||
|
temp_string += expr[index]
|
||||||
|
index += 1
|
||||||
|
while index < len(expr) and expr[index].isalpha():
|
||||||
|
temp_string += expr[index]
|
||||||
|
index += 1
|
||||||
|
tokenized.append(temp_string)
|
||||||
|
|
||||||
index += 1
|
else:
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
temp_string = ""
|
||||||
|
|
||||||
return tokenized
|
return tokenized
|
||||||
|
4
todo.txt
4
todo.txt
@@ -1,3 +1,3 @@
|
|||||||
1. Implement variable assignment e.g. x = 5
|
----DONE---- 1. Implement variable assignment e.g. x = 5
|
||||||
2. ALlow these variables to be used in future expressions
|
----DONE---- 2. Allow these variables to be used in future expressions
|
||||||
3. Implement additional error-checking
|
3. Implement additional error-checking
|
||||||
|
Reference in New Issue
Block a user