2016-01-19 16 views
9

Tôi muốn thực hiện quy tắc ngữ pháp này sử dụng thư viện parsec Haskell của:Haskell parsec: `many` combinator bên trong một 'optional` combinator

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

Đó là một quy tắc phân tích cú pháp mà chấp nhận một tùy chọn (tức là có khả năng trống) chuỗi. Nếu chuỗi nó acccepts không phải là trống rỗng, sau đó nó có thể được tiêu thụ bằng cách đi qua không hay nhiều lần xuất hiện của ab hoặc c parsers, nhưng chuỗi chấp nhận bởi bên ngoài nhất ? tùy chọn phân tích cú pháp phải được tiêu thụ bằng cách phân tích cú pháp a hoặc b, nhưng không phải c. Dưới đây là một ví dụ:

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 

Một nỗ lực đầu tiên có thể trông như thế này:

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

Nhưng many chỉ tiêu thụ tất cả các 'a' 'b' và 'c nhân vật' trong mỗi trường hợp kiểm tra, rời khỏi a <|> b không có nhân vật để tiêu thụ.

Câu hỏi:

Sử dụng combinators parsec, việc thực hiện đúng ((a | b | c)* (a | b))? để xác định myParser là gì?

+0

lẽ phân tích cú pháp (a | b | c) + và từ chối nó sau nếu nó kết thúc bằng c? –

Trả lời

4

Chúng tôi cũng có thể nêu này hơi khác nhau: c trong phân tích cú pháp của bạn chỉ có thể thành công nếu nó được theo sau bởi bất kỳ dấu hiệu, có thể được thực hiện với một đơn lookAhead:

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

cảm ơn, hoạt động. Tôi đã nghĩ rằng nó không hoạt động vì 'anyToken' mà tôi đã giả định chỉ có nghĩa là, dù đó là' d ',' \ n ', hay bất kỳ thứ gì. Tôi đã suy nghĩ một cái gì đó như 'myParser = nhiều (một <|> b <|> (c <* (lookAhead (thử một <|> thử b) " non C token "))) <* eof'. Tuy nhiên, định nghĩa của bạn 'myParser' * không * hoạt động. Ví dụ. Phân tích cú pháp "ca" trả về "ca", trong khi cố gắng phân tích cú pháp "cd" không thành công với "không mong muốn" d "mong đợi" a "," b "," c "hoặc kết thúc của đầu vào". Tại sao tổ hợp của «anyToken' lại chỉ chấp nhận 'a', 'b', hay 'c'? –

+1

@RobStewart: Do '<* eof'. 'myParser' hy vọng sẽ tiêu thụ tất cả đầu vào. – Zeta

+0

cảm ơn! Đánh dấu là câu trả lời được chấp nhận. –

Các vấn đề liên quan