提振精神:: ::气置换分析器和合成属性 [英] boost::spirit::qi permutation parser and synthesized attributes
问题描述
我想放在一起用精神简单的命令行分析器没有语义动作。
我使用BOOST 1.52,但我想避免使用C ++ 11的特性。语法的语法如下:
[ - P NUM1] [-j] [--jobs NUM2] STR1 STR2
可选参数可以是任何顺序。我成功地解析只可选参数。一旦我添加了额外的强制性两个字符串解析器它打破。当我尝试写下RSTART明确属性,并使用自动避类型推演它打破了平衡。任何帮助或建议非常AP preciated!
的#include<&iostream的GT;
#包括LT&;串GT;
#包括LT&;矢量>
#包括LT&;&迭代器GT;
#包括LT&;升压/精神/有/ qi.hpp>
#包括LT&;升压/ optional.hpp>
#包括LT&;升压/融合/有/ boost_tuple.hpp>布尔parse_line(常量标准::字符串&放大器; STR,布尔useStart1)
{
布尔RC = FALSE;
命名空间补气=的boost ::精神::补气; 使用boost ::精神:: ASCII ::空间类型;
使用boost ::精神:: ASCII ::空间;
使用boost ::精神:: ASCII :: char_; 标准::字符串::为const_iterator国际热核实验堆(str.begin()); 的std ::为size_t NUM1 = 88;
布尔BOOL1 = FALSE;
的std ::为size_t NUM2 = 88;
的std ::串STR1,STR2; 齐::规则<标准::字符串::为const_iterator,标准::字符串()> RSTRING = +〜空间;
齐::规则<标准::字符串::为const_iterator,性病::为size_t(),空间类型>
rOption1 =齐亮::(-p)>>补气:: int_;
齐::规则<标准::字符串::为const_iterator,布尔(),空间类型>
rOption2 =齐亮::(-j)>>齐:: ATTR(真);
齐::规则<标准::字符串::为const_iterator,性病::为size_t(),空间类型>
rOption3 =齐亮::(--jobs)>>补气:: int_;#如果定义(AAA)
齐::规则<标准::字符串::为const_iterator,
提振精神:: :: ASCII ::空间类型,
提高::元组LT;推动::可选<的std ::为size_t>中
推动::可选<布尔>中
推动::可选<的std ::为size_t>
>
>
#万一 汽车rstart1 =(rOption1 ^ ^ rOption2 rOption3);
汽车rstart2 =(rOption1 ^ ^ rOption2 rOption3)GT;> RSTRING>> RSTRING; 如果(useStart1)
齐:: phrase_parse(ITER,str.end()
(齐亮::(-p)>>气虚:: int_)^
(齐亮::(-j)>>气虚:: ATTR(真))^
(齐亮::(--jobs)>>气虚:: int_),空间,NUM1,BOOL1,NUM2);
其他
{
//齐:: phrase_parse(
// ITER,str.end(),rstart2,空间,NUM1,BOOL1,NUM2,STR1,STR2);
} 如果(ITER == str.begin())
ITER = str.begin(); // NOP
其他
如果(ITER!= str.end())
的std :: CERR<<语法错误:!\\ n \\ n;<<的std ::字符串(ITER,str.end())<<
其他
RC = TRUE; 性病::法院LT&;< NUM1:&所述;&下; NUM1<<的std :: ENDL;
性病::法院LT&;< BOOL1:&所述;&下; BOOL1<<的std :: ENDL;
性病::法院LT&;< NUM2:&所述;&下; NUM2<<的std :: ENDL;
性病::法院LT&;< STR1:&所述;&下; STR1<<的std :: ENDL;
性病::法院LT&;< STR2:&所述;&下; STR2<<的std :: ENDL; 返回RC;
}INT主(INT ARGC,字符** argv的)
{
的std ::矢量<标准::字符串> testData1;
testData1.push_back(-p 100 -j);
testData1.push_back(-j -p 100 --jobs 16);
testData1.push_back(--jobs 16 -j -p 100); 对于(的std ::矢量<标准::字符串> ::为const_iterator吧= testData1.begin();
它= testData1.end()!;它++)
{
性病::法院LT&;< \\ nparsing字符串:<< *它<<的std :: ENDL;
parse_line(*它,真正的);
} 的std ::矢量<标准::字符串> 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); 对于(的std ::矢量<标准::字符串> ::为const_iterator吧= testData2.begin();
它= testData2.end()!;它++)
{
性病::法院LT&;< \\ nparsing字符串:<< *它<<的std :: ENDL;
parse_line(*它,FALSE);
} 返回0;
}
您所面临的问题是,合并后的规则的属性基本上是:
元组LT;元组LT;为size_t,布尔,为size_t>中的std ::字符串,性病::字符串>
和把你的变量逐一调用phrase_parse你基本上是:
元组LT;为size_t,布尔,为size_t,标准::字符串,性病::字符串>
由于方式属性传播的作品在精神上,这是发生了什么:
全元组LT;为size_t,布尔,为size_t>
分配给您的NUM1(忽略布尔和第二为size_t)后,这种精神会尝试的第一个字符串赋值给您布尔,造成你有错误。
我认为解决这个最彻底的方法是创建一个自定义的结构来保存你的结果,反映了你的规则结构。
的#include<&iostream的GT;
#包括LT&;串GT;
#包括LT&;矢量>
#包括LT&;&迭代器GT;
#包括LT&;升压/精神/有/ qi.hpp>
#包括LT&;升压/融合/有/ adapt_struct.hpp>结构optional_command_line_options
{
INT NUM1;
布尔BOOL1;
INT NUM2;
};结构command_line_options
{
optional_command_line_options选择;
标准::字符串STR1;
标准::字符串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)
(标准::字符串,STR1)
(标准::字符串,STR2)
)布尔parse_line(常量标准::字符串&安培; STR)
{
布尔RC = FALSE;
命名空间补气=的boost ::精神::补气; 使用boost ::精神:: ASCII ::空间;
使用boost ::精神:: ASCII :: char_; 标准::字符串::为const_iterator国际热核实验堆(str.begin()); command_line_options选择;
options.opt.num1 = 88;
options.opt.bool1 = FALSE;
options.opt.num2 = 88; 齐::规则<标准::字符串::为const_iterator,标准::字符串()> RSTRING = +〜空间;
齐::规则<的std ::字符串::为const_iterator,提振精神:: :: ASCII ::空间类型,optional_command_line_options()> trule;
trule =
(齐亮::(-p)>>气虚:: int_)^
(齐亮::(-j)>>气虚:: ATTR(真))^
(齐亮::(--jobs)>>气虚:: int_)
; 齐::规则<标准::字符串::为const_iterator,提振精神:: :: ASCII ::空间类型,command_line_options()> arule;
arule = -trule>> RSTRING>> RSTRING; 布尔结果=齐:: phrase_parse(ITER,str.end()
arule,
空间,
选项
); 如果(结果&安培;&安培; ITER == str.end())
{
性病::法院LT&;< 解析成功。 <<的std :: ENDL;
RC = TRUE;
}
其他
{
的std :: CERR<<语法错误:!\\ n \\ n;<<的std ::字符串(ITER,str.end())<<
} 性病::法院LT&;<的std :: boolalpha;
性病::法院LT&;< NUM1:&所述;&下; options.opt.num1<<的std :: ENDL;
性病::法院LT&;< BOOL1:&所述;&下; options.opt.bool1<<的std :: ENDL;
性病::法院LT&;< NUM2:&所述;&下; options.opt.num2<<的std :: ENDL;
性病::法院LT&;< STR1:&所述;&下; options.str1<<的std :: ENDL;
性病::法院LT&;< STR2:&所述;&下; options.str2<<的std :: ENDL; 返回RC;
}INT主(INT / * * ARGC /,焦炭** / * argv的* /)
{
的std ::矢量<标准::字符串> 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); 对于(的std ::矢量<标准::字符串> ::为const_iterator吧= testData.begin();
它= testData.end()!;它++)
{
性病::法院LT&;< \\ nparsing字符串:<< *它<<的std :: ENDL;
parse_line(*它);
} 返回0;
}
运行在LWS 。
PS:你不能直接分配与汽车
有在其中嵌入文本(字符串或例如数字),而不使用boost ::原::申报规则DEEP_COPY;
自动trule =提振::原:: DEEP_COPY(齐亮::(-p)>>气虚:: int_);
有一个宏观称为BOOST_SPIRIT_AUTO这使得它更容易使用:
的#define BOOST_SPIRIT_AUTO(domain_,名称表达式)\\
TYPEDEF提振::原:: ::的result_of \\
DEEP_COPY< BOOST_TYPEOF(表达式)> ::类型名称## _ expr_type; \\
BOOST_SPIRIT_ASSERT_MATCH(\\
提振精神:: ::域_ ::域名,域名## _ expr_type); \\
BOOST_AUTO(姓名,提振::原:: DEEP_COPY(表达式));BOOST_SPIRIT_AUTO(补气,trule,齐亮::(-p)>>气虚:: int_);
I'm trying to put together a simple command line parser with SPIRIT without semantic actions. I'm using BOOST 1.52 but I would like to avoid using C++11 features. The grammar has the following syntax:
[-p num1] [-j] [--jobs num2] str1 str2
Optional parameters can be in any order. I successfully parsed only optional parameters. Once I add the additional mandatory two string parsers it breaks. It breaks even when I try to write down the "rstart" attributes explicitly and avoid type deduction using "auto". Any help or suggestion is very appreciated!
#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;
}
The problem you are facing is that the attribute of your combined rule is basically:
tuple< tuple<size_t,bool,size_t>, std::string, std::string >
and by putting your variables one by one on the call to phrase_parse you have basically:
tuple< size_t, bool, size_t, std::string, std::string >
Because of the way attribute propagation works in spirit this is what is happening:
the whole tuple<size_t,bool,size_t>
is assigned to your num1 (ignoring the bool and second size_t), after that spirit tries to assign the first string to your bool, resulting in the error you have.
I believe the cleanest way to solve this is creating a custom struct to hold your result that reflects the structure of your rules.
#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;
}
PS: You can't assign directly to rules declared with auto
that have literals embedded in them (strings or numbers for example) without using boost::proto::deep_copy;
auto trule = boost::proto::deep_copy(qi::lit( "-p" ) >> qi::int_);
There is a macro called BOOST_SPIRIT_AUTO that makes it easier to use:
#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_);
这篇关于提振精神:: ::气置换分析器和合成属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!