我正在尝试解析代表树的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和article about how to parse indented trees的帮助,我可以解析这样的示例。
问题是我当前的实现成功解析了字符串
A
B
C
D
作为
[Tree "A" [Tree "B" [Tree "C" []]], Tree "D" []]
节点D
被解析为另一个根。但是,我想使解析失败,因为D
相对于C
是未缩进的,但它与A
或B
的缩进级别不匹配。
我的实现如下(简化:树标签非空且仅包含字母数字字符;不支持所有类型的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
如何将此解析器更改为仅接受与某些外部缩进级别匹配的unindents?提前谢谢。
答案 0 :(得分:2)
只需用{/ 1>替换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.many tree
的问题是tree
可以任意缩进。只要tree
的未注册与任何外部缩进级别(示例中为D
)不匹配,解析器就会愉快地生成{{{的另一个顶级tree
(根) 1}}而不是失败。