gpt4 book ai didi

How to write a custom 'attempt' parser in FParsec?(如何在FParsec中编写自定义的“尝试”解析器?)

转载 作者:bug小助手 更新时间:2023-10-25 12:11:52 26 4
gpt4 key购买 nike



I'm trying to write a custom attempt parser in FParsec. I tried it, but I'm an F# / FParsec beginner and get lost with the F# compiler errors I produce. This is my best guess so far:

我正在尝试用FParsec编写一个定制的尝试解析器。我试过,但我是一个F#/FParsec初学者,我产生的F#编译器错误让我迷失了方向。这是我到目前为止最好的猜测:


let customAttempt (p: CharStream<State> -> ParserResult<SyntaxNode,State>) : Parser<SyntaxNode,State> =
fun (stream: CharStream<State>) ->
let previousState = stream.State
let (result, diagnostics) = p stream //This causes Error FS0001 This expression was expected to have type ''a * 'b' but here has type 'ParserResult<SyntaxNode,State>'
match diagnostics with
| [] -> result
| _ ->
stream.BacktrackTo previousState
result //Here I actually want to return a result associated with previousState

Why would I ever need to write a custom attempt parser?

为什么我需要编写一个定制的尝试解析器呢?


Because I want to attempt parsers that never fail. In the FParsec attempt documentation, they say

因为我想尝试永远不会失败的解析器。在FParsec尝试文档中,他们说



The parser attempt p applies the parser p. If p fails after changing the parser state or with a fatal error, attempt p will backtrack to the original parser state and report a non‐fatal error.



In my case, the parser p never fails. What I'm currently implementing is an error recovery for my parser based on the approach described in this block post. This approach is to construct a parser p that never fails. Instead, it would always return a Parser<SyntaxNode,State> value, where SyntaxNode is a type for an optional parser result, and State is a list of Diagnostics. In case this list is empty, the parser p was successful.

在我的例子中,解析器p从未失败过。我目前正在实现的是基于本文中描述的方法的解析器的错误恢复。这种方法是构造一个永不失败的解析器p。相反,它将始终返回Parser 值,其中SynaxNode是可选解析器结果的类型,State是诊断列表。如果该列表为空,则解析器p成功。


The mentioned approach to error recovery in FParsec works well for simple grammars. My grammar is more complex and involves choice, attempt, or skipManyTill parsers. Since p never fails in my case, these original FParsec parses do not do the trick anymore.

前面提到的FParsec中的错误恢复方法适用于简单的语法。我的语法更复杂,涉及选择、尝试或跳过ManyTill解析器。由于p在我的例子中从未失败过,所以这些原始的FParsec解析不再起作用。


Therefore, I'm trying to write my own versions of customChoice, customAttempt, or customSkipManyTill, so that I can use them for my grammar that would also support error recovery based on the mentioned approach of parsers that never fail but emit diagnostics instead.

因此,我尝试编写我自己的customChoice、customAttempt或customSkipManyTill版本,以便我可以将它们用于我的语法,该语法还支持基于上述解析器方法的错误恢复,这些解析器从不失败,而是发出诊断。


更多回答
优秀答案推荐

This is an interesting idea. I'd be curious to know how it turns out.

这是一个有趣的想法。我很想知道结果如何。


I think the problem with your code is that you're assuming that a parser returns a (result, diagnostics) tuple, but this is not correct. Diagnostics are actually stored in the stream state, not returned by the parser. I think you want to check the return value of the parser to determine whether to backtrack, so the code should probably look something like this:

我认为您代码的问题在于您假设解析器返回一个(结果、诊断)元组,但这是不正确的。诊断实际上存储在流状态中,而不是由解析器返回。我认为您需要检查解析器的返回值以确定是否回溯,因此代码可能如下所示:


let customAttempt (p : Parser<SyntaxNode, _>) =
fun (stream : CharStream<_>) ->
let state = stream.State
let reply = p stream
if reply.Result = SyntaxNode.Error then
stream.BacktrackTo(state)
reply

Note that I haven't tried this, so I don't know if it works. Good luck!

请注意,我还没有尝试过这个,所以我不知道它是否有效。祝好运!


更多回答

Thank you. It solved my f# compiler problem but not my core problem. I need some more investigation into this to follow up.

谢谢。它解决了我的f#编译器问题,但没有解决我的核心问题。我需要更多的调查来跟进这件事。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com