Что такое low и high паскаль
Что такое low и high паскаль
Для обработки ЭВМ данные представляются в виде величин и их совокупностей. С понятием величины связаны такая важная характеристика, как ее тип.
В языке Паскаль тип величины задают заранее. Все переменные, используемые в программе, должны быть объявлены в разделе описания с указанием их типа. Обязательное описание типа приводит к избыточности в тексте программ, но такая избыточность является важным вспомогательным средством разработки программ и рассматривается как необходимое свойство современных алгоритмических языков высокого уровня.
Простые типы данных
В таблице приведены простые типы данных Турбо Паскаль, объем памяти, необходимый для хранения одной переменной указанного типа, множество допустимых значений и применимые операции.
Перечисляемый и интервальный тип относятся к типам, определяемым пользователем и будут рассмотрены нами позже.
Дополнительные сведения о типах данных..
В Турбо Паскаль ограничения на совместимость типов можно обойти с помощью приведения типов. Приведение типов позволяет рассматривать одну и ту же величину в памяти ЭВМ как принадлежащую разным типам. Для этого используется конструкция Имя_Типа(переменная или значение)
Напрмер, Integer(‘Z’) представляет собой значение кода символа ‘Z’ в двухбайтном представлении целого числа, а Byte(534) даст значение 22, поскольку целое число 534 имеет тип Word и занимает два байта, а тип Byte занимает один байт, и в процессе приведения старший байт будет отброшен.
Волгоградский государственный педагогический университет
Кафедра алгебры, геометрии и информатики
Функции Low и High
Функции Low и High предназначены для работы с массивами. Функция Low возвращает нижнюю, а функция High – верхнюю границу индексов массива :
X, I, Lower, Upper : Integer;
MyArray : array[10..20] of Integer;
Begin
for I := Lower to Upper do
Применение функций Low и High для работы с массивами – хороший способ избежать ошибок, связанных с выходом индекса за допустимые пределы.
Динамические массивы
При объявлении динамического массива достаточно указать только тип его элементов. Память для размещения его элементов на этом этапе не выделяется. Фактически массив создается только во время выполнения программы. Для этого используется функция SetLength. Как только необходимость в массиве отпадает, следует освободить память вызовом процедуры Finalize. Рассмотрим пример:
BigArray : array of Integer;
Begin
Новый термин. Динамический массив размещается в оперативной памяти во время выполнения программы.
Размер динамического массива можно увеличивать или уменьшать во время выполнения. программы
По окончании использования его следует уничтожить.
Несомненное преимущество динамических массивов над статическими заключается в том, что в случае неопределенности потребного количеством элементов нам не надо объявлять массив «с запасом». Достаточно объявить динамический массив и управлять его размерами непосредственно из программы.
Для изменения размеров массива используют функцию Copy. Рассмотрим такой пример. Пусть динамический массив BigArray содержит 100 элементов. Нам необходимо увеличить его размер до 200 элементов. Для этого обращаемся к функции Copy:
Предыдущее содержимое (значения элементов) массива остается неизменным, а его размер увеличен до 200 элементов.
Двумерные динамические массивы создаются аналогично. Объявление двумерного динамического массива имеет вид:
BigArray : array of array of Integer;
Begin
SetLength(BigArray, 20, 20);
Строки
Строки в программах используются весьма интенсивно. Object Pascal дает нам три различных строковых типа: длинная строка, короткая строка и расширенная строка. Кроме того, есть строки с терминальным нулем.
Короткая строка
Короткая строка – это строка фиксированной длины с числом символов не более 255. Имеются два способа объявления строк фиксированной длины. В первом случае используется предопределенный тип ShortString, который объявляет строку длиной 255 байт. Во втором случае – ключевое слово string со спецификацией длины:
Так как объем памяти, выделяемой для строк этого типа, в процессе работы программы не изменяется, операции над строками фиксированной длины выполняются очень быстро. Однако, короткие строки – устаревший тип данных. В программах рекомендуется использовать длинные строки. Короткие строки называют строками с байтом длины, ибо первый ее элемент равен текущему числу символов в ней. Значение первого элемента можно прочесть и узнать сколько в строке символов, например,
Begin
В этом примере для определения длины строки используется значение S[0]. Можно также воспользоваться функцией Length.
ПРИМЕЧАНИЕ. Для преобразования значения типа Char в целую величину используется функция Ord. Функция Ord также применяется к перечислимым типам.
Ели это необходимо, первому элементу короткой строки можно присвоить значение длины. Это может потребоваться в некоторых специальных случаях. Отметим, что программное изменение длины строки относится к «продвинутой» технике и начинающим программистам этого делать не стоит.
Длинная строка
Строки этого типа относятся к объектам, которые размещаются в памяти динамически. Размер такой строки ограничен лишь доступным объемом оперативной памяти. Object Pascal выделяет и освобождает память для строк рассматриваемого типа по мере необходимости. Длинные строки – очень гибкий тип данных, но операции над ними требуют большего времени. Это объясняется необходимостью перераспределения памяти когда размер строки изменяется. Несмотря на это, в программах следует использовать строки именно этого типа.
Для объявления длинной строки используется ключевое слово string без спецификации длины:
S : string;
Длинные строки не содержат 0–го элемента длины. Попытка прочитать нулевой элемент, обратившись к нему как S[0], будет пресечена на этапе компиляции. Вместо этого надо пользоваться функцией Length чтобы узнать длину строки, или процедурой SetLength – чтобы установить требуемую длину строки. Более подробно об этом – в разделе «Строковые функции».
Что такое low и high паскаль
Написание любой большой программы невозможно как без разбиения задачи на менее сложные подзадачи, которые мы можем решать независимо, так и без повторного использования ранее написанного кода (представим, что каждая новая программа писалась бы «с нуля»?!). Решить эти важнейшие задачи позволяет механизм подпрограмм, имеющийся в любом языке программирования, в том числе, и в Паскале.
Итак, использование подпрограмм позволяет решить следующие задачи:
· уменьшение размеров кода и экономия памяти за счет возможности неоднократного вызова одной и той же подпрограммы в рамках одной программы;
· лучшее структурирование программы за счет разбиения задачи на более простые подзадачи;
· эффективное повторное использование однажды написанного кода.
Рассмотрим общую структуру сложной программы, содержащей две подпрограммы:
описана вне всех подпрограмм>
описана после заголовка подпрограммы>
Описанная перед телом подпрограммы локальная переменная i не имеет никакого отношения к одноименной переменной, описанной выше. На время выполнения подпрограммы локальная переменная i вытесняет глобальную, делая значение последней недоступной. После завершения подпрограммы значение локальной i будет утеряно, а значение глобальной i никак от этого не изменится. Итак, глобальные переменные видимы (доступны) от точки их определения до конца файла. Локальные переменные доступны только в том блоке операторных скобок, в котором они описаны и во вложенных в него блоках.
18.1. Процедуры
Общий вид подпрограммы-процедуры следующий:
(Список формальных параметров);
var описания локальных переменных;
procedure Equation (a,b,c:real;
Здесь мы попытались решить уравнение ax 2 +bx+c=0, значения a, b, c, ввел пользователь, ответы, если они вычислялись, будут помещены в переменные x1 и x2. При вызове вида
Equation (1,4,-3.5, x 3, x 4);
мы решили уравнение x 2 +4x-3.5=0, а ответы поместили в переменные x3 и x4. Еще один вызов
Equation (4,1,-3.5, x 3, x 4);
позволяет решить уравнение 4x 2 +x-3.5=0, записав ответы в переменные x1 и x2. Наконец, четвертое обращение к процедуре
решает уравнение x 2 +bx=0, помещая ответы в переменные x1 и x3.
И так далее. Суть в том, что при каждом вызове подпрограммы значения фактических параметров подставляются на место формальных и с ними производятся вычисления, предусмотренные операторами подпрограммы. Указанные требования называют согласованием параметров и описывают следующим образом: формальные и фактические параметры должны быть согласованы между собой по количеству, типу и порядку следования. Это означает, что количество формальных и фактических параметров должно быть одинаковым, при этом, при вызове процедуры каждый фактический параметр должен иметь тот же тип и занимать в списке то же место, что и соответствующий ему формальный параметр. Из сказанного следует, что нашу процедуру Equation можно вызвать только с пятью параметрами (а не тремя, семью или нулём), причем все эти параметры должны быть вещественными. Если формальный параметр является выходным (перед ним в заголовке процедуры указано ключевое слово var ), то соответствующий фактический параметр не может быть константой (ведь значение константы нельзя изменить). Для больше наглядности опишем данное соответствие в табл. 18.1.
Табл. 18.1. Соответствие формальных и фактических параметров
Формальный параметр в заголовке процедуры
Соответствующий фактический параметр при вызове процедуры
Переменная некоторого типа данных без ключевого слова var
Переменная, константа, элемент массива или значение выражения того же типа данных
Переменная некоторого типа данных с ключевым словом var
Переменная или элемент массива того же типа данных
procedure p1 (x:integer);
по значению, x по-прежнему равно 3>
procedure p1 (var x:integer);
переданной в качестве x>
оно было изменено процедурой p1>
Таким образом, использование var в заголовке процедуры подчеркивает, что параметр является переменной и может изменяться этой процедурой.
Перейдем к примерам.
Типы данных Паскаль
Обычно данные при обработке ЭВМ представляются в виде либо отдельных величин, либо в виде их совокупностей. Одной из важнейших, а может самой главной характеристикой величины является ее тип.
Что определяют типы данных Паскаль?
Во-первых, возможные значения переменных, функций, выражений, констант принадлежащих к исходному типу; во-вторых, он определяет внутреннюю форму представления данных в ЭВМ; и, в-третьих, определяет функции и операции, выполняющиеся над величинами, которые принадлежат тому или иному типу.
В языке Паскаль все переменные, которые потом в дальнейшем будут использоваться в программе, необходимо объявить в разделе описания, указав их тип. Постоянное обязательное описание типа приводит к возникновению избыточности в исходном тексте программ, но в то же время эта избыточность представляет собой вспомогательное средство в процессе разработки программ — что есть необходимое свойство современных высокоуровневых языков.
Типы данных Паскаль:
В Паскале различают следующие типы данных:
В таблице ниже представлены разновидности простых типов данных в Паскале и их характеристики:
Для порядковых типов, входящих в группу простых, характерны следующие свойства:
Эквивалентность и совместимость типов данных:
Немаловажное значение в языке Паскаль имеют понятия эквивалентности и совместимости типов. Дадим определения этим понятиям. Два типа TIP1 и ТIP2 называются эквивалентными в случае выполнения одного из условий:
Теперь введем понятие совместимости типов. Типы называются совместимыми, если:
Ограничения на совместимость типов можно обойти при помощи приведения типов:
Когда приведение типов используется к ссылке на переменную, то ее (ссылку) рассматривают в качестве экземпляра типа, который представлен идентификатором типа. Размер переменной (т.е. число байт, которое занимает переменная) должен быть равен размеру типа, представленного идентификатором типа.
После операции приведения типа переменной можно указать один или несколько квалификаторов, если это допускается указанным типом, например, integer(‘Z’) есть значение кода символа ‘Z’ в двух-байтном представлении целого числа, а byte(534) впоследствии даст значение 22, так как целое число 534 обладает типом word и занимает 2 байта, а тип byte занимает 1 байт, и в процессе приведения старший байт окажется отброшенным.
Надеюсь, что данная статья помогла Вам понять, что такое типы данных Паскаль. В дальнейшем рассмотрим каждый из этих типов.
Что такое low и high паскаль
— 12.1. Общее описание МП 8086/8088
— 12.1.1. Регистры
— 12.1.2. Адресация
— 12.1.3. Система команд
— 12.2. Специфика встроенного ассемблера
— 12.2.1. Оператор ASM
— 12.2.2. Синтаксис ассемблерных команд
— 12.2.3. Директивы ассемблера
— 12.2.4. Ассемблерные подпрограммы
Ассемблером называется машинно-зависимый компилятор, преобразующий специальным образом составленные текстовые строки в машинные инструкции. Как и любой другой компилятор, ассемблер упрощает разработку программ за счет того, что предоставляет пользователю доступ к кодам машинных инструкций и операндам с помощью символьных имен.
В этой главе рассматриваются приемы программирования с помощью ассемблера, встроенного в компилятор Турбо Паскаля. Встроенный ассемблер имеется в версиях 6.0 и 7.0 Турбо Паскаля и в руках опытного программиста представляет собой мощный инструмент, позволяющий «выжать» из ПК все возможное.
12.1. ОБЩЕЕ ОПИСАНИЕ МП 8086/8088
Чтобы использовать средства ассемблера, необходимо ясно представлять себе детали архитектуры микропроцессоров Intel 80×86. К этому семейству относятся микропроцессоры:
Микропроцессоры этого семейства наращивают свои возможности в перечисленном порядке, но строго совместимы от младших моделей к старшим: все, что может 8086/8088, реализует и Pentium, но не наоборот. Ниже обсуждается архитектура (внутреннее устройство, способы адресации и система команд) МП 8086/8088.
12.1.1. Регистры
В МП 8086/8088 имеется 14 регистров. В функциональном отношении они делятся на группы:
— регистры общего назначения (АХ, ВХ, СХ, DX); предназначены для хранения операндов и выполнения основных команд; любой из них может использоваться как совокупность двух независящих друг от друга 8-разрядных регистров: старшего байта регистра (АН, ВН, СН, DH) и младшего байта (AL, BL, CL, DL); например, АХ состоит из АН и AL;
— сегментные регистры (CS, DS, SS, ES); используются для указания сегмента при адресации памяти;
— регистры-указатели (SP, BP, IP); используются для указания смещения при адресации памяти;
— индексные регистры (SI, DI); применяются для индексной адресации;
— регистр флагов; используется для хранения признаков состояния процессора.
Внутри одной и той же функциональной группы регистры используются различным образом. Ниже описывается специфика использования регистров.
Регистр АХ. Является основным сумматором. Используется во всех арифметических операциях (сложить, умножить и т.п.). Только с помощью АХ и его полурегистров AHIAL возможен обмен данными с портами ввода/вывода.
Регистр ВХ. Используется как сумматор в арифметических операциях, а также как базовый регистр при индексной адресации.
Регистр СХ. В основном используется как счетчик при выполнении операций повторения и сдвига. Может также участвовать в арифметических операциях.
Регистр DX. Используется как регистр данных в операциях ввода/вывода, а также как сумматор при обработке длинных целых чисел (32-разрядных).
Регистр CS. Содержит номер сегмента памяти (сегмента кода), в котором располагается текущая машинная инструкция. Для получения полного адреса следующей команды его содержимое сдвигается влево на 4 разряда и складывается с регистром-указателем IP. Содержимое CS автоматически изменяется в командах дальнего (межсегментного) перехода и вызова процедур.
Регистр IP. Определяет смещение относительно начала сегмента кода CS очередной исполняемой машинной инструкции. Содержимое IP автоматически изменяется в ходе исполнения инструкции, обеспечивая правильный порядок выборки команд из памяти.
Регистр DS. Содержит номер сегмента памяти (сегмента данных), в котором располагаются данные (константы и переменные). Все глобальные переменные и типизированные константы программы Турбо Паскаля всегда располагаются в единственном сегменте, адресуемом этим регистром.
Регистр SP. Указывает на вершину стека, т.е. совместно с регистром 55 адресует ячейку памяти, куда будет помещаться операнд или откуда он будет извлекаться. Содержимое этого регистра автоматически уменьшается после размещения в стеке очередного операнда и увеличивается после извлечения операнда из стека.
Регистр ВР. Так называемый указатель базы. Облегчает создание и использование локального стека (т.е. стека для использования внутри процедуры).
Регистр ES. Дополнительный сегментный регистр ES используется для межсегментного обмена данными и в некоторых строковых операциях.
Регистр SI. Определяет адрес источника информации при индексной адресации данных (например, при обработке массивов). Обычно используется в паре с регистром DS.
Регистр флагов. Отдельные разряды (биты) этого регистра имеют следующее назначение.
Флаг переноса CF. Содержит 1, если произошел перенос единицы при сложении или заем единицы при вычитании. Используется также в циклических операциях и операциях сравнения.
Флаг внешнего переноса AF. Контролирует перенос из 3-го бита данных. Полезен при операциях над упакованными десятичными числами.
Флаг нуля ZF. Равен 1, если в результате операции получен ноль, и равен 0 в противном случае.
Флаг знака SF. Равен 1, если в результате операции получено отрицательное число (с единицей в старшем разряде).
Флаг трассировки TF. Равен 1, если программа исполняется по шагам, с передачей управления после каждой выполненной команды по прерыванию с вектором 1.
Флаг прерываний IF. Содержит 1, если микропроцессору разрешена обработка прерываний.
Флаг переполнения OF. Устанавливается в единицу, если в результате операции получено число, выходящее за разрядную сетку микропроцессора.
12.1.2. Адресация
Архитектура МП позволяет использовать семь различных способов адресации.
Извлекает операнд из регистра или помещает его в регистр. Примеры:
Операнд (8- или 16-разрядная константа) содержится непосредственно в теле команды. Примеры:
Смещение операнда задается в теле программы и складывается с регистром DS; например:
Исполнительный адрес операнда (точнее, его смещение) содержится в одном из регистров ВХ, ВР, SI или DI. Для указания косвенной адресации этот регистр должен заключаться в квадратные скобки, например:
Каждый из регистров BX. DI по умолчанию работает со своим сегментным регистром:
DS:BX, SS:BP, DS:SI, ES:DI
Допускается явное указание сегментного регистра, если он отличается от умалчиваемого, например:
Базовый регистр ВХ (или ВР) содержит базу (адрес начала некоторого фрагмента памяти), относительно которой ассемблер вычисляет смещение, например:
Адресация по базе с индексированием
Вариант индексной адресации для случая, когда индексируемая область памяти задается своей базой. Например:
Этот тип адресации удобен при обработке двумерных массивов. Если, например, АОВ есть массив из 10×10 байт вида
АОВ: array [0..9,0..9] of Byte;
то для доступа к элементу АОВ [2,3] можно использовать такой фрагмент
12.1.3. Система команд
Детальный анализ всех команд МП 8086/8088 занял бы слишком много места, поэтому в идущих за таблицами пояснениях рассматриваются лишь наиболее популярные команды. Исчерпывающее описание всех команд Вы найдете в [1], [20].
Команды пересылки данных
Мнемоника | Формат | Пояснение |
---|
Команды общего назначения |
---|
MOV | MOV приемник, источник | Переслать значение |
---|---|---|
PUSH | PUSH источник | Поместить в стек |
POP | POP приемник | Извлечь из стека |
XCHG | XCHG приемник, источник | Обменять значения |
XLAT | XLAT таблица | Загрузить в AL байт из таблицы |
Команды ввода-вывода |
---|
IN | IN аккумулятор, порт | Читать из порта |
---|---|---|
OUT | OUT порт, аккумулятор | Записать в порт |
Команды пересылки адреса |
---|
LEA | LEA регистр 16, память 16 | Загрузить исполнительный адрес |
---|---|---|
LDS | LDS регистр 16, память32 | Загрузить в DS:регистр16 полный адрес |
LES | LES регистр 16, память32 | Загрузить в ES:регистр16 полный адрес |
Команды пересылки флагов |
---|
LAHF | LAHF | Загрузить флаги в АН |
---|---|---|
SAHF | SAHF | Установить флаги из АН |
PUSHF | PUSHF | Поместить флаги в стек |
POPF | POPF | Извлечь флаги из стека |
С помощью MOV нельзя пересылать:
— из памяти в память, например, вместо
— константу или переменную в DS, например, нельзя
— один сегментный регистр в другой, например, нельзя
— в регистр CS; значение этого регистра (сегмента кода) автоматически меняется при выполнении дальних команд CALL и JMP; кроме того, он загружается из стека при выполнении команды RETF (выход из дальней процедуры).
Команда загрузки адреса LEA загружает в регистр адрес (смещение) нужного участка памяти. Этого же можно достичь с помощью зарезервированного слова OFFSET, стоящего перед именем переменной. Например:
Разница состоит в том, что в случае команды LEA разрешается использовать индексную адресацию, что особенно удобно при пересылке массивов данных.
Мнемоника | Формат | Комментарий |
---|
Команды сложения |
---|
ADD | ADD приемник, источник | Сложить |
---|---|---|
ADC | ADC приемник, источник | Сложить, добавить перенос |
ААА | ААА | Скорректировать сложение для таблицы ASCII |
DAA | DAA | Скорректировать сложение для двоично-десятичных чисел |
INC | INC приемник | Увеличить на единицу |
Команды вычитания |
---|
SUB | SUB приемник, источник | Вычесть |
---|---|---|
SBB | SBB приемник, источник | Вычесть с заемом |
AAS | AAS | Скорректировать вычитание для таблицы ASCII |
DAS | DAS | Скорректировать вычитание для двоично-десятичных чисел |
DEC | DEC приемник | Уменьшить на единицу |
NEG | NEG приемник | Обратить знак |
СМР | СМР приемник, источник | Сравнить |
Команды умножения |
---|
MUL | MUL источник | Умножить без знака |
---|---|---|
IMUL | IMUL источник | Умножить со знаком |
AАМ | ААМ | Скорректировать умножение для таблицы ASCII |
Команды деления |
---|
DIV | DIV источник | Делить без знака |
---|---|---|
IDIV | IDIV источник | Делить со знаком |
AAD | AAD | Скорректировать деление для таблицы ASCII |
Команды расширения знака |
---|
CBW | CBW | Преобразовать байт в слово |
---|---|---|
CWD | CWD | Преобразовать слово в двойное слово |
Мнемоника | Формат | Комментарий |
---|
Логические команды |
---|
AND | AND приемник, источник | Выполнить AND |
---|---|---|
OR | OR приемник, источник | Выполнить OR |
XOR | XOR приемник, источник | Выполнить XOR |
NOT | NOT приемник | Выполнить NOT |
TEST | TEST приемник, источник | Проверить |
Сдвиговые команды |
---|
SAL/SHL | SAL приемник, счетчик | Сдвинуть влево |
---|---|---|
SAR/SHR | SAR приемник, счетчик | Сдвинуть вправо |
ROL | ROL приемник, счетчик | Сдвинуть влево циклически |
ROR | ROR приемник, счетчик | Сдвинуть вправо циклически |
RCL | RCL приемник, счетчик | Сдвинуть влево с переносом |
RCR | RCR приемник, счетчик | Сдвинуть вправо с переносом |
Битовые команды используются при исчислении логических выражений, а также в тех случаях, когда необходимо изменить отдельные разряды операнда. Логические команды AND, OR, XOR и NOT эквивалентны соответствующим операциям Турбо Паскаля в случае, когда операндами являются целочисленные выражения. Команда TEST выполняет целочисленную операцию поразрядного суммирования AND, но не изменяет значения операндов, а лишь устанавливает флаги в соответствии со значением результата сравнения: обнуляет CF и OF, изменяет PF, ZF, SF и не меняетAF (флаг ZF установится в 1 в том случае, когда оба операнда содержат по единице хотя бы в одном соответствующем разряде). Команды сдвига SHL/SHR эквивалентны одноименным операциям Турбо Паскаля и отличаются от команд циклического сдвига ROLIROR тем, что вытесненные в ходе их выполнения значащие разряды теряются, в то время как при циклическом сдвиге эти разряды появляются «с другой стороны». Например, если выполнить фрагмент
Заметим, что счетчиком в командах сдвига может быть цифра 1 или количество сдвигов, указываемое в регистре CL.
Команды передачи управления
Мнемоника | Формат | Комментарий |
---|
Безусловные переходы |
---|
CALL | CALL имя | Войти в процедуру |
---|---|---|
RET | RET [количество параметров] | Вернуться из процедуры |
JUMP | JUMP имя | Перейти |
Условные переходы |
---|
JA/JNBE | JA близкая_метка | |
---|---|---|
JAE/JNB | JAE близкая_метка | Перейти, если выше или равно |
JB/JBAE/JC | JB близкая_метка | Перейти, если ниже |
JBE/JNA | JBE близкая_метка | Перейти, если ниже или равно |
JCXZ | JCXZ близкая_метка | Перейти, если СХ=0 |
JE/JZ | JE близкая_метка | Перейти, если равно |
JG/JNLE | JG близкая_метка | |
JGE/JNL | LGE близкая_метка | Перейти, если больше или равно |
JL/JNGE | JL близкая_метка | Перейти, если меньше |
JLE/JNG | JLE близкая_метка | Перейти, если меньше или равно |
JNC | JNC близкая_метка | Перейти, если нет переноса |
JNE/JNZ | JNE близкая_метка | Перейти, если не равно |
JNO | JNO близкая_метка | Перейти, если нет переполнения |
JNP/ JPO | JNP близкая_метка | Перейти, если нечетный |
JO | JO близкая_метка | Перейти, если перенос |
JP/JPE | JP близкая_метка | Перейти, если четный |
JS | JS близкая_метка | Перейти, если отрицательный |
Команды управления циклами |
---|
LOOP | LOOP близкая_метка | Повторить цикл |
---|---|---|
LOOPE/LOOPZ | LOOPE близкая_метка | Повторять, пока равны |
LOOPNE/LOOPNZ | LOOPNE близкая_метка | Повторять, пока не равны |
Procedure MyProc; Far;
При выходе из дальней процедуры команда RET извлекает из стека оба 16-разрядных слова и помещает первое в IP, а второе в CS, а при выходе из ближней извлекает из стека только смещение и помещает его в IP.
Команды условных переходов способны передавать управление на метку, расположенную в пределах ближайших плюс-минус 128 байт от самой команды. Если нужно передать управление на метку, расположенную дальше в том же сегменте, или на метку в другом сегменте, сразу за командой условной передачи располагают безусловную команду JMP или CAL, например:
Условие | Для беззнаковых чисел | Для чисел со знаками |
---|---|---|
Приемник больше источника | JA | JG |
Приемник и источник равны | JE | JE |
Приемник меньше источника | JB | JL |
Приемник не меньше источника | JAE | JGE |
Приемник не больше источника | JBE | JLE |
Приемник и источник не равны | JNE | JNE |
С точки зрения Турбо Паскаля пара asm. end считается операторными скобками, ограничивающими единственный оператор Паскаля, например:
Тело ассемблерного оператора asm. end может быть пустым или содержать несколько ассемблерных команд. Каждая ассемблерная команда должна располагаться на отдельной строке или отделяться от следующей за ней команды символом «;». Ниже приводятся два разных способа написания одной и той же последовательности ассемблерных команд:
В конце строки, содержащей единственную ассемблерную команду, или между двумя командами, располагающимися на одной строке, разрешается вставлять комментарий, который должен оформляться по обычным правилам Турбо Паскаля, т.е. ограничиваться символами «<», «>» или «(*», «*)». Таким образом, комментарии разрешены между ассемблерными командами, но не внутри них. Например, такой оператор будет правильным:
lea di,Y; mov ex,100 <и направление>eld
В пределах ассемблерного оператора допускаются любые команды, но Турбо Паскаль требует выполнения следующего соглашения:
Программист не должен делать каких-либо предположений о содержимом остальных регистров, и эти регистры могут иметь произвольное значение после завершения работы ассемблерного оператора. Исключением является случай ассемблерной функции, которая должна использовать некоторые регистры для возврата своего значения (см. п. 12.2.3).
12.2.2. Синтаксис ассемблерных команд
Здесь и далее ассемблерными командами называются команды на языке встроенного ассемблера, вставляемые в тело ассемблерного оператора asm. end. Структура ассемблерной команды такова:
[Метка] [Префикс] [Код [Операнд [,Операнд]]]
В квадратных скобках указываются необязательные элементы структуры.
Локальные метки объявляются непосредственно в теле ассемблерного оператора. Эти метки обязаны начинаться символом «@». Поскольку этот символ нельзя использовать в именах Турбо Паскаля, он позволяет отличить локальную метку от глобальной. Локальная метка не известна нигде вне ассемблерного оператора, поэтому на нее нельзя передать управление оператором GOTO. По этой же причине в разных ассемблерных операторах можно использовать одноименные локальные метки.
Встроенный ассемблер поддерживает следующие префиксы команд:
REP/REPE/REPNE Повтор строковой команды
REPZ/REPNZ Синоним REPE/REPNE
SEGCS Перекрытие CS
SEGDS Перекрытие DS
SEGSS Перекрытие SS
SEGES Перекрытие ES
Префиксы LOCK/REP/REPE/REPNE описаны в п. 12.1.3. Префиксы SEGxx определяют сегментный регистр, который должен использоваться вместо умалчиваемого, и распространяются только на следующие за ними ассемблерные команды.
Если префикс указан без кода инструкции, он распространяет свое действие на следующую ассемблерную команду.
Замечу, что если при обработке строковой команды произошло аппаратное прерывание, МП 8086/8088 «забывает» префиксы LOCK и SEGxx, которые, возможно, определены в той же команде, так что использовать сложные префиксные конструкции не рекомендуется.
Операндами встроенного ассемблера могут быть выражения, состоящие из комбинации регистров, констант, имен и символов операций.
Во встроенном ассемблере используется мнемоника регистров, указанная в п. 12.1.1, а также имя ST для ссылки на регистры арифметического сопроцессора.
Ассемблер поддерживает строковые и числовые константы.
Строковые константы заключаются в апострофы или кавычки. Если константа объявлена с помощью кавычек, внутри нее символ апостроф рассматривается наравне с другими символами, т.е. не считается ограничителем константы, точно так же внутри константы, обрамленной апострофами, не считается ограничителем символ кавычки. Если внутри константы необходимо указать ограничивающий ее символ, он удваивается. Примеры:
‘Символ » не считается ограничителем’
‘внутри строки, обрамленной кавычками «. «‘
Числовые константы могут быть только целыми и их значение не может превосходить емкости двойного слова, т.е. должно быть внутри диапазона
— 2 147 483 648. + 4 294 967 295.
Во встроенном ассемблере могут использоваться три предопределенных имени:
Имена @Code и @Data могут использоваться только в сочетании с директивой SEG для ссылки на нужный сегмент. Например:
Имя @Result используется для присвоения результата функции. Например:
Function Min(X,Y: Integer): Integer;
db ‘Турбо Паскаль’,13,10
dw 0,$ FFFF, NearProc
dd ‘ABCD1,999999999, FarProc
В качестве константных выражений разрешается использовать любые ассемблерные константы со значением, не выходящим из диапазона байта (DB), слова (DW) или двойного слова (DD). В любой директиве можно определять строковую константу, которая приводит к побайтовому заполнению памяти ASCII-кодами символов. Поскольку слово (двойное слово) размещается в памяти, начиная со своего младшего байта, старший (старшие) байт в директивах DW и DD при размещении строкой константы может остаться неопределенным и заполняется нулем. Например, два следующих объявления эквивалентны:
db ‘Текстовая строка,13,10,’$’
Обратите внимание на использование регистра DS. В соответствии с требованиями функции 9, он должен содержать сегмент выводимой строки. В нашем случае строка располагается в кодовом сегменте, поэтому мы вынуждены сначала сохранить значение DS в стеке, а затем восстановить его. Если бы мы этого не сделали, по завершении ассемблерного оператора регистр DS указывал бы на сегмент кода и была бы потеряна связь программы Турбо Паскаля с глобальными переменными и константами.
12.2.4. Ассемблерные подпрограммы
Function LongMul(X,Y:Integer):LongInt; Assembler;
При компиляции ассемблерных подпрограмм выполняется ряд оптимизаций кода, в том числе:
— параметры-значения строкового типа, а также длиной в 1, 2 и 4 байта не копируются во временную память, т.е. внутри подпрограммы они считаются параметрами-переменными ;
— компилятор не создает переменную @Result для результата функции, и ссылка на эту переменную в ассемблерной функции недопустима; исключением являются функции, возвращающие значения строкового типа, для них разрешается использовать ссылку на @Result;
— генерируются следующие команды на входе в подпрограмму и на ее выходе:
Все локальные переменные Турбо Паскаль размещает в стеке. Это относится как к обычным, так и к ассемблерным подпрограммам. Для ссылки на локальные переменные используется адресация по базе, задаваемой парой DS: ВР, поэтому при входе в процедуру всегда создается так называемый локальный стек: в регистр ВР помещается текущая граница стека, а сама эта граница смещается вверх на суммарную длину всех локальных переменных, чтобы работа со стеком внутри подпрограммы не разрушила локальные переменные. Например:
Ассемблерные функции должны следующим образом возвращать результат своей работы: