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
print
105
for t in test:
106
    print t
107
    print expression.parseString(t)
108
#    print power.parseString(t)
109
    print
110
111