一尘不染

将逻辑与其他中缀运算符区分开

sql

我试图解析SQL搜索条件和遇到麻烦解析器来区分逻辑(ANDOR来自其他缀操作符)。我将它们解析为不同的节点(也许很难做到),但是简化了评估阶段。这是相关的代码段(如有必要,我可以提供更多内容)。

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 or 2 = 2",它就无法解析

Ln中的错误:1 Col:7
1 = 1或2 = 2
引用
:期望:输入结束或中缀运算符
:7

我希望它将1错误之前的解析为标量表达式,并在or回溯时意识到它不是infix运算符,返回1为完整的标量,并认识到它正在解析逻辑运算符连接的条件的左侧or

相反,它似乎继续假设1开始一个更复杂的标量表达式,可能涉及一个infix运算符。

代码是否有问题,还是将AND/解析OR为infix运算符的解决方案(使用相同的OperatorPrecedenceParser)?我宁愿不走那条路,所以我希望我在某个地方犯了一个简单的错误。

完整的代码是要点。


阅读 128

收藏
2021-05-30

共1个答案

一尘不染

我认为最终您会发现需要使用优先级规则将andor视为infix运算符,因为这正是它们的本质,这就是为什么大多数解析器(包括fparsec和fsyacc)具有特殊功能来处理它们的原因(即,通过优先级和关联性解决歧义)规则)。

您已经发现一种情况突出了这一点,但考虑另一种情况:

1 = 1 or 2 = 2 and 3 =3

应该解析为(1 = 1 or 2 = 2) and 3 = 3还是1 = 1 or (2 = 2 and 3 = 3)

2021-05-30