Пример #1
0
    def __init__(self, *args, **kwargs):
        super(BonusPointCalculator, self).__init__(*args, **kwargs)

        self.Operators.update({
            "=": operator.eq,
            ">": operator.gt,
            "<": operator.lt,
            ">=": operator.ge,
            "<=": operator.le,
            ",": operator.and_,
            "[": lambda a, b: a and b or Zero,
            "]": lambda a, b: a and b or Zero,
        })

        BonusPointAddition = Addition | Comparison

        Expression = Forward()
        Atom = ((Identifier | Integer).setParseAction(self._push) |
                (LeftParenthesis + Expression.suppress() + RightParenthesis))
        Terminal = Atom + ZeroOrMore(
            (Multiplication + Atom).setParseAction(self._push))
        Expression << Terminal + ZeroOrMore(
            (BonusPointAddition + Terminal).setParseAction(self._push))
        Condition = Expression + ZeroOrMore(
            (Comma + Expression).setParseAction(self._push))

        Rule = (LeftBracket + Condition + Colon + Expression +
                RightBracket).setParseAction(self._push)
        Chain = Rule + ZeroOrMore((Addition + Rule).setParseAction(self._push))

        self.pattern = Chain + StringEnd()
Пример #2
0
    def bnf(self):
        '''
        The BNF grammar is defined bellow.
        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 ]*
        '''
        if not self._bnf:
            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 + "_$")
            minus = Literal("-")
            plus = Literal("+")
            div = Literal("/")
            mult = Literal("*")
            rpar = Literal(")").suppress()
            lpar = Literal("(").suppress()
            addop = plus | minus
            multop = mult | div
            expop = Literal("^")
            pi = CaselessLiteral("PI")

            expr = Forward()
            atom = (
                Optional("-") +
                (
                    pi |
                    e |
                    fnumber |
                    ident + lpar + delimitedList(expr) + rpar
                ).setParseAction(self.push_first) |
                (lpar + expr.suppress() + rpar)
            ).setParseAction(self.push_minus)

            # The right way to define exponentiation is -> 2^3^2 = 2^(3^2),
            # not (2^3)^2.
            factor = Forward()
            factor << atom + ZeroOrMore(
                (expop + factor).setParseAction(self.push_first)
            )

            term = factor + ZeroOrMore(
                (multop + factor).setParseAction(self.push_first)
            )
            expr << term + ZeroOrMore(
                (addop + term).setParseAction(self.push_first)
            )
            self._bnf = expr
        return self._bnf
Пример #3
0
def compute(input_string):
    # Debugging flag can be set to either "debug_flag=True" or "debug_flag=False"
    debug_flag = False

    explain_list = []
    variables = {}

    # 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()

    if input_string != "":
        try:
            L = pattern.parseString(input_string)
        except ParseException, err:
            raise ComputationException, "Error while parsing"
        print exprStack
        if len(exprStack) <= 1:
            return None
        result = evaluateStack(exprStack, explain_list)
        if len(str(result)) > 12:
            ret = "%e" % result
        else:
            ret = str(result)
        ret = ret.replace("e", " x 10^")
        ret = ret.replace("+", "")
        if len(explain_list):
            return "%s (%s)" % (ret, ", ".join(explain_list))
        else:
            return "%s" % ret
Пример #4
0
    def _get_bnf(self):
        """
        Returns the `Backus–Naur Form` for the parser
        """
        if not self.bnf:
            # Operators
            exponent_operator = Literal("^")
            # negate_operator = Literal("!")  # TODO: Implement this so we can write `!True`
            multiply_operator = oneOf("* / %")
            add_operator = oneOf("+ -")
            comparison_operator = oneOf("== != < <= > >= & |") ^ Keyword("in")

            # Functions
            e = CaselessLiteral("E")
            pi = CaselessLiteral("PI")

            lparen, rparen, lbrack, rbrack = map(Suppress, "()[]")
            ident = Word(alphas, alphas + nums + "_$")
            variable = Combine(Literal("$") + Word(alphanums + "_"))
            boolean = Keyword("True") ^ Keyword("False")
            string = quotedString.setParseAction(removeQuotes)
            numeric = Combine(
                Word("+-" + nums, nums) +
                Optional(Literal(".") + Optional(Word(nums))) +
                Optional(e + Word("+-" + nums, nums)))
            none = Keyword("None")

            expression = Forward()

            lists = Forward()
            lists << (lbrack + Optional(
                delimitedList(numeric ^ variable ^ boolean ^ string)) + rbrack)

            atom = (Optional("-") +
                    (pi | e | numeric | ident + lparen + expression +
                     rparen).setParseAction(self.push_stack)
                    | (variable | none | boolean | string
                       | Group(lists)).setParseAction(self.push_stack)
                    |
                    (lparen + expression.suppress() + rparen)).setParseAction(
                        self.push_unary_stack)

            # By defining exponentiation as "atom [^factor]" instead of "atom [^atom],
            # we get left to right exponents. 2^3^2 = 2^(3^2), not (2^3)^2.
            factor = Forward()
            factor << atom + ZeroOrMore(
                (exponent_operator + factor).setParseAction(self.push_stack))

            boolean = factor + ZeroOrMore(
                (comparison_operator + factor).setParseAction(self.push_stack))
            term = boolean + ZeroOrMore(
                (multiply_operator + boolean).setParseAction(self.push_stack))
            self.bnf = expression << term + ZeroOrMore(
                (add_operator + term).setParseAction(self.push_stack))

        return self.bnf
Пример #5
0
    def _BNF(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 ]*
        """
        if not self.bnf:
            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()
            #             comma = Literal( "," ).suppress()
            comma = Literal(",")
            addop = plus | minus
            multop = mult | div
            expop = Literal("^")
            pi = CaselessLiteral("PI")
            var_list = [Literal(i) for i in self.var_names]

            expr = Forward()
            arg_func = Forward()
            or_vars = MatchFirst(var_list)
            #             atom = (Optional("-") + ( pi | e | fnumber | ident + lpar + delimitedList(Group(expr)) + rpar | or_vars ).setParseAction( self._pushFirst ) | ( lpar + delimitedList(Group(expr)).suppress() + rpar ) ).setParseAction(self._pushUMinus)
            atom = ((Optional("-") + ( pi | e | fnumber | ident + lpar + arg_func + rpar | or_vars ).setParseAction( self._pushFirst )) | \
                     (Optional("-") + ( lpar + arg_func.suppress() + rpar )) ).setParseAction(self._pushUMinus)

            #             expr + ZeroOrMore( "," + expr )
            # 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(self._pushFirst))

            term = factor + ZeroOrMore(
                (multop + factor).setParseAction(self._pushFirst))
            expr << term + ZeroOrMore(
                (addop + term).setParseAction(self._pushFirst))
            arg_func << expr + ZeroOrMore(
                (comma + expr).setParseAction(self._pushFirst))
            self.bnf = expr
        return self.bnf
Пример #6
0
    def _BNF(self):
        base16 = Literal("$")
        hex = Combine(base16 + Word(hexnums + "_"))

        base4 = Literal("%%")
        quaternary = Combine(base4 + Word("0123_"))

        base2 = Literal("%")
        binary = Combine(base2 + Word("01_"))

        plusminus = Literal("+") | Literal("-")
        integer = Combine(Optional(plusminus) + Word(nums+"_"))

        name_token = Combine(Optional(Literal(":") | Literal("@")) + Word("_" + alphas, "_" + alphanums))
        name_token.setParseAction(self._mark_name_token)

        lparens = Literal("(").suppress()
        rparens = Literal(")").suppress()

        # op0 = Literal("@")
        op1 = (Literal("^^") | Literal("||") | Literal("|<") | Literal(">|") | Literal("!")).setParseAction(self._mark_unary)
        op2 = Literal("->") | Literal("<-") | Literal(">>") | Literal("<<") | Literal("~>") | Literal("><")
        op3 = Literal("&")
        op4 = Literal("|") | Literal("^")
        op5 = Literal("**") | Literal("*") | Literal("//") | Literal("/")
        op6 = Literal("+") | Literal("-")
        op7 = Literal("#>") | Literal("<#")
        op8 = Literal("<") | Literal(">") | Literal("<>") | Literal("==") | Literal("=<") | Literal("=>")
        op9 = Literal("NOT").setParseAction(self._mark_unary)
        op10 = Literal("AND")
        op11 = Literal("OR")
        op12 = Literal(",")

        expr = Forward()

        atom = name_token | hex | quaternary | binary | integer | quotedString
        atom.setParseAction(self._push)
        atom = atom | (lparens + expr.suppress() + rparens)
 
        # term0  = atom   + ZeroOrMore((op0 + atom)   .setParseAction(self._push))
        # term1  = term0  + ZeroOrMore((op1 + term0)  .setParseAction(self._push))
        term1  = atom   + ZeroOrMore((op1 + atom)   .setParseAction(self._push))
        term2  = term1  + ZeroOrMore((op2 + term1)  .setParseAction(self._push))
        term3  = term2  + ZeroOrMore((op3 + term2)  .setParseAction(self._push))
        term4  = term3  + ZeroOrMore((op4 + term3)  .setParseAction(self._push))
        term5  = term4  + ZeroOrMore((op5 + term4)  .setParseAction(self._push))
        term6  = term5  + ZeroOrMore((op6 + term5)  .setParseAction(self._push))
        term7  = term6  + ZeroOrMore((op7 + term6)  .setParseAction(self._push))
        term8  = term7  + ZeroOrMore((op8 + term7)  .setParseAction(self._push))
        term9  = term8  + ZeroOrMore((op9 + term8)  .setParseAction(self._push))
        term10 = term9  + ZeroOrMore((op10 + term9) .setParseAction(self._push))
        term11 = term10 + ZeroOrMore((op11 + term10).setParseAction(self._push))
        expr  << term11 + ZeroOrMore((op12 + term11).setParseAction(self._push))

        return expr
Пример #7
0
def BNF():
    """
    expop   :: '^'
    multop  :: '*' | '/' | '>>' | '<<' | '|' | '&'
    addop   :: '+' | '-'
    hex     :: '0x' + integer
    integer :: ['+' | '-'] '0'..'9'+
    atom    :: PI | E | real | fn '(' expr ')' | '(' expr ')'
    factor  :: atom [ expop factor ]*
    term    :: factor [ multop factor ]*
    expr    :: term [ addop term ]*
    """
    global bnf

    if not bnf:
        point = Literal(".")
        e = CaselessLiteral("E")
        hexnum = CaselessLiteral("0x") + OneOrMore(
            oneOf(nums + 'a b c d e f A B C D E F'))
        hexnum.setParseAction(lambda s, l, t: str(int(''.join(t), 16)))
        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("/")
        lshift = Literal("<<")
        rshift = Literal(">>")
        or_ = Literal("|")
        and_ = Literal("&")
        lpar = Literal("(").suppress()
        rpar = Literal(")").suppress()
        addop = plus | minus
        multop = mult | div | lshift | rshift | or_ | and_
        expop = Literal("^")
        pi = CaselessLiteral("PI")

        expr = Forward()
        atom = (Optional("-") +
                (pi | e | hexnum | fnumber
                 | ident + lpar + expr + rpar).setParseAction(pushFirst) |
                (lpar + expr.suppress() + 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
Пример #8
0
    def _BNF(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 ]*
        """
        if not self.bnf:
            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()
#             comma = Literal( "," ).suppress()
            comma = Literal( "," )
            addop  = plus | minus
            multop = mult | div
            expop = Literal( "^" )
            pi    = CaselessLiteral( "PI" )
            var_list = [Literal(i) for i in self.var_names]
            
            expr = Forward()
            arg_func = Forward()
            or_vars = MatchFirst(var_list)
#             atom = (Optional("-") + ( pi | e | fnumber | ident + lpar + delimitedList(Group(expr)) + rpar | or_vars ).setParseAction( self._pushFirst ) | ( lpar + delimitedList(Group(expr)).suppress() + rpar ) ).setParseAction(self._pushUMinus) 
            atom = ((Optional("-") + ( pi | e | fnumber | ident + lpar + arg_func + rpar | or_vars ).setParseAction( self._pushFirst )) | \
                     (Optional("-") + ( lpar + arg_func.suppress() + rpar )) ).setParseAction(self._pushUMinus) 
            
#             expr + ZeroOrMore( "," + expr )
            # 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( self._pushFirst ) )
            
            term = factor + ZeroOrMore( ( multop + factor ).setParseAction( self._pushFirst ) )
            expr << term + ZeroOrMore( ( addop + term ).setParseAction( self._pushFirst ) )
            arg_func << expr + ZeroOrMore( (comma + expr).setParseAction( self._pushFirst))
            self.bnf = expr
        return self.bnf
Пример #9
0
    def bnf(self):
        '''
        The BNF grammar is defined bellow.
        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 ]*
        '''
        if not self._bnf:
            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 + "_$")
            minus = Literal("-")
            plus = Literal("+")
            div = Literal("/")
            mult = Literal("*")
            rpar = Literal(")").suppress()
            lpar = Literal("(").suppress()
            addop = plus | minus
            multop = mult | div
            expop = Literal("^")
            pi = CaselessLiteral("PI")

            expr = Forward()
            atom = (Optional("-") +
                    (pi | e | fnumber | ident + lpar + delimitedList(expr) +
                     rpar).setParseAction(self.push_first) |
                    (lpar + expr.suppress() + rpar)).setParseAction(
                        self.push_minus)

            # The right way to define exponentiation is -> 2^3^2 = 2^(3^2),
            # not (2^3)^2.
            factor = Forward()
            factor << atom + ZeroOrMore(
                (expop + factor).setParseAction(self.push_first))

            term = factor + ZeroOrMore(
                (multop + factor).setParseAction(self.push_first))
            expr << term + ZeroOrMore(
                (addop + term).setParseAction(self.push_first))
            self._bnf = expr
        return self._bnf
Пример #10
0
def _dice_grammar(exprStack, varStack):

    def pushFirst(str, loc, toks):
        exprStack.append(toks[0])

    def assignVar(str, loc, toks):
        varStack.append(toks[0])

    point = Literal('.')
    e = CaselessLiteral('E')
    plusorminus = Literal('+') | Literal('-')
    singledie = Literal('d')
    number = Word(nums)
    integer = Combine(Optional(plusorminus) + number)
    singleroll = Combine(singledie + 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("^")
    dieop = Literal("d")
    assign = Literal("=")

    expr = Forward()
    atom = (
        (e | floatnumber | integer | ident | singleroll).setParseAction(
            pushFirst) | (lpar + expr.suppress() + rpar))
    roll = Forward()
    roll << atom + ZeroOrMore((dieop + roll).setParseAction(pushFirst))

    factor = Forward()
    factor << roll + 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

    return bnf + StringEnd()
Пример #11
0
def BNF():
    """
    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 ]*
    """
    global bnf
    if not bnf:
        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("-") +
                 (pi | e | fnumber
                  | ident + lpar + expr + rpar).setParseAction(pushFirst)
                 | (lpar + expr.suppress() + rpar)).setParseAction(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(pushFirst))

        term = factor + ZeroOrMore((multop + factor).setParseAction(pushFirst))
        expr << term + ZeroOrMore((addop + term).setParseAction(pushFirst))
        bnf = expr
    return bnf
Пример #12
0
def BNF():
    """
    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 ]*
    """
    global bnf
    if not bnf:
        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("-") + (pi | e | fnumber | ident +
                                  lpar + expr + rpar).setParseAction(pushFirst)
                | (lpar + expr.suppress() + rpar)).setParseAction(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(pushFirst))

        term = factor + ZeroOrMore((multop +
                                    factor).setParseAction(pushFirst))
        expr << term + ZeroOrMore((addop + term).setParseAction(pushFirst))
        bnf = expr
    return bnf
Пример #13
0
    def __parser(expression):
        """ adopted from Paul McGuire example. http://pyparsing.wikispaces.com/file/view/fourFn.py
        """
        expr_stack = []

        def push_first(strg, loc, toks):
            expr_stack.append(toks[0])

        def push_u_minus(strg, loc, toks):
            if toks and toks[0] == '-':
                expr_stack.append('unary -')

        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")
        x = CaselessLiteral("X")

        expr = Forward()
        atom = (Optional("-") +
                (x | _pi | _e | fnumber
                 | ident + lpar + expr + rpar).setParseAction(push_first) |
                (lpar + expr.suppress() + rpar)).setParseAction(push_u_minus)

        factor = Forward()
        factor << atom + ZeroOrMore(
            (expop + factor).setParseAction(push_first))

        term = factor + ZeroOrMore(
            (multop + factor).setParseAction(push_first))
        expr << term + ZeroOrMore((addop + term).setParseAction(push_first))

        expr.parseString(expression)
        return expr_stack
Пример #14
0
    def __init__(self, instance, *args, **kwargs):
        Expression = Forward()
        Atom = ((Identifier | Integer).setParseAction(self._push) |
                (LeftParenthesis + Expression.suppress() +
                 RightParenthesis)).setName('atom')
        Terminal = Atom + ZeroOrMore(
            (Multiplication + Atom).setParseAction(self._push))
        Expression << Terminal + ZeroOrMore(
            (Addition + Terminal).setParseAction(self._push))

        self.Operators = {
            "+": operator.add,
            "-": operator.sub,
            "*": operator.mul,
            "/": operator.truediv,
        }

        self.instance = instance
        self.pattern = Expression + StringEnd()
        self.stack = []
Пример #15
0
    def grammar(self):
        def push_first(s, loc, toks):
            self.stack.append(toks[0])

        def push_atom(s, loc, toks):
            atom = toks[0]
            number = _parse_number(atom)
            if number is not None:
                self.stack.append(number)
            else:
                self.stack.append(toks[0].lower())

        # constant expressions
        lpar   = Literal('(').suppress()
        rpar   = Literal(')').suppress()
        addop  = Literal('+') | Literal('-')
        multop = Literal('*') | Literal('/')
        bitop  = Literal('<<') | Literal('>>') | \
                 Literal('&')  | Literal('|') | Literal('^') | \
                 Literal('<-') | Literal('->')
        number = (Combine(Literal('$') + Word(nums+'_abcdefABCDEF'))) | \
                 (Combine(Literal('%') + Word('_01'))) | \
                 Word('_' + nums)
        id = Combine(Optional('@') + Optional(':') + Regex(r'[a-zA-Z_]\w*'))

        expr = Forward()
        term = Forward()
        bwterm = Forward()

        atom  = Optional('-') + (number | id)
        rexpr = (lpar + expr.suppress() + rpar).suppress()

        # bitwise operators have highest precedence, followed by mul/div and
        # finally add/sub
        bwterm << ( atom.setParseAction(push_atom) | rexpr ) + ZeroOrMore( (bitop + bwterm).setParseAction(push_first) )
        term << bwterm + ZeroOrMore( (multop + bwterm).setParseAction(push_first) )
        expr << term + ZeroOrMore( (addop + term).setParseAction(push_first) )

        return expr
Пример #16
0
def create_bnf(stack):
    point = Literal(".")
    comma = Literal(",")
    e = CaselessLiteral("E")
    inumber = Word(nums)
    fnumber = Combine(
        Word("+-" + nums, nums) + Optional(point + Optional(Word(nums))) +
        Optional(e + Word("+-" + nums, nums)))
    _of = Literal('of')
    _in = Literal('in')
    _by = Literal('by')
    _copy = Literal('copy')

    _mn = Literal('-n').setParseAction(replace('OA_SubN'))
    _me = Literal('-e').setParseAction(replace('OA_SubE'))
    _pn = Literal('+n').setParseAction(replace('OA_AddN'))
    _pe = Literal('+e').setParseAction(replace('OA_AddE'))
    _inn = Literal('*n').setParseAction(replace('OA_IntersectN'))
    _ine = Literal('*e').setParseAction(replace('OA_IntersectE'))
    regop = (_mn | _me | _pn | _pe | _inn | _ine)

    lpar = Literal("(").suppress()
    rpar = Literal(")").suppress()

    _all = Literal('all').setParseAction(replace('KW_All'))
    node = Literal('node')
    nodes = Literal('nodes')
    element = Literal('element')
    elements = Literal('elements')
    group = Literal('group')
    _set = Literal('set')
    surface = Literal('surface')

    ident = Word(alphas + '_.', alphanums + '_.')
    set_name = Word(nums) | ident

    function = Word(alphas + '_', alphanums + '_')
    function = Group(function).setParseAction(join_tokens)

    region = Combine(
        Literal('r.') + Word(alphas + '_', '_' + alphas + nums + '.'))
    region = Group(Optional(_copy, default='nocopy') + region)
    region.setParseAction(replace('KW_Region', keep=True))

    coor = oneOf('x y z')
    boolop = oneOf('& |')
    relop = oneOf('< > <= >= != ==')
    bool_term = (ZeroOrMore('(') + (coor | fnumber) + relop +
                 (coor | fnumber) + ZeroOrMore(')'))
    relation = Forward()
    relation << (ZeroOrMore('(') + bool_term + ZeroOrMore(boolop + relation) +
                 ZeroOrMore(')'))
    relation = Group(relation).setParseAction(join_tokens)

    nos = Group(nodes + _of + surface).setParseAction(replace('E_NOS'))
    nir = Group(nodes + _in + relation).setParseAction(
        replace('E_NIR', keep=True))
    nbf = Group(nodes + _by + function).setParseAction(
        replace('E_NBF', keep=True))
    ebf = Group(elements + _by + function).setParseAction(
        replace('E_EBF', keep=True))
    eog = Group(elements + _of + group + Word(nums)).setParseAction(
        replace('E_EOG', keep=True))
    nog = Group(nodes + _of + group + Word(nums)).setParseAction(
        replace('E_NOG', keep=True))
    onir = Group(node + _in + region).setParseAction(
        replace_with_region('E_ONIR', 2))
    ni = Group(node + delimitedList(inumber)).setParseAction(
        replace('E_NI', keep=True))
    ei1 = Group(element + delimitedList(inumber)).setParseAction(
        replace('E_EI1', keep=True))
    etuple = (lpar.suppress() + inumber + comma.suppress() + inumber +
              rpar.suppress())
    ei2 = Group(element + delimitedList(etuple)).setParseAction(
        replace('E_EI2', keep=True))
    noset = Group(nodes + _of + _set + set_name).setParseAction(
        replace('E_NOSET', keep=True))
    eoset = Group(elements + _of + _set + set_name).setParseAction(
        replace('E_EOSET', keep=True))

    region_expression = Forward()

    atom1 = (_all | region | ni | onir | nos | nir | nbf
             | ei1 | ei2 | ebf | eog | nog | noset | eoset)
    atom1.setParseAction(to_stack(stack))
    atom2 = (lpar + region_expression.suppress() + rpar)
    atom = (atom1 | atom2)

    aux = (regop + region_expression)
    aux.setParseAction(to_stack(stack))
    region_expression << atom + ZeroOrMore(aux)
    region_expression = StringStart() + region_expression + StringEnd()

    return region_expression
Пример #17
0
greater_equal_op = Combine(Literal(">") + Literal("="))
less_op = Combine(Literal("<") + ~Literal("="))
less_equal_op = Combine(Literal("<") + Literal("="))

addop = plus | minus
multop = mult | div
compop = less_op | greater_op | less_equal_op | greater_equal_op | not_equal_op | equal_op
expop = Literal("^")
#assign = Literal( "=" )
band = Literal("@")

expr = Forward()
atom = ((e | floatnumber | integer | ident.setParseAction(assignVar)
         | fn + lpar + expr + rpar | fn + lpar + expr + colon + expr + rpar
         | fn + lpar + expr + colon + expr + colon + expr +
         rpar).setParseAction(pushFirst) | (lpar + expr.suppress() + rpar))

factor = Forward()
factor << atom + ((band + factor).setParseAction(pushFirst) | ZeroOrMore(
    (expop + factor).setParseAction(pushFirst)))

term = factor + ZeroOrMore((multop + factor).setParseAction(pushFirst))
addterm = term + ZeroOrMore((addop + term).setParseAction(pushFirst))
expr << addterm + ZeroOrMore((compop + addterm).setParseAction(pushFirst))
bnf = expr

pattern = bnf + StringEnd()

# map operator symbols to corresponding arithmetic operations
opn = {
    "+": (lambda a, b: numpy.add(a, b)),
Пример #18
0
def create_bnf( stack ):
    point = Literal( "." )
    comma = Literal( "," )
    e = CaselessLiteral( "E" )
    inumber = Word( nums )
    fnumber = Combine( Word( "+-"+nums, nums ) + 
                       Optional( point + Optional( Word( nums ) ) ) +
                       Optional( e + Word( "+-"+nums, nums ) ) )
    _of = Literal( 'of' )
    _in = Literal( 'in' )
    _by = Literal( 'by' )
    _copy = Literal( 'copy' )

    _mn = Literal( '-n' ).setParseAction( replace( 'OA_SubN' ) )
    _me = Literal( '-e' ).setParseAction( replace( 'OA_SubE' ) )
    _pn = Literal( '+n' ).setParseAction( replace( 'OA_AddN' ) )
    _pe = Literal( '+e' ).setParseAction( replace( 'OA_AddE' ) )
    _inn = Literal( '*n' ).setParseAction( replace( 'OA_IntersectN' ) )
    _ine = Literal( '*e' ).setParseAction( replace( 'OA_IntersectE' ) )
    regop = (_mn | _me | _pn | _pe | _inn | _ine)

    lpar  = Literal( "(" ).suppress()
    rpar  = Literal( ")" ).suppress()

    _all = Literal( 'all' ).setParseAction( replace( 'KW_All' ) )
    node = Literal( 'node' )
    nodes = Literal( 'nodes' )
    element = Literal( 'element' )
    elements = Literal( 'elements' )
    group = Literal( 'group' )
    surface = Literal( 'surface' )
    variable = Word( 'xyz', max = 1 ) | Literal( 'domain' )
    any_var = Word( alphas + '_', alphanums + '_' ) | fnumber

    function = Word( alphas, alphanums + '_' )
    function = Group( function ).setParseAction( join_tokens )

    region = Combine( Literal( 'r.' ) + Word( alphas, '_' + alphas + nums ) )
    region = Group( Optional( _copy, default = 'nocopy' ) + region )
    region.setParseAction( replace( 'KW_Region', keep = True ) )

    coor = oneOf( 'x y z' )
    boolop = oneOf( '& |' )
    relop = oneOf( '< > <= >= != ==' )
    bool_term = ZeroOrMore( '(' ) + (coor | fnumber ) + relop + (coor | fnumber)\
               + ZeroOrMore( ')' )
    relation = Forward()
    relation << ZeroOrMore( '(' )\
             + bool_term + ZeroOrMore( boolop + relation )\
             + ZeroOrMore( ')' )
    relation = Group( relation ).setParseAction( join_tokens )

    nos = Group( nodes + _of + surface ).setParseAction( replace( 'E_NOS' ) )
    nir = Group( nodes + _in + relation ).setParseAction( \
        replace( 'E_NIR', keep = True ) )
    nbf = Group( nodes + _by + function ).setParseAction( \
        replace( 'E_NBF', keep = True ) )
    ebf = Group( elements + _by + function ).setParseAction( \
        replace( 'E_EBF', keep = True ) )
    eog = Group( elements + _of + group + Word( nums ) ).setParseAction( \
        replace( 'E_EOG', keep = True ) )
    nog = Group( nodes + _of + group + Word( nums ) ).setParseAction( \
        replace( 'E_NOG', keep = True ) )
    onir = Group( node + _in + region ).setParseAction( \
        replace_with_region( 'E_ONIR', 2 ) )
    ni = Group( node + delimitedList( inumber ) ).setParseAction( \
        replace( 'E_NI', keep = True ) )
    ei1 = Group( element + delimitedList( inumber ) ).setParseAction( \
        replace( 'E_EI1', keep = True ) )
    etuple = lpar.suppress() + inumber + comma.suppress() \
             + inumber + rpar.suppress()
    ei2 = Group( element + delimitedList( etuple ) ).setParseAction( \
        replace( 'E_EI2', keep = True ) )

    region_expression = Forward()

    atom1 = (_all | region | ni | onir | nos | nir | nbf
             | ei1 | ei2 | ebf | eog | nog)
    atom1.setParseAction( to_stack( stack ) )
    atom2 = (lpar + region_expression.suppress() + rpar)
    atom = (atom1 | atom2)

    aux = (regop + region_expression)
    aux.setParseAction( to_stack( stack ) )
    region_expression << atom + ZeroOrMore( aux )
    region_expression = StringStart() + region_expression + StringEnd()

#    region.set_debug()
#    relation.set_debug()
#    region_expression.set_debug()

    return region_expression
Пример #19
0
not_equal_op     = Literal( "!=" )
greater_op       = Combine( Literal( ">" ) + ~Literal( "=" ) )
greater_equal_op = Combine( Literal( ">" ) + Literal( "=" ) )
less_op          = Combine( Literal( "<" ) + ~Literal( "=" ) )
less_equal_op    = Combine( Literal( "<" ) + Literal( "=" ) )

addop  = plus | minus
multop = mult | div
compop = less_op | greater_op | less_equal_op | greater_equal_op | not_equal_op | equal_op
expop = Literal( "^" )
#assign = Literal( "=" )
band = Literal( "@" )

expr = Forward()
atom = ( ( e | floatnumber | integer | ident.setParseAction( assignVar ) | fn + lpar + expr + rpar | fn + lpar + expr + colon + expr + rpar | fn + lpar + expr + colon + expr + colon + expr + rpar ).setParseAction(pushFirst) |
         ( lpar + expr.suppress() + rpar )
       )

factor = Forward()
factor << atom + ( ( band + factor ).setParseAction( pushFirst ) | ZeroOrMore( ( expop + factor ).setParseAction( pushFirst ) ) )

term = factor + ZeroOrMore( ( multop + factor ).setParseAction( pushFirst ) )
addterm = term + ZeroOrMore( ( addop + term ).setParseAction( pushFirst ) )
expr << addterm + ZeroOrMore( ( compop + addterm ).setParseAction( pushFirst ) )
bnf = expr

pattern =  bnf + StringEnd()

# map operator symbols to corresponding arithmetic operations
opn = { "+" : ( lambda a,b: numpy.add( a, b ) ),
        "-" : ( lambda a,b: numpy.subtract( a, b ) ),
Пример #20
0
def create_bnf(stack):
    point = Literal(".")
    comma = Literal(",")
    e = CaselessLiteral("E")
    inumber = Word(nums)
    fnumber = Combine(Word("+-"+nums, nums) +
                       Optional(point + Optional(Word(nums))) +
                       Optional(e + Word("+-"+nums, nums)))
    _of = Literal('of')
    _in = Literal('in')
    _by = Literal('by')
    _copy = Literal('copy')

    _mv = Literal('-v').setParseAction(replace('OA_SubV'))
    _me = Literal('-e').setParseAction(replace('OA_SubE'))
    _mf = Literal('-f').setParseAction(replace('OA_SubF'))
    _mc = Literal('-c').setParseAction(replace('OA_SubC'))
    _ms = Literal('-s').setParseAction(replace('OA_SubS'))
    _pv = Literal('+v').setParseAction(replace('OA_AddV'))
    _pe = Literal('+e').setParseAction(replace('OA_AddE'))
    _pf = Literal('+f').setParseAction(replace('OA_AddF'))
    _pc = Literal('+c').setParseAction(replace('OA_AddC'))
    _ps = Literal('+s').setParseAction(replace('OA_AddS'))
    _inv = Literal('*v').setParseAction(replace('OA_IntersectV'))
    _ine = Literal('*e').setParseAction(replace('OA_IntersectE'))
    _inf = Literal('*f').setParseAction(replace('OA_IntersectF'))
    _inc = Literal('*c').setParseAction(replace('OA_IntersectC'))
    _ins = Literal('*s').setParseAction(replace('OA_IntersectS'))
    regop = (_mv | _me | _mf | _mc | _ms |
             _pv | _pe | _pf | _pc | _ps |
             _inv | _ine | _inf | _inc | _ins)

    lpar  = Literal("(").suppress()
    rpar  = Literal(")").suppress()

    _all = Literal('all').setParseAction(replace('KW_All'))
    vertex = Literal('vertex')
    vertices = Literal('vertices')
    cell = Literal('cell')
    cells = Literal('cells')
    group = Literal('group')
    _set = Literal('set')
    surface = Literal('surface')

    ident = Word(alphas + '_.', alphanums + '_.')
    set_name = Word(nums) | ident

    function = Word(alphas + '_', alphanums + '_')
    function = Group(function).setParseAction(join_tokens)

    region = Combine(Literal('r.') + Word(alphas + '_',
                                          '_' + alphas + nums + '.'))
    region = Group(Optional(_copy, default='nocopy') + region)
    region.setParseAction(replace('KW_Region', keep=True))

    coor = oneOf('x y z')
    boolop = oneOf('& |')
    relop = oneOf('< > <= >= != ==')
    bool_term = (ZeroOrMore('(') + (coor | fnumber) + relop + (coor | fnumber)
                 + ZeroOrMore(')'))
    relation = Forward()
    relation << (ZeroOrMore('(')
                 + bool_term + ZeroOrMore(boolop + relation)
                 + ZeroOrMore(')'))
    relation = Group(relation).setParseAction(join_tokens)

    nos = Group(vertices + _of + surface).setParseAction(replace('E_VOS'))
    nir = Group(vertices + _in + relation).setParseAction(
        replace('E_VIR', keep=True))
    nbf = Group(vertices + _by + function).setParseAction(
        replace('E_VBF', keep=True))
    ebf = Group(cells + _by + function).setParseAction(
        replace('E_CBF', keep=True))
    eog = Group(cells + _of + group + Word(nums)).setParseAction(
        replace('E_COG', keep=True))
    nog = Group(vertices + _of + group + Word(nums)).setParseAction(
        replace('E_VOG', keep=True))
    onir = Group(vertex + _in + region).setParseAction(
        replace_with_region('E_OVIR', 2))
    ni = Group(vertex + delimitedList(inumber)).setParseAction(
        replace('E_VI', keep=True))
    ei1 = Group(cell + delimitedList(inumber)).setParseAction(
        replace('E_CI1', keep=True))
    etuple = (lpar.suppress() + inumber + comma.suppress()
              + inumber + rpar.suppress())
    ei2 = Group(cell + delimitedList(etuple)).setParseAction(
        replace('E_CI2', keep=True))
    noset = Group(vertices + _of + _set + set_name).setParseAction(
        replace('E_VOSET', keep=True))
    eoset = Group(cells + _of + _set + set_name).setParseAction(
        replace('E_COSET', keep=True))

    region_expression = Forward()

    atom1 = (_all | region | ni | onir | nos | nir | nbf
             | ei1 | ei2 | ebf | eog | nog | noset | eoset)
    atom1.setParseAction(to_stack(stack))
    atom2 = (lpar + region_expression.suppress() + rpar)
    atom = (atom1 | atom2)

    aux = (regop + region_expression)
    aux.setParseAction(to_stack(stack))
    region_expression << atom + ZeroOrMore(aux)
    region_expression = StringStart() + region_expression + StringEnd()

    return region_expression
class EquationGrammar(object):
   def __init__(self):
      self._expr_stack=[]

      # every optional, matchfirst, or ZeroOrMore needs to have a probability defined in this dict
      self._generators={}

      # operators
      plus=Literal("+")
      minus=Literal("-")
      mult=Literal("*")
      div=Literal("/")
      addsub=plus|minus
      self._generators[addsub]=flip_gen([plus,minus])
      multdiv=mult|div
      self._generators[multdiv]=flip_gen([mult,div])

      # constants
      pi=CaselessLiteral("PI")
      e=CaselessLiteral("E")

      # numbers and identifiers
      point=Literal(".")
      integer=Combine(Word("+-"+nums,nums))
      self._generators[integer.expr]=num_gen(nums)

      #ident=Word(alphas,alphas+nums)
      fnsin=Literal("sin")
      fncos=Literal("cos")
      fntan=Literal("tan")
      fnabs=Literal("abs")
      fnident=fnsin|fncos|fntan|fnabs
      self._generators[fnident]=choose_gen([fnsin,fncos,fntan,fnabs],[0.4,0.4,0.1,0.1])
      variable=Literal("x")

      # grouping
      lparen=Literal("(").suppress()
      rparen=Literal(")").suppress()

      # expressions
      self._expr=Forward()
      optneg=Optional("-")
      self._generators[optneg]=flip_gen(["-",None])
      functioncall=fnident+lparen+self._expr+rparen
      atom_base=pi|e|integer|functioncall|variable
      atom_base_choices=[pi,e,integer,functioncall,variable]
      self._generators[atom_base]=(choose_gen(atom_base_choices,[0.1,0.1,0.2,0.3,0.3]),\
         choose_gen(atom_base_choices,[0.1,0.1,0.4,0.0,0.4]))
      parenthetical=lparen+self._expr.suppress()+rparen
      atom=(optneg+atom_base.setParseAction(self.push_first)|parenthetical).setParseAction(\
         self.push_uminus)
      atom_choices=[atom_base,parenthetical]
      self._generators[atom]=(choose_gen(atom_choices,[0.5,0.5]),choose_gen(atom_choices,[1.0,0.0]))

      # 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()
      # parse either curly braces or parenthesis, but only generate curly braces
      expon=Literal("^")
      exponlparen=Literal("{").suppress()
      exponrparen=Literal("}").suppress()
      mf_lparen=exponlparen|lparen
      lparen_choices=[exponlparen,lparen]
      self._generators[mf_lparen]=choose_gen(lparen_choices,[1.0,0.0])
      mf_rparen=exponrparen|rparen
      rparen_choices=[exponrparen,rparen]
      self._generators[mf_rparen]=choose_gen(rparen_choices,[1.0,0.0])

      exponfactor=(expon+mf_lparen.suppress()+factor+mf_rparen.suppress()).setParseAction(\
         self.push_first)
      zom_exponfactor=ZeroOrMore(exponfactor)
      self._generators[zom_exponfactor]=poisson_gen(exponfactor,0.2)
      factor << atom + zom_exponfactor

      multdivfactor=(multdiv+factor).setParseAction(self.push_first)
      zom_multdivfactor=ZeroOrMore(multdivfactor)
      self._generators[zom_multdivfactor]=poisson_gen(multdivfactor,0.5)
      term=factor+zom_multdivfactor

      addsubterm=(addsub+term).setParseAction(self.push_first)
      zom_addsubterm=ZeroOrMore(addsubterm)
      self._generators[zom_addsubterm]=poisson_gen(addsubterm,0.5)
      self._expr << term+zom_addsubterm

      self._id_expr=id(self._expr)

   def set_expr_stack(self,expr_stack):
      self._expr_stack=expr_stack

   def push_first(self,strg,loc,toks):
      self._expr_stack.append(toks[0])

   def push_uminus(self,strg,loc,toks):
      if toks and toks[0]=='-':
         self._expr_stack.append('unary -')

   def parse_string(self,s):
      return self._expr.parseString(s)

   @property
   def generators(self):
       return self._generators

   @property
   def id_expr(self):
       return self._id_expr

   @property
   def expr_stack(self):
       return self._expr_stack

   @property
   def root(self):
       return self._expr
Пример #22
0
    def _BNF(self):
        base16 = Literal("$")
        hex = Combine(base16 + Word(hexnums + "_"))

        base4 = Literal("%%")
        quaternary = Combine(base4 + Word("0123_"))

        base2 = Literal("%")
        binary = Combine(base2 + Word("01_"))

        plusminus = Literal("+") | Literal("-")
        integer = Combine(Optional(plusminus) + Word(nums + "_"))

        name_token = Combine(
            Optional(Literal(":") | Literal("@")) +
            Word("_" + alphas, "_" + alphanums))
        name_token.setParseAction(self._mark_name_token)

        lparens = Literal("(").suppress()
        rparens = Literal(")").suppress()

        # op0 = Literal("@")
        op1 = (Literal("^^") | Literal("||") | Literal("|<") | Literal(">|")
               | Literal("!")).setParseAction(self._mark_unary)
        op2 = Literal("->") | Literal("<-") | Literal(">>") | Literal(
            "<<") | Literal("~>") | Literal("><")
        op3 = Literal("&")
        op4 = Literal("|") | Literal("^")
        op5 = Literal("**") | Literal("*") | Literal("//") | Literal("/")
        op6 = Literal("+") | Literal("-")
        op7 = Literal("#>") | Literal("<#")
        op8 = Literal("<") | Literal(">") | Literal("<>") | Literal(
            "==") | Literal("=<") | Literal("=>")
        op9 = Literal("NOT").setParseAction(self._mark_unary)
        op10 = Literal("AND")
        op11 = Literal("OR")
        op12 = Literal(",")

        expr = Forward()

        atom = name_token | hex | quaternary | binary | integer | quotedString
        atom.setParseAction(self._push)
        atom = atom | (lparens + expr.suppress() + rparens)

        # term0  = atom   + ZeroOrMore((op0 + atom)   .setParseAction(self._push))
        # term1  = term0  + ZeroOrMore((op1 + term0)  .setParseAction(self._push))
        term1 = atom + ZeroOrMore((op1 + atom).setParseAction(self._push))
        term2 = term1 + ZeroOrMore((op2 + term1).setParseAction(self._push))
        term3 = term2 + ZeroOrMore((op3 + term2).setParseAction(self._push))
        term4 = term3 + ZeroOrMore((op4 + term3).setParseAction(self._push))
        term5 = term4 + ZeroOrMore((op5 + term4).setParseAction(self._push))
        term6 = term5 + ZeroOrMore((op6 + term5).setParseAction(self._push))
        term7 = term6 + ZeroOrMore((op7 + term6).setParseAction(self._push))
        term8 = term7 + ZeroOrMore((op8 + term7).setParseAction(self._push))
        term9 = term8 + ZeroOrMore((op9 + term8).setParseAction(self._push))
        term10 = term9 + ZeroOrMore((op10 + term9).setParseAction(self._push))
        term11 = term10 + ZeroOrMore(
            (op11 + term10).setParseAction(self._push))
        expr << term11 + ZeroOrMore((op12 + term11).setParseAction(self._push))

        return expr
Пример #23
0
    def __init__(self):

        self.ae = False
        self.local_dict = None
        self.f = None

        self.user_functions = None

        self.expr_stack = []
        self.texpr_stack = []

        # Define constants
        self.constants = {}

        # Define Operators
        self.opn = {"+": operator.add,
                    "-": operator.sub,
                    "*": operator.mul,
                    "/": operator.truediv,
                    ">": operator.gt,
                    ">=": operator.ge,
                    "<": operator.lt,
                    "<=": operator.le,
                    "==": operator.eq,
                    "!=": operator.ne,
                    "|": operator.or_,
                    "&": operator.and_,
                    "!": operator.inv}

        # Define xarray DataArray operators with 1 input parameter
        self.xfn1 = {"angle": xr.ufuncs.angle,
                     "arccos": xr.ufuncs.arccos,
                     "arccosh": xr.ufuncs.arccosh,
                     "arcsin": xr.ufuncs.arcsin,
                     "arcsinh": xr.ufuncs.arcsinh,
                     "arctan": xr.ufuncs.arctan,
                     "arctanh": xr.ufuncs.arctanh,
                     "ceil": xr.ufuncs.ceil,
                     "conj": xr.ufuncs.conj,
                     "cos": xr.ufuncs.cos,
                     "cosh": xr.ufuncs.cosh,
                     "deg2rad": xr.ufuncs.deg2rad,
                     "degrees": xr.ufuncs.degrees,
                     "exp": xr.ufuncs.exp,
                     "expm1": xr.ufuncs.expm1,
                     "fabs": xr.ufuncs.fabs,
                     "fix": xr.ufuncs.fix,
                     "floor": xr.ufuncs.floor,
                     "frexp": xr.ufuncs.frexp,
                     "imag": xr.ufuncs.imag,
                     "iscomplex": xr.ufuncs.iscomplex,
                     "isfinite": xr.ufuncs.isfinite,
                     "isinf": xr.ufuncs.isinf,
                     "isnan": xr.ufuncs.isnan,
                     "isreal": xr.ufuncs.isreal,
                     "log": xr.ufuncs.log,
                     "log10": xr.ufuncs.log10,
                     "log1p": xr.ufuncs.log1p,
                     "log2": xr.ufuncs.log2,
                     "rad2deg": xr.ufuncs.rad2deg,
                     "radians": xr.ufuncs.radians,
                     "real": xr.ufuncs.real,
                     "rint": xr.ufuncs.rint,
                     "sign": xr.ufuncs.sign,
                     "signbit": xr.ufuncs.signbit,
                     "sin": xr.ufuncs.sin,
                     "sinh": xr.ufuncs.sinh,
                     "sqrt": xr.ufuncs.sqrt,
                     "square": xr.ufuncs.square,
                     "tan": xr.ufuncs.tan,
                     "tanh": xr.ufuncs.tanh,
                     "trunc": xr.ufuncs.trunc}

        # Define xarray DataArray operators with 2 input parameter
        self.xfn2 = {"arctan2": xr.ufuncs.arctan2,
                     "copysign": xr.ufuncs.copysign,
                     "fmax": xr.ufuncs.fmax,
                     "fmin": xr.ufuncs.fmin,
                     "fmod": xr.ufuncs.fmod,
                     "hypot": xr.ufuncs.hypot,
                     "ldexp": xr.ufuncs.ldexp,
                     "logaddexp": xr.ufuncs.logaddexp,
                     "logaddexp2": xr.ufuncs.logaddexp2,
                     "logicaland": xr.ufuncs.logical_and,
                     "logicalnot": xr.ufuncs.logical_not,
                     "logicalor": xr.ufuncs.logical_or,
                     "logicalxor": xr.ufuncs.logical_xor,
                     "maximum": xr.ufuncs.maximum,
                     "minimum": xr.ufuncs.minimum,
                     "nextafter": xr.ufuncs.nextafter}

        # Define non-xarray DataArray operators with 2 input parameter
        self.fn2 = {"percentile": np.percentile}

        # Define xarray DataArray reduction operators
        self.xrfn = {"all": xr.DataArray.all,
                     "any": xr.DataArray.any,
                     "argmax": xr.DataArray.argmax,
                     "argmin": xr.DataArray.argmin,
                     "max": xr.DataArray.max,
                     "mean": xr.DataArray.mean,
                     "median": xr.DataArray.median,
                     "min": xr.DataArray.min,
                     "prod": xr.DataArray.prod,
                     "sum": xr.DataArray.sum,
                     "std": xr.DataArray.std,
                     "var": xr.DataArray.var}

        # Define non-xarray DataArray operators with 2 input parameter
        self.xcond = {"<": np.percentile}

        # Define Grammar
        point = Literal(".")
        e = CaselessLiteral("E")
        fnumber = Combine(Word("+-"+nums, nums) +
                          Optional(point + Optional(Word(nums))) +
                          Optional(e + Word("+-"+nums, nums)))
        variable = Word(alphas, alphas+nums+"_$")

        seq = Literal("=")
        b_not = Literal("~")
        plus = Literal("+")
        minus = Literal("-")
        mult = Literal("*")
        div = Literal("/")
        gt = Literal(">")
        gte = Literal(">=")
        lt = Literal("<")
        lte = Literal("<=")
        eq = Literal("==")
        neq = Literal("!=")
        b_or = Literal("|")
        b_and = Literal("&")
        l_not = Literal("!")
        lpar = Literal("(").suppress()
        rpar = Literal(")").suppress()
        comma = Literal(",")
        colon = Literal(":")
        lbrac = Literal("[")
        rbrac = Literal("]")
        lcurl = Literal("{")
        rcurl = Literal("}")
        qmark = Literal("?")
        scolon = Literal(";")
        addop = plus | minus
        multop = mult | div
        sliceop = colon
        compop = gte | lte | gt | lt
        eqop = eq | neq
        bitcompop = b_or | b_and
        bitnotop = b_not
        logicalnotop = l_not
        assignop = seq
        expop = Literal("^")

        expr = Forward()
        indexexpr = Forward()

        atom = (Optional("-") +
                (variable + seq + expr).setParseAction(self.push_assign) |
                indexexpr.setParseAction(self.push_index) |
                (lpar + expr + qmark.setParseAction(self.push_ternary1) + expr +
                 scolon.setParseAction(self.push_ternary2) + expr +
                 rpar).setParseAction(self.push_ternary) |
                (lpar + expr + qmark + expr + scolon + expr +
                 rpar).setParseAction(self.push_ternary) |
                (logicalnotop + expr).setParseAction(self.push_ulnot) |
                (bitnotop + expr).setParseAction(self.push_unot) |
                (minus + expr).setParseAction(self.push_uminus) |
                (variable + lcurl + expr +
                 rcurl).setParseAction(self.push_mask) |
                (variable + lpar + expr + (comma + expr)*3 +
                 rpar).setParseAction(self.push_expr4) |
                (variable + lpar + expr + (comma + expr)*2 +
                 rpar).setParseAction(self.push_expr3) |
                (variable + lpar + expr + comma + expr +
                 rpar).setParseAction(self.push_expr2) |
                (variable + lpar + expr + rpar |
                 variable).setParseAction(self.push_expr1) |
                fnumber.setParseAction(self.push_expr) |
                (lpar + expr + ZeroOrMore(comma + expr).setParseAction(self.get_tuple) +
                 rpar).setParseAction(self.push_tuple) |
                (lpar + expr.suppress() +
                 rpar).setParseAction(self.push_uminus))

        # Define order of operations for operators

        factor = Forward()
        factor << atom + ZeroOrMore((expop + factor).setParseAction(self.push_op))
        term = factor + ZeroOrMore((multop + factor).setParseAction(self.push_op))
        term2 = term + ZeroOrMore((addop + term).setParseAction(self.push_op))
        term3 = term2 + ZeroOrMore((sliceop + term2).setParseAction(self.push_op))
        term4 = term3 + ZeroOrMore((compop + term3).setParseAction(self.push_op))
        term5 = term4 + ZeroOrMore((eqop + term4).setParseAction(self.push_op))
        term6 = term5 + ZeroOrMore((bitcompop + term5).setParseAction(self.push_op))
        expr << term6 + ZeroOrMore((assignop + term6).setParseAction(self.push_op))

        # Define index operators

        colon_expr = (colon + FollowedBy(comma) ^ colon +
                      FollowedBy(rbrac)).setParseAction(self.push_colon)
        range_expr = colon_expr | expr | colon
        indexexpr << (variable + lbrac + delimitedList(range_expr, delim=',') +
                      rbrac).setParseAction(self.push_expr)

        self.parser = expr
Пример #24
0
class ExpressionParser(ParserElement):
    """Base class for parsing mathematical expressions from a string format into a symbolic representation of the
    mathematical operation expressed by it.

    Parameters
    ----------
    expr_str
        Mathematical expression in string format.
    args
        Dictionary containing all variables and functions needed to evaluate the expression.
    backend
        Backend instance in which to parse all variables and operations.
        See `pyrates.backend.numpy_backend.NumpyBackend` for a full documentation of the backends methods and
        attributes.
    kwargs
        Additional keyword arguments to be passed to the backend functions.

    Attributes
    ----------
    lhs
        Boolean, indicates whether expression is left-hand side or right-hand side of an equation
    rhs
        PyRatesOp for the evaluation of the right-hand side of the equation
    args
        Dictionary containing the variables of an expression
    solve
        Only relevant for lhs expressions. If True, lhs will be treated as a first-order ordinary differential equation.
    expr_str
        String representation of the mathematical expression
    expr
        Symbolic (Pyparsing-based) representation of mathematical expression.
    expr_stack
        List representation of the syntax tree of the (parsed) mathematical expression.
    expr_list
        List representation of the mathematical expression.
    op
        Operator for calculating the mathematical expression (symbolic representation).
    _op_tmp
        Helper variable for building `op`.
    ops
        Dictionary containing all mathematical operations that are allowed for a specific instance of the
        `ExpressionParser` (e.g. +, -, *, /).
    funcs
        Dictionary containing all additional functions that can be used within mathematical expressions with a specific
        instance of the `ExpressionParser` (e.g. sum(), reshape(), float32()).
    dtypes
        Dictionary containing all data-types that can be used within mathematical expressions with a specific instance
        of the `ExpressionParser` (e.g. float32, bool, int32).

    """
    def __init__(self, expr_str: str, args: dict, backend: tp.Any,
                 **kwargs) -> None:
        """Instantiates expression parser.
        """

        # call super init
        #################

        super().__init__()

        # bind attributes to instance
        #############################

        # input arguments
        self.vars = args.copy()
        self.var_map = {}
        self.backend = backend
        self.parser_kwargs = kwargs

        self.lhs, self.rhs, self._diff_eq, self._assign_type, self.lhs_key = self._preprocess_expr_str(
            expr_str)

        # add functions from args dictionary to backend, if passed
        for key, val in args.items():
            if callable(val):
                self.backend.ops[key] = val

        # additional attributes
        self.expr_str = expr_str
        self.expr = None
        self.expr_stack = []
        self.expr_list = []
        self.op = None
        self._finished_rhs = False
        self._instantaneous = kwargs.pop('instantaneous', False)

        # define algebra
        ################

        if not self.expr:

            # general symbols
            point = Literal(".")
            comma = Literal(",")
            colon = Literal(":")
            e = CaselessLiteral("E")
            pi = CaselessLiteral("PI")

            # parentheses
            par_l = Literal("(")
            par_r = Literal(")").setParseAction(self._push_first)
            idx_l = Literal("[")
            idx_r = Literal("]")

            # basic mathematical operations
            plus = Literal("+")
            minus = Literal("-")
            mult = Literal("*")
            div = Literal("/")
            mod = Literal("%")
            dot = Literal("@")
            exp_1 = Literal("^")
            exp_2 = Combine(mult + mult)
            transp = Combine(point + Literal("T"))
            inv = Combine(point + Literal("I"))

            # numeric types
            num_float = Combine(
                Word("-" + nums, nums) +
                Optional(point + Optional(Word(nums))) +
                Optional(e + Word("-" + nums, nums)))
            num_int = Word("-" + nums, nums)

            # variables and functions
            name = Word(alphas, alphas + nums + "_$")
            func_name = Combine(name + par_l, adjacent=True)

            # math operation groups
            op_add = plus | minus
            op_mult = mult | div | dot | mod
            op_exp = exp_1 | exp_2 | inv | transp

            # logical operations
            greater = Literal(">")
            less = Literal("<")
            equal = Combine(Literal("=") + Literal("="))
            unequal = Combine(Literal("!") + Literal("="))
            greater_equal = Combine(Literal(">") + Literal("="))
            less_equal = Combine(Literal("<") + Literal("="))

            # logical operations group
            op_logical = greater_equal | less_equal | unequal | equal | less | greater

            # pre-allocations
            self.expr = Forward()
            exponential = Forward()
            index_multiples = Forward()

            # basic organization units
            index_start = idx_l.setParseAction(self._push_first)
            index_end = idx_r.setParseAction(self._push_first)
            index_comb = colon.setParseAction(self._push_first)
            arg_comb = comma.setParseAction(self._push_first)
            arg_tuple = par_l + ZeroOrMore(self.expr.suppress() +
                                           Optional(arg_comb)) + par_r
            func_arg = arg_tuple | self.expr.suppress()

            # basic computation unit
            atom = (func_name + Optional(func_arg.suppress()) + ZeroOrMore(arg_comb.suppress() + func_arg.suppress()) +
                    par_r.suppress() | name | pi | e | num_float | num_int).setParseAction(self._push_neg_or_first) | \
                   (par_l.setParseAction(self._push_last) + self.expr.suppress() + par_r).setParseAction(self._push_neg)

            # apply indexing to atoms
            indexed = (Optional(minus) + atom).setParseAction(self._push_neg) + \
                      ZeroOrMore((index_start + index_multiples + index_end))
            index_base = (self.expr.suppress() | index_comb)
            index_full = index_base + ZeroOrMore(
                (index_comb + index_base)) + ZeroOrMore(index_comb)
            index_multiples << index_full + ZeroOrMore((arg_comb + index_full))

            # hierarchical relationships between mathematical and logical operations
            boolean = indexed + Optional(
                (op_logical + indexed).setParseAction(self._push_first))
            exponential << boolean + ZeroOrMore(
                (op_exp + Optional(exponential)).setParseAction(
                    self._push_first))
            factor = exponential + ZeroOrMore(
                (op_mult + exponential).setParseAction(self._push_first))
            expr = factor + ZeroOrMore(
                (op_add + factor).setParseAction(self._push_first))
            self.expr << expr  #(Optional(minus) + expr).setParseAction(self._push_neg)

    def parse_expr(self) -> tuple:
        """Parses string-based mathematical expression/equation.

        Returns
        -------
        tuple
            left-hand side, right-hand side and variables of the parsed equation.
        """

        # extract symbols and operations from equations right-hand side
        self.expr_list = self.expr.parseString(self.rhs)
        self._check_parsed_expr(self.rhs)

        # parse rhs into backend
        self.rhs = self.parse(self.expr_stack[:])

        # post rhs parsing steps
        if hasattr(self.rhs, 'vtype') or "float" in str(type(
                self.rhs)) or "int" in str(type(self.rhs)):
            self.rhs = self.backend.add_op('no_op', self.rhs,
                                           **self.parser_kwargs)
        self.clear()
        self._finished_rhs = True

        # extract symbols and operations from left-hand side
        self.expr_list = self.expr.parseString(self.lhs)
        self._check_parsed_expr(self.lhs)

        # parse lhs into backend
        self._update_lhs()

        return self.lhs, self.rhs, self.vars

    def parse(self, expr_stack: list) -> tp.Any:
        """Parse elements in expression stack into the backend.

        Parameters
        ----------
        expr_stack
            Ordered list with expression variables and operations. Needs to be processed from last to first item.

        Returns
        -------
        tp.Any
            Parsed expression stack element (object type depends on the backend).

        """

        # get next operation from stack
        op = expr_stack.pop()

        # check type of operation
        #########################

        if op == '-one':

            # multiply expression by minus one
            self.op = self.backend.add_op('*', self.parse(expr_stack), -1,
                                          **self.parser_kwargs)

        elif op in ["*=", "/=", "+=", "-=", "="]:

            # collect rhs
            op1 = self.parse(expr_stack)

            # collect lhs
            indexed_lhs = True if "]" in expr_stack else False
            op2 = self.parse(expr_stack)

            # combine elements via mathematical/boolean operator
            if indexed_lhs:
                self.op = self._apply_idx(op=op2[0],
                                          idx=op2[1],
                                          update=op1,
                                          update_type=op,
                                          **self.parser_kwargs)
            else:
                self.op = self.backend.add_op(op, op2, op1,
                                              **self.parser_kwargs)

        elif op in "+-/**^@<=>=!==%":

            # collect elements to combine
            op2 = self.parse(expr_stack)
            op1 = self.parse(expr_stack)

            # combine elements via mathematical/boolean operator
            self.op = self.backend.add_op(op, op1, op2, **self.parser_kwargs)

        elif ".T" == op or ".I" == op:

            # transpose/invert expression
            self.op = self.backend.add_op(op, self.parse(expr_stack),
                                          **self.parser_kwargs)

        elif op == "]":

            # parse indices
            indices = []
            while len(expr_stack) > 0 and expr_stack[-1] != "[":
                index = []
                while len(expr_stack) > 0 and expr_stack[-1] not in ",[":
                    if expr_stack[-1] == ":":
                        index.append(expr_stack.pop())
                    else:
                        try:
                            int(expr_stack[-1])
                            index.append(expr_stack.pop())
                        except ValueError:
                            tmp = self._finished_rhs
                            self._finished_rhs = False
                            index.append(self.parse(expr_stack))
                            self._finished_rhs = tmp
                indices.append(index[::-1])
                if expr_stack[-1] == ",":
                    expr_stack.pop()
            expr_stack.pop()

            # build string-based representation of idx
            if 'idx' not in self.vars.keys():
                self.vars['idx'] = {}
            idx = ""
            i = 0
            for index in indices[::-1]:
                for ind in index:
                    if type(ind) == str:
                        idx += ind
                    elif isinstance(ind, Number):
                        idx += f"{ind}"
                    else:
                        self.vars['idx'][f'idx_var_{i}'] = ind
                        idx += f"idx_var_{i}"
                    i += 1
                idx += ","
            idx = idx[0:-1]

            # extract variable and apply idx if its a rhs variable. Else return variable and index
            if self._finished_rhs:
                op = expr_stack.pop(-1)
                if op in self.vars:
                    op_to_idx = self.vars[op]
                else:
                    op_to_idx = self.parse([op])
                self.op = (op_to_idx, idx)
            else:
                op_to_idx = self.parse(expr_stack)
                op_idx = self._apply_idx(op_to_idx, idx, **self.parser_kwargs)
                self.op = op_idx

        elif op == "PI":

            # return float representation of pi
            self.op = math.pi

        elif op == "E":

            # return float representation of e
            self.op = math.e

        elif op in self.vars:

            # extract constant/variable from args dict
            self.op = self.vars[op]

        elif op[-1] == "(":

            expr_stack.pop(-1)

            # parse arguments
            args = []
            while len(expr_stack) > 0:
                args.append(self.parse(expr_stack))
                if len(expr_stack) == 0 or expr_stack[-1] != ",":
                    break
                else:
                    expr_stack.pop()

            # apply function to arguments
            try:
                if len(args) == 1:
                    self.op = self.backend.add_op(op[0:-1], args[0],
                                                  **self.parser_kwargs)
                else:
                    self.op = self.backend.add_op(op[0:-1], *tuple(args[::-1]),
                                                  **self.parser_kwargs)
            except KeyError:
                if any([
                        "float" in op, "bool" in op, "int" in op, "complex"
                        in op
                ]):
                    self.op = self.backend.add_op('cast', args[0], op[0:-1],
                                                  **self.parser_kwargs)
                else:
                    raise KeyError(
                        f"Undefined function in expression: {self.expr_str}. {op[0:-1]} needs to be "
                        f"provided in arguments dictionary.")

        elif op == ")":

            # check whether expression in parenthesis is a group of arguments to a function
            start_par = -1
            found_end = 0
            while found_end < 1:
                if "(" in expr_stack[start_par]:
                    found_end += 1
                if ")" in expr_stack[start_par]:
                    found_end -= 1
                start_par -= 1
            if "," in expr_stack[start_par + 1:]:

                args = []
                while True:
                    args.append(self.parse(expr_stack))
                    if expr_stack[-1] == ",":
                        expr_stack.pop(-1)
                    elif expr_stack[-1] == "(":
                        expr_stack.pop(-1)
                        break
                    else:
                        break
                self.op = args[::-1]

            else:

                self.op = self.parse(expr_stack)
                expr_stack.pop(-1)

        elif any([op == "True", op == "true", op == "False", op == "false"]):

            # return boolean
            self.op = True if op in "Truetrue" else False

        elif any(["float" in op, "bool" in op, "int" in op, "complex" in op]):

            expr_stack.pop(-1)

            # extract data type
            try:
                self.op = self.backend.add_op('cast', self.parse(expr_stack),
                                              op[0:-1], **self.parser_kwargs)
            except AttributeError:
                raise AttributeError(
                    f"Datatype casting error in expression: {self.expr_str}. "
                    f"{op[0:-1]} is not a valid data-type for this parser.")

        elif "." in op:

            self.op = float(op)

        elif op.isnumeric():

            self.op = int(op)

        elif op[0].isalpha():

            if self._finished_rhs:

                if op == 'rhs':
                    self.op = self.rhs
                else:
                    shape = self.rhs.shape if hasattr(self.rhs,
                                                      'shape') else ()
                    dtype = self.rhs.dtype if hasattr(
                        self.rhs, 'dtype') else type(self.rhs)
                    self.op = self.backend.add_var(vtype='state_var',
                                                   name=op,
                                                   shape=shape,
                                                   dtype=dtype,
                                                   **self.parser_kwargs)
                    self.vars[op] = self.op

            elif op == 't':

                self.op = self.backend.add_var(vtype='state_var',
                                               name=op,
                                               shape=(),
                                               dtype='float',
                                               value=0.0,
                                               **self.parser_kwargs)

            else:

                raise ValueError(
                    f"Undefined variable detected in expression: {self.expr_str}. {op} was not found "
                    f"in the respective arguments dictionary.")

        else:

            raise ValueError(
                f"Undefined operation detected in expression: {self.expr_str}. {op} cannot be "
                f"interpreted by this parser.")

        return self.op

    def clear(self):
        """Clears expression list and stack.
        """
        self.expr_list.clear()
        self.expr_stack.clear()

    def _update_lhs(self):
        """Applies update to left-hand side of equation. For differential equations, different solving schemes are
        available.
        """

        # update left-hand side of equation
        ###################################

        diff_eq = self._diff_eq

        if diff_eq:

            lhs = self.vars[self.lhs_key]

            # update state variable vectors
            y_idx = self._append_to_var(var_name='y', val=lhs)
            self._append_to_var(var_name='y_delta', val=lhs)

            # extract left-hand side variable from state variable vector
            lhs_indexed = self.backend._create_op(
                'index', self.backend.ops['index']['name'], self.vars['y'],
                y_idx)
            lhs_indexed.short_name = lhs.short_name

            if 'y_' in lhs_indexed.value:
                del_start, del_end = lhs_indexed.value.index(
                    '_'), lhs_indexed.value.index('[')
                lhs_indexed.value = lhs_indexed.value[:
                                                      del_start] + lhs_indexed.value[
                                                          del_end:]
            self.vars[self.lhs_key] = lhs_indexed

            # assign rhs to state var delta vector
            self.rhs = self.backend.add_op('=', self.vars['y_delta'], self.rhs,
                                           y_idx, **self.parser_kwargs)

            # broadcast rhs and lhs and store results in backend
            self.backend.state_vars.append(lhs.name)
            self.backend.vars[lhs.name] = self.vars[self.lhs_key]
            self.rhs.state_var = lhs.name

        else:

            # simple update
            if not self._instantaneous:
                self.backend.next_layer()
            indexed_lhs = "]" in self.expr_stack
            self.lhs = self.parse(self.expr_stack + ['rhs', self._assign_type])
            if not indexed_lhs:
                self.backend.lhs_vars.append(self.vars[self.lhs_key].name)
            if not self._instantaneous:
                self.backend.previous_layer()

    def _preprocess_expr_str(self, expr: str) -> tuple:
        """Turns differential equations into simple algebraic equations using a certain solver scheme and extracts
        left-hand side, right-hand side and update type of the equation.

        Parameters
        ----------
        expr
            Equation in string format.

        Returns
        -------
        tuple
            Contains left hand side, right hand side and left hand side update type
        """

        # collect equation specifics
        ############################

        # split equation into lhs and rhs and assign type
        lhs, rhs, assign_type = split_equation(expr)

        if not assign_type:
            return self._preprocess_expr_str(f"x = {expr}")

        # for the left-hand side, check whether it includes a differential operator
        if "d/dt" in lhs:
            diff_eq = True
            lhs_split = lhs.split('*')
            lhs = "".join(lhs_split[1:])
        elif "'" in lhs:
            diff_eq = True
            lhs = lhs.replace("'", "")
        elif "d" in lhs and "/dt" in lhs:
            diff_eq = True
            lhs = lhs.split('/dt')[0]
            lhs = lhs.replace("d", "", count=1)
        else:
            diff_eq = False

        # get clean name of lhs
        lhs_key = lhs.split('[')[0]
        lhs_key = lhs_key.replace(' ', '')
        lhs = lhs.replace(' ', '')

        # store equation specifics
        if diff_eq and assign_type != '=':
            raise ValueError(
                f'Wrong assignment method for equation: {expr}. '
                f'A differential equation cannot be combined with an assign type other than `=`.'
            )

        return lhs, rhs, diff_eq, assign_type, lhs_key

    def _push_first(self, strg, loc, toks):
        """Push tokens in first-to-last order to expression stack.
        """
        self.expr_stack.append(toks[0])

    def _push_neg(self, strg, loc, toks):
        """Push negative one multiplier if on first position in toks.
        """
        if toks and toks[0] == '-':
            self.expr_stack.append('-one')

    def _push_neg_or_first(self, strg, loc, toks):
        """Push neg one multipler to expression stack if on first position in toks, else push toks from first-to-last.
        """
        if toks and toks[0] == '-':
            self.expr_stack.append('-one')
        else:
            self.expr_stack.append(toks[0])

    def _push_last(self, strg, loc, toks):
        """Push tokens in last-to-first order to expression stack.
        """
        self.expr_stack.append(toks[-1])

    def _apply_idx(self,
                   op: tp.Any,
                   idx: tp.Any,
                   update: tp.Optional[tp.Any] = None,
                   update_type: tp.Optional[str] = None,
                   **kwargs) -> tp.Any:
        """Apply index idx to operation op.

        Parameters
        ----------
        op
            Operation to be indexed.
        idx
            Index to op.
        update
            Update to apply to op at idx.
        update_type
            Type of left-hand side update (e.g. `=` or `+=`).
        kwargs
            Additional keyword arguments to be passed to the indexing functions.

        Returns
        -------
        tp.Any
            Result of applying idx to op.

        """

        kwargs.update(self.parser_kwargs)

        # get constants/variables that are part of the index
        args = []
        if idx in self.vars['idx']:
            idx = self.vars['idx'].pop(idx)
        if type(idx) is str:
            idx_old = idx
            idx = []
            for idx_tmp in idx_old.split(','):
                for idx_tmp2 in idx_tmp.split(':'):
                    idx.append(idx_tmp2)
                    if idx_tmp2 in self.vars['idx']:
                        idx_var = self.vars['idx'].pop(idx_tmp2)
                        if not hasattr(idx_var, 'short_name'):
                            if hasattr(idx_var, 'shape') and tuple(
                                    idx_var.shape):
                                idx_var = idx_var[0]
                            idx[-1] = f"{idx_var}"
                        else:
                            if "_evaluated" in idx_var.short_name:
                                idx[-1] = f"{idx_var.numpy()}"
                            else:
                                idx[-1] = idx_var.short_name
                                args.append(idx_var)
                    idx.append(':')
                idx.pop(-1)
                idx.append(',')
            idx.pop(-1)
            idx = "".join(idx)

        return self.backend.apply_idx(op, idx, update, update_type,
                                      *tuple(args))

    def _check_parsed_expr(self, expr_str: str) -> None:
        """check whether parsing of expression string was successful.

        Parameters
        ----------
        expr_str
            Expression that has been attempted to be parsed.
        """

        for sub_str in sorted(self.expr_stack, key=len)[::-1]:
            if sub_str == 'E':
                sub_str = 'e'
            expr_str = expr_str.replace(sub_str, "")
        expr_str = expr_str.replace(" ", "")
        expr_str = expr_str.replace("(", "")
        expr_str = expr_str.replace(")", "")
        expr_str = expr_str.replace("-", "")
        if len(expr_str) > 0:
            raise ValueError(
                f"Error while parsing expression: {self.expr_str}. {expr_str} could not be parsed."
            )

    def _append_to_var(self, var_name: str, val: tp.Any) -> str:

        # create variable vector if not existent
        if var_name not in self.vars:
            self.vars[var_name] = self.backend.add_var(vtype='state_var',
                                                       name=var_name,
                                                       shape=(),
                                                       dtype=val.dtype,
                                                       value=[],
                                                       squeeze=False)

        # append left-hand side variable to variable vector
        var = self.backend.remove_var(var_name)
        var_val = var.numpy().tolist()
        append_val = val.numpy().tolist()
        if sum(var.shape) and sum(val.shape):
            new_val = var_val + append_val
        elif sum(var.shape):
            new_val = var_val + [append_val]
        else:
            new_val = append_val if type(append_val) is list else [append_val]

        # add updated variable to backend
        self.vars[var_name] = self.backend.add_var(vtype='state_var',
                                                   name=var_name,
                                                   value=new_val,
                                                   shape=(len(new_val), ),
                                                   dtype=var.dtype,
                                                   squeeze=False)

        # return index to variable vector to retrieve appended values
        i1 = len(var_val) + self.backend.idx_start
        i2 = len(new_val) + self.backend.idx_start
        return f"{i1}:{i2}" if i2 - i1 > 1 else f"{i1}"

    @staticmethod
    def _compare(x: tp.Any, y: tp.Any) -> bool:
        """Checks whether x and y are equal or not.
        """
        test = x == y
        if hasattr(test, 'shape'):
            test = test.any()
        return test
Пример #25
0
    def init_grammar(self):
        LPAR, RPAR, LBRACK, RBRACK, LBRACE, RBRACE, SEMI, COMMA, EQUAL, COLON = map(Suppress, "()[]{};,=:")

        USE = Keyword("use")
        MODULE = Keyword("module")
        IF = Keyword("if")
        FOR = Keyword("for")
        ELSE = Keyword("else")
        TRUE = Keyword("true")
        FALSE = Keyword("false")
        UNDEF = Keyword("undef")
        mul_operator = oneOf("* /")
        add_operator = oneOf("+ -")
        exp_operator = Literal( "^" )

        boolOperand = ( TRUE | FALSE )
        boolOperand.setParseAction(BoolOperand)

        boolExpr = infixNotation( boolOperand, [
            ("not", 1, opAssoc.RIGHT, BoolNot),
            ("and", 2, opAssoc.LEFT,  BoolAnd),
            ("or",  2, opAssoc.LEFT,  BoolOr),
        ])

        identifier = Word("$" + alphas + "_", alphanums + "_")
        plusorminus = Literal('+') | Literal('-')
        numberal = Word(nums)
        e = CaselessLiteral('E')
        integer = Combine( Optional(plusorminus) + numberal )
        floatnumber = Combine( integer +
                       Optional( Literal('.') + Optional(numberal) ) +
                       Optional( e + integer )
                     )
        number = ( integer | floatnumber )

        calculation = Forward()
        atom = ( ( e | floatnumber | integer | identifier ).setParseAction( self.pushFirst ) |
                 ( LPAR + calculation.suppress() + RPAR )
               )

        factor = Forward()
        factor << atom + ZeroOrMore( ( exp_operator + factor ).setParseAction( self.pushFirst ) )

        term = factor + ZeroOrMore( ( mul_operator + factor ).setParseAction( self.pushFirst ) )
        calculation << term + ZeroOrMore( ( add_operator + term ).setParseAction( self.pushFirst ) )
        calculation.setParseAction(self.calculate)


        constant = number.setParseAction(self.constant_action)
        modifier_name = ( Keyword("translate") | Keyword("rotate") | Keyword("scale") | Keyword("simplify") )

        use = (USE + identifier("name") + SEMI).setParseAction(self.use_action)

        expression = Forward()

        arguments = delimitedList(expression("exp").setParseAction(self.argument_action))
        module_call = ((identifier("name") + FollowedBy("(")).setParseAction(self.module_call_prepare_action) +
                       LPAR + Optional(arguments)("args") + RPAR)
        module_call_statement = (module_call + SEMI).setParseAction(self.module_call_action)

        primitive_argument_assignment_value = (calculation | boolExpr)

        primitive_argument_assignment = (identifier("variable") + EQUAL + primitive_argument_assignment_value).setParseAction(self.primitive_argument_assignment_action)
        primitive_argument = (primitive_argument_assignment | expression("exp"))
        primitive_argument_list = delimitedList(primitive_argument.setParseAction(self.argument_action))

        modifier = ( (modifier_name + FollowedBy("(")).setParseAction(self.primitive_modifier_prepare_action) +
                              LPAR + Optional(primitive_argument_list)("args") + RPAR).setParseAction(self.primitive_modifier_action)

        primitive_call_statement = ( ZeroOrMore(modifier)("modifiers") + (identifier("name") + FollowedBy("(")).setParseAction(self.primitive_call_prepare_action) +
                                    LPAR + Optional(primitive_argument_list)("args") + RPAR + SEMI).setParseAction(self.primitive_call_action)

        expression << (boolExpr | calculation).setParseAction(self.debug_action)#.setParseAction(lambda x: x[0])

        statement = Forward()

        assign_statement = (identifier("variable") + EQUAL + expression("expression") + SEMI).setParseAction(self.assign_action)

        modifier_scope = ( (ZeroOrMore(modifier)("modifiers") + identifier("name") + LPAR + Optional(primitive_argument_list)("args") + RPAR + FollowedBy("{")).setParseAction(self.modifier_scope_prepare_action) +
                            LBRACE + ZeroOrMore(statement) + RBRACE ).setParseAction(self.modifier_scope_action)

        vector = (LBRACK + calculation + COLON + calculation + RBRACK).setParseAction(self.vector_action)

        for_loop_scope = ( ZeroOrMore(modifier)("modifiers") + ( FOR + LPAR + identifier("index") + EQUAL + vector("loop_range") + RPAR + FollowedBy("{") ).setParseAction(self.begin_for_loop_scope) +
                         LBRACE + ZeroOrMore(statement)("body") + RBRACE ).setParseAction(self.for_loop_scope_action)

        statement << ( for_loop_scope | primitive_call_statement | module_call_statement | Suppress(assign_statement) | modifier_scope )

        body = OneOrMore(statement)

        self.program = (ZeroOrMore(use) + body).setParseAction(self.program_end_action)
Пример #26
0
	def __init__(self):
		# 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('$',alphanums + '_') 

		plus  = Literal( "+" )
		minus = Literal( "-" )
		mult  = Literal( "*" )
		div   = Literal( "/" )
		lpar  = Literal( "(" ).suppress()
		rpar  = Literal( ")" ).suppress()
		addop  = plus | minus
		multop = mult | div
		expop = Literal( "^" )	

		expr = Forward()
		def defineFunction(name, parameterCount=None):
			keyword = CaselessKeyword(name).setParseAction(self.pushEnd)
			funcPattern = keyword + lpar
			if parameterCount == None:
				funcPattern += Optional(expr+ZeroOrMore(Literal(',')+expr))
			elif parameterCount > 0:
				funcPattern += expr
				for i in range(parameterCount-1):
					funcPattern += Literal(',') + expr
			funcPattern += rpar
			return funcPattern.setParseAction(self.pushFirst)
		maxFunc = defineFunction('max')
		minFunc = defineFunction('min')
		casesFunc = defineFunction('cases')
		cases1Func = defineFunction('cases1', parameterCount = 5)
		cases2Func = defineFunction('cases2', parameterCount = 8)
		cases3Func = defineFunction('cases3', parameterCount = 11)
		cases333Func = defineFunction('cases333', parameterCount = 11)
		round3downFunc = defineFunction('round3down', parameterCount = 1)
		
		#func = (funcident.setParseAction(self.pushEnd)+lpar +Optional(expr+ZeroOrMore(Literal(',')+expr))+rpar).setParseAction(self.pushFirst)
		atom = ( maxFunc | minFunc | casesFunc | cases1Func | cases2Func | cases3Func | cases333Func| round3downFunc |
				( e | floatnumber | integer | ident ).setParseAction(self.pushFirst) |
				( lpar + expr.suppress() + rpar )
			)
				
		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 ) )

		self.pattern =  expr + StringEnd()
		# map operator symbols to corresponding arithmetic operations
		self.opn = { "+" : self.handleNone( lambda a,b: a + b ),
				"-" : self.handleNone( lambda a,b: a - b ),
				"*" : self.handleNone( lambda a,b: a * b, none_survives=True ),
				"/" : self.handleNone( lambda a,b: a / b, none_survives=True ),
				"^" : self.handleNone( lambda a,b: a ** b, none_survives=True ) }
		self.functions = { 'max': max,
			'min': self.min,
			'cases': self.cases,
			'cases1': self.cases1,
			'cases2': self.cases2,
			'cases3': self.cases3,
			'cases333': self.cases333,
			'round3down': self.round3down
			}
Пример #27
0
def BNF():
    """
    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 ]*
    equation:: expr [equality expr]*
    logic :: equation [logicalop equation]*
    """
    global bnf
    if not bnf:
        point = Literal(".")
        e = CaselessLiteral("E")
        fnumber = Combine(
            Word("+-" + nums, nums) + Optional(point + Optional(Word(nums))) +
            Optional(e + Word("+-" + nums, nums)))
        #columnName = Word(alphanums)

        ident = Word(alphas + ChineseCharacters.unicodeList + nums,
                     ChineseCharacters.unicodeList + alphas + nums + "_$[]")

        plus = Literal("+")
        minus = Literal("-")
        mult = Literal("*")
        div = Literal("/")
        andand = Literal("&&")
        oror = Literal("||")
        is_a1 = Literal("==")
        is_a2 = Literal("=")
        is_a = is_a1 | is_a2
        less_than = Literal("<")
        bigger_than = Literal(">")
        bigger_or_equal = Literal(">=")
        less_or_equal = Literal("<=")
        is_not_a = Literal("!=")

        lpar = Literal("(").suppress()
        rpar = Literal(")").suppress()
        addop = plus | minus
        multop = mult | div
        compop = is_a | is_not_a | less_than | bigger_than
        compop2 = bigger_or_equal | less_or_equal
        logical = andand | oror
        expop = Literal("^")
        pi = CaselessLiteral("PI")

        logic = Forward()
        atom = (Optional("-") +
                (ident | e | fnumber
                 | pi + lpar + logic + rpar).setParseAction(pushFirst) |
                (lpar + logic.suppress() + 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))
        equation = expr + ZeroOrMore((compop + expr).setParseAction(pushFirst))
        equation2 = equation + ZeroOrMore(
            (compop2 + expr).setParseAction(pushFirst))
        logic << equation2 + ZeroOrMore(
            (logical + equation2).setParseAction(pushFirst))
        bnf = logic
    return bnf
Пример #28
0
def BNF():
    """
    expop   :: '^'
    multop  :: '*' | '/' | '>>' | '<<' | '|' | '&'
    addop   :: '+' | '-'
    hex     :: '0x' + integer
    integer :: ['+' | '-'] '0'..'9'+
    atom    :: PI | E | real | fn '(' expr ')' | '(' expr ')'
    factor  :: atom [ expop factor ]*
    term    :: factor [ multop factor ]*
    expr    :: term [ addop term ]*
    """
    global bnf

    if not bnf:
        point = Literal( "." )
        e     = CaselessLiteral( "E" )
        hexnum = CaselessLiteral("0x") + OneOrMore(oneOf(nums + 'a b c d e f A B C D E F'))
        hexnum.setParseAction(lambda s,l,t:str(int(''.join(t),16)))
        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( "/" )
        lshift  = Literal( "<<" )
        rshift  = Literal( ">>" )
        or_  = Literal( "|" )
        and_  = Literal( "&" )
        lpar  = Literal( "(" ).suppress()
        rpar  = Literal( ")" ).suppress()
        addop  = plus | minus
        multop = mult | div | lshift | rshift | or_ | and_
        expop = Literal( "^" )
        pi    = CaselessLiteral( "PI" )

        expr = Forward()
        atom = (Optional("-") + ( pi | e | hexnum | fnumber | ident + lpar + expr + rpar ).setParseAction( pushFirst ) | ( lpar + expr.suppress() + 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
Пример #29
0
 def grammar(self):
     if not self.bnf:
         point = Literal( "." )
         fnumber = Combine( Word( nums ) + 
                            Optional( point + Optional( Word( nums ) ) ) 
                            )
         ident = Word(alphas.lower()+"_", alphanums+"_")
         plus  = Literal( "+" )
         minus = Literal( "-" )
         mult  = Literal( "*" )
         # passiverate = Word('infty') | Word('T')
         div   = Literal( "/" )
         lpar  = Literal( "(" ).suppress()
         rpar  = Literal( ")" ).suppress()
         addop  = plus | minus
         multop = mult | div
         assign = Literal('=')
         expop = Literal( "^" )
         expr = Forward()
         atom = Optional("-") + ( fnumber | ident + lpar + expr + rpar | ident).setParseAction(self._pushFirst ) | lpar + expr.suppress() + rpar 
         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 ) )
         bnf = (ident + assign).setParseAction(self._assignVar) + expr 
         self.bnf = bnf
     return self.bnf
Пример #30
0
    def BNF(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 ]*
        """
        #global bnf
        if not self.bnf:
            point = Literal(".")
            fnumber = Combine(
                Word("+-" + nums, nums) +
                Optional(point + Optional(Word(nums))))
            ident = Word(alphas, alphas + nums + "_$")
            sensor_ident = (CaselessLiteral('GET_SENSOR_VAL:').suppress() +
                            Word(alphas + nums + "_$")).setParseAction(
                                self.get_sensor_value)

            and_ = CaselessLiteral('AND')
            or_ = CaselessLiteral('OR')
            not_ = CaselessLiteral('NOT')
            neq = CaselessLiteral('!=')
            lt = Literal('<')
            eqlt = CaselessLiteral('<=')
            gt = Literal('>')
            eqgt = CaselessLiteral('>=')
            eq = CaselessLiteral('==')

            plus = Literal("+")
            minus = Literal("-")
            mult = Literal("*")
            div = Literal("/")
            lpar = Literal("(").suppress()
            rpar = Literal(")").suppress()
            add_op = plus | minus
            mult_op = mult | div
            cmp_op = eqlt | eqgt | eq | neq | lt | gt

            expr = Forward()
            atom = (Optional("-") +
                    (fnumber | sensor_ident |
                     ident + lpar + expr + rpar).setParseAction(self.pushFirst)
                    | (lpar + expr.suppress() + rpar)).setParseAction(
                        self.pushUMinus)

            term = atom + ZeroOrMore(
                (mult_op + atom).setParseAction(self.pushFirst))
            add_exp = term + ZeroOrMore(
                (add_op + term).setParseAction(self.pushFirst))
            cmp_exp = add_exp + ZeroOrMore(
                (cmp_op + add_exp).setParseAction(self.pushFirst))
            cmp_not_exp = cmp_exp + ZeroOrMore(
                (not_ + cmp_exp).setParseAction(self.pushFirst))
            cmp_not_and_exp = cmp_not_exp + ZeroOrMore(
                (and_ + cmp_not_exp).setParseAction(self.pushFirst))
            cmp_not_and_or_exp = cmp_not_and_exp + ZeroOrMore(
                (or_ + cmp_not_and_exp).setParseAction(self.pushFirst))
            expr << cmp_not_and_or_exp
            self.bnf = expr
        return self.bnf
Пример #31
0
    def init_parser(self):
        """
        expop   :: '^'
        multop  :: '*' | '/'
        addop   :: '+' | '-'
        integer :: ['+' | '-'] '0'..'9'+
        atom    :: real | Word(alphas) | array | fn '(' expr ')' | '(' expr ')'
        factor  :: atom [ expop factor ]*
        term    :: factor [ multop factor ]*
        expr    :: term [ addop term ]*
        """
        
        atoms = self.language.get_parser_atoms()

        variable = atoms['variable']#.setParseAction(downcaseTokens)

        func_lpar  = atoms['func_lpar'].setParseAction(self._push2stack('('))
        func_delim = atoms['func_delim']
        func_rpar  = atoms['func_rpar'].setParseAction(self._push2stack(')'))

        array_lpar  = atoms['array_lpar'].setParseAction(self._push2stack('['))
        array_delim = atoms['array_delim']
        array_rpar  = atoms['array_rpar'].setParseAction(self._push2stack(']'))

        lpar   = atoms['lpar'].suppress()
        rpar   = atoms['rpar'].suppress()
        expop  = atoms['exp']
        
        addop  = atoms['plus'] | atoms['minus']
        multop = atoms['mult'] | atoms['div']
        cmpop  = atoms['equal']

        expr = Forward() # forward declaration of an entire expression
        # this is necessary for defining the recursive grammar
        
        # smallest entity of a mathematical expression:
        array = variable + \
            array_lpar + \
            atoms['int'].addParseAction(self.push_first) + \
            ZeroOrMore(array_delim + atoms['int']) + \
            array_rpar
        
        func_call = atoms['function'].setParseAction(downcaseTokens) + \
            func_lpar + \
            expr + \
            ZeroOrMore(func_delim + expr) + \
            func_rpar
            
        
        obj = (atoms['consts'] | atoms['float'] | array | func_call | variable)
        atom = (
                Optional("-") + # optional unary minus
                (
                    obj.addParseAction(self.push_first) |
                    (lpar + expr.suppress() + rpar) # subexpression
               )
           ).setParseAction(self.push_unary_minus)
        
        # 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.push_first)
           )

        # sequence of multiplications
        term = factor + ZeroOrMore(
                (multop + factor).setParseAction(self.push_first)
           )
        
        # sequence of summations
        expr << term + ZeroOrMore(
                (addop + term).setParseAction(self.push_first)
           )
        
        # comparison operators
        equation = expr + \
            Optional(cmpop + expr).setParseAction(self.push_first)

        # assignment operator
        self.parser = (
                (variable ^ array).setParseAction(self.push_first) + 
                atoms['assign'] +
                equation
           ).setParseAction(self._push2stack('=')) | \
            equation

        return self.parser
Пример #32
0
    def __init__(self):
        # 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('$', alphanums + '_')

        plus = Literal("+")
        minus = Literal("-")
        mult = Literal("*")
        div = Literal("/")
        lpar = Literal("(").suppress()
        rpar = Literal(")").suppress()
        addop = plus | minus
        multop = mult | div
        expop = Literal("^")

        expr = Forward()

        def defineFunction(name, parameterCount=None):
            keyword = CaselessKeyword(name).setParseAction(self.pushEnd)
            funcPattern = keyword + lpar
            if parameterCount == None:
                funcPattern += Optional(expr + ZeroOrMore(Literal(',') + expr))
            elif parameterCount > 0:
                funcPattern += expr
                for i in range(parameterCount - 1):
                    funcPattern += Literal(',') + expr
            funcPattern += rpar
            return funcPattern.setParseAction(self.pushFirst)

        maxFunc = defineFunction('max')
        minFunc = defineFunction('min')
        casesFunc = defineFunction('cases')
        cases1Func = defineFunction('cases1', parameterCount=5)
        cases2Func = defineFunction('cases2', parameterCount=8)
        cases3Func = defineFunction('cases3', parameterCount=11)
        cases333Func = defineFunction('cases333', parameterCount=11)
        round3downFunc = defineFunction('round3down', parameterCount=1)

        #func = (funcident.setParseAction(self.pushEnd)+lpar +Optional(expr+ZeroOrMore(Literal(',')+expr))+rpar).setParseAction(self.pushFirst)
        atom = (maxFunc | minFunc | casesFunc | cases1Func | cases2Func
                | cases3Func | cases333Func | round3downFunc |
                (e | floatnumber | integer | ident).setParseAction(
                    self.pushFirst) | (lpar + expr.suppress() + rpar))

        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))

        self.pattern = expr + StringEnd()
        # map operator symbols to corresponding arithmetic operations
        self.opn = {
            "+": self.handleNone(lambda a, b: a + b),
            "-": self.handleNone(lambda a, b: a - b),
            "*": self.handleNone(lambda a, b: a * b, none_survives=True),
            "/": self.handleNone(lambda a, b: a / b, none_survives=True),
            "^": self.handleNone(lambda a, b: a**b, none_survives=True)
        }
        self.functions = {
            'max': self.max,
            'min': self.min,
            'cases': self.cases,
            'cases1': self.cases1,
            'cases2': self.cases2,
            'cases3': self.cases3,
            'cases333': self.cases333,
            'round3down': self.round3down
        }
Пример #33
0
class FormulaParser(object):
    """
    Deconstruct mathematical algebra expressions and convert those into
    callable funcitons.


    Deconstruct mathematical algebra expressions and convert those into
    callable funcitons.

    This formula parser was inspired by the fourFun pyparsing example and also
    benefited from additional substantial contributions by Paul McGuire.
    This module uses pyparsing for this purpose and the parser is adopted from
    the `fourFun example`__.

    Example usage::

        >>> parser = FormulaParser()
        >>> parser.set_formula('log(a * 3 + b)')
        >>> parser.evaluate({'a': 5, 'b': 23})
        ... 3.6375861597263857
        >>> parser.evaluate({'a': [5, 6, 7], 'b': [23, 24, 25]})
        ... array([ 3.63758616,  3.73766962,  3.8286414 ])

    __ http://pyparsing.wikispaces.com/file/view/fourFn.py
    """
    def __init__(self):
        """
        Setup the Backus Normal Form (BNF) parser logic.
        """
        # Set an empty formula attribute
        self.formula = None

        # Instantiate blank parser for BNF construction
        self.bnf = Forward()

        # Expression for parenthesis, which are suppressed in the atoms
        # after matching.
        lpar = Literal(const.LPAR).suppress()
        rpar = Literal(const.RPAR).suppress()

        # Expression for mathematical constants: Euler number and Pi
        e = Keyword(const.EULER)
        pi = Keyword(const.PI)
        null = Keyword(const.NULL)
        _true = Keyword(const.TRUE)
        _false = Keyword(const.FALSE)

        # Prepare operator expressions
        addop = oneOf(const.ADDOP)
        multop = oneOf(const.MULTOP)
        powop = oneOf(const.POWOP)
        unary = reduce(operator.add, (Optional(x) for x in const.UNOP))

        # Expression for floating point numbers, allowing for scientific notation.
        number = Regex(const.NUMBER)

        # Variables are alphanumeric strings that represent keys in the input
        # data dictionary.
        variable = delimitedList(Word(alphanums),
                                 delim=const.VARIABLE_NAME_SEPARATOR,
                                 combine=True)

        # Functional calls
        function = Word(alphanums) + lpar + self.bnf + rpar

        # Atom core - a single element is either a math constant,
        # a function or a variable.
        atom_core = function | pi | e | null | _true | _false | number | variable

        # Atom subelement between parenthesis
        atom_subelement = lpar + self.bnf.suppress() + rpar

        # In atoms, pi and e need to be before the letters for it to be found
        atom = (unary + atom_core.setParseAction(self.push_first)
                | atom_subelement).setParseAction(self.push_unary_operator)

        # 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(
            (powop + factor).setParseAction(self.push_first))

        term = factor + ZeroOrMore(
            (multop + factor).setParseAction(self.push_first))
        self.bnf << term + ZeroOrMore(
            (addop + term).setParseAction(self.push_first))

    def push_first(self, strg, loc, toks):
        self.expr_stack.append(toks[0])

    def push_unary_operator(self, strg, loc, toks):
        """
        Set custom flag for unary operators.
        """
        if toks and toks[0] in const.UNARY_REPLACE_MAP:
            self.expr_stack.append(const.UNARY_REPLACE_MAP[toks[0]])

    def evaluate_stack(self, stack):
        """
        Evaluate a stack element.
        """
        op = stack.pop()

        if op in const.UNARY_OPERATOR_MAP:
            return const.UNARY_OPERATOR_MAP[op](self.evaluate_stack(stack))

        elif op in const.OPERATOR_MAP:
            op2 = self.evaluate_stack(stack)
            op1 = self.evaluate_stack(stack)
            # Handle null case
            if isinstance(op1, str) and op1 == const.NULL:
                op2 = self.get_mask(op2, op)
                op1 = True
            elif isinstance(op2, str) and op2 == const.NULL:
                op1 = self.get_mask(op1, op)
                op2 = True
            return const.OPERATOR_MAP[op](op1, op2)

        elif op in const.FUNCTION_MAP:
            return const.FUNCTION_MAP[op](self.evaluate_stack(stack))

        elif op in const.KEYWORD_MAP:
            return const.KEYWORD_MAP[op]

        elif op in self.variable_map:
            return self.variable_map[op]

        else:
            try:
                return numpy.array(op, dtype=const.ALGEBRA_PIXEL_TYPE_NUMPY)
            except ValueError:
                raise RasterAlgebraException(
                    'Found an undeclared variable "{0}" in formula.'.format(
                        op))

    @staticmethod
    def get_mask(data, operator):
        # Make sure the right operator is used
        if operator not in (const.EQUAL, const.NOT_EQUAL):
            raise RasterAlgebraException(
                'NULL can only be used with "==" or "!=" operators.')
        # Get mask
        if numpy.ma.is_masked(data):
            return data.mask
        # If there is no mask, all values are not null
        return numpy.zeros(data.shape, dtype=numpy.bool)

    def set_formula(self, formula):
        """
        Store the input formula as the one to evaluate on.
        """
        # Remove any white space and line breaks from formula.
        self.formula = formula.replace(' ', '').replace('\n',
                                                        '').replace('\r', '')

    def prepare_data(self):
        """
        Basic checks and conversion of input data.
        """
        for key, var in self.variable_map.items():
            # Keywords are not allowed as variables, variables can not start or
            # end with separator.
            if keyword.iskeyword(key) or key != key.strip(
                    const.VARIABLE_NAME_SEPARATOR):
                raise RasterAlgebraException(
                    'Invalid variable name found: "{}".'.format(key))

            # Convert all data to numpy arrays
            if not isinstance(var, numpy.ndarray):
                self.variable_map[key] = numpy.array(var)

    def evaluate(self, data={}, formula=None):
        """
        Evaluate the input data using the current formula expression stack.

        The formula is stored as attribute and can be re-evaluated with several
        input data sets on an existing parser.
        """
        if formula:
            self.set_formula(formula)

        if not self.formula:
            raise RasterAlgebraException('Formula not specified.')

        # Store data for variables
        self.variable_map = data

        # Check and convert input data
        self.prepare_data()

        # Reset expression stack
        self.expr_stack = []

        # Populate the expression stack
        self.bnf.parseString(self.formula)

        # Evaluate stack on data
        return self.evaluate_stack(self.expr_stack)
Пример #34
0
div = Literal("/")
solveop = Literal("\\")
solvePDop = Literal("\\p")
outer = Literal("@")
# solveop = Literal("~")
lpar = Literal("(").suppress()
rpar = Literal(")").suppress()
addop = plus | minus
multop = mult | div | outer | solveop | solvePDop
# expop = Literal("^")
expop = Literal(".")
assignop = 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))
equation = (ident + assignop).setParseAction(_assignVar) + expr + StringEnd()

# End of grammar definition
# -----------------------------------------------------------------------------
## The following are helper variables and functions used by the Binary Infix Operator
## Functions described below.

vprefix = "@pvec@"
# vprefix = "m3_"
vplen = len(vprefix)
Пример #35
0
    def __init__(self):

        self.ae = False
        self.local_dict = None
        self.f = None

        self.user_functions = None

        self.expr_stack = []
        self.texpr_stack = []

        # Define constants
        self.constants = {}

        # Define Operators
        self.opn = {
            "+": operator.add,
            "-": operator.sub,
            "*": operator.mul,
            "/": operator.truediv,
            ">": operator.gt,
            ">=": operator.ge,
            "<": operator.lt,
            "<=": operator.le,
            "==": operator.eq,
            "!=": operator.ne,
            "|": operator.or_,
            "&": operator.and_,
            "!": operator.inv,
            "^": operator.pow,
            "**": operator.pow,
            "<<": np.left_shift,
            ">>": np.right_shift
        }

        # Define xarray DataArray operators with 1 input parameter
        self.xfn1 = {
            "angle": xr.ufuncs.angle,
            "arccos": xr.ufuncs.arccos,
            "arccosh": xr.ufuncs.arccosh,
            "arcsin": xr.ufuncs.arcsin,
            "arcsinh": xr.ufuncs.arcsinh,
            "arctan": xr.ufuncs.arctan,
            "arctanh": xr.ufuncs.arctanh,
            "ceil": xr.ufuncs.ceil,
            "conj": xr.ufuncs.conj,
            "cos": xr.ufuncs.cos,
            "cosh": xr.ufuncs.cosh,
            "deg2rad": xr.ufuncs.deg2rad,
            "degrees": xr.ufuncs.degrees,
            "exp": xr.ufuncs.exp,
            "expm1": xr.ufuncs.expm1,
            "fabs": xr.ufuncs.fabs,
            "fix": xr.ufuncs.fix,
            "floor": xr.ufuncs.floor,
            "frexp": xr.ufuncs.frexp,
            "imag": xr.ufuncs.imag,
            "iscomplex": xr.ufuncs.iscomplex,
            "isfinite": xr.ufuncs.isfinite,
            "isinf": xr.ufuncs.isinf,
            "isnan": xr.ufuncs.isnan,
            "isreal": xr.ufuncs.isreal,
            "log": xr.ufuncs.log,
            "log10": xr.ufuncs.log10,
            "log1p": xr.ufuncs.log1p,
            "log2": xr.ufuncs.log2,
            "rad2deg": xr.ufuncs.rad2deg,
            "radians": xr.ufuncs.radians,
            "real": xr.ufuncs.real,
            "rint": xr.ufuncs.rint,
            "sign": xr.ufuncs.sign,
            "signbit": xr.ufuncs.signbit,
            "sin": xr.ufuncs.sin,
            "sinh": xr.ufuncs.sinh,
            "sqrt": xr.ufuncs.sqrt,
            "square": xr.ufuncs.square,
            "tan": xr.ufuncs.tan,
            "tanh": xr.ufuncs.tanh,
            "trunc": xr.ufuncs.trunc
        }

        # Define xarray DataArray operators with 2 input parameter
        self.xfn2 = {
            "arctan2": xr.ufuncs.arctan2,
            "copysign": xr.ufuncs.copysign,
            "fmax": xr.ufuncs.fmax,
            "fmin": xr.ufuncs.fmin,
            "fmod": xr.ufuncs.fmod,
            "hypot": xr.ufuncs.hypot,
            "ldexp": xr.ufuncs.ldexp,
            "logaddexp": xr.ufuncs.logaddexp,
            "logaddexp2": xr.ufuncs.logaddexp2,
            "logicaland": xr.ufuncs.logical_and,
            "logicalnot": xr.ufuncs.logical_not,
            "logicalor": xr.ufuncs.logical_or,
            "logicalxor": xr.ufuncs.logical_xor,
            "maximum": xr.ufuncs.maximum,
            "minimum": xr.ufuncs.minimum,
            "nextafter": xr.ufuncs.nextafter
        }

        # Define non-xarray DataArray operators with 2 input parameter
        self.fn2 = {"percentile": np.percentile, "pow": np.power}

        # Define xarray DataArray reduction operators
        self.xrfn = {
            "all": xr.DataArray.all,
            "any": xr.DataArray.any,
            "argmax": xr.DataArray.argmax,
            "argmin": xr.DataArray.argmin,
            "max": xr.DataArray.max,
            "mean": xr.DataArray.mean,
            "median": xr.DataArray.median,
            "min": xr.DataArray.min,
            "prod": xr.DataArray.prod,
            "sum": xr.DataArray.sum,
            "std": xr.DataArray.std,
            "var": xr.DataArray.var
        }

        # Define non-xarray DataArray operators with 2 input parameter
        self.xcond = {"<": np.percentile}

        # Define Grammar
        point = Literal(".")
        e = CaselessLiteral("E")
        fnumber = Combine(
            Word("+-" + nums, nums) + Optional(point + Optional(Word(nums))) +
            Optional(e + Word("+-" + nums, nums)))
        variable = Word(alphas, alphas + nums + "_$")

        seq = Literal("=")
        b_not = Literal("~")
        plus = Literal("+")
        minus = Literal("-")
        mult = Literal("*")
        div = Literal("/")
        ls = Literal("<<")
        rs = Literal(">>")
        gt = Literal(">")
        gte = Literal(">=")
        lt = Literal("<")
        lte = Literal("<=")
        eq = Literal("==")
        neq = Literal("!=")
        b_or = Literal("|")
        b_and = Literal("&")
        l_not = Literal("!")
        lpar = Literal("(").suppress()
        rpar = Literal(")").suppress()
        comma = Literal(",")
        colon = Literal(":")
        lbrac = Literal("[")
        rbrac = Literal("]")
        lcurl = Literal("{")
        rcurl = Literal("}")
        qmark = Literal("?")
        scolon = Literal(";")
        addop = plus | minus
        multop = mult | div
        sliceop = colon
        shiftop = ls | rs
        compop = gte | lte | gt | lt
        eqop = eq | neq
        bitcompop = b_or | b_and
        bitnotop = b_not
        logicalnotop = l_not
        assignop = seq
        expop = Literal("^") | Literal("**")

        expr = Forward()
        indexexpr = Forward()

        atom = (
            Optional("-") +
            (variable + seq + expr).setParseAction(self.push_assign)
            | indexexpr.setParseAction(self.push_index) |
            (lpar + expr + qmark.setParseAction(self.push_ternary1) + expr +
             scolon.setParseAction(self.push_ternary2) + expr +
             rpar).setParseAction(self.push_ternary) |
            (lpar + expr + qmark + expr + scolon + expr + rpar).setParseAction(
                self.push_ternary) |
            (logicalnotop + expr).setParseAction(self.push_ulnot) |
            (bitnotop + expr).setParseAction(self.push_unot) |
            (minus + expr).setParseAction(self.push_uminus) |
            (variable + lcurl + expr + rcurl).setParseAction(self.push_mask) |
            (variable + lpar + expr +
             (comma + expr) * 3 + rpar).setParseAction(self.push_expr4) |
            (variable + lpar + expr +
             (comma + expr) * 2 + rpar).setParseAction(self.push_expr3) |
            (variable + lpar + expr + comma + expr + rpar).setParseAction(
                self.push_expr2) |
            (variable + lpar + expr + rpar | variable).setParseAction(
                self.push_expr1) | fnumber.setParseAction(self.push_expr) |
            (lpar + expr + ZeroOrMore(comma + expr).setParseAction(
                self.get_tuple) + rpar).setParseAction(self.push_tuple) |
            (lpar + expr.suppress() + rpar).setParseAction(self.push_uminus))

        # Define order of operations for operators

        factor = Forward()
        factor << atom + ZeroOrMore(
            (expop + factor).setParseAction(self.push_op))
        term = factor + ZeroOrMore(
            (multop + factor).setParseAction(self.push_op))
        term2 = term + ZeroOrMore((addop + term).setParseAction(self.push_op))
        term3 = term2 + ZeroOrMore(
            (shiftop + term2).setParseAction(self.push_op))
        term4 = term3 + ZeroOrMore(
            (sliceop + term3).setParseAction(self.push_op))
        term5 = term4 + ZeroOrMore(
            (compop + term4).setParseAction(self.push_op))
        term6 = term5 + ZeroOrMore((eqop + term5).setParseAction(self.push_op))
        term7 = term6 + ZeroOrMore(
            (bitcompop + term6).setParseAction(self.push_op))
        expr << term7 + ZeroOrMore(
            (assignop + term7).setParseAction(self.push_op))

        # Define index operators

        colon_expr = (colon + FollowedBy(comma)
                      ^ colon + FollowedBy(rbrac)).setParseAction(
                          self.push_colon)
        range_expr = colon_expr | expr | colon
        indexexpr << (variable + lbrac + delimitedList(range_expr, delim=',') +
                      rbrac).setParseAction(self.push_expr)

        self.parser = expr
Пример #36
0
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),
Пример #37
0
    def __init__(self):
        """
        Setup the Backus Normal Form (BNF) parser logic.
        """
        self.dtype=ALGEBRA_PIXEL_TYPE_NUMPY
        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 + "_$")

        # Operators
        plus = Literal("+")
        minus = Literal("-")
        mult = Literal("*")
        div = Literal("/")
        eq = Literal("==")
        neq = Literal("!=")
        lt = Literal("<")
        le = Literal("<=")
        gt = Literal(">")
        ge = Literal(">=")
        ior = Literal("|")
        iand = Literal("&")
        lpar = Literal("(").suppress()
        rpar = Literal(")").suppress()
        addop = plus | minus | eq
        multop = mult | div | eq | neq | ge | le | gt | lt | ior | iand  # Order matters here due to "<=" being caught by "<"
        expop = Literal("^")
        pi = CaselessLiteral("PI")

        # Letters for variables
        aa = CaselessLiteral("a")
        bb = CaselessLiteral("b")
        cc = CaselessLiteral("c")
        dd = CaselessLiteral("d")
        ee = CaselessLiteral("e")
        ff = CaselessLiteral("f")
        gg = CaselessLiteral("g")
        hh = CaselessLiteral("h")
        ii = CaselessLiteral("i")
        jj = CaselessLiteral("j")
        kk = CaselessLiteral("k")
        ll = CaselessLiteral("l")
        mm = CaselessLiteral("m")
        nn = CaselessLiteral("n")
        oo = CaselessLiteral("o")
        pp = CaselessLiteral("p")
        qq = CaselessLiteral("q")
        rr = CaselessLiteral("r")
        ss = CaselessLiteral("s")
        tt = CaselessLiteral("t")
        uu = CaselessLiteral("u")
        vv = CaselessLiteral("v")
        ww = CaselessLiteral("w")
        xx = CaselessLiteral("x")
        yy = CaselessLiteral("y")
        zz = CaselessLiteral("z")

        bnf = Forward()

        atom = (
            Optional('-') + Optional("!") + (
                pi | e | fnumber | ident + lpar + bnf + rpar |  # pi needs to be before the letters for it to be found
                aa | bb | cc | dd | ee | ff | gg | hh | ii | jj | kk | ll | mm |
                nn | oo | pp | qq | rr | ss | tt | uu | vv | ww | xx | yy | zz
            ).setParseAction(self.push_first) | (lpar + bnf.suppress() + rpar)
        ).setParseAction(self.push_unary_operator)

        # 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(self.push_first))

        term = factor + ZeroOrMore((multop + factor).setParseAction(self.push_first))
        bnf << term + ZeroOrMore((addop + term).setParseAction(self.push_first))

        self.bnf = bnf
Пример #38
0
    def init_parser(self):
        """
        expop   :: '^'
        multop  :: '*' | '/'
        addop   :: '+' | '-'
        integer :: ['+' | '-'] '0'..'9'+
        atom    :: real | Word(alphas) | array | fn '(' expr ')' | '(' expr ')'
        factor  :: atom [ expop factor ]*
        term    :: factor [ multop factor ]*
        expr    :: term [ addop term ]*
        """

        atoms = self.language.get_parser_atoms()

        variable = atoms["variable"]  # .setParseAction(downcaseTokens)

        func_lpar = atoms["func_lpar"].setParseAction(self._push2stack("("))
        func_delim = atoms["func_delim"]
        func_rpar = atoms["func_rpar"].setParseAction(self._push2stack(")"))

        array_lpar = atoms["array_lpar"].setParseAction(self._push2stack("["))
        array_delim = atoms["array_delim"]
        array_rpar = atoms["array_rpar"].setParseAction(self._push2stack("]"))

        lpar = atoms["lpar"].suppress()
        rpar = atoms["rpar"].suppress()
        expop = atoms["exp"]

        addop = atoms["plus"] | atoms["minus"]
        multop = atoms["mult"] | atoms["div"]
        cmpop = atoms["equal"]

        expr = Forward()  # forward declaration of an entire expression
        # this is necessary for defining the recursive grammar

        # smallest entity of a mathematical expression:
        array = (
            variable
            + array_lpar
            + atoms["int"].addParseAction(self.push_first)
            + ZeroOrMore(array_delim + atoms["int"])
            + array_rpar
        )

        func_call = (
            atoms["function"].setParseAction(downcaseTokens)
            + func_lpar
            + expr
            + ZeroOrMore(func_delim + expr)
            + func_rpar
        )

        obj = atoms["consts"] | atoms["float"] | array | func_call | variable
        atom = (
            Optional("-")
            + (  # optional unary minus
                obj.addParseAction(self.push_first)
                | (lpar + expr.suppress() + rpar)  # subexpression
            )
        ).setParseAction(self.push_unary_minus)

        # 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.push_first))

        # sequence of multiplications
        term = factor + ZeroOrMore((multop + factor).setParseAction(self.push_first))

        # sequence of summations
        expr << term + ZeroOrMore((addop + term).setParseAction(self.push_first))

        # comparison operators
        equation = expr + Optional(cmpop + expr).setParseAction(self.push_first)

        # assignment operator
        self.parser = (
            (variable ^ array).setParseAction(self.push_first)
            + atoms["assign"]
            + equation
        ).setParseAction(self._push2stack("=")) | equation

        return self.parser
Пример #39
0
    def parser(self):
        point = Literal(".")
        e = CaselessLiteral("E")
        fnumber = Combine(Word("+-" + nums, nums) +
                          Optional(point + Optional(Word(nums))) +
                          Optional(e + Word("+-" + nums, nums)))
        # ident = reduce(lambda x, y: x | y, self.func_name_parsers)
        ident = Word(alphas, alphas + nums + "_$")

        plus = Literal("+")
        minus = Literal("-")
        mult = Literal("*")
        div = Literal("/")
        _or = Literal("|")
        _and = Literal("&")
        lpar = Literal("(").suppress()
        rpar = Literal(")").suppress()
        lt = Keyword("<")
        le = Keyword("<=")
        gt = Keyword(">")
        ge = Keyword(">=")
        addop = plus | minus | le | lt | gt | ge
        multop = mult | div | _or | _and
        expop = Literal("^")
        pi = CaselessLiteral("PI")

        # column_names = [Literal(col_name) for col_name in self.col_names]
        # Equivalent to: 'x_1 | x_2 | ... | x_n'
        # column = self.col_name_parser()

        # Function arguments
        plusorminus = Literal('+') | Literal('-')
        number = Word(nums)
        integer = Combine(Optional(plusorminus) + number).setParseAction(lambda x: int(x[0]))
        floatnumber = Combine(integer +
                              Optional(point + Optional(number)) +
                              Optional(e + integer)
                              ).setParseAction(lambda x: float(x[0]))

        arg = (integer | floatnumber | quotedString.addParseAction(removeQuotes)).setParseAction(lambda x: x[0])

        args = Optional(delimitedList(arg), default=None).setParseAction(lambda x: {'args': [z for z in x]})
        kwarg = (Word(alphas, alphas + nums + "_$") + Suppress("=") + arg).setParseAction(lambda x: {x[0]: x[1]})
        kwargs = Optional(Suppress(",") + delimitedList(kwarg), default=None)
        kwargs.setParseAction(lambda x:
                              {'kwargs': dict(pair for d in x for pair in d.items())} if x[0] is not None else {
                                  'kwargs': None})

        func_inputs = (Suppress(",") + args + kwargs)
        func_input_block = Optional(func_inputs, default={'args': None, 'kwargs': None}) \
            .setParseAction(lambda x: self._add_func_inputs(dict(pair for d in x for pair in d.items())))

        expr = Forward()

        kwarg.setParseAction(lambda x: {x[0]: x[1]})

        value = self.value_parser()

        atom = (Optional("-") + (value | pi | e | fnumber | ident + lpar + expr + func_input_block
                                 + rpar).setParseAction(lambda x: self.push_first(tok=x[0])) | (
                    lpar + expr.suppress() + rpar)).setParseAction(lambda x: self.push_unary_minus(toks=x))

        factor = Forward()
        factor << atom + ZeroOrMore((expop + factor).setParseAction(lambda x: self.push_first(tok=x[0])))

        term = factor + ZeroOrMore((multop + factor).setParseAction(lambda x: self.push_first(tok=x[0])))
        expr << term + ZeroOrMore((addop + term).setParseAction(lambda x: self.push_first(tok=x[0])))
        if self.deferred_eval:
            expr.setParseAction(lambda x: originalTextFor(expr))
        return expr
Пример #40
0
class FormulaParser(object):
    """
    Deconstruct mathematical algebra expressions and convert those into
    callable funcitons.


    Deconstruct mathematical algebra expressions and convert those into
    callable funcitons.

    This formula parser was inspired by the fourFun pyparsing example and also
    benefited from additional substantial contributions by Paul McGuire.
    This module uses pyparsing for this purpose and the parser is adopted from
    the `fourFun example`__.

    Example usage::

        >>> parser = FormulaParser()
        >>> parser.set_formula('log(a * 3 + b)')
        >>> parser.evaluate({'a': 5, 'b': 23})
        ... 3.6375861597263857
        >>> parser.evaluate({'a': [5, 6, 7], 'b': [23, 24, 25]})
        ... array([ 3.63758616,  3.73766962,  3.8286414 ])

    __ http://pyparsing.wikispaces.com/file/view/fourFn.py
    """

    def __init__(self):
        """
        Setup the Backus Normal Form (BNF) parser logic.
        """
        # Set an empty formula attribute
        self.formula = None

        # Instantiate blank parser for BNF construction
        self.bnf = Forward()

        # Expression for parenthesis, which are suppressed in the atoms
        # after matching.
        lpar = Literal(const.LPAR).suppress()
        rpar = Literal(const.RPAR).suppress()

        # Expression for mathematical constants: Euler number and Pi
        e = Keyword(const.EULER)
        pi = Keyword(const.PI)
        null = Keyword(const.NULL)
        _true = Keyword(const.TRUE)
        _false = Keyword(const.FALSE)

        # Prepare operator expressions
        addop = oneOf(const.ADDOP)
        multop = oneOf(const.MULTOP)
        powop = oneOf(const.POWOP)
        unary = reduce(operator.add, (Optional(x) for x in const.UNOP))

        # Expression for floating point numbers, allowing for scientific notation.
        number = Regex(const.NUMBER)

        # Variables are alphanumeric strings that represent keys in the input
        # data dictionary.
        variable = delimitedList(Word(alphanums), delim=const.VARIABLE_NAME_SEPARATOR, combine=True)

        # Functional calls
        function = Word(alphanums) + lpar + self.bnf + rpar

        # Atom core - a single element is either a math constant,
        # a function or a variable.
        atom_core = function | pi | e | null | _true | _false | number | variable

        # Atom subelement between parenthesis
        atom_subelement = lpar + self.bnf.suppress() + rpar

        # In atoms, pi and e need to be before the letters for it to be found
        atom = (
            unary + atom_core.setParseAction(self.push_first) | atom_subelement
        ).setParseAction(self.push_unary_operator)

        # 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((powop + factor).setParseAction(self.push_first))

        term = factor + ZeroOrMore((multop + factor).setParseAction(self.push_first))
        self.bnf << term + ZeroOrMore((addop + term).setParseAction(self.push_first))

    def push_first(self, strg, loc, toks):
        self.expr_stack.append(toks[0])

    def push_unary_operator(self, strg, loc, toks):
        """
        Set custom flag for unary operators.
        """
        if toks and toks[0] in const.UNARY_REPLACE_MAP:
            self.expr_stack.append(const.UNARY_REPLACE_MAP[toks[0]])

    def evaluate_stack(self, stack):
        """
        Evaluate a stack element.
        """
        op = stack.pop()

        if op in const.UNARY_OPERATOR_MAP:
            return const.UNARY_OPERATOR_MAP[op](self.evaluate_stack(stack))

        elif op in const.OPERATOR_MAP:
            op2 = self.evaluate_stack(stack)
            op1 = self.evaluate_stack(stack)
            # Handle null case
            if isinstance(op1, six.string_types) and op1 == const.NULL:
                op2 = self.get_mask(op2, op)
                op1 = True
            elif isinstance(op2, six.string_types) and op2 == const.NULL:
                op1 = self.get_mask(op1, op)
                op2 = True
            return const.OPERATOR_MAP[op](op1, op2)

        elif op in const.FUNCTION_MAP:
            return const.FUNCTION_MAP[op](self.evaluate_stack(stack))

        elif op in const.KEYWORD_MAP:
            return const.KEYWORD_MAP[op]

        elif op in self.variable_map:
            return self.variable_map[op]

        else:
            try:
                return numpy.array(op, dtype=const.ALGEBRA_PIXEL_TYPE_NUMPY)
            except ValueError:
                raise RasterAlgebraException('Found an undeclared variable "{0}" in formula.'.format(op))

    @staticmethod
    def get_mask(data, operator):
        # Make sure the right operator is used
        if operator not in (const.EQUAL, const.NOT_EQUAL):
            raise RasterAlgebraException('NULL can only be used with "==" or "!=" operators.')
        # Get mask
        if numpy.ma.is_masked(data):
            return data.mask
        # If there is no mask, all values are not null
        return numpy.zeros(data.shape, dtype=numpy.bool)

    def set_formula(self, formula):
        """
        Store the input formula as the one to evaluate on.
        """
        # Remove any white space and line breaks from formula.
        self.formula = formula.replace(' ', '').replace('\n', '').replace('\r', '')

    def prepare_data(self):
        """
        Basic checks and conversion of input data.
        """
        for key, var in self.variable_map.items():
            # Keywords are not allowed as variables, variables can not start or
            # end with separator.
            if keyword.iskeyword(key) or key != key.strip(const.VARIABLE_NAME_SEPARATOR):
                raise RasterAlgebraException('Invalid variable name found: "{}".'.format(key))

            # Convert all data to numpy arrays
            if not isinstance(var, numpy.ndarray):
                self.variable_map[key] = numpy.array(var)

    def evaluate(self, data={}, formula=None):
        """
        Evaluate the input data using the current formula expression stack.

        The formula is stored as attribute and can be re-evaluated with several
        input data sets on an existing parser.
        """
        if formula:
            self.set_formula(formula)

        if not self.formula:
            raise RasterAlgebraException('Formula not specified.')

        # Store data for variables
        self.variable_map = data

        # Check and convert input data
        self.prepare_data()

        # Reset expression stack
        self.expr_stack = []

        # Populate the expression stack
        self.bnf.parseString(self.formula)

        # Evaluate stack on data
        return self.evaluate_stack(self.expr_stack)
Пример #41
0
    def defineGrammar(self, input_strings):
        point = Literal('.')
        e = CaselessLiteral('E')
        plusorminus = Literal('+') | Literal('-')
        number = Word(nums)
        #print "Nums", number
        integer = Combine(Optional(plusorminus) + number)
        floatnumber = Combine(integer + Optional(point + Optional(number)) +
                              Optional(e + integer))

        ident = Word(alphas, alphanums + '_')
        #print "ident", ident
        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()
        #print "Expr" , expr
        atom = ((e | floatnumber | integer | ident).setParseAction(
            self.pushFirst) | (lpar + expr.suppress() + rpar))

        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))
        bnf = Optional((ident + assign).setParseAction(self.assignVar)) + expr

        pattern = bnf + StringEnd()
        #print "pattern" , pattern

        # map operator symbols to corresponding arithmetic operations
        self.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)
        }
        exprns = input_strings.split(",")
        for input_string in exprns:

            self.exprStack = []
            self.varStack = []
            if input_string != '':
                # try parsing the input string
                try:
                    L = pattern.parseString(input_string)
                    #print "L", L
                except ParseException, err:
                    L = ['Parse Failure', input_string]
            if debug_flag: print input_string, "->", L
            if len(L) == 0 or L[0] != 'Parse Failure':
                if debug_flag: print "exprStack=", self.exprStack

                # calculate result , store a copy in ans , display the result to user
                result = self.evaluateStack(self.exprStack)
                self.variables['ans'] = result
                print input_string, "=", result

                # Assign result to a variable if required
                if debug_flag: print "var=", self.varStack
                if len(self.varStack) == 1:
                    self.variables[self.varStack.pop()] = result
                if debug_flag: print "variables=", self.variables
            else:
                print 'Parse Failure'
                print err.line
                print " " * (err.column - 1) + "^"
                print input_string, "-", err
Пример #42
0
def create_bnf(stack):
    point = Literal(".")
    e = CaselessLiteral("E")
    inumber = Word(nums)
    fnumber = Combine(
        Word("+-" + nums, nums) + Optional(point + Optional(Word(nums))) +
        Optional(e + Word("+-" + nums, nums)))
    _of = Literal('of')
    _in = Literal('in')
    _by = Literal('by')
    _copy = Literal('copy')

    _mv = Literal('-v').setParseAction(replace('OA_SubV'))
    _me = Literal('-e').setParseAction(replace('OA_SubE'))
    _mf = Literal('-f').setParseAction(replace('OA_SubF'))
    _mc = Literal('-c').setParseAction(replace('OA_SubC'))
    _ms = Literal('-s').setParseAction(replace('OA_SubS'))
    _pv = Literal('+v').setParseAction(replace('OA_AddV'))
    _pe = Literal('+e').setParseAction(replace('OA_AddE'))
    _pf = Literal('+f').setParseAction(replace('OA_AddF'))
    _pc = Literal('+c').setParseAction(replace('OA_AddC'))
    _ps = Literal('+s').setParseAction(replace('OA_AddS'))
    _inv = Literal('*v').setParseAction(replace('OA_IntersectV'))
    _ine = Literal('*e').setParseAction(replace('OA_IntersectE'))
    _inf = Literal('*f').setParseAction(replace('OA_IntersectF'))
    _inc = Literal('*c').setParseAction(replace('OA_IntersectC'))
    _ins = Literal('*s').setParseAction(replace('OA_IntersectS'))
    regop = (_mv | _me | _mf | _mc | _ms | _pv | _pe | _pf | _pc | _ps | _inv
             | _ine | _inf | _inc | _ins)

    lpar = Literal("(").suppress()
    rpar = Literal(")").suppress()

    _all = Literal('all').setParseAction(replace('KW_All'))
    vertex = Literal('vertex')
    vertices = Literal('vertices')
    cell = Literal('cell')
    cells = Literal('cells')
    group = Literal('group')
    _set = Literal('set')
    surface = Literal('surface')

    ident = Word(alphas + '_.', alphanums + '_.')
    set_name = Word(nums) | ident

    function = Word(alphas + '_', alphanums + '_')
    function = Group(function).setParseAction(join_tokens)

    region = Combine(
        Literal('r.') + Word(alphas + '_-', '_-' + alphas + nums + '.'))
    region = Group(Optional(_copy, default='nocopy') + region)
    region.setParseAction(replace('KW_Region', keep=True))

    coor = oneOf('x y z')
    boolop = oneOf('& |')
    relop = oneOf('< > <= >= != ==')
    bool_term = (ZeroOrMore('(') + (coor | fnumber) + relop +
                 (coor | fnumber) + ZeroOrMore(')'))
    relation = Forward()
    relation << (ZeroOrMore('(') + bool_term + ZeroOrMore(boolop + relation) +
                 ZeroOrMore(')'))
    relation = Group(relation).setParseAction(join_tokens)

    nos = Group(vertices + _of + surface).setParseAction(replace('E_VOS'))
    nir = Group(vertices + _in + relation).setParseAction(
        replace('E_VIR', keep=True))
    nbf = Group(vertices + _by + function).setParseAction(
        replace('E_VBF', keep=True))
    ebf = Group(cells + _by + function).setParseAction(
        replace('E_CBF', keep=True))
    eog = Group(cells + _of + group + Word(nums)).setParseAction(
        replace('E_COG', keep=True))
    nog = Group(vertices + _of + group + Word(nums)).setParseAction(
        replace('E_VOG', keep=True))
    onir = Group(vertex + _in + region).setParseAction(
        replace_with_region('E_OVIR', 2))
    ni = Group(vertex + delimitedList(inumber)).setParseAction(
        replace('E_VI', keep=True))
    ei = Group(cell + delimitedList(inumber)).setParseAction(
        replace('E_CI', keep=True))
    noset = Group(vertices + _of + _set + set_name).setParseAction(
        replace('E_VOSET', keep=True))
    eoset = Group(cells + _of + _set + set_name).setParseAction(
        replace('E_COSET', keep=True))

    region_expression = Forward()

    atom1 = (_all | region | ni | onir | nos | nir | nbf
             | ei | ebf | eog | nog | noset | eoset)
    atom1.setParseAction(to_stack(stack))
    atom2 = (lpar + region_expression.suppress() + rpar)
    atom = (atom1 | atom2)

    aux = (regop + region_expression)
    aux.setParseAction(to_stack(stack))
    region_expression << atom + ZeroOrMore(aux)
    region_expression = StringStart() + region_expression + StringEnd()

    return region_expression
Пример #43
0
def parse_math_str(input_string, variables={}):

    # 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 = []

    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 op in variables:
                return variables[op]
            else:
                return 0
        elif re.search('^[-+]?[0-9]+$', op):
            return int(op)
        else:
            return float(op)

    # 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 as 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
            return 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)
Пример #44
0
	def defineGrammar(self, input_strings):
		point = Literal('.')
		e = CaselessLiteral('E')
		plusorminus = Literal('+') | Literal('-')
		number = Word(nums)
		#print "Nums", number 
		integer = Combine( Optional(plusorminus) + number )
		floatnumber = Combine( integer +
				       Optional( point + Optional(number) ) +
				       Optional( e + integer )
				     )

		ident = Word(alphas,alphanums + '_') 
		#print "ident", ident 
		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()
		#print "Expr" , expr
		atom = ( ( e | floatnumber | integer | ident ).setParseAction(self.pushFirst) | 
			 ( lpar + expr.suppress() + rpar )
		       )
		
		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 ) )
		bnf = Optional((ident + assign).setParseAction(self.assignVar)) + expr

		pattern =  bnf + StringEnd()
		#print "pattern" , pattern
		
		# map operator symbols to corresponding arithmetic operations
		self.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 ) }
		exprns = input_strings.split(",")
		for input_string in exprns:
								
			self.exprStack = []
	    		self.varStack  = []
			if input_string != '':
			      # try parsing the input string
			      try:
				L=pattern.parseString( input_string )
				#print "L", L
			      except ParseException,err:
				L=['Parse Failure',input_string]	
			if debug_flag: print input_string, "->", L
			if len(L)==0 or L[0] != 'Parse Failure':
			  if debug_flag: print "exprStack=", self.exprStack
			 
			# calculate result , store a copy in ans , display the result to user
			  result=self.evaluateStack(self.exprStack)
			  self.variables['ans']=result
			  print input_string , "=" , result
			  
			# Assign result to a variable if required
			  if debug_flag: print "var=",self.varStack
			  if len(self.varStack)==1:
			    self.variables[self.varStack.pop()]=result
			  if debug_flag: print "variables=",self.variables
			else:
			  print 'Parse Failure'
			  print err.line
			  print " "*(err.column-1) + "^"
			  print input_string , "-" , err
Пример #45
0
M2X_template = "FFT_M2X_%i.c"
X2L_template = "FFT_X2L_%i.c"

print '''
/* This file is automatically generated by gen_FFT_M2X_X2L_aux.py */
/* DO NOT EDIT! */

#include"_fmmv.h"
'''

if len(argv) > 1 and argv[1] == "cores_init":
    ident = Word(alphas, alphas + nums + "_")
    fun_decl = (Literal("void") + ident + Literal("(double *y, double *x)"))
    group = Forward()
    group << "{" + ZeroOrMore(group ^ CharsNotIn("{}")) + "}"
    tail = fun_decl.suppress() + group.suppress() + ZeroOrMore(CharsNotIn(""))
    tail.ignore(cStyleComment)

    for M in M_list:
        file = open(dirname + "/" + (M2X_template % M))
        t = tail.parseString("".join(file.readlines()))
        print t[0].replace("double", "_FLOAT_")
        file.close()
        file = open(dirname + "/" + (X2L_template % M))
        t = tail.parseString("".join(file.readlines()))
        print t[0].replace("double", "_FLOAT_")
        file.close()

elif len(argv) > 1 and "cores" in argv[
        1]:  ####################################################
    if "simd2" in argv[1]: