# SimpleCalc.py
#
# Demonstration of the parsing module,
# Sample usage
#
# $ python SimpleCalc.py
# Type in the string to be parse or 'quit' to exit the program
# > g=67.89 + 7/5
# 69.29
# > g
# 69.29
# > h=(6*g+8.8)-g
# 355.25
# > h + 1
# 356.25
# > 87.89 + 7/5
# 89.29
# > ans+10
# 99.29
# > quit
# Good bye!
#
#
from __future__ import division
# Uncomment the line below for readline support on interactive terminal
# import readline
import re
from pyparsing import Word,alphas,ParseException,Literal,CaselessLiteral\
, Combine, Optional, nums, Or, Forward, ZeroOrMore, StringEnd, alphanums
import math
# Debugging flag can be set to either "debug_flag=True" or "debug_flag=False"
debug_flag=False
exprStack = []
varStack = []
variables = {}
def pushFirst( str, loc, toks ):
exprStack.append( toks[0] )
def assignVar( str, loc, toks ):
varStack.append( toks[0] )
# define grammar
point = Literal('.')
e = CaselessLiteral('E')
plusorminus = Literal('+') | Literal('-')
number = Word(nums)
integer = Combine( Optional(plusorminus) + number )
floatnumber = Combine( integer +
Optional( point + Optional(number) ) +
Optional( e + integer )
)
ident = Word(alphas,alphanums + '_')
plus = Literal( "+" )
minus = Literal( "-" )
mult = Literal( "*" )
div = Literal( "/" )
lpar = Literal( "(" ).suppress()
rpar = Literal( ")" ).suppress()
addop = plus | minus
multop = mult | div
expop = Literal( "^" )
assign = Literal( "=" )
expr = Forward()
atom = ( ( e | floatnumber | integer | ident ).setParseAction(pushFirst) |
( lpar + expr.suppress() + rpar )
)
factor = Forward()
factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( pushFirst ) )
term = factor + ZeroOrMore( ( multop + factor ).setParseAction( pushFirst ) )
expr << term + ZeroOrMore( ( addop + term ).setParseAction( pushFirst ) )
bnf = Optional((ident + assign).setParseAction(assignVar)) + expr
pattern = bnf + StringEnd()
# map operator symbols to corresponding arithmetic operations
opn = { "+" : ( lambda a,b: a + b ),
"-" : ( lambda a,b: a - b ),
"*" : ( lambda a,b: a * b ),
"/" : ( lambda a,b: a / b ),
"^" : ( lambda a,b: a ** b ) }
# Recursive function that evaluates the stack
def evaluateStack( s ):
op = s.pop()
if op in "+-*/^":
op2 = evaluateStack( s )
op1 = evaluateStack( s )
return opn[op]( op1, op2 )
elif op == "PI":
return math.pi
elif op == "E":
return math.e
elif re.search('^[a-zA-Z][a-zA-Z0-9_]*$',op):
if variables.has_key(op):
return variables[op]
else:
return 0
elif re.search('^[-+]?[0-9]+$',op):
return long( op )
else:
return float( op )
if __name__ == '__main__':
# input_string
input_string=''
# Display instructions on how to quit the program
print "Type in the string to be parse or 'quit' to exit the program"
input_string = raw_input("> ")
while input_string != 'quit':
# Start with a blank exprStack and a blank varStack
exprStack = []
varStack = []
if input_string != '':
# try parsing the input string
try:
L=pattern.parseString( input_string )
except ParseException,err:
L=['Parse Failure',input_string]
# show result of parsing the input string
if debug_flag: print input_string, "->", L
if len(L)==0 or L[0] != 'Parse Failure':
if debug_flag: print "exprStack=", exprStack
# calculate result , store a copy in ans , display the result to user
result=evaluateStack(exprStack)
variables['ans']=result
print result
# Assign result to a variable if required
if debug_flag: print "var=",varStack
if len(varStack)==1:
variables[varStack.pop()]=result
if debug_flag: print "variables=",variables
else:
print 'Parse Failure'
print err.line
print " "*(err.column-1) + "^"
print err
# obtain new input string
input_string = raw_input("> ")
# if user type 'quit' then say goodbye
print "Good bye!"
|