Получить последнее сообщение об ошибке, выданное для инструкции
Я заметил, что сообщения об ошибках, отправленные FParsec, были довольно "неоднозначными", за исключением последнего сообщения, отправленного для инструкции. Вот пример:
Код для разбора:
if (2 + 2 == 4)
Здесь, как правило, должен быть блок инструкций (так в скобках).
И что я получаю:
Ошибка: Ошибка в Ln: 1 Col: 1, если (2 + 2 == 4) ^ Ожидается: [некоторые инструкции]
Парсер возвращается после: Ошибка в Ln: 1 Col: 3 if (2 + 2 == 4) ^ Неверный идентификатор: 'if' является зарезервированным ключевым словом
Анализатор возвращается после: Ошибка в Ln: 1 Col: 16 if (2 + 2 == 4) ^ Примечание: ошибка произошла в конце входного потока. Ожидается: стартовый блок
Как видите, актуально только последнее сообщение об ошибке. Поэтому я хотел бы знать, если нет способа отобразить только этот, и, следовательно, последний, не проходя через другие. Я думаю, это не легко, так как это особенность FParsec, но вы никогда не знаете...
Я не думаю, что мне нужно публиковать код F#, поскольку он обычно используется библиотекой.
редактировать
Вот код моего анализатора для разбора примера выше:
type Statement =
| If of Expr * Block option
// And others...
and Block = Block of Statement list
let ws = pspaces >>. many pspaces |>> (fun _ -> ())
let str_ws s = pstring s .>> ws
let pexpr, pexprimpl = createParserForwardedToRef ()
// With their implementations (addition, subtraction, ...)
let pstatement, pstatementimpl = createParserForwardedToRef ()
// With their implementations, like "pif" below
let psinglestatement = pstatement |>> fun statement -> [statement]
let pstatementblock =
psinglestatement <|>
between (ws >>. str_ws "{") (ws >>. str_ws "}") (many pstatement)
let pif =
pipe2
(str_ws "if" >>. pexpr)
(pstatementblock)
(fun cnd block -> If(cnd, Some (Block(block))))
pstatementimpl :=
attempt (pif) <|>
// And others...
Редактировать II:
Вот код идентификатора анализа:
let reserved = [
"if"; "else" // And other...
]
let pidentifierraw =
let inline isIdentifierFirstChar c = isLetter c
let inline isIdentifierChar c = isLetter c || isDigit c
many1Satisfy2L isIdentifierFirstChar isIdentifierChar "identifier"
let pidentifier =
pidentifierraw
>>= fun s ->
if reserved |> List.exists ((=) s) then fail ("Bad identifier: '" + s + "' is a reserved keyword")
else preturn s
type Literal =
| Identifier of string
// And other...
let pid = pidentifier |>> Literal.Identifier
pexpr
это набор значений, включая идентификаторы, литералы и их операции:
let pexpr, pexprimpl = createParserForwardedToRef ()
type Assoc = Associativity
let opp = OperatorPrecedenceParser<Expr, unit, unit> ()
pexprimpl := opp.ExpressionParser <?> "expression"
let term = pvalue .>> ws <|> between (str_ws "(") (str_ws ")") pexpr
opp.TermParser <- term
let inops = [ "+"; "-"; "*"; "/"; "=="; "!="; "<="; ">="; "<"; ">" ]
for op in inops do opp.AddOperator(InfixOperator(op, ws, 1, Assoc.Left, fun x y -> InfixOp(x, op, y)))
pvalue
определяет литералы, включая идентификаторы с pidentifier
, Я не думаю, что мне нужно помещать их определения, так как все они следуют этой схеме (например):
let ptrue = str_ws "true" |>> fun _ -> Bool(true)
let pfalse = str_ws "false" |>> fun _ -> Bool(false)
let pbool = ptrue <|> pfalse