![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
In-depth: The Parser ContextBoost , ,
OverviewКонтекст парсераявляется еще одной концепцией. Пример (объект) классаконтекстсоздается до начала нетерминального анализа и разрушается после завершения анализа. Нетерминал — это либо правило, либо подправило, либо грамматика. Нетерминалы имеютКонтекстПараметр шаблона. Следующий псевдокод показывает, что происходит, когда используется нетерминал:
Контекст предусмотрен для расширения. Его основная цель состоит в том, чтобы выявить начало и конец функции нетерминала для размещения внешних крючков. Мы можем расширить нетерминал множеством способов, написав специализированные классы контекста, не изменяя сам класс. Например, мы можем сделать информацию о нетерминальном излучении отладкой диагностики, написав класс контекста, который распечатывает текущее состояние сканера в каждой точке прохождения разбора, где нетерминал вызывается. Пример парсерного контекста, который распечатывает информацию отладки:
В большинстве случаев контекст будет невидимым с точки зрения пользователя. В общем, клиентам фреймворка не нужно иметь дело напрямую или даже знать о контекстах. Однако опытные пользователи могут найти некоторое применение контекстам. Это часть публичного API. Другие части структуры в других слоях над ядром используют контекст для расширения нетерминалов. Class declarationКлассparser_contextявляется классом контекста по умолчанию, который используется нетерминалом. template <typename AttrT = nil_t> Параметр шаблона non-terminalContextTявляется концепцией. Классparser_contextвыше является простейшей моделью этого понятия. Функции по умолчаниюparser_context'spre_parseиpost_parseявляются просто не-ops. Вы можете думать о шаблонном параметре нетерминалаContextTкак о политике, которая определяет, как нетерминал будет вести себя до и после анализа. Клиент может предоставить свою собственную политику контекста, передав параметр шаблона контекста, определенный пользователем, определенному нетерминалу.
Базазаслуживает дальнейшего объяснения. Вот идет... Контекст - это строго стек-класс. Он создается до разбора и разрушается после выхода функции неконцевого члена. Иногда нам нужны вспомогательные данные, которые существуют на протяжении всего срока службы нетерминального хоста. Поскольку нетерминал наследует от контекстаbase_t, сам контекст при создании получает доступ к этому при строительстве, когда нетерминал передается в качестве аргумента конструктору.и. Нетерминал наследует от контекстаbase_ttypedef. Единственным требованием является то, что это класс, который по умолчанию можно построить. Требования к копированию и назначению зависят от хоста. Если хост требует этого, то и контекстbase_t. В общем, не помешало бы обеспечить эти базовые требования. Non-default Attribute TypeПрямо из коробки классparser_contextможет быть параматерирован с типом, отличным от по умолчаниюnil_t. Следующий код демонстрирует использование шаблонаparser_contextс явным аргументом для объявления правил с результатами соответствия, отличными отnil_t: rule<parser_context<int> > int_rule = int_p; parse( "123", // Using a returned value in the semantic action int_rule[cout << arg1 << endl] ); В этом примереint_ruleобъявляется сintатрибутным типом. Следовательно, переменнаяint_ruleможет содержать любой парсер, который возвращает значениеint(например,int_pилиbin_p). Важно отметить, что мы можем использовать возвращенное значение в семантическом действии, связанном сint_rule.
An ExampleВ качестве примера давайте посмотрим на контекст парсера Spirit, который вставляет некоторый вывод отладки в процесс парсинга: template<typename ContextT> struct parser_context_linker : public ContextT { typedef ContextT base_t; template <typename ParserT> parser_context_linker(ParserT const& p) : ContextT(p) {} // This is called just before parsing of this non-terminal template <typename ParserT, typename ScannerT> void pre_parse(ParserT const& p, ScannerT &scan) { // call the pre_parse function of the base class this->base_t::pre_parse(p, scan); #if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES if (trace_parser(p.derived())) { // print out pre parse info impl::print_node_info( false, scan.get_level(), false, parser_name(p.derived()), scan.first, scan.last); } scan.get_level()++; // increase nesting level #endif } // This is called just after parsing of the current non-terminal template <typename ResultT, typename ParserT, typename ScannerT> ResultT& post_parse( ResultT& hit, ParserT const& p, ScannerT& scan) { #if BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES --scan.get_level(); // decrease nesting level if (trace_parser(p.derived())) { impl::print_node_info( hit, scan.get_level(), true, parser_name(p.derived()), scan.first, scan.last); } #endif // call the post_parse function of the base class return this->base_t::post_parse(hit, p, scan); } }; При отладкеBOOST_SPIRIT_DEBUGэтот парсерный контекст вводится в производную иерархию текущегоparser_context, который первоначально был указан для использования для конкретного парсера, поэтому параметр шаблонаContextTпредставляет исходныйparser_context. По этой причине функцииpre_parseиpost_parseназывают его аналогами из базового класса. Кроме того, эти функции называют специальной функциейprint_node_info, которая выполняет фактический вывод информации о состоянии парсера текущего нетерминала. Для получения дополнительной информации о печатной информации, вы можете захотеть взглянуть на темуОтладка.
Copyright © 1998-2003 Joel de Guzman
Статья In-depth: The Parser Context раздела может быть полезна для разработчиков на c++ и boost. Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта. :: Главная :: ::
|
|||||||||||||||||||||||||||||||||||
©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007 |