Опыт использования    Boost Spirit         Иван Романенко(viva.cpp@gmail.com)
Ожидается• Инфа о спирите и карме• Основы синтаксиса спирта• Примеры получения практической пользы• Почему спирит - не то ...
Парсинг                      Структура   Текст                       данных                  struct Data                  ...
Генерация                   Структура   Текст                    данных                  struct Data                  {   ...
Мотивация• Бьюсь об заклад, я могу написать простое регулярное  выражение для разбора этого текста• Я не хочу подключать д...
Regexp
Парсер в одной функции
Spirit way
Области применения• Специализированные конфигурационные  файлы• Коммуникация с устройствами• Поддержка произвольных формат...
Что такое Boost Spirit ?• Это объектено-ориентированный нисходящий  синтаксический анализатор.• Позволяет описывать формат...
Spirit состоит из:• Qi – парсер• Karma - генератор• Lex – лексический анализатор• Classic – старая версия парсера
Qi APIsscanf( …,”%d”, var)parse(…, int_, var)parse(…, int_)(8))
ЧислаТип            Правилоsigned         short_, int_, long_, long_longunsigned       bin, oct, hex, ushort_, ulong_, uin...
СимволыТип            Правилоcharacter      char_, char_(’x’), char_(’a’,’z’),               char_(“a-zA-Z”), ‘x’string   ...
Операторы      Описание          Синтаксис‘ИЛИ’                      a|bПоследовательно           a >> b0 или множество ра...
Операторы      Описание          Синтаксис‘ИЛИ’                      a|b      Допустимо правилоПоследовательно           a...
Операторы      Описание          Синтаксис‘ИЛИ’                      a|b      За правилом аПоследовательно           a >> ...
Операторы      Описание        Синтаксис‘ИЛИ’                    a|b      *char_(‘a’)Последовательно         a >> b    “aa...
Операторы      Описание          Синтаксис‘ИЛИ’                      a|b    *(char_ - ‘=’) >> ‘=’ >> int_Последовательно  ...
Операторы      Описание          Синтаксис‘ИЛИ’                      a|bПоследовательно           a >> b    int_ % ‘,’0 ил...
Операторы      Описание          Синтаксис‘ИЛИ’                      a|bПоследовательно           a >> b    int_ ^ alpha0 ...
Атрибутыint varInt;parse(…, int_, varInt)int varInt; double varDbl;parse(…, int_ >> “_“ >> double_, varInt, varDbl)double ...
Атрибуты операторов         Описание         Синтаксис  0 или множество раз        *a           a: A --> *a: vector<A>    ...
Атрибуты операторов      Описание     СинтаксисПоследовательно      a >> b                               std::pair<A,B>a: ...
Атрибуты операторов      Описание      СинтаксисПоследовательно       a >> ba: A, b: A --> (a >> b): vector<A>a: vector<A>...
Управление атрибутами              Описание                  СинтаксисИгнорирование атрибута                    omit[]Эксп...
Profit ?
Атрибуты операторов                перезагрузкаstd::string data(“1 2 3 4 5 6");std::list< int > numbers;phrase_parse(data....
Атрибуты операторов               перезагрузкаstd::string data(“1,2,3,4,5,6");std::list< int > numbers;phrase_parse(data.b...
Атрибуты операторов                перезагрузкаstd::string data("p=3.14 g=9.8");std::list< std::pair<std::string, double> ...
Атрибуты операторов               перезагрузкаstd::string data("p=3.14 g=9.8");std::map<std::string, double> records;phras...
Атрибуты операторов               перезагрузкаstd::string data(“n p=3.14 n g=9.8 ");std::map<std::string, double> records;...
Пользовательский типstruct Record{std::string name;double value;};BOOST_FUSION_ADAPT_STRUCT(  Record,  (std::string, name)...
Атрибуты операторов               революцияstd::string data("p=3.14 g=9.8");std::list<Record> records;phrase_parse(data.be...
Custom actionstd::string data("p=3.14 g=9.8");void SomeFnc(Record& rec){  std::cout << rec.name << " " << rec.value << std...
Организация своих правил
Пользовательские правила• Новые правила создаются на базе уже  существующих• Правило может иметь локальные переменные• Пра...
Пользовательские правилаtemplate <typename Iterator, typename Signature>struct rule;qi::rule<char*, std::vector<int>()> st...
Примерstruct Record{std::string name;double value;};qi::rule<…, std::string()> name = +char_ - ‘=’;qi::rule<…, double()> v...
Грамматика• Объединяет правила в более  высокоуровневую абстракцию• Экспортирует атрибут• Может иметь локальные переменные...
Организация грамматикиtemplate <typename Iterator>struct my_grammar: qi::grammar<Iterator, mini_xml() >{    my_grammar() :...
Обработка ошибок...xml = ……on_error<fail>    (        xml      , std::cout          << val("Error! Expecting ")          <...
Karma APIsprintf( …,”%d”, var)generate(…, int_, var)
Динамический спирит
Проблемы• Листинг об ошибке длиною в вечность• Время компиляции зашкаливает• Отладка в уме
Листинг об ошибке длиною в         вечность
Листинг об ошибке длиною в              вечность• Дойти до первой строки ошибки - это ваш файл.• Одной строкой выше будет ...
Проверки времени компиляции
Время компиляции#include <boost/spirit/include/qi.hpp>std::string data("12 23 34 56");std::list<int> numbers;phrase_parse(...
Время компиляцииMiddle-size парсер из реального проекта400 строк кода.1 парсер и 2 генератора.Время компиляции: ~ 5 мин.RA...
Отладка         BOOST_SPIRIT_DEBUG_NODE( NODE )std::string data("12 23");std::list<int> numbers;rule<std::string::const_it...
Отладка<testRule> <try>12 23</try> <success> 23</success>           “12 23” <attributes>[12]</attributes></testRule><testR...
Сравнение
ANTLR• Отдельная среда разработки и наличие плагинов для Eclipse• Генерирует парсер на языках:  ActionScript, C, C#, Java,...
ANTLR Debugger
bison/yacc                                                      Копипаста с википедииAdvantages:1. An LALR parser is fast ...
Спасибо за внимание
Приложения
Атрибуты операторов        Описание   Синтаксис‘ИЛИ’                a|ba: A, b: B --> (a | b): variant<A, B>a: A, b: Unuse...
Placeholders  Placeholder       Description  _1, _2, …         Nth attribute of the parser.  _val              The enclosi...
CiklumCPPSat: Ivan Romanenko "Experience of work with Boost Spirit"
Upcoming SlideShare
Loading in …5
×

CiklumCPPSat: Ivan Romanenko "Experience of work with Boost Spirit"

720 views

Published on

Published in: Education
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
720
On SlideShare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

CiklumCPPSat: Ivan Romanenko "Experience of work with Boost Spirit"

  1. 1. Опыт использования Boost Spirit Иван Романенко(viva.cpp@gmail.com)
  2. 2. Ожидается• Инфа о спирите и карме• Основы синтаксиса спирта• Примеры получения практической пользы• Почему спирит - не то что вам нужно• Сравнение с аналогами
  3. 3. Парсинг Структура Текст данных struct Data { int a;“123 456 678” int b; int c; };
  4. 4. Генерация Структура Текст данных struct Data { int a;“123 456 678” int b; int c; };
  5. 5. Мотивация• Бьюсь об заклад, я могу написать простое регулярное выражение для разбора этого текста• Я не хочу подключать дополнительные библиотеки• Одной строки с использованием scanf/istream будет достаточно• std::string и boost::lexical_cast мои друзья
  6. 6. Regexp
  7. 7. Парсер в одной функции
  8. 8. Spirit way
  9. 9. Области применения• Специализированные конфигурационные файлы• Коммуникация с устройствами• Поддержка произвольных форматов данных• Всё что угодно, имеющее «синтаксис»
  10. 10. Что такое Boost Spirit ?• Это объектено-ориентированный нисходящий синтаксический анализатор.• Позволяет описывать формат используя синтаксис, приближённый к EBNF(Расширенной форме Бэкуса – Наура), прямо в С++ коде.• Позволяет связывать описание синтаксиса с конкретными типами данных, обеспечивая строгую типизацию.
  11. 11. Spirit состоит из:• Qi – парсер• Karma - генератор• Lex – лексический анализатор• Classic – старая версия парсера
  12. 12. Qi APIsscanf( …,”%d”, var)parse(…, int_, var)parse(…, int_)(8))
  13. 13. ЧислаТип Правилоsigned short_, int_, long_, long_longunsigned bin, oct, hex, ushort_, ulong_, uint_real float_, double_, long_doubleboolean bool_binary byte_, word, dword, qwordbig endian big_word, big_dword, big_qwordlitte endian litte_word, litte_dword, litte_qword
  14. 14. СимволыТип Правилоcharacter char_, char_(’x’), char_(’a’,’z’), char_(“a-zA-Z”), ‘x’string string(“foo”), lit(“bar”), “bar”classification alnum, alpha, blank, cntrl, digit, graph, lower, print, punct, space, upper, xdigit
  15. 15. Операторы Описание Синтаксис‘ИЛИ’ a|bПоследовательно a >> b0 или множество раз *aНе меньше одного раза +aОпциональное -aРазность a-bСписок a%b‘И’ в любом порядке a^b
  16. 16. Операторы Описание Синтаксис‘ИЛИ’ a|b Допустимо правилоПоследовательно a >> b а или b0 или множество раз *a int_ | doubleНе меньше одного раза +aОпциональное -a “123” , “3.14”Разность a-bСписок a%b‘И’ в любом порядке a^b
  17. 17. Операторы Описание Синтаксис‘ИЛИ’ a|b За правилом аПоследовательно a >> b следует b0 или множество раз *a int_ >> ‘_‘ >> doubleНе меньше одного раза +aОпциональное -a “123_3.14”Разность a-bСписок a%b‘И’ в любом порядке a^b
  18. 18. Операторы Описание Синтаксис‘ИЛИ’ a|b *char_(‘a’)Последовательно a >> b “aaaaa”0 или множество раз *a +char_Не меньше одного раза +a “name”Опциональное -aРазность a-b *( int_ >> -char_(‘,’) )Список a%b “1,2,3,4”‘И’ в любом порядке a^b
  19. 19. Операторы Описание Синтаксис‘ИЛИ’ a|b *(char_ - ‘=’) >> ‘=’ >> int_Последовательно a >> b0 или множество раз *a “variable=123”Не меньше одного раза +aОпциональное -aРазность a-bСписок a%b‘И’ в любом порядке a^b
  20. 20. Операторы Описание Синтаксис‘ИЛИ’ a|bПоследовательно a >> b int_ % ‘,’0 или множество раз *a “1,2,3,4”Не меньше одного раза +aОпциональное -aРазность a-bСписок a%b‘И’ в любом порядке a^b
  21. 21. Операторы Описание Синтаксис‘ИЛИ’ a|bПоследовательно a >> b int_ ^ alpha0 или множество раз *a “12a”Не меньше одного раза +a “a12”Опциональное -aРазность a-bСписок a%b‘И’ в любом порядке a^b
  22. 22. Атрибутыint varInt;parse(…, int_, varInt)int varInt; double varDbl;parse(…, int_ >> “_“ >> double_, varInt, varDbl)double varDbl;parse(…, int_(8) >> char_(“_“) >> double_, varDbl)
  23. 23. Атрибуты операторов Описание Синтаксис 0 или множество раз *a a: A --> *a: vector<A> a: Unused --> *a: Unusedправило : атрибут правила --> выражение : атрибут выраженияint_ : int --> *int_ : vector<int>
  24. 24. Атрибуты операторов Описание СинтаксисПоследовательно a >> b std::pair<A,B>a: A, b: B --> (a >> b): tuple<A, B>a: A, b: Unused --> (a >> b): Aa: Unused, b: B --> (a >> b): Ba: Unused, b: Unused --> (a >> b): Unused
  25. 25. Атрибуты операторов Описание СинтаксисПоследовательно a >> ba: A, b: A --> (a >> b): vector<A>a: vector<A>, b: A --> (a >> b): vector<A>a: A, b: vector<A> --> (a >> b): vector<A>a: vector<A>, b: vector<A> --> (a >> b): vector<A>
  26. 26. Управление атрибутами Описание СинтаксисИгнорирование атрибута omit[]Экспорт промежутка на котором raw[]сработало правило [first,last]a: A --> omit[a]: unused_typea: A --> raw[a]: boost::iterator_range<Iter>
  27. 27. Profit ?
  28. 28. Атрибуты операторов перезагрузкаstd::string data(“1 2 3 4 5 6");std::list< int > numbers;phrase_parse(data.begin(), data.end(), *int_, space, numbers);
  29. 29. Атрибуты операторов перезагрузкаstd::string data(“1,2,3,4,5,6");std::list< int > numbers;phrase_parse(data.begin(), data.end(), (int_ % ‘,’), space, numbers);
  30. 30. Атрибуты операторов перезагрузкаstd::string data("p=3.14 g=9.8");std::list< std::pair<std::string, double> > records;phrase_parse(data.begin(), data.end(), *( +alpha >> ”=“ >> double_ ), space, records);
  31. 31. Атрибуты операторов перезагрузкаstd::string data("p=3.14 g=9.8");std::map<std::string, double> records;phrase_parse(data.begin(), data.end(), *( +alpha >> ”=“ >> double_ ), space, records);
  32. 32. Атрибуты операторов перезагрузкаstd::string data(“n p=3.14 n g=9.8 ");std::map<std::string, double> records;phrase_parse(data.begin(), data.end(), *( +alpha >> ”=“ >> double_ ), space, records);
  33. 33. Пользовательский типstruct Record{std::string name;double value;};BOOST_FUSION_ADAPT_STRUCT( Record, (std::string, name) (double, value))
  34. 34. Атрибуты операторов революцияstd::string data("p=3.14 g=9.8");std::list<Record> records;phrase_parse(data.begin(), data.end(), *( +alpha >> ”=“ >> double_ ), space, records);
  35. 35. Custom actionstd::string data("p=3.14 g=9.8");void SomeFnc(Record& rec){ std::cout << rec.name << " " << rec.value << std::endl;}qi:rule<std::string::const_iterator,Record()> recRule = +alpha >> ”=“ >> double_;phrase_parse(data.begin(), data.end(), *(recRule [&SomeFnc] ), space);
  36. 36. Организация своих правил
  37. 37. Пользовательские правила• Новые правила создаются на базе уже существующих• Правило может иметь локальные переменные• Правило может принимать входные параметры• Правило экспортирует атрибут
  38. 38. Пользовательские правилаtemplate <typename Iterator, typename Signature>struct rule;qi::rule<char*, std::vector<int>()> start;qi::rule<char*, std::vector<int>(int)> start;qi::rule<char*, …, qi::locals<int> > start;
  39. 39. Примерstruct Record{std::string name;double value;};qi::rule<…, std::string()> name = +char_ - ‘=’;qi::rule<…, double()> value = ‘*’ >> double_ >> ‘+’;qi::rule<…, Record()> start = name >> ‘=‘ >> value;
  40. 40. Грамматика• Объединяет правила в более высокоуровневую абстракцию• Экспортирует атрибут• Может иметь локальные переменные• Предоставляет каллбеки об ошибках
  41. 41. Организация грамматикиtemplate <typename Iterator>struct my_grammar: qi::grammar<Iterator, mini_xml() >{ my_grammar() : my_grammar ::base_type(xml) { … start = name >> ‘=‘ >> value; } qi::rule<…, Record()> start; qi::rule<…, double()> value; qi::rule<…, std::string()> name;};
  42. 42. Обработка ошибок...xml = ……on_error<fail> ( xml , std::cout << val("Error! Expecting ") << _4 // what failed? << val(" here: "") << construct<std::string>(_3, _2) // iterators to error-pos, end << val(""") << std::endl );}Input: “<foo><bar></foo></bar>”Error! Expecting "bar" here: "foo></bar>"Error! Expecting end_tag here: "<bar></foo></bar>"-------------------------Parsing failed-------------------------
  43. 43. Karma APIsprintf( …,”%d”, var)generate(…, int_, var)
  44. 44. Динамический спирит
  45. 45. Проблемы• Листинг об ошибке длиною в вечность• Время компиляции зашкаливает• Отладка в уме
  46. 46. Листинг об ошибке длиною в вечность
  47. 47. Листинг об ошибке длиною в вечность• Дойти до первой строки ошибки - это ваш файл.• Одной строкой выше будет файл спирита.
  48. 48. Проверки времени компиляции
  49. 49. Время компиляции#include <boost/spirit/include/qi.hpp>std::string data("12 23 34 56");std::list<int> numbers;phrase_parse(data.begin(), data.end(), *int_, space, numbers);Тестовая система: Core 2 Duo T7100 1.8 ГцВремя компиляции: ~20 сек (Release or Debug)Размер exe файла: 180 кб (71 кб для main(),std::cout<< “Hi”;- )Используя Precompiled HeaderВремя компиляции: < 1 сек (Release or Debug)Размер PCH файла: 100 мб.
  50. 50. Время компиляцииMiddle-size парсер из реального проекта400 строк кода.1 парсер и 2 генератора.Время компиляции: ~ 5 мин.RAM использовано: 1.5 ГбРазмер exe файла: 1.4 Мб(Release) & 3.5 Мб(Debug)Размер (output dir) для одной конфигурации: 876 мбИспользуя Precompiled HeaderВремя компиляции: ~ 4 мин 30 секРазмер PCH файла: 150 мб.Установив Debug Information Format -> DisabledВремя компиляции: ~ 3 мин 20 сек.Экономия: 200 мб(для одного cpp) и 527 мб(для проекта)
  51. 51. Отладка BOOST_SPIRIT_DEBUG_NODE( NODE )std::string data("12 23");std::list<int> numbers;rule<std::string::const_iterator,int(),space_type> testRule = int_;BOOST_SPIRIT_DEBUG_NODE(testRule);phrase_parse(data.begin(), data.end(), *testRule , space, numbers);
  52. 52. Отладка<testRule> <try>12 23</try> <success> 23</success> “12 23” <attributes>[12]</attributes></testRule><testRule> <try> 23</try> <success></success> “12 23” <attributes>[23]</attributes></testRule><testRule> “12 23” <try></try> <fail/></testRule>Press any key to continue . . .
  53. 53. Сравнение
  54. 54. ANTLR• Отдельная среда разработки и наличие плагинов для Eclipse• Генерирует парсер на языках: ActionScript, C, C#, Java, JavaScript, Objective-C, Perl, Python, Ruby• Статическая проверка правил• Интерпритатор• Отладчик
  55. 55. ANTLR Debugger
  56. 56. bison/yacc Копипаста с википедииAdvantages:1. An LALR parser is fast (if the parsing algorithm uses a matrix parser-table format).2. An LALR parser is linear in speed (i.e. the speed is based on the size of the input text file only and not based on the size of the language being recognized).Disadvantages:1. Software engineers are required to use an LALR parser generator, which may or may not be user friendly and may require some learning time.2. Implementing meaningful error messages in the parser may be very difficult or impossible.3. Understanding the parsing algorithm is often quite difficult.4. If an error occurs, it may be difficult to determine whether its in the grammar or the parser code.5. If there is an error in the parser generator, this may be very difficult to fix.
  57. 57. Спасибо за внимание
  58. 58. Приложения
  59. 59. Атрибуты операторов Описание Синтаксис‘ИЛИ’ a|ba: A, b: B --> (a | b): variant<A, B>a: A, b: Unused --> (a | b): optional<A>a: Unused, b: B --> (a | b): optional<B>a: Unused, b: Unused --> (a | b): Unuseda: A, b: A --> (a | b): A
  60. 60. Placeholders Placeholder Description _1, _2, … Nth attribute of the parser. _val The enclosing rule’s synthesized attribute. _r1, _r2, ... The enclosing rule’s Nth inherited attribute. _a, _b, ..., _j The enclosing rule’s local variables. _pass Assign false to force parser failure.qi::rule<char*, int> = lit(“EnumValue") [ val_ = MyEnum::Value ]

×