У меня есть следующая грамматика fsyacc для (слегка измененной формы) условий поиска SQL:
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
, но перенос константы или всего условия поиска в parens приводит к его сбою (как ни странно, оборачивание сравнения в parens работает).Вот пример, который терпит неудачу:
Error in Ln: 1 Col: 8
(1 = 1 or 2 = 2)
^
Expecting: infix operator or ')'
: 8
Скаляр, условие сравнения и поиска могут начинаться одинаково (open paren -> constant -> infix operator), но в конечном итоге существенно различаются по типу операторавстречается.Например, если вы нажмете or
, вы знаете, что открывающая скобка относится ко всему условию, а не к сопоставлению с левой стороны.Правильно ли это обрабатывается при возврате?Если это так, как бы вы потерпели неудачу - при синтаксическом анализе сложного выражения - таким образом, чтобы не потреблять никакого ввода?
Обработка необязательных скобок для скаляров, сравнений и условий поиска обрабатывается слева.рекурсия в грамматике fsyacc.Я понимаю, что это должно быть учтено в FParsec.Но из вышеприведенной ошибки я не могу себе представить, как избежать обширных возвратов в любом случае.