【问题标题】:FParsec ‘many’ primitive fails when stream.UserState updated当 stream.UserState 更新时,FParsec“多”原语失败
【发布时间】:2021-02-10 19:32:43
【问题描述】:

以下例程是对official documentation, "Tracing a parser"“解析器跟踪包装器的一个小而简化的更改。

let (<!>) (parser: Parser<_,USER_STATE>) label : Parser<_,USER_STATE> =
    fun stream ->
        do stream.UserState <- stream.UserState  // <= works if commented out!
        let reply = parser stream
        reply

此包装器允许在解析器执行时检查reply,并根据需要更新stream.UserState

注意:此代码只是将stream.UserState 复制到自身上,实际上什么都不做,因为这是以下错误的最小操作。 official documentation manipulating stream.UserState ("Recursive grammers with nesting restrictions”) 操纵 stream.UserState 更多...

在第 3 行注释掉 do stream.UserState &lt;- stream.UserState 允许重复(生成列表)和非重复 FParsec 原语成功。对于这些生成列表的原语,最后一个从属解析器故障被解除,例如 many 的应用程序成功。

如果上述包装器中的parser 不是一个 FParsec 原语,它通过重复应用从属解析器来创建结果列表(如 manysepEndBy 那么这段代码解析成功

如果parser IS 是一个 FParsec 重复原语(例如 manysepEndBy),则从属解析器应用程序的失败也将作为重复 FParsec 的失败传递出去原始 - 意外失败

为什么包含 do stream.UserState &lt;- stream.UserState 会导致像 many 这样的 FParsec 原语失败?

EDIT1:请注意,FParsec documentationstream.UserState 进行了分配,正如在此问题中所做的那样。 @brianbern,我从你的帖子中不明白我在做什么是错误的给定文档。谢谢!

如何在不中断对 FParsec many 原语的调用的情况下分配给stream.UserState

【问题讨论】:

    标签: f# fparsec


    【解决方案1】:

    发生这种情况的原因是CharStream.UserState 的设置器增加了流的StateTag 作为副作用。来自FParsec source code

    public TUserState UserState {
        get { return _UserState; }
        set { _UserState = value; ++StateTag; }
    }
    

    因此,当您将流的 UserState 分配给自身时,它与什么都不做一样。

    更新:“many”解析器的文档指出:

    解析器many p 重复应用解析器p 直到p 失败。它返回p 返回的结果列表。 在序列的末尾p 必须在不改变解析器状态的情况下失败 并且不发送FatalError 信号,否则many p 将失败并出现p 报告的错误。

    FParsec 文档中的示例不会在序列末尾修改解析器状态,但您的示例解析器会在每次调用时修改解析器状态。

    【讨论】:

    • FParsec 文档对 stream.UserState 进行了分配,就像在这个问题中所做的那样。如何在不中断对 FParsec many 原语的调用的情况下分配给 stream.UserState
    • 好的,我会尝试更新我的答案以进一步解释。
    • 出色的收获!不知道我将如何做我需要做的事情,但至少我有一个线索。谢谢@brianberns。
    • @user:558823 @'Stephan Tolksdorf' @Stephan Tolksdorf 为什么像 many 这样的 FParsec 原语不将 UserState 展开到最后一个 UserState(和计数器),就在重复应用子应用失败之前-解析器?如果最终重复应用的从属解析器失败,则原始 many 当前会失败。如果应用于产生解析器结果列表的many 原语或类似原语,这会破坏记录在案的解析器跟踪函数 (quanttec.com/fparsec/users-guide/…)。
    • 我希望他回应,但我认为根本原因是性能。如果每个原语在启动时都保存了用户状态,那么解析器总体上会慢得多。这很像数据库事务 - 作为开发人员,您必须决定何时启动事务,然后何时提交或回滚(通过 attempt 原语)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多