неділю, 10 січня 2010 р.

Синтаксичний розбір із Spirit2

Мабуть, із самого початку для синтаксичного розбору на C++ я використовував boost::spirit. Вірою і правдою він служив аж п’ять років, і от вийшла цілком нова його версія під гордим номером 2. Старий код, звісно, продовжує працювати, якщо трохи підпиляти оголошення простору імен. А от мене здолала цікавість, що ж такого особливого нагородили в новій.

Відверто, відкриття перевершило всі сподівання. Новинка дозволяє писати вражаюче лаконічний код. Тобто, задум автора видно навіть при поверхневому перегляді. Важче вже збагнути, як ця магія працює, і треба бути готовим танцювати навколо із бубном, якщо щось не вдається відразу.

Для прикладу візьмімо клапоть коду розроблюваної версії IPMP2. Треба розібрати отримані із запиту HTTP GET аргументи та заповнювати вектор пар “ключ-значення”. Spirit2 підходить для цього, як лікар прописав. Ось опис граматики:

        
namespace qi = boost::spirit::qi;

// Магічне оголошення граматики
template <typename IterT, typename ParamsT>
struct CgiGram : qi::grammar<IterT, ParamsT()>
{
    // В конструкторі описуємо цю граматику
    // Крім того зазначаємо початкове правило
    CgiGram () : CgiGram::base_type (start)
    {
        using namespace qi;

        start %= parm % '&';  // Починаємо зі списку параметрів,
                              // розділених символом '&'

        parm %=  *chr         // Параметр — це пара ключ-значення,
             >>  '='          // а між ними '='
             >>  *chr
             ;

        chr %= char_('+') [_val = ' ']       // Або це '+' → ' '
            |  '%' >> attr_cast<char>(xchar) // Або символ з ASCII коду
            |  (char_ - char_("=&"))         // Або будь-що, окрім =,&
            ;
    }

    qi::uint_parser<unsigned, 16, 2, 2> xchar;
    qi::rule<IterT, ParamsT()> start;              // Стартове правило
    qi::rule<IterT,                                // Правило для параметра
             typename ParamsT::value_type()> parm;
    qi::rule<IterT, char()> chr;                   // Правило для символа
};

      

Отже, сокира є. А як наварити з неї борщу — це домашнє завдання для допитливих.