2016-11-13 23 views
3

我想使用Megaparsec解析Haskell中類似於此的文本。使用Megaparsec解析塊註釋使用開始和結束符號

# START SKIP 
def foo(a,b): 
    c = 2*a # Foo 
    return a + b 
# END SKIP 

,其中# START SKIP# END SKIP標記文本解析的塊的開始和結束。

skipBlockComment相比,我想讓解析器返回開始標記和結束標記之間的界限。

這是我的解析器。

skip :: Parser String 
skip = s >> manyTill anyChar e 
    where s = string "# START SKIP" 
     e = string "# END SKIP" 

skip解析器按預期工作。

爲了允許的開始和結束標誌內的白色空間的可變的量,例如# START SKIP我已嘗試以下步驟:

skip' :: Parser String 
skip' = s >> manyTill anyChar e 
    where s = symbol "#" >> symbol "START" >> symbol "SKIP" 
     e = symbol "#" >> symbol "END" >> symbol "SKIP" 

使用skip'解析上述文本提供了以下錯誤。

3:15: 
unexpected 'F' 
expecting "END", space, or tab 

我想了解這個錯誤的原因以及如何修復它。

+3

問題是你的解析器有一個共同的前綴。看看['try'](https://hackage.haskell.org/package/megaparsec-5.1.1/docs/Text-Megaparsec.html#v:try)。 – Alec

回答

6

正如亞歷克已經評論的那樣,問題是e遇到'#'時,它會計爲消耗字符。 parsec及其衍生工作的方式是,只要您消費了任何字符,就會致力於該解析分支 - 即不再考慮manyTill anyChar替代方案,即使e最終在此處失敗。

您可以輕鬆地請求在try回溯雖然,通過包裝結束分隔符:

skip' :: Parser String 
skip' = s >> manyTill anyChar e 
    where s = symbol "#" >> symbol "START" >> symbol "SKIP" 
     e = try $ symbol "#" >> symbol "END" >> symbol "SKIP" 

然後,這將消耗'#'前設置了「關卡」,而當e後來失敗(在你的榜樣,在"Foo"),它就會像沒有任何字符匹配一樣。

實際上,對於skip,傳統的parsec也會給出相同的行爲。只是,因爲尋找一個字符串,只有匹配完全匹配是一個普遍的任務,megaparsec的string被實現爲try . string,即如果失敗發生在該固定字符串內,那麼它總是會回溯。

但是,複合解析器在默認情況下仍然不會回溯,就像它們在attoparsec中一樣。主要原因是,如果任何事情都可以回溯到任何一點,那麼在錯誤消息中顯示的故障點確實無法獲得明確的結果。

+0

謝謝@leftaroundabout!非常好的解釋。 –

相關問題