Pyparsing - How To Parse String With Comparison Operators?
Solution 1:
As pointed out by @rici, you have added the evaluation part, but not the parsing part.
The parser is defined in these lines:
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__))
The order of these statements is important, because they cause the parser to recognize the precedence of operations, which you learned in high school math. That is, exponentiation is highest, then multiplication and division next, then addition and subtraction next.
You'll need to insert your relational operators to this parser definition following the same pattern. After addition, the convention from C language operator precedence (I found this reference - https://www.tutorialspoint.com/cprogramming/c_operators_precedence.htm) is:
relationaloperations-<=,>=,>,<equalityoperations-==,!=
In your case, you choose to use '=' instead of '==', and that should be okay in this setting. I suggest you use pyparsing's oneOf
helper to define these operator groups, as it will take care of the case where a short string might mask a longer string (as when '/' masked '//' in your earlier post).
Note that, by mixing these operations all into one expression parser, you will get things like 5 + 2 > 3
. Since '>' has lower precedence, 5+2 will be evaluated first giving 7, then 7 > 3 will be evaluated, and operator.__gt__
will return 1 or 0.
The difficulty in extending this example to other operators was what caused me to write the infixNotation
helper method in pyparsing. You may want to give that a look.
EDIT:
You asked about using Literal('<=') | Literal('>=) | etc.
, and as you wrote it, that will work just fine. You just have to be careful to look for the longer operators ahead of the shorter ones. If you write Literal('>') | Literal('>=') | ...
then matching '>=' would fail because the first match would match the '>' and then you would be left with '='. Using oneOf
takes care of this for you.
To add the additional parser steps, you only want do the expr <<= ...
step for the last level. Look at the pattern of statements again. Change expr <<= term + etc.
to arith_expr = term + etc.
, follow it to add levels for relational_expr
and equality_expr
, and then finish with expr <<= equality_expr
.
The pattern for this is based on:
factor := atom (^ atom)...
term := factor (mult_op factor)...
arith_expr := term (add_op term)...
relation_expr := arith_expr (relation_op arith_expr)...
equality_expr := relation_expr (equality_op relation_expr)...
Try doing that conversion to Python/pyparsing on your own.
Solution 2:
factor << atom + \
ZeroOrMore((expop + factor).setParseAction(self.__push_first__))
term = factor + \
ZeroOrMore((multop + factor).setParseAction(self.__push_first__))
arith_expr = term + \
ZeroOrMore((addop + term).setParseAction(self.__push_first__))
relational = arith_expr + \
ZeroOrMore((diffop + arith_expr).setParseAction(self.__push_first__))
expr <<= relational + \
ZeroOrMore((compop + relational).setParseAction(self.__push_first__))
So I tested that, it works! Thank you very much PaulMcG ! : )
Post a Comment for "Pyparsing - How To Parse String With Comparison Operators?"