Boost::spirit::qi排列解析器和合成属性
boost::spirit::qi permutation parser and synthesized attributes
我正试图将一个简单的命令行解析器与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())<<"!nn";
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(忽略bool和第二个size_t),之后spirit试图将第一个字符串分配给bool,导致您遇到的错误。
我认为解决这个问题最干净的方法是创建一个自定义结构来保存反映规则结构的结果。
#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())<<"!nn";
}
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;
}
运行在LWS上。
PS:不使用boost::proto::deep_copy;
你不能直接赋值给用auto
声明的有文字嵌入的规则(例如字符串或数字)auto trule = boost::proto::deep_copy(qi::lit( "-p" ) >> qi::int_);
有一个名为BOOstrongPIRIT_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_);
相关文章:
- boost::spirit指针属性是用nullptr初始化的吗?
- 在 Spirit X3 中使用布尔属性而不是可选属性
- boost :: Spirit :: Karma语法:逗号从结构上划定了带有选件属性的输出
- 使用 Spirit 将 std::vector<std::vector<double> 解析为结构属性
- boost :: spirit :: x3中的connathesting std ::对属性属性
- boost :: Spirit属性分配:struct is_nullary:基本类型无法成为结构或类型
- 使用spirit::qi时如何忽略来自spirit::lex的令牌属性
- Boost Spirit电子邮件地址解析器属性生成
- 如何使用 boost::tuple 作为 boost::spirit 规则中的属性
- spirit::qi :将继承的属性引用传递给 phoenix::function
- Boost的属性.Spirit语法:Boost::variant的std:vector错误
- 使用 boost::spirit 解析二进制文件时更改属性类型
- boost::spirit::qi具有相同的简单自适应结构属性的规则会导致编译错误
- 将boost::spirit符号表作为继承属性传递到语法中
- Boost::spirit::qi排列解析器和合成属性
- 用不同的符号表重新计算Boost Spirit解析属性的最有效方法是什么?
- Boost spirit解析器属性类型不工作
- 如何将多态属性与boost::spirit::qi解析器一起使用
- 如何将 boost::spirit::qi::lexeme 的属性转换为 std::string?
- Spirit X3,语义作用使编译失败:属性没有预期的大小