2011-01-23 62 views
2

下面是一个示例代码Plus操作如预期

#include <boost/config/warning_disable.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix_operator.hpp> 

#include <iostream> 
#include <string> 

namespace qi = boost::spirit::qi; 

    template <typename Iterator> 
    struct input : qi::grammar<Iterator, unsigned()> 
    { 
     input() : input::base_type(start) 
     { 
      using qi::lit; 
      using qi::double_; 

      start = lit("ADD") 
          >> +(
            +lit(" ") 
            >> double_ 
            >> +lit(" ") 
            >> double_ 
           ); 
     } 

     qi::rule<Iterator, unsigned()> start; 
    }; 

int main() 
{ 

    input<std::string::const_iterator> input_parser; // Our grammar 
    std::string str = "ADD 1132.324 2342.234"; 
    unsigned result; 

    std::string::const_iterator iter = str.begin(); 
    std::string::const_iterator end = str.end(); 

    bool r = qi::parse(iter, end, input_parser, result); 

} 

我收到以下错误不起作用。

/usr/local/include/boost/spirit/home/qi/nonterminal/rule.hpp:201: instantiated from ‘boost::spirit::qi::rule& boost::spirit::qi::rule::operator=(const Expr&) [with Expr = boost::proto::exprns_::expr&, const boost::proto::exprns_::expr&>, 1l>&, const boost::spirit::terminal&>, 2l>&, const boost::proto::exprns_::expr&>, 1l>&>, 2l>&, const boost::spirit::terminal&>, 2l>&>, 1l>&>, 2l>, Iterator = __gnu_cxx::__normal_iterator, std::allocator > >, T1 = unsigned int()(), T2 = boost::fusion::unused_type, T3 = boost::fusion::unused_type, T4 = boost::fusion::unused_type]’ mini.c++:34: instantiated from ‘input::input() [with Iterator = __gnu_cxx::__normal_iterator, std::allocator > >]’ mini.c++:49: instantiated from here /usr/local/include/boost/spirit/home/qi/operator/plus.hpp:62: error: no type named ‘type’ in ‘struct boost::spirit::traits::container_valueâ€

怪异的部分是,如果我使用减号( - )操作即

start = lit("ADD") 
          >> -(
            +lit(" ") 
            >> double_ 
            >> +lit(" ") 
            >> double_ 
           ); 

...它编译完全没有问题!

在gcc上编译4.3.4。

回答

2

您的启动规则公开的属性为unsigned,而plus-parser公开容纳包装元素属性的容器类型。下面是从docs属性传播规则:

a: A --> +a: vector<A> 

(即,如果解析器a暴露A类型的属性,解析器+a将暴露(标准)容器保持的A情况下,例如std::vector<A>)。

在你的情况下,嵌入式解析器公开double的。出于这个原因,你需要为预期改变才能起作用代码:

template <typename Iterator> 
struct input : qi::grammar<Iterator, std::vector<double>()> 
{ 
    input() : input::base_type(start) 
    { 
     using qi::lit; 
     using qi::double_; 
     start = lit("ADD") >> +(+lit(" ") >> double_ >> +lit(" ") >> double_); 
    } 

    qi::rule<Iterator, std::vector<double>()> start; 
}; 

int main() 
{ 
    input<std::string::const_iterator> input_parser; // Our grammar 
    std::string str = "ADD 1132.324 2342.234"; 

    std::vector<double> result; 
    std::string::const_iterator iter = str.begin(); 
    std::string::const_iterator end = str.end(); 
    bool r = qi::parse(iter, end, input_parser, result); 
} 

但不幸的是,事情并不像看起来那么容易。当前版本的Spirit有一个阻止代码工作的错误(即使即将发布的Boost V1.46仍然会有这个错误,但它在SVN中继中是固定的)。问题是,plus并没有将嵌入式元素“扁平化”到提供的容器中,从而导致每次由上面的代码解析的double都会丢失。

的解决方法是避免序列露出里面加多于一个属性:

start = lit("ADD") >> +(+lit(" ") >> double_); 

验证之后该解析的元素的数目是偶数。

附注:您似乎想跳过输入中元素之间的空白。这可以通过使用跳过解析器更容易实现:

template <typename Iterator> 
struct input : qi::grammar<Iterator, std::vector<double>(), qi::space_type> 
{ 
    input() : input::base_type(start) 
    { 
     using qi::lit; 
     using qi::double_; 
     start = lit("ADD") >> +double_; 
    } 

    qi::rule<Iterator, std::vector<double>(), qi::space_type> start; 
}; 

int main() 
{ 
    input<std::string::const_iterator> input_parser; // Our grammar 
    std::string str = "ADD 1132.324 2342.234"; 

    std::vector<double> result; 
    std::string::const_iterator iter = str.begin(); 
    std::string::const_iterator end = str.end(); 
    bool r = qi::phrase_parse(iter, end, input_parser, qi::space, result); 
} 

它同时规避了上述问题。

+0

谢谢。你的解决方案运行良好,我现在看到我做错了什么。我的实际语法是空格分隔,所以我不能跳过空格。 – 2011-01-24 07:47:58