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