Можно ли повторно использовать грамматику boost :: spirit :: qi в другом определении грамматики? - PullRequest
22 голосов
/ 13 марта 2012

Можно ли повторно использовать 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 грамматику?

РЕДАКТИРОВАТЬ: Подумав об этом, я просто определить qi::rule s в пространстве имен, а затем собрать грамматику из правил, которые мне нужны?

1 Ответ

18 голосов
/ 16 марта 2012

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

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

AFAIK, в отличие от qi :: грамматики, 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);
}
...