对于 SQL 搜索条件,我有以下 fsycc 语法(稍作修改的形式):
scalar_expr:
| ID { Identifier($1) }
| constant { Constant($1) }
| unary_op scalar_expr { Unary($1, $2) }
| scalar_expr binary_op scalar_expr { Binary($2, $1, $3) }
| LPAREN scalar_expr RPAREN { $2 }
search_condition:
| search_condition OR search_condition { Or($1, $3) }
| search_condition AND search_condition { And($1, $3) }
| scalar_expr comparison scalar_expr { Comparison($2, $1, $3) }
| LPAREN search_condition RPAREN { $2 }
我已经在 FParsec 中重新实现了它(在上一个问题的帮助下)。以下是相关位:
let binOpp = OperatorPrecedenceParser()
let scalarExpr = binOpp.ExpressionParser
binOpp.TermParser <-
[ constant
id
between lparen rparen scalarExpr ]
|> choice
// binary/unary ops added here
let comparison =
let compareExpr = pipe3 scalarExpr compareOp scalarExpr (fun l op r -> Comparison(op, l, r))
between lparen rparen compareExpr <|> compareExpr
let andTerm = stringCIReturn "and" (fun l r -> And(l, r)) .>> ws
let orTerm = stringCIReturn "or" (fun l r -> Or(l, r)) .>> ws
let searchCondition, searchConditionRef = createParserForwardedToRef()
searchConditionRef:=
chainl1 comparison (andTerm <|> orTerm)
<|> between lparen rparen searchCondition
这会解析1 = 1 or 2 = 2
,但在括号中包装一个常量或整个搜索条件会导致它失败(奇怪的是,在括号中包装比较有效)。这是一个失败的例子:
Error in Ln: 1 Col: 8
(1 = 1 or 2 = 2)
^
Expecting: infix operator or ')'
: 8
标量、比较和搜索条件可能都以类似的方式开始(开括号 -> 常量 -> 中缀运算符),但本质上是根据最终遇到的运算符类型来区分的。例如,如果您点击,or
您就知道左括号属于整个条件,而不是左侧的比较。这是否通过回溯正确处理?如果是这样,您将如何以不消耗任何输入的方式在解析复杂表达式时失败?
处理标量、比较和搜索条件的可选括号由 fsyacc 语法中的左递归处理。我知道这需要在 FParsec 中考虑。但是从上述错误中,我无法想象如何摆脱广泛的回溯。