LAB_9_2014c (1075931), страница 3
Текст из файла (страница 3)
[ELSE
<директивы для ложного значения условия> ]
ENDIF
Рассмотрим простые примеры условных директив:
IF N EQ 5
print 'A', PER
ELSE
print 'B', PER
ENDIF
Если переменная этапа компиляции N равна 5, то выполняется обращение к макрокоманде print с параметром ‘A’, в противном случае с параметром ‘B’.
IFIDN <&CR>,<PER>
CALL LFCR
ENDIF
Если параметр макрокоманды (CR) установлен в значение <PER>, то вызывается процедура перевода строки и возврата каретки.
IFNDEF COUNT
COUNT = 0
ENDIF
Если переменная этапа компиляции COUNT пока не определена, то она определяется с начальным значением равным нулю.
IFB V
JMP MET
ENDIF
Если параметр макрокоманды V не задан при вызове (BLANK - пустой), то генерируется команда безусловной передачи управления на метку.
Надеюсь, что более полную информацию по условной компиляции вы найдете в литературе, документации и справочниках по ассемблеру и макроассемблеру (см. список литературы). Практическое использование таких директив Вы должны продемонстрировать при выполнении 9-й ЛР.
15 Директива EXITM
Обычно работа макрокоманды завершается в тот момент, когда встретилась последняя для рассмотрения директива ENDM макроопределения. Существует и другая возможность завершить работу макрокоманды (как процедуры этапа компиляции) – это использование директивы EXITM. Если встретилась такая директива, то дальнейший режим обработки макровызова завершается и Ассемблер переключается на обработку команды, следующей за данным макровызовом. В одном макроопределении может быть несколько выходов, которые выполняются директивой EXITM. Например, если после проверки параметра мы обнаруживаем ошибку, то можем сделать выход из макроопределения. Например:
…
IF <PAR> NE <TEST>
…
JMP MET
ELSE
EXITM
…
ENDIF
…
EQ exp1 EQ exp2 TRUE, если выражение1 равно выражению2
NE exp1 NE exp2 TRUE,если выражение1 не равно выражению2
LT exp1 LT ехр2 TRUE,если выражение1 меньше
выражения2
LE exp1 LE exp2 TRUE,если выражение1 меньше
или равно выражению 2
GT exp1 GT exp2 TRUE,если выражение1 больше
выражения2
GE exp1 GE exp2 TRUE,если выражение1 больше
или равно выражению2
NOT NOT exp TRUE,если выражение - FALSE,
иначе FALSE
AND exp1 AND exp2 TRUE,если только оба выражение1
и выражение2 - TRUE
OR exp1 OR exp2 TRUE,если выражение1 либо выра-
жение2 - TRUE
XOR exp1 XOR exp2 TRUE,если выражение1 равно лог.
NOT от выражения2
FALSE (0000 16-CC) Для IF TRUE любое нулевое выра-
жение - FALSE
TRUE (FFFF 16-CC) Для IF TRUE любoe ненулевое вы-
ражение – TRUE
16 Отладка макрокоманд
Отладка макрокоманд является трудоемкой задачей, так как нет специальных отладчиков для этого. Результат работы макрокоманд можно увидеть только в листинге программы с включенным режимом макрорасширений (см. выше). По результатам макрорасширений можно судить о правильности их работы. При необходимости можно выдать сообщение на стандартный вывод (дисплей или окно ошибок) собственное пользовательское сообщение. Это выполняется директивой %OUT. Например:
%OUT Отладка макрокоманды print
В окно ошибок будет помещено это сообщение. Если такая директива встретится в макрокоманде, то будет напечатано это сообщение. Для инициации (форсированном выполнении прерывания компиляции) ошибки используется другая директива - .ERR. Например:
.ERR
%OUT Ошибка в макрокоманде print
В окно ошибок будет помещено это сообщение, в текст листинга также вставиться сообщение и компиляция останавливается.
17 Сравнение макросов и процедур
По сравнению с процедурами макрокоманды имеют, как минимум, следующие четыре преимущества:
-
Макрокоманды являются более гибкими по сравнению с процедурами. Они позволяют задавать параметры, пропускать их при вызове макрокоманд, выполнять условную компиляцию.
-
Макрокоманды выполняются с более высокой скоростью (более эффективной), так как не тратиться время на команды вызова, а все действия по настройке выполняются на этапе компиляции.
-
Макрокоманды легко упаковать в библиотеку и подключать их в программу.
-
Программа, построенная на основе макрокоманд, является более наглядной и понятной.
Недостатками макрокоманд по сравнению с процедурами является:
-
Программа, построенная на основе макрокоманд, имеет больший размер, так как при каждом вызове макрокоманды выполняется макрорасширение. В некоторых случаях это может стать существенным недостатком.
-
Макрокоманды труднее отлаживать, так как трудно создать специальный отладчик, так как все выполняется на этапе компиляции.
В целом, можно сделать вывод, что если рационально использовать комбинацию механизмов макрокоманд и процедур, то можно получить эффективный и наглядный код даже на языке Ассемблера.
18 Макрокоманды – процедуры этапа компиляции
Для тех, кто хорошо освоил механизм макрокоманд, приходит понимание того, что механизм макрокоманд и условной компиляции программ очень мощный и эффективный механизм для создания программных систем. Главное понять, что макрокоманды, по сути, являются процедурами этапа компиляции. Так как существует возможность вложенного вызова макрокоманд, возможность определения переменных этапа компиляции и использования библиотек, то возникает возможность описания собственного языка специального назначения. Действительно существуют специализированные системы программирования, целиком построенные на основе макроассемблера. Например, система имитационного моделирования GPSS в первых своих версиях была реализована по этой схеме. Важно, что трудозатраты на такие системы значительно ниже, чем при создании системы программирования с нуля.
19 Примеры программы с макросами
В следующем тексте работающей программы с макросами, которые я привожу без пояснений, вы найдете много полезных фрагментов для выполнения 9-й ЛР.
mycode segment 'code'
assume cs:mycode, ds:mycode
assume ss: stseg
; Макрокоманда выделения памяти c заполнением выражениями
FCount = 1
Fparam = 1
FIELD MACRO VAR
DB &VAR
ENDM
;;; Натуральные числа в порядке возрастания
MAS MACRO SIZEM , NAME , BASE
FCount = BASE
&NAME DB BASE
REPT SIZEM - 1
FIELD %FCount + 1
FCount = FCount + 1
ENDM
ENDM
;;; Натуральные числа в порядке убывания
MASM MACRO SIZEM , NAME , BASE , STEP
FCount = BASE
&NAME DB BASE
REPT SIZEM - 1
FIELD %FCount - 1
FCount = FCount - STEP
ENDM
ENDM
; Арифметическая прогрессия
MASN MACRO SIZEM , NAME , BASE , STEP
FCount = 1
&NAME DB BASE
REPT SIZEM - 1
FIELD %FCount * STEP + BASE
FCount = FCount + 1
ENDM
ENDM
; Геометрическая прогрессия
MASP MACRO SIZEM , NAME , BASE , STEP
FCount = 1
&NAME DB STEP + BASE
REPT SIZEM - 1
FParam = 1
REPT Fcount + 1
FParam = Fparam * STEP
ENDM
FIELD %FParam + BASE
FCount = FCount + 1
ENDM
ENDM
; Макрокоманда суммировани
SUM MACRO NAME , SIZE , VSUM
LOCAL VM
LOCAL VERR
PUSH CX
PUSH AX
PUSH DX
PUSH SI
MOV CX , SIZE
CMP CX , 0
JB VERR
XOR AX , AX
MOV SI,0
XOR DX , DX
VM: MOV DL , NAME[SI]
ADD AX, DX
INC SI
LOOP VM
MOV VSUM , AX
MOV DX, AX
CALL PRINTDEC
VERR: POP SI
POP DX
POP AX
POP CX
ENDM
;Макрокоманда для произведения
PRSTR MACRO NAME , SIZE , KSTR
LOCAL MC
LOCAL MC1
LOCAL MFIN
LOCAL MPROD
PUSH CX
PUSH SI
;; НУ цикла
;; Перевод строки
mov dl, 0Ah
mov ah, 2
int 21h
mov dl, 0Dh
mov ah, 2
int 21h
MOV CX , SIZE
MOV SI , 0
;; Цикл по массиву
MC: PUSH CX
MOV CX , KSTR
;; Цикл по строке
MC1: MOV DL, NAME[SI]
CALL PRINTB
INC SI
CMP SI , SIZE
JNE MPROD
;; Последний перевод
mov dl, 0Ah
mov ah, 2
int 21h
mov dl, 0Dh
mov ah, 2
int 21h
JMP MFIN
MPROD:
LOOP MC1
POP CX
;; Перевод строки
mov dl, 0Ah
mov ah, 2
int 21h
mov dl, 0Dh
mov ah, 2
int 21h
LOOP MC
;; Конец Цикла
MFIN:
POP SI
POP CX
ENDM
;Макрокоманда печати массива в десятичном виде по столбцам
PRCOL MACRO NAME , SIZE , KCOL
LOCAL MC
LOCAL MC1
LOCAL MFIN
LOCAL MPROD
LOCAL TEMP
LOCAL OBXOD
LOCAL MTEMP
PUSH CX
PUSH SI
;; НУ цикла
;; Перевод строки
mov dl, 0Ah
mov ah, 2
int 21h
mov dl, 0Dh
mov ah, 2
int 21h
;; Определение числа строк
MOV CX , SIZE/KCOL
MOV SI , SIZE MOD KCOL
CMP SI , 0
JE MTEMP
ADD CX, 1
MTEMP: MOV TEMP , CX
;;
MOV SI , 0
;; Цикл по массиву
MC: PUSH CX
MOV CX , KCOL
PUSH SI
;; Цикл по строке
MC1: MOV DL, NAME[SI]
CMP SI , SIZE
JGE MPROD
CALL PRINTB
ADD SI , TEMP
LOOP MC1
;;
MPROD:POP SI
INC SI
POP CX
;; Перевод строки
mov dl, 0Ah
mov ah, 2
int 21h
mov dl, 0Dh
mov ah, 2
int 21h
LOOP MC
;; Конец Цикла
MFIN:
POP SI
POP CX
JMP OBXOD
TEMP DW 0
OBXOD:
ENDM
;
main proc
;Занесение регистра DS
PUSH CS
POP DS
;;;;;;;;;;;;;;;;;;
JMP MEND1
; Описания и генрация массивов
.XALL
MAS 10 , T0 , 3
.SALL
MASM 5 , T1 , 100
MASN 5 , T2 , 1 , 5
.XALL
MASP 5 , T3 , 10 , 3
.SALL
PRSTR T0 , 5, 3
; PRCOL T0 , 5, 3
; выход с ожиданием
VAR DW 0
; Запрос символа с клавиатуры
; Цикл Суммирования
MEND1:
SUM T0 , 10 , VAR
MOV DX , VAR
CALL printdec
MOV DL , 131
CALL printb
PRSTR T0 , 20, 5
; PRCOL T0 , 27, 6
mov ah, 08h
int 21h
mov al, 0
; Выход в ДОС
mov ah, 4ch
int 21h
main endp
;-------------------
;;;;;;;;;;;;;;;
; Печать числа
; DX - число
printdec proc
; Перевод числа
; 10000
PUSH CX
PUSH SI
PUSH AX
; Начальные условия цикла перевода
MOV SI , 0
MOV CX , 4
; DX:AX - делимое
MOV DDWORK , 10000
; Цикл перевода
CICLE:
MOV AX, DX
MOV DX , 0
DIV DDWORK
; AX - остаток , DX - частное
XCHG DX , AX
; Коррекция для вывода символа
ADD dl , 30h
CMP dl , 30h
JNE MC1
MOV dl , 20h
MC1: MOV CHI[SI] , dl
INC SI
; DX - остаток , AX - частное
XCHG DX , AX
; Новый делитель
PUSH DX
PUSH AX
MOV AX , DDWORK
MOV DX , 0
DIV D10
MOV DDWORK , AX
POP AX
POP DX
LOOP CICLE
; На конец цикла
; Коррекция для вывода символа
ADD dl , 30h
MOV CHI[SI] , dl
; Вывод строки
MOV AH , 09h
MOV DX , offset STR
int 021h
POP AX
POP SI
POP CX
ret
printdec endp
; Перевод десятичное и печать байтовой переменной
; без перевода строки DL - байт
printb proc
PUSH CX
PUSH SI
PUSH AX
; Начальные условия цикла перевода
MOV SI , 0
MOV CX , 2
; DX:AX - делимое