Низкоуровневое программирование для Дzenствующих
Вид материала | Документы |
- Низкоуровневое программирование, 108.99kb.
- Курс является базовым как для изучения других математических дисциплин, так и для более, 36.89kb.
- 1 Обобщенное программирование. Обобщенное программирование это еще одна парадигма программирования,, 55.18kb.
- Введение в линейное программирование линейное программирование (ЛП), 139.72kb.
- Учебно-методический комплекс для студентов заочного обучения специальности Прикладная, 63.23kb.
- Аттестационное тестирование в сфере профессионального образования, 72.49kb.
- Лекции по дисциплине «Социальное моделирование и программирование», 44.69kb.
- Программа дисциплины Линейное программирование Семестр, 17.93kb.
- Программа дисциплины "Программирование" для направления, 488.76kb.
- Рабочая программа по дисциплине Программирование на языке высокого уровня для специальности, 182.97kb.
III. Макромир MASM
Макрос представляет собой именованный участок исходного текста программы, который обрабатывается компилятором каждый раз в том месте, где вызывается макрос.
-= Подробней =- |
Пример: Создайте небольшой модуль с именем macro.asm. И напишите в нём несколько строчек .386 .data .code echo Hello!!! echo Ты должен увидеть во время компиляции end Так действует директива echo. С помощью неё можно подсмотреть значения переменных. Mycount = 1 %echo @CatStr(%Mycount) Если вы не знаете, как это работает, не волнуйтесь, обо всём будет рассказано. А пока несколько экспериментов: Напишите: MyMacro macro reg dec reg endm .code mov eax,5 MyMacro reg MyMacro reg Взгляните на код программы под отладчиком. Что у вас получилось? Что будет, если вы измените текст внутри макроопределения? Теперь напишите: MyVar = 1 MyMacro macro MyVar = MyVar+1 %echo MyVar = @CatStr(%MyVar) endm MyMacro MyMacro MyMacro MyMacro Каким будет вывод на экран во время компиляции? |
С этого момента вам придётся различать в ассемблере ML две подсистемы: препроцессор и компилятор. Если компилятор переводит код мнемоник в машинный код, вычисляет значения меток и смещений, то препроцессор занимается вычислением выражений этапа компиляции, и что самое важное – процессом раскрытия макросов.
Подобно многим объектам мира программирования макро имеет два состояния в исходном тексте: определение, и использование.
Таким образом, мы будем иметь дело с определением макроса (макроопределением), и его вызовом (использованием макроса).
Макроопределением называется любой текст, заключённый между ключевыми словами:
MacroName macro paramlist
макроопределение
endm
При каждом вызове макро, а именно:
…
MacroName
или
mov eax, MacroName()
…
Будет анализироваться и исполнятся текст, заключённый в макро. Именно так это и реализовано в ML. Поскольку текст в макроопределении не компилируется, то естественно, вы не увидите сообщений об ошибке, даже если с точки зрения ассемблера эта ошибка будет в теле макроопределения. Однако ошибка появится при попытке вызова макроопределения, её могут выдать вам, либо сам препроцессор, либо компилятор, если текст, сгенерированный препроцессором является неверным с точки зрения компилятора.
Каждый раз, когда препроцессор встречает макроопределение, он помещает его имя в специальную таблицу, и копирует его тело к себе в память (это не обязательно именно так, но вам должна быть понятна суть). Встретив макроопределение, препроцессор не проверяет, а есть ли макро с таким же именем. Это значит, что макро можно переопределять.
MyMacro macro
echo Это макро 1
endm
MyMacro macro
echo Это макро 2
endm
MyMacro
Вы можете самостоятельно удалять макроопределения, из памяти препроцессора используя директиву PURGE:
PURGE macroname
После этой директивы макро с именем macroname перестаёт существовать. И вы освобождаете память для компилятора.
Конечно же, использование макро было бы бесполезным, если бы макро не имел формальных параметров. При вызове макро, препроцессор заменяет все имена формальных параметров их непосредственными значениями в теле макроопределения. Список формальных параметров разделяется запятой, и может иметь вид:
MyMacro macro param0, param1:REQ, param2 := <0>,param3:VARARG
Здесь:
Param0 – пример определения параметра.
Param1:REQ – ключевое слово REQ указывает на то, что этот параметр обязательный. То есть, если он не будет указан, вы получите ошибку этапа компиляции.
Param2:=<0> – пример параметра, который имеет значение по умолчанию. То есть если этот параметр не будет указан при вызове макро, он будет равен этому значению.
Заметьте, что при вызове макро параметр может быть не определён: MyMacro param1,,param3 Значение второго параметра неопределенно. |
Param3:vararg – становится именем параметра, который воспринимает всё остальное как строку. При этом запятые между параметрами так же попадают в строку, а значит число параметров макроса в принципе неограниченно.
Ограничениям являются особенности архитектуры компилятора. Так, например, компилятор имеет ограничение на длину логической строки, которая равна 512 байтам. |
Конечно же, после параметра с директивой vararg не возможно объявить другие параметры.
Обратите внимание, что если при определении формального параметра в макро нет директивы – он считается необязательным параметром. Более подробно о вызове макро и значении параметров я расскажу далее. |
-= Подробней =- |
Пример: Так что же происходит с формальными параметрами? Посмотрите, как работает препроцессор ML: MyMacro macro param1,param2 mov eax, param1 mov ebx, param2 endm MyMacro var, 123 1. Препроцессор берёт текст внутри макро, и заменяет в нём все слова param1, param2, на их значения: « mov eax, var mov ebx, 123 » 2. Полученный текст вставляет на место вызова макро, и передаёт компилятору. Вот интересно, а что будет если: MyMacro macro param1,param2 MyMacro2 macro param1 mov eax, param1 mov ebx, param2 endm endm MyMacro var, 123 |
Можно различать два вида макро – макропроцедуры и макрофункции.
В официальном руководстве MASM различается четыре основных вида макро. Text macros – текстовый макрос Macro procedures – макро-процедура Repeat blocks – блок повторения Macro functions – макро-функция Однако автор считает, что разделение макро на два вида – лучше систематизирует материал, и отражает суть темы. |
Макрофункции в отличие от макропроцедур могут возвращать результат, и получают список формальных параметров в скобках, подобно функциям в С. Например:
mov eax,@GetModuleHandle()
Заметьте, что к макрофункции невозможно обратится как к макро, вы всегда должны заключать формальные параметры макрофункции между «()», иначе MASM не будет распознавать её как макрофункцию:
mov eax,@GetModuleHandle
error A2148: invalid symbol type in expression
: @GetModuleHandle
Препроцессор MASM анализирует текст макроопределения на наличие директивы exitm, и помечает макрос как макрофункцию.
Ключевое слово exitm
Таким образом, окончательно будем считать, что макро, не имеющие в себе вызова директивы exitm – это макропроцедуры, а макро, которые имеют exitm – это макрофункции. |
;#######################################################
@GetModuleHandle macro
Invoke GetModuleHandle,0
exitm
endm
.code
; Это макрофункция так нельзя
@GetModuleHandle ;;– ошибка
; Так можно
@GetModuleHandle()
;########################################################
@GetModuleHandle macro
Invoke GetModuleHandle,0
endm
.code
; Это макрос. Так правильно
@GetModuleHandle
; Так можно, но всё равно это вызывает ошибку ?
; warning A4006: too many arguments in macro call
@GetModuleHandle()
; Это макро, а не макрофункция так нельзя!!!
mov eax,@GetModuleHandle
; И так нельзя
mov eax,@GetModuleHandle()
;########################################################
Что касается директивы endm, которая заканчивает каждое макроопределение, в руководстве написано, что при помощи неё так же можно указать возвращаемый параметр: endm Однако на практике это не так. ? Очень странно, хотя об этом чётко написано в руководстве. |
Заметьте, что макропроцедура может быть вызвана только в начале строки:
@GetModuleHandle
;; Но не так:
mov eax,@MyMacro
Макрофункция может быть вызвана в любых выражениях:
;; Так:
mov eax,@GetModuleHandle()
;; И так:
@FunMacro()
;; И так:
@GetModuleHandle() EQU eax
0>0>