我试图解析SQL搜索条件和遇到麻烦解析器来区分逻辑(AND,OR来自其他缀操作符)。我将它们解析为不同的节点(也许很难做到),但是简化了评估阶段。这是相关的代码段(如有必要,我可以提供更多内容)。
AND
OR
let opp = OperatorPrecedenceParser<_,_,_>() let scalarExpr = opp.ExpressionParser opp.TermParser <- constant <|> id <|> between lparen rparen scalarExpr <|> scalarExpr //infix operators added here let comparison = //(e.g., 1 < 2) let compareExpr = pipe3 scalarExpr compareOp scalarExpr (fun l op r -> Comparison(op, l, r)) between lparen rparen compareExpr <|> compareExpr let andTerm = pstringCI "and" .>> ws let orTerm = pstringCI "or" .>> ws let searchCondition, searchConditionRef = createParserForwardedToRef() searchConditionRef := [ comparison pipe3 searchCondition andTerm searchCondition (fun l _ r -> And(l, r)) pipe3 searchCondition orTerm searchCondition (fun l _ r -> Or(l, r)) between lparen rparen searchCondition ] |> choice let filter : Parser<_,unit> = ws >>. searchCondition .>> eof
"1 = 1" 正确解析为 Comparison (Eq,Constant (Int32 1),Constant (Int32 1))
"1 = 1"
Comparison (Eq,Constant (Int32 1),Constant (Int32 1))
但是一旦我尝试使用逻辑运算符(例如)将两个比较合并在一起"1 = 1 or 2 = 2",它就无法解析
"1 = 1 or 2 = 2"
Ln中的错误:1 Col:7 1 = 1或2 = 2 引用 :期望:输入结束或中缀运算符 :7
我希望它将1错误之前的解析为标量表达式,并在or回溯时意识到它不是infix运算符,返回1为完整的标量,并认识到它正在解析逻辑运算符连接的条件的左侧or。
1
or
相反,它似乎继续假设1开始一个更复杂的标量表达式,可能涉及一个infix运算符。
代码是否有问题,还是将AND/解析OR为infix运算符的解决方案(使用相同的OperatorPrecedenceParser)?我宁愿不走那条路,所以我希望我在某个地方犯了一个简单的错误。
OperatorPrecedenceParser
该完整的代码是要点。
我认为最终您会发现需要使用优先级规则将and其or视为infix运算符,因为这正是它们的本质,这就是为什么大多数解析器(包括fparsec和fsyacc)具有特殊功能来处理它们的原因(即,通过优先级和关联性解决歧义)规则)。
and
您已经发现一种情况突出了这一点,但考虑另一种情况:
1 = 1 or 2 = 2 and 3 =3
应该解析为(1 = 1 or 2 = 2) and 3 = 3还是1 = 1 or (2 = 2 and 3 = 3)?
(1 = 1 or 2 = 2) and 3 = 3
1 = 1 or (2 = 2 and 3 = 3)