2012-07-17 69 views
6

我試圖用Parsec在Haskell中編寫解析器。目前,我有一個程序,可以解析Haskell Parsec遇到的解析器[...]

test x [1,2,3] end 

,這是否給出如下

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

其中commaSep被定義爲

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

現在的代碼是對我有某種方式解析類似的說法,具體如下:

test x [1...3] end 

作爲Haskell和Parsec的新手,我確信有一些簡單的方法可以做到這一點,但我並不知道。任何幫助,將不勝感激。

再次感謝。

+0

應該週期數是恆定的還是可變的?數字和時段之間以及時段之間是否允許有空格?順便說一句,你的第一個解析器匹配'test x [1,2,3] end';也許這不是你想要的。 – dflemstr 2012-07-17 15:29:53

+0

週期數應該是恆定的,即對於任何情況,[1 ... 3]應該包含正好3個週期。諸如[1 ... 3]之間的空格應該被忽略。希望能夠澄清一下我之後的情況。 – 2012-07-17 15:32:56

回答

14

我將使用Control.Applicative的一些功能,如(*>)。如果您想避免Parsec的monadic接口並偏好應用接口,這些函數很有用,因爲在我看來解析器變得更容易閱讀。

如果您不熟悉基本的應用功能,請留下評論,我會解釋它們。如果你不確定,你可以在Hoogle上查找它們。


正如我理解你的問題,你要對一些數據結構這樣的解析器:

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

解析器可以解析這樣的數據結構是這樣的(我不是編譯的代碼,但它應該工作):

-- 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

非常感謝你,這正是我所需要的。再次感謝! – 2012-07-17 15:58:05

+1

@VincentRusso它是'fmap'的同義詞。 – phg 2012-07-17 15:59:02

+0

好吧,我仍然試圖正確的最後一件事。我可以只是做一些像 l - 嘗試(sepBy自然的逗號表示<|>自然符號「...」自然); 只是,我在這裏的實現不起作用,是否有類似的東西我可以做?你的例子很好,但解析器當前實現的方式似乎與上面的例子不太一樣。再次感謝您的幫助。 – 2012-07-17 18:00:14