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())<<"!
";
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 << "
parsing 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 << "
parsing string:" << *it << std::endl;
parse_line( *it,false );
}
return 0;
}
See Question&Answers more detail:os