![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Porting from Spirit 1.8.xBoost , Spirit 2.5.2 , Notes
|
classic.hpp | < |
classic_actor.hpp | |
< | |
classic_core.hpp | < |
classic_debug.hpp | qi_debug.hpp |
< | Нет, пользуйтесьSpirit.Qiпредикаты вместо if_p, тогда как_p, for_p (включено< |
< | < |
classic_meta.hpp | Нет |
classic_symbols.hpp | < |
classic_utility.hpp | Нет, не частьSpirit.Qiбольше, эти компоненты будут добавлены с течением времени вRepository . |
Изменены функции свободного разбора (основной API-интерфейс). Это включает в себя названия бесплатных функций, а также их интерфейс. ВSpirit.Classicвсе свободные функции были названы<parse
>. ВSpirit.Qiони называются либо<qi::parse
>, либо<qi::phrase_parse
>в зависимости от того, следует ли делать разбор с помощью шкипера<qi::phrase_parse
>или нет<qi::parse
>. Все свободные функции возвращаются простым<bool
>. Возврат<true
>означает успех (т.е. парсер совпал) или<false
>(т.е. парсер не совпадал). Это эквивалентно бывшему старому<parse_info
>члену<hit
>.Spirit.Qiбольше не поддерживает отслеживание согласованной длины входа. Старый<parse_info
>элемент<full
>можно эмулировать путем сравнения итераторов после возвращения<qi::parse
>.
Все примеры кода в этом разделе предполагают, что следующие включают в себя заявления и использование директив для вставки.Дух.Классика:
#include <boost/spirit/include/classic.hpp> #include <boost/spirit/include/phoenix1.hpp> #include <iostream> #include <string>
using namespace boost::spirit::classic;
Дух.Qi:
#include <boost/spirit/include/qi.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <iostream> #include <string> #include <algorithm>
using namespace boost::spirit;
Следующие аналогичные примеры должны прояснить различия. Первый пример вSpirit.Classic:
std::string input("1,1"); parse_info<std::string::iterator> pi = parse(input.begin(), input.end(), int_p); if (pi.hit) std::cout << "successful match!\n"; if (pi.full) std::cout << "full match!\n"; else std::cout << "stopped at: " << std::string(pi.stop, input.end()) << "\n"; std::cout << "matched length: " << pi.length << "\n";
И вот эквивалентная часть кода, использующаяSpirit.Qi:
std::string input("1,1"); std::string::iterator it = input.begin(); bool result = qi::parse(it, input.end(), qi::int_); if (result) std::cout << "successful match!\n"; if (it == input.end()) std::cout << "full match!\n"; else std::cout << "stopped at: " << std::string(it, input.end()) << "\n"; // seldomly needed: use std::distance to calculate the length of the match std::cout << "matched length: " << std::distance(input.begin(), it) << "\n";
Изменения, необходимые для парсинга фраз (т.е. парсинга с помощью шкипера), аналогичны. Вот как работает парсинг фраз вSpirit.Classic:
std::string input(" 1, 1"); parse_info<std::string::iterator> pi = parse(input.begin(), input.end(), int_p, space_p); if (pi.hit) std::cout << "successful match!\n"; if (pi.full) std::cout << "full match!\n"; else std::cout << "stopped at: " << std::string(pi.stop, input.end()) << "\n"; std::cout << "matched length: " << pi.length << "\n";
И вот эквивалентный пример вSpirit.Qi:
std::string input(" 1, 1"); std::string::iterator it = input.begin(); bool result = qi::phrase_parse(it, input.end(), qi::int_, ascii::space); if (result) std::cout << "successful match!\n"; if (it == input.end()) std::cout << "full match!\n"; else std::cout << "stopped at: " << std::string(it, input.end()) << "\n"; // seldomly needed: use std::distance to calculate the length of the match std::cout << "matched length: " << std::distance(input.begin(), it) << "\n";
Обратите внимание, что парсеры символов находятся в отдельном пространстве имен (здесь<boost::spirit::ascii::space
>) какSpirit.Qiтеперь поддерживает работу с различными наборами символов. См. разделПространство имен символовдля получения дополнительной информации.
ВSpirit.Classicвсе парсерные примитивы имеют суффиксы, прилагаемые к их именам, кодирующие их тип:<"_p"
>для парсеров,<"_a"
>для ленивых действий,<"_d"
>для директив и т. д. ВSpirit.Qiу нас нет ничего подобного. Единственными суффиксами являются отдельные буквы подчеркивания<"_"
>, применяемые там, где имя в противном случае противоречило бы ключевому слову или предопределенному имени (например,<int_
>для целого парсера). В целом, большинство, если не все примитивные парсеры и директивы были переименованы. См.Qi Quick Referenceдля обзора имен различных доступных примитивов, директив и операторов.
Spirit.Classic.
raw
[]
директива раскрывает пару итераторов
указывает на соответствие последовательности его встроенного парсера. Даже если мы очень
много поощрять вас переписать ваши парсеры, чтобы воспользоваться полученным
специфические атрибуты, иногда полезно получить доступ к
лежащая в основе последовательность ввода.
.
Типы<grammar<>
>и<rule<>
>одинаково важны дляДуха.Qi, как и дляДуха.Классика. Их основная цель все та же: они позволяют определять нетерминалы и являются основными строительными блоками для более сложных парсеров. Тем не менее, оба типа были переработаны, и их интерфейсы изменились. Давайте сначала рассмотрим два примера, а затем объясним различия. Вот простая грамматика и ее использование вSpirit.Classic:
struct roman : public grammar<roman> { template <typename ScannerT> struct definition { definition(roman const& self) { hundreds.add ("C" , 100)("CC" , 200)("CCC" , 300)("CD" , 400)("D" , 500) ("DC" , 600)("DCC" , 700)("DCCC" , 800)("CM" , 900) ; tens.add ("X" , 10)("XX" , 20)("XXX" , 30)("XL" , 40)("L" , 50) ("LX" , 60)("LXX" , 70)("LXXX" , 80)("XC" , 90) ; ones.add ("I" , 1)("II" , 2)("III" , 3)("IV" , 4)("V" , 5) ("VI" , 6)("VII" , 7)("VIII" , 8)("IX" , 9) ; first = eps_p [phoenix::var(self.r) = phoenix::val(0)] >> ( +ch_p('M') [phoenix::var(self.r) += phoenix::val(1000)] || hundreds [phoenix::var(self.r) += phoenix::_1] || tens [phoenix::var(self.r) += phoenix::_1] || ones [phoenix::var(self.r) += phoenix::_1] ) ; } rule<ScannerT> first; symbols<unsigned> hundreds; symbols<unsigned> tens; symbols<unsigned> ones; rule<ScannerT> const& start() const { return first; } }; roman(unsigned& r_) : r(r_) {} unsigned& r; };
std::string input("MMIX"); // MMIX == 2009 unsigned value = 0; roman r(value); parse_info<std::string::iterator> pi = parse(input.begin(), input.end(), r); if (pi.hit) std::cout << "successfully matched: " << value << "\n";
И вот аналогичная грамматика и ее использование вSpirit.Qi:
template <typename Iterator> struct roman : qi::grammar<Iterator, unsigned()> { roman() : roman::base_type(first) { hundreds.add ("C" , 100)("CC" , 200)("CCC" , 300)("CD" , 400)("D" , 500) ("DC" , 600)("DCC" , 700)("DCCC" , 800)("CM" , 900) ; tens.add ("X" , 10)("XX" , 20)("XXX" , 30)("XL" , 40)("L" , 50) ("LX" , 60)("LXX" , 70)("LXXX" , 80)("XC" , 90) ; ones.add ("I" , 1)("II" , 2)("III" , 3)("IV" , 4)("V" , 5) ("VI" , 6)("VII" , 7)("VIII" , 8)("IX" , 9) ; // qi::_val refers to the attribute of the rule on the left hand side first = eps [qi::_val = 0] >> ( +lit('M') [qi::_val += 1000] || hundreds [qi::_val += qi::_1] || tens [qi::_val += qi::_1] || ones [qi::_val += qi::_1] ) ; } qi::rule<Iterator, unsigned()> first; qi::symbols<char, unsigned> hundreds; qi::symbols<char, unsigned> tens; qi::symbols<char, unsigned> ones; };
std::string input("MMIX"); // MMIX == 2009 std::string::iterator it = input.begin(); unsigned value = 0; roman<std::string::iterator> r; if (qi::parse(it, input.end(), r, value)) std::cout << "successfully matched: " << value << "\n";
Обе версии выглядят достаточно похожими, но мы видим несколько отличий (подробнее рассмотрим каждую из них ниже):
definition
>The Scanner Business () долгое время был проблемой. Грамматика и типы правил были специально переработаны, чтобы избежать этой проблемы в будущее. Это также означает, что нам не нужна отсроченная мгновенная связь. внутреннего определения класса в грамматике. Так что редизайн не только помог решить давнюю проблему дизайна, это помогло упростить вещи значительно. .
ВсеSpirit.Qiпарсерные компоненты имеют четко определенные типы атрибутов. Грамматика и правила не являются исключением. Но поскольку оба должны быть достаточно общими, чтобы их можно было использовать для любого парсера, их тип атрибута должен быть четко указан. В примере выше грамматики<roman
>и правила<first
>оба имеют атрибут<unsigned
>:
// grammar definition template <typename Iterator> struct roman : qi::grammar<Iterator, unsigned()> {...}; // rule definition qi::rule<Iterator, unsigned()> first;
Используемая нотация напоминает определение типа функции. Это очень естественно, поскольку вы можете думать о синтезированном атрибуте грамматики и правиле как о его «возвращенной стоимости». На самом деле и правило, и грамматика «вернут» неподписанное значение — то значение, которое они соответствовали.
![]() | Note |
---|---|
Нотация типа функции позволяет также задавать параметры. Они интерпретируются как типы унаследованных атрибутов, которые, как ожидается, будут переданы во время разбора. Для получения дополнительной информации см. раздел о наследственных и синтезированных атрибутах для правил и грамматикАтрибуты. |
Если нет желаемого атрибута, не нужно указывать. Тип атрибута по умолчанию как для грамматики, так и для правил<unused_type
>, который является особым типом заполнителя. Как правило, использование<unused_type
>в качестве атрибута парсера интерпретируется как «этот парсер не имеет атрибута». Это в основном используется для парсеров, применяемых к частям входа, не несущим никакой существенной информации, а скорее являющимся разграничителями или структурными элементами, необходимыми для правильной интерпретации входа.
Последнее различие может показаться довольно косметическим и незначительным. Но оказывается, что отсутствие необходимости указывать, какое правило в грамматике является правилом начала (путем возвращения его из функции<start()
>), также означает, что любое правило в грамматике может быть непосредственно использовано в качестве правила начала. Тем не менее, базовый класс грамматики инициализируется с правилом, которое он должен использовать в качестве правила начала, если экземпляр грамматики непосредственно используется в качестве парсера.
Статья Porting from Spirit 1.8.x раздела Spirit 2.5.2 Notes может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
реклама |