ВІКІСТОРІНКА
Навигация:
Інформатика
Історія
Автоматизація
Адміністрування
Антропологія
Архітектура
Біологія
Будівництво
Бухгалтерія
Військова наука
Виробництво
Географія
Геологія
Господарство
Демографія
Екологія
Економіка
Електроніка
Енергетика
Журналістика
Кінематографія
Комп'ютеризація
Креслення
Кулінарія
Культура
Культура
Лінгвістика
Література
Лексикологія
Логіка
Маркетинг
Математика
Медицина
Менеджмент
Металургія
Метрологія
Мистецтво
Музика
Наукознавство
Освіта
Охорона Праці
Підприємництво
Педагогіка
Поліграфія
Право
Приладобудування
Програмування
Психологія
Радіозв'язок
Релігія
Риторика
Соціологія
Спорт
Стандартизація
Статистика
Технології
Торгівля
Транспорт
Фізіологія
Фізика
Філософія
Фінанси
Фармакологія


Команда сравнения строк CMPS (CMPSB, CMPSW)

Команда CMPS сравнивает значение элемента одной строки (DS:SI) со значением элемента второй строки (ES:DI) и настраивает значения регистров на следующие элементы строк в соответствии с флагом направления DF. Сравнение происходит как и по команде сравнения CMP. Результат – сформированные флаги.

Команда сканирования строки SCAS (SCASB, SCASW)

Команда SCAS производит сравнение содержимого регистра (AL или AX) с байтом памяти, абсолютный адрес которого определяется парой ES:DI, после чего регистр DI устанавливается на соседний элемент памяти (байт или слово) в соответствии с флагом DF. Команда SCAS используется обычно для поиска в строке (ES:DI) элемента заданного в регистре AL или AX.

Команда пересылки строки MOVS (MOVSB, MOVSW)

Команда MOVS пересылает поэлементно строку DS:SI в строку ES:DI и настраивает значения индексных регистров на следующий элемент строки.

Команда сохранения строки STOS (STOSB, STOSW)

Команда STOS заполняет строку, содержащуюся по адресу ES:DI, элементом из регистра AL или AX. На флаги команда не влияет.

Команда загрузки строки LODS (LODSB, LODSW)

Команда LODS записывает в регистр AL или AX содержимое ячейки памяти, адрес которой задается регистрами DS:SI. Флаги не меняются.

Команды управления процессором

К командам управления процессором чаще всего относят команды работы (установка и очистка) с флагами. Среди них наиболее часто приходится использовать следующие:

- команда CLC устанавливает значение флага переноса CF, равное нулю. Все остальные флаги и регистры остаются неизменными;

- команда CMC изменяет значение флага переноса CF на противоположное. Другие флаги остаются без изменений;

- команда STC устанавливает флаг переноса в единицу;

- команда CLD очищает флаг направления DF. Все остальные флаги и регистры остаются неизменными. После выполнения CLD используемые строковые операции будут увеличивать индексный регистр (SI или DI);

- команда STD устанавливает флаг направления DF в единицу, что заставляет все последующие строковые операции уменьшать при их выполнении индексные регистр (SI или DI);

- команда CLI очищает флаг прерываний, в результате чего процессор не распознает внешние маскируемые прерывания;

- команда STI устанавливает флаг разрешения прерываний IF в единицу. После этого при завершении работы следующей команды процессор может выполнять обработку внешних прерываний, если эта команда снова не сбросит флаг прерываний.

Структуры данных

Массивы

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

 

Mas1 DB 10 DUP (?)

 

а двумерный массив слов:

 

Mas2 DW 10 DUP (10 DUP (?))

 

 

Таким образом, в случае, когда элементы массива нумеруются с нуля, доступ к ним значительно упрощается. Поэтому, в большинстве случаев именно так и делается.

Для многомерных массивов ситуация аналогична.

Теперь рассмотрим каким образом организуется доступ к элементам массива. Основная трудность возникает в ситуации, когда массив обрабатывается в цикле, и необходимо организовать доступ к каждому элементу массива. В этом случае поступают следующим образом:

- адрес текущего элемента массива X+(Type X)*i разбивается на два слагаемых: постоянное слагаемое X (начальный адрес массива) и переменное слагаемое (Type X)*i (смещение текущего элемента относительно начала массива);

- постоянное слагаемое записывается в саму команду, а переменное слагаемое заносится в какой-либо регистр модификатор, который также указывается в команде.

Таким образом, изменяя в цикле значение регистра-модификатора, можно на каждой итерации цикла получить доступ к новому элементу массива.

Ниже приведен фрагмент программы, иллюстрирующий нахождение суммы элементов одномерного массива байт, описанного выше.

 

MOV AX,0 ;начальное значение суммы

MOV CX,10 ;счетчик циклов (кол-во элементов)

MOV SI,0 ;начальное значение индекса

M: ADD AX,Mas1[SI] ;AX:=AX+Mas1[i]

INC SI ;увеличение индекса

LOOP M

Связанные списки

Списком (линейным, однонаправленным) называется последовательность звеньев, которые могут размещаться в произвольных местах памяти и в каждом из которых содержится элемент списка (Ei) и ссылка на следующее звено (изображена стрелкой):

 

В последнем звене размещается специальная «пустая» ссылка nil, указывающая на конец списка. Ссылка на первое звено списка хранится в некоторой переменной LIST, если список пуст, то ее значением является nil.

Возможность размещать звенья списков в любых местах памяти обуславливают плюсы и минусы списков. Достоинством списков является то, что их длина заранее не фиксируется, что под них надо отводить ровно столько места, сколько требуется в текущий момент, и что удаление и вставка элементов реализуются просто и быстро – заменой ссылок в одном-двух звеньях. К недостаткам же списков относится лишний расход памяти для хранения ссылок и то, что доступ к элементам списка осуществляется последовательно.

Для хранения звеньев списков обычно отводят специальную область памяти, называемую кучей (heap). Обычно на начало кучи постоянно указывает сегментный регистр ES. Если внутри кучи звено списка имеет адрес (смещение) А, то абсолютный адрес этого звена задается адресной парой ES:A. Ссылка на звено – это адрес данного звена. Для экономии памяти ссылкой на звено обычно считается лишь смещение А, то есть адрес этого звена, отсчитанный от начала кучи (два байта). Под каждое звено отводится несколько соседних байтов памяти, в первых из которых размещается соответствующий элемент списка ELEM, а в остальных ссылка на следующее звено NEXT. Размер звена зависит от размера элементов списка.

При программировании на языке Ассемблера звенья списка удобно рассматривать как структуры следующего типа:

 

NODE STRUC ;тип звена списка

ELEM DW ? ;элемент списка

NEXT DW ? ;ссылка на следующее звено

NODE ENDS

 

Поэтому, если необходимо получить доступ к полям звена, который имеет адрес А, то это осуществляется следующим образом:

 

ES:A.ELEM – поле с элементом

ES:A.NEXT – поле с адресом следующего звена

 

В качестве пустой ссылки nil обычно используется адрес 0, при этом удобно описать в программе этот адрес как константу

 

NIL ЕQU 0

 

и далее пользоваться именем NIL.

Ссылки на первые звенья списков, как правило, хранятся в переменных из сегмента данных, имеют размер 16 бит и описываются, например, следующим образом:

 

List DW ?

 

При работе со списком приходится последовательно просматривать его звенья. Поэтому необходимо знать адрес текущего звена. Для хранения этого адреса удобно использовать какой-либо регистр-модификатор, например, ВХ. Если текущим является i-e звено списка, то графически это можно представить так:

 

 

В этом случае доступ к полям текущего звена можно получить следующим образом ES:[BX].ELEM и ES:[BX].NEXT.

Анализ текущего элемента списка

Следующий фрагмент программы иллюстрирует анализ, равенства элемента из текущего звена значению некоторой переменной X, и, если условие истинно, переход на метку EQ:

 

MOV AX,ES:[BX].ELEM

CMP АХ,Х

JE EQ

 

Переход к следующему звену списка

Фрагмент программы, иллюстрирующий эту операцию, выглядит следующим образом (ВХ – текущее звено списка):

 

MOV BX,ES:[BX].NEXT

 

Поиск элемента в списке

Нижеследующий фрагмент программы отыскивает в списке LIST значение X. Если X найден, то в регистр AL заносится 1 (входит) иначе 0.

 

MOV AL,0

MOV СХ,Х ;искомая величина

MOV BX,LIST ;bх - nil или адрес 1-го звена

L: СМР BX,NIL

JE NO ;конец списка

СМР ES:[BX].ELEM,CX

JE YES

MOV BX,ES:[BX].NEXT ;bх - адрес следующего звена

JMP L

YES: MOV AL,1

NO: ...

 

Вставка элемента в список

Для вставки нового элемента X в список LIST необходимо выполнить следующие действия (см. рис. 12.3):

1) отвести (выделить) место под новое звено (эти действия выполняет процедура NEW (см. ниже), она отыскивает в куче свободное место и возвращает его адрес через регистр DI);

2) заполнить новое звено, то есть в поле ELEM записать величину X, а в поле NEXT – ссылку на бывшее первое звено (она берется из LIST),

3) в LIST записать адрес нового звена (берется из DI):

 

CALL NEW ;new(di)

MOV AX,X

MOV ES:[DI].ELEM,AX ;di^.elem=x

MOV AX, LIST

MOV ES:[DI].NEXT,AX ;di^.next:=list

MOV LIST,DI ;list=di

 

Организация кучи

При программировании на языке Ассемблера необходимо самому освобождать и выделять память под звенья списка (процедуры New и Dispose). Ниже приведен один из вариантов организации кучи.

Список свободной памяти

В процессе работы программы память постоянно освобождается и выделяется, то есть занятые и свободные ячейки в сегменте кучи разбросаны. Поэтому удобно все свободные ячейки кучи объединить в один список, который принято называть списком свободной памяти (ССП). Начало этого списка указывается в некоторой фиксированной ячейке, например, с именем HEAP_PTR (heap pointer – указатель кучи). Используется ССП следующим образом: когда программе нужно место под новое звено, то оно выделяется из этого ССП, а когда программа отказывается от какого-то звена, то это звено добавляется к ССП.

Поскольку в простейшем случае звенья имеют фиксированную длину, то имеет смысл объединять в ССП элементы именно этого размера (например, двойные слова, как в предыдущих примерах). Если при этом ссылку на следующее звено ССП хранить во втором слове звена, то получим обычный список.

Место для переменной HEAP_PTR лучше всего отвести в самом начале кучи – в ячейке с относительным адресом 0. В этом случае ни одно звено не будет размещаться в этой ячейке и не будет иметь адрес 0, то есть этот адрес останется свободным и его можно использовать для представления пустой ссылки nil.

Описание сегмента кучи

Поскольку куча – это один из сегментов памяти, используемый программой, то его необходимо описать в программе (n – число звеньев в куче):

 

HEAP_SIZE EQU N

HEAP SEGMENT ;сегмент кучи

HEAP_PTR DW ? ;ячейка с начальным адресом ССП

DD HEAP_SIZE DUP(?)

HEAP ENDS

 

Инициализация кучи

Первоначально все ячейки кучи свободны и не объединены в ССП. Поэтому в начале программы необходимо связать все ячейки (двойные слова) кучи в единый список и записать в HEAP_PTR ссылку на начало этого списка. Ниже приведен пример подпрограммы инициализации кучи:

 

INIT_HEAP PROC FAR

PUSH SI

PUSH BX

PUSH CX

;установка ES на начало сегмента кучи

MOV CX,HEAP

MOV ES,CX

;объединение всех двойных слов кучи в ССП

MOV CX,HEAP_SIZE ;число звеньев в ССП

MOV BX,NIL ;ссылка на построенную часть ССП

MOV SI,4*HEAP_SIZE-2 ;адрес нового звена ССП

INIT1:MOV ES:[SI].NEXT,BX ;добавить в начало

MOV BX,SI ;ССП новое звено

SUB SI,4 ;SI - на двойное слово "выше"

LOOP INIT1

MOV ES:HEAP_PTR,BX ;HEAP_PTR – на начало ССП

POP CX

POP BX

POP SI

RET

INIT_HEAP ENDP

 

Обратиться к этой процедуре необходимо в начале программы, после чего уже можно использовать процедуры NEW и DISPOSE (приведенные варианты процедур NEW и DISPOSE рассчитаны только на случай, когда звенья всех списков имеют один и тот же размер).

Процедура Dispose

К этой процедуре программа обращается, когда она отказывается от некоторого звена. Адрес этого звена, например, передается через регистр DI. Звено становится свободным и его необходимо добавить в начало ССП:

 

;на входе: DI - адрес ненужного звена

DISPOSE PROC FAR

PUSH ES:HEAP_PTR

POP ES:[DI].NEXT ;di^.next:=heap_ptr

MOV ES:HEAP_PTR,DI ;heap_ptr:=di

RET

DISPOSE ENDP

 

Процедура New

К этой процедуре программа обращается, когда ей необходимо место для нового звена списка. Это место берется из ССП: от этого списка отщепляется одно из звеньев и отдается программе. Проще всего отделить первое звено. Адрес этого звена процедура должна вернуть через регистр DI.

 

;на выходе: DI - адрес свободного звена

NEW PROC FAR

MOV DI,ES:HEAP_PTR

СMР DI,NIL

JE EMPTY ;пустой ССП -> ЕНРТУ_НЕАР

PUSH ES:[DI].NEXT

POP ES:HEAP_PTR ;heap_ptr - на 2-е звено ССП

RET

EMPTY: ;реакция на пустую кучу

...

NEW ENDP

Условное ассемблирование

Язык Ассемблера включает в себя директивы условного ассемблирования. Условное ассемблирование удобно при многократных прогонах программы. Оно дает возможность в исходном тексте держать несколько вариантов одного и того же участка программы и при каждом прогоне оставлять в окончательном тексте только один из них. Какой именно вариант будет оставлен, зависит от тех или иных условий, которые автор программы задает перед прогоном. Таким образом, автор программы не должен перед каждым ее прогоном вручную редактировать текст, а возлагает эту работу на макрогенератор.

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

 

IF-директива

фрагмент-1

ELSE

фрагмент-2

ENDIF

 

или

 

IF-директива

фрагмент-1

ENDIF

 

Директивы ELSE и ENDIF обязательно должны записываться в отдельных строках. В каждом же фрагменте может быть любое число любых предложений, в частности в них снова могут быть IF-блоки, то есть допускается вложенность IF-блоков.

В IF-директиве указывается некоторое условие, которое проверяется макрогенератором. Если условие выполнено, то макрогенератор оставляет в окончательном тексте программы только фрагмент-1, а фрагмент-2 исключает, не переносит в окончательный текст. Если же условие не выполнено, тогда фрагмент-1 игнорируется, а в окончательную программу вставляется только фрагмент-2. Если части ELSE нет, то считается, что фрагмент-2 пуст, поэтому при невыполнении условия такой IF-блок ничего не «поставляет» в окончательный текст программы.

Поскольку условие в IF-директиве проверяется на этапе макрогенерации, то в нем не должно быть ссылок на величины, которые станут известными только при выполнении программы (например, в условии нельзя ссылаться на содержимое регистров или ячеек памяти). Более того, условие должно быть таким, чтобы макрогенератор мог вычислить его сразу, как только встретит (в нем не должно быть ссылок вперед).

В макроязыке довольно много IF-директив их удобно рассматривать парами, в каждой из которых директивы проверяют противоположные условия.

Директивы IF и IFE имеют следующий вид:

 

IF константное_выражение

IFE константное_выражение

 

Встречая любую из этих директив, макрогенератор вычисляет указанное в ней константное выражение. В директиве IF условие считается выполненным, если значение выражения отлично от 0, а директиве IFE - если значение равно 0.

В общем случае константное выражение, указываемое в директивах IF и IFE, может быть любым, но по смыслу оно, должно быть логическим выражением. В языке Ассемблера имеется шесть операторов отношения:

 

выражение EQ выражение

выражение NE выражение

выражение LT выражение

выражение LE выражение

выражение GT выражение

выражение GE выражение

 

Названия этих операторов: EQ -равно, NE - не равно, LT - меньше, LE -меньше или равно, GT - больше, GE - больше или равно. Оба операнда должны быть либо константными выражениями, либо адресными выражениями, значениями которых обязаны быть адреса из одного и того же сегмента памяти. Если проверяемое отношение выполняется, то значением оператора является «истина», не если выполняется – «ложь».

Логические значения и отношения можно объединять в более сложные логические выражения с помощью следующих логических операторов:

 

NOT константное_выражение

константное_выражение AND константное_выражение

константное_выражение OR константное_выражение

константное_выражение XOR константное_выражение

 

Эти операторы реализуют соответственно операции отрицания, конъюнкции, дизъюнкции и «исключающего ИЛИ». Их операндами могут быть любые константные выражения (но не адресные), значения которых трактуются как 16-битовые слова. Значением этих операторов также является 16-битовое слово, которое получается в результате поразрядного выполнения соответствующей операции (не следует путать операторы и команды: операторы используются для записи операндов команд и директив и вычисляются на этапе трансляции программы, а команды выполняются на этапе счета программы).

Директивы IFIDN, IFDIF, IFB и IFNB имеют следующий вид:

 

IFIDN <tl>,<t2>

IFDIF <tl>,<t2>

 

где tl и t2 - любые последовательности символов (обязательно должны быть заключены в угловые скобки), которые посимвольно сравниваются.

В директиве IFIDN условие считается выполненным, если эти строки равны, а в директиве IFDIF - если они не равны. При сравнении этих текстов большие и малые буквы не отождествляются.

Обе эти директивы имеет смысл использовать лишь внутри тела макроса, указывая в сравниваемых текстах формальные параметры макроса. При макроподстановке эти параметры будут заменяться на фактические параметры, и это позволяет проверить, заданы ли при обращении к макросу фактические параметры определенного вида или нет.

Директивы

 

IFB <t>

IFNB <t>

 

Фактически являются вариантами директив IFIDN и IFDIF, когда второй текст пуст. В директиве IFB условие считается выполненным, если текст t пуст, а в директиве IFNB - если текст t не пуст.

Эти директивы используются в макросах для проверки, задан ли фактический параметр или нет.

Ниже представлен пример использования директив условного ассемблирования.

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

Это можно осуществить следующим образом. Пусть режим прогона программы указывается с помощью константы DEBUG, которая описана в начале текста программы и которой присваивается значение 1 (отладка) или значение 0 (счет). Тогда, (см. пример ниже) участок исходной программы с отладочной печатью (например, переменной X) должен быть записан так, как указано слева, в окончательном же тексте программы этот участок будет выглядеть так, как изображено справа (PRINT – макрос вывода на экран):

 

… MOV Х,АХ IF DEBUG PRINT X ENDIF MOV BX,0 … Debug<>0 … MOV X,AX PRINT X MOV BX,0 … Debug=0 MOV X,AX MOV BX,0 …

 

При таком построении текста программы достаточно перед ее прогоном поменять лишь одну строчку – описание константы DEBUG, чтобы макрогенератор сформировал разный окончательный текст программы (с ОП или без них).

Включать и исключать ОП в текст программы можно и с помощью команд условного перехода. Основное отличие условного ассемблирования и команд условного перехода состоит в том, что в последнем случае команды ОП остаются в программе всегда, и потому всегда занимают место в памяти. Кроме того, в этом случае проверка, выполнять команды ОП или нет, делается в процессе выполнения программы, и на это тратится время. При условном же ассемблировании команды ОП, если они не нужны, будут удалены из программы и потому, не будут занимать место в памяти, а также тратить время на проверку условия.

Макросредства

Макросредства языка Ассемблера позволяют формировать в исходной программе блоки предложений (макроопределения), имеющие одно общее имя, и затем многократно использовать это имя для представления всего блока. В процессе ассемблирования компилятор автоматически замещает каждое распознаваемое макроимя (макрокоманду) последовательностью предложений в соответствии с макроопределением, в результате чего формируется макрорасширение.

Макрокоманда может встречаться в исходной программе столько раз, сколько это необходимо. Макроопределение в исходном файле должно предшествовать его первому использованию в макрокоманде. Макроопределение может как непосредственно находиться в тексте программы, так и подключаться из другого файла директивой INCLUDE. В макроопределение могут быть переданы параметры, которые будут управлять макроподстановкой или задавать фрагменты текста.

В программе на языке Ассемблера макрокоманды выполняют в целом те же функции, что и процедуры, то есть обеспечивают многократное и функционально законченное действие с параметрическим управлением. Различие заключается в следующем:

1) процедура присутствует в исходной программе один раз, тогда как тело макроопределения дублируется столько раз, сколько соответствующих макрокоманд содержит исходный файл;

2) текст процедуры статичен и неизменен в то время, как состав макрорасширения может зависеть от параметров макрокоманды;

Следует помнить, что параметры макрокоманды - это значения времени ассемблирования, а параметры процедуры принимают какие-то определенные значения лишь в процессе выполнения программы.

Макродирективы

Макроопределение представляет собой блок исходных предложений, начинающийся директивой MACRO и заканчивающийся директивой ENDM. Формат макроопределения:

 

имя MACRO [[формальный-параметр,...]]

предложения

ENDM

 

Именем макроопределения считается имя, указанное в директиве MACRO. Оно должно быть уникальным и может использоваться в исходном файле для вызова макроопределения. Формальные параметры представляют собой внутренние по отношению к данному макроопределению имена, которые используются для обозначения значений, передаваемых в макроопределение при его вызове. Может быть определено любое число формальных параметров, но все они должны помещаться на одной строке и разделяться запятыми.

В теле макроопределения допустимы любые предложения языка Ассемблера, в том числе и другие макродирективы. Допустимо любое число предложений, а каждый формальный параметр может быть использован любое число раз в этих предложениях.

Макроопределения могут быть переопределены. При этом нет необходимости заботиться об удалении из исходного файла первого макроопределения, так как каждое следующее макроопределение автоматически замещает предыдущее макроопределение с тем же именем.

Макроопределение может быть вызвано в любой момент простым указанием его имени в исходном файле. Ассемблер при этом копирует предложения макроопределения в точку вызова, замещая в этих предложениях формальные параметры на фактические параметры, задаваемые при вызове.

Общий вид макровызова:

 

имя [[фактический-параметр,...]]

 

Имя должно быть именем ранее определенного в исходном файле макроопределения. Фактическим параметром может быть имя, число или другое значение. Допустимо любое число фактических параметров, но все они должны помещаться на одной строке. Элементы списка параметров должны разделяться запятыми, пробелами, или TAB-символами.

Компилятор замещает первый формальный параметр на первый фактический параметр, второй формальный параметр на второй фактический параметр и т.д. Если фактических параметров в макровызове больше, чем формальных параметров в макроопределении, лишние фактические параметры игнорируются. Если же фактических параметров меньше, чем формальных, формальные параметры, для которых не заданы фактические, замещаются пустыми строками (пробелами). Для определения того, заданы или не заданы соответствующие фактические параметры могут быть использованы директивы IFB и IFNB (см. «13. Условное ассемблирование»).

В макросредствах языка Ассемблера имеется возможность передавать список значений в качестве одного параметра. Этот список должен быть заключен в одинарные угловые скобки < >, а сами элементы списка – разделяться запятыми, например:

 

allocb <1,2,3,4>

 

При написании макроопределений иногда возникает необходимость в задании меток инструкций или имен полей данных. Поскольку каждое макроопределение может использоваться многократно, возникают ситуации, когда несколько имен или меток определены многократно, что вызовет ошибку трансляции. Для обеспечения правильной обработки таких ситуаций в макроязыке предусмотрена директива LOCAL, позволяющая локализовать заданные имена исключительно в данном макрорасширении. Формат:

 

LOCAL формальное-имя,...

 

Формальное-имя может затем использоваться в данном макроопределении с уверенностью, что при каждом макровызове его значение будет уникальным. В директиве LOCAL, если она присутствует, должно быть задано хотя бы одно имя, а если их несколько, они должны разделяться запятыми. Для обеспечения уникальности определенных директивой LOCAL имен Ассемблер для каждого такого имени при каждом макровызове порождает реальное имя следующего вида:

 

??номер

 

Номер представляет собой 16-ричное число в пределах от 0000 до FFFF. Для предотвращения повторного определения имен программисту не рекомендуется определять в своей программе имена этого типа.

Директива LOCAL может использоваться только в макроопределении, причем, там она должна предшествовать всем другим предложениям макроопределения, то есть следовать непосредственно после MACRO.

Для удаления макроопределений служит директива PURGE. Формат:

 

PURGE имя-макроопределения,...

 

Директивой PURGE удаляются все текущие макроопределения с указанными именами. Последующий вызов одного из этих макроопределений будет приводить к ошибке. Если имя-макроопределения представляет мнемонику инструкции или директивы, восстанавливается первоначальный смысл мнемоники в соответствии со значением данного ключевого слова. Директива PURGE часто используется для удаления ненужных макроопределений из подключаемой директивой INCLUDE библиотеки макроопределений. Библиотека макроопределений представляет собой обычный последовательный файл, который, в общем случае, может содержать большое число макроопределений. Комбинация директив INCLUDE и PURGE позволяет выбрать из них только нужные для данной программы, что сократит размер исходного файла.

Выход из текущего макроопределения до достижения директивы ENDM обеспечивается директивой EXITM, имеющей следующий формат:

 

EXITM

 

Выход из макроопределения по директивам ENDM и EXITM заключается в прекращении генерации текущего макрорасширения и возврате в точку вызова текущего макроопределения в динамически внешнем макрорасширении или в исходной программе. Ниже приведен пример законченного макроопределения:

 

add MACRO param

IFB param

EXITM

ENDIF

ADD AX,param

ENDM

 

В этом макроопределении осуществляется добавление величины, определяемой формальным параметром param, к содержимому регистра AX. Блок условного ассемблирования IFB обеспечивает выход из макроопределения, если при вызове параметр не был задан.

 


 

 

© 2013 wikipage.com.ua - Дякуємо за посилання на wikipage.com.ua | Контакти