使用 FParsec 进行基本错误恢复
假设我有这个解析器:
let test p str =
match run p str with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
let myStatement =
choice (seq [
pchar '2' >>. pchar '+' .>> pchar '3' .>> pchar ';';
pchar '3' >>. pchar '*' .>> pchar '4' .>> pchar ';';
])
let myProgram = many myStatement
test myProgram "2+3;3*4;3*4;" // Success: ['+'; '*'; '*']
现在, "2+3;2*4;3*4;3+3;"
将失败,并出现 2*4;
周围的错误。但是,如果我想要 2*4;
和 3+3;
的错误,最佳实践是什么?基本上,我想扫描到最近的“;”但仅当出现致命错误时。如果发生这种情况,我想汇总错误。
亲切的问候,Lasse Espeholt
更新: recoverWith
是一个很好的解决方案,谢谢!但鉴于:
let myProgram =
(many1 (myStatement |> recoverWith '�')) <|>% []
test myProgram "monkey"
我希望得到没有错误的 []
。或者也许更“公平”一点:
let myProgram =
(attempt (many1 (myStatement |> recoverWith '�'))) <|>% []
Assume I've this parser:
let test p str =
match run p str with
| Success(result, _, _) -> printfn "Success: %A" result
| Failure(errorMsg, _, _) -> printfn "Failure: %s" errorMsg
let myStatement =
choice (seq [
pchar '2' >>. pchar '+' .>> pchar '3' .>> pchar ';';
pchar '3' >>. pchar '*' .>> pchar '4' .>> pchar ';';
])
let myProgram = many myStatement
test myProgram "2+3;3*4;3*4;" // Success: ['+'; '*'; '*']
Now, "2+3;2*4;3*4;3+3;"
will fail with error around 2*4;
. But what is best practice if I want both the error for 2*4;
and 3+3;
? Basically, I want to scan to the nearest ';' but only if there is a fatal error. And if that happens I want to aggregate the errors.
Kind regards, Lasse Espeholt
Update: recoverWith
is a nice solution, thanks! But given:
let myProgram =
(many1 (myStatement |> recoverWith '�')) <|>% []
test myProgram "monkey"
I would expect to get []
with no errors. Or maybe a bit more "fair":
let myProgram =
(attempt (many1 (myStatement |> recoverWith '�'))) <|>% []
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
FParsec 没有内置支持从致命解析器错误中恢复,这将允许您获取部分解析器结果并从多个位置收集错误。然而,为此目的定义自定义组合器函数非常容易。
例如,要从简单语句解析器中的错误中恢复,您可以定义以下
recoverWith
组合器:然后您可以按如下方式使用此组合器:
使用
test myProgram "2+3;2* 进行测试4;3*4;3+3"
将产生输出:更新:
嗯,我以为你想从致命错误中恢复,以便收集多个错误消息并可能产生部分结果。例如,对于语法突出显示或允许用户一次修复多个错误很有用的东西。
您的更新似乎表明您只想在出现解析器错误时忽略部分输入,这要简单得多:
更新 2:
以下是
recoverWith
它不会聚合错误,并且仅在参数解析器消耗输入(或以任何其他方式更改解析器状态)时尝试从错误中恢复:FParsec has no built-in support for recovering from fatal parser errors that would allow you to obtain partial parser results and collect errors from multiple positions. However, it's pretty easy to define a custom combinator function for this purpose.
For example, to recover from errors in your simple statement parser you could define the following
recoverWith
combinator:You could then use this combinator as follows:
Testing with
test myProgram "2+3;2*4;3*4;3+3"
would yield the output:Update:
Hmm, I thought you wanted to recover from a fatal error in order to collect multiple error messages and maybe produce a partial result. Something that would for example be useful for syntax highlighting or allowing your users to fix more than one error at a time.
Your update seems to suggest that you just want to ignore parts of the input in case of a parser error, which is much simpler:
Update 2:
The following is a version of
recoverWith
that doesn't aggregate errors and only tries to recover from an error if the argument parser consumed input (or changed the parser state in any other way):