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 |