我正在使用 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)
如果我使用浮点数或算术表达式作为 Rank[3 + 1.1] 之类的参数,则解析工作正常,如果我简化 dbRef 语法使其只是 Word(alphas) 它也可以工作。我一生都无法弄清楚我的完整语法有什么问题。我尝试重新排列操作数的顺序以及简化 functionCall 语法无济于事。谁能看到我做错了什么?
一旦我得到这个工作,我想采取最后一步,并在表达式中引入对变量赋值的支持..
编辑:经过进一步测试,如果我从 dbRef 语法中删除可打印文件,一切正常:
dbRef = Combine(Word(alphas) + OneOrMore(":") + Word(alphanums) + \
Optional("_" + Word(alphas)))
但是,如果我将字符“-”添加到 dbRef(我需要像“Class:SN”这样的 DB 字段),解析器将再次失败。我认为我的 operatorPrecedence 中的 signop 正在消耗“-”?