2016-01-19 20 views
9

bir` optional` combinator içindeki many` combinator: İsteğe bağlı kabul eden bir ayrıştırıcı kural (yani potansiyel olarak boşHaskell parsekten: `Ben Haskell'ın parsekten kütüphanesini kullanarak bu dilbilgisi kuralı uygulamak istiyorum

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

) dize. o acccepts dize boş değilse, o zaman ab veya c ayrıştırıcıları sıfır veya daha fazla oluşumları geçerek tüketilebilir, ancak en dış ? opsiyonel ayrıştırıcı tarafından kabul dize ayrıştırıcı a ile yahut tüketilmelidir b, ancak c. İşte bir örnek:

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 

şöyle görünebilir bir ilk girişim:

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

Ama many sadece a <|> b bırakarak her test durumda tüm 'a' 'b' ve 'c' karakteri tüketir Tüketecek karakter yok.

soru:

parsekten combinators kullanarak, myParser tanımlamak ((a | b | c)* (a | b))? doğru uygulanması nedir?

Ayrıca bu biraz farklı ifade edebiliriz
+0

Belki ayrıştırmak (a | b | c) + ve c ile biterse daha sonra reddetmek? –

cevap

4

: tek lookAhead ile yapılabilir herhangi bir simge, ardından durumunda yerini ayrıştırıcı içinde c sadece başarılı olabilir:

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

teşekkürler, bu işe yarıyor. Yarısı, 'anyToken' yüzünden çalışmamayı bekledim, sadece 'd', '\ n' olsun ya da her neyse, sadece bunu kastetmiştim. MyParser = çok (= <|> b <|> (c <* (lookAhead (bir <|> deneme b'yi deneyin) "non C jetonu")) <* eof' gibi bir şey düşünüyordum. Ancak, 'myParser' * 'inizin tanımı * çalışır. Örneğin. "Ca" ayrıştırma "ca" değerini döndürürken "cd" yi ayrıştırmaya çalışmak "beklenmedik" d "ile" a "," b "," c "veya" girişin sonu "bekleniyor. Neden "anyToken" birleştiricisi sadece 'a', 'b' veya 'c' kabul etmeye istekli? –

+1

@RobStewart: '<* eof' nedeniyle. 'myParser' tüm girdileri tüketmeyi umuyor. – Zeta

+0

Teşekkürler! Kabul edilen cevap olarak işaretlendi. –

İlgili konular