2013-08-20 24 views
2

此問題與Parsecuu-parsinglib都有關。當我們編寫解析器組合器時,它們處理來自編譯器的字符流。是否有可能解析一個字符並將其放回(或返回另一個字符)到輸入流?在Haskell中將字符插入解析器組合字符流中

我想例如解析輸入「測試+ 5」,解析test和識別test圖案,把例如v字符回到字符流之後,因此而continuating解析過程我們與v + 5

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

+0

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

+0

是的,Parsec可以做到這一點,但它肯定會增加解析器的複雜性,並使調試更加困難。它的一個常見用途是實現編程語言的預處理器。 –

回答

1

我不確定這些解析器是否可以直接使用,但通常情況下,您可以通過將解析器與允許注入剩餘物的一些流相結合來實現它。

例如,使用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,然後結合導管而不是解析器。

1

我認爲最簡單的方法來存檔這是建立一個多層次的分析器。想想一個詞法分析器+解析器組合。這是解決這個問題的一個乾淨方法。

你必須分開這兩種解析。搜索和替換解析轉到第一個解析器,而構建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")

可能的變型:

  • 創建類和實例用於組合包裹解析器階段。 (可能攜帶解析器的狀態。)
  • 創建的中間表示,令牌
1

流這很容易在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