Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import re
- from pyparsing import (Literal, CaselessLiteral, Word, Group, Combine, Optional,
- ZeroOrMore, Forward, nums, alphas, Regex, ParseException)
- exprStack = []
- rasters = dict()
- def pushFirst(strg, loc, toks):
- exprStack.append(toks[0])
- def pushUMinus(strg, loc, toks):
- for t in toks:
- if t == '-':
- exprStack.append('unary -')
- else:
- break
- def rasterPath(rasterName):
- global rasters
- return rasters[rasterName]
- # Define grammar
- bnf = None
- def BNF():
- global bnf
- if not bnf:
- point = Literal('.')
- colon = Literal(',')
- e = CaselessLiteral('E')
- pi = CaselessLiteral( "PI" )
- fnumber = Regex(r'[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?')
- ident = Combine('"' + Word(alphas, alphas + nums + '_') + '"')
- func = Word(alphas)
- plus = Literal('+')
- minus = Literal('-')
- mult = Literal('*')
- div = Literal('/')
- mod = Literal('%')
- lpar = Literal('(').suppress()
- rpar = Literal(')').suppress()
- addop = plus | minus
- multop = mult | div | mod
- expop = Literal('^')
- expr = Forward()
- atom = ((0, None) * minus + (pi | e | fnumber | ident | func + lpar + expr + rpar | ident).setParseAction(pushFirst) |
- Group(lpar + expr + rpar)).setParseAction(pushUMinus)
- # by defining exponentiation as "atom [ ^ factor ]..." instead of
- # "atom [ ^ atom ]...", we get right-to-left exponents, instead of
- # left-to-righ that is, 2^3^2 = 2^(3^2), not (2^3)^2.
- factor = Forward()
- factor << atom + ZeroOrMore((expop + factor).setParseAction(pushFirst))
- term = factor + ZeroOrMore((multop + factor).setParseAction(pushFirst))
- expr << term + ZeroOrMore((addop + term).setParseAction(pushFirst))
- bnf = expr
- return bnf
- # map operator symbols to corresponding arithmetic operations
- opn = {'+': lambda x, y: 'binarymathraster({}, {}, add)'.format(x, y),
- '-': lambda x, y: 'binarymathraster({}, {}, substract)'.format(x, y),
- '*': lambda x, y: 'binarymathraster({}, {}, times)'.format(x, y),
- '/': lambda x, y: 'binarymathraster({}, {}, divide)'.format(x, y),
- '%': lambda x, y: 'binarymathraster({}, {}, mod)'.format(x, y),
- '^': lambda x, y: 'binarymathraster({}, {}, power)'.format(x, y)}
- fn = {'sin': lambda x: 'sin({})'.format(x),
- 'cos': lambda x: 'cos({})'.format(x),
- 'tan': lambda x: 'tan({})'.format(x),
- 'asin': lambda x: 'asin({})'.format(x),
- 'acos': lambda x: 'acos({})'.format(x),
- 'atan': lambda x: 'atan({})'.format(x),
- 'log10': lambda x: 'log10({})'.format(x),
- 'ln': lambda x: 'ln({})'.format(x),
- 'abs': lambda x: 'abs({})'.format(x),
- 'sqrt': lambda x: 'sqrt({})'.format(x),
- 'ceil': lambda x: 'ceil({})'.format(x),
- 'floor': lambda x: 'floor({})'.format(x),
- 'sign': lambda x: 'sign({})'.format(x),
- 'sinh': lambda x: 'sinh({})'.format(x)}
- def evaluateStack(s):
- op = s.pop()
- if op == 'unary -':
- return -evaluateStack(s)
- if op in '+-*/^':
- op2 = evaluateStack(s)
- op1 = evaluateStack(s)
- return opn[op](op1, op2)
- elif op == 'PI':
- return math.pi # 3.1415926535
- elif op == 'E':
- return math.e # 2.718281828
- elif op in fn:
- return fn[op](evaluateStack(s))
- elif re.search('\"(.+?)\"', op):
- return rasterPath(op.strip('"'))
- elif op[0].isalpha():
- raise Exception('invalid identifier "%s"' % op)
- else:
- return float(op)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement