Синтаксис этих директив следующий:
IF(N)DEF символическое_имяфрагмент_программы_1 ELSEфрагмент_программы_2ENDIF |
Данные директивы позволяют управлять трансляцией фрагментов программы в зависимости от того, определено или нет в программе некоторое символическое_имя. Директива 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 не определено, то выйти из макросаEXITMelse ;иначе — на вычисление mov cl,nife sw sal x,cl ;умножение на степень 2 сдвигом влево else sar x,cl ;деление на степень 2 сдвигом вправо endifendif |
Как видим, эти директивы логически связаны с директивами 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<SIZE_Mexitm<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. После этого попробуйте два варианта действий:
- Определите где-то в начале исходного текста программы значение этой переменной с помощью equ:
- Запустите программу на трансляцию командной строкой вида
- tasm /dsize_m=15 /zi prg_13_2,,,
В листинге 6 мы использовали еще одну возможность транслятора — директиву display, с помощью которой можно формировать пользовательское сообщение в процессе трансляции программы.