Parsing 递归解析语法消耗输入,无法解析序列

Parsing 递归解析语法消耗输入,无法解析序列,parsing,recursion,f#,fparsec,Parsing,Recursion,F#,Fparsec,我正在尝试编写一个解析器。然而,每当我试图解析备选方案时,就会遇到堆栈溢出异常。以下是引发问题的示例: #r@.\packages\FParsec\lib\net40 client\FParsecCS.dll #r@“.\packages\FParsec\lib\net40 client\FParsec.dll” 开放式FParsec 类型分析器 类型元素= |元素列表的替换项 |字符串的解析字符串 let(pRuleElement,pRuleElementRef):(解析器*解析器ref)=c

我正在尝试编写一个解析器。然而,每当我试图解析备选方案时,就会遇到堆栈溢出异常。以下是引发问题的示例:

#r@.\packages\FParsec\lib\net40 client\FParsecCS.dll
#r@“.\packages\FParsec\lib\net40 client\FParsec.dll”
开放式FParsec
类型分析器
类型元素=
|元素列表的替换项
|字符串的解析字符串
let(pRuleElement,pRuleElementRef):(解析器*解析器ref)=createParserForwardedToRef()
让电话响=
pchar''>>。多个harstill(不属于[''''])(pchar'>>)
|>>解析字符串
让pAlternates:解析器=
sepBy1 pRuleElement(多(pchar“”)>>(pchar“/”)>>。多(pchar“”)
|>>交替
做Prulementref:=
选择
[
pString
帕特涅茨
]
"\"0\" / \"1\" / \"2\" / \"3\" / \"4\" / \"5\" / \"6\" / \"7\""
|>运行(pRuleElement.>>(skipNewline eof))
只需重新排列
选项
即可轻松解决此问题,如下所示:

do prulementref:=
选择
[
帕特涅茨
pString
]
但是,这会导致堆栈溢出,因为它会不断尝试解析新的替代序列,而不使用输入。此外,该方法会打破ABNF优先级:

  • 字符串、名称和格式
  • 评论
  • 值范围
  • 重复
  • 分组,可选
  • 串联
  • 另类
  • 我的问题基本上可以归结为:如何将单个元素(可以是元素序列或元素的单个实例)的解析结合起来?如果您需要任何澄清/其他示例,请告诉我

    非常感谢您的帮助,谢谢

    编辑:

    我可能应该提到还有各种其他类型的分组。序列组
    (元素]
    和可选组
    [可选元素]
    。其中
    元素
    可以是嵌套组/可选组/字符串/其他元素类型。下面是序列组解析的示例(为简单起见,不包括可选的组解析):

    #r@.\packages\FParsec\lib\net40 client\FParsecCS.dll
    #r@“.\packages\FParsec\lib\net40 client\FParsec.dll”
    开放式FParsec
    类型分析器
    类型元素=
    |元素列表的替换项
    |元素列表的序列组
    |字符串的解析字符串
    let(pRuleElement,pRuleElementRef):(解析器*解析器ref)=createParserForwardedToRef()
    让电话响=
    pchar''>>。多个harstill(不属于[''''])(pchar'>>)
    |>>解析字符串
    让pAlternates:解析器=
    管道2
    (pRuleElement.>>(多(pchar')>>(pchar'/')>>。多(pchar'))
    (sepBy1 pRuleElement(许多(pchar“”)>>(pchar'/')>.many(pchar“”))
    (有趣的第一次休息->第一次:休息)
    |>>交替
    让pSequenceGroup:解析器=
    在(pchar'(')(pchar'))(seppy1 pRuleElement(pchar'))之间
    |>>序列组
    做Prulementref:=
    选择
    [
    帕特涅茨
    pSequenceGroup
    pString
    ]
    "\"0\" / ((\"1\" \"2\") / \"2\") / \"3\" / (\"4\" / \"5\") / \"6\" / \"7\""
    |>运行(pRuleElement.>>(skipNewline eof))
    

    如果我首先尝试解析替换项/序列组,它会以堆栈溢出异常终止,因为它随后会重复解析替换项。

    问题是,当您对输入运行
    pRuleElement
    解析器时,它会正确解析一个字符串,留下一些未使用的输入,但稍后会失败在将返回的
    选项之外

    您可以在主输入上运行
    pAlternates
    解析器,该解析器实际上可以工作:

    "\"0\" / \"1\" / \"2\" / \"3\" / \"4\" / \"5\" / \"6\" / \"7\""
    |> run (pAlternates .>> (skipNewline <|> eof))
    
    “0\”/“1\”/“2\”/“3\”/“4\”/“5\”/“6\”/“7\”
    |>运行(pAlternates.>>(skipNewline eof))
    

    我怀疑您可能可以这样做,
    pAlternates
    解析器工作正常,即使是在单个字符串上,
    Alternates
    只会返回包含单个列表的
    Alternates

    看起来解决方案只是在解析备选方案时不尝试解析备选方案,以避免出现无限loop导致堆栈溢出。在我的问题中发布的代码的工作版本如下:

    #r@.\packages\FParsec\lib\net40 client\FParsecCS.dll
    #r@“.\packages\FParsec\lib\net40 client\FParsec.dll”
    开放式FParsec
    类型分析器
    类型元素=
    |元素列表的替换项
    |元素列表的序列组
    |字符串的解析字符串
    let(pRuleElement,pRuleElementRef):(解析器*解析器ref)=createParserForwardedToRef()
    let(pNotAlternatives,pNotAlternativesRef):(Parser*Parser ref)=createParserForwardedToRef()
    让电话响=
    pchar''>>。多个harstill(不属于[''''])(pchar'>>)
    |>>解析字符串
    让pAlternates:解析器=
    管道2
    (pNotAlternatives.>>?(许多(pchar“”)>>?(pchar“/”)>>。许多(pchar“”))
    (sepBy1 pNotAlternatives(许多(pchar')>>?(pchar'/')>>。许多(pchar'))
    (有趣的第一次休息->第一次:休息)
    |>>交替
    让pSequenceGroup:解析器=
    在(pchar'(')(pchar'))(seppy1 pRuleElement(pchar'))之间
    |>>序列组
    做Prulementref:=
    选择
    [
    帕特涅茨
    pSequenceGroup
    pString
    ]
    执行PNOTAlternativeRef:=
    选择
    [
    pSequenceGroup
    pString
    ]
    "\"0\" / (\"1\" \"2\") / \"3\" / (\"4\" / \"5\") / \"6\" / \"7\""
    |>运行(pRuleElement.>>(skipNewline eof))
    
    除了添加了
    pNotAlternatives
    之外,我还对它进行了修改,以便它在解析可选分隔符
    /
    失败时可以回溯,从而允许它在“意识到”它毕竟不是一个可选分隔符列表之后继续操作。

    你好,Toma