import pyparsing as pp
# works with and without packrat
pp.ParserElement .enablePackrat ( )
pp.ParserElement .setDefaultWhitespaceChars ( ' \t ' )
operand = pp.Word ( pp.nums )
var = pp.Word ( pp.alphas )
arith_expr = pp.Forward ( )
arith_expr.ignore ( pp.pythonStyleComment )
lpar = pp.Suppress ( "(" )
rpar = pp.Suppress ( ")" )
# code to implement selective ignore of NL's inside ()'s
NL = pp.Suppress ( "\n " )
base_ignore = arith_expr.ignoreExprs [ :]
ignore_stack = base_ignore[ :]
def lpar_pa( ) :
ignore_stack.append ( NL)
arith_expr.ignore ( NL)
#~ print('post-push', arith_expr.ignoreExprs)
def rpar_pa( ) :
ignore_stack.pop ( -1 )
arith_expr.ignore ( None )
for e in ignore_stack:
arith_expr.ignore ( e)
#~ print('post-pop', arith_expr.ignoreExprs)
def reset_stack( *args) :
arith_expr.ignore ( None )
for e in base_ignore:
arith_expr.ignore ( e)
#~ print('post-reset', arith_expr.ignoreExprs)
lpar.addParseAction ( lpar_pa)
rpar.addParseAction ( rpar_pa)
arith_expr.setFailAction ( reset_stack)
arith_expr.addParseAction ( reset_stack)
# now define the infix notation as usual
arith_expr <<= pp.infixNotation ( operand | var,
[
( "-" , 1 , pp.opAssoc .RIGHT ) ,
( pp.oneOf ( "* /" ) , 2 , pp.opAssoc .LEFT ) ,
( pp.oneOf ( "- +" ) , 2 , pp.opAssoc .LEFT ) ,
] ,
lpar= lpar, rpar= rpar
)
assignment = var + '=' + arith_expr
# Try it out!
assignment.runTests ( [
"""a = 1 + 3""" ,
"""a = (1 + 3)""" ,
"""a = 1 + 2 + (
3 +
1)""" ,
"""a = 1 + 2 + ((
3 +
1))""" ,
"""a = 1 + 2 +
3""" ,
"""a = (1 + (2 + 3) +
4)""" ,
] , fullDump= False )
aW1wb3J0IHB5cGFyc2luZyBhcyBwcAoKIyB3b3JrcyB3aXRoIGFuZCB3aXRob3V0IHBhY2tyYXQKcHAuUGFyc2VyRWxlbWVudC5lbmFibGVQYWNrcmF0KCkKCnBwLlBhcnNlckVsZW1lbnQuc2V0RGVmYXVsdFdoaXRlc3BhY2VDaGFycygnIFx0JykKCm9wZXJhbmQgPSBwcC5Xb3JkKHBwLm51bXMpCnZhciA9IHBwLldvcmQocHAuYWxwaGFzKQoKYXJpdGhfZXhwciA9IHBwLkZvcndhcmQoKQphcml0aF9leHByLmlnbm9yZShwcC5weXRob25TdHlsZUNvbW1lbnQpCmxwYXIgPSBwcC5TdXBwcmVzcygiKCIpCnJwYXIgPSBwcC5TdXBwcmVzcygiKSIpCgojIGNvZGUgdG8gaW1wbGVtZW50IHNlbGVjdGl2ZSBpZ25vcmUgb2YgTkwncyBpbnNpZGUgKCkncwpOTCA9IHBwLlN1cHByZXNzKCJcbiIpCmJhc2VfaWdub3JlID0gYXJpdGhfZXhwci5pZ25vcmVFeHByc1s6XQppZ25vcmVfc3RhY2sgPSBiYXNlX2lnbm9yZVs6XQpkZWYgbHBhcl9wYSgpOgogICAgaWdub3JlX3N0YWNrLmFwcGVuZChOTCkKICAgIGFyaXRoX2V4cHIuaWdub3JlKE5MKQogICAgI34gcHJpbnQoJ3Bvc3QtcHVzaCcsIGFyaXRoX2V4cHIuaWdub3JlRXhwcnMpCmRlZiBycGFyX3BhKCk6CiAgICBpZ25vcmVfc3RhY2sucG9wKC0xKQogICAgYXJpdGhfZXhwci5pZ25vcmUoTm9uZSkKICAgIGZvciBlIGluIGlnbm9yZV9zdGFjazoKICAgICAgICBhcml0aF9leHByLmlnbm9yZShlKQogICAgI34gcHJpbnQoJ3Bvc3QtcG9wJywgYXJpdGhfZXhwci5pZ25vcmVFeHBycykKZGVmIHJlc2V0X3N0YWNrKCphcmdzKToKICAgIGFyaXRoX2V4cHIuaWdub3JlKE5vbmUpCiAgICBmb3IgZSBpbiBiYXNlX2lnbm9yZToKICAgICAgICBhcml0aF9leHByLmlnbm9yZShlKQogICAgI34gcHJpbnQoJ3Bvc3QtcmVzZXQnLCBhcml0aF9leHByLmlnbm9yZUV4cHJzKQpscGFyLmFkZFBhcnNlQWN0aW9uKGxwYXJfcGEpCnJwYXIuYWRkUGFyc2VBY3Rpb24ocnBhcl9wYSkKYXJpdGhfZXhwci5zZXRGYWlsQWN0aW9uKHJlc2V0X3N0YWNrKQphcml0aF9leHByLmFkZFBhcnNlQWN0aW9uKHJlc2V0X3N0YWNrKQoKIyBub3cgZGVmaW5lIHRoZSBpbmZpeCBub3RhdGlvbiBhcyB1c3VhbAphcml0aF9leHByIDw8PSBwcC5pbmZpeE5vdGF0aW9uKG9wZXJhbmQgfCB2YXIsCiAgICBbCiAgICAoIi0iLCAxLCBwcC5vcEFzc29jLlJJR0hUKSwKICAgIChwcC5vbmVPZigiKiAvIiksIDIsIHBwLm9wQXNzb2MuTEVGVCksCiAgICAocHAub25lT2YoIi0gKyIpLCAyLCBwcC5vcEFzc29jLkxFRlQpLAogICAgXSwKICAgIGxwYXI9bHBhciwgcnBhcj1ycGFyCiAgICApCgphc3NpZ25tZW50ID0gdmFyICsgJz0nICsgYXJpdGhfZXhwcgoKIyBUcnkgaXQgb3V0IQphc3NpZ25tZW50LnJ1blRlc3RzKFsKIiIiYSA9IDEgKyAzIiIiLAoiIiJhID0gKDEgKyAzKSIiIiwKIiIiYSA9IDEgKyAyICsgKCAKMyArCjEpIiIiLAoiIiJhID0gMSArIDIgKyAoKCAKMyArCjEpKSIiIiwKIiIiYSA9IDEgKyAyICsgICAKMyIiIiwKIiIiYSA9ICgxICsgKDIgKyAzKSArCjQpIiIiLApdLCBmdWxsRHVtcD1GYWxzZSk=