import math ;

import string ;

import pickle ;

from otherFuncs import *

import random

trigfuncs = { "sin" : math . sin , "cos" : math . cos , "tan" : math . tan ,

"csc" : csc , "sec" : sec , "cot" : cot } ;

basicOps = { "+" : "plus" , "-" : "minus" , "*" : "multiplied by" , "/" : "divided by" } ;

miscOps = { "^" : "to the power of" , "trigfuncs" : trigfuncs ,

"log" : math . log10 , "sqrt" : math . sqrt ,

"(" : "pOn" , ")" : "pOff" , "neg" : neg } ;

allOps = [ basicOps , trigfuncs , miscOps ] ;

allDigits = list ( string . digits ) ;

commonVars = [ "x" , "y" , "z" ] ;

def parse ( func ) :

parsedFunc = [ ] ;

testStr = "" ;

func = func. replace ( " " , "_" ) ;

for part in func:

maxI = len ( parsedFunc ) - 1 ;

if part == "_" :

continue ;

#numbers in ints and floats are split up, so combine them for final product

if part in allDigits or part == "." :

#print("testing: %s" % part)

if len ( parsedFunc ) > 0 and parsedFunc [ maxI ] [ 0 ] in allDigits:

prevPart = parsedFunc. pop ( maxI ) ;

newPart = prevPart + part ;

parsedFunc. append ( newPart ) ;

else :

parsedFunc. append ( part ) ;

continue ;

#deals with variables

elif part in commonVars:

if len ( parsedFunc ) > 0 and parsedFunc [ maxI ] [ 0 ] in allDigits:

parsedFunc. append ( "*" ) ;

parsedFunc. append ( part ) ;

continue ;

for op in allOps:

if part in op:

parsedFunc. append ( part )

#parsedFunc.append(op[part]);

#print("appended: %s" % part)

testStr = ""

continue ;

else :

continue ;

#checks to see if part of func is smaller part of a math function

if part not in allOps [ 0 ] and part not in allOps [ 1 ] and part not in allOps [ 2 ] :

testStr = testStr. rstrip ( "" ) ;

testStr + = part ;

#print("Testing string: %s" % testStr);

for op in allOps:

if testStr in op and len ( testStr ) > 1 :

#print("appending: %s" % testStr);

parsedFunc. append ( testStr ) ;

testStr = "" ;

continue ;

"""while "neg" in parsedFunc:

print(parsedFunc)

i = parsedFunc.index("neg")

num = parsedFunc[i+1]

if isInt(num):

num = str(-1*int(num))

elif isFloat(num):

num = str(-1*float(num))

elif parsedFunc.count("neg") == 1:

break

print(num)

parsedFunc[i] = num

parsedFunc.pop(i+1)

print(parsedFunc)"""

#print(parsedFunc);

return parsedFunc ;

#a = parse("neg(sqrt(sin(x)))+17.12x");

#print(a);

def doOp ( func ) :

operand1 = func [ 0 ]

op = func [ 1 ]

operand2 = func [ 2 ]

if op == '+' :

return operand1 + operand2

elif op == '-' :

return operand1 - operand2

elif op == '*' :

return operand1 * operand2

elif op == '/' :

return operand1 / operand2

else :

print ( "Op not identified: %s" % op )

def findSpecFunc ( f ) :

sfList = [ ]

for i in range ( len ( f ) ) :

char = f [ i ]

if char in trigfuncs or char in miscOps:

sfList. append ( i )

return sfList

def pemdas ( func ) :

if type ( func ) != type ( [ ] ) :

func = list ( func )

op = [ ]

ops = [ ]

result = "SYNTAX_ERROR"

#turn parentheses and exponents into numbers

while "(" in func:

#get interval that is inside parentheses

start = func. index ( "(" )

end = func. index ( ")" )

testFunc = func [ start+ 1 :end ]

#if in the interval the amount of open p and close p isn't equal

#keep expanding interval until it is

while testFunc. count ( "(" ) != testFunc. count ( ")" ) :

newEnd = func [ end+ 1 : ] . index ( ")" ) + end + 1

end = newEnd

testFunc = func [ start+ 1 :newEnd ]

#put result where open parentheses was and delete everything that was there

func [ start ] = str ( pemdas ( testFunc ) )

del func [ start+ 1 :end+ 1 ]

while "^" in func:

start = func. index ( "^" ) - 1

end = func. index ( "^" ) + 1

if isInt ( func [ start ] ) :

base = int ( func [ start ] )

elif isFloat ( func [ start ] ) :

base = float ( func [ start ] )

if isInt ( func [ end ] ) :

exp = int ( func [ end ] )

elif isFloat ( func [ end ] ) :

exp = float ( func [ end ] )

func [ start ] = str ( ( base ) **exp )

del func [ start+ 1 :end+ 1 ]

#turning "special" functions into numbers

#get indices of all special functions in func

sfIndexes = findSpecFunc ( func )

#print(sfIndexes)

#print("func: ", func)

for i in sfIndexes:

sf = func [ i ]

#print(i+1)

#print("len ", len(func))

operand = func [ i+ 1 ]

if isInt ( operand ) :

operand = int ( operand )

elif isFloat ( operand ) :

operand = float ( operand )

try :

result = str ( trigfuncs [ sf ] ( operand ) )

except :

result = str ( miscOps [ sf ] ( operand ) )

func [ i ] = result

del func [ i+ 1 ]

#decrement indices in list since an item was removed

for i in range ( len ( sfIndexes ) ) :

n = sfIndexes [ i ]

sfIndexes [ i ] = n - 1

#returns value of func immediately if it is only one int or float

if len ( func ) == 1 :

if isInt ( func [ 0 ] ) :

return int ( func [ 0 ] )

elif isFloat ( func [ 0 ] ) :

return float ( func [ 0 ] )

else :

return "SYNTAX_ERROR"

#once all that stuff is cleared, cover the MDAS part of PEMDAS

for i in range ( len ( func ) ) :

char = func [ i ]

if isInt ( char ) :

op. append ( int ( char ) )

elif isFloat ( char ) :

op. append ( float ( char ) )

elif char in list ( basicOps. keys ( ) ) :

#check ahead to see if there is another op

if len ( func ) - 1 >= i+ 2 :

currentOp = char

nextOp = func [ i+ 2 ]

#only 2 conditions where we need to evaluate op higher in hierarchy

if currentOp == "+" and nextOp in ( "*" , "/" ) or currentOp == "-" and nextOp in ( "*" , "/" ) :

#put the + or - in op, append op to ops, then clear op and evaluate again

op. append ( currentOp )

ops. append ( op )

op = [ ]

else :

op. append ( currentOp )

else :

op. append ( char )

continue

#true if there are two numbers and a func

if len ( op ) == 3 :

result = doOp ( op )

#Check and see if there is an op that needs to finish

if len ( ops ) > 0 :

#Look ahead and see if there are other operations higher in hierarchy

if len ( func ) - 1 >= i+ 2 :

#If so, make op = result and keep going

if ops [ - 1 ] [ 1 ] in ( "+" , "-" ) and func [ i+ 1 ] in ( "*" , "/" ) :

op = [ result ]

continue

#Append result to ops otherwise, and run doOp again to get new result

else :

ops [ - 1 ] . append ( result )

result = doOp ( ops [ - 1 ] )

#remove op from ops when done

ops. remove ( ops [ - 1 ] )

op = [ result ]

return result

import time

f = "0 + cos(1^1^1) + " * 1000 + "0"

start = time . time ( )

a = pemdas ( parse ( f ) )

print ( "Took " , time . time ( ) - start , "seconds" )