2012-02-04 106 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