Низкоуровневое программирование для Дzenствующих

Вид материалаДокументы

Содержание


III.5. Вычисление рекурсивных выражений
Вложенное выражение
III.6. Встроенные макрофункции и директивы
Имя макроопределения, его тип
Информация об окружении
Информация о файле
Строковые макрофункции
1). Если необязательный параметр length
Информация о сегментах
Tiny, small
IFE выражениеELSEIFE
IFNDEF выражениеELSEIFNDEF
IFNB строкаELSEIFNB
IFDIFI str1,str2ELSEIFDIFI
IFIDN str1,str2ELSEIFIDN
IFIDN str1,str2ELSEIFIDN
Подобный материал:
1   ...   34   35   36   37   38   39   40   41   42

III.5. Вычисление рекурсивных выражений


Теперь, когда мы рассмотрели правила анализа и вычисления выражений в MASM, остаётся раскрыть важный вопрос: «Как происходит анализ выражений, если они состоят из других выражений?».

Обычно это называется короче: вложенные выражения.

Вложенное выражение – это такое выражение, элементы которого сами являются выражениями, которые так же могут иметь вложенность.




Замороченное определение, похожее на «Иди туда, не знаю куда, возьми то, не знаю что» – пример старинной народной русской рекурсии, которая так часто встречается в нашей жизни. :))

Например, вызов макрофункции при вызове макро – это вложенное выражение:

MyMacro FunMacro(Мой парамерт)

;;Или это:

%echo FunMacro(Мой параметр)

;;Или это:

MyMacro FunMacro(Fun2(Привет))

Вложенность характеризуется параметром количества уровней вложенности. В недавнем примере уровень вложенности был равен двум. При чём вызов Fun2() можно называть выражением низшего уровня вложенности, а вызов макро MyMacro – выражением верхнего уровня.

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

Например, для случая:

Fun2 macro param
exitm
endm
FunMacro(Fun2(%(12+34)))

Порядок вычислений такой:
  1. %(12+34) = 46
  2. Fun2(46)
  3. FunMacro(MyCount = 46)
  4. Результат выполнения FunMacro(MyCount = 46)

А иначе препроцессор не смог бы. Если бы он начал вычисления выражений с верхнего уровня, то это то же самое, как если бы он попытался выполнить народную русскую рекурсию:
«Пойди туда, не знаю куда…, вычисли то, не знаю что»
или
FunMacro(???)

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

Это правило называется рекурсивным вычислением выражений. Оно используется везде, кроме мест вычисления значений макропараметров при вызове макро (как макросов, так и макрофункций). В этом случае действует правило: результат вложенного выражения присваивается макропараметру и не анализируется повторно. Это значит, что в данном примере:

myvar EQU <123>


MyMacro macro param1,param2,param3

echo param1

endm


FunMacro macro param:VARARG

exitm


endm


MyMacro FunMacro(var,@CatStr(<%>,myvar),var4)

вывод будет таким:

var,myvar,var4

То есть препроцессор не будет снова вычислять выражение для второго макропараметра функции FunMacro(). Если бы он сделал это, то тогда вывод был бы таким, как в этом случае:

%echo FunMacro(var,@CatStr(<%>,myvar),var4)
Вывод:
var,123,var4

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

 

III.6. Встроенные макрофункции и директивы


Несмотря на то, что этот пункт не касается самих макросов в MASM, он необходим, для того, чтобы строить макросы, и манипулировать выражениями, возникающими внутри макросов.

MASM обладает несколькими встроенными макрофункциями, макропеременными и макроконстантами, которые работают так, как если бы они были макро, определённые вами. Вот список этих предопределений:

Имя макроопределения, его тип

Описание

Определения Даты и Времени

@Date,
текстовое макроопределение (не макрофункция)

Возвращает строку вида MM/ДД/ГГ
Где:
MM – месяц, две цифры
ДД – день, две цифры
ГГ – год, две цифры

@Time,
текстовое макроопределение (не макрофункция)

Возвращает текущее время в 24-х часовом формате вида ЧЧ:ММ:СС
ЧЧ – часы, два числа
ММ – минуты, два числа
СС – секунды, два числа

Информация об окружении

@Cpu, числовая макроконстанта

Битовая маска, определяющая режим работы процессора. Никакой информации о полях этой маски нет.

@Environ(env), макрофункция

Возвращает строковое значение переменной среды окружения. Например:

%echo @Environ(TEMP)

Вывод: F:\Temp\asm

@Interface, целочисленная макроконстанта

Информация о языковых параметрах вызова.

@Version,  строковая макроконстанта

Возвращает версию ML.

Например:

%echo Version = @Version

Вывод: Version   = 614Или 615 в MASM 6.15

Информация о файле

@FileCur, строковая макропеременная

Возвращает имя файла и путь к нему (если есть), так как был подан этот файл в командной строке компилятору ML.

Пример:

%echo FileCur = @FileCur

Вывод: FileCur = .\start.asm

@FileName, строковая макропеременная

Возвращает имя файла, без его расширения. То есть для модуля start.asm:

%echo FileName = @FileName

Вывод:FileName = START

@Line, целочисленная макроконстанта

Возвращает номер текущей строки в файле.

Пример:

%echo Line = @CatStr(%@Line)

Вывод:Line = 31

Строковые макрофункции

@CatStr( string1 [[, string2...]] ), макрофункция

Возвращает строку, созданную объединением строк параметров функции.

Пример:

%echo @CatStr(,var)

Вывод:Myvar

@InStr( [[position]], string1, string2 ), макрофункция

Возвращает позицию вхождения строки string2 в строку string1. Если параметр position определён, тогда поиск начинается именно с этой позиции. Отсчёт позиции начинается с единицы. В случае, если вхождение не найдено макрофункция возвращает значение 0. Параметр position должен быть целым числом больше нуля, но не равным нулю.

Пример:

%echo @InStr(1,asdfg,s)

Вывод:02

@SizeStr( string ) макрофункция

Возвращает число, характеризующее длину строки, или, что тоже самое количество символов в строке. Функция возвращает число, однако, поскольку это макрофункция то тип возвращаемого значения – строка.

@SubStr( string, position [[, length]] ) макрофункция

Возвращает подстроку строки string, начиная с позиции, указанной в параметре position (отсчёт начинается с 1). Если необязательный параметр length задан, он ограничивает размер возвращаемой строки. Параметр length не может быть меньше нуля, и не может быть строкой.

Пример:

%echo @SubStr(1234567890,2)

%echo @SubStr(1234567890,1,5)


Вывод:

234567890

12345

Информация о сегментах

@code, строковая  макропеременная

Возвращает имя сегмента кода.

@data, строковая макропеременная

Возвращает модель памяти.

Пример:

%echo data    = @data

Вывод:data    = FLAT

@fardata?, строковая макропеременная

Равен имени сегмента FARDATA?

@WordSize, численная константа

Содержит размер слова в байтах.
Для 16-bits – 2.
Для 32-bits – 4.

@CodeSize, численная константа

Содержит идентификатор типа памяти.
0 – TINY, SMALL, COMPACT, FLAT.
1 – MEDIUM, LARGE, HUGE

@Model, численная константа

1 – TINY
2 – SMALL
3 – COMPACT
4 – MEDIUM
5 – LARGE
6 – HUGE
7 – FLAT

@CurSeg, строковая макропеременная

Хранит имя текущего сегмента.

@fardata, @stack, строковая макропеременная

Содержат соответствующие имена сегментов

Кроме знания макрофункций, нам так же понадобятся знания о блоках ветвлений или просто IF блоках. Эти блоки позволяют исполнять тот или иной участок исходного кода в зависимости от того, выполняется какое-либо условие или нет. Часто это называют «Условным ассемблированием (компиляцией)», однако для MASM это нечто большее, нежели простое управление компилятором, так как, вы уже поняли, мы имеем дело, как с кодом машины, так и с макрокодом, который вычисляется и живёт только во время компиляции.

Условный блок в MASM имеет следующий общий вид:

[IFDIRECTIVE] условие
...
[ELSEDIRECTIVE] условие
...
ELSE
...
ENDIF

Если выражение «Условие» равно истине, то выполняется блок кода, идущий после условной директивы, иначе управление передаётся на следующий оператор за блоком. [IFDIRECTIVE]/[ELSEDIRECTIVE] – могут быть той или иной директивой условия. Стандартные директивы IF/ELSEIF/ELSE требуют, чтобы выражение, стоящее при них, было целочисленным. Если вам необходимо проверять другие условия, то для этого в MASM предусмотрены специальные директивы.

Список [IFDIRECTIVE]/[ELSEDIRECTIVE]:

Блок

Условие выполнения блока

IF выражение
ELSEIF выражение
ELSE

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

IF1
ELSEIF1

если ассемблер выполняет первый проход

IF2
ELSEIF2

если ассемблер выполняет второй проход (устарело)

IFE выражение
ELSEIFE выражение

если выражение равно нулю

IFDEF выражение
ELSEIFDEF выражение

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

Идентификатором может быть макро, макропеременная, переменная, макроконстанта, любой другой идентификатор.

При помощи этой директивы, можно проверить была ли определена та или иная переменная, макро, константа.

IFDEF PROGRAM_IMAGE_BASE
;; Выполняем действия если PROGRAM_IMAGE_BASE
;; определена
ELSE


IFNDEF выражение
ELSEIFNDEF выражение

если идентификатор не определён.

IFB строка
ELSEIFB строка

если строка пустая.

Строка считается пустой, если её длинна равна нулю, либо она содержит одни пробелы. С помощью этой директивы можно определяет присутствие/отсутствие необязательных макропараметров.

MyMacro macro param1,param2
IFB

;; Если макропараметр не определён,
;; генерируем ошибку
.ERR <Не определён параметр param2>

IFNB строка
ELSEIFNB строка

если строка не пуста.

IFDIF str1,str2
ELSEIFDIF str1,str2

если строки различны.

IFDIF ,

echo Этот код выполнится

echo потому что строки различны

ENDIF



IFDIFI str1,str2
ELSEIFDIFI str1,str2

если строки различны (без учёта различий в регистре букв).

IFDIF ,
echo Этот код не выполнится
echo потому что строки Одинаковы
ENDIF

IFIDN str1,str2
ELSEIFIDN str1,str2

если строки одинаковы.

IFDIF ,
echo Этот код не выполнится
echo потому что строки Различны
ENDIF

IFIDN str1,str2
ELSEIFIDN str1,str2

если строки одинаковы (без учёта различий в регистре букв).

IFDIF ,
echo Этот код выполнится
echo потому что строки Одинаковы
ENDIF

На протяжении всей статьи я часто пользовался следующей директивой, которая позволяет выводить текст на консоль во время компиляции. Эта директива echo. Как мы узнаем позже, она оказалось просто незаменимой при проектировании макро.

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

Кроме этого, есть ещё одна группа директив, без которой мы не сможем обойтись. Не сможем потому, что макрофункции, или макросы, которые мы собираемся создавать должны быть слегка умными, иначе говоря, иметь «защиту от дурака».

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

Именно для этого и существует простой набор директив условной генерации ошибки. Действуют они подобно условным блокам и директиве echo. Пример безусловной генерации ошибки:

.ERR <Ошибочка вышла, гражданин начальник>

Условная генерация ошибки, имеют ту же форму, что и IFDIRECTIVE в таблице выше, однако последним дополнительным параметром является строка сообщения. Например:

.ERRE выражение,<ошибка, если выражение равно нулю>
.ERRNZ выражение,<ошибка, если выражение не равно нулю>
.ERRDEF id,<ошибка, если id определен>
.ERRB строка,<ошибка, если строка пуста>
.ERRNB строка,<ошибка, если строка не пуста>
.ERRDIF str1,str2,<ошибка, если строки различны>
.ERRDIFI str1,str2,<ошибка, если строки различны

(без учёта регистра)>
.ERRIDN str1,str2,<ошибка, если строки одинаковы>
.ERRIDNI str1,str2,<ошибка, если строки одинаковы

(без учёта регистра)>