boost :: spirit :: qi permutation解析器和合成属性

问题描述:

我正在尝试将一个简单的命令行解析器与SPIRIT放在一起,而没有语义操作。 我正在使用BOOST 1.52,但我想避免使用C++ 11功能。语法的语法如下:boost :: spirit :: qi permutation解析器和合成属性

[-p num1] [-j] [--jobs num2] str1 str2 

可选参数的顺序可以是任意的。我成功解析了可选参数。一旦我添加了额外的强制性两个字符串分析器,就会中断。当我尝试明确写下“rstart”属性并避免使用“auto”进行类型扣除时,它甚至保持不变。任何帮助或建议非常感谢!

#include <iostream> 
#include <string> 
#include <vector> 
#include <iterator> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/optional.hpp> 
#include <boost/fusion/include/boost_tuple.hpp> 

bool parse_line(const std::string&str,bool useStart1) 
{ 
    bool rc=false; 
    namespace qi = boost::spirit::qi; 

    using boost::spirit::ascii::space_type; 
    using boost::spirit::ascii::space; 
    using boost::spirit::ascii::char_; 

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

    std::size_t num1 =88; 
    bool  bool1 =false; 
    std::size_t num2 =88; 
    std::string str1,str2; 

    qi::rule< std::string::const_iterator,std::string() > rstring=+~space; 
    qi::rule< std::string::const_iterator,std::size_t() ,space_type > 
     rOption1=qi::lit("-p") >> qi::int_; 
    qi::rule< std::string::const_iterator,bool()  ,space_type > 
     rOption2=qi::lit("-j") >> qi::attr(true); 
    qi::rule< std::string::const_iterator,std::size_t() ,space_type > 
     rOption3=qi::lit("--jobs") >> qi::int_; 

#if defined(AAA) 
    qi::rule< std::string::const_iterator, 
       boost::spirit::ascii::space_type, 
       boost::tuple< boost::optional<std::size_t>, 
           boost::optional<bool>, 
           boost::optional<std::size_t > 
       > 
      > 
#endif 

    auto rstart1 = (rOption1^rOption2^rOption3) ; 
    auto rstart2 = (rOption1^rOption2^rOption3) >> rstring >> rstring; 

    if(useStart1) 
     qi::phrase_parse(iter,str.end(), 
      (qi::lit("-p") >> qi::int_)^
      (qi::lit("-j") >> qi::attr(true))^
      (qi::lit("--jobs") >> qi::int_),space,num1,bool1,num2); 
    else 
    { 
    // qi::phrase_parse(
    //  iter,str.end(),rstart2,space,num1,bool1,num2,str1,str2); 
    } 

    if(iter==str.begin()) 
     iter=str.begin(); //NOP 
    else 
    if(iter!=str.end()) 
     std::cerr<<"syntax error: "<<std::string(iter,str.end())<<"!\n\n"; 
    else 
     rc=true; 

    std::cout << "num1:" << num1 << std::endl; 
    std::cout << "bool1:"<< bool1 << std::endl; 
    std::cout << "num2:" << num2 << std::endl; 
    std::cout << "str1:" << str1 << std::endl; 
    std::cout << "str2:" << str2 << std::endl; 

    return rc; 
} 

int main(int argc,char**argv) 
{ 
    std::vector<std::string> testData1; 
    testData1.push_back("-p 100 -j"); 
    testData1.push_back("-j -p 100 --jobs 16"); 
    testData1.push_back("--jobs 16 -j -p 100"); 

    for(std::vector<std::string>::const_iterator it=testData1.begin(); 
     it!=testData1.end(); ++it) 
    { 
     std::cout << "\nparsing string:" << *it << std::endl; 
     parse_line(*it,true); 
    } 

    std::vector<std::string> testData2; 
    testData2.push_back("-p 100 -j ifile ofile"); 
    testData2.push_back("-j -p 100 --jobs 16 ifile ofile"); 
    testData2.push_back("--jobs 16 -j -p 100 ifile ofile"); 

    for(std::vector<std::string>::const_iterator it=testData2.begin(); 
     it!=testData2.end(); ++it) 
    { 
     std::cout << "\nparsing string:" << *it << std::endl; 
     parse_line(*it,false); 
    } 

    return 0; 
} 

你所面对的问题是,你的组合规则的属性基本上是:

tuple< tuple<size_t,bool,size_t>, std::string, std::string > 

并把你的变量逐个调用phrase_parse你已经基本上:

tuple< size_t, bool, size_t, std::string, std::string > 

由于属性传播在精神中的作用方式,这就是发生了什么:

整个tuple<size_t,bool,size_t>被分配给你的num1(忽略布尔和第二个size_t),之后精神试图分配第一个字符串到你的布尔,导致你有错误。

我相信最简洁的方法来解决这个问题是创建一个自定义结构来保存反映规则结构的结果。

#include <iostream> 
#include <string> 
#include <vector> 
#include <iterator> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/fusion/include/adapt_struct.hpp> 

struct optional_command_line_options 
{ 
    int num1; 
    bool bool1; 
    int num2; 
}; 

struct command_line_options 
{ 
    optional_command_line_options opt; 
    std::string str1; 
    std::string str2; 
}; 

BOOST_FUSION_ADAPT_STRUCT(
    optional_command_line_options, 
    (int, num1) 
    (bool, bool1) 
    (int, num2) 
) 

BOOST_FUSION_ADAPT_STRUCT(
    command_line_options, 
    (optional_command_line_options, opt) 
    (std::string, str1) 
    (std::string, str2) 
) 

bool parse_line(const std::string&str) 
{ 
    bool rc=false; 
    namespace qi = boost::spirit::qi; 

    using boost::spirit::ascii::space; 
    using boost::spirit::ascii::char_; 

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

    command_line_options options; 
    options.opt.num1=88; 
    options.opt.bool1=false; 
    options.opt.num2=88; 

    qi::rule< std::string::const_iterator, std::string() > rstring=+~space; 


    qi::rule<std::string::const_iterator, boost::spirit::ascii::space_type,optional_command_line_options() > trule; 
    trule= 
     (qi::lit("-p") >> qi::int_)^
     (qi::lit("-j") >> qi::attr(true))^
     (qi::lit("--jobs") >> qi::int_) 
     ; 

    qi::rule< std::string::const_iterator, boost::spirit::ascii::space_type, command_line_options() >arule; 
    arule = -trule >> rstring >> rstring; 

    bool result=qi::phrase_parse(iter,str.end(), 
           arule, 
           space, 
           options 
    ); 

    if(result && iter==str.end()) 
    { 
     std::cout << "Parse successful." << std::endl; 
     rc=true; 
    } 
    else 
    { 
     std::cerr<<"syntax error: "<<std::string(iter,str.end())<<"!\n\n"; 
    } 

    std::cout << std::boolalpha; 
    std::cout << "num1:" << options.opt.num1 << std::endl; 
    std::cout << "bool1:"<< options.opt.bool1 << std::endl; 
    std::cout << "num2:" << options.opt.num2 << std::endl; 
    std::cout << "str1:" << options.str1 << std::endl; 
    std::cout << "str2:" << options.str2 << std::endl; 

    return rc; 
} 

int main(int /*argc*/,char**/*argv*/) 
{ 
    std::vector<std::string> testData; 
    testData.push_back("-p 100 -j ifile ofile"); 
    testData.push_back("-j -p 100 --jobs 16 ifile ofile"); 
    testData.push_back("--jobs 16 -j -p 100 ifile ofile"); 
    testData.push_back("--jobs 16 -p 100 ifile ofile"); 
    testData.push_back("ifile ofile"); 

    for(std::vector<std::string>::const_iterator it=testData.begin(); 
     it!=testData.end(); ++it) 
    { 
     std::cout << "\nparsing string:" << *it << std::endl; 
     parse_line(*it); 
    } 

    return 0; 
} 

Running on LWS。注:不能使用boost :: proto :: deep_copy;你不能直接指定用auto声明的嵌入文字(例如字符串或数字)的规则。

auto trule = boost::proto::deep_copy(qi::lit("-p") >> qi::int_); 

有一个宏叫BOOST_SPIRIT_AUTO这使得它更容易使用:

#define BOOST_SPIRIT_AUTO(domain_, name, expr)         \ 
    typedef boost::proto::result_of::           \ 
     deep_copy<BOOST_TYPEOF(expr)>::type name##_expr_type;     \ 
    BOOST_SPIRIT_ASSERT_MATCH(             \ 
     boost::spirit::domain_::domain, name##_expr_type);      \ 
    BOOST_AUTO(name, boost::proto::deep_copy(expr)); 

BOOST_SPIRIT_AUTO(qi,trule,qi::lit("-p") >> qi::int_); 
+0

完美的 - 它按预期工作!非常感谢你的工作解决方案和许多有价值的评论,为我清除了一切:-) –

+0

@ user2280070当然还有+1,我的朋友:) \ [我已经[得出结论](http:// chat .stackoverflow.com/rooms/10/loungec)我不应该介意你在匿名账户下发布“无政府主义风格”。毕竟,内容很棒。但是,请问您是否认为SO不仅仅关于内容,还涉及内容评估,声誉是SO用户辨别权威答案的一种方式,在低流量标签中这个。如果我不符合要求,请随时忽略此内容。我只是想提一次,]。 – sehe