Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
MProc / M2 / Лекция 2.doc
Скачиваний:
16
Добавлен:
16.04.2013
Размер:
207.36 Кб
Скачать

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

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

...

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

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

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

  • истина – число, которое содержит двоичные единицы во всех разрядах;

  • ложь – число, которое содержит двоичные нули во всех разрядах.

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

Контрольные вопросы.

  1. Как известно, команды ассемблера могут иметь метку. Может ли иметь метку директива? Если «да», то приведите парочку примеров.

  1. Может ли процедура содержать несколько сегментов ?

  1. Может ли сегмент содержать несколько процедур?

  1. Может ли программа не содержать ни одного сегмента?

  1. Может ли программа не содержать ни одной процедуры?

  1. Как сделать, чтобы все переходы типа JMPбыли бы длинными?

1 IEEE Standard for Binary Floating-Point Arithmetic, ANSI/IEEE Std. 754-1985 (IEEE, New York).

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