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

Generator Semantic Actions

Boost , Spirit 2.5.2 , Tutorials

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

В предыдущем разделе мы упоминали очень важное различие между парсерами и генераторами. В то время как парсеры могут использоваться без «производства» каких-либо данных, генераторам всегда нужны данные для генерации выходных данных. Мы упомянули один из способов передачи данных генератору, предоставляя его в качестве параметра одной из основных функций API (например,<generate()>или<generate_delimited()>). Но иногда это невозможно или нежелательно.

ПодобноДуху,мы имеем смысловые действия вДухе. карматакже. Семантические действия могут быть прикреплены к любой точке грамматической спецификации. Эти действия являются функциями C++ или функциональными объектами, которые вызываются всякий раз, когда часть генератора собирается быть вызванной. Скажем, у вас есть генератор<G>и функция C++<F>, вы можете сделать вызов генератора<F>непосредственно перед его вызовом, прикрепив<F>:

G[F]

Выражение выше связывает<F>с генератором<G>.

Семантические действия вSpirit.Qiвызываются после того, как парсер успешно соответствует своему входу и сопоставленное значение передается в семантическое действие. В духе. Кармапроисходит наоборот. Семантические действия вызываются до того, как вызывается соответствующий генератор. Они могут предоставлять данные, требуемые генератором.

Сигнатура функции/функции объекта зависит от типа генератора, к которому он присоединен. Генератор<double_>ожидает, что число будет генерироваться. Таким образом, если мы прикрепим функцию<F>к<double_>, мы должны объявить<F>как:

void F(double& n);

где функция должна инициализировать параметр<n>со значением для генерации.

[Important]Important

Как правило, и более формально, семантическое действие<F>, прикрепленное к генератору<G>, должно учитывать тип атрибута генератора в качестве его первого параметра. Для получения дополнительной информации об атрибутах генератора см. раздел Атрибуты генератора.

В приведенном выше примере функция F принимает<double&>в качестве своего первого параметра, поскольку атрибутом генератора<double_>является<double>.

На самом деле, есть еще 2 аргумента (контекст генератора и ссылка на фулевый параметр «прохода»). На данный момент они нам не нужны, но мы увидим больше других аргументов позже.Дух.Кармапозволяет нам связать одну функцию аргумента, как выше. Остальные аргументы просто игнорируются.

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

void f(Attrib&);
void f(Attrib&, Context&);
void f(Attrib&, Context&, bool&);
Examples of Semantic Actions

В следующем примере представлены различные способы прикрепления семантических действий:

  • Использование простого указателя функции
  • Использование простого функционального объекта
  • ИспользованиеBoost.Bindс простой функцией
  • ИспользованиеBoost.Bindс функцией участника
  • ИспользованиеBoost.Lambda

Предположим, у нас есть:

namespace client
{
    namespace karma = boost::spirit::karma;
    // A plain function
    void read_function(int& i)
    {
        i = 42;
    }
    // A member function
    struct reader
    {
        void print(int& i) const
        {
            i = 42;
        }
    };
    // A function object
    struct read_action
    {
        void operator()(int& i, unused_type, unused_type) const
        {
            i = 42;
        }
    };
}

Обратите внимание, что с функциональными объектами мы должны иметь<operator()>с 3 аргументами. Поскольку мы не заботимся о двух других, мы можем использовать<unused_type>для них. Мы увидим больше<unused_type>в другом месте. Привыкай к этому.<unused_type>— класс поддержки, предоставляемый Духом. В большинстве случаев это означает «Мне все равно, просто используйте соответствующий по умолчанию».

Все следующие примеры генерируют выходы формы:

"{integer}"

Целое число внутри кудрявых брекетов.

Первый пример показывает, как прикрепить простую функцию:

generate(outiter, '{' << int_[&read_function] << '}');

Что нового?<int_>является родным братом<double_>. Я уверен, что вы можете догадаться, что делает этот генератор и какой атрибут он ожидает.

Следующий пример показывает, как прикрепить простой функциональный объект:

generate(outiter, '{' << int_[read_action()] << '}');

Мы можем использоватьBoost.Bindдля связывания функций членов:

reader r;
generate(outiter, '{' << int_[boost::bind(&reader::print, &r, _1)] << '}');

Также мы можем использоватьBoost.Bindдля связывания простых функций:

generate(outiter, '{' << int_[boost::bind(&read_function, _1)] << '}');

И последнее, но не менее важное: мы также можем использоватьBoost.Lambda:

std::stringstream strm("42");
generate(outiter, '{' << int_[strm >> lambda::_1] << '}');

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

The examples above can be found here: actions.cpp

Phoenix

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

[Important]Important

Существуют различные способы написания семантических действий.Дух. Карма: с использованием простых функций,Boost.Bind,Boost.LambdaилиPhoenix. Последние три позволяют использовать специальные заполнители для управления размещением параметров<_1>,<_2>и т.д. Каждая из этих библиотек имеет свою собственную реализацию заполнителей, все в разных пространствах имен. Вы должны убедиться, что не смешиваете заполнители с библиотекой, к которой они не принадлежат, и не используете разные библиотеки при написании семантического действия.

Как правило, дляBoost.Bind, использовать<::_1>,<::_2>и т. Д. (Да, эти заполнители определены в глобальном пространстве имен).

ДляBoost.Lambdaиспользуйте заполнители, определенные в пространстве имен<boost::lambda>.

Для семантических действий, написанных с использованиемФеникса, используйте заполнители, определенные в пространстве имен<boost::spirit>. Обратите внимание, что все существующие заполнители для вашего удобства также доступны из пространства имен<boost::spirit::karma>.


PrevUpHomeNext

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




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



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


реклама


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

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 20:32:06/0.0081849098205566/0