Макрос
 

Некоторые термины, используемые в исходном коде (Обратите внимание на двойной смысл):
  • macro: Объекты #defined / #macro которые будут расширены заменяемым текстом
  • macro: макрос похож на функцию #define m(a, b)
  • define: однострочный объект #define simple
  • argless define (должен быть вызван без параметров): макрос как функция без параметров  #define f()

Как хранятся макросы

Макросы в основном хранятся как необработанный текст, а не как работающий маркер (как например , в libcpp GCC). Тело простого #defines без параметров сохранено как одна строка. Макросы с параметрами хранятся как последовательность "макро-маркеров". Есть три типа макро-маркеров:
    • text("<text>")
Необработанный текст, но пробелы и пустые строки обрезаны (как в #define без параметров)
    • textw("<wstring text>")
То же самое, только для ввода Unicode.
    • parameter(index)
parameter макроса использовался здесь для объявления. Индекс(index) указывает, какой именно. Во время расширения, текст аргумента (index) вставляется где параметр был в декларации.
    • stringify_parameter(index)
То же как выше, кроме параметра, который будет строковым соединителем во время расширения.
Примечание: макро-маркеры - фактически symb.bi:FB_DEFTOK структуры, и они содержат идентификатор поля значения FB_DEFTOK_TYPE_*, чтобы указать то, что они содержат.

Для примера:

	#define add(x, y) x + y

станет:

	parameter(0), text(" + "), parameter(1)

И текстовое расширение будет:

	argument(0) + " + " + argument(1)
Хранение макросов как текст - довольно простая реализация, но все же это требует многоразовый повторный анализ тела макроса. Например, так как GCC работает с предварительной обработкой маркеров и запущенных маркеров, макросы хранятся в виде маркеров, делая расширение очень быстрым, в итоге нет никакой потребности маркировать тело макроса снова и снова. Реализация fbc не так гибка и возможно не так эффективна, но менее сложна (относительно управления кодом и управления памятью) и имеет потенциал роста тоже: Реализация ## (маркерное слияние PP) тривиальна. ## просто опущен при записи тела макроса, тогда как в работающем маркере , маркеры должны быть объединены явно.

Когда раскрываются макросы?

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

В lexNextToken (), каждый алфавитно-цифровой идентификатор ищется в symb модуле, чтобы проверить, является ли это ключевым словом или макросом. Макросы и ключевые слова сохранены в той же хэш-таблице. Обратите внимание на то, что у макросов не может быть имени как у ключевых слов; "#define Integer" вызовет ошибку. Если макрос обнаружен, он сразу расширяется, процесс также вызывает "загрузку" макроса (pp-define.bas:ppDefineLoad()).

Макрос вызов парсинга

Если макрос принимает параметры, "вызов" макроса должен быть проанализирован, во многом как вызов функции. Так как макрорасширение уже происходит в lexNextToken(), разбор источника лексем здесь немного сложнее. Движение вперед является возможным только путем замены (и потери) текущего маркера. Нельзя полагаться на маркеры очереди при дальнейшем просмотре. Можно только заменить текущий маркер , просматривая впереди и разбирая аргументы макроса.

lexNextToken() используется, чтобы проанализировать параметры. Макросы в самих параметрах рекурсивно макрорасширены, в то время как параметры проанализированы и зарегистрированы в текстовой форме. Тексты параметра сохранены для использования во время расширения.

Так, параметры макроса расширены, прежде чем тот макрос сам будет расширен, это может рассматриваться в качестве положительной и отрицательной функции:

#define stringify(s) #s
stringify(__LINE__)
результаты во 2 линии в FB, но __LINE__ в C, потому что в C параметры макроса не расширены, когда используется с # или ##. В C два макроса должны использоваться:

#define stringize(s) #s
#define stringify(s) stringize(s)
stringify(__LINE__)

Соединение текста макрорасширения

Текст расширения — это построение строки из маркеров тела макроса. Для параметров макроса, текст параметра берется из массива параметров, создаваемого вызовом парсера макросов, используя индексы, сохраненные в параметрах маркера. Параметр стрингификации делается здесь.

Есть специальные для построения определений (__LINE__, __FUNCTION__, __FB_DEBUG__, и др.):
Обратный вызов используется, чтобы получить их "значение". Например: обратный вызов __LINE__ просто возвращает строку, содержащую текущий номер строки лексического анализатора.

Расширение

Текст макрорасширения (deftext) сохраняется лексером, и теперь он будет читать символы оттуда некоторое время, вместо того, чтобы читать из входного буфера файла. Пропуск символов в тексте макроса это как пропуск символов в файле ввода: После того, как пропущено это потеряно, нет никакого возврата. Так, там никогда не бывает "старого" (проанализированного) макро-текста, только текущий символьный и проанализированный на будущее образ текста. Новый макро-текст добавляется к передней части существующего макро-текста. Таким путем макросы в макросах расширены.

Эта реализация не до конца позволяют выявить макро рекурсии. Было бы трудно отслеживать, какие символы в буфере текста макроса принадлежат какому макросу, хотя это вроде как необходимо, чтобы иметь возможность продвинуть и вытолкать макросы должным образом. Это могло быть сделано более легко с символически выполненной реализацией, как замечено в libcpp GCC. Однако, C не позволяет рекурсивные макросы: В C идентификатор макроса неопределен (не инициировано расширение) в теле макроса. Это не в случае с fbc, потому что (опять же) не реализован способ определить, когда заканчивается тело макроса.

В настоящее время fbc только отслеживает первый расширенный макрос (верхнего уровня), это просто обнаружить. Конец определенного макроса достигнут как только больше нет макро-текста.

Вот почему рекурсия обнаружена здесь:

#define a a
a
и здесь тоже:

#define a b
#define b a
a
но не здесь: (Обратите внимание, что FBC будет работать в бесконечном цикле)

#define a a
#define m a
m


Примечание: Если вы что-то поняли на этой странице, то я вас поздравляю