Adrian Z.
Adrian Z.

Reputation: 934

pyparsing precedence splitting

In most examples that I can find precedence uses grouped (oneOf) literals to set the same level. With this approach I would have to look up which of the 2 (or more) it is and then continue with evaluation. What I would like to do is split the operators to directly know which one it is and evaluate it.

This is what I would like to implement, but the precedence levels are now wrong

arith_prec = [
    (subtract_op, 2, opAssoc.LEFT, ast.Substraction),
    (add_op, 2, opAssoc.LEFT, ast.Addition),
    (divide_op, 2, opAssoc.LEFT, ast.Division),
    (multiplication_op, 2, opAssoc.LEFT, ast.Multiplication),
]

This is what I had before but had to match which of the two (or more) it was

plusop = oneOf(['+', '-'])
multop = oneOf(['*', '/'])
arith_prec = [
    (plusop, 2, opAssoc.LEFT,),
    (multop, 2, opAssoc.LEFT,),
]

Is there a way of doing this? I have tested with using oneOf and Or inside of the arith_prec but to no use.

Upvotes: 1

Views: 337

Answers (1)

PaulMcG
PaulMcG

Reputation: 63747

You will have to match the operators within your parse action/class. Note that you will potentially get several operations, not just one with two operands. For instance, parsing "1 - 3 + 2" will give you [1, '-', 3, '+', 2], so you really can't have this create an Addition or Subtraction class.

Perhaps combine them to classes like AddSub and MultDiv, which will iterate left-to-right through the parsed values to evaluate the value:

class BinOp:
    operator_map = {}

    def __init__(self, tokens):
        self.tokens = tokens

    def eval(self):
        seq = self.tokens
        ret = seq[0]
        for operator, operand in zip(seq[1::2], seq[2::2]):
            ret = self.operator_map[operator](ret, operand)
        return ret

class AddSub(BinOp):
    operator_map = {'+': operator.add, '-': operator.sub}

class MultDiv(BinOp):
    operator_map = {'*': operator.mul, '/': operator.truediv}

plusop = oneOf(AddSub.operator_map.keys())
multop = oneOf(MultDiv.operator_map.keys())
arith_prec = [
    (multop, 2, opAssoc.LEFT, MultDiv),
    (plusop, 2, opAssoc.LEFT, AddSub),
]

Or broaden your concept of "addition" to include '+' and '-' operations. (As in engineering school, we had to generalize the concept of "acceleration" to include any change in velocity, either up or down.)

In any event, if you are using the infixNotation method, you will have to have each level of precedence include all the operators at that level.

Upvotes: 1

Related Questions