![]() |
Макровизначення і макрокоманди
Припустимо, що ми маємо два фрагменти програми:
Якщо ввести формальні параметри ARG1, ARG2, ARG3, тоді можна написати одну узагальнену програму: MOV AX, ARG1 ADD AX, ARG2 SUB AX, ARG3 Така узагальнена програма може бути оформлена у вигляді макровизначення. Макровизначення – це записана за чітко визначеними правилами послідовність машинних команд Асемблера, якій присвоєно ім’я. Загальний формат макровизначення: Ім’я макровизначення MACRO [Список формальних параметрів] Тіло макровизначення ENDM Для нашого прикладу макровизначення буде мати такий вигляд: CALC MACRO ARG1, ARG2, ARG3 MOV AX, ARG1 ADD AX, ARG2 SUB AX, ARG3 ENDM У тому місці програми, де повинна виконуватись послідовність команд, яка розміщена у макровизначенні, записується макрокоманда. Її формат: Ім’я макровизначення [Список фактичних параметрів] Для нашої програми приклади макрокоманд: CALC A, B, C CALC M, N, P Ім’я макрокоманди повинно збігатись з іменем макровизначення, до якого звертається макрокоманда. У макрокоманді фактичні параметри записуються у тому самому порядку, в якому перераховані формальні параметри у відповідному макровизначенні. У середині макровизначення може бути розташоване звернення до іншої макрокоманди, яка в цьому випадку носить назву вкладеної макрокоманди. Під час трансляції програми макрокоманда заміняється командами з відповідного макровизначення. Цей процес називається макророзширенням.
Приклад програми з використанням макровизначень Наведена нижче програма демонструє використання макросів, які зменшують обсяг програми і надають їй більшої наглядності. NAME MYPROG KARETKA MACRO ARG ; Макровизначення для роботи з кареткою MOV AH, 02h MOV DL, ARG INT 21h ENDM OUT_NUMB MACRO ; Макровизначення для виведення цифри MOV AH, 06h ADD AL, 48 MOV DL, AL INT 21h ENDM OUT_STR MACRO ; Макровизначення для виведення рядка MOV AH, 09h INT 21h ENDM STACKSG SEGMENT STACK DB 128 DUP(?) ; резервування пам’яті для стеку STACKSG ENDS DATE_SG SEGMENT A DB 2 B DB 3 C DB 4 str0 DB "Data: A=2; B=3; C=4.$" str1 DB "Rezult 1: Y = A+B+C = $" str2 DB "Rezult 2: Y = A*B-C = $" DATE_SG ENDS CODE_SG SEGMENT ASSUME CS:CODE_SG, DS:DATE_SG, SS:STACKSG START PROC FAR PUSH DS SUB AX,AX PUSH AX MOV AX,DATE_SG MOV DS,AX CALL MAIN RET START ENDP MAIN PROC KARETKA 0Ah ; Переведення каретки MOV DX, OFFSET str0 OUT_STR KARETKA 0Ah ; Переведення каретки KARETKA 0Dh ; Повернення каретки MOV DX, OFFSET str1 OUT_STR MOV AL, A MOV BL, B ADD AL, BL ADD AL, C OUT_NUMB KARETKA 0Ah ; Переведення каретки KARETKA 0Dh ; Повернення каретки MOV DX, OFFSET str2 OUT_STR MOV AL, A CBW IMUL B SUB AL, C OUT_NUMB KARETKA 0Ah ; Переведення каретки RET MAIN ENDP CODE_SG ENDS END START
У наведеній програмі створено три макроси. Макрос OUT_NUMB використовується для виведення на екран однієї цифри, значення якої знаходиться у регістрі АL. Макрос OUT_STR призначений для виведення на екран рядка символів, причому перед викликом цього макросу необхідно занести в регістр DX адресу символьного рядка. Макрос KARETKA використовується для роботи з кареткою (переведення на новий рядок, повернення каретки на початок рядка). У ньому використовується параметр ARG, який дозволяє змінювати призначення цього макроса. Так, якщо значення аргументу дорівнюватиме 0Ah, то відбудеться переведення каретки на новий рядок, 0Dh – повернення каретки, 08h – переведення на один символ назад, 07h – подача звукового сигналу, тощо.
Проблема міток у макровизначеннях
В одній програмі одне й те саме макровизначення може бути використано декілька разів. Якщо макровизначення містить мітку, то при його багаторазовому використанні у відповідних макророзширеннях з’являються оператори з однаковими мітками. З точки зору мови це є синтаксичною помилкою. Для запобігання дублювання міток вони описуються за допомогою директиви (оператора) LOCAL, наприклад: LOCAL МЕТ1, МЕТ2 У цьому випадку транслятор замість вказаної мітки записує число, а при кожному зверненні до макровизначення це число збільшується на 1.
Циклічні макроси (директиви повторення)
Директиви повторення вимагають від асемблера повторити блок операторів, що завершується директивою ENDM. Ці директиви не обов’язково повинні знаходитись в макровизначенні, але якщо вони там знаходяться, то одна директива ENDM потрібна для завершення блоку, який повторюється, а друга директива ENDM – для завершення макровизначення. Директива REPT приводить до повторення блока операторів (команд або інших директив) до директиви ENDM у відповідності з кількістю повторень, вказаних у виразі REPT вираз Наприклад, якщо записати REPT 3 INC CX ENDM то команда INC CX виконається тричі: INC CX INC CX INC CX За допомогою директиви IRP можна при кожному повторенні використовувати різні параметри: IRP формальний параметр, <список>. У списку параметри можуть бути символами, рядками, числовими або арифметичними константами. Наприклад, якщо макрокомандою PUSH_REGS <AX, BX, CX, DX> викликається макровизначення PUSH_REGS MACRO LIST IRP REG, <LIST> PUSH REG ENDM ENDM це означатиме, що виконуються такі команди: PUSH AX PUSH BX PUSH CX PUSH DX Як видно з наведеного прикладу, асемблер здійснює стільки проходів тіла макровизначення, скільки вказано елементів у списку. І при кожному такому проході асемблер підставляє замість формального параметра наступний за порядком елемент у списку. Якщо список параметрів містить символи, тоді можна застосувати директиву повторення IRPC, формат якої такий: IRPC формальний параметр, рядок символів Наприклад, якщо записати IRPC CHAR, ABCD ADD AX, CHAR&X ENDM то виконається така група команд ADD AX, AX ADD AX, BX ADD AX, CX ADD AX, DX В даному прикладі використовується символ ”&” (амперсанд), який вказує асемблеру на необхідність конкатенації символів.
Умовні макроси (умовні директиви) Виконання макровизначення може бути поставлено у залежність від виконання певних умов, що задаються директивою IFxx: IFxx вираз умови . . .
ELSE . . .
ENDIF Якщо задана умова виконується, то транслюються лише оператори, розташовані до директиви ELSE, у протилежному випадку – ті оператори, що записані після директиви ELSE. У середині умови макровизначення можна використовувати також директиву EXITM, яка достроково завершує виконання макровизначення. Так cамо, як і директиви повторення, умовні директиви не обов’язково повинні знаходитися у макровизначенні. У таблиці 1 наведено перелік різних умовних директив. Нижче наведено приклад умовної директиви, яка викликає макровизначення ERROR у випадку, коли опущено деякий параметр m: IFB <m> ERROR EXITM ENDIF Як видно з цього прикладу, директива ELSE може бути відсутньою. Таблиця 1 – Умовні директиви
Використання макробібліотек Найбільшої ефективності і зручності у роботі з макросами можна досягти лише при використанні макробібліотек. За допомогою будь-якого текстового редактора можна створити свою особисту бібліотеку, куди можуть бути розміщені макровизначення. Якщо файл макробібліотеки має ім’я MACRO.LIB, то для її підключення на початку програми слід використати таку директиву: INCLUDE MACRO.LIB Слід зауважити, що при підключенні макробібліотеки асемблер переписує в програму всі наявні в ній макровизначення, у тому числі і ті, до яких може і не бути звернень у даній програмі. Тому доцільніше мати декілька невеликих макробібліотек і підключати їх при необхідності. Наприклад, якщо в наведеному вище прикладі вилучити макроси KARETKA, OUT_STR та OUT_NUMB і записати їх в окремий файл з іменем “MyLib.lib”, то в основній програмі замість текстів коду цих макросів слід написати лише одну директиву:
INCLUDE MyLib.lib.
|
|||||||||||||||||||||||||
|