2016-11-13 6 views
3

Megaparsecを使用して、これと同様のテキストをHaskellで解析したいとします。 # START SKIP# END SKIPを解析するテキストのブロックの開始と終了をマーク開始と終了の記号を使用してMegaparsecでブロックコメントを解析する

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

、。

skipBlockCommentと比較すると、パーサーは開始マーカーと終了マーカーの間の行を返すようにします。

これは私のパーサーです。

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

skipパーサーは意図したとおりに動作します。

は、たとえば # START SKIPのために私は、次の試してみた、開始と終了のマーカー内の空白の可変量を可能にするには:上記のテキストを解析する skip'を使用し

skip' :: Parser String 
skip' = s >> manyTill anyChar e 
    where s = symbol "#" >> symbol "START" >> symbol "SKIP" 
     e = symbol "#" >> symbol "END" >> symbol "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出会い'#'として、それは消費文字としてカウントされていることです。そして、パルクとその派生物の仕組みは、あなたがどんなキャラクターを摂取してもすぐに、eが最終的にここで失敗したにもかかわらず、その代わりにmanyTill anyCharの代替案が考慮されないということです。

あなたは簡単に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")、まったく一致しなかったかのように動作します。

実際、伝統的なparsecはskipでも同様の動作をします。 が完全にと一致する場合は、文字列を検索して成功するだけなので、megaparsecのstringtry . stringのように実装されます。つまり、その固定文字列内でエラーが発生した場合は常にバックトラックします。

しかし、複合パーサーは、attoparsecのように、デフォルトでバックトラックしません。主な理由は、何らかの理由で逆戻りできるものがあれば、エラーメッセージを表示するには、実際にはの障害点を明確にすることができないということです。

+0

ありがとうございました@leftaroundabout!非常に良い説明。 –

関連する問題