以下のような複雑な論理式を解析しようとしています。
x > 7 AND x < 8 OR x = 4
解析された文字列をバイナリツリーとして取得します。上記の式の場合、予想される解析済みの式は次のようになります。
[['x', '>', 7], 'AND', [['x', '<', 8], 'OR', ['x', '=', 4]]]
「OR」論理演算子は「AND」演算子よりも優先されます。括弧はデフォルトの優先順位を上書きできます。より一般的には、解析された式は次のようになります。
<left_expr> <logical_operator> <right_expr>
別の例は
input_string = x > 7 AND x < 8 AND x = 4
parsed_expr = [[['x', '>', 7], 'AND', ['x', ',', 8]], 'AND', ['x', '=', 4]]
これまでのところ、残念ながらバイナリツリー形式で解析された式を生成できないこの単純なソリューションを思いつきました。operatorPrecedenceは、前の例と同じ論理演算子が連続して存在する場合、ここでは役に立たないようです。
import pyparsing as pp
complex_expr = pp.Forward()
operator = pp.Regex(">=|<=|!=|>|<|=").setName("operator")
logical = (pp.Keyword("AND") | pp.Keyword("OR")).setName("logical")
vars = pp.Word(pp.alphas, pp.alphanums + "_") | pp.Regex(r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?")
condition = (vars + operator + vars)
clause = pp.Group(condition ^ (pp.Suppress("(") + complex_expr + pp.Suppress(")") ))
expr = pp.operatorPrecedence(clause,[
("OR", 2, pp.opAssoc.LEFT, ),
("AND", 2, pp.opAssoc.LEFT, ),])
complex_expr << expr
print complex_expr.parseString("x > 7 AND x < 8 AND x = 4")
任意の提案やガイダンスは大歓迎です。
BNF
式(括弧なし)は次のようになります。
<expr> -> <expr> | <expr> <logical> <expr>
<expr> -> <opnd> <relational> <opnd>
<opnd> -> <variable> | <numeric>
<relational> -> <'>'> | <'='> | <'>='> | <'<='> | <'!='>