View difference between Paste ID: f7eb6be8a and
SHOW:
|
|
- or go back to the newest paste.
| 1 | # | |
| 2 | # simpleArith.py | |
| 3 | # | |
| 4 | # Example of defining an arithmetic expression parser using | |
| 5 | # the operatorGrammar helper method in pyparsing. | |
| 6 | # | |
| 7 | # Copyright 2006, by Paul McGuire | |
| 8 | # | |
| 9 | ||
| 10 | from pyparsing import * | |
| 11 | ParserElement.enablePackrat() #comment this out once for comparison | |
| 12 | ||
| 13 | ||
| 14 | # To use the operatorGrammar helper: | |
| 15 | # 1. Define the "atom" operand term of the grammar. | |
| 16 | # For this simple grammar, the smallest operand is either | |
| 17 | # and integer or a variable. This will be the first argument | |
| 18 | # to the operatorGrammar method. | |
| 19 | # 2. Define a list of tuples for each level of operator | |
| 20 | # precedence. Each tuple is of the form | |
| 21 | # (opExpr, numTerms, rightLeftAssoc, parseAction), where | |
| 22 | # - opExpr is the pyparsing expression for the operator; | |
| 23 | # may also be a string, which will be converted to a Literal | |
| 24 | # - numTerms is the number of terms for this operator (must | |
| 25 | # be 1 or 2) | |
| 26 | # - rightLeftAssoc is the indicator whether the operator is | |
| 27 | # right or left associative, using the pyparsing-defined | |
| 28 | # constants opAssoc.RIGHT and opAssoc.LEFT. | |
| 29 | # - parseAction is the parse action to be associated with | |
| 30 | # expressions matching this operator expression (the | |
| 31 | # parse action tuple member may be omitted) | |
| 32 | # 3. Call operatorGrammar passing the operand expression and | |
| 33 | # the operator precedence list, and save the returned value | |
| 34 | # as the generated pyparsing expression. You can then use | |
| 35 | # this expression to parse input strings, or incorporate it | |
| 36 | # into a larger, more complex grammar. | |
| 37 | # | |
| 38 | ||
| 39 | ||
| 40 | #dummy parse actions | |
| 41 | def action_op_prefix(s, loc, toks): | |
| 42 | # print "pre: ", toks | |
| 43 | return | |
| 44 | ||
| 45 | def action_op_infix(s, loc, toks): | |
| 46 | # print "in : ", toks | |
| 47 | return | |
| 48 | ||
| 49 | def action_op_infix_left(s, loc, toks): | |
| 50 | # print "inL: ", toks | |
| 51 | return | |
| 52 | ||
| 53 | ||
| 54 | #The leaf nodes of the parse tree: integer numbers and variable names | |
| 55 | integer = Word(nums).setParseAction(lambda t:int(t[0])) | |
| 56 | variable = (NotAny(Keyword('not') | Keyword('and') | Keyword('or')) +
| |
| 57 | Word(alphas,exact=1)) | |
| 58 | ||
| 59 | #Let parentheses work with power and unary '-' too | |
| 60 | expression = Forward() | |
| 61 | primary = integer | variable | Suppress('(') + expression + Suppress(')')
| |
| 62 | ||
| 63 | #Power and unary operations are intertwined to get correct operator precedence: | |
| 64 | # -a**-b == -(a ** (-b)) | |
| 65 | power, u_expr = Forward(), Forward() | |
| 66 | #Exponentiation: a**b; | |
| 67 | #Strongest binding on left side, weaker than unary operations (-a) on right side. | |
| 68 | power1 = Group(primary + '**' + u_expr) .setParseAction(action_op_infix) | |
| 69 | power << (power1 | primary) | |
| 70 | #Unary arithmetic operations: -a; +a | |
| 71 | u_expr1 = Group(oneOf('- +') + u_expr) .setParseAction(action_op_prefix)
| |
| 72 | u_expr << (u_expr1 | power) | |
| 73 | ||
| 74 | #All other operators are defined here. Those with the strongest binding come first. | |
| 75 | expression << operatorPrecedence( u_expr, | |
| 76 | [(oneOf('* /'), 2, opAssoc.LEFT, action_op_infix_left),
| |
| 77 | (oneOf('+ -'), 2, opAssoc.LEFT, action_op_infix_left),
| |
| 78 | (oneOf('< > <= >= == !='), 2, opAssoc.LEFT, action_op_infix_left),
| |
| 79 | (Keyword('not'), 1, opAssoc.RIGHT, action_op_prefix),
| |
| 80 | (Keyword('and'), 2, opAssoc.LEFT, action_op_infix_left),
| |
| 81 | (Keyword('or'), 2, opAssoc.LEFT, action_op_infix_left),
| |
| 82 | ]) | |
| 83 | ||
| 84 | test = [ | |
| 85 | "1**2**3**4", | |
| 86 | "-2**-3 == -(2**(-3))", #why does this expression take so long? | |
| 87 | "3----++-2", | |
| 88 | "1 and 2 or not a and b", | |
| 89 | "not a <= a and c > d", | |
| 90 | "9 + 2 - 3 + 4", | |
| 91 | "9 + 2 * 4", | |
| 92 | "(9 + 2) * 3", | |
| 93 | "(9 + -2) * 3**-4**5", | |
| 94 | "M*X + B", | |
| 95 | "M*(X + B)", | |
| 96 | # "2+3*4-2+3*4-2+3*4**-2**+3*4-2+3*4 and -2+3*4-2+3*4 or -2+3*4**-2**+3*4**-2**+3*4\ | |
| 97 | # -2+3*4-2+3*4-2+3*4-2+3*4-2+3*4-2 or 3*4-2 and not 3*4*2+3*4-2+3*4-2+3*4**-2**3*4\ | |
| 98 | # -2+3*4-2+3*(4-2+3)*4*-2+3*4**-2**+3**4**-2**+3**(4-(2+3)*4-2+3*4-2+3*4-2)+3*4-+3\ | |
| 99 | # *4-2+3*4-2+3*4*2+3*4-2+3*4-2+3*4**-2**+3**4**-2 < +3*4-2 or 3**4-2+3*4-2+3*4**-2\ | |
| 100 | # **+3**-4**-2*+3*4-2+3*4-2==+3*4 or -2+3*4<-2+3*4-2+3*4-2+3*4-2+3*4+1-2-3-------4" | |
| 101 | ] | |
| 102 | ||
| 103 | #test the parser | |
| 104 | ||
| 105 | for t in test: | |
| 106 | print t | |
| 107 | print expression.parseString(t) | |
| 108 | # print power.parseString(t) | |
| 109 | ||
| 110 | ||
| 111 |