Подтвердить что ты не робот

Можно ли повторно использовать boost:: spirit:: qi grammar в другом определении грамматики?

Можно ли повторно использовать грамматику boost::spirit:qi в другой грамматике (как правило, например)?

Например, если я определяю грамматику для разбора строки текста в структуру, содержащую уличный адрес.

   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_;
   }

Я мог бы повторно использовать эту грамматику в двух других грамматиках, например, может быть, для разбора вектора адресов, хранящихся в файле. Другое повторное использование может быть в более сложной структуре, где одно из полей - это структура адресного адреса.

  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;
  }

Вместо того, чтобы определять всю грамматику в одном месте, я собираюсь разбить ее на более мелкие блоки многократного использования, это нормально, если они находятся внутри одного заголовочного файла. Мои структуры данных несколько сложнее (пара полей внутри структуры со списком других структур и т.д.), Поэтому я не хочу помещать ее в одну грамматику.

Можно ли повторно использовать грамматику boost::spirit::qi таким образом?

EDIT: Размышляя об этом, я просто определяю qi::rule в пространстве имен и затем собираю грамматику из правил, которые мне нужны?

4b9b3361

Ответ 1

Конечно, вы можете. В вашем случае просто введите address_grammar<iter> address_; в свой код.

Позвольте мне показать вам еще один пример. Вы можете найти компилируемый код здесь: http://ideone.com/GW4jO (см. также ниже)

AFAIK, в отличие от qi:: grammar, qi:: rule трудно повторно использовать.


Полный образец

#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);
}