2012-02-04 54 views
3

我有一个由混合变量($(name))和变量值对($(name:value))组成的简单文法。我有一个手工编码的递归解析器,但有兴趣将它用作学习Spirit的练习,最终(/很快)我将需要它来使用更复杂的语法。使用Boost.Spirit解析混合值和键值对

总之,一套我与(简化从完整的语法)工作可能的形式是:

$(variable)  // Uses simple look-up, recursion and inline replace 
$(name:value) // Inserts a new variable into the local lookup table 

我现在的规则是这样:

typedef std::map<std::string, std::string> dictionary; 

template <typename Iterator> 
bool parse_vars(Iterator first, Iterator last, dictionary & vars, std::string & output) 
{ 
    using qi::phrase_parse; 
    using qi::_1; 
    using ascii::char_; 
    using ascii::string; 
    using ascii::space; 
    using phoenix::insert; 

    dictionary statevars; 

    typedef qi::rule<Iterator, std::string()> string_rule; 
    typedef qi::rule<Iterator, std::pair<std::string, std::string>()> pair_rule; 

    string_rule state = string >> ':' >> string; // Error 3 
    pair_rule variable = 
    (
     char_('$') >> '(' >> 
     (
      state[insert(phoenix::ref(statevars), _1)] | 
      string[output += vars[_1]] // Error 1, will eventually need to recurse 
     ) >> ')' 
    ); // Error 2 

    bool result = phrase_parse 
    (
     first, last, 
     (
      variable % ',' 
     ), 
     space 
    ); 

    return r; 
} 

如果:这不是什么很明显,我不知道Spirit是如何工作的,而且文档除了实际的解释之外都有其他的东西,所以这大概需要一个小时的时间。

零件在可变规则我特别问题是领先的char_('$'),但除去这会导致移位运算错误(编译器解释'$' >> '('作为右移位)。

编译时,我得到有关状态规则,特别是创造了对错误,并查找:

  1. 错误C2679:二进制“[”:没有操作员发现这需要右手类型'const boost :: spirit :: _ 1_type'的操作数(或者没有可接受的转换)
  2. 错误C2512:'boost :: spirit :: qi :: rule :: rule':没有适当的默认构造函数可用

更改查找(vars[_1])以简单的+=给出:

。错误C2665:“的boost ::精神:: char_class ::分类::是”:没有15个重载可以转换所有的参数类型

错误1似乎涉及到的类型(属性?)的_1占位符,但应该是一个字符串,并且在用于打印或连接到输出字符串时是。 2似乎引起的噪音1.

错误3,向下挖掘模板的误差的叠层,似乎涉及不能够转动状态规则成一对,这似乎奇数,因为它几乎完全匹配其中一条规则从this example

如何修改变量规则以正确处理两个输入表单?

回答

2

有几件事情需要注意:

  1. 适应std::pair(这样你就可以用地图中使用它),你应该包括(至少)

    #include <boost/fusion/adapted/std_pair.hpp> 
    
  2. 它看起来像你正试图创建一个符号表。你可以使用qi::symbols

  3. 避免混合输出生成与分析,过度

我没有“固定”所有上述(由于缺乏上下文的),但我这事情复杂化我乐意帮助解决由此产生的任何其他问题。

这里是一个固定的代码版本,保持非常接近OP。 编辑现在也已经测试过,输出如下:

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/fusion/adapted/std_pair.hpp> 
#include <map> 

namespace qi = boost::spirit::qi; 
namespace phx = boost::phoenix; 

typedef std::map<std::string, std::string> dictionary; 

template <typename Iterator, typename Skipper = qi::space_type> 
    struct parser : qi::grammar<Iterator, Skipper> 
{ 
    parser(dictionary& statevars, std::string& output) : parser::base_type(start) 
    { 
     using namespace qi; 
     using phx::insert; 

     with_initializer = +~char_(":)") >> ':' >> *~char_(")"); 

     simple   = +~char_(")"); 

     variable   = 
      "$(" >> (
        with_initializer [ insert(phx::ref(statevars), qi::_1) ] 
       | simple   [ phx::ref(output) += phx::ref(statevars)[_1] ] 
      ) >> ')'; 

     start = variable % ','; 

     BOOST_SPIRIT_DEBUG_NODE(start); 
     BOOST_SPIRIT_DEBUG_NODE(variable); 
     BOOST_SPIRIT_DEBUG_NODE(simple); 
     BOOST_SPIRIT_DEBUG_NODE(with_initializer); 
    } 

    private: 
    qi::rule<Iterator, std::pair<std::string, std::string>(), Skipper> with_initializer; 
    qi::rule<Iterator, std::string(), Skipper> simple; 
    qi::rule<Iterator, Skipper> variable; 
    qi::rule<Iterator, Skipper> start; 
}; 

template <typename Iterator> 
bool parse_vars(Iterator &first, Iterator last, dictionary & vars, std::string & output) 
{ 
    parser<Iterator> p(vars, output); 
    return qi::phrase_parse(first, last, p, qi::space); 
} 

int main() 
{ 
    const std::string input = "$(name:default),$(var),$(name)"; 
    std::string::const_iterator f(input.begin()); 
    std::string::const_iterator l(input.end()); 

    std::string output; 
    dictionary table; 

    if (!parse_vars(f,l,table,output)) 
     std::cerr << "oops\n"; 
    if (f!=l) 
     std::cerr << "Unparsed: '" << std::string(f,l) << "'\n"; 
    std::cout << "Output: '" << output << "'\n"; 
} 

输出:

Output: 'default' 
+0

@peachykeen:我已经修复了我的代码示例(我一直在用我的鼻子阅读,因为我完全错过了'parse_vars' _template function_甚至没有实例化的事实:)现在它运行并且测试对我来说确定。 – sehe 2012-02-05 16:48:15

+0

我打算说,我试过了,它给了类似的错误;将在今天晚些时候再次测试,并让你知道发生了什么。 :) – ssube 2012-02-07 14:23:09

+0

对于子集文法,更新实际上工作得很好。现在我必须补充其余的... – ssube 2012-02-09 00:17:03

-2

你必须有char _('$'),否则>>两边都是'char' - 你需要至少有一种精神类型来获得重载操作符>>。

您可能还需要使用phoenix中的_1。

也看看: http://boost-spirit.com/home/articles/qi-example/parsing-a-list-of-key-value-pairs-using-spirit-qi/

+0

这是不好的建议的事实,不需要在非技术位? – sehe 2012-02-05 13:11:41

+0

第一点很明显,问题是'char _('$')'是否是那里正确的精神构造。其余部分是无关紧要的,尽管为复杂文法手动编写解析器并不是一个好的或可行的想法。 – ssube 2012-02-05 16:06:54

+0

我已经删除了可能回答的争议部分。是的,char _('$')是我的答案所暗示的正确结构。不是手动解析键值对列表特别困难。 – Pete 2013-07-25 11:37:39