Макроопределение и макрорасширение

Макроопределение – это описание, которое связывает некий текст с его именем. Например:

Считалка MACRO

Раз, Два, три, четыре, пять

Всем ребятам надо спать.

ENDM

Здесь «Считалка» - это имя макроопределения ( «макроса»), а всё, что находится во второй и третьей строках макроопределения называется «телом макроса». Компилятор ML.EXE имеет в своей функциональности встроенную подсистему «макрогенератор» (иногда употребляется термин «препроцессор», особенно в англоязычных источниках), которая выполняет всю работу с макросами. Эта работа выполняется перед тем, как включается транслятор, который потом переводит текст исходника в машинный числовой формат.

Самое основное, что делает макрогенератор – он при обработке исходного текста сначала выполняет макрорасширения. Макрорасширение – это ЗАМЕНА встретившегося в исходнике имени макроса на его тело. То есть, если в исходнике во многих местах встретилась строка («макровызов»)

Считалка

то ее каждое вхождение будет стёрто, а вместо него везде будет подставлено

Раз, Два, три, четыре, пять

Всем ребятам надо спать.

Параметризация макросов

Макросы могут иметь формальные строковые параметры, которые перечисляются в строке заголовка после слова MACRO через запятую. Например, приведенное выше макроопределение можно переделать в параметризованное так.

Считалка MACRO парам1, п2, па3, параметр4, п5

парам1, п2, па3, параметр4, п5

Всем ребятам надо спать.

ENDM

Тогда при макровызове можно задать фактические параметры, которые будут подставлены на место формальных при макрорасширении:

Считалка Мы , , устали, , танцевать

будет преобразована макрогенератором в макрорасширение:

Мы,, устали,, танцевать

Всем ребятам надо спать.

Обратите внимание, что здесь второй и четвертый фактический параметры заданы пустыми. Фактический параметр заменяет в теле макроопределения формальный по принципу «строка заменяет строку».

Уникальность меток при макрорасширениях

В макросах могут встречаться метки. Вот, например, макрос, который устанавливает флаги процессора в соответствии со значением параметра, а затем, если флаг знака S != 1 (старший бит равен 0, это значит, что если число рассматривать как знаковое, то оно положительное), то следует «перепрыгивание» на метку (число положительное, делать ничего не надо), а иначе число преобразуется в такое же, но с противоположным знаком. Короче, это вычисление абсолютной величины параметра:

Absval MACRO param

test param, param

jns metka

neg param

metka:

EMDM

В этом макросе кроется принципиальная ошибка. Суть её в том, что сколько раз будет произведена макрорасширение Absval, столько раз в исходный текст будет подставлена метка metka: . Мы помним, что метки – это адресные константы, равные адресу (смещению) метки в секции кода. Если в программе окажутся одинаковые метки в разных местах программы, то компилятор не разберётся с этой проблемой: у адресной константы не может быть одновременно несколько разных значений. Результат очевиден – компиляция прерывается с ошибкой «Повторяющиеся метки».

Выход из этой ситуации прост. Пусть макрогенератор сам «выдумывает» уникальные имена меток при выполнении макрорасширений. Чтобы он это стал делать, надо объявить встречающиеся в теле макроса метки как «локальные». Это надо написать сразу после заголовка макроопределения:

Absval MACRO param

LOCAL metka

test param, param

jns metka

neg param

metka:

EMDM

Теперь макровызов Absval EDX будет расширено в

test EDX, EDX

jns ??0000

neg EDX

??0000:

Второй макровызов, пусть это будет Absval AL,будет расширен в

test AL, AL

jns ??0001

neg AL

??0001:

Имена ??0000 и ??0001 – это и есть уникальные имена меток, которые сочинил сам макрогенератор. Компилятор образует их из буквенной строки «??» и лепит справа символьную 16-ричную запись номера метки в диапазоне от 0000 до FFFF. (Известно, что символ ? в ассемблере рассматривается как буква, поэтому искусственные имена ??0000, ??0001 и т.д. синтаксически совершенно корректны). Номер увеличивается на 1 при каждом новом макрорасширении. Поучается, что макрогенератор в одной программе способен создать 0FFFFh = 65536 искусственных меток. Такое возможное их количество перекрывает все мыслимые практические потребности.

Макроконстанты

Макроконстанта определяется с помощью ключевого слова EQU (от слова equivalence – равносильно). Например

One equ 2*3

Username equ 1024/8

Понимать это нужно так: макрогенератор строку «One» везде заменит на результат вычисления выражения 2*3, а строку «Username» - на результат вычисления выражения 1024/8. Единожды определив такие числовые макроконстанты, переопределить их потом нельзя. Замены имён макроконстант на строки-значения производятся в исходном тексте в строках, расположенных ниже определения. Поэтому макроконстанты нужно определять в самом начале asm-файлов.