我正在使用pyparsing,发现它非常适合开发一个简单的DSL,它允许我从MongoDB中提取数据字段并对它们进行简单的算术运算。我现在正在尝试扩展我的工具,以便我可以将Rank [Person:Height]形式的函数应用于字段,并可能包含简单表达式作为函数调用的参数。我正在努力使解析语法工作。以下是我到目前为止的情况:
# Define parser
expr = Forward()
integer = Word(nums).setParseAction(EvalConstant)
real = Combine(Word(nums) + "." + Word(nums)).setParseAction(EvalConstant)
# Handle database field references that are coming out of Mongo,
# accounting for the fact that some fields contain whitespace
dbRef = Combine(Word(alphas) + ":" + Word(printables) + \
Optional(" " + Word(alphas) + " " + Word(alphas)))
dbRef.setParseAction(EvalDBref)
# Handle function calls
functionCall = (Keyword("Rank") | Keyword("ZS") | Keyword("Ntile")) + "[" + expr + "]"
functionCall.setParseAction(EvalFunction)
operand = functionCall | dbRef | (real | integer)
signop = oneOf('+ -')
multop = oneOf('* /')
plusop = oneOf('+ -')
# Use parse actions to attach Eval constructors to sub-expressions
expr << operatorPrecedence(operand,
[
(signop, 1, opAssoc.RIGHT, EvalSignOp),
(multop, 2, opAssoc.LEFT, EvalMultOp),
(plusop, 2, opAssoc.LEFT, EvalAddOp),
])
我的问题是,当我测试一个像Rank [Person:Height]这样的简单表达式时,我得到一个解析异常:
ParseException: Expected "]" (at char 19), (line:1, col:20)
如果我使用float或算术表达式作为Rank [3 + 1.1]这样的参数,解析工作正常,如果我简化了dbRef语法,那么它只是Word(alphas)它也可以工作。不能为我的生活弄清楚我的完整语法有什么不对。我已经尝试重新排列操作数的顺序以及简化functionCall语法无济于事。谁能看到我做错了什么?
一旦我开始工作,我想采取最后一步,并在表达式中引入对变量赋值的支持..
编辑:经过进一步测试,如果我从dbRef语法中删除了printables,那么一切正常:
dbRef = Combine(Word(alphas) + OneOrMore(":") + Word(alphanums) + \
Optional("_" + Word(alphas)))
然而,如果我将字符“ - ”添加到dbRef(我需要DB字段,如“Class:S-N”),解析器会再次失败。我认为“ - ”是由我的operatorPrecedence中的signop消耗的吗?
答案 0 :(得分:2)
似乎发生的情况是,测试字符串末尾的]
字符(Rank[Person:Height]
)被作为dbRef
令牌的一部分消耗,因为此标记的部分已过去最初的:
被声明为由Word(printables)组成(这个字符集,不幸的是包括方括号字符)
然后解析器尝试生成functionCall
,但错过了结束]
因此错误消息。
暂定的解决方法是使用不包含方括号的字符集,可能更明确,例如:
dbRef = Combine(Word(alphas) + ":" + Word(alphas, alphas+"-_./") + \
Optional(" " + Word(alphas) + " " + Word(alphas)))
修改强>:
仔细观察,上面的内容是松散的,但令牌层次结构是错误的(例如,解析器尝试生成functionCall
作为expr
等的一个操作数。)
此外,由于-
符号的含糊不清,我的建议修补程序不起作用,在dbRef
范围内应该被理解为普通字符,而在expr
范围内时应理解为加号。这种类型的问题在解析器中很常见,并且有很多方法可以解决这个问题,尽管我不确定如何使用pyparsing。
答案 1 :(得分:0)
找到解决方案 - 问题是我的dbRef语法消耗了一些属于函数规范的字符。新语法正常工作:
dbRef = Combine(Word(alphas) + OneOrMore(":") + Word(alphanums) + \
Optional(oneOf("_ -") + Word(alphas)))