使用 FParsec 解析可选多行表达式

发布于 2024-12-21 08:05:39 字数 952 浏览 4 评论 0原文

我正在为这种形式的字符串编写一个 FParsec 解析器:

do[ n times]([ action] | \n([action]\n)*endDo)

换句话说,这是一个带有可选时间量词的“do”语句,以及单个“action”语句或“action”列表(每个都在一个新的行),末尾有一个“end do”(为了简单起见,我省略了缩进/尾随空格处理)。

这些是有效输入的示例:

do action

do 3 times action

do
endDo

do 3 times
endDo

do
action
action
endDo

do 3 times
action
action
endDo

这看起来不是很复杂,但是:

为什么这不起作用?

let statement = pstring "action"
let beginDo = pstring "do"
                >>. opt (spaces1 >>. pint32 .>> spaces1 .>> pstring "times")
let inlineDo = tuple2 beginDo (spaces >>. statement |>> fun w -> [w])
let expandedDo = (tuple2 (beginDo .>> newline)
                    (many (statement .>> newline)))
                 .>> pstring "endDo"
let doExpression = (expandedDo <|> inlineDo)

这个表达式的正确解析器是什么?

I'm writing an FParsec parser for strings in this form:

do[ n times]([ action] | \n([action]\n)*endDo)

in other words this is a "do" statement with an optional time quantifier, and either a single "action" statement or a list of "action"s (each on a new line) with an "end do" at the end (I omitted indentations/trailing space handling for simplicity).

These are examples of valid inputs:

do action

do 3 times action

do
endDo

do 3 times
endDo

do
action
action
endDo

do 3 times
action
action
endDo

This does not look very complicated, but:

Why does this not work?

let statement = pstring "action"
let beginDo = pstring "do"
                >>. opt (spaces1 >>. pint32 .>> spaces1 .>> pstring "times")
let inlineDo = tuple2 beginDo (spaces >>. statement |>> fun w -> [w])
let expandedDo = (tuple2 (beginDo .>> newline)
                    (many (statement .>> newline)))
                 .>> pstring "endDo"
let doExpression = (expandedDo <|> inlineDo)

What is a correct parser for this expression?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

怀里藏娇 2024-12-28 08:05:39

您需要使用attempt函数。
我刚刚修改了您的 beginDodoExpression 函数。

这是代码:

let statement  o=o|>  pstring "action"

let beginDo o= 
    attempt (pstring "do"
        >>. opt (spaces1 >>. pint32 .>> spaces1 .>> pstring "times")) <|> 
        (pstring "do" >>% None)                                       <|o

let inlineDo   o= tuple2 beginDo (spaces >>. statement |>> fun w -> [w]) <|o
let expandedDo o= (tuple2 (beginDo .>> newline) (many (statement .>> newline)))
                 .>> pstring "endDo" <|o

let doExpression o= ((attempt expandedDo) <|> inlineDo) .>> eof <|o

我在末尾添加了一个 eof 。这样测试起来会更容易。

我还添加了虚拟 o 参数以避免值限制。

You need to use the attempt function.
I just modified your beginDo and doExpression functions.

This is the code:

let statement  o=o|>  pstring "action"

let beginDo o= 
    attempt (pstring "do"
        >>. opt (spaces1 >>. pint32 .>> spaces1 .>> pstring "times")) <|> 
        (pstring "do" >>% None)                                       <|o

let inlineDo   o= tuple2 beginDo (spaces >>. statement |>> fun w -> [w]) <|o
let expandedDo o= (tuple2 (beginDo .>> newline) (many (statement .>> newline)))
                 .>> pstring "endDo" <|o

let doExpression o= ((attempt expandedDo) <|> inlineDo) .>> eof <|o

I added an eof at the end. This way it will be easier to test.

I added also dummy o parameters to avoid the value restriction.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文