I am trying to write a parser for an arguments list would allow something along the lines of the following:
myFunc( arg0, arg1, namedArg0 = valueA, namedArg1 = valueB )
In the above example, I would like the first two arguments to resolve to entities of TypeA, which would then be contained by a std::vector< TypeA >. The second two arguments would resolve to TypeB, which would be contained by a std::vector< TypeB >. All TypeA arguments should come before all TypeB arguments. But I would like all to be parsed from a single comma-separated list. It should be possible to have only TypeA arguments, only TypeB arguments or a sequence of TypeA elements followed by a sequence of TypeB elements.
I'm having trouble defining the rules such that the comma separating the final TypeA argument from the first TypeB argument is not mistaken for the expectation of another TypeA argument.
My current implementation is below. Can anyone offer any suggestions as to how to approach this problem?
The key distinction here is that TypeA arguments should be a single symbol whereas TypeB arguments should take the form of: symbol = symbol.
The problem seems to be related to the fact that TypeA arguments are equivalent to the first portion of TypeB arguments, therefore making the end of the TypeA sequence unclear?
Thanks!
struct Params
{
std::vector<TypeA> a_elements;
std::vector<TypeB> b_elements;
Params(const std::vector<TypeA>& a_vec, const std::vector<TypeB>& b_vec)
: a_elements( a_vec ), b_elements( b_vec ) {}
static Params create(const std::vector<TypeA>& a_vec, const std::vector<TypeB>& b_vec)
{
return Params( a_vec, b_vec );
}
};
struct ParamsParser : qi::grammar<Iterator, Params(), Skipper>
{
qi::rule<Iterator, Params(), Skipper> start_rule;
qi::rule<Iterator, std::vector<TypeA>(), Skipper> type_a_vec_opt_rule;
qi::rule<Iterator, std::vector<TypeB>(), Skipper> type_b_vec_opt_rule;
qi::rule<Iterator, std::vector<TypeA>(), Skipper> type_a_vec_rule;
qi::rule<Iterator, std::vector<TypeB>(), Skipper> type_b_vec_rule;
qi::rule<Iterator, TypeA(), Skipper> type_a_rule;
qi::rule<Iterator, TypeB(), Skipper> type_b_rule;
qi::rule<Iterator, std::string(), Skipper> symbol_rule;
ParamsParser() : ParamsParser::base_type( start_rule, "params_parser" )
{
start_rule =
// version 1:
( ( '(' >> type_a_vec_rule >> ',' >> type_b_vec_rule >> ')' )
[ qi::_val = boost::phoenix::bind( Params::create, qi::_1, qi::_2 ) ] )
// version 2:
| ( ( '(' >> type_a_vec_opt_rule >> ')' )
[ qi::_val = boost::phoenix::bind( Params::create, qi::_1, std::vector<TypeB>() ) ] )
// version 3:
| ( ( '(' >> type_b_vec_opt_rule >> ')' )
[ qi::_val = boost::phoenix::bind( Params::create, std::vector<TypeA>(), qi::_1 ) ] )
;
type_a_vec_opt_rule = -type_a_vec_rule;
type_b_vec_opt_rule = -type_b_vec_rule;
type_a_vec_rule = ( type_a_rule % ',' );
type_b_vec_rule = ( type_b_rule % ',' );
type_a_rule = ( symbol_rule );
type_b_rule = ( symbol_rule >> '=' >> symbol_rule );
symbol_rule = qi::char_( "a-zA-Z_" ) >> *qi::char_( "a-zA-Z_0-9" );
}
};