Discussion:
[Pyparsing] Call operator
Will McGugan
2014-04-04 17:15:21 UTC
Permalink
Hi,

I have an expression parser that is working nicely, and I'd like to add a
'call' syntax. Basically something like this:

<operand>(<operand>)

Which should be simple to implement, I have an index operator
<operand>[<operand>] which works, but when I use round brackets the parser
gets stuck in an infinite loop.

I think this may be because operatorPrecendance already uses brackets for
parenthesis. Any idea how I would implement this?

Here's my grammar definition:

integer = Word(nums)
real = Combine(Word(nums) + "." + Word(nums))

constant = oneOf('True False None yes no') + WordEnd()

variable = Regex(r'([a-zA-Z0-9\._]+)')
explicit_variable = '$' + Regex(r'([a-zA-Z0-9\._]+)')

string = QuotedString('"', escChar="\\") | QuotedString('\'', escChar="\\")
regexp = QuotedString('/', escChar=None)
timespan = Combine(Word(nums) + oneOf('ms s m h d'))

variable_operand = variable
explicit_variable_operand = explicit_variable
integer_operand = integer
real_operand = real
number_operand = real | integer
string_operand = string
operand = variable | real | integer | string

assignop = Literal('=')
groupop = Literal(',')
signop = oneOf('+ -')
multop = oneOf('* / // %')
filterop = oneOf('|')
plusop = oneOf('+ -')
notop = Literal('not')

rangeop = Literal('..')
exclusiverangeop = Literal('...')
ternaryop = ('?', ':')

variable_operand.setParseAction(EvalVariable)
explicit_variable_operand.setParseAction(EvalExplicitVariable)
integer_operand.setParseAction(EvalInteger)
real_operand.setParseAction(EvalReal)
string_operand.setParseAction(EvalString)
constant.setParseAction(EvalConstant)
regexp.setParseAction(EvalRegExp)
timespan.setParseAction(EvalTimespan)

expr = Forward()
modifier = Combine(Word(alphas + nums) + ':')


callop = Group(Suppress('(') + expr + Suppress(')'))

operand = (timespan |
real_operand |
integer_operand |
string_operand |
regexp |
constant |
explicit_variable_operand |
variable_operand
)

comparisonop = (oneOf("< <= > >= != == ~= ^= $=") |
(Literal('is not') + WordEnd()) |
(oneOf("is in instr lt lte gt gte matches fnmatches") +
WordEnd()) |
(Literal('not in') + WordEnd()) |
(Literal('not instr') + WordEnd()))
logicop = oneOf("and or") + WordEnd()

logicopOR = Literal('or') + WordEnd()
logicopAND = Literal('and') + WordEnd()
formatop = Literal('::')


expr << operatorPrecedence(operand, [

(signop, 1, opAssoc.RIGHT, EvalSignOp),
(exclusiverangeop, 2, opAssoc.LEFT, EvalExclusiveRangeOp),
(rangeop, 2, opAssoc.LEFT, EvalRangeOp),

(callop, 2, opAssoc.LEFT, EvalCallOp),
(index, 1, opAssoc.LEFT, EvalIndexOp),

(modifier, 1, opAssoc.RIGHT, EvalModifierOp),

(formatop, 2, opAssoc.LEFT, EvalFormatOp),

(multop, 2, opAssoc.LEFT, EvalMultOp),
(plusop, 2, opAssoc.LEFT, EvalAddOp),
(assignop, 2, opAssoc.LEFT, EvalAssignOp),
(groupop, 2, opAssoc.LEFT, EvalGroupOp),


(filterop, 2, opAssoc.LEFT, EvalFilterOp),

(comparisonop, 2, opAssoc.LEFT, EvalComparisonOp),
(notop, 1, opAssoc.RIGHT, EvalNotOp),
#(logicop, 2, opAssoc.LEFT, EvalLogicOp),

(logicopOR, 2, opAssoc.LEFT, EvalLogicOpOR),
(logicopAND, 2, opAssoc.LEFT, EvalLogicOpAND),

(ternaryop, 3, opAssoc.LEFT, EvalTernaryOp),
])

Thanks,

Will
--
Will McGugan
http://www.willmcgugan.com
Loading...