gpt4 book ai didi

c++ - boost::spirit::qi 排列解析器和综合属性

转载 作者:搜寻专家 更新时间:2023-10-31 01:49:50 25 4
gpt4 key购买 nike

我正在尝试将一个简单的命令行解析器与没有语义操作的 SPIRIT 放在一起。我正在使用 BOOST 1.52,但我想避免使用 C++11 功能。语法具有以下句法:

[-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 >

由于属性传播在 spirit 上的工作方式,这就是正在发生的事情:

整体tuple<size_t,bool,size_t>被分配给你的 num1(忽略 bool 和第二个 size_t),在那个 spirit 试图将第一个字符串分配给你的 bool 之后,导致你有错误。

我认为解决此问题的最简洁方法是创建一个自定义结构来保存反射(reflect)规则结构的结果。

#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 .

PS:您不能直接分配给用 auto 声明的规则在不使用 boost::proto::deep_copy 的情况下嵌入文字(例如字符串或数字);

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_);

关于c++ - boost::spirit::qi 排列解析器和综合属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15998059/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com