3

我正在使用 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 正在消耗“-”?

4

2 回答 2

2

似乎发生的情况是,测试]字符串(不幸的是包括方括号字符)Rank[Person:Height]dbRef:

然后解析器尝试生成 afunctionCall但缺少关闭]因此错误消息。

一个暂定的解决方法是使用不包含方括号的字符集,可能更明确,例如:

dbRef = Combine(Word(alphas) + ":" + Word(alphas, alphas+"-_./") + \
    Optional(" " + Word(alphas) + " " + Word(alphas)))

编辑
仔细一看,上面的内容大致正确,但是令牌层次结构是错误的(例如,解析器尝试将 afunctionCall作为 an 的一个操作数expr 等)。此外,由于符号
的歧义,我建议的修复将不起作用-在 a 中应理解为普通字符,在 中应理解为dbRefplusOp expr。这种类型的问题在解析器中很常见,并且有一些方法可以解决这个问题,尽管我不确定 pyparsing 到底如何。

于 2012-11-28T00:14:08.870 回答
0

找到解决方案 - 问题是我的 dbRef 语法正在消耗一些属于函数规范的字符。正确工作的新语法:

dbRef = Combine(Word(alphas) + OneOrMore(":") + Word(alphanums) + \
    Optional(oneOf("_ -") + Word(alphas)))
于 2012-11-28T01:06:52.310 回答