|
|
|
|
Приемы кодирования и некоторые предупреждения
Когда необходимо создать действительную команду перехода и метку перехода, мы будем использовать макросы mkjmp, mkjmp2, mklbl и mklbl1.
Действительные метки состоят из идентификатора типа и номеров. Единственный способ получить числовое значение символа заключается в применении
оператора процента (%), который действителен только при использовании с аргументом вызова макро. Мы хотим вычислить символ, определяемый двумя
элементами информации из счетчика, так:
Однако Руководство по MASM сообщает нам, что оператор амперсанда (&) не может быть использован в вызове макро. Таким образом, мы должны создать
временную переменную и использовать ее.
??tmp = &p3&p2
mkjmp2 p1,p2,%??tmp
|
Все это влечет за собой следующее. Первая форма, содержащая амперсанды в вызове макро, должна работать. Однако выбор скрытой возможности вызывает
проблемы будущей совместимости и даже реализуемости. Кроме того, Вы всегда должны задаваться вопросом, может ли неподдерживаемая или несанкционированная
функция зависеть от реализации совместимости. Решение этой дилеммы остается за читателем.
Авторы использовали эту несанкционированную возможность в программе, не генерирующей программного кода, но решающей знаменитую задачу "Ханойские
башни" в рекурсивной манере. Кроме того, для достижения общности наш метод создания символов счетчиков из нескольких частей позволяет при необходимости
создавать новые счетчики. Перед своим использованием эти счетчики должны инициализироваться, в противном случае первая попытка увеличить или уменьшить
их значение вызовет ошибку "Символ не определен". Используя условный оператор IFDEF, можно проверить, требуется ли инициализация при каждом
использовании символа.
Инициализация связана еще с одной тонкостью работы MASM. Как мы установили, MASM является двухпроходным ассемблером, определяющим символы при
первом проходе и затем использующим их при втором. Это значит, что определения символов защищены от первого прохода ко второму. Таким образом,
когда MASM начинает второй проход, все счетчики первого прохода уже определены и содержат свои старые значения. Если в начале второго прохода
переинициализация символов не происходит,возникает фазовая ошибка, так как начальные значения счетчиков отличаются.
Для инициализации символов на первом проходе необходима конструкция IFDEF, так как заранее мы не знаем, сколько счетчиков потребуется, а
использования IFDEF на втором проходе недостаточно. Мы решили эту проблему, создав символы ?р2sw ..., которые на втором проходе анализируются на
необходимость установки в нулевые значения. Имя получается из Switch (переключателя) фазы 2. Этот процесс проверки предоставляет хорошую возможность
выявить, принадлежат ли уровни вложенности самому верхнему уровню, указывая, что конструкции IF-IFEND, DOWHILE-DOEND и т.д. спарены
правильно.
В Листинге 1-16 приведены простые примеры расширения макросов структурного управления, определенных ранее. Как можно видеть, мы подавили те части
расширения, которые не вырабатывают код или метки переходов. Если Вы хотите ознакомиться с работой этих макросов более детально, используйте
директиву .LALL. Прибегайте только к сокращенному примеру, так как обработка этих макро вызывает выполнение множества шагов. Количество шагов также
объясняет, почему происходит увеличение требуемого времени ассемблирования программы. Используя эти макро, не ожидайте быстрого ассемблирования,
но рассчитывайте на быстрое кодирование.
Листинг 1-15. Вложенная структура IF-THEN-ELSE
----------------------------------------------------------------
; Сжатый исходный код программы
@IfTrue e условие (a)
@IfTrue e условие (b)
@IfElse "else" для условия (b)
@IfEnd конец условия (b)
@IfElse "else" для условия (a)
@IfTrue e условие (c)
@IfElse "else" для условия (c)
@IfEnd конец условия (c)
@IfEnd конец условия (a)
; Листинг расширения
@IfTrue e условие (a)
1 je ??0000
3 jmp ?if_100
1 ??0000:
; выполнить, если условие (а) истинно
@IfTrue e условие (b)
1 je ??0001
3 jmp ?if_110
1 ??0001:
; выполнить, если условие (b) истинно
@IfElse "else" для условия (b)
3 jmp ?if_111
3 ?if_110:
; выполнить, если условие (b) не истинно
@IfEnd конец условия (b)
3 ?if_111:
@IfElse "else" для условия (a)
3 jmp ?if_101
3 ?if_100:
; выполнить, если условие (а) не истинно
@IfTrue e условие (c)
1 je ??0002
3 jmp ?if_112
1 ??0002:
; выполнить, если условие (с) истинно
@IfElse "else" для условия (c)
3 jmp ?if_113
3 ?if_112:
; выполнить, если условие (с) не истинно
@IfEnd конец условия (c)
3 ?if_113:
@IfEnd конец условия (a)
3 ?if_101:
---------------------------------------------------------------
|
Листинг 1-16. Расширение структурированных макросов
----------------------------------------------------------------
@IfTrue e
1 je ??0000
3 jmp ?if_100
1 ??0000:
; Выполнить, если истина
@IfElse
3 jmp ?if_101
3 ?if_100:
; Выполнить, если не истина
@IfEnd
3 ?if_101:
;- - - - - - - - - - - - - - - - - - - - - - - - - -
@DoWhile ax,le,bx
3 ?do_100:
1 cmp ax,bx
1 jle ??0001
3 jmp ?do_101
1 ??0001:
; Выполнять пока ax <= bx
@DoExit
3 jmp ?do_101
; Выйти из программы
@DoEnd
3 jmp ?do_100
3 ?do_101:
;- - - - - - - - - - - - - - - - - - - - - - - - - - - -
@Repeat
3 ?rep_100:
; Выполнять пока соблюдается условие
@Until ax,e,bx
1 cmp ax,bx
1 je ??0002
3 jmp ?rep_100
1 ??0002:
;- - - - - - - - - - - - -- - - - - - - - - - - - - - -
@For ax,10,20,+
1 mov ax,10 ;инициализировать счетчик
1 jmp ??0003 ;начать цикл FOR
3 ?for_100:
1 inc ax ;увеличить счетчик
1 ??0003: ;проверить на необходимость продолжения
1 cmp ax,20 ;достигнут ли конец
1 jl ??0004 ;нет - продолжить цикл
3 jmp ?for_101
1 ??0004:
; Выполнить для ах = 10 до 20 с шагом 2
@ForEnd
3 jmp ?for_100
3 ?for_101:
----------------------------------------------------------------
|
|
|