Некоторые термины, используемые в исходном коде (Обратите внимание на
двойной смысл):
- macro: Объекты #defined / #macro которые будут расширены
заменяемым текстом
- macro: макрос похож на функцию #define m(a, b)
- define: однострочный объект #define simple
- argless define (должен быть вызван без параметров): макрос как
функция без параметров #define f()
Как хранятся макросы
Макросы в основном хранятся как необработанный текст, а
не как работающий маркер (как например , в libcpp GCC). Тело простого
#defines без параметров сохранено как одна строка. Макросы с параметрами
хранятся как последовательность "макро-маркеров". Есть три типа
макро-маркеров:
Необработанный текст, но пробелы и пустые строки обрезаны (как в #define
без параметров)
То же самое, только для ввода Unicode.
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 b
#define b a
a
но не здесь: (Обратите внимание, что FBC будет работать в
бесконечном цикле)
#define a a
#define m a
m
Примечание: Если вы что-то поняли на этой странице, то я вас поздравляю