获取针对指令抛出的最后一条错误消息

时间:2018-10-27 23:48:30

标签: f# parsec fparsec

我注意到FParsec发送的错误消息非常“含糊”,除了为指令发送的最后一条消息。 这是一个示例:

要解析的代码:

if (2 + 2 == 4)

通常,这里应该有一个指令块(所以放在括号中)。

我得到的是什么

  

失败:Ln错误:1列:如果(2 + 2 == 4)则为1 ^期望值:[一些说明]

     

解析器回溯到以下时间:Ln错误:1列:3如果(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

0 个答案:

没有答案