Will McGugan
2014-04-04 17:15:21 UTC
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
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
Will McGugan
http://www.willmcgugan.com