在Haskell中将字符插入解析器组合字符流中

问题描述:

此问题与Parsecuu-parsinglib都有关。当我们编写解析器组合器时,它们处理来自编译器的字符流。是否有可能解析一个字符并将其放回(或返回另一个字符)到输入流?在Haskell中将字符插入解析器组合字符流中

我想例如解析输入“测试+ 5”,解析test和识别test图案,把例如v字符回到字符流之后,因此而continuating解析过程我们与v + 5

匹配我现在不想在任何特定情况下使用此功能 - 我想深入了解可能性。

+0

这当然是可能的秒差距,你可以使用'getInput'和'setInput'功能。 –

+0

是的,Parsec可以做到这一点,但它肯定会增加解析器的复杂性,并使调试更加困难。它的一个常见用途是实现编程语言的预处理器。 –

我不确定这些解析器是否可以直接使用,但通常情况下,您可以通过将解析器与允许注入剩余物的一些流相结合来实现它。

例如,使用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,然后结合导管而不是解析器。

我认为最简单的方法来存档这是建立一个多层次的分析器。想想一个词法分析器+解析器组合。这是解决这个问题的一个干净方法。

你必须分开这两种解析。搜索和替换解析转到第一个解析器,而构建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")

可能的变型:

  • 创建类和实例用于组合包裹解析器阶段。 (可能携带解析器的状态。)
  • 创建的中间表示,令牌

流这很容易在UU-parsinglib使用pSwitch函数来完成。但问题是为什么你想这样做?由于输入中缺少v?在这种情况下,uu-parsinglib将自动执行纠错,所以你不需要像这样的东西。否则,你可以写

pSwitch :: (st1 -> (st2, st2 -> st1)) -> P st2 a -> P st1 a 
pInsert_v = pSwitch (\st1 -> (prepend v st2, id) (pSucceed()) 

这取决于你的实际状态类型V是如何实际增加,所以你必须给自己定义函数

prepend
。我不知道这样的插入会如何影响该文件中的当前位置等

Doaitse Swierstra