2012-07-17 10 views
6

Tôi đang cố viết một trình phân tích cú pháp trong Haskell bằng Parsec. Hiện nay tôi có một chương trình có thể phân tíchTrình phân tích cú pháp phân tích cú pháp Haskell để gặp phải [...]

test x [1,2,3] end 

Các mã mà thực hiện điều này được đưa ra như sau

testParser = do { 
    reserved "test"; 
    v <- identifier; 
    symbol "["; 
    l <- sepBy natural commaSep; 
    symbol "]"; 
    p <- pParser; 
    return $ Test v (List l) p 
} <?> "end" 

nơi commaSep được định nghĩa là

commaSep  = skipMany1 (space <|> char ',') 

Bây giờ là có một cách nào đó đối với tôi để phân tích một tuyên bố tương tự, cụ thể:

test x [1...3] end 

Làm quen với Haskell và Parsec cho vấn đề đó, tôi chắc chắn có một số cách ngắn gọn để làm điều này mà tôi không biết. Bất kỳ trợ giúp sẽ được đánh giá cao.

Xin cảm ơn một lần nữa.

+0

Số kỳ có thể là hằng số hay biến không? Khoảng trống có được phép giữa các số và dấu chấm và giữa các dấu chấm không? Nhân tiện, trình phân tích cú pháp đầu tiên của bạn khớp với 'kiểm tra x [1,, 2, ,, 3] kết thúc'; có lẽ đó không phải là những gì bạn muốn. – dflemstr

+0

Số lượng dấu chấm phải không đổi, tức là [1 ... 3] phải bao gồm chính xác 3 dấu chấm cho mọi trường hợp. Khoảng trắng ở giữa chẳng hạn như [1 ... 3] sẽ bị bỏ qua. Hy vọng rằng làm rõ những gì tôi đang sau một chút. –

Trả lời

14

Tôi sẽ sử dụng một số chức năng từ Control.Applicative như (*>). Các hàm này rất hữu ích nếu bạn muốn tránh giao diện đơn thuần của Parsec và thích giao diện ứng dụng hơn, bởi vì các trình phân tích cú pháp trở nên dễ đọc theo cách đó theo ý kiến ​​của tôi.

Nếu bạn không quen với các chức năng cơ bản, hãy để lại nhận xét và tôi sẽ giải thích chúng. Bạn có thể tìm kiếm chúng trên Hoogle nếu bạn không chắc chắn.


Như tôi đã hiểu vấn đề của bạn, bạn muốn có một phân tích cú pháp cho một số cấu trúc dữ liệu như thế này:

data Test = Test String Numbers 
data Numbers = List [Int] | Range Int Int 

Một phân tích cú pháp có thể phân tích một cấu trúc dữ liệu như vậy sẽ giống như thế này (tôi đã không biên soạn mã, nhưng nó sẽ hoạt động):

-- parses "test <identifier> [<numbers>] end" 
testParser :: Parser Test 
testParser = 
    Test <$> reserved "test" *> identifier 
     <*> symbol "[" *> numbersParser <* symbol "]" 
     <* reserved "end" 
     <?> "test" 

numbersParser :: Parser Numbers 
numbersParser = try listParser <|> rangeParser 

-- parses "<natural>, <natural>, <natural>" etc 
listParser :: Parser Numbers 
listParser = 
    List <$> sepBy natural (symbol ",") 
     <?> "list" 

-- parses "<natural> ... <natural>" 
rangeParser :: Parser Numbers 
rangeParser = 
    Range <$> natural <* symbol "..." 
     <*> natural 
     <?> "range" 
+0

Ah cảm ơn bạn rất nhiều, đó là chính xác những gì tôi cần. Cảm ơn một lần nữa! –

+1

@VincentRusso nó là một từ đồng nghĩa cho 'fmap'. – phg

+0

Được rồi, một điều cuối cùng tôi vẫn đang cố gắng làm đúng. Tôi có thể làm điều gì đó giống như l <- try (sepBy dấu phẩy tự nhiênSep <|> biểu tượng tự nhiên "..." tự nhiên); Chỉ, triển khai của tôi ở đây không hoạt động, có điều gì đó tương tự mà tôi có thể làm không? Ví dụ của bạn là tuyệt vời, nhưng cách trình phân tích cú pháp hiện đang được triển khai dường như không chơi độc đáo như vậy với ví dụ trên. Một lần nữa cám ơn vì sự giúp đỡ của bạn. –