Конспект лекций Системное программирование (семестр 2) Возле названия каждой лекции написано число пар, в течение которых она будет читаться (+ ср обозначает

Вид материалаКонспект
Директивы WHILE и REPT
ENDM. При использовании директивы WHILE
REPT, подобно директиве WHILE
WHILE и REPT
REPT уменьшается автоматически после каждой итерации цикла. Проанализируйте результат трансляции листинга 13.3. Таким образом, д
Директива IRP
Директива IRPC
IRP, но отличается тем, что она на каждой очередной итерации заменяет формальный_аргумент
Директивы условной компиляции
EXITM и GOTO
GOTO имя_метки
Директивы компиляции по условию
Директивы IF и IFE
ELSE в объектный код помещается фрагмент_программы_2
IFE аналогично директиве IF
Директивы IFDEF и IFNDEF
IF и ENDIF
Директивы IFB и IFNB
IFB проверяет равенство аргумента
ELSE, в объектный код помещается фрагмент_программы_1
...
Полное содержание
Подобный материал:
1   ...   47   48   49   50   51   52   53   54   ...   57

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


С помощью макросредств ассемблера можно не только частично изменять входящие в макроопределение строки, но и модифицировать сам набор этих строк и даже порядок их следования. Сделать это можно с помощью набора макродиректив (далее — просто директив). Их можно разделить на две группы:
  • директивы повторения WHILE, REPT, IRP и IRPC.
  • Директивы этой группы предназначены для создания макросов, содержащих несколько идущих подряд одинаковых последовательностей строк. При этом возможна частичная модификация этих строк.
  • директивы управления процессом генерации макрорасширения EXITM и GOTO.
  • Они предназначены для управления процессом формирования макрорасширения из набора строк соответствующего макроопределения. С помощью этих директив можно как исключать отдельные строки из макрорасширения, так и вовсе прекращать процесс генерации. Директивы EXITM и GOTO обычно используются вместе с условными директивами компиляции, поэтому они будут рассмотрены вместе с ними.

Директивы WHILE и REPT


Директивы WHILE и REPT применяют для повторения определенное количество раз некоторой последовательности строк.

Эти директивы имеют следующий синтаксис:

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

последовательность_строк

ENDM






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

последовательность строк

ENDM

Обратите внимание, что последовательность повторяемых строк в обеих директивах ограничена директивой ENDM.

При использовании директивы WHILE макрогенератор транслятора будет повторять последовательность_строк до тех пор, пока значение константное_выражение не станет равно нулю. Это значение вычисляется каждый раз перед очередной итерацией цикла повторения (то есть значение константное_выражение должно подвергаться изменению внутри последовательность_строк в процессе макрогенерации).

Директива REPT, подобно директиве WHILE, повторяет последовательность_строк столько раз, сколько это определено значением константное_выражение. Отличие этой директивы от WHILE состоит в том, что она автоматически уменьшает на единицу значение константное_выражение после каждой итерации.

В качестве примера рассмотрим листинг 4, в котором демонстрируется применение директив WHILE и REPT для резервирования области памяти в сегменте данных. Имя идентификатора и длина области задаются в качестве параметров для соответствующих макросов def_sto_1 и def_sto_2.



Листинг 4. Использование директив повторения

;prg_13_3.asm

def_sto_1 macro id_table,ln:=<5>

;макрос резервирования памяти длиной len.

;Используется WHILE

id_table label byte

len=ln

while len

db 0

len=len-1

endm

endm

def_sto_2 macro id_table,len

;макрос резервирования памяти длиной len

id_table label byte

rept len

db 0

endm

endm


data segment para public 'data'

def_sto_1 tab_1,10

def_sto_2 tab_2,10

data ends

;сегменты команд и стека в этой программе необязательны

end

Заметьте, что счетчик повторений в директиве REPT уменьшается автоматически после каждой итерации цикла. Проанализируйте результат трансляции листинга 13.3.

Таким образом, директивы REPT и WHILE удобно применять для “размножения” в тексте программы последовательности одинаковых строк без внесения в эти строки каких-либо изменений.

Следующие две директивы, IRP и IRPC, делают этот процесс более гибким, позволяя модифицировать на каждой итерации некоторые элементы в последовательность_строк.

Директива IRP


Директива IRP имеет следующий синтаксис:

IRP формальный_аргумент,<строка_символов_1,...,строка_символов_N>

последовательность_строк

ENDM

Действие данной директивы заключается в том, что она повторяет последовательность_строк N раз, то есть столько раз, сколько строк_символов заключено в угловые скобки во втором операнде директивы IRP. Но это еще не все.

Повторение последовательности_строк сопровождается заменой в ней формального_аргумента строкой символов из второго операнда.

Так, при первой генерации последовательности_строк формальный_аргумент в них заменяется на строка_символов_1.

Если есть строка_символов_2, то это приводит к генерации второй копии последовательности_строк, в которой формальный_аргумент заменяется на строка_символов_2. Эти действия продолжаются до строка_символов_N включительно.

К примеру, рассмотрим результат определения в программе следующей конструкции:

irp ini,<1,2,3,4,5>

db ini

endm

Макрогенератором будет сгенерировано следующее макрорасширение:

db 1

db 2

db 3

db 4

db 5

Директива IRPC


Директива IRPC имеет следующий синтаксис:

IRPC формальный_аргумент,строка_символов

последовательность строк

ENDM

Действие данной директивы подобно IRP, но отличается тем, что она на каждой очередной итерации заменяет формальный_аргумент очередным символом из строка_символов.

Понятно, что количество повторений последовательность_строк будет определяться количеством символов в строка_символов.

К примеру:

irpc rg,

push rg&x

endm

В процессе макрогенерации эта директива развернется в следующую последовательность строк:

push ax

push bx

push cx

push dx

Директивы условной компиляции


Последний тип макросредств — директивы условной компиляции.

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

С этими директивами применяются директивы управления процессом генерации макрорасширений EXITM и GOTO.

Директива EXITM не имеет операндов, и ее действие заключается в том, что она немедленно прекращает процесс генерации макрорасширения, начиная с того места, где она встретилась в макроопределении.

Директива GOTO имя_метки переводит процесс генерации макроопределения в другое место, прекращая тем самым последовательное разворачивание строк макроопределения. Метка, на которую передается управление, имеет специальный формат:

:имя_метки

Примеры применения этих директив будут приведены ниже.

Директивы компиляции по условию


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

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

Всего имеется 10 типов условных директив компиляции. Их логично попарно объединить в четыре группы:
  1. Директивы IF и IFE — условная трансляция по результату вычисления логического выражения.
  2. Директивы IFDEF и IFNDEF — условная трансляция по факту определения символического имени.
  3. Директивы IFB и IFNB — условная трансляция по факту определения фактического аргумента при вызове макрокоманды.
  4. Директивы IFIDN, IFIDNI, IFDIF и IFDIFI — условная трансляция по результату сравнения строк символов.

Условные директивы компиляции имеют общий синтаксис и применяются в составе следующей синтаксической конструкции:

IFxxx логическое_выражение_или_аргументы

фрагмент_программы_1

ELSE

фрагмент_программы_2

ENDIF

Заключение некоторых фрагментов текста программы — фрагмент_программы_1 и фрагмент_программы_2 — между директивами IFxxx, ELSE и ENDIF приводит к их выборочному включению в объектный модуль. Какой именно из этих фрагментов — фрагмент_программы_1 или фрагмент_программы_2 — будет включен в объектный модуль, зависит от конкретного типа условной директивы, задаваемого значением xxx, и значения условия, определяемого операндом (операндами) условной директивы логическое_выражение_или_аргумент(ы).

Синтаксические конструкции, соответствующие директивам условной компиляции, могут быть вложенными друг в друга (см. "Вложенность директив условной трансляции")

Директивы IF и IFE


Синтаксис этих директив следующий:

IF(E) логическое_выражение

фрагмент_программы_1

ELSE

фрагмент_программы_2

ENDIF

Обработка этих директив макроассемблером заключается в вычислении логического_выражения и включении в объектный модуль фрагмент_программы_1 или фрагмент_программы_2 в зависимости от того, в какой директиве IF или IFE это выражение встретилось:
  • если в директиве IF логическое выражение истинно, то в объектный модуль помещается фрагмент_программы_1.
  • Если логическое выражение ложно, то при наличии директивы ELSE в объектный код помещается фрагмент_программы_2. Если же директивы ELSE нет, то вся часть программы между директивами IF и ENDIF игнорируется и в объектный модуль ничего не включается. Кстати сказать, понятие истинности и ложности значения логического_выражения весьма условно. Ложным оно будет считаться, если его значение равно нулю, а истинным — при любом значении, отличном от нуля.
  • директива IFE аналогично директиве IF анализирует значение логического_выражения. Но теперь для включения фрагмент_программы_1 в объектный модуль требуется, чтобы логическое_выражение имело значение “ложь”.

Директивы IF и IFE очень удобно использовать при необходимости изменения текста программы в зависимости от некоторых условий.

К примеру, составим макрос для определения в программе области памяти длиной не более 50 и не менее 10 байт (листинг 5).

Листинг 5. Использование условных директив IF и IFE

<1>;prg_13_4.asm

<2>masm

<3>model small

<4> stack 256

<5> def_tab_50 macro len

<6>if len GE 50

<7>GOTO exit

<8>endif

<9> if len LT 10

<10>:exit

<11>EXITM

<12>endif

<13>rept len

<14> db 0

<15>endm

<16>endm

<17>.data

<18>def_tab_50 15

<19> def_tab_50 5

<20>.code

<21>main:

<22> mov ax,@data

<23> mov ds,ax

<24>exit:

<25> mov ax,4c00h

<26> int 21h

<27>end main

ENDIF

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

В нем вы увидите, что в результате трансляции строка 18 листинга 5 развернется в пятнадцать нулевых байт, а строка 19 оставит макрогенератор совершенно равнодушным, так как значение фактического операнда в строках 6 и 9 будет ложным. Обратите внимание, что для обработки реакции на ложный результат анализа в условной директиве мы использовали макродирективы EXITM и GOTO.

Другой интересный и полезный вариант применения директив IF и IFEотладочная печать.

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

Можно определить в программе некоторую переменную, к примеру debug, и использовать ее совместно с условными директивами IF или IFE. К примеру,

<1>...

<2>debug equ 1

<3>...

<4>.code

<5>...

<6>if debug

<7>;любые команды и директивы ассемблера

<8>;(вывод на печать или монитор)

<9>endif

На время отладки и тестирования программы вы можете заключить отдельные участки кода в своеобразные операторные скобки в виде директив IF и ENDIF (строки 6-9 последнего фрагмента), которые реагируют на значение логической переменной debug. При значении debug = 0 транслятор полностью проигнорирует текст внутри этих условных операторных скобок; при debug = 1, наоборот, будут выполнены все действия, описанные внутри них.

Директивы IFDEF и IFNDEF


Синтаксис этих директив следующий:

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, то есть их можно применять в тех же самых случаях, что и последние.

Есть еще одна интересная возможность использования этих директив. На уроке 4 мы обсуждали формат командной строки и говорили об опциях, которые в ней можно задавать. Вспомните одну из опций командной строки TASM — опцию

/dидентификатор=значение.

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

В качестве примера рассмотрим листинг 6, в котором мы попытаемся с помощью макроса контролировать процесс резервирования и инициализации некоторой области памяти в сегменте данных.

Листинг 6. Инициализация значения идентификатора из командной строки

<1>;prg_13_5.asm

<2>masm

<3>model small

<4> stack 256

<5>def_tab_50 macro len

<6>ifndef len

<7>display 'size_m не определено, задайте значение 10
<9>else

<10>if len GE 50

<11>GOTO exit

<12>endif

<13>if len LT 10

<14>:exit

<15>EXITM

<16>endif

<17>rept len

<18> db 0

<19>endm

<20>endif

<21>endm

<22>;size_m=15

<23>.data

<24>def_tab_50 size_m

<25>

<26>.code

<27>main:

<28> mov ax,@data

<29> mov ds,ax

<30>exit:

<31> mov ax,4c00h

<32> int 21h

<33>end main

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

    size_m equ 15
  2. Запустите программу на трансляцию командной строкой вида
  3. tasm /dsize_m=15 /zi prg_13_2,,,

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

Директивы 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 игнорируется и в объектный модуль не включается.

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

show macro reg

ifb

display 'не задан регистр'

exitm

endif

...

endm

Если теперь в сегменте кода вызвать макрос show без аргументов, то будет выведено сообщение о том, что не задан регистр и генерация макрорасширения будет прекращена директивой exitm.

Директивы IFIDN, IFIDNI, IFDIF и IFDIFI


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

Синтаксис этих директив:

IFIDN(I) аргумент_1,аргумент_2

фрагмент_программы_1

ELSE

фрагмент_программы_2

ENDIF




IFDIF(I) аргумент_1,аргумент_2

фрагмент_программы_1

ELSE

фрагмент_программы_2

ENDIF

В этих директивах проверяются аргумент_1 и аргумент_2 как строки символов. Какой именно код — фрагмент_программы_1 или фрагмент_программы_1 — будет транслироваться по результатам сравнения, зависит от кода директивы.

Парность этих директив объясняется тем, что они позволяют учитывать либо не учитывать различие строчных и прописных букв. Так, директивы IFIDNI и IFDIFI игнорируют это различие, а IFIDN и IFDIF — учитывают.

Директива IFIDN(I) сравнивает символьные значения аргумент_1 и аргумент_2.

Если результат сравнения положительный, то фрагмент_программы_1 транслируется и помещается в объектный модуль.

В противном случае, при наличии директивы ELSE, в объектный код помещается фрагмент_программы_1.

Если же директивы ELSE нет, то вся часть программы между директивами IFIDN(I) и ENDIF игнорируется и в объектный модуль не включается.

Действие IFDIF(I) обратно IFIDN(I).

Если результат сравнения отрицательный (строки не совпадают), транслируется фрагмент_программы_1.

В противном случае все происходит аналогично рассмотренным ранее директивам.

Как мы уже упоминали, эти директивы удобно применять для проверки фактических аргументов макрокоманд.

К примеру, проверим, какой из регистров — al или ah — передан в макрос в качестве параметра (проверка проводится без учета различия строчных и прописных букв):

show macro rg

ifdifi ,

goto M_al

else

ifdifi ,

goto M_ah

else

exitm

endif

endif

:M_al

...

:M_ah

...

endm

ENDIF

Вложенность директив условной трансляции


Как мы неоднократно видели в приведенных выше примерах, TASM допускает вложенность условных директив компиляции. Более того, так как вложенность требуется довольно часто, TASM предоставляет набор дополнительных директив формата ELSEIFxxx, которые заменяют последовательность подряд идущих ELSE и IFxxx в структуре:

IFxxx

;

ELSE

IFxxx

;...

ENDIF

ENDIF

Эту последовательность условных директив можно заменить эквивалентной последовательностью дополнительных директив:

IFxxx

;...

ELSEIFxxx

;...

ENDIF

Наличие xxx в ELSExxx говорит о том, что каждая из директив IF, IFB, IFIDN и т. д. имеет аналогичную директиву ELSEIF, ELSEIFB, ELSEIFIDN и т. д.

В конечном итоге это улучшает читаемость кода. В последнем примере фрагмента макроса, проверяющем, имя какого регистра было передано в макрос, наблюдается подобная ситуация. Последовательность ELSE и IFDIFI можно записать так, как в строке 4:

<1>show macro rg

<2>ifdifi ,

<3>goto M_al

<4>elseifdifi ,

<5> goto M_ah

<6>else

<7>exitm

<8>endif

<9>:M_al

<10>...

<11>:M_ah

<12>...

<13>endm

Директивы генерации ошибок


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

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

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

Безусловная генерация пользовательской ошибки


К безусловным директивам генерации пользовательской ошибки относится только одна директива — это ERR (.ERR).

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

К примеру, эту директиву можно было бы вставить в ту ветвь программы (в последнем рассмотренном нами макроопределении), которая выполняется, если указанный в качестве аргумента регистр отличен от al и ah:

show macro rg

ifdifi ,

goto M_al

else

ifdifi ,

goto M_ah

else

.Err

endif

endif

...

endm

Если после определенного таким образом макроопределения в сегменте кода вызвать макрокоманду show с фактическим параметром, отличным от имен регистров ah или al, будет сгенерирована ошибка компиляции (с текстом “User error”), сам процесс компиляции прекращен и, естественно, объектный модуль создан не будет.

Остальные директивы являются условными, так как их поведение определяют некоторые условия.

Условная генерация пользовательской ошибки


Набор условий, на которые реагируют директивы условной генерации пользовательской ошибки, такой же, как и у директив условной компиляции. Поэтому и количество этих директив такое же. К их числу относятся следующие директивы:
  • .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:

<1> show macro rg

<2>;если rg в макрокоманде не будет задан,

<3>;то завершить компиляцию

<4>.errb

<5>;текст макроопределения

<6>;...

<7>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 байт

...

Кроме того, выражение не должно содержать компоненты, которые транслятор еще не обработал к тому месту программы, где находится условная директива.

Также мы отметили, что логические результаты “истина” и “ложь” являются условными в том смысле, что ноль соответствует логическому результату “ложь”, а любое ненулевое значение — “истине”.

Но в языке ассемблера существуют операторы, которые позволяют сформировать и “чисто логический” результат. Это так называемые операторы отношений, выражающие отношение двух значений или константных выражений.

В контексте условных директив вместе с операторами отношений можно рассматривать и логические операторы. Результатом работы и тех, и других может быть одно из двух значений:
  • истина — число, которое содержит двоичные единицы во всех разрядах;
  • ложь — число, которое содержит двоичные нули во всех разрядах.

Операторы, которые можно применять в выражениях условных директив и которые формируют логические результаты, приведены в табл. 1 и 2.
Таблица 1. Операторы отношений

Оператор/

Синтаксис

Результат отношения

EQ (equal) — равно

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

истина — если выражение_1 равно выражение_2

NE (not equal) — не

равно

Выражение_1 NE выражение_2

Истина — если выражение_1 не равно выражение_2

LT (less than) — меньше

Выражение_1 LT выражение_2

Истина — если выражение_1 меньше выражение_2

LE (less or equal) — меньше или равно

Выражение_1 LE выражение_2

Истина — если выражение_1 меньше или равно выражение_2

GT (greater than) — больше

Выражение_1 GT выражение_2

Истина — если выражение_1 больше выражение_2

GE (greater or equal) — больше или равно

Выражение_1 GE выражение_2

Истина — если выражение_1 больше или равно выражение_2
Таблица 2. Логические операторы

Оператор

Синтаксис

Результат

NOT — логическое отрицание

NOT выражение

Истина — если выражение ложно;

ложь — если выражение истинно

AND — логическое И

выражение_1 AND выражение_2

Истина — если выражение_1 и выражение_2 истинны

OR — логическое ИЛИ

выражение_1 OR выражение_2

Истина — если выражение_1 или выражение_2 истинны

XOR — исключающее ИЛИ

выражение_1 XOR выражение_2

Истина — если выражение_1 = (NOT выражение_2)

Дополнительное управление трансляцией


TASM предоставляет средства для вывода текстового сообщения во время трансляции программы — директивы DISPLAY и %OUT. С их помощью можно, при необходимости, следить за ходом трансляции.

К примеру:

display недопустимые аргументы макрокоманды

...

%out недопустимое имя регистра

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