Получить последнее сообщение об ошибке, выданное для инструкции - PullRequest
0 голосов
/ 28 октября 2018

Я заметил, что сообщения об ошибках, отправленные 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
...