我正在尝试用 attoparsec 制作一个简单的解析器。生产规则大致如下:
block: ?token> [inline]
inline: <?token>foo<?> | anyText
所以,我想要得到的是,一个块以文字 ? 开头,然后是一个标记,然后是 >,然后是一系列内联。
内联是 foo 形式的序列,或者只是任何纯文本。
我有爆炸性的内存使用,但我不确定如何分解解析器来避免它。我正在编写的解析器的目的是提取那些“令牌”的东西。这是我的实现:
import Control.Applicative
import Control.Monad
import Data.Attoparsec.Text as Text
import Data.Text
blockLine :: Parser [Text]
blockLine = do
block <- hiddenBlock -- the block token
inlines <- many (hiddenInline <|> inline) -- followed by inlines, which might have tokens
return $ block : inlines
inline = manyTill anyChar (hiddenInline <|> (endOfInput >> return Text.empty))
hiddenInline = Text.pack <$> do
char '<' -- opening "tag"
char '?' -- opening "tag" still
token <- manyTill anyChar (char '>') -- the token
manyTill anyChar (string "<?>") -- close the "tag"
return token
hiddenBlock = Text.pack <$> do
char '?'
manyTill anyChar (char '>')
对我来说,这看起来是将生产规则非常直接地转换为 LL 解析器。我想困难在于我不确定如何表达内联的产生。它应该是“任意”文本,但是一旦找到 hiddenInline,解析就应该停止。