Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

In-depth: The Parser

Boost , ,

In-depth: The Parser

Что заставляет дух тикать? Теперь о некоторых деталях... Класс парсера является наиболее фундаментальной сущностью в рамках. Парсер принимает сканер, состоящий из пары первого итератора, и возвращает в результате объект соответствия. Итераторы ограничивают данные, которые в настоящее время анализируются. Объект соответствия оценивает истинность, если анализ увенчается успехом, и в этом случае вход продвигается соответственно. Каждый парсер может представлять собой определенный шаблон или алгоритм, или это может быть более сложный парсер, сформированный в виде композиции других парсеров.

Все парсеры наследуют от базового класса шаблонов, парсер:

template <typename DerivedT>
struct parser
{
    /*...*/
    DerivedT& derived();
    DerivedT const& derived() const;
};

Этот класс является базовым для всех парсеров. Класс парсера на самом деле не знает, как анализировать что-либо, но вместо этого полагается на параметр шаблонаDerivedT.Чтобы сделать реальный анализ. Этот метод известен как"Любопытно повторяющийся шаблон шаблона"в шаблонных кругах метапрограммирования. Эта стратегия наследования дает нам силу полиморфизма без накладных расходов на виртуальную функцию. По сути, это способ реализациикомпиляции полиморфизма времени.

parser_category_t

Каждый производный парсер имеет типдефparser_category_tОпределяет его категорию. По умолчанию, если не указано, он наследует от базового класса парсера, который типизирует его parser_category_t какplain_parser_category.. Некоторые классы шаблонов предоставляются для различения различных типов парсеров. Следующие категории являются наиболее общими. Более конкретные типы могут наследоваться от них.

Parser categories
plain_parser_category Your plain vanilla parser
binary_parser_category A parser that has subject a and b (e.g. alternative)
unary_parser_category A parser that has single subject (e.g. kleene star)
action_parser_category A parser with an attached semantic action
    struct plain_parser_category {};
    struct binary_parser_category       : plain_parser_category {};
    struct unary_parser_category        : plain_parser_category {};
    struct action_parser_category       : unary_parser_category {};

embed_t

Каждый парсер имеет типдефembed_t. Этот типдеф определяет, как парсер встроен в композит. По умолчанию, если один не указан, парсер будет встроен по стоимости. То есть копия парсера помещается в качестве переменной члена композита. Большинство парсеров встроены в стоимость. Однако в некоторых ситуациях это нежелательно или невозможно. Одним из примеров является правило. Правило, в отличие от других парсеров, встроено посредством ссылки.

The match

Матч держит результат парсера. Объект матча оценивает истинность, когда найден успешный матч, в противном случае ложный. Длина матча - это количество символов (или токенов), которые успешно совпадают. Это можно проверить по длине.Функция члена. Отрицательное значение означает, что матч неудачный.

Каждый парсер может иметь ассоциированный атрибут. Этот атрибут также возвращается обратно клиенту на успешном разборе через объект матча. Мы можем получить этот атрибут через значение матча.Функция члена. Следует предупредить, что атрибут матча может быть недействительным, и в этом случае получение атрибута приведет к исключению. Функцияимеет_valid_attribute()можно спросить, безопасно ли получить атрибут матча. Атрибут может быть установлен в любое время через значение члена[v], гдеvявляется новым значением атрибута.

Атрибут соответствия действителен:

  • в успешном матче
  • когда его значение устанавливается череззначение (val)Функция члена
  • если он назначен или скопирован с совместимого объекта соответствия (например,matchизmatch) с действительным атрибутом. Объект соответствияAсовместим с другим объектом соответствияB, если тип атрибутаAможет быть назначен из типа атрибутаB(т.е.a = b;должен компилироваться).

Атрибут матча не определен:

  • На неудачном матче
  • при попытке скопировать или назначить из другого объекта соответствия с несовместимым типом атрибутов (например,matchизmatch).

The match class:

    template <typename T>
    class match
    {
    public:
        /*...*/
        typedef T attr_t;
operator safe_bool() const; // convertible to a bool int length() const; bool has_valid_attribute() const; void value(T const&) const; T const& value(); };

match_result

Неоднократно упоминалось, что в результате парсер возвращает объект соответствия. Это упрощение. На самом деле, ради универсальности, парсеры действительно не закодированы, чтобы вернуть объект соответствия. Точнее, парсер возвращает объект, который придерживается концептуального интерфейса, примером которого является совпадение. Тем не менее, мы будем называть тип результата парсера объектом соответствия, независимо от того, является ли он классом соответствия, производным или совершенно не связанным типом.

Meta-functions

What are meta-functions? We all know how functions look like. In simplest terms, a function accepts some arguments and returns a result. Here is the function we all love so much:

int identity_func(int arg)
{ return arg; } // return the argument arg

Meta-functions are essentially the same. These beasts also accept arguments and return a result. However, while functions work at runtime on values, meta-functions work at compile time on types (or constants, but we shall deal only with types). The meta-function is a template class (or struct). The template parameters are the arguments to the meta-function and a typedef within the class is the meta-function's return type. Here is the corresponding meta-function:

template <typename ArgT>
struct identity_meta_func
{ typedef ArgT type; } // return the argument ArgT

The meta-function above is invoked as:

typename identity_meta_func<ArgT>::type

By convention, meta-functions return the result through the typedef type. Take note that typename is only required within templates.

Фактический тип соответствия, используемый парсером, зависит от двух типов: типа атрибута парсера и типа сканера.match_result— это метафункция, которая возвращает желаемый тип соответствия, заданный тип атрибута и тип сканера.

Использование:

    typename match_result<ScannerT, T>::type

Мета-функция в основном отвечает на вопрос "с учетом типа сканераScannerTи типа атрибутаT, какой тип совпадения требуется?"имя типатребуется только в шаблонах ].

The parse member function

Бетонные подклассы, наследуемые от парсера, должны иметь соответствующую членскую функциюпарс.Совместимость с концептуальным интерфейсом:

    template <typename ScannerT>
    RT
    parse(ScannerT const& scan) const;

гдеRT— желаемый тип возврата парсера.

The parser result

Бетонные подклассы, наследуемые от парсера, в большинстве случаев должны иметь вложенный результат метафункции, который возвращает результаттипафункции парсера члена парсера, учитывая тип сканера. Метафункция имеет вид:

    template <typename ScannerT>
    struct result
    {
        typedef RT type;
    };

гдеRT— желаемый тип возврата парсера. Это обычно, но не всегда, зависит от параметра шаблонаScannerT. Например, при данном типе атрибутовintможно использовать метафункцию match_result:

    template <typename ScannerT>
    struct result
    {
        typedef typename match_result<ScannerT, int>::type type;
    };

Если парсер не обеспечивает метафункцию результата, по умолчанию предоставляется базовый класс парсера.Дефолт объявляется как:

    template <typename ScannerT>
    struct result
    {
        typedef typename match_result<ScannerT, nil_t>::type type;
    };

Без метафункции результата обратите внимание, что атрибут парсера по умолчанию составляетnil_t(т.е. у парсера нет атрибута).

parser_result

При наличии типа сканераScannerTи типа парсераParserT, каков будет фактический результат парсера? Ответ на этот вопрос дает метафункцияparser_result.

Использование:

    typename parser_result<ParserT, ScannerT>::type

В общем, мета-функция просто пересылает вызов к мета-функции результата парсера:

    template <typename ParserT, typename ScannerT>
    struct parser_result
    {
        typedef typename ParserT::template result<ScannerT>::type type;
    };

Это похоже на глобальную функцию, называемую функцией члена. В большинстве случаев использование выше эквивалентно:

    typename ParserT::template result<ScannerT>::type

Тем не менее, на это не следует постоянно полагаться, потому что метафункция результата анализатора может быть специализирована для конкретных типов анализатора и / или сканера.

Метафункция parser_result делает подпись требуемой функции члена parse почти канонической:

    template <typename ScannerT>
    typename parser_result<self_t, ScannerT>::type
parse(ScannerT const& scan) const;

гдеself_tпредставляет собой типдеф для парсера.

parser class declaration

    template <typename DerivedT>
    struct parser
    {
        typedef DerivedT                embed_t;
        typedef DerivedT                derived_t;
        typedef plain_parser_category   parser_category_t;
        template <typename ScannerT>
        struct result
        {
            typedef typename match_result<ScannerT, nil_t>::type type;
        };
        DerivedT& derived();
        DerivedT const& derived() const;
        template <typename ActionT>
        action<DerivedT, ActionT>
        operator[](ActionT const& actor) const;
    };


Статья In-depth: The Parser раздела может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-07-05 14:21:20/0.0056610107421875/0