Skip to content

Instantly share code, notes, and snippets.

@jatinsharrma
Last active July 1, 2020 17:28
Show Gist options
  • Save jatinsharrma/e64bfbe225d9d97d770873d4700e5765 to your computer and use it in GitHub Desktop.
Save jatinsharrma/e64bfbe225d9d97d770873d4700e5765 to your computer and use it in GitHub Desktop.
Mathematical Expression Evaluator : For Calculator Application
#--------------------------------------------------------------------
#--------------Mathematical Expresion Evaluater----------------------
#--------------------------------------------------------------------
'''Logic:
this program makes use of the operator precedence parser concept.
(An operator precedence parser is a Compiler Design Concept)
There are checkpoint you can uncomment those to see how code is running
It can try to delete wrong litreals and evaluate the expression. (You have to do some modification where literal function is called to make use of this feature)
You can uncomment the print statements to see where program is corrrecting epression.
'''
stack = [] # Main stack which saves all literals generated
numeral = False # If true : Seen Number/Decimal Previously else : Seen an Operator Previously
decimal = False # if true : Used decimal in current number else: no decimal used in current number
parflag = False # if true : Seen a closing bracket else : No closing bracket encountered
parCount = 0 # keep count of starting brackets. // Note : Not a full proof plan to check bracket matching
wrongFlag = False # If true : Means wrong expression else: expression is right
negativeFlag = False # if true we have seen a negative sign after an operator else no negative sign
# Evaluates the expression
def operatorPrecedence(a):
stack1 = ["$"]
stack2 = []
i = 0
if parCount == 0:
while i!= len(a):
#print(a[i],stack1,stack2)
if str(a[i]) not in "/+-*()":
stack2.append(float(a[i]))
else:
if a[i] == "(":
stack1.append(a[i])
elif a[i] == ")":
if "(" not in stack1 :
wrongFlag = True
return "Wrong"
if stack1[0] != "(":
while stack1[-1] != "(":
calculateAndDelete(a,stack1,stack2)
stack1.pop()
else:
previous = stack1[-1]
if precedence(previous,a[i]):
stack1.append(a[i])
else:
calculateAndDelete(a,stack1,stack2)
stack1.append(a[i])
i+=1
#print(stack2,stack1)
while len(stack1) > 1:
calculateAndDelete(a,stack1,stack2)
#print(stack2,stack1)
return stack2[-1] if stack2 else 0
else:
print("wrong")
wrongFlag = True
# Tell the precedence // Note here * and / are of same precedence. I haven't implemented Leght to right precedence
def precedence(op1,op2):
if op1 in "+-" and op2 in "*/":
return True
if op1 in "$(" and op2 in "+-*/":
return True
return False
# Calculated the sub expression and return to operatorPrecedence function
def operation(operant1, operant2, operator):
if operator == "*": return operant1 * operant2
if operator == "+": return operant1 + operant2
if operator == "-": return operant1 - operant2
if operator == "/": return operant1 / operant2
# Evalutes the smaller expresion using operation function and also pops out literals which are used to evaluate
def calculateAndDelete(a,b,c):
operant2 = c.pop()
operant1 = c.pop()
operator = b.pop()
c.append(operation(operant1, operant2, operator))
# Divides the input into the literals
def literals2(a):
global numeral
global stack
global parCount
global parflag
global decimal
global wrongFlag
global negativeFlag
if a:
# When we have seen no number or an operator and no closing bracket previously
if not(numeral or parflag):
if a == ("(") :
stack.append(a)
parCount += 1
elif a ==(")") and not parCount:
#print("wrong 1 ")
wrongFlag = True
elif a == ("-") and not negativeFlag:
stack.append(a)
numeral = True
negativeFlag = True
elif not (a in "+-*/)."):
stack.append(a)
numeral = True
parflag = False
negativeFlag = False
elif a == "." and not decimal:
stack.append("0.")
numeral = True
decimal = True
else:
#print("Wrong 2 ")
wrongFlag = True
# When we have seen one/more numeral or no operator and no closing bracket before
elif numeral and not parflag:
if a == ")" and parCount:
stack.append(a)
parflag = True
numeral = False
decimal = False
parCount -= 1
elif not (a in "-+/*()."):
stack.append(stack.pop() + a)
negativeFlag = False
elif a == "." and not decimal:
decimal = True
stack.append(stack.pop() + a)
elif a == "-" and negativeFlag:
pass
#print("Wrong 7")
elif a in "-+/*" and not negativeFlag:
stack.append(a)
numeral = False
parflag + False
decimal = False
else:
#print("wrong 3")
wrongFlag = True
# When we have not seen any numeral or an operator and closing bracket
elif not numeral and parflag:
if a in "+-*/":
stack.append(a)
parflag = False
elif a == ")" and parCount:
parCount -= 1
stack.append(a)
else:
#print("wrong 4")
wrongFlag = True
#print(numeral,parflag,negativeFlag)
else:
#print("Wrong 5")
wrongFlag = True
# just a calling function
a = "--11++(-2)+3"
for i in a:
literals2(i)
# if wrongFlag == True:
# break
print(stack)
if (numeral or parflag) and not wrongFlag:
print(operatorPrecedence(stack))
else:
print("Wrong 6")
#---------------------------------------------------------------------
#-------------Sample Output with checkpoint uncommented---------------
#---------------------------------------------------------------------
'''
Finding literals
True False
['1']
False False
['1', '+']
True False
['1', '+', '1']
True False
['1', '+', '11']
False False
['1', '+', '11', '+']
False False
['1', '+', '11', '+', '(']
True False
['1', '+', '11', '+', '(', '1']
False True
['1', '+', '11', '+', '(', '1', ')']
Evalutaing Expression
1 ['$'] []
+ ['$'] [1.0]
11 ['$', '+'] [1.0]
+ ['$', '+'] [1.0, 11.0]
( ['$', '+'] [12.0]
1 ['$', '+', '('] [12.0]
) ['$', '+', '('] [12.0, 1.0]
[12.0, 1.0] ['$', '+']
[13.0] ['$']
13.0
'''
#-----------------------------------------------------------------
#------------Just a initial try for finding literals -------------
#------------------It do not work with decimals-------------------
#-----------------------------------------------------------------
#operator = False
# def literals(a):
# global stack
# global operator
# global numeral
# global parCount
# global parflag
# if operator == False and numeral == False:
# if a == "(":
# stack.append(a)
# parCount += 1
# elif a not in "/+*" and not parflag:
# stack.append(a)
# numeral = True
# parflag = False
# elif a == ")" and parflag and parCount:
# stack.append(a)
# parflag = True
# parCount -= 1
# elif a in "+-/*" and parflag:
# stack.append(a)
# operator = True
# else:
# print("wrong expression")
# elif numeral == True and operator == False:
# if parCount and a ==")":
# stack.append(a)
# numeral = False
# parflag = True
# parCount -= 1
# elif parCount == 0 and a == ")":
# print("wrong")
# elif a == "(":
# print("wromg")
# elif a not in "/+-*":
# stack.append(stack.pop() + a)
# numeral = True
# else:
# stack.append(a)
# numeral = False
# operator = True
# parflag = False
# elif numeral == False and operator == True:
# if a == "(":
# stack.append(a)
# parCount += 1
# elif a == ")":
# print("wrong")
# elif a not in "/+*":
# stack.append(a)
# numeral = True
# operator = False
# parflag =True
# else :
# print("wrong expression")
# #print(operatorPrecedence([1,"+","(",3,"*",4,")"]))
# #print(operatorPrecedence([1, "*", ")",3, ")","+",5,"(" ,")","/",4]))
# print(operatorPrecedence([1, "*",3, "+","(",5,"*" ,6,")","/",4]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment