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

Subrules

Boost , ,

Subrules

Дух реализуется с использованием шаблонов выражения. Это очень мощная техника. Наряду с его мощью возникают некоторые осложнения. Мы почти считаем само собой разумеющимся, что когда мы пишемi | j >>k, гдеi,jиkявляются целыми числами, результат все еще является целым числом. Тем не менее, с шаблонами выражения, то же самое выражениеi | j >>k, гдеi,jиkимеют типT, в результате получается сложный составной тип [см.Основные понятия]. Духовные выражения, представляющие собой комбинации примитивов и композитов, дают бесконечное множество новых типов. Одна из проблем заключается в том, что C++ не предлагает простой возможности для вывода типа произвольно сложного выражения, которое дает сложный тип. При этом легко написать:

    int r = i | j >> k; // where i, j, and k are ints

Шаблоны выражения дают бесконечный запас типов. Без правилав C++ нет простого способа сделать это, еслиi,jиkявляются парсерами Духа:

    <what_type???> r = i | j >> k; // where i, j, and k are Spirit parsers

Еслиi,jиkявляютсяобъектамиchlit< >, мы хотим:

    typedef
        alternative<
            chlit<>      //  i
          , sequence<
                chlit<>  //  j
              , chlit<>  //  k
            >
        >
    rule_t;
    rule_t r = i | j >> k; // where i, j, and k are chlit<> objects

Мы намеренно отформатировали объявление типа, чтобы сделать его понятным. Попробуйте это с более сложным выражением. Хотя это может быть сделано, явное изложение типа шаблона выражения Духа утомительно и подвержено ошибкам. Правая сторона (rhs) должна отражать тип левой стороны (lhs).Но если вы все еще хотите сделать это, см. этоссылкадля техники.

тип и авто

Некоторые компиляторы уже поддерживаюттипключевое слово. Это может быть использовано, чтобы освободить нас от необходимости явно вводить тип (намеренно каламбур). Используятип, мы можем переписать выражение Духа выше как:

<typeof><><(i |j>> k)r =i| j>>k;>



Хотя это лучше, чем явно объявлять сложный тип, он избыточный, подвержен ошибкам и все еще болен для глаз. Выражение набирается дважды. Единственный способ упростить это - ввести макрос (см. эту ссылкудля получения дополнительной информации).

Дэвид Абрахамспредложил в comp.std.c++ повторно использовать ключевое словоautoдля вычисленных по типу переменных. Об этом говорится на сайте boost.org. Пример:

<auto><r =i| j>>k;>

Как только такое расширение C++ будет принято в стандарт, это будет аккуратное решение и отлично подходит для нашей цели. Это не полное решение, хотя, поскольку есть все еще ситуации, когда мы не знаем заранее, например, когда предварительное объявление циклических зависимых правил.

К счастью, на помощь приходят правила. Правила могут фиксировать тип выражения, присвоенного ему. Таким образом:

    rule<> r = i | j >> k;  // where i, j, and k are chlit<> objects

Это может быть не очевидно, но за кулисами простые правила фактически реализуются с использованием указателя на полиморфный абстрактный класс во время выполнения, который содержит динамический тип парсера, назначенного ему. Когда выражение Духа приписывается правилу, его тип инкапсулируется в конкретный подкласс абстрактного класса. Функция виртуального разбора делегирует разбор инкапсулируемому объекту.

Однако правила имеют недостатки:

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

Static rules: subrules

Подправило является полностью статичной версией правила. Подправило не имеет недостатков, перечисленных выше.

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

    template<int ID, typename ContextT = parser_context<> >
    class subrule;

Первый параметр шаблона дает подправилу идентификационный тег. Как правило, есть параметр шаблона ContextT, который по умолчанию<parser_context>. Вам не нужно беспокоиться о параметре шаблонаContextT, если вы не хотите настроить поведение подправила на низком уровне. Подробная информация о параметре шаблонаContextTпредставленав другом месте.

Выше представлен публичный API. ПослеContextTможет быть больше параметров шаблона. Все, что послеContextTпараметра не должно беспокоить клиента и предназначено исключительно для внутреннего использования.

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

    struct calculator : public grammar<calculator>
    {
        template <typename ScannerT>
        struct definition
        {
            definition(calculator const& self)
            {
                first =
                (
                    expression  = term >> *(('+' >> term) | ('-' >> term)),
                    term        = factor >> *(('*' >> factor) | ('/' >> factor)),
                    factor      = integer | group,
                    group       = '(' >> expression >> ')'
                );
            }
            subrule<0>  expression;
            subrule<1>  term;
            subrule<2>  factor;
            subrule<3>  group;
            rule<ScannerT> first;
            rule<ScannerT> const&
            start() const { return first; }
        };
    };

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

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

Однако подправило не является панацеей. Подправила сильно толкают компилятор C++ на колени. Например, текущие компиляторы имеют предел глубины рекурсии, который не может быть превышен. Даже не думайте о написании полной паскалевой грамматики, используя только подправила. Грамматика, использующая подправила, представляет собой одно выражение C++. Современные компиляторы C++ не очень хорошо справляются со сложными выражениями. Наконец, для того, чтобы стать держателем подправил, по-прежнему необходимо четкое правило.

Приведенный выше код является хорошим примером рекомендуемого способа использования подправил. Обратите внимание на иерархию. У нас есть грамматика, которая инкапсулирует весь калькулятор. Правило старта — это простое правило, которое содержит набор подправил. Подправила, в свою очередь, определяют фактические детали грамматики.

Template instantiation depth

Spirit pushes the C++ compiler hard. Current C++ compilers cannot handle very complex heavily nested expressions very well. One restricting factor is the typical compiler's limit on template recursion depth. Some, but not all, compilers allow this limit to be configured.

g++'s maximum can be set using a compiler flag: -ftemplate-depth. Set this appropriately if you have a relatively complex grammar.

Microsoft Visual C++ can take greater than 1000 for both template class and function instantiation depths. However, the linker chokes with deep template function instantiation unless inline recursion depth is set using these pragmas:

#pragma inline_depth(255)
#pragma inline_recursion(on)

Perhaps this limitations no longer applies to more current versions of these compilers. Be sure to check your compiler documentation.

Эта установка обеспечивает хороший баланс. Подзаконные акты выполняют всю работу. У каждой грамматики есть только одно правило:первое. Правило используется только для того, чтобы удерживать подправила и делать их видимыми для грамматики.

The subrule definition

Как и правило, выражение после назначения оператора=определяет подправило:

    identifier = expression

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

Separators [ , ]

При этом правила прекращаются полуколоном';'. Подправила не прекращаются, а разделяются запятой:',. Как и заявления Паскаля, последнее подправило в группе может не иметь запятой.

    a = ch_p('a'),
    b = ch_p('b'),
    c = ch_p('c'), // BAD, trailing comma

<

  a=ch_p('a'),
   b=ch_p('b'),
   c=ch_p('c') // OK
>

Стартовое правило

В отличие от правил, парсинг исходит из начального подправила. Первое (самое верхнее) подправило в группе подправил называетсястартовым подправилом. В приведенном выше примеревыражениеявляется начальным подправилом. При вызове группы подправил первым называется выражение начального подправила.

IDs

Каждое подправило имеет соответствующий идентификатор; интегральную константу, которая однозначно определяет подправило. Приведенный выше пример имеет четыре подправила. Они объявляются как:

    subrule<0>  expression;
    subrule<1>  term;
    subrule<2>  factor;
    subrule<3>  group;

Aliases

Можно иметь подправила с аналогичными идентификаторами. Подправило с аналогичным идентификатором будет псевдонимом другого. Оба подправила могут использоваться взаимозаменяемо.

    subrule<0>  a;
    subrule<0>  alias;  // alias of a

Groups: scope and nesting

Сфера действия подправила и его определение — это замкнутая группа, обычно (и по соглашению), заключенная в скобки. Идентификаторы за пределами области не видны напрямую. Внутренние подгруппы могут быть вложены путем включения каждой подгруппы в другой набор скобок. Каждая группа уникальна и действует самостоятельно. Следовательно, хотя это может быть нецелесообразно, подправило в группе может иметь тот же идентификатор, что и подправило в другой группе, поскольку обе группы независимы друг от друга.

    subrule<0> a;
    subrule<1> b;
    subrule<0> c;
    subrule<1> d;
    (                       // outer subrule group, scope of a and b
        a = ch_p('a'),
        b =
        (                   // inner subrule group, scope of b and c
            c = ch_p('c'),
            d = ch_p('d')
        )
    )

Подправила должны быть уникальными только в группе. Грамматика — это неявная группа. Кроме того, даже подправила в грамматике могут иметь одинаковые идентификаторы без столкновения, если они находятся внутри группы. Подправила могут быть явно сгруппированы с использованием скобок. Парентезированные группы имеют уникальные области применения. В приведенном выше коде группа внешних подправил определяет подправилаaиb, в то время как группа внутренних подправил определяет подправилаcиd. Обратите внимание, что определениеbявляется внутренним подправилом.



 

<>

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




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



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


реклама


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

Время компиляции файла: 2024-08-30 11:47:00
2025-05-20 06:33:15/0.0087699890136719/1