Низкоуровневое программирование для Дzenствующих

Вид материалаДокументы

Содержание


III.1. Функционирование макросов
Подобный материал:
1   ...   11   12   13   14   15   16   17   18   ...   42

III.1. Функционирование макросов


Чтобы строить макросы, важно понимать, как они работают, и как их обрабатывает MASM. Давайте рассмотрим типичный макро, и этапы его обработки.


MyMacro macro param1,param2,param3:VARARG

echo param1

echo param2

echo param3

endm


MyMacro Параметр 1, Параметр 2, Параметр 3, Параметр 4

;; Вывод -=-=-=-=-=-=-=-=

Параметр 1

Параметр 2

Параметр 3,Параметр 4


1. Компилятор встречает лексему MyMacro

2. Он проверяет, содержится ли эта лексема в словаре ключевых слов

3. Если нет, то он проверяет, содержится ли эта лексема в списке макросов.

4. Если да, он передаёт текст, содержащийся в макро препроцессору. Препроцессор заменяет все вхождения формальных параметров в этом тексте на их значения. В данном случае мы имеем:

echo Параметр 1
echo Параметр 2
echo Параметр 3,Параметр 4

5. Препроцессор возвращает компилятору обработанный текст, который после компилируется.

Обратите внимание на пункт 4 и 5. Они ключевые. Очень часто при работе с макроопределениями появляются ошибки из-за неверного понимания порядка генерирования макро текста. Например:


PROGRAM_IMAGE_BASE EQU 400000h

FunMacro macro

exitm <Параметр 3,параметр 4>

endm


MyMacro macro param1,param2,param3:VARARG

echo param1

echo param2

echo param3

endm


MyMacro PROGRAM_IMAGE_BASE, FunMacro(),Параметр 5


А теперь самостоятельно опишите порядок действий компилятора при вызове этого макро. Запишите его себе куда-нибудь, так чтобы сравнить, и смотрите на вывод:

PROGRAM_IMAGE_BASE
Параметр 3, Параметр 4
Параметр 5

Прежде чем объяснять действительный порядок, я оговорюсь, что директива echoникогда не обрабатывает определённые константы, такие как PROGRAM_IMAGE_BASE.

Это утверждение справедливо даже тогда, когда перед директивой echo стоит оператор %, который может раскрывать только текстовые макроопределения. То есть выражение:

echo FunMacro()

Даст результат:

FunMacro()

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

echo PROGRAM_IMAGE_BASE
echo Параметр 3, Параметр 4
echo Параметр 5

Это означает следующее:
  1. При вызове макро, значение формальных параметров воспринимается как текст, и передаётся в макро как строка.
  2. Исключение составляют лишь макрофункции, результат выполнения которых вычисляется и присваивается значению параметра.

Специальный оператор % заставляет ассемблер вычислять текстовую строку, следующую за ним, и только потом подставлять в правое выражение. Например, если мы перепишем макровызов так:

MyMacro %PROGRAM_IMAGE_BASE, FunMacro,Параметр 5

То получим вывод:

4194304 ;; Значение PROGRAM_IMAGE_BASE
Параметр 3, Параметр 4
Параметр 5

Давайте рассмотрим ещё один пример, который хорошо показывает, как работает макро. Например, вы определили макропроцедуру (именно его, а не макрофункцию). То когда вы пишите такое:

@Macro что-то, что придёт вам в голову [символ возврата каретки]

Что делает препроцессор ML:

1. Считывает всю строку до символа возврата каретки;

2. Смотрит, как вы определили параметры в макро;

3. Сканирует строку на наличие символа «,» или «<», «>»;

Вам может показаться странным, но препроцессору всё равно, какие символы идут во время вызова макро. То есть вы можете вызвать макро так:

@MyMacro Привет, это кириллица в файле,\

и ML не будет на неё ругаться
или
@MyMacro !@#$%&*(){}[]

Посмотрите как СИльно (от буквы ) будет выглядеть макро в MASM:

MyMacro{Это что С++?}
MyMacro[Нет, это MASM]

4. Назначает формальным параметрам (любого типа, кроме VARARG) макро участки строк, которые были определены разделителями запятыми (предварительно очистив от хвостовых и начальных пробелов, если только строка не была определена в угловых кавычках <>);

5. Если макро содержит формальный параметр типа VARARG, то ML сперва инициализирует значениями (согласно пункту 4) обычные формальные параметры, и только потом назначает параметру типа VARARG (который может быть только один в конце списка параметров) всю строку до конца.

-= Обратите внимание =-

Если вы пишите макровызов как
@Macro Param1 , Param2
То значение параметров будут:
param1 = «Param1»
param2 = «Param2»
Если вы хотите передать сами значения строк, то должны заключит их в угловые кавычки:
@Macro < Param1 >,< Param2 >

6. Препроцессор разрешает все вызовы макрофункций, если они есть в лексемах параметра, и присваивает их результат соответствующему параметру. Если лексему в строке параметра предваряет символ %, то он вычисляет её значение до того, как передаст строку внутрь макро.

-= Обратите внимание =-

Благодаря именно такому порядку:
1. Разделение строки на макропараметры
2. Поиск и Вызов макрофункций в значениях макропараметров
3. Присвоение результатов соответствующему макропараметру

в следующем случае:


MyMacro macro param1,param2,param3

echo param1

endm

--------------------------------------

FunMacro macro param:VARARG

exitm param

endm


MyMacro FunMacro(param1, param2, param3)


OUT:

param1, param2, param3

--------------------------------------


строка, возращаемая макрофункцией присваивается параметру param1, а не param2, param3

Теперь вы в состоянии объяснить следующую ситуацию:


MyMacro macro



endm


MyMacro()


Предупреждение при компиляции:

: warning A4006: too many arguments in macro call

Как нужно было бы изменить этот макро (именно макро, а не макрофункцию), чтобы предупреждение не выдавалось? А почему оно происходит?

Если вы с лёгкостью ответили на этот вопрос, значит, материал усвоен, иначе советую ещё раз прочитать его, и ответить на следующий вопрос.

Как должен понять компилятор следующий код:


MyMacro macro param1

param1

endm


MyMacro = 2

Естественно отвечать на этот вопрос вы должны без помощи компилятора (то есть проверить компиляцией). Если вы не можете ответить на этот вопрос, или неуверенны в верности ответа, я поменяю задание:


MyMacro macro param1

echo param1

endm


MyMacro = 2

Запустите его в ML. Если и теперь вы сомневаетесь – перечитайте этот пункт снова и снова, продолжая экспериментировать.