Is it possible to reuse boost::spirit:qi
grammar in another grammar (as a rule for example)?
For example if I define a grammar to parse line of text into a structure holding street address.
template< typename iter >
struct address_grammar : qi::grammar< iter, address() >
{
...
qi::rule< iter, std::string() > street_name;
qi::rule< iter, std::string() > street_number;
qi::rule< iter, address() > address_;
}
I might want to reuse that grammar in two other grammars, for example one might be for parsing of a vector of addresses stored in a file. Another re-use might be in more complex structure where one of the fields is this street address structure.
template< typename iter >
struct company_grammar : qi::grammar< iter, company() >
{
...
qi::rule< iter, std::string() > comp_name;
// can I reuse the address grammar somehow here ???
qi::rule< iter, company() > company;
}
Instead of defining the whole grammar in one place I'm thinking to split it into smaller reusable blocks, it is fine if they are inside one header file. My data structures are slightly more complex (couple of fields inside struct with a list of other structures and so on) so I don't want to put it into one grammar.
Is it possible to reuse boost::spirit::qi
grammar in this way?
EDIT: Thinking about it, do I just define qi::rule
s in a namespace and then put together a grammar from the rules that I need?
Of course you can. In your case, just put address_grammar<iter> address_;
in your code.
Let me show you another example. You can find a compilable code here: http://ideone.com/GW4jO (see also below)
AFAIK, unlike qi::grammar, qi::rule is hard to reuse.
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
struct Date {
int year, month, day;
};
struct Time {
int hour, minute, second;
};
BOOST_FUSION_ADAPT_STRUCT(
Date,
(int, year)
(int, month)
(int, day)
)
BOOST_FUSION_ADAPT_STRUCT(
Time,
(int, hour)
(int, minute)
(int, second)
)
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
typedef std::string::const_iterator Iterator;
class DateParser:
public qi::grammar < Iterator, Date() > {
qi::rule < Iterator, Date() > main;
public:
DateParser(): base_type(main) {
main %= qi::int_ >> '-' >> // Year
qi::int_ >> '-' >> // Month
qi::int_; // Day
}
};
class TimeParser:
public qi::grammar < Iterator, Time() > {
qi::rule < Iterator, Time() > main;
public:
TimeParser(): base_type(main) {
main %= qi::int_ >> ':' >> // Hour
qi::int_ >> ':' >> // Minute
qi::int_; // Second
}
};
class DateTimeParser:
public qi::grammar < Iterator, boost::variant<Date, Time>() > {
qi::rule < Iterator, boost::variant<Date, Time>()> main;
public:
DateTimeParser(): base_type(main) {
main %= date_parser | time_parser;
}
DateParser date_parser;
TimeParser time_parser;
};
#include<iostream>
#include<cstdio>
struct Printer : public boost::static_visitor<> {
void operator()(Date a) const {
printf("Year: %d, Month: %d, Day: %d\n", a.year, a.month, a.day);
}
void operator()(Time a) const {
printf("Hour: %d, Minute: %d, Second: %d\n", a.hour, a.minute, a.second);
}
};
int main() {
std::string s;
std::getline(std::cin, s);
Iterator beg = s.begin(), end = s.end();
boost::variant<Date, Time> ret;
phrase_parse(beg, end, DateTimeParser(), ascii::space, ret);
if (beg != end)
puts("Parse failed.");
else
boost::apply_visitor(Printer(), ret);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With