2012-02-04 107 views
3

在這裏,我記住可能的配置是規範樹,每個規範都有一個相應的關鍵字(字符串)和類型。事情是這樣的:使用Parsec解析配置

data Select = And | Or 
data ConfigTree = Node Select [ConfigTree] | Leaf (String, *) 

我不知道怎麼給,有沒有「類型的類型」正常寫,但沒關係,對於時刻。

現在,給定這樣一棵樹,我想構建一個解析器,它可以讀取可能的有效配置;我假設我已經有了可以解析關鍵字/類型對的子解析器。

例如,一個可能的配置樹是:

Node And [ Leaf ("width", Double) 
     , Node Or [ Leaf ("height", Double) , Leaf ("aspectratio", Double) 
     ] 

其可以指定一個矩形的大小。一種可能的配置文件會,說:

aspectratio = 2 
width = 10 

(讓我們假設一個配置文件只是一個分隔換行符的名單對,關鍵字=等等,其中胡說的東西該關鍵字可以處理相應的解析器;但它們可以以任何順序排列,只需與樹的一個可能「有效子集」匹配,其中有效子集是包含頂級節點的任何子集,其中包含它所包含的「and」節點的所有子節點,並確切地說,它包含一個「或」節點的一個孩子。)

我不知道如何開始構建這樣的解析器。任何人都可以提供一些關於如何繼續的技巧,或者將上述ConfigTree數據類型完全重構爲更適合解析的方法?

回答

2

爲此構建解析器的問題是您的輸入格式根本不符合您的數據類型。輸入格式是一個簡單的,可輕鬆解析的鍵值對列表,而您的數據類型是一棵樹。例如。要確定And節點中的所有子樹是否有效,必須知道完整的輸入。

因此,不要直接在解析器中驗證鍵值對的列表,而只需在之後執行。

我已經把一個小例子來說明我的意思:

data Type = TDouble | TString 
data Select = And | Or 
data ConfigTree = Node Select [ConfigTree] | Leaf (String, Type) 

-- matches a list of key-value pairs against a tree 
match :: [(String, String)] -> ConfigTree -> Bool 
match sts (Leaf (s, t)) = case filter ((== s) . fst) sts of 
          -- we don't want multiple occurences of a key 
          [(_, v)] -> if valid v t then True else False 
          _  -> False 
match sts (Node And cfgs) = and . map (match sts) $ cfgs 
-- not completely what you described, because it will match 1 or more 
match sts (Node Or cfgs) = or . map (match sts) $ cfgs 

-- validates a string against a type 
valid :: String -> Type -> Bool 
valid s TDouble = case reads s :: [(Double, String)] of 
        [(_, "")] -> True 
        _   -> False 
valid _ TString = True 

-- this is what you actually parsed 
config = [ ("aspectratio", "2") 
     , ("width", "123") 
     , ("name", "Sam") 
     ] 

-- the example tree 
cfgTree = Node And [ Leaf ("width", TDouble) 
        , Node Or [ Leaf ("height", TDouble), Leaf ("aspectratio", TDouble)] 
        ] 

我不認爲這是一個特別有用的例子,因爲它是所有檢查,如果你的配置數據是有效的,它不會提取它們,但我希望它能夠證明我的意思。

+0

非常感謝。我剛剛完成了使用這個答案來完成將輸入變爲填充配置樹的內容,如果生成的樹無效,則會發出錯誤。我還沒有將錯誤信息儘可能地提供給幫助(這是我考慮使用Parsec的原因之一),但現在看起來工作正常。謝謝! – 2012-02-05 03:56:51

+0

好的,我現在唯一真正的問題是:除了列出所有可能發揮作用的類型之外,是否有一種正確處理類型的好方法? (我意識到這不是真正的問題,對不起。) – 2012-02-05 08:26:30

+0

也許'Data.Dynamic'是你在找什麼?但我不認爲列出所有類型是一個壞主意。會有多少種不同的類型?也許3 - 詮釋,雙和字符串?順便說一句:你看看Hackage上的軟件包是否適合你的需求? – bzn 2012-02-05 09:11:00