如果未缩进的代码与外部的缩进级别不匹配,使Text.Parsec.Indent解析失败

3
我将尝试在Haskell中解析表示树的字符串。每个节点都位于一行上,其中缩进确定了嵌套层次(例如,类似于Python或Haskell的语法)。
成功的解析结果应该是类型为[Tree](玫瑰树森林),其中:
data Tree = Tree String [Tree]
          deriving Show

例如,字符串
A
    B
    C
D
    E
        F

应该导致
[Tree "A" [Tree "B" [], Tree "C" []], Tree "D" [Tree "E" [Tree "F" []]]]

使用 Haskell indents package 和一篇关于如何解析缩进树的 文章 的帮助,我可以解析出以下示例。
问题在于我的当前实现成功解析了该字符串。
A
    B
        C
      D

as

[Tree "A" [Tree "B" [Tree "C" []]], Tree "D" []]

节点D被解析为另一个根。然而,我希望在解析D失败,因为它与C相比没有缩进,但它的缩进级别与AB不匹配。
我的实现如下(简化:树标签非空且仅包含字母数字字符;不支持每种Unicode换行符)。
import qualified Control.Applicative as A
import qualified Control.Monad as M
import qualified Text.Parsec as P
import qualified Text.Parsec.Indent as I

parse :: String -> Either P.ParseError [Tree]
parse = I.runIndent "" . P.runParserT forest () ""

forest = P.many tree A.<* P.eof

tree = spacing A.*> I.withBlock Tree node tree

spacing = P.many P.newline A.*> indentation

indentation = P.many $ P.char ' '

node = label A.<* spacing

label = P.many1 P.alphaNum A.<* lineEnd

lineEnd = M.void P.newline P.<|> P.eof

这个解析器如何修改才能仅接受与某个外部缩进级别匹配的未缩进内容?提前感谢。

same 已经提供了这个功能,不是吗? - Zeta
我想我现在明白了。定义 forest = I.block tree A.<* P.eof 可以帮助解决问题!(我需要等一会儿才能回答自己。) - evolutics
1个回答

2

只需将forest的定义替换为

forest = I.block tree A.<* P.eof

看起来做到了这一点。这里的I.block确保源字符串的根缩进到相同的级别。

例子:

A
    B
        C
      D

当前失败了

(line 4, column 7):
unexpected 'D'
expecting " " or end of input
not indented or indentation doesn't match
< p > P.many tree 的问题在于tree可以任意缩进。一旦tree的取消缩进与任何外部缩进级别(示例中的D)不匹配,解析器就会愉快地增加另一个forest的顶级tree(根),而不是失败。 < /p >

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接