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

Semantic Actions

Boost , ,

Semantic Actions

Семантические действия имеют форму:выражение[действие]

В конечном счете, после того, как мы определили нашу грамматику и создали соответствующий парсер, нам нужно будет произвести некоторый вывод и выполнить некоторую работу, помимо синтаксического анализа; если, конечно, мы не хотим просто проверить соответствие ввода нашей грамматике, что очень редко бывает. Семантические действия могут быть прикреплены к любому выражению на любом уровне иерархии парсера. Действие - это функция или объект функции C/C++, который будет называться, если совпадение найдено в конкретном контексте, где оно прикреплено. Функция действия служит крюком в парсере и может использоваться, например:

Генерировать выход из парсера (например, АСТ)
Предупреждения или ошибки
Управление таблицами символов

Generic Semantic Actions (Transduction Interface)

Общим семантическим действием может быть любая свободная функция или объект функции, совместимый с интерфейсом:

    void f(IteratorT first, IteratorT last);

гдеИтератор- тип используемого итератора,первыйуказывает на текущий вход ипоследнийуказывает на один после окончания входа (идентичный диапазонам итератора STL). Объект функции (функционер) должен иметь участникаоператора().с той же подписью, что и выше:

    struct my_functor
    {
        void operator()(IteratorT first, IteratorT last) const;
    };

Итераторы, указывающие на соответствующую часть входа, передаются в функцию/функтор.

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

Example:

    void
    my_action(char const* first, char const* last)
    {
        std::string str(first, last);
        std::cout << str << std::endl;
    }
    rule<> myrule = (a | b | *(c >> d))[&my_action];

Функцияmy_actionбудет называться всякий раз, когда выражение(a | b | * (c >>d)соответствует части входного потока при разборе. Два итератора,первыйипоследний, переходят в функцию. Эти итераторы указывают на начало и конец, соответственно, части входного потока, где находится совпадение.

Const-ness:

С помощью функторов обратите внимание, что оператордолжен бытьconst. Это означает, что функторы неизменны. Можно захотеть иметь некоторые переменные, которые изменяются при вызове действия. Это не очень хорошая идея. В первую очередь, функторы предпочтительно легкие. Функторы часто проходят вокруг, и это повлечет за собой много накладных расходов, если функторы сильно нагружены. Во-вторых, функторы передаются по стоимости. Таким образом, фактический объект функтора, который, наконец, прикрепляется к парсеру, не будет оригинальным экземпляром, предоставленным клиентом. Это означает, что изменения в состоянии функтора не повлияют на исходный функтор, который прошел клиент, поскольку они являются отдельными копиями. Если функтору необходимо обновить некоторые переменные состояния, что часто бывает, то лучше использовать ссылки на внешние данные. Следующий пример показывает, как это можно сделать:

    struct my_functor
    {
        my_functor(std::string& str_)
        : str(str_) {}
        void
        operator()(IteratorT first, IteratorT last) const
        {
            str.assign(first, last);
        }
        std::string& str;
    };

Full Example:

Вот наш калькулятор, усиленный семантическими действиями:

    namespace
    {
        void    do_int(char const* str, char const* end)
        {
            string  s(str, end);
            cout << "PUSH(" << s << ')' << endl;
        }
        void    do_add(char const*, char const*)    { cout << "ADD\n"; }
        void    do_subt(char const*, char const*)   { cout << "SUBTRACT\n"; }
        void    do_mult(char const*, char const*)   { cout << "MULTIPLY\n"; }
        void    do_div(char const*, char const*)    { cout << "DIVIDE\n"; }
        void    do_neg(char const*, char const*)    { cout << "NEGATE\n"; }
    }

Мы дополняем нашу грамматику смысловыми действиями:

    struct calculator : public grammar<calculator>
    {
        template <typename ScannerT>
        struct definition
        {
            definition(calculator const& self)
            {
                expression
                    =   term
                        >> *(   ('+' >> term)[&do_add]
                            |   ('-' >> term)[&do_subt]
                            )
                    ;
                term =
                    factor
                        >> *(   ('*' >> factor)[&do_mult]
                            |   ('/' >> factor)[&do_div]
                            )
                        ;
                factor
                    =   lexeme_d[(+digit_p)[&do_int]]
                    |   '(' >> expression >> ')'
                    |   ('-' >> factor)[&do_neg]
                    |   ('+' >> factor)
                    ;
            }
            rule<ScannerT> expression, term, factor;
            rule<ScannerT> const&
            start() const { return expression; }
        };
    };

Кормление в выражении(-1 + 2) * (3 + -4), например, по правилувыражениедаст ожидаемый выход:

-1
2
ADD
3
-4
ADD
MULT

Что, кстати, и есть Обратная польская нотация (РПН) данного выражения, напоминающая некоторые примитивные калькуляторы и язык Форт.

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

Specialized Actions

В общем, семантические действия принимают пару первого итератора. Существуют ситуации, когда мы можем захотеть передать данные в обработанной форме. Конкретным примером является числовой парсер. Неразумно передавать необработанные данные в семантическое действие, прикрепленное к числовому парсеру, и просто выбрасывать то, что было проанализировано парсером. Мы хотим передать фактический парсированный номер.

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

Unless explicitly stated in the documentation of a specific parser type, parsers not included in the list by default expect the generic signature as explained above.

Numeric Actions

Применяется к:

uint_p
int_p
ureal_p
real_p

Подпись для функций:

    void func(NumT val);

Подпись для функторов:

    struct ftor
    {
        void operator()(NumT val) const;
    };

ГдеNumT- любой примитивный числовой тип, такой какint,long,float,doubleи т.д., или пользователь, определенный числовой тип, такой как big_int.NumT- это тот же тип параметра шаблона, который используется дляuint_p,int_p,ureal_pилиreal_p. Парсируемое число передается в функцию/функтор.

Character Actions

Применяется к:

chlit, ch_p
range, range_p
anychar
alnum, alpha
cntrl, цифровая
граф, нижняя
печать, пунктирная
пространство, верхняя
xdigit

Подпись для функций:

    void func(CharT ch);

Подпись для функторов:

    struct ftor
    {
        void operator()(CharT ch) const;
    };

гдеCharT- значение_тип итератора, используемого при парсинге. Например, итераторchar const*имеетзначение_типchar. Соответствующий символ передается в функцию/функтор.

Cascading Actions

Действия могут быть каскадными. Каскадные действия также наследуют функциональный интерфейс оригинала. Например:

    uint_p[fa][fb][fc]

Здесь функторыfa,fbиfcвсе ожидают подписиvoid operator()(неподписанный n) const.

Directives and Actions

Директивы наследуют функциональный/функциональный интерфейс субъекта, который они охватывают. Пример:

    as_lower_d[ch_p('x')][f]

Здесь функторfожидает подписьvoid operator()(char ch) const, предполагая, что используемый итератор являетсяchar const*.



 

 

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




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



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


реклама


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

Время компиляции файла: 2024-08-30 11:47:00
2025-05-20 04:49:28/0.0072159767150879/1