Starting from the Employee - Parsing into structs example:
template <typename Iterator>
struct employee_parser : qi::grammar<Iterator, employee(), ascii::space_type>
{
employee_parser() : employee_parser::base_type(start)
{
using qi::int_;
using qi::lit;
using qi::double_;
using qi::lexeme;
using ascii::char_;
quoted_string %= lexeme['"' >> +(char_ - '"') >> '"'];
start %=
lit("employee")
>> '{'
>> int_ >> ','
>> quoted_string >> ','
>> quoted_string >> ','
>> double_
>> '}'
;
}
qi::rule<Iterator, std::string(), ascii::space_type> quoted_string;
qi::rule<Iterator, employee(), ascii::space_type> start;
};
suppose I wanted to replace quoted_string
with a rule that matches any string stored in a given container.
For example, if I have a container such as:
std::array<std::string, 4> match_list =
{ "string0", "string1", "string2", "string3" };
and I want the parser to only match the input against one of the values in the array (the container doesn't have to be an array).
I'm sure this is simple, but the Spirit help pages don't seem to address this.
It is simple: https://www.boost.org/doc/libs/1_67_0/libs/spirit/doc/html/spirit/qi/reference/string/symbols.html
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
struct employee {
int id;
std::string sym;
std::string name;
double value;
};
BOOST_FUSION_ADAPT_STRUCT(employee, id, sym, name, value)
template <typename Iterator, typename Skipper = qi::space_type>
struct employee_parser : qi::grammar<Iterator, employee(), Skipper>
{
employee_parser() : employee_parser::base_type(start)
{
using namespace qi;
quoted_string = lexeme['"' >> +(char_ - '"') >> '"'];
symbol_.add
("string0")
("string1")
("string2")
("string3")
;
start =
lit("employee")
>> '{'
>> int_ >> ','
>> symbol_ >> ','
>> quoted_string >> ','
>> double_
>> '}'
;
}
qi::rule<Iterator, std::string(), Skipper> quoted_string;
qi::rule<Iterator, employee(), Skipper> start;
qi::symbols<char, std::string> symbol_;
};
int main() {
std::string const input = "employee { 42, string3, \"more names or stuff\", 6.7 }";
using It = std::string::const_iterator;
It f = input.begin(), l = input.end();
employee_parser<It> p;
employee e;
if (phrase_parse(f, l, p, qi::space, e)) {
using boost::fusion::operator<<;
std::cout << boost::fusion::tuple_delimiter(';');
std::cout << "Parsed: " << e << "\n";
} else {
std::cout << "Parse failed\n";
}
if (f!=l)
std::cout << "Remaining input: '" << std::string(f,l) << "'\n";
}
Prints
Parsed: (42;;more names or stuff;6.7)
To actually include values:
symbol_.add
("string0", "STRING0")
("string1", "STRING1")
("string2", "STRING2")
("string3", "STRING3")
;
Prints Live On Coliru
Parsed: (42;STRING3;more names or stuff;6.7)
Or you can use another type altogether:
symbol_.add
("string0", 0)
("string1", 1)
("string2", 2)
("string3", 3)
;
With
symbol_.add
("string0", 0)
("string1", 1)
("string2", 2)
("string3", 3)
;
Which prints Live On Coliru
Parsed: (42;3;more names or stuff;6.7)
Finally, you might use raw[]
instead to "transduce" the input sequence, for example combined with qi::no_space[]
: Live On Coliru
>> raw[no_case[symbol_]] >> ','
Prints
Parsed: (42;sTrInG3;more names or stuff;6.7)