LINUX.ORG.RU

Вопросы по boost::spirit

 , , ,


0

5

Начал изучать сабж. Пару раз бросал и садился писать свой парсер, но, как ни крути, spirit получается удобнее. Только вот по нему нет нормальной документации и примеров, поэтому не остаётся ничего кроме как спросить здесь.

Первое, собственно, посоветуйте нормальных примеров вместо фуфла с офсайта, которое покрывает только самые тривиальные случаи использования.

Далее конкретные вопросы.

Есть парсер списка команд вида

FOO 1, 2, 3
BAR 1, 2, "ARG3"
BAZ 2, 0.5, "ZZZ"

парсит их в структуры вида

struct cmdfoo {
  int arg1;
  int arg2;
  int arg3;
};

структуры нужно запаковать в набор векторов в другой структуре

struct cmdlist {
  std::vector<cmdfoo> foos;
  std::vector<cmdbar> bars;
  std::vector<cmdbaz> bazs;
}

В целом, на BOOST_FUSION_ADAPT_STRUCT это хорошо ложится, но есть исключения.

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

BARa 1, 2, 3
BARb 1, 2, 4

struct cmdbar {
  enum { A, B } type;
  int arg1;
  int arg2;
  int arg3;
  int arg4;
};

Что с этим делать? Во-первых, не хочется дублировать правило грамматики для парсинга очень похожих штук. Во-вторых, как использовать BOOST_FUSION_ADAPT_STRUCT чтобы было 2 adapt'а для одной сруктуры? Видел BOOST_FUSION_ADAPT_STRUCT_NAMED, но как сказать правилу которое

qi::rule<Iterator, cmdbar()>, foocmda_rule;

использовать конкретный adapt?

Во-вторых, в грамматике, очевидно, будет общее правило для любой команды:

cmd_rule = cmdfoo_rule | cmdbar_rule | cmdbaz_rule;

Я видел что в таких случаях возвращают boost::variant, но не хочется паковать правила в вариант, а выше по грамматике распаковывать чтобы распихать по векторам. Можно как-то достучаться из правил-листьев до верха, т.е. правила которое генерирует cmdlist?

Это пока основное что мне не понятно.

★★★★★

Отвечаю сам себе на первый вопрос, работает так:

struct cmdbar {
  enum Type { A, B };
  Type type;
  int arg1;
  int arg2;
  int arg3;
  int arg4;
};

BOOST_FUSION_ADAPT_STRUCT_NAMED_NS(
  cmdbar, , cmdbara,
  (cmdbar::Type, type)
  (int, arg1)
  (int, arg2)
  (int, arg3)
)

BOOST_FUSION_ADAPT_STRUCT_NAMED_NS(
  cmdbar, , cmdbarb,
  (cmdbar::Type, type)
  (int, arg1)
  (int, arg2)
  (int, arg4)
)

...

Rule<Iterator, cmdbara(), ascii::space> rule_cmdbara = qi::lit("BARa") >> qi::attr(cmdbar::A) >> qi::int_ >> qi::int_ >> qi::int_;
Rule<Iterator, cmdbarb(), ascii::space> rule_cmdbarb = qi::lit("BARb") >> qi::attr(cmdbar::B) >> qi::int_ >> qi::int_ >> qi::int_;
Rule<Iterator, cmdbar(), ascii::space> rule_cmdbar = rule_cmdbara | rule_cmdbarb;

Т.е. структура биндится под несколькими именами, значение для type генерируется через qi::attr, в общем правиле для любых cmdbar в качестве типа значения можно указывать просто cmdbar, ADAPT_STRUCT для него не нужен.

Правила пришлось всё-таки продублировать - у меня там разное число аргументов, так что иначе наверное никак. А вот если бы число и тип аргументов было бы одинаковое, можно было разрулить это на уровне ADAPT_STRUCT и понадобилось бы только одно правило.

Подводные камни тут ещё такие (понять что не так очень сложно, ибо бустовые ошибки на 10 страниц - сами знаете)

  • во-первых, не забывайте нужные инклуды
  • boost по умолчанию разрешает захват только 10 значений (т.е. если у структуры 11 полей - то-ли в ADAPT_STRUCT, то-ли в описании правила получим ошибку компиляции). У меня было больше, для этого надо увеличить FUSION_MAX_VECTOR_SIZE (задефайнить его в нужное значение перед включением бустовских инклудов)
  • почему-то если для родительских правил не указывать типа значения программа не собирается. Т.е. я сначала написал грамматику без генерации структур, а генерацию хотел прикрутить постепенно, добавляя значения сначала листьям и опускаясь к корню, а хрена с два. Наверное поканало бы наоборот подниматься из корня, постепенно добавляя поля в ADAPT_STRUCT и, соответственно, типы в определения правил.
slovazap ★★★★★
() автор топика
Последнее исправление: slovazap (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.