使用 FParsec 是否可以在解析器失败时操纵错误位置?

问题描述 投票:0回答:2

作为示例,我将采用 Phillip Trelford 的这个简单 C# 解析器。为了解析标识符,他写了这个(略有改变):

let reserved = ["for";"do"; "while";"if";"switch";"case";"default";"break" (*;...*)]
let pidentifierraw =
    let isIdentifierFirstChar c = isLetter c || c = '_'
    let isIdentifierChar c = isLetter c || isDigit c || c = '_'
    many1Satisfy2L isIdentifierFirstChar isIdentifierChar "identifier"
let pidentifier =
    pidentifierraw
    >>= fun s ->
        if reserved |> List.exists ((=) s) then fail "keyword instead of identifier"
        else preturn s

pidentifier 的问题是,当它失败时,位置指示器位于流的末尾。我的一个例子:

Error in Ln: 156 Col: 41 (UTF16-Col: 34)
        Block "main" 116x60 font=default fg=textForeground
                                        ^
Note: The column count assumes a tab stop distance of 8 chars.
keyword instead of identifier

显然,不是 C# 代码片段,但为了示例起见,我使用

pidentifier
来解析
font=
之后的文本。是否可以告诉 FParsec 在解析输入的开头显示错误?使用
>>?
.>>.?
或任何回溯变体似乎没有效果。

parsing f# parser-combinators fparsec
2个回答
2
投票

我认为你想要的是

attempt
,如果解析器
p
失败,它将回溯到原始解析器状态。所以你可以将
pidentifier
定义为:

let pidentifier =
    pidentifierraw
    >>= fun s ->
        if reserved |> List.exists ((=) s) then fail "keyword instead of identifier"
        else preturn s
    |> attempt   // rollback on failure

输出类似于:

Failure:
Error in Ln: 1 Col: 1
default
^

The parser backtracked after:
  Error in Ln: 1 Col: 8
  default
         ^
  Note: The error occurred at the end of the input stream.
  keyword instead of identifier

更新

如果您不想在错误消息中看到回溯信息,您可以使用简化版的

attempt
,如下所示:

let attempt (parser : Parser<_, _>) : Parser<_, _> =
    fun stream ->
        let mutable state = CharStreamState(stream)
        let reply = parser stream
        if reply.Status <> Ok then
            stream.BacktrackTo(&state)
        reply

输出现在只是:

Failure:
Error in Ln: 1 Col: 1
default
^
keyword instead of identifier

1
投票

不幸的是,我错过了

>>=?
运算符,它显然(至少在语义上)等同于
Brian Berns 正确建议的 
attempt

这两种方法的问题是如果前面的解析器也在回溯,则后续消息

The parser backtracked after:[…]

可能会级联:

Error in Ln: 156 Col: 29 (UTF16-Col: 22) Block "main" 116x60 font=default fg=textForeground ^ Note: The column count assumes a tab stop distance of 8 chars. Expecting: space/tab The parser backtracked after: Error in Ln: 156 Col: 42 (UTF16-Col: 35) Block "main" 116x60 font=default fg=textForeground ^ Note: The column count assumes a tab stop distance of 8 chars. Expecting: space/tab Other error messages: keyword instead of identifier
    
© www.soinside.com 2019 - 2024. All rights reserved.