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

The Scanner and Parsing

Boost , ,

The Scanner and Parsing

Задачасканеразаключается в подаче последовательного входного потока данных в парсер. Сканер извлекает данные из ввода, посылки, потенциально модифицируя или фильтруя, а затем, наконец, отправляет результат отдельным элементам парсера по требованию, пока вход не исчерпан. Сканер состоит из двух передних итераторов STL, первого и последнего, где первый удерживается ссылкой, а последний - значением. Первый итератор удерживается путем ссылки, чтобы его можно было перепозиционировать. Следующая диаграмма иллюстрирует, что происходит:

Сканер управляет различными аспектами процесса анализа с помощью набора политик. Существует три набора политик, которые регулируют:

Итерация и фильтрация
Признание и сопоставление
Обработка семантических действий

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

сканерпредставляет собой класс шаблонов, ожидающий двух параметров:ИтераторТ, тип итератора иПолитикиТСовокупность правил.Итераторнеисправностьchar const*в то время какполитикапо умолчанию дляscanner_policies<>, предопределенный набор политик сканера, который мы можем использовать прямо из коробки.

    template<
        typename IteratorT  = char const*,
        typename PoliciesT  = scanner_policies<> >
    class scanner;

Spirit использует те же концепции итератора и интерфейс, формально определенные стандартной библиотекой шаблонов C++ (STL). Мы можем использовать итераторы, поставляемые контейнерами STL (например,список,вектор,строкаи т. д.), как есть, или, возможно, написать наш собственный. Итераторы могут быть такими же простыми, как указатель (например,char const*). На другом конце спектра итераторы могут быть довольно сложными; например, адаптер итератора, который обертывает лексер, такой как LEX.

The Free Parse Functions

Фреймворк предоставляет пару бесплатных функций, чтобы сделать разборку щелчком. Эти функции парсера имеют две формы. Первая форма работает на уровнесимволов. Вторую строчку мы видим встрокеи встроке.

скип парсер— это почти любой парсер примитивный или композитный. Его цель состоит в том, чтобы переместить первый итератор сканерана действительные токены, пропуская белые пространства. В C, например, вкладка't', новая строка'n', возврат'r', пространство''и символы внутри комментариев/*...*/рассматриваются как белые пространства.

Уравнение характеристик

    template <typename IteratorT, typename DerivedT>
    parse_info<IteratorT>
    parse
    (
        IteratorT const&        first,
        IteratorT const&        last,
        parser<DerivedT> const& p
    );
    template <typename CharT, typename DerivedT>
    parse_info<CharT const*>
    parse
    (
        CharT const*            str,
        parser<DerivedT> const& p
    );

Есть два варианта. Первый вариант принимаетпервую,последнююпару итераторов, как вы делаете алгоритмы STL. Второй вариант принимает нулевую законченную строку. Последним аргументом является парсерp, который будет использоваться для разбора входных данных.

Уровни разбора фраз

    template <typename IteratorT, typename ParserT, typename SkipT>
    parse_info<IteratorT>
    parse
    (
        IteratorT const&        first,
        IteratorT const&        last,
        parser<ParserT> const&  p,
        parser<SkipT> const&    skip
    );
    template <typename CharT, typename ParserT, typename SkipT>
    parse_info<CharT const*>
    parse
    (
        CharT const*            str,
        parser<ParserT> const&  p,
        parser<SkipT> const&    skip
    );

Как и выше, есть два варианта. Первый вариант принимаетпервую,последнююпару итераторов, как вы делаете алгоритмы STL. Второй вариант принимает нулевую законченную строку.pявляется парсером, который будет использоваться для разбора входных данных. Последний аргументskip— это skip parser.

Структура parse_info

Вышеприведенные функции возвращают структуруparse_info, параметризованную пройденным типом итератора. Структура parse_info состоит из следующих элементов:

parse_info
stop Points to the final parse position (i.e The parser recognized and processed the input up to this point)
hit True if parsing is successful. This may be full: the parser consumed all the input, or partial: the parser consumed only a portion of the input.
full True when we have a full match (i.e The parser consumed all the input).
length The number of characters consumed by the parser. This is valid only if we have a successful match (either partial or full).

The phrase_scanner_t and wide_phrase_scanner_t

Для удобства Spirit объявляет эти типдефы:

    typedef scanner<char const*, unspecified> phrase_scanner_t;
    typedef scanner<wchar_t const*, unspecified> wide_phrase_scanner_t;

Это точные типы сканеров, используемые Духом для вызовов функции разбора, проходящей вchar const*(струна C) илиwchar_t const*(широкая строка) в качестве первого параметра иspace_pв качестве пропуска-парсера (третий параметр). Например, мы можем использовать эти типдефы для объявления некоторых правил. Пример:

    rule<phrase_scanner_t> my_rule;
    parse("abrakadabra", my_rule, space_p);

Direct parsing with Iterators

Функции бесплатного анализа облегчают нам задачу. Используя их, нам не нужно беспокоиться о тонкостях сканера. Функции свободного анализа скрывают грязные детали. Однако когда-нибудь в будущем нам нужно будет попасть под капот. Приятно, что мы знаем, с чем имеем дело, когда возникает такая необходимость. Нам нужно будет перейти на низкий уровень и напрямую вызвать функцию парсера.

Если мы хотим работать на уровнесимволов, процедура довольно проста:

    scanner<IteratorT> scan(first, last);
    if (p.parse(scan))
    {
        //  Parsed successfully. If first == last, then we have
        //  a full parse, the parser recognized the input in whole.
    }
    else
    {
        //  Parsing failure. The parser failed to recognize the input
    }
The scanner position on an unsucessful match

On a successful match, the input is advanced accordingly. But what happens on an unsuccessful match? Be warned. It might be intuitive to think that the scanner position is reset to its initial position prior to parsing. No, the position is not reset. On an unsuccessful match, the position of the scanner is undefined! Usually, it is positioned at the farthest point where the error was found somewhere down the recursive descent. If this behavior is not desired, you may need to position the scanner yourself. The example in the numerics chapter illustrates how the scanner position can be saved and later restored.

Еслиpявляется парсером, который мы хотим использовать, ипервый/последнийявляются парами итератора, относящимися к входу. Мы просто создаем сканер, учитывая итераторы. Тип сканера, который мы будем использовать здесь, использует по умолчаниюscanner_policies<>.

Ситуация немного сложнее, когда мы хотим работать на уровнефразы:

    typedef skip_parser_iteration_policy<SkipT> iter_policy_t;
    typedef scanner_policies<iter_policy_t> scanner_policies_t;
    typedef scanner<IteratorT, scanner_policies_t> scanner_t;
    iter_policy_t iter_policy(skip);
    scanner_policies_t policies(iter_policy);
    scanner_t scan(first, last, policies);

    if (p.parse(scan))
    {
        //  Parsed successfully. If first == last, then we have
        //  a full parse, the parser recognized the input in whole.
    }
    else
    {
        //  Parsing failure. The parser failed to recognize the input
    }

ЕслиСкипТявляется типом скип-парсера,скип.pявляется парсером, который мы хотим использовать, ипервый/последнийявляются парами итератора, относящимися к входу. Учитывая тип пропуска-парсераSkipT,skip_parser_iteration_policyсоздает политику итерации сканера, которая пропускает части, которые распознаются пропуском-парсером. Это можно использовать для создания сканера. Классscanner_policiesохватывает все политики, связанные со сканером, включая политику итерации.

lexeme_scanner

При переходе с уровня фразы на уровень символов, lexeme_d(см.?tid=6908) делает свою магию, отключая пропуск белых пространств. Это делается путем настройки сканера. Однако, когда мы делаем это, все парсеры внутри лексемы получают преобразованный тип сканера. В большинстве случаев это не должно быть проблемой. Однако, когда правила называются внутриlexeme_d, компилятор задыхается, если правило не имеет правильного типа сканера. Если правило должно использоваться внутриlexeme_d, то тип правила должен быть:

    rule<lexeme_scanner<ScannerT>::type> r;

гдеScannerTявляется фактическим типом используемого сканера. Обратите внимание, чтоlexeme_scannerбудет работать только для сканеров уровня фраз.

as_lower_scanner

Аналогично,as_lower_dвыполняет свою работу путем фильтрации и преобразования всех символов, полученных от сканера, в нижний регистр. Это также делается путем настройки сканера. Затем все парсеры внутрикак_lower_dполучают преобразованный тип сканера. Если правило должно использоваться внутрикак_lower_d, то тип правила должен быть:

    rule<as_lower_scanner<ScannerT>::type> r;

гдеScannerTявляется фактическим типом используемого сканера.

See the techniques section for an example of a grammar using a multiple scanner enabled rule, lexeme_scanner and as_lower_scanner.

no_actions_scanner

Опять же, директиваno_actions_dнастраивает сканер для отключения семантических действий. Как и раньше, все парсеры внутриno_actions_dполучают преобразованный тип сканера. Если правило должно использоваться внутриno_actions_d, то тип правила должен быть:

    rule<no_actions_scanner<ScannerT>::type> r;

гдеScannerT- фактический тип используемого сканера.

Be sure to add "typename" before lexeme_scanner, as_lower_scanner and no_actions_scanner when these are used inside a template class or function.

См.no_actions.cpp. Это часть духовного распределения.



 

 

Статья The Scanner and Parsing раздела может быть полезна для разработчиков на c++ и boost.




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



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


реклама


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

Время компиляции файла: 2024-08-30 11:47:00
2025-05-20 04:04:42/0.0058660507202148/0