2016-01-19 3 views
9

` optional`コンビネータ内部many`コンビネータ:オプションを受け入れパーサー規則は(すなわち潜在的に空であるHaskellのパーセク: `私はHaskellのパーセクライブラリ使用して、この文法規則を実装したいと思います

((a | b | c)* (a | b))? 

を)文字列。それはacccepts文字列が空でない場合、それはabまたはcパーサの0回以上の繰り返しを通過することによって消費することができますが、最も外側の?オプションのパーサによって受け入れられた文字列がパーサaするかのどちらかに消費されなければなりませんbであるが、cではない。ここでは例です:

module Main where 

import Text.Parsec 
import Text.Parsec.Text 

a,b,c :: GenParser() Char 
a = char 'a' 
b = char 'b' 
c = char 'c' 

-- ((a | b | c)* (a | b))? 
myParser = undefined 

shouldParse1,shouldParse2,shouldParse3, 
     shouldParse4,shouldFail :: Either ParseError String 
-- these should succeed 
shouldParse1 = runParser myParser() "" "" -- because ? optional 
shouldParse2 = runParser myParser() "" "b" 
shouldParse3 = runParser myParser() "" "ccccccb" 
shouldParse4 = runParser myParser() "" "aabccab" 

-- this should fail because it ends with a 'c' 
shouldFail = runParser myParser() "" "aabccac" 

main = do 
    print shouldParse1 
    print shouldParse2 
    print shouldParse3 
    print shouldParse4 
    print shouldFail 

次のようになります。最初の試み:

myParser = option "" $ do 
    str <- many (a <|> b <|> c) 
    ch <- a <|> b 
    return (str ++ [ch]) 

しかしmanyはちょうどa <|> bを残して、各テストケース内のすべての「」「B」と「C」の文字を消費消費する文字はありません。

質問:パーセクコンビネータを使用して

myParserを定義する((a | b | c)* (a | b))?の正しい実装は何ですか?

我々はまた、これはわずかに異なる述べることができる
+0

はたぶんパース(| B | C) +それがcで終わったら後で拒否しますか? –

答えて

4

:それは、単一のlookAheadで行うことができます任意のトークン、続くなら、あなたのパーサでcのみ成功することがあります。

myParser = many (a <|> b <|> (c <* (lookAhead anyToken <?> "non C token"))) <* eof 
+1

ありがとう、それは動作します。私はそれが「d」、「\ n」、または何であろうと、それを意味すると思われていた「anyToken」のために動作しないと期待していた半分でした。私は 'myParser = many(" Cトークンではない) "<|> b <|>(C <*(lookAhead try try <|>b " non C token ")))<* eof'のようなものを考えていました。しかし、あなたの 'myParser' *の定義は機能します。例えば。 "ca"を解析すると、 "cd"を解析しようとすると "a"、 "b"、 "c"、または "end of input"を予期しない "d"で失敗します。なぜa、b、またはcを受け入れるだけのanyTokenコンビネータですか? –

+1

@RobStewart: '<* eof'のため。 'myParser'は全ての入力を消費することを期待しています。 – Zeta

+0

ありがとう!承認された回答としてマークされます。 –

関連する問題