- •Include directory
- •Include имя_файла_с_путём
- •Include dop1.Asm
- •Операции
- •Взаимодействие с языками высокого уровня.
- •II equ word ptr ll ; Равно 5678h
- •I2 equ word ptr c2 ; Равно …
- •Irp формальный_аргумент,
- •Irpc формальный_аргумент,строка_символов
- •Irpc rg,
- •Id_table label byte
- •Id_table label byte
- •IFxxx логическое_выражение_или_аргументы
- •If(e) логическое_выражение
- •If(n)def символическое_имя
- •Ifndef sw ;если sw не определено, то выйти из макроса
- •If(n)b аргумент
If(n)def символическое_имя
фрагмент_программы_1
ELSE
фрагмент_программы_2
ENDIF
Данные директивы позволяют управлять трансляцией фрагментов программы в зависимости от того, определено или нет в программе некоторое символическое_имя. Директива IFDEF проверяет, описано или нет в программе символическое_имя, и если это так, то в объектный модуль помещается фрагмент_программы_1. В противном случае, при наличии директивы ELSE, в объектный код помещается фрагмент_программы_2.
Если же директивы ELSE нет (и символическое_имя в программе не описано), то вся часть программы между директивами IF и ENDIF игнорируется и в объектный модуль не включается.
Действие IFNDEF обратно IFDEF. Если символического_имени в программе нет, то транслируется фрагмент_программы_1. Если оно присутствует, то при наличии ELSE транслируется фрагмент_программы_2. Если ELSE отсутствует, а символическое_имя в программе определено, то часть программы, заключенная между IFNDEF и ENDIF, игнорируется.
В качестве примера рассмотрим ситуацию, когда в объектный модуль программы должен быть включен один из трех фрагментов кода. Какой из трех фрагментов будет включен в объектный модуль, зависит от значения некоторого идентификатора switch:
если switch = 0, то сгенерировать фрагмент для вычисления выражения y = x*2**n;
если switch = 1, то сгенерировать фрагмент для вычисления выражения y = x/2**n;
если switch не определен, то ничего не генерировать.
Соответствующий фрагмент исходной программы может выглядеть так:
Ifndef sw ;если sw не определено, то выйти из макроса
EXITM
else ;иначе — на вычисление
mov cl,n
ife sw
sal x,cl ;умножение на степень 2 сдвигом влево
else
sar x,cl ;деление на степень 2 сдвигом вправо
endif
endif
Как видим, эти директивы логически связаны с директивами IF и IFE, то есть их можно применять в тех же самых случаях, что и последние.
Директивы IFB и IFNB.
Синтаксис этих директив следующий:
If(n)b аргумент
фрагмент_программы_1
ELSE
фрагмент_программы_2
ENDIF
Данные директивы используются для проверки фактических параметров, передаваемых в макрос. При вызове макрокоманды они анализируют значение аргумента, и в зависимости от того, равно оно пробелу или нет, транслируется либо фрагмент_программы_1, либо фрагмент_программы_1. Какой именно фрагмент будет выбран, зависит от кода директивы:
Директива IFB проверяет равенство аргумента пробелу. В качестве аргумента могут выступать имя или число. Если его значение равно пробелу (то есть фактический аргумент при вызове макрокоманды не был задан), то транслируется и помещается в объектный модуль фрагмент_программы_1. В противном случае, при наличии директивы ELSE, в объектный код помещается фрагмент_программы_1. Если же директивы ELSE нет, то при равенстве аргумента пробелу вся часть программы между директивами IFB и ENDIF игнорируется и в объектный модуль не включается.
Действие IFNB обратно IFB. Если значение аргумента в программе не равно пробелу, то транслируется фрагмент_программы_1. В противном случае, при наличии директивы ELSE, в объектный код помещается фрагмент_программы_1. Если же директивы ELSE нет, то вся часть программы (при неравенстве аргумента пробелу) между директивами IFNB и ENDIF игнорируется и в объектный модуль не включается.
Директивы IFIDN, IFIDNI, IFDIF и IFDIFI.
Эти директивы позволяют не просто проверить наличие или значение аргументов макрокоманды, но и выполнить идентификацию аргументов как строк символов.
Синтаксис этих директив:
IFIDN(I) <аргумент_1>,<аргумент_2>
фрагмент_программы_1
ELSE
фрагмент_программы_2
ENDIF
IFDIF(I) <аргумент_1>,<аргумент_2>
фрагмент_программы_1
ELSE
фрагмент_программы_2
ENDIF
В этих директивах проверяются аргумент_1 и аргумент_2 как строки символов. Какой именно код – фрагмент_программы_1 или фрагмент_программы_2 – будет транслироваться по результатам сравнения, зависит от кода директивы.
Парность этих директив объясняется тем, что они позволяют учитывать либо не учитывать различие строчных и прописных букв. Так, директивы IFIDNI и IFDIFI игнорируют это различие, а IFIDN и IFDIF – учитывают.
Директива IFIDN(I) сравнивает символьные значения аргумент_1 и аргумент_2. Если результат сравнения положительный, то фрагмент_программы_1 транслируется и помещается в объектный модуль. В противном случае, при наличии директивы ELSE, в объектный код помещается фрагмент_программы_2. Если же директивы ELSE нет, то вся часть программы между директивами IFIDN(I) и ENDIF игнорируется и в объектный модуль не включается.
Действие IFDIF(I) обратно IFIDN(I). Если результат сравнения отрицательный (строки не совпадают), транслируется фрагмент_программы_1. В противном случае все происходит аналогично рассмотренным ранее директивам.
Как уже упоминалось, эти директивы удобно применять для проверки
фактических аргументов макрокоманд. К примеру, проверим, какой из регистров - al или ah - передан в макрос в качестве параметра (проверка проводится без учета различия строчных и прописных букв):
show macro rg
ifdifi rg,<al>
goto M_al
else
ifdifi rg,<ah>
goto M_ah
else
exitm
endif
endif
:M_al
...
:M_ah
...
endm
Вложенность директив условной трансляции.
Как мы неоднократно видели, TASM допускает вложенность условных директив компиляции. Более того, так как вложенность требуется довольно часто, TASM предоставляет набор дополнительных директив формата ELSEIFxxx, которые заменяют последовательность подряд идущих ELSE и IFxxx в структуре:
IFxxx
;...
ELSE
IFxxx
;...
ENDIF
ENDIF
Эту последовательность условных директив можно заменить эквивалентной последовательностью дополнительных директив:
IFxxx
;...
ELSEIFxxx
;...
ENDIF
Наличие xxx в ELSExxx говорит о том, что каждая из директив IF, IFB, IFIDN и т.д. имеет аналогичную директиву ELSEIF, ELSEIFB, ELSEIFIDN и т.д. В конечном итоге это улучшает читаемость кода. В последнем примере фрагмента макроса, проверяющем, имя какого регистра было передано в макрос, наблюдается подобная ситуация. Последовательность ELSE и IFDIFI можно записать так:
show macro rg
ifdifi rg,<al>
goto M_al
elseifdifi rg,<ah>
goto M_ah
else
exitm
endif
:M_al
...
:M_ah
...
endm
Директивы генерации ошибок.
В языке TASM есть ряд директив, называемых директивами генерации пользовательской ошибки. Их можно рассматривать и как самостоятельное средство, и как метод, расширяющий возможности директив условной компиляции. Они предназначены для обнаружения различных ошибок в программе, таких как неопределенные метки или пропуск параметров макроса.
Директивы генерации пользовательской ошибки по принципу работы можно разделить на два типа:
безусловные директивы, генерирующие ошибку трансляции без проверки каких-либо условий;
условные директивы, генерирующие ошибку трансляции после проверки определенных условий.
Большинство директив генерации ошибок имеют два обозначения, хотя принцип их работы одинаков. Второе название отражает их сходство с директивами условной компиляции. При дальнейшем обсуждении такие парные директивы будут приводиться в скобках.
Безусловная генерация пользовательской ошибки.
К безусловным директивам генерации пользовательской ошибки относится только одна директива – это ERR (.ERR).
Данная директива, будучи вставлена в текст программы, безусловно приводит к генерации ошибки на этапе трансляции и удалению объектного модуля. Она очень эффективна при ее использовании с директивами условной компиляции или в теле макрокоманды с целью отладки.
К примеру, эту директиву можно было бы вставить в ту ветвь программы (в последнем рассмотренном нами макроопределении), которая выполняется, если указанный в качестве аргумента регистр отличен от al и ah:
show macro rg
ifdifi rg,<al>
goto M_al
else
ifdifi rg,<ah>
goto M_ah
else
.err “Недопустимый тип аргумента”
endif
endif
:M_al
...
:M_ah
...
endm
Если после определенного таким образом макроопределения в сегменте кода вызвать макрокоманду show с фактическим параметром, отличным от имен регистров ah или al, будет сгенерирована ошибка компиляции (с текстом “Недопустимый тип аргумента”), сам процесс компиляции прекращен и, естественно, объектный модуль создан не будет.
Остальные директивы являются условными, так как их поведение определяют некоторые условия.
Условная генерация пользовательской ошибки.
Набор условий, на которые реагируют директивы условной генерации пользовательской ошибки, такой же, как и у директив условной компиляции. Поэтому и количество этих директив такое же.
К их числу относятся следующие директивы:
.ERRB (ERRIFB) и .ERRNB (ERRIFNB)
.ERRDEF (ERRIFDEF) и .ERRNDEF (ERRIFNDEF)
.ERRDIF (ERRIFDIF) и .ERRIDN (ERRIFIDN)
.ERRE (ERRIFE) и .ERRNZ (ERRIF)
Принцип их работы ясен, поэтому рассматривать их мы будем очень кратко. Заметим только, что как и директивы условной компиляции, использовать большинство директив условной генерации пользовательской ошибки можно как в макроопределениях, так и в любом месте программы.
Директивы .ERRB (ERRIFB) и .ERRNB (ERRIFNB).
Синтаксис директив:
.ERRB (ERRIFB) <имя_формального_аргумента>
генерация пользовательской ошибки, если <имя_формального_аргумента> пропущено;
.ERRNB (ERRIFNB) <имя_формального_аргумента>
генерация пользовательской ошибки, если <имя_формального_аргумента> присутствует.
Данные директивы применяются для генерации ошибки трансляции в зависимости от того, задан или нет при вызове макрокоманды фактический аргумент, соответствующий формальному аргументу в заголовке макроопределения с именем <имя_формального_аргумента>.
По принципу действия эти директивы полностью аналогичны соответствующим директивам условной компиляции IFB и IFNB. Их обычно используют для проверки задания параметров при вызове макроса.
Строка имя_формального_аргумента должна быть заключена в угловые скобки.
К примеру, определим обязательность задания фактического аргумента, соответствующего формальному аргументу rg, в макросе show:
show macro rg
.errb “аргумент не задан” ;и завершаем компиляцию
; текст макроопределения
endm
Директивы .ERRDEF (ERRIFDEF) и .ERRNDEF (ERRIFNDEF).
Синтаксис директив:
.ERRDEF(ERRIFDEF) символическое_имя
если указанное символическое_имя определено до выдачи этой директивы в программе, то генерируется пользовательская ошибка.
.ERRNDEF(ERRIFNDEF) символическое_имя
— если указанное символическое_имя не определено до момента обработки транслятором данной директивы, то генерируется пользовательская ошибка.
Данные директивы генерируют ошибку трансляции в зависимости от того, определено или нет некоторое символическое_имя в программе.
Не забывайте о том, что компилятор TASM по умолчанию формирует объектный модуль за один проход исходного текста программы. Следовательно, директивы .ERRDEF (ERRIFDEF) и .ERRNDEF (ERRIFNDEF) отслеживают факт определения символического_имени только в той части исходного текста, которая находится до этих директив.
Директивы .ERRDIF (ERRIFDIF) и .ERRIDN (ERRIFIDN).
Синтаксис директив:
.ERRDIF (ERRIFDIF) <строка_1>,<строка_2>
директива, генерирующая пользовательскую ошибку, если две строки посимвольно не совпадают. Строки могут быть символическими именами, числами или выражениями и должны быть заключены в угловые скобки. Аналогично директиве условной компиляции IFDIF, при сравнении учитывается различие прописных и строчных букв.
.ERRIDN (ERRIFIDN) <строка_1>,<строка_2>
директива, генерирующая пользовательскую ошибку, если строки посимвольно идентичны. Строчное и прописное написание одной и той же буквы воспринимается как разные символы.
Для того чтобы игнорировать различия строчных и прописных букв, существуют аналогичные директивы:
.ERRIFDIFI <строка_1>,<строка_2>
то же, что и ERRIFDIF, но игнорируется различие строчных и прописных букв при сравнении <строка_1> и <строка_2>.
.ERRIFIDNI <строка_1>,<строка_2>
то же, что и ERRIFIDN, но игнорируется различие строчных и прописных букв при сравнении <строка_1> и <строка_2>.
Данные директивы, как и соответствующие им директивы условной компиляции, удобно применять для проверки передаваемых в макрос фактических параметров.
Директивы .ERRE (ERRIFE) и .ERRNZ (ERRIF).
Синтаксис директив:
.ERRE (ERRIFE) константное_выражение
директива вызывает пользовательскую ошибку, если константное_выражение ложно (равно нулю). Вычисление константного_выражения должно приводить к абсолютному значению, и это выражение не может содержать компонентов, являющихся
ссылками вперед.
.ERRNZ(ERRIF) константное_выражение
директива вызывает пользовательскую ошибку, если константное_выражение истинно (не равно нулю). Вычисление константного_выражения должно приводить к абсолютному
значению и не может содержать компонентов, являющихся ссылками вперед.
Константные выражения в условных директивах.
Как вы успели заметить, во многих условных директивах в формировании условия участвуют выражения. Результат вычисления этого выражения обязательно должен быть константой. Хотя его компонентами могут быть и символические параметры, но их сочетание в выражении должно давать абсолютный результат. К примеру:
.data
mas db ...
len dd ...
...
.code
...
.erre (len-mas) lt 10 ;генерация ошибки, если длина
;области mas меньше 10 байт
...
Кроме того, выражение не должно содержать компоненты, которые транслятор еще не обработал к тому месту программы, где находится условная директива. Также мы отметили, что логические результаты “истина” и “ложь” являютсяусловными в том смысле, что ноль соответствует логическому результату “ложь”, а любое ненулевое значение — “истине”.
Но в языке ассемблера существуют операторы, которые позволяют сформировать и “чисто логический” результат. Это так называемые операторы отношений, выражающие отношение двух значений или константных выражений.
В контексте условных директив вместе с операторами отношений можно рассматривать и логические операторы. Результатом работы и тех, и других может быть одно из двух значений:
истина – число, которое содержит двоичные единицы во всех разрядах;
ложь – число, которое содержит двоичные нули во всех разрядах.
Операторы, которые можно применять в выражениях условных директив, аналогичны тем, которые были при рассмотрении операций.
Контрольные вопросы.
Как известно, команды ассемблера могут иметь метку. Может ли иметь метку директива? Если «да», то приведите парочку примеров.
Может ли процедура содержать несколько сегментов ?
Может ли сегмент содержать несколько процедур?
Может ли программа не содержать ни одного сегмента?
Может ли программа не содержать ни одной процедуры?
Как сделать, чтобы все переходы типа JMP были бы длинными?
1 IEEE Standard for Binary Floating-Point Arithmetic, ANSI/IEEE Std. 754-1985 (IEEE, New York).
2 Числа, у которых самый старший разряд мантиссы не нулевой называются нормализованными. Такие числа обеспечивают максимальную точность представления. Поскольку целая часть мантиссы всегда 1, то хранить ее нет необходимости.
