这个问题与Parsec和uu-parsinglib都有关。当我们编写解析器组合子时,它们会处理来自编译器的字符流。有没有可能解析一个字符并将其放回(或返回另一个字符)到输入流?
例如,我希望解析输入"test + 5",解析t、e、s、t,并在识别test模式后,将例如v字符放回字符流中,因此在继续解析过程时,我们将根据v + 5进行匹配
我现在不想在任何特定的情况下使用它-我想深入了解其中的可能性。
发布于 2013-08-21 00:56:16
我不确定是否可以直接使用这些解析器,但通常您可以通过将解析器与一些允许注入剩余物的流相结合来实现。
例如,使用attoparsec-conduit可以将解析器转换为管道,使用
sinkParser :: (AttoparsecInput a, MonadThrow m)
=> Parser a b -> Consumer a m b其中Consumer是一种特殊类型的管道,它不产生任何输出,只接收输入并返回最终值。
由于管道支持剩余物,因此您可以创建一个helper方法来转换解析器,该解析器可选地将一个值返回到流中,并将其转换为管道:
import Data.Attoparsec.Types
import Data.Conduit
import Data.Conduit.Attoparsec
import Data.Functor
reinject :: (AttoparsecInput a, MonadThrow m)
=> Parser a (Maybe a, b) -> Consumer a m b
reinject p = do
(lo, r) <- sinkParser p
maybe (return ()) leftover lo
return r然后使用sinkParser将标准解析器转换为管道,使用reinject将这些特殊解析器转换为管道,然后组合管道而不是解析器。
发布于 2013-08-22 18:38:58
我认为最简单的归档方法是构建一个多层解析器。考虑词法分析器+解析器的组合。这是解决这个问题的一种干净的方法。
您必须将这两种解析分开。搜索和替换解析转到第一个解析器,构建AST解析转到第二个解析器。或者,您可以创建一个中间令牌表示。
import Text.Parsec
import Text.Parsec.String
parserLvl1 :: Parser String
parserLvl1 = many (try (string "test" >> return 'v') <|> anyChar)
parserLvl2 :: Parser Plus
parserLvl2 = do text1 <- many (noneOf "+")
char '+'
text2 <- many (noneOf "+")
return $ Plus text1 text2
data Plus = Plus String String
deriving Show
wholeParse :: String -> Either ParseError Plus
wholeParse source = do res1 <- parse parserLvl1 "lvl1" source
res2 <- parse parserLvl2 "lvl2" res1
return res2现在您可以解析您的示例了。wholeParse "test+5"结果为Right (Plus "v" "5")。
可能的变体:
的标记流
https://stackoverflow.com/questions/18338707
复制相似问题