Created
December 9, 2013 19:08
-
-
Save zg/7878924 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import division | |
from pyparsing import (Literal,CaselessLiteral,Word,Combine,Group,Optional, | |
ZeroOrMore,Forward,nums,alphas,oneOf) | |
import math | |
import operator | |
__author__='Paul McGuire' | |
__version__ = '$Revision: 0.0 $' | |
__date__ = '$Date: 2009-03-20 $' | |
__source__='''http://pyparsing.wikispaces.com/file/view/fourFn.py | |
http://pyparsing.wikispaces.com/message/view/home/15549426 | |
''' | |
__note__=''' | |
All I've done is rewrap Paul McGuire's fourFn.py as a class, so I can use it | |
more easily in other places. | |
''' | |
class NumericStringParser(object): | |
''' | |
Most of this code comes from the fourFn.py pyparsing example | |
''' | |
def pushFirst(self, strg, loc, toks ): | |
self.exprStack.append( toks[0] ) | |
def pushUMinus(self, strg, loc, toks ): | |
if toks and toks[0]=='-': | |
self.exprStack.append( 'unary -' ) | |
def __init__(self): | |
""" | |
expop :: '^' | |
multop :: '*' | '/' | |
addop :: '+' | '-' | |
integer :: ['+' | '-'] '0'..'9'+ | |
atom :: PI | E | real | fn '(' expr ')' | '(' expr ')' | |
factor :: atom [ expop factor ]* | |
term :: factor [ multop factor ]* | |
expr :: term [ addop term ]* | |
""" | |
point = Literal( "." ) | |
e = CaselessLiteral( "E" ) | |
fnumber = Combine( Word( "+-"+nums, nums ) + | |
Optional( point + Optional( Word( nums ) ) ) + | |
Optional( e + Word( "+-"+nums, nums ) ) ) | |
ident = Word(alphas, alphas+nums+"_$") | |
plus = Literal( "+" ) | |
minus = Literal( "-" ) | |
mult = Literal( "*" ) | |
div = Literal( "/" ) | |
lpar = Literal( "(" ).suppress() | |
rpar = Literal( ")" ).suppress() | |
addop = plus | minus | |
multop = mult | div | |
expop = Literal( "^" ) | |
pi = CaselessLiteral( "PI" ) | |
expr = Forward() | |
atom = ((Optional(oneOf("- +")) + | |
(pi|e|fnumber|ident+lpar+expr+rpar).setParseAction(self.pushFirst)) | |
| Optional(oneOf("- +")) + Group(lpar+expr+rpar) | |
).setParseAction(self.pushUMinus) | |
# by defining exponentiation as "atom [ ^ factor ]..." instead of | |
# "atom [ ^ atom ]...", we get right-to-left exponents, instead of left-to-right | |
# that is, 2^3^2 = 2^(3^2), not (2^3)^2. | |
factor = Forward() | |
factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( self.pushFirst ) ) | |
term = factor + ZeroOrMore( ( multop + factor ).setParseAction( self.pushFirst ) ) | |
expr << term + ZeroOrMore( ( addop + term ).setParseAction( self.pushFirst ) ) | |
# addop_term = ( addop + term ).setParseAction( self.pushFirst ) | |
# general_term = term + ZeroOrMore( addop_term ) | OneOrMore( addop_term) | |
# expr << general_term | |
self.bnf = expr | |
# map operator symbols to corresponding arithmetic operations | |
epsilon = 1e-12 | |
self.opn = { "+" : operator.add, | |
"-" : operator.sub, | |
"*" : operator.mul, | |
"/" : operator.truediv, | |
"^" : operator.pow } | |
self.fn = { "sin" : math.sin, | |
"cos" : math.cos, | |
"tan" : math.tan, | |
"abs" : abs, | |
"trunc" : lambda a: int(a), | |
"round" : round, | |
"sgn" : lambda a: abs(a)>epsilon and cmp(a,0) or 0} | |
def evaluateStack(self, s ): | |
op = s.pop() | |
if op == 'unary -': | |
return -self.evaluateStack( s ) | |
if op in "+-*/^": | |
op2 = self.evaluateStack( s ) | |
op1 = self.evaluateStack( s ) | |
return self.opn[op]( op1, op2 ) | |
elif op == "PI": | |
return math.pi # 3.1415926535 | |
elif op == "E": | |
return math.e # 2.718281828 | |
elif op in self.fn: | |
return self.fn[op]( self.evaluateStack( s ) ) | |
elif op[0].isalpha(): | |
return 0 | |
else: | |
return float( op ) | |
def eval(self,num_string,parseAll=True): | |
self.exprStack=[] | |
results=self.bnf.parseString(num_string,parseAll) | |
val=self.evaluateStack( self.exprStack[:] ) | |
return val |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment