LINUX.ORG.RU

Пытаюсь читать исходники boost::spirit.


0

3

Встречаю такую конструкцию:

    // Our extended terminals
    BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(
        ( lit, lit_type )
        ( bin, bin_type )
        ( oct, oct_type )
        ( hex, hex_type )
        ( bool_, bool_type )
        ( ushort_, ushort_type )
        ( ulong_, ulong_type )
        ( uint_, uint_type )
        ( short_, short_type )
        ( long_, long_type )
        // ещё куча таких строк //
     )

Я не стал копаться в глубинах макроса BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX, состоящего из тыщи других макросов, а застрял на увиденном.

Что это за разделённые переводами строки пары слов в скобках? Что это такое, синтаксически? Это какая-то фича макроязыка, типа список на макроязыке?

Я не стал копаться в глубинах макроса BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX, состоящего из тыщи других макросов, а застрял на увиденном.

А зря. Я его вижу первый раз в жизни, но там идея вполне ясна.

Что это за разделённые переводами строки пары слов в скобках? Что это такое, синтаксически? Это какая-то фича макроязыка, типа список на макроязыке?

Типа того. Фишка в том, препроцессор агрится не на все запятые, чтобы разделить строку на аргументы. Запятые, находящиеся в круглых скобках, не считаются. Поэтому FOO((a1, b1) (a2, b2) (a3, b3))[/ine] на самом деле принимает один аргумент.

Потом идёт жуткая херь в стиле буста, чтобы раскрыть это в BAR((a1, b1)) (a2, b2) (a3, b3). Который в итоге раскрывается в HUX(a1, b1) HUX(a2, b2) HUX(a3, b3) и так далее.

Как именно они это делают, я пока ещё не понял.

ilammy ★★★
()
#!/bin/bash

for m in BOOST_SPIRIT_DEFINE_TERMINALS_NAME \
         BOOST_PP_SEQ_FOR_EACH \
         BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A \
         BOOST_PP_CAT \
         BOOST_SPIRIT_TERMINAL_NAME \
         BOOST_SPIRIT_IS_TAG; do
  echo ""
  echo '#include <boost/spirit/home/support/terminal.hpp>

#undef '"$m"'
#define '"$m $m"'
Disabled macro: '"$m"'
BOOST_SPIRIT_DEFINE_TERMINALS_NAME(
    ( verbatim, verbatim_type )
    ( no_delimit, no_delimit_type )
)

' > main.cpp
  g++ -E main.cpp 2>/dev/null | sed -n '/Disabled macro:/,$p'
done

rm -rf main.cpp
anonymous
()
Ответ на: комментарий от ilammy

Всё упёрлось попытку понять, как они делают это раскрытие. Это какая-то либа, написанная суровыми финскими геймдевщиками. Там есть всякие макро-понятия sequence, array, list с блек джеком и шлюхами.

То есть, я не понимаю, как работает ()()()()()()().

kiverattes ★☆
() автор топика
Последнее исправление: kiverattes (всего исправлений: 1)
Ответ на: комментарий от kiverattes

Открыл вот такое явление в природе:

#define A(x, y) ((a ## x, A ## y))B
#define B(x, y) ((b ## x, B ## y))A

Оно превращает

// вход
A(1,2)(3,4)(5,6)(7,8)

// выход
((a1, A2))((b3, B4))((a5, A6))((b7, B8))A

// вход
A(1,2)(3,4)(5,6)(7,8)(9,10)

// выход
((a1, A2))((b3, B4))((a5, A6))((b7, B8))((a9, A10))B

Как может работать ()()()()() частично понятно, что с этим делать неясно пока.

kiverattes ★☆
() автор топика
Ответ на: комментарий от kiverattes

Нашёл вот такую байдень.

#define BOOST_SPIRIT_TERMINAL_X(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_Y
#define BOOST_SPIRIT_TERMINAL_Y(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_X
#define BOOST_SPIRIT_TERMINAL_X0
#define BOOST_SPIRIT_TERMINAL_Y0

Она делает то же, что мой код выше - перемалывает последовательность ()()()(), как-бы переставляя очередную () вперёд и отдавая оставшуюся часть остальному макросу, который делает то же самое и вызывает первый макрос обратно.

Я не понимаю, как оно останавливается. В конце новой (переработанной) последовательности всегда остаётся имя одного из макросов.

kiverattes ★☆
() автор топика
Ответ на: комментарий от anonymous

Ах да, лошади кушают овёс и сено. Тоже тайна, почему они это делают. Наверное прочитали где-то, что так надо.

anonymous
()
Ответ на: комментарий от kiverattes

Блин, дошло.

Смотрим на макрос из первого топика:

    BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(
        ( lit, lit_type )
        ( bin, bin_type )
        ( oct, oct_type )
        ( hex, hex_type )
        ( bool_, bool_type )
        ...
   )

он определён так:

#define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(seq)                              \
    BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A, _,           \
        BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0))                           \
    /***/

Тут интересна последняя строка:
seq - это последовательность (a,b)(a,b)(a,b).
BOOST_SPIRIT_TERMINAL_X - это вышеописанная парочка тянитолкай:

#define BOOST_SPIRIT_TERMINAL_X(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_Y
#define BOOST_SPIRIT_TERMINAL_Y(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_X
#define BOOST_SPIRIT_TERMINAL_X0
#define BOOST_SPIRIT_TERMINAL_Y0

Тут четыре строки. Первая берёт (x,y), выдаёт ((x,y)) BOOST_SPIRIT_TERMINAL_Y. BOOST_SPIRIT_TERMINAL_Y - это макрос из второй строки, который делает то же самое, но в конце ставит снова имя макроса из первой строки. Так они друг друга херачат, то есть на псевдокоде это можно записать так:

// вход: (1,2)(3,4)(5,6)
BOOST_SPIRIT_TERMINAL_X(1,2)(3,4)(5,6)
((1,2)) BOOST_SPIRIT_TERMINAL_Y(3,4)(5,6)
((1,2))((3,4)) BOOST_SPIRIT_TERMINAL_X(5,6)
((1,2))((3,4))((5,6)) BOOST_SPIRIT_TERMINAL_Y

В конце остаётся висеть имя одного из макросов (в зависимости от чётности количества элементов последовательности. Что с ним делать? Смотрим во второй code-сниппет данного сообщения, где написано BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0)). Что такое BOOST_PP_CAT? Это макрос, который тупо через ## соединяет свой первый аргумент с 0. Получается, к нашему хвосту в конец дописывается 0:

((1,2))((3,4))((5,6)) BOOST_SPIRIT_TERMINAL_Y0
а макрос BOOST_SPIRIT_TERMINAL_Y0 определён как пустой макрос. То есть, таким образом, BOOST_SPIRIT_TERMINAL_Y0 просто удаляется, остаётся ((1,2))((3,4))((5,6)).

То есть, (1,2)(3,4)(5,6) перемолотилось в ((1,2))((3,4))((5,6)). Но от этого не легче )

kiverattes ★☆
() автор топика
Ответ на: комментарий от dimon555

В бусте практически отсутствует ООП - только макросы и шаблоны, только хардкор

annulen ★★★★★
()
Последнее исправление: annulen (всего исправлений: 2)
Ответ на: комментарий от kiverattes

Я незнаю как к этому относиться. Кто-то ведь написал это, значит это я тупой, а не C++ сложный.

Вопрос на тему макросов отвлечённый. Какой смысл делать макросы-функции без аргументов? Типа

#define ZUZUZU() AA(A0, A1) BB(B0, B1)

Почему нельзя было написать

#define ZUZUZU AA(A0, A1) BB(B0, B1)

kiverattes ★☆
() автор топика
Ответ на: комментарий от kiverattes

Ну очевидно же, чтобы нельзя было написать

ZUZUZU(superargument)

А вообще ты прав в твоих догадках.

anonymous
()
Ответ на: комментарий от anonymous

Ты мозг. Мне не очевидно. То есть, ZUZUZU даст приписать к себе скобки, а ZUZUZU() скажет «чё суёшь, урод, мля, не видишь я без аргументов»?

kiverattes ★☆
() автор топика
Ответ на: комментарий от anonymous

Кстати, эти «переданные аргументы» никуда не пропадут, а будут рассматриваться компилятором как самостоятельное выражение.

anonymous
()
Ответ на: комментарий от kiverattes

Можно глянуть на более документированный пример использования такого синтаксиса: BOOST_PP_SEQ_FOR_EACH

Иногда весьма удобно.

ratatosk
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.