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

Quickstart 2 - A better word counter using Spirit.Lex

Boost , Spirit 2.5.2 , Spirit.Lex 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

Lex Quickstart 1 - счетчик слов с использованием Spirit.Lex быть слишком сложным и не быть написанным, чтобы использовать возможности предоставляется этим инструментом. В частности, предыдущий пример не был напрямую использовать лексерные действия для подсчета строк, слов и символов. Так что Пример, приведенный на этом этапе обучения, покажет, как использовать семантический действия в Spirit.Lex. Даже несмотря на то, что эти примеры все еще Пересчитывает текстовые элементы, цель - ввести новые понятия и конфигурацию опции вдоль линий (полный пример кода см. здесь: word_count_lexer.cpp). .

Prerequisites

В дополнение к единственному требуемому #include, специфичному для Spirit.Lex этот пример должен включать в себя пару заголовков из библиотеки Boost.Phoenix. Этот пример показывает, как прикрепить фанкторы к токеновым определениям, которые могут быть сделаны с использованием любого типа C++ техники, приводящей к звонкому объекту. Использование Boost.Phoenix для этой задачи упрощает ситуацию и избегает добавления зависимостей в другие библиотеки (Boost.Phoenix уже используется для Spirit в любом случае).

#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/include/phoenix_algorithm.hpp>
#include <boost/spirit/include/phoenix_core.hpp>

Чтобы сделать весь код ниже более читаемым, мы представляем следующие пространства имен.

namespace lex = boost::spirit::lex;

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

%{
    int c = 0, w = 0, l = 0;
%}
%%
[^ \t\n]+  { ++w; c += yyleng; }
\n         { ++c; ++l; }
.          { ++c; }
%%
main()
{
    yylex();
    printf("%d %d %d\n", l, w, c);
}

Semantic Actions in Spirit.Lex

Spirit.Lex использует очень похожий способ ассоциирования действий с токенскими определениями (которые должны выглядеть знакомым всем, кто знает, с Spirit, а также): указывая операции для выполнения внутри пары [] скобы. Для того, чтобы можно было прикрепить семантические действия к токеновым определениям для каждого из них, существует пример token_def>.

template <typename Lexer>
struct word_count_tokens : lex::lexer<Lexer>
{
    word_count_tokens()
      : c(0), w(0), l(0)
      , word("[^ \t\n]+")     // define tokens
      , eol("\n")
      , any(".")
    {
        using boost::spirit::lex::_start;
        using boost::spirit::lex::_end;
        using boost::phoenix::ref;
        // associate tokens with the lexer
        this->self
            =   word  [++ref(w), ref(c) += distance(_start, _end)]
            |   eol   [++ref(c), ++ref(l)]
            |   any   [++ref(c)]
            ;
    }
    std::size_t c, w, l;
    lex::token_def<> word, eol, any;
};

Семантика показанного кода следующая. Код внутри [] скобы будут выполняться всякий раз, когда соответствующий токен будет сопоставлен лексическим анализатором. Это очень похоже на Flex, где код действия, связанный с определением токена, выполняется после распознавания соответствующей последовательности ввода. Код выше использует функциональные объекты, построенные с использованием Boost.Phoenix, но можно вставить любую функцию или функциональный объект C++, если он выставляет правильный интерфейс. Более подробную информацию см. в разделе Lexer Semantic Actions.

Associating Token Definitions with the Lexer

Если сравнивать этот код с кодом от Lex Quickstart 1 - счетчик слов с использованием Spirit.Lex в отношении того, как жетоновые определения связаны с lexer, вы заметите, что здесь используется другой синтаксис. В предыдущем примере мы использовали себя.add() стиль API, в то время как мы здесь непосредственно присваиваем токены определения себя, сочетая различные токенные определения с использованием оператора |. Вот код сниппет снова:

this->self
    =   word  [++ref(w), ref(c) += distance(_1)]
    |   eol   [++ref(c), ++ref(l)]
    |   any   [++ref(c)]
    ;

Таким образом, у нас есть очень мощный и естественный способ построения лексического анализатора. Если переводится на английский язык, это может быть прочитано как: лексический анализатор будет распознавать ('=') токены, как определено любым из ('|') токен определений word, eol, и any.

Второе отличие от предыдущего примера заключается в том, что мы явно не указываем никаких токенов для использования для отдельных токенов. Использование семантических действий для запуска некоторой полезной работы освободило нас от необходимости их определения. Для обеспечения того, чтобы каждый токен получил id Spirit.Lex библиотека внутренне присваивает уникальные номера токеновым определениям, начиная с постоянной, определенной boost::spirit<37>::lex::min_token_id.

Pulling everything together

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

int main(int argc, char* argv[])
{
1  typedef
        lex::lexertl::token<char const*, lex::omit, boost::mpl::false_>
     token_type;
2  typedef lex::lexertl::actor_lexer<token_type> lexer_type;
3  word_count_tokens<lexer_type> word_count_lexer;
4  std::string str (read_from_file(1 == argc ? "word_count.input" : argv[1]));
    char const* first = str.c_str();
    char const* last = &first[str.size()];
5  lexer_type::iterator_type iter = word_count_lexer.begin(first, last);
    lexer_type::iterator_type end = word_count_lexer.end();
6  while (iter != end && token_is_valid(*iter))
        ++iter;
    if (iter == end) {
        std::cout << "lines: " << word_count_lexer.l
                  << ", words: " << word_count_lexer.w
                  << ", characters: " << word_count_lexer.c
                  << "\n";
    }
    else {
        std::string rest(first, last);
        std::cout << "Lexical analysis failed\n" << "stopped at: \""
                  << rest << "\"\n";
    }
    return 0;
}

1

Указание omit, так как тип атрибута токена генерирует класс токенов, не держащий ни одного атрибута токена вообще (даже диапазон итератора соответствующей последовательности ввода), поэтому оптимизируя токен, лексер и, возможно, выполнение парсера как можно больше. Указание mpl::false_, поскольку параметр 3-го шаблона генерирует токен типа и итератора, оба без лексера состояния, что позволяет еще более агрессивную оптимизацию. В результате экземпляры токенов содержат идентификаторы токенов в качестве единственного члена данных.

2

Это определяет тип lexer для использования

3

Создание экземпляра объекта lexer, необходимого для применения лексического анализа

4

Прочтите вход из данного файла, токенизируйте весь вход, отбрасывая все сгенерированные токены

5

Создайте пару итераторов, возвращающих последовательность сгенерированных токенов

6

Здесь мы просто итерируем все токены, убедившись разорвать петлю, если недействительный токен вернется из лексера


PrevUpHomeNext

Статья Quickstart 2 - A better word counter using Spirit.Lex раздела Spirit 2.5.2 Spirit.Lex Tutorials может быть полезна для разработчиков на c++ и boost.




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



:: Главная :: Spirit.Lex Tutorials ::


реклама


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

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