私は pyparsing を使用していますが、MongoDB からデータ フィールドを抽出し、単純な算術演算を実行できる単純な DSL を開発するのに優れていることがわかりました。私は現在、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] のような引数として float または算術式を使用すると、解析は正常に機能し、dbRef 文法を単純化して Word(alphas) だけでも機能します。私の一生の間、私の完全な文法の何が問題なのかを理解することはできません. オペランドの順序を並べ替えたり、functionCall 文法を単純化しようとしましたが、役に立ちませんでした。誰かが私が間違っていることを見ることができますか?
これが機能するようになったら、最後の一歩を踏み出し、式での変数代入のサポートを導入したいと思います..
編集:さらにテストすると、dbRef 文法から印刷可能なものを削除すると、問題なく動作します:
dbRef = Combine(Word(alphas) + OneOrMore(":") + Word(alphanums) + \
Optional("_" + Word(alphas)))
ただし、文字「-」を dbRef (「Class:SN」などの DB フィールドに必要) に追加すると、パーサーが再び失敗します。operatorPrecedence の signop によって「-」が消費されていると思いますか?