ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.


Мужское здоровье как сохранить Мужскую.

 

B.Pascal 7 & Objects

                      Руководство по языку
ННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННННН

         B.Pascal 7 & Objects/LR       - 1 -

        Введение.......................................................10
        О чем рассказывается в данном руководстве......................11
        Часть I. Язык Borland Pascal...................................12
        Глава 1. Что такое программа Borland Pascal?...................12
        Программа Borland Pascal.......................................13
        Процедуры и функции............................................13
        Операторы......................................................15
        Выражения......................................................16
        Лексемы........................................................17
        Типы, переменные, константы и типизированные константы.........17
        Компоновка частей..............................................19
        Модули.........................................................20
        Синтаксические диаграммы.......................................21
        Глава 2. Лексемы...............................................22
        Специальные символы............................................22
        Зарезервированные слова и стандартные директивы Borland
         Pascal........................................................24
        Идентификаторы.................................................25
        Числа..........................................................27
        Метки..........................................................29
        Строки символов................................................29
        Комментарии....................................................31
        Строки программы...............................................31
        Глава 3. Константы.............................................32
        Глава 4. Типы..................................................34
        Простые типы...................................................35
        Порядковые типы................................................35
        Целочисленные типы.............................................37
        Булевские типы.................................................39
        Символьный тип (char)..........................................40
        Перечислимые типы..............................................40
        Отрезки типа...................................................41
        Вещественные типы..............................................42
        Программная поддержка чисел с плавающей точкой.................43
        Аппаратная поддержка чисел с плавающей точкой..................43
        Строковые типы.................................................44
        Структурные типы...............................................45
        Типы массив....................................................46
        Типы запись....................................................48
        Объектные типы.................................................50
        Компоненты и область действия..................................54
        Методы.........................................................54
        Виртуальные методы.............................................54
        Динамические методы............................................56
        Создание экземпляров объектов..................................57
        Активизация методов............................................59
        Активизация уточненных методов.................................60
        Множественные типы.............................................61
        Файловые типы..................................................62
        Ссылочные типы.................................................63
        Тип Pointer....................................................64
        Тип PChar......................................................64
        Процедурные типы...............................................65

         B.Pascal 7 & Objects/LR       - 2 -

        Процедурные значения...........................................65
        Совместимость типов............................................67
        Тождественные и совместимые типы...............................67
        Тождественность типов..........................................67
        Совместимость типов............................................68
        Совместимость по присваиванию..................................69
        Раздел описания типов..........................................70
        Глава 5. Переменные и типизированные константы.................72
        Описания переменных............................................72
        Сегмент данных.................................................73
        Сегмент стека..................................................73
        Абсолютные переменные..........................................74
        Ссылки на переменные...........................................76
        Квалификаторы..................................................77
        Массивы, строки и индексы......................................78
        Записи и десигнаторы полей.....................................79
        Десигнаторы компонентов объекта................................79
        Переменные-указатели и динамические переменные.................79
        Приведение типов переменных....................................81
        Типизированные константы.......................................83
        Константы простого типа........................................84
        Константы строкового типа......................................84
        Константы структурного типа....................................85
        Константы типа массив..........................................86
        Константы типа запись..........................................88
        Константы объектного типа......................................89
        Константы множественного типа..................................90
        Константы ссылочного типа......................................91
        Константы процедурного типа....................................92
        Глава 6. Выражения.............................................93
        Синтаксис выражений............................................94
        Операции.......................................................99
        Арифметические операции........................................99
        Унарные арифметические операции...............................100
        Логические операции...........................................101
        Булевские операции............................................101
        Операция со строками..........................................103
        Операции над символьными указателями..........................104
        Операции над множествами......................................105
        Операции отношения............................................106
        Сравнение простых типов.......................................107
        Сравнение строк...............................................107
        Сравнение упакованных строк...................................107
        Сравнение указателей..........................................107
        Сравнение символьных указателей...............................108
        Сравнение множеств............................................108
        Проверка на принадлежность к множеству........................108
        Операция @....................................................109
        Использование операции @ для переменной.......................110
        Использование операции @ для процедуры или функции или
         метода.......................................................111
        Вызовы функции................................................111
        Описатели множества...........................................113

         B.Pascal 7 & Objects/LR       - 3 -

        Приведение типа значений......................................114
        Процедурные типы в выражениях.................................115
        Глава 7. Операторы............................................117
        Простые операторы.............................................117
        Оператор присваивания.........................................118
        Операторы процедуры...........................................119
        Операторы перехода............................................120
        Структурные операторы.........................................120
        Составные операторы...........................................121
        Условные операторы............................................121
        Оператор условия (if).........................................122
        Оператор варианта (case)......................................123
        Оператор цикла................................................125
        Оператор цикла с постусловием (repeat)........................125
        Операторы цикла с предусловием (while)........................127
        Операторы цикла с параметром (for)............................128
        Оператор with.................................................131
        Глава 8. Блоки, локальность и область действия................133
        Синтаксис.....................................................133
        Правила для области действия..................................136
        Область действия для блока....................................136
        Область действия записи.......................................137
        Область действия объекта......................................137
        Область действия модуля.......................................137
        Глава 9. Процедуры и функции..................................139
        Описания near и far...........................................141
        Описания export...............................................142
        Описания interrupt............................................143
        Описание forward..............................................143
        Описания external.............................................145
        Описания assembler............................................147
        Описания inline...............................................147
        Описания функций..............................................148
        Описания методов..............................................150
        Конструкторы и деструкторы....................................151
        Восстановление ошибок конструктора............................154
        Параметры.....................................................156
        Параметры-значения............................................157
        Параметры-константы...........................................157
        Параметры-переменные..........................................157
        Нетипизированные параметры....................................158
        Открытые параметры............................................160
        Открытые строковые параметры..................................160
        Открытые параметры-массивы....................................162
        Динамические переменные объектного типа.......................163
        Процедурные переменные........................................165
        Параметры процедурного типа...................................168
        Глава 10. Программы и модули..................................170
        Синтаксис программ............................................170
        Заголовок программы...........................................170
        Оператор uses.................................................171
        Синтаксис модулей.............................................172
        Заголовок модуля..............................................172

         B.Pascal 7 & Objects/LR       - 4 -

        Интерфейсная секция...........................................173
        Секция реализации.............................................174
        Секция инициализации..........................................175
        Косвенные ссылки на модули....................................175
        Перекрестные ссылки на модули.................................177
        Совместное использование описаний.............................179
        Глава 11. Динамически компонуемые библиотеки..................180
        Что такое DLL?................................................180
        Использование DLL.............................................180
        Модули импорта................................................182
        Статический и динамический импорт.............................184
        Написание DLL.................................................185
        Директива процедуры export....................................187
        Оператор exports..............................................187
        Код инициализации библиотеки..................................189
        Замечания по программированию библиотек.......................191
        Глобальные переменные в DLL...................................191
        Глобальные переменные и файлы в DLL...........................191
        DLL и модуль System...........................................191
        Ошибки этапа выполнения в DLL.................................192
        DLL и сегменты стека..........................................192
        Создание совместно используемых DLL...........................193
        Глава 12. Библиотеки исполняющей системы......................194
        Модули Borland Pascal.........................................194
        Модуль System.................................................195
        Модуль Dos и WinDos...........................................195
        Модуль Crt....................................................195
        Модуль WinCrt.................................................196
        Модуль Printer................................................196
        Модуль WinPrn.................................................196
        Модуль Overlay................................................196
        Модуль Strings................................................197
        Модуль Graph..................................................197
        Модули Turbo3 и Graph3........................................197
        Модули WinTypes и WinProcs....................................197
        Модуль Win31..................................................198
        Модуль WinAPI.................................................198
        Модули, поддерживающие Windows 3.1............................198
        Глава 13. Стандартные процедуры и функции.....................199
        Процедуры управления работой программы........................200
        Функции преобразования........................................200
        Арифметические функции........................................201
        Порядковые процедуры и функции................................202
        Строковые процедуры и функции.................................202
        Процедуры и функции динамического распределения памяти........203
        Функции для работы с указателями и адресами...................204
        Прочие процедуры и функции....................................205
        Предописанные переменные......................................206
        Глава 14. Ввод и вывод........................................215
        Файловый ввод-вывод...........................................217
        Текстовые файлы...............................................219
        Нетипизированные файлы........................................221
        Переменная FileMode...........................................221

         B.Pascal 7 & Objects/LR       - 5 -

        Устройства в Borland Pascal...................................222
        Устройства DOS................................................223
        Устройство CОN................................................224
        Устройства LРT1, LРT2 и LРT3..................................224
        Устройства CОМ1 и CОМ2........................................225
        Устройство NUL................................................225
        Устройства, предназначенные для текстовых файлов..............225
        Ввод и вывод с помощью модуля Crt.............................226
        Использование модуля CRT......................................227
        Окна CRT......................................................227
        Специальные символы...........................................228
        Ввод строк....................................................228
        Процедуры и функции модуля Crt................................230
        Константы и переменные модуля Crt.............................232
        Ввод и вывод с помощью модуля WinCrt..........................233
        Использование модуля WinCrt...................................234
        Специальные символы...........................................236
        Ввод строк....................................................236
        Процедуры и функции...........................................237
        Переменные модуля WinCrt......................................239
        Печать из программы Windows...................................241
        Изменение заголовков..........................................241
        Изменение шрифтов.............................................242
        Остановка задания печати......................................243
        Специальные символы...........................................243
        Процедуры и функции модуля WinPrn.............................244
        Функция Open..................................................246
        Функция InOut.................................................246
        Функция Flush.................................................247
        Функция Clоsе.................................................247
        Глава 15. Использование сопроцессора 80x87....................248
        Типы данных процессора 80x87..................................251
        Арифметические операции с повышенной точностью................252
        Сравнение вещественных чисел..................................253
        Стек вычислений сопроцессора 80x87............................253
        Запись вещественных чисел при использовании сопроцессора
         80x87........................................................255
        Модули, в которых используется сопроцессор 80x87..............255
        Распознавание сопроцессора 80х87 в программах DOS.............256
        Распознавание сопроцессора 80x87 в программе Windows..........257
        Использование эмуляции сопроцессора 80x87 на языке
         ассемблера...................................................258
        Глава 16. Модуль Dоs..........................................259
        Процедуры и функции модуля Dos................................260
        Константы, типы и переменные модуля Dos.......................263
        Типы..........................................................263
        Переменные модуля Dos.........................................264
        Процедуры и функции модуля WinDos.............................265
        Константы, типы и переменные модуля WinDos....................268
        Типы..........................................................269
        Переменные модуля WinDos......................................269
        Глава 17. Программирование в защищенном режиме DOS............270
        Что такое защищенный режим?...................................270

         B.Pascal 7 & Objects/LR       - 6 -

        Расширения Borland защищенного режима DOS.....................274
        DPMI-сервер...................................................274
        Администратор этапа выполнения................................274
        Разработка прикладных программ DOS защищенного режима.........276
        Надежное программирование в защищенном режиме.................276
        Загрузка в сегментные регистры недопустимых значений..........277
        Функция Ptr и массивы Mem.....................................277
        Абсолютные переменные.........................................277
        Операции с сегментами.........................................278
        Использование сегментных......................................278
        Доступ к памяти вне границ сегмента...........................278
        Запись в сегмент кода.........................................279
        Разыменование указателей nil..................................279
        Сегменты кода и данных........................................279
        Управление динамически распределяемой памятью.................280
        Предопределенные селекторы....................................280
        Переменная SelectorInc........................................281
        Модуль WinAPI.................................................284
        Управление памятью............................................284
        Подпрограммы управления памятью API...........................285
        Управление модулем............................................289
        Управление ресурсами..........................................290
        Управление селектором.........................................291
        Другие подпрограммы API.......................................292
        Прямой доступ к DPMI-серверу..................................293
        Компиляция прикладной программы защищенного режима............293
        Выполнение программы защищенного режима DOS...................294
        Управление объемом используемой RTM памяти....................295
        Глава 18. Строки с завершающим нулем..........................297
        Что такое строка с завершающим нулем?.........................297
        Функции модуля Strings........................................297
        Функции модуля Strings........................................298
        Использование строк с завершающим нулем.......................299
        Символьные указатели и строковые литералы.....................301
        Символьные указатели и символьные массивы.....................302
        Индексирование символьного указателя..........................303
        Операции с символьными указателями............................304
        Строки с завершающим нулем и стандартные процедуры............305
        Пример использования функций с завершающим нулем..............306
        Глава 19. Использование графического интерфейса Borland.......308
        Драйверы......................................................308
        Поддержка устройства IBM 8514.................................310
        Система координат.............................................311
        Текущий указатель.............................................311
        Текст.........................................................313
        Графические изображения и их виды.............................314
        Области просмотра и двоичные образы...........................314
        Поддержка страниц и цветов....................................315
        Обработка ошибок..............................................315
        Начало работы.................................................316
        Пользовательские программы управления динамически
         распределяемой памятью.......................................318
        Процедуры модуля Graph........................................321

         B.Pascal 7 & Objects/LR       - 7 -

        Константы, типы и переменные модуля Graph.....................326
        Константы.....................................................326
        Типы..........................................................328
        Переменные....................................................328
        Глава 20. Использование оверлеев..............................329
        Администратор оверлеев........................................330
        Управление оверлейным буфером.................................331
        Процедуры и функции модуля Overlay............................334
        Коды результата...............................................335
        Разработка программ с оверлеями...............................335
        Генерация оверлейного кода....................................336
        Требование использования дальнего типа вызовов................337
        Инициализация администратора оверлеев.........................338
        Разделы инициализации в оверлейных модулях....................341
        Что не должно использоваться в качестве оверлеев..............342
        Отладка оверлеев..............................................343
        Внешние программы в оверлеях..................................343
        Задание функции чтения оверлея................................345
        Оверлеи в файлах .EXE.........................................347
        Часть III. В среде Borland Pascal.............................348
        Глава 21. Использование памяти................................348
        Использование памяти программами реального режима DOS.........348
        Администратор динамически распределяемой области памяти DOS...350
        Методы освобождения областей динамически распределяемой
         памяти.......................................................352
        Список свободных блоков.......................................355
        Переменная HeapError..........................................356
        Использование памяти в программах DOS защищенного режима......359
        Сегменты кода.................................................359
        Атрибуты сегмента.............................................359
        Атрибуты MOVEABLE или FIXED...................................359
        Атрибуты PRELOAD или DEMANDLOAD...............................359
        Атрибуты DISCARDABLE или PERMAMENT............................359
        Сегменты данных и стека.......................................361
        Изменение атрибутов...........................................361
        Администратор динамически распределяемой области памяти DOS...362
        Переменная HeapError..........................................363
        Использование памяти в программах Windows.....................365
        Атрибуты сегментов............................................365
        Атрибуты MOVEABLE или FIXED...................................365
        Атрибуты PRELOAD или DEMANDLOAD...............................365
        Атрибуты DISCARDABLE или PERMANENT............................365
        Изменение атрибутов...........................................365
        Сегмент локальных динамических данных.........................367
        Администратор динамически распределяемой области памяти.......368
        Переменная HeapError..........................................370
        Форматы внутреннего представления данных......................372
        Целочисленные типы............................................372
        Символьный тип................................................372
        Булевский тип.................................................372
        Перечислимый тип..............................................372
        Типы с плавающей точкой.......................................373
        Вещественный тип..............................................373

         B.Pascal 7 & Objects/LR       - 8 -

        Тип числа с одинарной точностью...............................374
        Тип числа с двойной точностью.................................374
        Тип числа с повышенной точностью..............................375
        Сложный тип...................................................375
        Значения типа указатель.......................................375
        Значения строкового типа......................................376
        Значения множественного типа..................................376
        Значения типа массив..........................................376
        Значения типа запись..........................................376
        Объектные типы................................................377
        Таблица виртуальных методов...................................378
        Таблица динамических методов..................................381
        Значения файлового типа.......................................385
        Процедурные типы..............................................387
        Прямой доступ к памяти........................................387
        Прямой доступ к портам........................................387
        Глава 22. Вопросы управления..................................388
        Соглашения по вызовам.........................................388
        Параметры-переменные..........................................388
        Параметры-значения............................................388
        Открытые строковые параметры..................................389
        Результаты функций............................................390
        Ближние и дальние типы вызовов................................391
        Вложенные процедуры и функции.................................391
        Соглашения о вызовах методов..................................392
        Вызовы виртуальных методов....................................394
        Вызовы динамических методов...................................395
        Конструкторы и деструкторы....................................396
        Стандартный код входа и выхода................................396
        Соглашения по сохранению регистров............................400
        Процедуры выхода..............................................400
        Обработка прерываний..........................................403
        Разработка процедур обработки прерываний......................403
        Глава 23. Автоматическая оптимизация..........................405
        Свертывание констант..........................................405
        Слияние констант..............................................405
        Вычисление по короткой схеме..................................405
        Параметры-константы...........................................406
        Устранение избыточной загрузки указателей.....................406
        Подстановка констант множественного типа......................406
        Малые множества...............................................407
        Порядок вычисления............................................407
        Проверка на допустимость границ...............................408
        Использование сдвига вместо умножения.........................408
        Автоматическое выравнивание на границу слова..................408
        Удаление неиспользуемого кода.................................409
        Эффективная компоновка........................................409
        Часть IV. Использование Borland Pascal с языком ассемблера....411
        Глава 24. Встроенный ассемблер................................411
        Оператор asm..................................................411
        Использование регистров.......................................412
        Синтаксис операторa ассемблера................................412
        Метки.........................................................413

         B.Pascal 7 & Objects/LR       - 9 -

        Размер инструкции RET.........................................413
        Автоматическое определение размера перехода...................414
        Директивы ассемблера..........................................415
        Операнды......................................................417
        Выражения.....................................................417
        Различия между выражениями Паскаля и ассемблера...............418
        Элементы выражений............................................419
        Константы.....................................................420
        Числовые константы............................................420
        Строковые константы...........................................420
        Регистры......................................................422
        Идентификаторы................................................422
        Классы выражений..............................................426
        Типы выражений................................................427
        Операции в выражениях.........................................430
        Процедуры и функции ассемблера................................434
        Глава 25. Компоновка с программами на языке ассемблера........437
        Турбо Ассемблер и Borland Pascal..............................438
        Примеры программ на языке ассемблера..........................440
        Методы на языке ассемблера....................................441
        Включаемый машинный код.......................................442
        Операторы Inline..............................................442
        Директивы inline..............................................444

         B.Pascal 7 & Objects/LR      - 10 -

                                   Введение
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Данное руководство  посвящено используемому в Borland Pascal
        with Objects языку Паскаль. Оно

             * Дает формальное определение языка Borland Pascal.

             * Поясняет,  как использовать и писать динамически компонуе-
               мые библиотеки.

             * Знакомит вас с библиотекой исполняющей системы.

             * Поясняет, как писать программы для защищенного режима DOS.

             * Освещает  такие вопросы Borland Pascal,  как использование
               памяти, форматы данных, соглашения по вызову, ввод и вывод
               и автоматическая оптимизация.

             * Описывает,  как  использовать  Borland Pascal с языком ас-
               семблера.

                   Примечания: Обзор всего набора документации по Borland
              Pascal вы можете найти во введении к "Руководству пользова-
              теля".

             Если вы

             - хотите узнать, как установить Borland Pascal в системе;

             - использовали Turbo Pascal или Turbo Pascal for Windows ра-
               нее и хотите узнать, что нового в этой версии;

             - не  знакомы  с интерактивной интегрированной средой разра-
               ботки программ (IDE) фирмы Borland;

             - хотите познакомиться с введением в  объектно-ориентирован-
               ное программирование;

             - не имеете опыта программирование на Паскале в Windows;

             - хотите познакомиться с ObjectWindows;

        то прочитайте "Руководство пользователя".

             Чтобы найти справочные материалы по следующим темам:

             - библиотеки исполняющей системы;

             - директивы компилятора;

             - сообщения об ошибках;


         B.Pascal 7 & Objects/LR      - 11 -

             - работа с редактором;

        прочтите "Справочное руководство программиста".

                   О чем рассказывается в данном руководстве
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Данное руководство разбито на четыре части:  грамматика язы-
        ка, библиотеки, вопросы продвинутого программирования и использо-
        вание с Borland Pascal языка ассемблера.

             В Части I "Язык Borland Pascal"  определяется  язык  Borland
        Pascal. Сначала  вы  познакомитесь  с  общей структурой программы
        Borland Pascal; затем о каждом элементе программы будет рассказа-
        но более подробно.

             Часть II  "Библиотеки исполняющей системы" содержит информа-
        цию о стандартных модулях, образующих библиотеку исполняющей сис-
        темы, и о том,  как их использовать.  Здесь рассказывается также,
        как писать программы для защищенного режима DOS.

             В Части III "В среде Borland Pascal" дается техническая  ин-
        формация для продвинутых пользователей. Здесь рассказывается:

             - об использовании памяти в Borland Pascal;

             - о  том,  как в Borland Pascal реализовано управление прог-
               раммой;

             - о деталях по вводу и выводу;

             - об оптимизации вашего кода.

             В Части IV "Использование Borland Pascal с языком  ассембле-
        ра" поясняется,  как использовать встроенный ассемблер и как ком-
        поновать ваши программы Паскаля с кодом Турбо Ассемблера.




         B.Pascal 7 & Objects/LR      - 12 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                         Часть I. Язык Borland Pascal
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

                 Глава 1. Что такое программа Borland Pascal?
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Следующие несколько  глав  посвящены формальному определению
        языка Borland Pascal.  В каждой главе обсуждается один из элемен-
        тов Borland  Pascal.  Совместно  эти  элементы образуют программу
        Borland Pascal.

             Однако, изучая части,  трудно понять целое.  В данной  главе
        дается общий  обзор  программы  Borland  Pascal,  опуская детали.
        Здесь приводится краткое описание каждого элемента  программы,  а
        затем показывается,  как все это компонуется вместе.  Подробности
        элементов языка освещаются  главах 2 - 11.



         B.Pascal 7 & Objects/LR      - 13 -

                           Программа Borland Pascal
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В своей простейшей форме программа Borland Pascal состоит из
        заголовка программы, который именует программу, и основного прог-
        раммного блока,  выполняющего  назначение  программы.  В основном
        программном блоке находится секция кода, заключенная между ключе-
        выми словами begin и end.  Приведем простейшую программу, иллюст-
        рирующую эти принципы:

             program Privet;
             begin
               Writeln('Добро пожаловать в Borland Pascal');
             end.

             Первая строка  -  это  заголовок программы,  который именует
        данную программу.  Остальная часть программы - это исходный  код,
        который начинается ключевым словом begin и заканчивается end. Хо-
        тя данная конкретная программа содержит только  одну  строку,  их
        может быть  много.  В любой программе Borland Pascal все действия
        выполняются между begin и end.

                              Процедуры и функции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Процедуры и функции позволяют разделить логику программы  на
        более мелкие и управляемые фрагменты и аналогичны подпрограммам в
        других языках.  Как и в основном блоке программы,  все действия в
        процедурах  и функциях заключаются в begin и end.  Каждый из этих
        сегментов кода выполняет конкретную задачу.

             ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
             і Процедура или функция                                    і
             іЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїі
             іі Заголовок процедуры или функции                        іі
             іАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩі
             іЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїі
             іі Блок процедуры или функциями                           іі
             іі begin                                                  іі
             ііЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїіі
             ііі Логика                                               ііі
             ііАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩіі
             іі end;                                                   іі
             іАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩі
             АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ


         B.Pascal 7 & Objects/LR      - 14 -

             Рис. 1.1 Диаграмма процедуры или функции.

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

             Приведем пример функции. Следующая функция GetNumber получа-
        ет число от пользователя:

             function GetNumber: Real;
             var
                Responce: Real;
             begin
                Write('Введите число: ');
                Readln(Response);
                GetNumber := Response;
             end;

             Процедура или функция должна содержаться в  программе  перед
        секцией основного кода. В основном коде она может затем использо-
        ваться (вызываться).

             ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
             і Процедура или функция                                    і
             іЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїі
             іі Заголовок процедуры или функции                        іі
             іАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩі
             іЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїі
             іі Блок процедуры или функциями                           іі
             ііЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїіі
             ііі Процедуры или функции (0 или более)                  ііі
             ііАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩіі
             іі begin                                                  іі
             ііЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїіі
             ііі Логика                                               ііі
             ііАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩіі
             іі end;                                                   іі
             іАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩі
             АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Рис. 1.2 Простая программа на Паскале.

             В следующем примере дается набросок программы, в которой ис-
        пользуется функция GetNumber.  Программист разделил логику  прог-
        раммы на три задачи:

             1. Получение числа от пользователя.

             2. Выполнение с этим числом необходимых вычислений.

             3. Печать отчета.

         B.Pascal 7 & Objects/LR      - 15 -


             Основная логика   программы   заключена  в  последнем  блоке
        begin..end.

             Program Report;

             var
               A: Real;
             { другие описания }
                .
                .
                .
               function GetNumber: Real;
               var
                  Responce: Real;
               begin
                  Write('Введите число: ');
                  Readln(Response);
                  GetNumber := Response;
               end;

               procedure Calculate(X: Real);
                  .
                  .
                  .
               procedure PrintReport;
                  .
                  .
                  .
             begin
               A: = GetNumber;
               Calculate(A);
               PrintReport;
             end.

             Основная логика  программы  достаточно проста для понимания.
        Все детали убраны в тела процедур и функций. Использование проце-
        дур и функций позволяет вам рассматривать программу более удобным
        и модульным способом.

                                   Операторы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Исходный код  между begin и end содержит операторы,  которые
        описывают выполняемые программой действия.  Это называются опера-
        торной частью программы. Приведем примеры операторов:

             A := B + C;                   { присвоить значение }

             Calculate(Length, Height);    { активизировать процедуру }

             if X < 2 then                 { оператор условия }
                 Answer := X * Y;

         B.Pascal 7 & Objects/LR      - 16 -


             begin                         { составной оператор }
               X := 3;
               Y := 4;
               Z := 5;
             end;

             while not EOF(InFile) do      { оператор цикла }
             begin
                ReadLn(InFile, Line);
                Process(Line);
             end;

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

                                   Выражения
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Выражения Паскаля могут состоять из более простых выражений.
        О комбинации операндов и операций вы можете прочитать в Главе  6.
        Они могут  быть  достаточно сложными.  Приведем некоторые примеры
        выражений:

             X + Y
             Done <> Error
             I <= Length
             -X



         B.Pascal 7 & Objects/LR      - 17 -

                                     Лексемы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             function                   { зарезервированное слово }
             (                          { специальный символ }
             :=                         { специальный символ }
             Calculate                  { идентификатор процедуры }
             9                          { число }

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

             ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
             і Операторы (1 или более)                                  і
             іЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїі
             іі Выражения (1 или более)                                іі
             ііЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїіі
             ііі Лексемы (1 или более)                                ііі
             ііАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩіі
             іАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩі
             АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Рис. 1.3 Диаграмма оператора.


             Типы, переменные, константы и типизированные константы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Переменная может содержать изменяемое значение. Каждая пере-
        менная должна иметь тип. Тип переменной определяет множество зна-
        чений, которые может иметь переменная.

             Например, в  следующей  программе описываются переменные X и
        Y, имеющие тип Integer.  Таким образом,  X и  Y  могут  содержать
        только целые значения (числа).  Если в вашей программе предприни-
        мается попытка присвоить этим переменным значения  другого  типа,
        Borland Pascal сообщает об ошибке.

             program Example;

             const
                A = 12;           { константа A не изменяет значения }
                B: Integer = 23;  { типизированная константа B получает
                                    начальное значение }
             var
               X, Y: Integer;     { переменные X и Y имеют тип Integer }
               J: Real;           { переменная J имеет тип Real }


         B.Pascal 7 & Objects/LR      - 18 -

             begin
               X := 7;            { переменной X присваивается значение }
               Y := 7;            { переменной Y присваивается значение }
               X := Y + Y;        { значение переменной X изменяется }
               J := 0.075;        { переменной J присваивается значение
                                    с плавающей точкой }
             end.

             В этой простой и не очень полезной программе X первоначально
        присваивается значение 7; двумя операторами ниже ей присваивается
        новое значение:  Y + Y. Как можно видеть, значение переменной мо-
        жет изменяться.

             A - это константа. Программа назначает ей значение 12, и это
        значение изменяться  не  может  - в ходе выполнения программы оно
        остается постоянным.

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

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




         B.Pascal 7 & Objects/LR      - 19 -

                                Компоновка частей
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Теперь, когда  вы  познакомились  с  основными  компонентами
        программы Borland Pascal, давайте посмотрим, как все это работает
        вместе. Приведем диаграмму программы Borland Pascal:

             ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
             і Программа на Паскале                                     і
             іЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїі
             іі Заголовок программы                                    іі
             іАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩі
             іЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїі
             іі Необязательные операторы uses                          іі
             іАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩі
             іЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїі
             іі Основной блок программы                                іі
             ііЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїіі
             ііі Описания                                             ііі
             ііАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩіі
             ііЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїіі
             ііі Процедуры или функции (0 или более)                  ііі
             іііЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїііі
             іііі Описания                                           іііі
             іііАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩііі
             ііі begin                                                ііі
             ііі    ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїііі
             ііі    і Операторы (1 или более)                        іііі
             ііі    АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩііі
             ііі end;                                                 ііі
             ііАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩіі
             іі begin                                                  іі
             іі  ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїіі
             іі  і Операторы (1 или более)                            ііі
             іі  іЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїііі
             іі  іі Выражения (1 или более)                          іііі
             іі  ііЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДїіііі
             іі  ііі Лексемы (1 или более)                          ііііі
             іі  ііАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩіііі
             іі  іАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩііі
             іі  АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩіі
             іі end.                                                   іі
             іАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩі
             АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Рис. 1.4 Расширенная диаграмма программы на Паскале.

             Программу на Паскале составляют заголовок программы,  необя-
        зательный оператор uses (о нем будет рассказано позднее) и основ-
        ной блок программы.  В основном блоке могут присутствовать  более
        мелкие блоки  процедур и функций.  Хотя на диаграмме это не пока-
        зано, процедуры им функции могут быть вложенными в другие  проце-
        дуры или функции.  Другими словами,  блоки могут содержать другие

         B.Pascal 7 & Objects/LR      - 20 -

        блоки.

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

                                     Модули
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Программа Borland Pascal может  использовать  блоки  кода  в
        программных модулях.  Модуль  (unit)  можно рассматривать как ми-
        ни-программу, которую может использовать ваша прикладная програм-
        ма. Как и программа, он имеет заголовок (который называется заго-
        ловком модуля) и основной блок, ограниченный begin и end.

             Основной блок любой программы Borland Pascal может  включать
        в себя  строку, позволяющую программе использовать один или более
        модулей. Например, если вы пишете программу DOS с именем Colors и
        хотите изменять  цвета выводимого на экран текста,  то ваша прог-
        рамма может  использовать  стандартный  модуль  Crt,   являющийся
        частью библиотеки исполняющей системы Borland Pascal:

             program Colors;
             uses Crt;
             begin
                .
                .
                .
             end.

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

             Библиотеки исполняющей системы Borland Pascal включают в се-
        бя несколько модулей, которые вы найдете весьма полезными. Напри-
        мер, благодаря  использованию модулей Dos или WinDos,  ваша прог-
        рамма может получить доступ к нескольким подпрограммам операцион-
        ной системы и подпрограммам работы с файлами.

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


         B.Pascal 7 & Objects/LR      - 21 -

                            Синтаксические диаграммы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             При изучении  глав  2  -  11,  где определяется язык Borland
        Pascal, вы встретите синтаксические диаграммы, например:

                                  ЪДДДї     ЪДДДДДДДДДДДДДДї     ЪДДДї
            константа-массив  ДДД>і ( ГДДДД>ітипизированнаяГДДВД>і ) ГДД>
                                  АДДДЩ  ^  і  константа   і  і  АДДДЩ
                                         і  АДДДДДДДДДДДДДДЩ  і
                                         і      ЪДДДї         і
                                         АДДДДДДґ , і<ДДДДДДДДЩ
                                                АДДДЩ

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

             Имена в  прямоугольных рамках с текстом должны быть заменены
        действительными конструкциями.  Некоторые рамки содержат зарезер-
        вированные слова, знаки операций и знаки пунктуации, то есть фак-
        тические термы,  используемые в программе.  Имена в блоках -  это
        конструкции  языка.  Имена,  написанные  по-английски  (например,
        procedure),  представляю собой зарезервированные слова и операции
        Borland Pascal.



         B.Pascal 7 & Objects/LR      - 22 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                                Глава 2. Лексемы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Лексемы - это минимальные значимые единицы текста в програм-
        ме,  написанной на Паскале.  Они представлены такими  категориями
        как специальные символы, идентификаторы, метки, числа и строковые
        константы.

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

                   Примечание: Разделители  не  могут быть частью лексем,
              за исключением строковых констант.

                               Специальные символы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Borland Pascal использует следующие подмножества набора сим-
        волов кода ASCII:

             * Буквы - буквы английского алфавита от A до Z и от a до z.

             * Цифры - арабские цифры от 0 до 9.

             * Шестнадцатиричные  цифры - арабские цифры от 0 до 9, буквы
               от A до F и буквы от a до f.

             * Разделители - символ пробела (ASCII 32) и все  управляющие
               символы  кода  ASCII  (ASCII  0-31),  включая символ конца
               строки или символ возврата (ASCII 13).

         буква
           і
           АДДДДДДДДДВДДДДДДДДДДДДДДВДДДДДДДДДДДДДДВДДДДДДДДДДДДДДї
                     і              і              і              і
                     v              v              v              v
                   ЪДДДї          ЪДДДї          ЪДДДї          ЪДДДї
                   і A і   ...    і Z і          і a і   ...    і z і
                   АДВДЩ          АДВДЩ          АДВДЩ          АДВДЩ
                     і              і              і              і
                     АДДДДДДДДДДДДДДБДДДДДДДДДДДДДДБДДДДДДДДДДДДДДБДДДД>


         B.Pascal 7 & Objects/LR      - 23 -


         цифра
           і
           АДДДДДДВДДДДДДДДДДДї
                  і           і
                  v           v
                ЪДДДї       ЪДДДї
                і 0 і  ...  і 9 і
                АДВДЩ       АДВДЩ
                  і           і
                  АДДДДДДДДДДДБДДДДДДД>

         шестнадцатиричная
         цифра
          і         ЪДДДДДДДДДДДї
          АДДДДДДДД>і   цифра   іДДДДДДДДДДДДДДДДДДДДДДДДДї
              і     АДДДДДДДДДДДЩ                         і
              і                                           і
              АДДДВДДДДДДДДДВДДДДДДДДДВДДДДДДДДДї         і
                  і         і         і         і         і
                  v         v         v         v         і
                ЪДДДї     ЪДДДї     ЪДДДї     ЪДДДї       і
                і A і ..  і F і     і a і ... і f і       і
                АДВДЩ     АДВДЩ     АДВДЩ     АДВДЩ       і
                  і         і         і         і         і
                  АДДДДДДДДДБДДДДДДДДДБДДДДДДДДДБДДДДДДДДДБДДДДДДДДД>

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

            +  -  *  /  =  <  >  [  ]  .  ,  (  )  :  ;  ^  @  {  }  $  #

             Следующие пары символов также представляют собой специальные
        символы:

                        <=  >=  :=  ..  (*  *)  (.  .)

             Кроме того,  некоторые  специальные символы являются знаками
        операций. Левая квадратная скобка ([) эквивалентна паре символов,
        состоящей из левой круглой скобки и точки ((.). Аналогично правая
        квадратная скобка (]) эквивалентна паре  символов,  состоящей  из
        точки и правой круглой скобки (.)).



         B.Pascal 7 & Objects/LR      - 24 -

                             Зарезервированные слова
                     и стандартные директивы Borland Pascal
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

            Следующие слова являются зарезервированными в Borland Pascal:

                     Зарезервированные слова Borland Pascal   Таблица 1.1
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
            and              exports             mod            shr
            array            file                nil            string
            asm              for                 not            then
            begin            function            object         to
            case             goto                of             type
            const            if                  or             unit
            consatructor     implementation      packed         until
            destructor       in                  procedure      uses
            div              inherited           program        var
            do               inline              record         while
            downto           interface           repeat         with
            else             label               set            xor
            end              library             shl
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Далее приведены стандартные директивы Borland Pascal.  В от-
        личие от зарезервированных слов пользователь может их переопреде-
        лить. Однако делать это не рекомендуется.

                       Стандартные директивы Borland Pascal   Таблица 1.2
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                    absolute       far            name        resident
                    assembler      forward        near        virtual
                    export         index          private
                    external       interrupt      public
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД



         B.Pascal 7 & Objects/LR      - 25 -

                                 Идентификаторы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Идентификаторы выступают в качестве  имен  констант,  типов,
        переменных, процедур, модулей, программ и полей в записях.

             Идентификатор может иметь любую длину,  однако только первые
        его 63 символа являются значимыми. Идентификатор должен начинать-
        ся  с буквы и не может содержать пробелов.  После первого символа
        идентификатора можно использовать буквы,  цифры и символы подчер-
        кивания (значение ASCII $5F). Как и в зарезервированных словах, в
        идентификаторах можно использовать как строчные,  так и прописные
        буквы (компилятор их не различает).

             Идентификатор должен  начинаться  с буквы и не должен содер-
        жать пробелов.  После первого символа допускаются буквы,  цифры и
        символ подчеркивания (ASCII $5F).  Как и зарезервированные слова,
        идентификаторы безразличны к регистру клавиатуры.

             Когда имеется несколько мест с указанием одного  и  того  же
        идентификатора,  для  задания  нужного  идентификатора необходимо
        уточнить этот идентификатор с помощью идентификатора модуля. Нап-
        ример, для уточнения идентификатора Ident с помощью идентификато-
        ра модуля UnitName следует записать UnitNamt.Ident.  Такой комби-
        нированный идентификатор называется уточненным идентификатором.

                   Примечание: Модули описываются в Главе 7  "Руководства
              пользователя" и в Главе 10 данного руководства.

                              ЪДДДДДДДДДДДї
         Идентификатор ДДВДДД>і   буква   іДДДДДДДДДДДДДДДДДДДДДДДДДВД>
                         і    АДДДДДДДДДДДЩ ^ ^                     і
                         і  ЪДДДДДДДДДДДДДї і і                     і
                         АД>і   символ    ГДЩ і   ЪДДДДДДДДДДДДДї   і
                            іподчеркиванияі   ГДДДґ    буква    і<ДДґ
                            АДДДДДДДДДДДДДЩ   і   АДДДДДДДДДДДДДЩ   і
                                              і   ЪДДДДДДДДДДДДДї   і
                                              ГДДДґ    цифра    і<ДДґ
                                              і   АДДДДДДДДДДДДДЩ   і
                                              і   ЪДДДДДДДДДДДДДї   і
                                              АДДДґ   символ    і<ДДЩ
                                                  іподчеркиванияі
                                                  АДДДДДДДДДДДДДЩ


         B.Pascal 7 & Objects/LR      - 26 -


                                   ЪДДДї
         символ подчеркиванияДДДДД>і _ іДДДДД>
                                   АДДДЩ

         идентификатор программы        ЪДДДДДДДДДДДДДї
         идентификатор модуля     ДДДДД>іидентификаторіДДДД>
         идентификатор поля             АДДДДДДДДДДДДДЩ

                                                   ЪДДДДДДДДДДДДДДДї
         уточненный  ДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДґ идентификатор ГДД>
         идентификатор і                         ^ АДДДДДДДДДДДДДДДЩ
                       і  ЪДДДДДДДДДДДДДї  ЪДДДї і
                       АД>іидентификаторГД>і . ГДЩ
                          і  модуля     і  АДДДЩ
                          АДДДДДДДДДДДДДЩ

             Приведем несколько примеров идентификаторов:

             Writeln
             Exit
             Real2String
             System.MemAvail
             Dos.Exec
             WinCrt.Windows



         B.Pascal 7 & Objects/LR      - 27 -

                                      Числа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Для чисел,  представляющих собой константы целого и  вещест-
        венного типа, используется обычная десятичная запись. Целая конс-
        танта в шестнадцатиричном формате имеет в качестве  префикса знак
        доллара ($).  Техническое обозначение (E или е с показателем сте-
        пени) в вещественных типах читается,  как "на десять в  степени".
        Например, 7E-2  означает  7х10^-2, а  12.25E+6  или  12.25E6  оба
        обозначают 12.25х10^+6. Синтаксические диаграммы для записи чисел
        приведены ниже.

                                         ЪДДДДДДДДДДДДДДДДДї
             последовательность ДДДДДДДД>ішестнадцатиричнаяГДДДДДДДВДД>
             шестнадцатиричных     ^     і     цифра       і       і
             цифр                  і     АДДДДДДДДДДДДДДДДДЩ       і
                                   АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                                         ЪДДДДДДДДДДДДДДДДДї
             последовательность ДДДДДДДД>і     цифра       ГДДДДДДДВДДД>
             цифр                  ^     АДДДДДДДДДДДДДДДДДЩ       і
                                   і                               і
                                   АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                                        ЪДДДДДДДДДДДДДДДДДДї
             целые без знака  ДДДДВДДДД>іпоследовательностьГДДДДДДДДДДД>
                                  і     і     цифр         і     ^
                                  і     АДДДДДДДДДДДДДДДДДДЩ     і
                                  і                              і
                                  і     ЪДДДї     ЪДДДДДДДДДДДДДДБДДДї
                                  АДДДД>і $ іДДДД>іпоследовательностьі
                                        АДДДЩ     ішестнадцатиричных і
                                                  і       цифр       і
                                                  АДДДДДДДДДДДДДДДДДДЩ
                         ЪДДДї
             знак  ДВДДД>і + ГДДДДДДД>
                    і    АДДДЩ   ^
                    і    ЪДДДї   і
                    АДДД>і - ГДДДЩ
                         АДДДЩ


         B.Pascal 7 & Objects/LR      - 28 -


             вещественное без знака
              і   ЪДДДДДДДДДДї    ЪДДДї  ЪДДДДДДДДДДї
              АДД>іПоследова-ГДВД>і . ГД>іпоследова-ГДДВДДДДДДДДДДДДДДДДДД>
                  ітельность і і  АДДДЩ  ітельность і  і               ^
                  і цифр     і і         і цифр     і  і               і
                  АДДДДДДДДДДЩ і         АДДДДДДДДДДЩ  і               і
                               і                       v  ЪДДДДДДДДДДї і
                               АДДДДДДДДДДДДДДДДДДДДДДДДД>імасштабныйГДЩ
                                                          і множительі
                                                          АДДДДДДДДДДЩ

            масштабный множитель
              і          ЪДДДї                   ЪДДДДДДДДДДДДДДДДДДї
              АДДДДДДДВД>і E ГДДДДДВДДДДДДДДДДДД>іпоследовательностьГДД>
                      і  АДДДЩ ^   і          ^  і      цифр        і
                      і  ЪДДДї і   і  ЪДДДДї  і  АДДДДДДДДДДДДДДДДДДЩ
                      АД>і е ГДЩ   АД>ізнакГДДЩ
                         АДДДЩ        АДДДДЩ

            число без знака
              і              ЪДДДДДДДДДДДДДДДї
              АДДДДДДДДДДДВД>іцелое без знакаГДДДДДДДД>
                          і  АДДДДДДДДДДДДДДДЩ    ^
                          і  ЪДДДДДДДДДДДДї       і
                          АД>івещественноеГДДДДДДДЩ
                             ібез знака   і
                             АДДДДДДДДДДДДЩ

            число со знаком
              і                          ЪДДДДДДДДДДДДДДДї
              АДДДДДДДДВДДДДДДДДДДДДДДДД>ічисло без знакаГДДДД>
                       і             ^   АДДДДДДДДДДДДДДДЩ
                       і  ЪДДДДї     і
                       АД>ізнакГДДДДДЩ
                          АДДДДЩ

             Числа с  десятичными точками или показателями степени предс-
        тавляют собой константы вещественного типа.  Остальные десятичные
        числа обозначают константы целого типа. Они должны принимать зна-
        чения в диапазоне от -2147483648 до 2147483647.

             Шестнадцатиричные числа обозначают  константы целочисленного
        типа.   Они   должны  находиться  в  диапазоне  от  $00000000  до
        $FFFFFFFF.  Окончательный знак значения определяется шестнадцати-
        ричной записью.



         B.Pascal 7 & Objects/LR      - 29 -

                                      Метки
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Меткой является  последовательность цифр в диапазоне от 0 до
        9999.  Начальные нули не являются значащими. Метки используются с
        операторами перехода goto.

                                    ЪДДДДДДДДДДДДДДДДДДДДДДї
             Метка ДДДДДДДВДДДДДДДД>і  последовательность  ГДДДДДДДДДД>
                          і         і       цифр           і      ^
                          і         АДДДДДДДДДДДДДДДДДДДДДДЩ      і
                          і                                       і
                          і            ЪДДДДДДДДДДДДДї            і
                          АДДДДДДДДДДД>іидентификаторГДДДДДДДДДДДДЩ
                                       АДДДДДДДДДДДДДЩ

             Как расширение стандартного Паскаля, Borland Pascal позволя-
        ет использовать в качестве меток идентификаторы функций.


                                 Строки символов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Строка символов представляет собой  последовательность,  со-
        держащую  ноль  и  более символов из расширенного набора символов
        кода ASCII,  записанную в одной строке программы и заключенную  в
        одиночные кавычки (апострофы).  Строка символов, ничего не содер-
        жащая между апострофами, называется нулевой строкой. Два последо-
        вательных  апострофа  в  строке символов обозначают один символ -
        апостроф. Атрибут длины строки символов выражается действительным
        количеством символов между апострофами, например:

             'Borland'
             'You'll see'
             ''''
             ';'
             ' '
             ''                                   { пустая строка }
             ' '                                  { пробел }

             В качестве  расширения стандартного Паскаля,  Borland Pascal
        разрешает вставлять в строку символов управляющие символы. Символ
        # с целой константой без знака в диапазоне от 0 до 255 обозначает
        соответствующий этому значению символ в коде ASCII.  Между симво-
        лом  #  и  целой  константой не должно быть никаких разделителей.
        Аналогично,  если несколько управляющих  символов  входит  строку
        символов, то между ними не должно быть разделителей.

             Приведем несколько примеров строк символов:

              #13#10
             'Line 1'#13'Line2'
             #7#7'Make up!'#7#7

         B.Pascal 7 & Objects/LR      - 30 -


                                      ЪДДДДДДДДДДДДДДДДДДДДДДї
              строка символов ДДДДВДД>і строка в кавычках    ГДДДВДВ>
                                ^ і   АДДДДДДДДДДДДДДДДДДДДДДЩ   і і
                                і і   ЪДДДДДДДДДДДДДДДДДДДДДДї   і і
                                і АДД>і управляющая строка   ГДДДЩ і
                                і     АДДДДДДДДДДДДДДДДДДДДДДЩ     і
                                АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                                 ЪДДДї                    ЪДДДї
                 строка   ДДДДДД>і ' ГДДДДДДДДДДДДДДВДДДД>і ' ГДДДД>
                 в кавычках      АДДДЩ ^  ЪДДДДДДї  і     АДДДЩ
                                       АДДґсимволі<ДЩ
                                          істрокиі
                                          АДДДДДДЩ

                                      ЪДДДДДДДДДДДДДДДДДДДДДДї
                 символ строки ДДДВДД>ілюбой символ, кроме ' ГДДДДДДД>
                                  і   і или CR               і   ^
                                  і   АДДДДДДДДДДДДДДДДДДДДДДЩ   і
                                  і        ЪДДДї       ЪДДДї     і
                                  АДДДДДДД>і ' ГДДДДДД>і ' ГДДДДДЩ
                                           АДДДЩ       АДДДЩ

                                      ЪДДДї  ЪДДДДДДДДДДДДДДДДДДДї
                 символ строки ДДДДДД>і # ГД>і беззнаковое целое ГДВДД>
                                ^     АДДДЩ  АДДДДДДДДДДДДДДДДДДДЩ і
                                і                                  і
                                АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                   Примечание: CR - символ возврата каретки.

             Длина символьной  строки  - это фактическое число символов в
        строке.  Строка символов любой длины совместима с любым строковым
        типом и, при разрешении директивой {$X+} расширенного синтаксиса,
        с типом PChar..  Кроме того,  строка символов с длиной, равной 1,
        совместима  с любым типом Char.  Строка символов длиной n,  где n
        больше или равен 1, допустима для любого строкового типа и упако-
        ванных массивов из n символов.


         B.Pascal 7 & Objects/LR      - 31 -


                                  Комментарии
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Следующие конструкции  представляют собой комментарии и поэ-
        тому игнорируются компилятором:

             { любой текст, не содержащий правую фигурную скобку }
             (* любой текст, не содержащий звездочку/правую круглую
                скобку *)

             Комментарий, содержащий знак доллара ($) сразу после  откры-
        вающей скобки { или (*,  является директивой компилятора. За сим-
        волом $ следует мнемоника команды компилятора.

                   Примечание: Общее описание директив компилятора дано в
              Главе 2 "Справочного руководства программиста".


                                Строки программы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В Borland Pascal строки программы имеют максимальную длину в
        126 символов.



         B.Pascal 7 & Objects/LR      - 32 -

                               Глава 3. Константы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Константа - это идентификатор,  отмечающий значение, которое
        не может изменяться.  Идентификатор константы не может быть вклю-
        чен в свое собственное описание.

             описание константы
              і      ЪДДДДДДДДДДДДДї    ЪДДДї   ЪДДДДДДДДДї    ЪДДДї
              АДДДДД>іидентификаторГДДД>і = ГДД>іконстантаГДДД>і ; ГДВДД>
                ^    АДДДДДДДДДДДДДЩ    АДДДЩ   АДДДДДДДДДЩ    АДДДЩ і
                і                                                    і
                АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Идентификатор константы  с предшествующим ему знаком обозна-
        чает значение целого или вещественного типа.

             Являясь расширением  стандартного  Паскаля,  Borland  Pascal
        позволяет  использовать выражения-константы.  Выражение-константа
        представляет собой выражение,  которое может вычисляться компиля-
        тором  без  необходимости выполнения программы.  Приведем примеры
        выражений-констант:

              100
              'A'
              256 - 1
              (2.5 + 1) / (2.5 - 1)
              'Borland' + '' + 'Pascal'
              Chr(32)
              Ord('Z') - Ord('A') + 1

             Простейший случай  выражения-константы  представляет   собой
        простая  константа,  например 100 или 'A'.  В стандартном Паскале
        допускается использовать  только  простые  константы.  В  Borland
        Pascal разрешено использование выражений-констант.

                             ЪДДДДДДДДДї
              константа ДДДД>івыражениеГДДД>
                             АДДДДДДДДДЩ

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

             - ссылки  на  переменные  и  типизированные константы (кроме
               констант в адресных выражениях, описываемых в Главе 5);

             - вызовы функций (кроме тех, которые отмечены далее);

             - оператор получения адреса @ (кроме констант в адресных вы-
               ражениях, описываемых в Главе 5).

             За исключением  этих ограничений для выражений-констант соб-

         B.Pascal 7 & Objects/LR      - 33 -

        людаются те же синтаксические правила,  что и для обычных выраже-
        ний (описанных в Главе 6 "Выражения").

             В выражениях-константах  допускается  использовать следующие
        стандартные функции:

             Abs, Chr,  Hi,  High,  Length, Lo, Low, Odd, Ord, Pred, Ptr,
             Round, SizeOf, Succ, Swap, Trunc.

             Приведем некоторые  примеры использования выражений-констант
        в описаниях констант:

             const
                 Min = 0;
                 Max = 100;
                 Center = (Max - Min) div 2;
                 Beta = Chr(255);
                 NumChars = Ord('Z') - Ord('A') + 1;
                 Message = 'Out of memory';
                 ErrStr = 'Error:' + Message + '.';
                 ErrPos = 80 - Length(Error) div 2;
                 ErrAttr = Blink + Red * 16 + White;
                 Ln10 = 2.302585092994095684;
                 Ln10R = 1 / Ln10;
                 Numeric = ['0'..'9'];
                 Alpha = ['A'..'Z','a'..'z'];
                 AlphaNum = Alpha + Numeric;



         B.Pascal 7 & Objects/LR      - 34 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                                  Глава 4. Типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             При описании переменной необходимо указать ее тип. Тип пере-
        менной описывает набор значений,  которые она может принимать,  и
        действия, которые могут быть над ней выполнены. Описание типа оп-
        ределяет идентификатор, который обозначает этот тип.

                        ЪДДДДДДДДДДДДДДДї   ЪДДДї   ЪДДДДДї   ЪДДДї
            описание ДД>і идентификатор ГДД>і = ГДД>і тип ГДД>і ; ГДД>
              типа      АДДДДДДДДДДДДДДДЩ   АДДДЩ   АДДДДДЩ   АДДДЩ

             Указание идентификатора  в левой части описания типа означа-
        ет,  что он определен как идентификатор типа для блока, в котором
        указано  это описание типа.  Область действия идентификатора типа
        не включает его самого,  исключение составляют  типы  "указатель"
        (которые называют также ссылочными типами).

                                ЪДДДДДДДДДДДДДДДДДДДДї
            тип   ДДДДДДДДВДДДД>і     простой тип    іДДДДДДДДД>
                          і     АДДДДДДДДДДДДДДДДДДДДЩ    ^
                          і     ЪДДДДДДДДДДДДДДДДДДДДї    і
                          ГДДДД>і   строковый тип    ГДДДДґ
                          і     АДДДДДДДДДДДДДДДДДДДДЩ    і
                          і     ЪДДДДДДДДДДДДДДДДДДДДї    і
                          ГДДДД>і   ссылочный тип    ГДДДДґ
                          і     АДДДДДДДДДДДДДДДДДДДДЩ    і
                          і     ЪДДДДДДДДДДДДДДДДДДДДї    і
                          ГДДДД>і   структурный тип  ГДДДДґ
                          і     АДДДДДДДДДДДДДДДДДДДДЩ    і
                          і     ЪДДДДДДДДДДДДДДДДДДДДї    і
                          ГДДДД>і   процедурный тип  ГДДДДґ
                          і     АДДДДДДДДДДДДДДДДДДДДЩ    і
                          і     ЪДДДДДДДДДДДДДДДДДДДДї    і
                          АДДДД>і идентификатор типа ГДДДДЩ
                                АДДДДДДДДДДДДДДДДДДДДЩ

             Имеется пять следующих основных классов типов.  Они описыва-
        ются в следующем разделе.



         B.Pascal 7 & Objects/LR      - 35 -

                                  Простые типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Простые типы определяют упорядоченные множества значений.

                                     ЪДДДДДДДДДДДДДДДДДДДї
              простой тип ДДДДДВДДДД>і  порядковый тип   ГДДДДДДДДД>
                               і     АДДДДДДДДДДДДДДДДДДДЩ     ^
                               і     ЪДДДДДДДДДДДДДДДДДДДї     і
                               АДДДД>і вещественный тип  ГДДДДДЩ
                                     АДДДДДДДДДДДДДДДДДДДЩ
                                     ЪДДДДДДДДДДДДДДДДДДДДї
              вещественный тип ДДДДД>і   идентификатор    ГДДДДД>
                                     і вещественного типа і
                                     АДДДДДДДДДДДДДДДДДДДДЩ

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

                   Примечание: В разделах "Числа" и "Строковые константы"
              Главы 2 вы можете найти описание того, как обозначать конс-
              танты целого и вещественного типов.

                                 Порядковые типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Порядковые типы  представляют собой подмножество простых ти-
        пов.  Все простые типы,  отличные от вещественных типов, являются
        порядковыми и выделяются по следующим четырем характеристикам.

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

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

             -  К  любому значению порядкового типа можно применить стан-
                дартную функцию Pred,  возвращающую  предшествующее этому
                значению значение. Если эта функция применяется к первому

         B.Pascal 7 & Objects/LR      - 36 -

                значению в этом порядковом типе, то выдается сообщение об
                ошибке.

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

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

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

             Синтаксис порядкового типа имеет следующий вид:

                                    ЪДДДДДДДДДДДДДДДДДДДДї
             порядковый  ДДДДДВДДДД>і   отрезок типа     ГДДДДДДДДД>
               тип            і     АДДДДДДДДДДДДДДДДДДДДЩ     ^
                              і     ЪДДДДДДДДДДДДДДДДДДДДї     і
                              ГДДДД>і  перечислимый тип  ГДДДДДґ
                              і     АДДДДДДДДДДДДДДДДДДДДЩ     і
                              і     ЪДДДДДДДДДДДДДДДДДДДДї     і
                              АДДДД>і   идентификатор    ГДДДДДЩ
                                    і порядкового типа   і
                                    АДДДДДДДДДДДДДДДДДДДДЩ

             Borland Pascal имеет 10 встроенных порядковых типов: Integer
        (целое), Shortint (короткое целое), Longint (длинное целое), Byte
        (длиной в байт),  Word (длиной  в  слово),  Boolean  (булевское),
        ByteBool (булевское размером в байт),  WordBool (булевское разме-
        ром в слово), LongBool (длинный булевский тип) и Char (символьный
        тип).  Кроме того, имеется два других класса определяемых пользо-
        вателем порядковых типов: перечислимые типы и отрезки типов (под-
        диапазоны).



         B.Pascal 7 & Objects/LR      - 37 -

                               Целочисленные типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В Borland Pascal имеется пять предопределенных целочисленных
        типов: Shortint (короткое целое), Integer (целое), Longint (длин-
        ное целое),  Byte (длиной в байт) и Word (длиной в слово). Каждый
        тип обозначает определенное подмножество целых чисел, как это по-
        казано в следующей таблице.

                       Предопределенные целочисленные типы    Таблица 4.1
        ЪДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДї
        і        Тип         і      Диапазон      і         Формат      і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДґ
        і   короткое целое   і    -128 .. 127     і   8 бит со знаком   і
        і   (Shortint)       і                    і                     і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДґ
        і   целое            і  -32768 .. 32767   і   16 бит со знаком  і
        і   (Integer)        і                    і                     і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДґ
        і   длинное целое    і  -2147483648 ..    і   32 бита со знаком і
        і   (Longint)        і       ..2147483647 і                     і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДґ
        і   длиной в байт    і       0 .. 255     і   8 бит  без знака  і
        і   (Byte)           і                    і                     і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДґ
        і   длиной в слово   і       0 .. 65535   і   16 бит без знака  і
        і   (Word)           і                    і                     і
        АДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДЩ

             Арифметические действия  над  операндами целочисленного типа
        предполагают 8-битовую,  16-битовую и 32-битовую точность в соот-
        ветствии со следующими правилами:

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

             - В  случае  бинарной  операции (операции,  использующей два
               операнда), оба операнда преобразуются к их общему типу пе-
               ред  тем,  как над ними совершается действие.  Общим типом
               является встроенный целочисленный тип с наименьшим  диапа-
               зоном, включающим все возможные значения обоих типов. Нап-
               ример, общим типом для целого и целого длиной в байт явля-
               ется  целое,  а  общим  типом для целого и целого длиной в
               слово является длинное целое. Действие выполняется в соот-
               ветствии  с точностью общего типа и типом результата явля-
               ется общий тип.

             - Выражение справа в операторе присваивания вычисляется  не-
               зависимо от размера или типа переменной слева.

             - Любые операнды размером в байт преобразуются к промежуточ-
               ному операнду размером в слово,  который  совместим  перед

         B.Pascal 7 & Objects/LR      - 38 -

               выполнением  арифметической  операции  с  типами Integer и
               Word.

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

                 Примечание: Приведение типов описывается в Главах 5 и 6.



         B.Pascal 7 & Objects/LR      - 39 -

                                 Булевские типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Существует 4  предопределенных  булевских   типа:   Boolean,
        ByteBool, WordBool и LongBool. Значения булевского типа обознача-
        ются встроенными идентификаторами констант False и True. Посколь-
        ку  булевский  тип является перечислимым,  между этими значениями
        имеют место следующие отношения:

             - False < True
             - Ord(False)  = 0
             - Ord(True)   = 1
             - Succ(False) = True
             - Pred(True)  = False

             Переменные типа Boolean и ByteBool  занимают 1 байт,   пере-
        менная WordBool занимает два байта (слово), а переменная LongBool
        занимает четыре байта (два слова). Boolean - это наиболее предпо-
        чтительный тип,   использующей   меньше  памяти;  типа  ByteBool,
        WordBool и LongBool обеспечивают совместимость с другими  языками
        и средой Windows.

             Предполагается, что переменная типа Boolean имеет порядковые
        значения 0 и 1,  но переменные типа ByteBool, WordBool и LongBool
        могут иметь  другие  порядковые  значения.  Когда  выражение типа
        ByteBool, WordBool или LongBool равна 1,  то подразумевается, что
        она имеет  значение  True,  а если оно равно 0 - то False.  Когда
        значение типа ByteBool, WordBool или LongBool используется в кон-
        тексте, где ожидается значение Boolean,  компилятор будет автома-
        тически генерировать код,  преобразующий любое ненулевое значение
        в значение True.



         B.Pascal 7 & Objects/LR      - 40 -

                              Символьный тип (char)
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Строковая константа  с  длиной  1  может обозначать значение
        константы символьного типа. Любое значение символьного типа может
        быть получено с помощью стандартной функции Chr.

                                Перечислимые типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                             ЪДДДї    ЪДДДДДДДДДДДДДДДї    ЪДДДї
             перечислимый ДД>і ( ГДДД>і   список      ГДДД>і ) ГДДД>
             тип             АДДДЩ    іидентификаторові    АДДДЩ
                                      АДДДДДДДДДДДДДДДЩ

             список                   ЪДДДДДДДДДДДДДї
             идентификаторов ДДДДДДДД>іидентификаторГДДДВДДДД>
                                ^     АДДДДДДДДДДДДДЩ   і
                                і      ЪДДДї            і
                                АДДДДДДґ , і<ДДДДДДДДДДДЩ
                                       АДДДЩ

             При указании идентификатора в списке  идентификаторов  пере-
        числимого типа он описывается как константа для блока,  в котором
        указано описание перечислимого типа. Типом этой константы являет-
        ся описанный перечислимый тип.

             Порядковый номер  перечислимой константы определяется ее по-
        зицией в списке идентификаторов при описании. Перечислимый тип, в
        котором описывается константа,  становится ее типом. Первая пере-
        числимая константа в списке имеет порядковый номер 0.

             Приведем пример перечислимого типа:

             type
                suit = (club, diamond, heart, spade);

             Согласно этим  описаниям  diamond  является  константой типа
        suit.

             При применении функции Ord к значению перечислимого типа Ord
        возвращает целое число, которое показывает, какое положение зани-
        мает это значение в отношении других значений этого перечислимого

         B.Pascal 7 & Objects/LR      - 41 -

        типа.  Согласно предшествующим описаниям, Ord(club) возвращает 0,
        Ord(diamond) возвращает 1 и так далее.

                                  Отрезки типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

         отрезок          ЪДДДДДДДДДДДї    ЪДДДДї    ЪДДДДДДДДДДДї
         типа ДДДДДДДДДДД>і константа ГДДД>і .. ГДДД>і константа ГДДД>
                          АДДДДДДДДДДДЩ    АДДДДЩ    АДДДДДДДДДДДЩ

             Обе константы должны иметь один и тот же порядковый тип. От-
        резки  типов,  имеющие вид a..b,  предполагают,  что a меньше или
        равно b.

             Приведем примеры отрезков типов:

             0..99
             -128..127
             club..heart

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

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

             const
                X = 50;
                Y = 10;
             type
                Color = (Red, Green, Blue);
                Scale = (X - Y) * 2..(X + Y) * 2;

             Согласно синтаксису стандартного Паскаля,  если  определение
        типа начинается с круглой скобки,  то это перечислимый тип (такой
        как Color в данном примере).  Однако Scale предназначен для опре-
        деления отрезка типа.  Решение состоит в том,  чтобы переупорядо-
        чить первое выражение поддиапазона или задать  другую  константу,
        равную значению данного выражения, и использовать эту константу в
        определении типа:

            type
                Scale = 2 * (X - Y)..(X + Y);



         B.Pascal 7 & Objects/LR      - 42 -

                                Вещественные типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             К вещественному типу относится подмножество вещественных чи-
        сел, которые могут быть представлены в формате с плавающей точкой
        с фиксированным числом цифр.  Запись значения в формате с плаваю-
        щей запятой обычно включает три значения - m, b и e - таким обра-
        зом,  что m x b^e=n, где b всегда равен 2, а m и e являются цело-
        численными  значениями  в  диапазоне  вещественного   типа.   Эти
        значения m и e далее определяют диапазон представления и точность
        вещественного типа.

             Имеется пять видов вещественных типов:  вещественное (Real),
        с одинарной точностью (Single),  с двойной точностью (Double),  с
        повышенной точностью (Extended) и сложное  (Comp).  Действия  над
        типами с одинарной точностью,  с двойной точностью и с повышенной
        точностью и над сложным типом могут выполняться только при  нали-
        чии числового сопроцессора 8087 (который был описан ранее).

             Вещественные типы различаются диапазоном и точностью связан-
        ных с ними значений (см. Таблицу 4.2).

                           Диапазон представления
                  и десятичные цифры для вещественных типов   Таблица 4.2
        ЪДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДї
        і        Тип            і        Диапазон           і   Цифры   і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДґ
        і вещественное          і2.9x10^-39 .. 1.7x10^38    іот 11 до 12і
        і (Real)                і                           і           і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДґ
        і с одинарной точностью і1.5x10^-45 .. 3.4x10^38    іот 7 до 8  і
        і (Single)              і                           і           і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДґ
        і с двойной точностью   і5.0x10^-324 .. 1.7x10^308  іот 15 до 16і
        і (Double)              і                           і           і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДґ
        і с повышенной точностьюі1.9x10^-4951 .. 1.1x10^4932іот 19 до 20і
        і (Extended)            і                           і           і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДґ
        і сложный тип           і   -2^63 + 1 .. 2^63 - 1   і           і
        і (Comp)                і                           і           і
        АДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДЩ

                   Примечание: Сложный тип содержит только  целочисленные
              значения  в  диапазоне от -2^63+1 до 2^63-1,  что приблизи-
              тельно равно -9.2x10^18 и 9.2x10^18.

             Borland Pascal поддерживает две модели  генерации  кода  для
        выполнения действий над вещественными типами: программную для чи-
        сел с плавающей точкой и аппаратную для чисел с плавающей точкой.
        Выбор  соответствующей  модели осуществляется с помощью директивы
        компилятора $N.


         B.Pascal 7 & Objects/LR      - 43 -

                 Программная поддержка чисел с плавающей точкой
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В состоянии {$N-}, которое устанавливается по умолчанию, ге-
        нерируемый код выполняет все вычисления  с  вещественными  типами
        программно, через вызов подпрограмм библиотеки исполняющей систе-
        мы.  Из-за соображений скорости и размера кода в  этом  состоянии
        допускаются только действия над переменными типа real (веществен-
        ное).  Любая попытка оттранслировать операторы, выполняющие дейс-
        твия над типами с одинарной точностью, с двойной точностью, с по-
        вышенной точностью и над сложными типами,  вызовет  сообщение  об
        ошибке.

                  Аппаратная поддержка чисел с плавающей точкой
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В состоянии {$N+} генерируемый  код выполняет все вычисления
        над вещественными типами с помощью числового  сопроцессора  8087.
        Это состояние позволяет использовать все пять вещественных типов,
        однако оно требует наличия сопроцессора 8087 на  этапе компиляции
        и выполнения.

             Borland Pascal включает в себя библиотеки исполняющей систе-
        мы, которые автоматически эмулируют программным путем сопроцессор
        80х87, если при выполнении прикладной программы DOS реального или
        защищенного режима он отсутствует.  Для определения того, следует
        ли в программу DOS включить эмулятор сопроцессора 80x87,  исполь-
        зуется директива компилятора $E. Если вы создает прикладную прог-
        рамму для  реального  или  защищенного режима DOS,  и сопроцессор
        80х87 отсутствует,  разрешение директивы компилятора $E обеспечи-
        вает полную программную эмуляцию сопроцессора 80x87. Для программ
        Windows директива $E не действует,  так как Windows  обеспечивает
        собственные подпрограммы эмуляции.

                   Примечание: Более  детальное  описание  генерации кода
              при аппаратной поддержке чисел с плавающей запятой вы може-
              те  найти  в  Главе  15  "Использование сопроцессора 8087 в
              Borland Pascal".



         B.Pascal 7 & Objects/LR      - 44 -

                                 Строковые типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Значением строкового типа является последовательность симво-
        лов с динамическим атрибутом длины (в зависимости от действитель-
        ного числа символов при выполнении программы) и постоянным  атри-
        бутом размера в диапазоне от 1 до 255.  Текущее значение атрибута
        длины можно получить с помощью стандартной функции Length.

                             ЪДДДДДДї
           строковый тип ДДД>іstringГДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД>
                             АДДДДДДЩ  і                          ^
                                       і  ЪДДДї   ЪДДДДДї   ЪДДДї і
                                       АД>і [ ГДД>іцелоеГДД>і ] ГДЩ
                                          АДДДЩ   і без і   АДДДЩ
                                                  ізнакаі
                                                  АДДДДДЩ

                   Примечание: Операторы работы со строковыми типами опи-
              сываются разделах  "Строковые операторы" и "Операторы отно-
              шений" Главы 6.

             Отношение между  любыми двумя строковыми значениями устанав-
        ливается согласно отношению порядка между значениями  символов  в
        соответствующих позициях. В двух строках разной длины каждый сим-
        вол более длинной строки без соответствующего символа в более ко-
        роткой строке принимает значение "больше"; например, 'Xs' больше,
        чем 'X'.  Нулевые строки могут быть равны только  другим  нулевым
        строкам, и они являются наименьшими строковыми значениями.

                   Примечание: Стандартные процедуры и функции для работы
              со строковыми типами описаны в разделе "Строковые процедуры
              и функции".

             К символам в строках можно обращаться как к элементам масси-
        ва. См. раздел "Массивы, строки и индексы" в Главе 5.

             К идентификатору  строкового  типа  и к ссылке на переменную
        строкового типа можно применять стандартные функции Low и High. В
        этом случае  функция Low возвращает 0,  а High возвращает атрибут
        размера (максимальную длину) данной строки.

             Параметр-переменная, описанная  с   помощью   идентификатора
        OpenString и  ключевого слова string в состоянии {$P+},  является
        открытым строковым параметром.  Открытые строковые параметры поз-
        воляют  передавать одной и той же процедуре или функции строковые
        переменные изменяющегося размера.

                   Примечание: Открытые строковые параметры описываются в
              Главе 9.



         B.Pascal 7 & Objects/LR      - 45 -

                                Структурные типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                                            ЪДДДДДДДДДДДДДДДї
         структурный ДДВДДДДДДДДДДДДДДДДВДД>і  тип массив   ГДДДДД>
             тип       і  ЪДДДДДДДДї ^  і   АДДДДДДДДДДДДДДДЩ  ^
                       АД>і packed ГДЩ  і   ЪДДДДДДДДДДДДДДДї  і
                          АДДДДДДДДЩ    ГДД>і множественный ГДДґ
                                        і   і     тип       і  і
                                        і   АДДДДДДДДДДДДДДДЩ  і
                                        і   ЪДДДДДДДДДДДДДДДї  і
                                        ГДД>і файловый тип  ГДДґ
                                        і   АДДДДДДДДДДДДДДДЩ  і
                                        і   ЪДДДДДДДДДДДДДДДї  і
                                        ГДД>і тип "запись"  ГДДґ
                                        і   АДДДДДДДДДДДДДДДЩ  і
                                        і   ЪДДДДДДДДДДДДДДДї  і
                                        АДД>і объектный тип ГДДЩ
                                            АДДДДДДДДДДДДДДДЩ

             Слово packed (упакованный) в описании структурного типа тре-
        бует  от  компилятора  уплотнить  хранимые  данные,  даже за счет
        уменьшения скорости доступа к компоненту в переменной этого типа.
        Слово packed  не  имеет никакого действия в Borland Pascal,  пос-
        кольку упаковка выполняется здесь автоматически  всюду,  где  это
        возможно.



         B.Pascal 7 & Objects/LR      - 46 -

                                   Типы массив
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Массивы содержат фиксированное число элементов одного  типа,
        так называемого типа элемента.  На приводимой ниже синтаксической
        диаграмме тип элемента следует за словом of.

                 ЪДДДДДДДї  ЪДДДї    ЪДДДДДДДї    ЪДДДї  ЪДДДДї  ЪДДДДДї
         тип  ДД>і array ГД>і [ ГДДД>і тип   ГДВД>і ] ГД>і of ГД>і тип Г>
         массив  АДДДДДДДЩ  АДДДЩ ^  іиндексаі і  АДДДЩ  АДДДДЩ  АДДДДДЩ
                                  і  АДДДДДДДЩ і
                                  і    ЪДДДї   і
                                  АДДДДґ , і<ДДЩ
                                       АДДДЩ

             тип         ЪДДДДДДДДДДДДДДДДї
             индекса ДДД>і порядковый тип ГДДД>
                         АДДДДДДДДДДДДДДДДЩ

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

             Приведем пример типа массив:

             array[1..100] of Real

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

             array[boolean] of array[1..100] of array[Size] of Real

        интерпретируется компилятором точно так же, как массив:

             array[boolean,1..10,Size] of Real

             Кроме того, можно записать выражение:

             packed array[1..10] of packed array[1..8] of Boolean
        как
             packed array[1..10,1..8] of Boolean

             Для доступа к элементам массива необходимо указать идентифи-
        катор  массива  с  одним или несколькими индексами в скобках (см.
        раздел "Массивы, строки и индексы").

             Тип массив, имеющий вид:


         B.Pascal 7 & Objects/LR      - 47 -

             packed array[M..N] of Char

        где M меньше N,  называется упакованным  строковым  типом  (слово
        packed  можно  опустить,  поскольку  оно  не оказывает действия в
        Borland Pascal). Упакованный строковый тип имеет некоторые свойс-
        тва, не характерные для других типов массив (см. раздел "Тождест-
        венные и совместимые типы" далее в этой главе).

             Массив вида:

             array[0..X] of Char

        где X - положительное целое число,  называется массивом с нулевой
        базой. Массивы  с нулевой базой используются для хранения строк с
        завершающим нулем, и, когда разрешен расширенный синтаксис (с по-
        мощью директивы  компилятора {$X+}),  символьный массив с нулевой
        базой совместим со значением типа PChar.  Полностью эта тема  об-
        суждается в Главе 18 "Использование строк с завершающим нулем".

             Параметр, описанный с помощью синтаксиса array of T, называ-
        ется открытым строковым параметром.  Открытые строковые параметры
        позволяют передавать одной и той же процедуре или функции строко-
        вые переменные изменяющегося размера.

                   Примечание: Открытые строковые параметры описываются в
              Главе 9.



         B.Pascal 7 & Objects/LR      - 48 -

                                   Типы запись
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                        ЪДДДДДДДДї                    ЪДДДДДї
         тип запись ДДД>і record ГДДВДДДДДДДДДДДДДДДД>і end ГДД>
                        АДДДДДДДДЩ  і  ЪДДДДДДДДї ^   АДДДДДЩ
                                    АД>і список ГДЩ
                                       і  полей і
                                       АДДДДДДДДЩ

         список  ЪДДДДДДДДДДДДї
         полейВД>і фиксирован-ГДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДД>
              і  і ная часть  і і  ЪДДДї    ЪДДДДДДДДДДДДї ^ і  ЪДДДї ^
              і  АДДДДДДДДДДДДЩ АД>і ; ГДДД>і вариантная ГДЩ АД>і ; ГДЩ
              і                    АДДДЩ ^  і   часть    і      АДДДЩ
              АДДДДДДДДДДДДДДДДДДДДДДДДДДЩ  АДДДДДДДДДДДДЩ

                           ЪДДДДДДДДДДДДДДДДДї   ЪДДДї    ЪДДДДДї
        фиксированная ДДДД>і     список      ГДД>і : ГДДД>і тип ГДДВДД>
        часть           ^  і идентификаторов і   АДДДЩ    АДДДДДЩ  і
                        і  АДДДДДДДДДДДДДДДДДЩ                     і
                        і                                          і
                        і            ЪДДДї                         і
                        АДДДДДДДДДДДДґ ; і<ДДДДДДДДДДДДДДДДДДДДДДДДЩ
                                     АДДДЩ

             Фиксированная часть типа запись содержит список  фиксирован-
        ных полей вместе с идентификатором и типом для каждого поля. Каж-
        дое поле содержит информацию, которая всегда отыскивается одним и
        тем же способом.

             Приведем пример типа запись:

             record
               year:  integer;          { год }
               month: 1..12;            { месяц }
               day:   1..31;            { число }
             end


         B.Pascal 7 & Objects/LR      - 49 -


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

         вариантная часть
         і  ЪДДДДї                      ЪДДДДДДДДї  ЪДДї     ЪДДДДДДДї
         АД>іcaseГДВДДДДДДДДДДДДДДДДДДД>ітип поляГД>іofГДДДД>івариантГДВ>
            АДДДДЩ і                 ^  іпризнакаі  АДДЩ ^   АДДДДДДДЩ і
                   і ЪДДДДДДДї ЪДДДї і  АДДДДДДДДЩ       і    ЪДДДї    і
                   А>іиденти-Г>і : ГДЩ                   АДДДДґ ; і<ДДДЩ
                     іфикаторі АДДДЩ                          АДДДЩ
                     АДДДДДДДЩ

                       ЪДДДДДДДДДДДДДДДДї
         тип поля ДДДД>і  идентификатор ГДДДД>
         признака      іпорядкового типаі
                       АДДДДДДДДДДДДДДДДЩ

                      ЪДДДДДДДДДї    ЪДДДї  ЪДДДї                ЪДДДї
         вариант ДДДД>іконстантаГДВД>і : ГД>і ( ГДВДДДДДДДДДДДДД>і ) ГДД>
                   ^  АДДДДДДДДДЩ і  АДДДЩ  АДДДЩ і           ^  АДДДЩ
                   і    ЪДДДї     і               і           і
                   АДДДДґ , і<ДДДДЩ               і  ЪДДДДДДї і
                        АДДДЩ                     АД>ісписокГДЩ
                                                     іполей і
                                                     АДДДДДДЩ

             Вы можете видеть на диаграмме,  что каждый вариант идентифи-
        цирован  по  крайней мере одной константой.  Все константы должны
        быть отличными друг от друга и иметь порядковый  тип, совместимый
        с типом поля признака.  Доступ к вариантным и фиксированным полям
        один и тот же.

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

             Ниже приводятся несколько примеров типов запись:

             record
               firstName,lastName : string[40];
               birthDate : Date;
               case citizen : boolean of
                 True  : (birthPlace: string[40]);
                 False : (country   : string[20];

         B.Pascal 7 & Objects/LR      - 50 -

                          entryPort : string[20];
                          entryDate : Date;
                          exitDate  : Date);
             end

             record
               x,y : real;
               case kind : Figure of
                 rectangle : (height,wigth: real);     { прямоугольник }
                 triangle : (size1,side2,angle: real); { треугольник }
                 circle : (radius: real);              { круг }
             end

                                 Объектные типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Объектный тип является структурой,  состоящей из фиксирован-
        ного числа компонентов. Каждый компонент является либо полем, со-
        держащим данные строго определенного типа, либо методом, выполня-
        ющим  операции над объектом.  По аналогии с описанием переменных,
        описание поля указывает тип данного этого поля  и  идентификатор,
        именующий  поле:  по  аналогии с описанием процедуры или функции,
        описание метода указывает заголовок процедуры, функции, конструк-
        тора или деструктора.

             Объектный тип может наследовать компоненты другого объектно-
        го типа.  Если T2 наследует от T1,  то T2 является потомком T1, а
        T1 является родителем T2.


         B.Pascal 7 & Objects/LR      - 51 -


             Наследование является транзитивным, то есть если T3 наследу-
        ет от T2,  а T2 наследует от T1,  то T3 наследует от T1.  Область
        (домен) объектного типа состоит из него самого и из всех его нас-
        ледников.

                       ЪДДДДДДї                      ЪДДДДДДДДДДДДДДДДї
         тип объектаДД>іobjectГДВДДДДДДДДДДДДДДДДДДД>ісписок компонентГДї
                       АДДДДДДЩ і  ЪДДДДДДДДДДДДї ^  АДДДДДДДДДДДДДДДДЩ і
                                АД>іHаследованиеГДЩ                     і
                                   АДДДДДДДДДДДДЩ                       і
                            ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
                            і                                      ЪДДДї
                            АДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДґendГ>
                              і   ЪДДДДДДДї   ЪДДДДДДДДДДДДДДДДї і АДДДЩ
                              АДД>іprivateГДД>ісписок компонентГДЩ
                                  АДДДДДДДЩ   АДДДДДДДДДДДДДДДДЩ

                         ЪДДДї  ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї  ЪДДДї
         наследование ДД>і ( ГД>іидентификатор объектного типаГД>і ) ГДД>
                         АДДДЩ  АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ  АДДДЩ

         список компонент ДДВДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДД>
                            і  ЪДДДДДДДДї  ^  і  ЪДДДДДДДДДї  ^
                            АД>і список ГДДЩ  АД>і список  ГДДЩ
                               і полей  і        і методов і
                               АДДДДДДДДЩ        АДДДДДДДДДЩ

                          ЪДДДДДДДДДДДДДДДДДДДДДДї  ЪДДДї  ЪДДДДї ЪДДДї
         список полей ДДД>іcписок идентификаторовГД>і : ГД>іtypeГ>і ; ГВ>
                       ^  АДДДДДДДДДДДДДДДДДДДДДДЩ  АДДДЩ  АДДДДЩ АДДДЩі
                       і                                               і
                       АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                           ЪДДДДДДДДДї                            ЪДДДї
         список методов ДД>ізаголовокГДВДДДДДДДДДДДДДДДДДДДДДДДДДДґ ; ГВД>
                        ^  і метода  і і ЪДДДї  ЪДДДДДДДї        ^АДДДЩі
                        і  АДДДДДДДДДЩ А>і ; ГД>іvirtualГВДДДДДДДЩ     і
                        і                АДДДЩ  АДДДДДДДЩі   ^         і
                        і                                і   АДДДДДДДДїі
                        і                                і ЪДДДДДДДДДїіі
                        і                                А>і  целая  ГЩі
                        і                                  іконстантаі і
                        і                                  АДДДДДДДДДЩ і
                        АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                                   ЪДДДДДДДДДДДДДДДДДДДДДДДДї
         заголовок метода ДДДДВДДД>і заголовок процедуры    ГДДДДДД>
                              і    АДДДДДДДДДДДДДДДДДДДДДДДДЩ  ^
                              і    ЪДДДДДДДДДДДДДДДДДДДДДДДДї  і
                              ГДДД>і заголовок функции      ГДДґ
                              і    АДДДДДДДДДДДДДДДДДДДДДДДДЩ  і
                              і    ЪДДДДДДДДДДДДДДДДДДДДДДДДї  і

         B.Pascal 7 & Objects/LR      - 52 -

                              ГДДД>і заголовок конструктора ГДДґ
                              і    АДДДДДДДДДДДДДДДДДДДДДДДДЩ  і
                              і    ЪДДДДДДДДДДДДДДДДДДДДДДДДї  і
                              АДДД>і заголовок деструктора  ГДДЩ
                                   АДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Следующий исходный  код  приводит пример описания объектного
        типа.  Далее во всей этой главе на данное описание будут делаться
        ссылки.

             type
               Point = object
               X, Y: integer;
             end;

             Rect = object
               A, B: TPoint;
               procedure Init(XA, YA, XB, YB: Integer);
               procedure Copy(var R: TRectangle);
               procedure Move(DX, DY: Integer);
               procedure Grow(DX, DY: Integer);
               procedure Intersect(var R: TRectangle);
               procedure Union(var R: TRectangle);
               function Contains(P: Point): Boolean;
             end;

             StringPtr = ^String;
             FieldPtr = ^TField;

             TField = object
               X, Y, Len: Integer;
               Name: StringPtr;
               constructor Copy(var F: TField);
               constructor Init(FX, FY, FLen: Integer; FName: String);
               destructor Done; virtual;
               procedure Display; virtual;
               procedure Edit; virtual;
               function GetStr: String; virtual;
               function PutStr(S: String): Boolean; virtual;
             end;

             StrFieldPtr = ^TStrField;

             StrField = object(TField)
               Value: PString;
               constructor Init(FX, FY, FLen: Integer; FName: String);
               destructor Done; virtual;
               function GetStr: String; virtual;
               function PutStr(S: String): Boolean;
               virtual;
               function Get: string;
               procedure Put(S: String);
             end;

         B.Pascal 7 & Objects/LR      - 53 -


             NumFieldPtr = ^TNumField;

             TNumField = object(TField)
             private
               Value, Min, Max: Longint;
             public
               constructor Init(FX, FY, FLen: Integer; FName: String;
                                FMin, FMax: Longint);
                function GetStr: String; virtual;
                function PutStr(S: String): Boolean; virtual;
                function Get: Longint;
                function Put(N: Longint);
             end;

             ZipFieldPtr = ^TZipField;

             ZipField = object(TNumField)
             function GetStr: String; virtual;
             function PutStr(S: String): Boolean;
             virtual;
             end;

             В отличие от других типов,  объектные типы могут описываться
        только  в  разделе  описаний типов,  находящемся на самом внешнем
        уровне области действия программы или модуля. Таким образом, объ-
        ектные  типы  не  могут описываться в разделе описаний переменных
        или внутри блока процедуры, функции или метода.

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



         B.Pascal 7 & Objects/LR      - 54 -

                          Компоненты и область действия
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Область действия идентификатора компоненты  простирается  за
        пределы объектного типа. Более того, область действия идентифика-
        тора компонента  простирается  сквозь  блоки  процедур,  функций,
        конструкторов и деструкторов, которые реализуют методы объектного
        типа и его наследников.  Исходя из  этих  соображений,  написание
        идентификатора компоненты должно быть уникальным внутри объектно-
        го типа и внутри всех его наследников,  а также внутри  всех  его
        методов.

             Область действия  идентификатора  компонента,  описанного  в
        части private описания типа, ограничивается модулем (программой),
        которая содержит описание объектного типа. Другими словами, част-
        ные (private) компоненты-идентификаторы  действуют,  как  обычные
        общедоступные  идентификаторы  в рамках модуля,  который содержит
        описание объектного типа, а вне модуля любые частные компоненты и
        идентификаторы  неизвестны  и недоступны.  Поместив в один модуль
        связанные типы объектов,  можно сделать так, что эти объекты смо-
        гут  обращаться  к частным компонентам друг друга,  и эти частные
        компоненты будут неизвестны другим модулям.

             В описании объектного типа заголовок метода  может  задавать
        параметры описываемого объектного типа, даже если описание еще не
        полное. Это иллюстрируется методами Copy,  Intersect и Union типа
        TRectange в предыдущем примере.

                                     Методы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Описание метода  внутри объектного типа соответствует опере-
        жающему описанию метода (forward). Таким образом, где-нибудь пос-
        ле описания объектного типа, но внутри той же самой области дейс-
        твия, что и область действия описания объектного типа, метод дол-
        жен реализоваться путем определения его описания.

             Если требуется уникальный идентификатор метода, то использу-
        ется уточненный идентификатор метода. Он состоит из идентификато-
        ра типа объекта, за которым следуют точка и идентификатор метода.
        Как и любому другому идентификатору,  идентификатору  уточненного
        метода, если требуется, могут предшествовать идентификатор пакета
        и точка.

         уточненный идентификатор метода
         і  ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї ЪДДДї ЪДДДДДДДДДДДДДДДДДДДДї
         АД>іидентификатор объектного типаГ>і . Г>іидентификатор методаГ>
            АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ АДДДЩ АДДДДДДДДДДДДДДДДДДДДЩ

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

             По умолчанию,  методы являются статическими,  однако они мо-

         B.Pascal 7 & Objects/LR      - 55 -

        гут, за исключением конструкторов, быть виртуальными (посредством
        включения директивы virtual в описание метода). Компилятор разре-
        шает ссылки на вызовы статических методов во время процесса  ком-
        пиляции, тогда как вызовы виртуальных методов разрешаются во вре-
        мя выполнения. Это иногда называют поздним связыванием.

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

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

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



         B.Pascal 7 & Objects/LR      - 56 -

                               Динамические методы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Borland Pascal поддерживает дополнительные методы с  поздним
        связыванием, которые  называются динамическими методами.  Динами-
        ческие методы отличаются от виртуальных только характером их дис-
        петчеризации на этапе выполнения. Во всех других отношениях дина-
        мические методы считаются эквивалентными виртуальным.

             Описание динамического метода эквивалентно  описанию  вирту-
        ального метода,  но описание динамического метода должно включать
        в себя индекс динамического метода,  который  указывается  непос-
        редственно за ключевым словом virtual. Индекс динамического мето-
        да  должен  быть  целочисленной  константой  в  диапазоне от 1 до
        656535 и должен быть уникальным среди индексов других  динамичес-
        ких методов,  содержащихся в объектном типе или его предках. Нап-
        ример:

             procedure FileOpen(var Msg: TMessage); virtual 100;

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

                   Примечание: Подробнее о динамических методах и о  раз-
              нице  в  диспетчеризации динамических и виртуальных методов
              рассказывается в Главе 22.



         B.Pascal 7 & Objects/LR      - 57 -

                          Создание экземпляров объектов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Экземпляр объекта  создается посредством описание переменной
        или константы  объектного  типа  или путем применения стандартной
        процедуры New к переменной типа указатель на объектный  тип.  Ре-
        зультирующий объект называется экземпляром объектного типа.

             var
             F: TField;
             Z: TZipField;
             FP: PField;
             ZP: PZipField;

             С учетом этих описание  переменных  F  является  экземпляром
        TField, а Z - экземпляром TZipField. Аналогично, после применения
        New к FP и ZP,  FP будет указывать на экземпляр TField, а ZP - на
        экземпляр TZipField.

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

             var
               S: StrField;
             begin
               S.Init (1, 1, 25, 'Первое имя');
               S.Put ('Френк');
               S.Display;
               ...
               S.Done;
             end;

             Если S.Init не вызывался, то вызов S.Display приведет к неу-
        дачному завершению данного примера.

             Присваивание экземпляра  объектного  типа  не  подразумевает
        инициализации экземпляра.

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

             Если экземпляр объекта не инициализируется,  и проверка диа-
        пазона включена (директивой {$R+}),  то первый вызов виртуального
        метода экземпляра объекта дает ошибку этапа выполнения. Если про-
        верка диапазона выключена (директивой {$R-}), то первый виртуаль-
        ного метода неинициализированного объекта может привести  к  неп-
        редсказуемому поведению.

             Правило обязательной инициализации применимо также к экземп-

         B.Pascal 7 & Objects/LR      - 58 -

        лярам, которые являются компонентами структурных типов. Например:

             var
                Comment: array [1..5] of TStrField;
                I: integer;
             begin
                for I := 1 to 5 do
                Comment [I].Init (1, I + 10, 40, 'первое_имя');
                   .
                   .
                   .
                for I := 1 to 5 do Comment [I].Done;
             end;

             Для динамических  экземпляров  инициализация,  как  правило,
        связана с размещением,  а очистка - с удалением,  что достигается
        благодаря расширенному  синтаксису  стандартных  процедур  New  и
        Dispose. Например:

             var
               SP: StrFieldPtr;
             begin
               New (SP, Init (1, 1, 25, 'первое_имя');
               SP^.Put ('Френк');
               SP^.Display;
                   .
                   .
                   .
               Dispose (SP, Done);
             end;

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

             Например, указатель  типа  ZipFieldPtr  может  присваиваться
        указателям типа PZipField,  PNumField и PField, а во время выпол-
        нения программы указатель типа PField может либо  иметь  значение
        nil, либо указывать на экземпляр TField, TNumField или TZipField,
        или на любой экземпляр дочернего по отношению к TField типа.

             Эти правила совместимости указателей по присваиванию  приме-
        нимы также к параметрам-переменным объектного типа. Например, ме-
        тоду TField.Copy  могут  быть  переданы  экземпляры типов TField,
        TStrField,  TNumField,  TZipField или любые другие экземпляры до-
        чернего от TField типа.



         B.Pascal 7 & Objects/LR      - 59 -

                               Активизация методов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Метод активизируется посредством оператора вызова  процедуры
        или функции, состоящего из десигнатора метода, за которым следует
        список параметров. Такой тип вызова называется активизацией мето-
        да.

         десигнатор метода
         і                                         ЪДДДДДДДДДДДДДДДДДДДДї
         АДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД>іидентификатор методаГ>
           і                                   ^   АДДДДДДДДДДДДДДДДДДДДЩ
           і ЪДДДДДДДДДДДДДДДДДДДДДДї ЪДДДї    і
           А>і ссылка на переменную Г>і . ГДДДДЩ
             АДДДДДДДДДДДДДДДДДДДДДДЩ АДДДЩ

             Ссылка на переменную задается, если десигнатор метода должен
        описывать экземпляр объектного типа,  а идентификатор метода дол-
        жен обозначать метод этого объектного типа.

             Экземпляр, обозначенный десигнатором метода,  становится не-
        явным фактическим параметром метода; он соответствует формальному
        параметру-переменной с именем Self, который владеет объектным ти-
        пом, соответствующим активизированному методу.

             Для статических  методов описанный тип (на этапе компиляции)
        определяет, какой из методов активизируется. Например, десигнато-
        ры F.Init и FP^.Init всегда  активизируют  TField.Init,  так  как
        описанным типом F и FP^ является TField.

             Для виртуальных методов выбором экземпляра управляет  факти-
        ческий тип (этапа выполнения).  Например,  десигнатор FP^.Display
        может активизировать  методы  TField.Display,  TStrField.Display,
        TNumField.Display или TZipField.Display (в зависимости от  факти-
        ческого типа экземпляра, указываемого FP).

             В операторе with,  ссылающемся на экземпляр объектного типа,
        ссылка на  переменную  в  десигнаторе метода может опускаться.  В
        этом случае экземпляром, на который ссылается оператор with, ста-
        новится неявный  параметр  Self  активизации метода.  Аналогично,
        ссылка не переменную может опускаться в  методе.  В  этом  случае
        параметром Self метода, содержащего вызов, становится неявный па-
        раметр Self активизации метода.



         B.Pascal 7 & Objects/LR      - 60 -

                         Активизация уточненных методов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

         десигнатор уточненного метода
         і   ЪДДДДДДДДДДДДДДДДДДДДДДї ЪДДДї        ЪДДДДДДДДДДДДДДДДДДДДї
         АДВ>і    идентификатор     Г>і . ГДДДДДДД>іидентификатор методаГ>
           і і   объектного типа    і АДДДЩ    ^   АДДДДДДДДДДДДДДДДДДДДЩ
           і АДДДДДДДДДДДДДДДДДДДДДДЩ          і
           і ЪДДДДДДДДДДДДДДДДДДДДДДї          і
           А>і      inherited       ГДДДДДДДДДДЩ
             АДДДДДДДДДДДДДДДДДДДДДДЩ

             Объектный тип,  заданный  в  десигнаторе уточненного метода,
        должен быть таким же,  как и включающий метод объектный тип,  или
        соответствовать родительскому типу.

             Для обозначения родительского объектного типа или объектного
        типа, включающего   метод,   можно  использовать  ключевое  слово
        inherited;  в методах объектного типа, не имеющего предка, ключе-
        вое слово inherited использоваться не может.

             Неявный параметр Self активизации уточненного метода  стано-
        вится параметром  Self  метода,  содержащего  вызов.  Активизация
        уточненных методов  не  предусматривает механизма диспетчеризации
        виртуальных методов - вызов будет всегда статическим и всегда вы-
        зывает заданный метод.

             Активизация уточненного метода используется обычно в переоп-
        ределяющем методе  для  активизации  переопределяющего метода.  С
        учетом описанных выше типов приведем некоторые примеры  активиза-
        ции уточненных методов:

             constructor TNumField.Init(Fx, FY, Flen: Integer;
               FName: String; FMin, FMax: Longint);
             begin
               inherited Init(FX, FY, FLen, FName);
               Value := 0;
               Min := FMin;
               Max := FMax;
             end;

             function TZipField.PutStr(S: String): Boolean;
             begin
               PutStr := (Length(S) = 5) and TNumField.PutStr(S);
             end;

             Как показывают  эти примеры,  активизация уточненных методов
        позволяет переопределяющему методу "вновь использовать" код мето-

         B.Pascal 7 & Objects/LR      - 61 -

        да, который он переопределяет.


                               Множественные типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Диапазон значений  множественного  типа  представляет  собой
        мощность  множества  для определенного порядкового типа (базового
        типа).  Каждое возможное значение  множественного  типа  является
        подмножеством возможных значений базового типа.

             Переменная множественного  типа может принимать как все зна-
        чения множества, так и ни одного.

                              ЪДДДДДї    ЪДДДДї    ЪДДДДДДДДДДДДДДДДї
            тип множество ДДД>і set ГДДД>і of ГДДД>і порядковый тип ГДДД>
                              АДДДДДЩ    АДДДДЩ    АДДДДДДДДДДДДДДДДЩ

             Базовый тип не должен иметь более 256 возможных  значений, и
        порядковые значения верхней и нижней границы базового типа должны
        не превышать диапазона от 0 до 255. В силу этого базовый тип мно-
        жества не может быть коротким целым (Shortint),  целым (Integer),
        длинным целым (Longint) или словом (Word).

                  Примечание: Операции над множественными типами описыва-
             ются в разделе "Операции над множествами" в Главе 6.  В раз-
             деле "Описатели множеств" показано,  как определять значения
             множества.

             Любой множественный тип может принимать значение [], которое
        называется пустым множеством.


         B.Pascal 7 & Objects/LR      - 62 -


                                  Файловые типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Файловый тип  состоит  из линейной последовательности компо-
        нентов,  которые могут иметь любой тип за  исключением  файлового
        типа или структурного типа,  содержащего компонент с файловым ти-
        пом. Число компонентов описанием файлового типа не устанавливает-
        ся.

                               ЪДДДДДДї     ЪДДДДї    ЪДДДДДї
              файловый тип ДДД>і file ГДДВД>і of ГДДД>і тип ГДДДДД>
                               АДДДДДДЩ  і  АДДДДЩ    АДДДДДЩ  ^
                                         АДДДДДДДДДДДДДДДДДДДДДЩ

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

             Стандартный файловый  тип  Text определяет файл,  содержащий
        символы,  упорядоченные в строки. Текстовые файлы используют спе-
        циальные процедуры  ввода-вывода,  которые описываются в Главе 14
        "Ввод и вывод".




         B.Pascal 7 & Objects/LR      - 63 -

                                 Ссылочные типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Cсылочный тип (указатель) определяет множество значений, ко-
        торые указывают на динамические  переменные  определенного  типа,
        называемого  базовым  типом.  Переменная ссылочного типа содержит
        адрес динамической переменной в памяти.

                                    ЪДДДї    ЪДДДДДДДДДДДДДї
               ссылочный тип ДДДДДД>і ^ ГДДД>і базовый тип ГДД>
                                    АДДДЩ    АДДДДДДДДДДДДДЩ

                                   ЪДДДДДДДДДДДДДДДДДДДДДї
                  базовый тип ДДДД>і  идентификатор типа ГДДД>
                                   АДДДДДДДДДДДДДДДДДДДДДЩ

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

             Переменной-указателю можно присвоить значение с помощью про-
        цедуры New, операции @ или функции Ptr. Процедура New отводит но-
        вую область памяти в динамически распределяемой области для дина-
        мических  переменных  и сохраняет адрес этой области в переменной
        указателя. Операция @ ориентирует переменную-указатель на область
        памяти, содержащую существующую переменную, включая и те перемен-
        ные,  которые имеют идентификаторы. Функция Ptr ориентирует пере-
        менную-указатель на определенный адрес в памяти.

             Зарезервированное слово nil обозначает константу со значени-
        ем указателя, которая ни на что не указывает.




         B.Pascal 7 & Objects/LR      - 64 -

                                   Тип Pointer
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Встроенный тип  Pointer  обозначает  нетипизированный указа-
        тель, то есть указатель, который не указывает ни на какой опреде-
        ленный тип. Переменные типа Pointer могут быть разыменованы: ука-
        зание символа ^ после такой переменной вызывает появление ошибки.
        Как  и значение,  обозначаемое словом nil,  значения типа Pointer
        совместимы со всеми другими типами указателей.

                   Примечание: В  разделе "Указатели и динамические пере-
              менные" в Главе 5 вы можете найти синтаксис ссылки на дина-
              мические переменные, которые указываются с помощью указате-
              ля-переменной.


                                    Тип PChar
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Для представления указателя на строку с завершающим нулем  в
        Borland Pascal имеется предопределенный тип PChar. В блоке System
        данный тип описывается следующим образом:

             type PChar = ^Char;

             Borland Pascal поддерживает набор расширенных правил, позво-
        ляющих работать  со  строками с завершающим нулем,  используя тип
        PChar. Полностью эта тема обсуждается в Главе  18  "Использование
        строк с завершающим нулем".




         B.Pascal 7 & Objects/LR      - 65 -

                                Процедурные типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             В описании процедурного типа задаются параметры, а для функ-
        ции - результат функции.

        процедурный тип
         і
         і  ЪДДДДДДДДДї
         АВ>іprocedureГДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД>
          і АДДДДДДДДДЩ і  ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДї ^           ^
          і             АД>ісписок формальных параметровГДЩ           і
         ЪЩ                АДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ             АДї
         і ЪДДДДДДДДї                                  ЪДДДї ЪДДДДДДДДДїі
         А>іfunctionГВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД>і : Г>ірезультатГЩ
           АДДДДДДДДЩі ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДї^ АДДДЩ АДДДДДДДДДЩ
                     А>ісписок формальных параметровГЩ
                       АДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Характерно, что синтаксис записи процедурного типа в точнос-
        ти совпадает с записью заголовка процедуры  или  функции,  только
        опускается  идентификатор  после  ключевого  слова  procedure или
        function.  Приведем некоторые примеры описаний процедурного типа:

             type
                Proc = procedure;
                SwapProc = procedure(var X, Y: Integer);
                StrProc = procedure(S: String);
                MathFunc = function(X: Real): Real;
                DeviceFunc = function(var F: text): Integer;
                MaxFunc = function(A, B: Real; F: MathFunc): Real;

             Имена параметров в описании процедурного типа  играют  чисто
        декоративную роль - на смысл описание они не влияют.

             Borland Pascal не позволяет описывать функции, которые возв-
        ращают значения процедурного типа.  Результат функции должен быть
        строкового,  вещественного, целого, символьного, булевского типа,
        указателем  или иметь перечислимый тип,  определенный пользовате-
        лем.

                              Процедурные значения
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Переменной процедурного  типа  можно  присвоить  процедурное

         B.Pascal 7 & Objects/LR      - 66 -

        значение. Процедурные значения могут быть следующими:

             * значениями nil;
             * ссылкой на переменную процедурного типа;
             * идентификатором процедуры или функции.

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

             var
                P: SwapProc;
                F: MathFunc;

             procedure Swap(var A, B: Integer); far;
             var
               Temp: Integer;
             begin
               Temp := A;
               A := B;
               B := Temp;
             end;

             function Tan(Angle: Real); far;
             begin
               Tan := Sin(Angle) / Cos(Angle);
             end;

             Переменным P и F можно присвоить значения следующим образом:

             P := Swap;
             F := Tan;

        а вызовы с помощью P и F можно выполнить так:

             P(I, J);                  { эквивалентно Swap(I, J) }
             X := F(X);                { эквивалентно X := Tan(X) }

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

             if @P <> nil then P(I, J);

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



         B.Pascal 7 & Objects/LR      - 67 -

                               Совместимость типов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Чтобы они считались совместимыми,  процедурные  типы  должны
        иметь одно и то же число параметров,  а параметры в соответствую-
        щих позициях должны иметь  тождественные  типы.  При  определении
        совместимости процедурных типов имена параметров значения не име-
        ют. Значение nil совместимо с любым процедурным типом.

             Чтобы использоваться в качестве процедурных значений, проце-
        дуры и  функции  должны описываться с директивой far и компилиро-
        ваться в состоянии с {$F+}.  Кроме того,  в качестве  процедурных
        значений не  могут  указываться  стандартные процедуры и функции,
        вложенные процедуры и функции,  методы, процедуры и функции, опи-
        санные с ключевым словом inline или interrupt.

             Стандартные процедуры и функции - это подпрограммы,  описан-
        ные в модуле Unit,  например, WriteLn, ReadLn, Chr или Ord. Чтобы
        использовать в  качестве процедурного значения стандартную проце-
        дуру и функцию,  напишите для нее "оболочку". Например, следующая
        функция DSin  совместима  по  присваиванию с описанным выше типом
        MathFunc:

             function FSin(X: Real): Real; far;
             begin
               FSin := Sin(X);
             end;

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

                        Тождественные и совместимые типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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


                              Тождественность типов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Тождественность типов требуется только для переменных факти-
        ческих и формальных параметров при вызове процедур и функций.

             Два типа,  скажем T1 и T2, являются тождественными, если яв-
        ляется истинным одно из следующих утверждений:  T1 и T2 представ-
        ляю собой один и тот же идентификатор типа; T1 описан как эквива-

         B.Pascal 7 & Objects/LR      - 68 -

        лентный типу, тождественному T2.

             Второе условие означает,  что T1 не обязательно должен  быть
        описан  как непосредственно эквивалентный T2.  Следующие описания
        типов:

             T1 = integer;
             T2 = T1;
             T3 = integer;
             T4 = T2;

        означают, что T1,  T2,  T3,  T4 и integer являются тождественными
        типами. Следующие описания типов:

             T5 = set of integer;
             T6 = set of integer;

        не определяют T5 и T6 как тождественные, поскольку set of integer
        не является идентификатором типа. Две переменные, описанные в од-
        ном и том же описании, например:

             V1, V2: set of integer;

        имеют тождественные  типы,  поскольку  их  описания не раздельны.
        Описания:

             V1: set of integer;
             V2: set of integer;
             V3: integer;
             V4: integer;

        означают, что V3 и V4 имеют тождественный тип, а V1 и V2 - нет.


                               Совместимость типов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Совместимость типов имеет место, если выполняется по крайней
        мере одно из следующих условий:

             * Оба типа являются одинаковыми.

             * Оба типа являются вещественными типами.

             * Оба типа являются целочисленными.

             * Один тип является поддиапазоном другого.

             * Оба типа являются отрезками одного и того же основного ти-

         B.Pascal 7 & Objects/LR      - 69 -

               па.

             * Оба типа являются множественными типами с совместимыми ба-
               зовыми типами.

             * Один тип является строковым типом,  а другой  -  строковым
               типом, упакованным строковым типом или типом PChar;

             * Один  тип  -  это тип Pointer,  а другой - любой ссылочный
               тип.

             * Один тип является типом PChar,  а другой - символьным мас-
               сивом  с нулевой базой вида array[0..X] of Char (это дейс-
               твует только при разрешении директивой {$X+}  расширенного
               синтаксиса).

             * Оба  типа являются указателями идентичных типов (это дейс-
               твует только при разрешении указателя с проверкой типа ди-
               рективой {$X+}).

             * Оба  типа  являются  процедурными с идентичными типами ре-
               зультатов,  одинаковым числом параметров  и  соответствием
               между параметрами.


                          Совместимость по присваиванию
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Совместимость по присваиванию необходима,  если имеет  место
        присваивание значения, например, в операторе присваивания или при
        передаче значений параметров.

             Значение типа T1 является совместимым по присваиванию с  ти-
        пом T2 (то есть допустим оператор T1:=T2),  если выполняется одно
        из следующих условий:

             * T1 и T2 имеют тождественные типы,  и ни один из них не яв-
               ляется  файловым  типом или структурным типом,  содержащим
               компонент с файловым типом на одном из своих уровней.

             * T1 и T2 являются совместимыми порядковыми типами, и значе-
               ния типа T2 попадают в диапазон возможных значений T1.

             * T1 и T2 являются вещественными типами,  и значения типа T2
               попадают в диапазон возможных значений T1.

             * T1 является вещественным типом,  а T2 является целочислен-
               ным типом.

             * T1 и T2 являются строковыми типами.

             * T1 является строковым типом,  а T2 является символьным ти-
               пом (Char).

         B.Pascal 7 & Objects/LR      - 70 -


             * T1 является строковым типом,  а  T2  является  упакованным
               строковым типом.

             * T1  и T2 являются совместимыми упакованными строковыми ти-
               пами.

             * T1 и T2 являются совместимыми множественными типами, и все
               члены  значения типа T2 попадают в диапазон возможных зна-
               чений T1.

             * T1 и T2 являются совместимыми типами указателей.

             * T1 - это тип PChar,  а T2 - это строковая  константа  (это
               действует только при разрешении директивой {$X+} расширен-
               ного синтаксиса).

             * T1 является типом PChar,  а T2 - символьным массивом с ну-
               левой базой вида array[0..X] of Char (это действует только
               при разрешении директивой {$X+} расширенного синтаксиса).

             * T1 и T2 являются совместимыми процедурными типами.

             * T1 представляет собой процедурный тип,  а T2  -  процедура
               или функция с идентичным типом результата, идентичным чис-
               лом параметров и соответствием между типами параметров.

             * Объектный тип T2 совместим по присваиванию с объектным ти-
               пом T1, если T2 является доменом T1.

             * Тип указателя Р2, указывающий на объект типа Т3, совместим
               по присваиванию с типом указателя P1,  указывающим на объ-
               ект T1, если T2 является доменом T1.

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


                              Раздел описания типов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Программы, процедуры и функции имеют для описания типов спе-
        циальный раздел описания типов. Например:

             type
               TRange     = integer;
               TNumber    = integer;
               TColor     = (red,green,blue);
               TTextIndex = 1..100;
               TTestValue = -99..99;
               TTestList  = array[TestIndex] of TestValue;
               PestList   = ^TTestList;

         B.Pascal 7 & Objects/LR      - 71 -

               TDate      = object
                               year: integer;
                               month: 1..12;
                               day: 1.. 31;
                             procedure SetDate(D, M, Y: Integer);
                             function ShowDate: String;
                             end;

             MeasureData = record
                             when: Date;
                             count: TTestIndex;
                             data: TestListPtr;
                           end;
             TMeasureList = array[1..50] of MeasureData;
             TName        = string[80];
             TSex         = (male,female);
             TPersonDate  = ^TPersonData;
             TPersonData  = record
                             name,firstName: TName;
                             age:            integer;
                             married:        boolean;
                             father,child,sibling: Person;
                               case s: Sex of
                                 male:   (bearded: boolean);
                                 female: (pregnant: boolean);
                            end;
             TPersonDate = array[0..SizeOf(TPersonDate)-1] of Byte;
             TPeople  = file of TPersonData;

             В этом примере Range,  Number и Integer являются тождествен-
        ными типами. TTestIndex является просто совместимым и совместимым
        по присваиванию,  но не тождественным,  с типами Number,  Range и
        Integer. Обратите  внимание на использование в описаниях TCharVal
        и TPersonBuf выражений-констант.



         B.Pascal 7 & Objects/LR      - 72 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                 Глава 5. Переменные и типизированные константы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

                               Описания переменных
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Описание переменной  представляет собой список идентификато-
        ров, которые обозначают новые переменные и их типы.

         описание     ЪДДДДДДДДДДДДї  ЪДДДї  ЪДДДї                ЪДДДї
         переменной Д>ісписок иден-ГД>і : ГД>ітипГДВДДДДДДДДДДДВД>і ; Г>
                      ітификаторов і  АДДДЩ  АДДДЩ і           і  АДДДЩ
                      АДДДДДДДДДДДДЩ               і ЪДДДДДДДДїі
                                                   А>іabsoluteГЩ
                                                     АДДДДДДДДЩ

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

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

             Приведем пример раздела описания переменной:

             var
               X,Y,Z: real;
               I,J,K: integer;
               Digit: 0..9;
               C: Color;
               Done,Error: boolean;
               Operator: (plus, minus, times);
               Hue1,Hue2: set of Color;
               Today: Date;
               Results: MeasureList;
               P1,P2: Person;
               Matrix: array[1..10,1..10] of Real;

             Переменные, описанные  вне  процедуры и функции,  называются
        глобальными переменными и располагаются в сегменте данных.  Пере-
        менные,  описанные в самой процедуре или функции,  называются ло-
        кальными переменными и располагаются в сегменте стека.



         B.Pascal 7 & Objects/LR      - 73 -

                                 Сегмент данных
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Если для  глобальных  переменных требуется более 65520 байт,
        то следует распределить большие структуры в виде динамических пе-
        ременных. Дальнейшее описание этой темы  можно  найти  в  разделе
        "Указатели и динамические переменные" настоящей главы.

                                  Сегмент стека
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Размер сегмента стека устанавливается  с  помощью  директивы
        компилятора $M и лежит в пределах от 1024 до 65520 байт. По умол-
        чанию размер стека равен 16384 байт.

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

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

              Директива компилятора $S используется для проверок перепол-
        нения стека в программе.  В состоянии {$S+},  принятом по умолча-
        нию, генерируется код, осуществляющий проверку переполнения стека
        в начале каждой процедуры или функции.  В состоянии  {$S-}  такие
        проверки не проводятся.  Переполнение стека может вызвать аварий-
        ное завершение работы системы,  поэтому не следует отменять  про-
        верки стека,  если нет абсолютной уверенности в том, что перепол-
        нения не произойдет.



         B.Pascal 7 & Objects/LR      - 74 -

                              Абсолютные переменные
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

         описание       ЪДДДДДДДДї    ЪДДДДДДДДДї  ЪДДДї  ЪДДДДДДДДДї
         абсолютной ДДД>іabsoluteГДВД>іцелое безГД>і : ГД>іцелое безГДВД>
         переменной     АДДДДДДДДЩ і  і знака   і  АДДДЩ  і знака   і і
                                   і  АДДДДДДДДДЩ         АДДДДДДДДДЩ і
                                   і       ЪДДДДДДДДДДДДДї            і
                                   АДДДДДД>іидентификаторГДДДДДДДДДДДДЩ
                                           і  переменной і
                                           АДДДДДДДДДДДДДЩ

             Отметим, что список идентификаторов  в  описании  переменной
        при указании оператора absolute может содержать только один иден-
        тификатор.

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

             CrtMode   : byte absolute $0040:$0049;

             Первая константа обозначает базу сегмента,  а вторая опреде-
        ляет смещение внутри этого сегмента.  Обе константы не должны вы-
        ходить за пределы диапазона от $0000 до $FFFF (от 0 до 65535).

             В программах защищенного режима DOS и в Windows первую форму
        оператор absolute нужно использовать очень аккуратно, если вообще
        стоит это  делать.  Во  время  выполнения  прикладной   программы
        Windows или  DOS защищенного режима она может не иметь полномочий
        доступа к областям памяти вне вашей программы.  Попытка доступа к
        этим областям памяти может привести к сбою программы.

         B.Pascal 7 & Objects/LR      - 75 -


             Вторая форма  оператора  absolute  используется для описания
        переменной,  которая помещается "поверх"  другой  переменной,  то
        есть по тому же самому адресу, что и другая переменная.

             var
               Str: string[32];
               StrLen: byte absolute Str;

             Это описание указывает,  что переменная StrLen должна разме-
        щаться с того же адреса, что и переменная Str, а поскольку первый
        байт  строковой переменной содержит динамическую длину строки, то
        StrLen будет содержать длину Str.

             Эту вторую форму оператора absolute можно без  опасения  ис-
        пользовать при программировании в Windows или в защищенном режиме
        DOS. Память,  к которой вы обращаетесь, находится в области прог-
        раммы.




         B.Pascal 7 & Objects/LR      - 76 -

                              Ссылки на переменные
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Ссылка на переменную может обозначать следующее:

             - переменную;

             - компонент в переменной структурного или строкового типа;

             - динамическую переменную,  на которую указывает  переменная
               типa указатель.

             Синтаксис ссылки на переменную имеет вид:

                         ЪДДДДДДДДДДДДДї
         ссылка на  ДВДД>іидентификаторГДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДД>
         переменную  і   і  переменной і        ^^  ЪДДДДДДДДДДДДї  і
                     і   АДДДДДДДДДДДДДЩ        іАДДґквалификаторі<ДЩ
                     і   ЪДДДДДДДДДДДДДДДї      і   АДДДДДДДДДДДДЩ
                     ГДД>іприведение типаГДДДДДДґ
                     і   і  переменной   і      і
                     і   АДДДДДДДДДДДДДДДЩ      АДДДДДї
                     і   ЪДДДДДДДДДї  ЪДДДДДДДДДДДДї  і
                     АДД>івыражениеГД>іквалификаторГДДЩ
                         АДДДДДДДДДЩ  АДДДДДДДДДДДДЩ

             Отметим, что  синтаксис  ссылки  на переменную допускает ис-
        пользование выражения, вычисляющего значение ссылочного типа. Вы-
        ражение должно следовать за квалификатором, разыменовывающим ссы-
        лочное значение (или индексирующим значением  указателя,  если  с
        помощью директивы {$X+} разрешен расширенный синтаксис), что дает
        фактическую ссылку на переменную.




         B.Pascal 7 & Objects/LR      - 77 -

                                  Квалификаторы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Обращение к функции представляет собой  идентификатор  пере-
        менной с несколькими квалификаторами или без них, которые изменя-
        ют значение обращения к функции.

                                      ЪДДДДДДї
                   квалификатор ДДВДД>іиндексГДДДДДДДДДД>
                                  і   АДДДДДДЩ        ^
                                  і   ЪДДДДДДДДДДДДї  і
                                  ГДД>і десигнатор ГДДґ
                                  і   і    поля    і  і
                                  і   АДДДДДДДДДДДДЩ  і
                                  і   ЪДДДї           і
                                  АДД>і ^ ГДДДДДДДДДДДЩ
                                      АДДДЩ

             Идентификатор массива без квалификатора является  ссылкой на
        весь массив, например:

             Results

             Идентификатор массива  с указанным индексом обозначает конк-
        ретный элемент массива, в данном случае структурную переменную:

             Results[Current+1]

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

             Results[Current+1].Data

             Десигнатор  поля в указателе-поле может сопровождаться  сим-
        волом указателя (^) с тем,  чтобы указать различие между указате-
        лем-полем и динамической переменной, на которую он указывает.

              Results[Current+1].Data^

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

              Results[Current+1].Data^[J]




         B.Pascal 7 & Objects/LR      - 78 -

                            Массивы, строки и индексы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

                             ЪДДДї        ЪДДДДДДДДДї        ЪДДДї
                   индекс ДД>і [ ГДДДДДДД>івыражениеГДДДДВДД>і ] ГДД>
                             АДДДЩ  ^     АДДДДДДДДДЩ    і   АДДДЩ
                                    і       ЪДДДї        і
                                    АДДДДДДДґ , і<ДДДДДДДЩ
                                            АДДДЩ

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

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

             Matrix[I][J]

        что тождественно записи:

             Matrix[I,J]

             Строковую переменную  можно  проиндексировать с помощью оди-
        ночного индексного выражения, значение которого должно быть в ди-
        апазоне  0...n,  где n - указанный в описании размер строки.  Это
        дает доступ к каждому символу в строковом значении, если значение
        символа имеет тип Char.

             Первый символ строковой переменной (индекс 0) содержит дина-
        мическую длину строки,  то есть Length(S) тождественно Ord(S[0]).
        Если атрибуту длины присваивается значение, то компилятор не про-
        веряет, является ли это значение меньшим описанного размера стро-
        ки. Вы можете указать индекс строки и вне ее текущей динамической
        длины.  В этом случае считываемые  символы  будут  случайными,  а
        присваивания вне текущей длины не повлияют на действительное зна-
        чение строковой переменной.

             Когда с помощью директивы компилятора {$X+} разрешен  расши-
        ренный синтаксис,  значение PChar может индексироваться одиночным
        индексным выражением типа Word. Индексное выражение задает смеще-
        ние, которое  нужно  добавить  к символу перед его разыменованием
        для получения ссылки на переменную типа Char.

         B.Pascal 7 & Objects/LR      - 79 -



                           Записи и десигнаторы полей
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Конкретное поле  переменной-записи  обозначается  с  помощью
        ссылки на переменную-запись,  после которой указывается обозначе-
        ние поля, специфицирующее это поле.

                                  ЪДДДї    ЪДДДДДДДДДДДДДї
             обозначение поля ДДД>і . іДДД>іидентификаторіДДД>
                                  АДДДЩ    і поля        і
                                           АДДДДДДДДДДДДДЩ

             Приведем несколько примеров десигнаторов полей:

             Today.Year
             Results[1].Count
             Result[1].When.Month

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


                         Десигнаторы компонентов объекта
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Формат десигнатора  компонента  объекта совпадает с форматом
        десигнатора поля записи. То есть, он состоит из экземпляра (ссыл-
        ки на переменную),  за которым следует точка и идентификатор ком-
        понента. Десигнатор компонента, который обозначает метод, называ-
        ется  десигнатором  метода.  К  экземпляру  объектного типа можно
        применить оператор with.  В этом случае при ссылке на  компоненты
        объектного типа экземпляр и точку можно опустить.

             Экземпляр и точку можно опустить также в любом блоке метода.
        При этом эффект будет тот же,  что и при записи перед ссылкой  на
        компонент Self и точки.


                 Переменные-указатели и динамические переменные
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Значением переменной-указателя является  или  nil  (то  есть
        пустое значение), или адрес значения, указывающий на динамическую
        переменную.

             Ссылка на динамическую переменную,  на которую указывает пе-
        ременная-указатель,  записывается  в  виде  переменной-указателя,
        после которой ставится символ указателя (^).

             Динамические переменные и значения их указателей создаются с
        помощью стандартных процедур New и GetMem. Вы можете использовать

         B.Pascal 7 & Objects/LR      - 80 -

        операцию @ и стандартную функцию Ptr для создания значений указа-
        теля, которые рассматриваются как указатели динамических перемен-
        ных.

             Значение nil не указывает ни на какую  переменную.  Если  вы
        попытаетесь получить доступ к динамической переменной при неопре-
        деленном значении указателя или указателе,  равном nil, результат
        будет неопределенным.

             Приведем несколько  примеров  ссылок (указателей) на динами-
        ческие переменные:

             P1^
             P1.Sibling^
             Results[1].Data^




         B.Pascal 7 & Objects/LR      - 81 -

                           Приведение типов переменных
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                        ЪДДДДДДДДДДДДДї   ЪДДДї   ЪДДДДДДДДДДї   ЪДДДї
         приведение ДДД>іидентификаторГДД>і ( ГДД>іссылка на ГДД>і ) ГД>
         типов          і    типа     і   АДДДЩ   іпеременнуюі   АДДДЩ
                        АДДДДДДДДДДДДДЩ           АДДДДДДДДДДЩ

             Когда приведение типов применяется к ссылке  на  переменную,
        ссылка  на переменную рассматривается как экземпляр типа,  предс-
        тавленного идентификатором типа.  Размер переменной (число  байт,
        занимаемых переменной) должен быть равен размеру типа,  представ-
        ленного идентификатором типа.  После приведения  типа  переменной
        можно указать один или несколько квалификаторов,  если это допус-
        кается указанным типом.

                   Примечание: Определять  допустимость  приведения  типа
              должен программист.

             Приведем несколько примеров приведения типов переменных:

             type
               TByteRec = record
                            lo, hi: byte;
                          end;
               TWordRec = record
                            low, high: word;
                          end;
               TPtrRec = record
                           ofs, seg: word;
                         end;
               PByte = ^Byte;
             var
               B: byte;
               W: word;
               L: longint;
               P: pointer;
             begin
               W := $1234;
               B := TByteRec(W).lo;
               TByteRec(W).hi := 0;
               L := $1234567;
               W := TWordRec(L).lo;
               B := PByte(L)^;
               P := Ptr($40,$49);
               W := TPtrRec(P).seg;
               Inc(TPtrRec(P).Ofs,4);
             end.


         B.Pascal 7 & Objects/LR      - 82 -

             Обратите внимание на использование для доступа к  младшим  и
        старшим байтам слова типа TByteRec:  это соответствует встроенным
        функциям Lo и Hi, только над левой частью в операции присваивание
        может выполняться приведение типа. Отметим также, что для доступа
        к младшим и старшим словам длинного целого,  а также к смещению и
        адресу сегмента указателя используются типы TWordRec и TPtrRec.

             Borland Pascal также полностью поддерживает приведение типов
        для процедурных типов. Например, имея следующие описания:

             type
                Func = function(X: Integer): Integer;
             var
                F: Func;
                P: Pointer;
                N: Integer;

        вы можете построить следующие присваивания:

             F := Func(P); { присвоить F значение процедурного типа в P }
             Func(P) := F; { присвоить P значение процедурного типа в F }
             @F := P;      { присвоить F значение-указатель в P }
             P := @F;      { присвоить P значение-указатель в F }
             N := F(N);    { вызвать функцию через F }
             N := Func(P)(N); { вызвать функцию через P }

             Обратите в частности внимание на операцию  получения  адреса
        @,  которая применяется к переменной процедурного типа.  Ее можно
        использовать в левой части  присваивания.  Кроме  того,  отметьте
        приведение  типа на последней строке при вызове функцию через пе-
        ременную-указатель.

         B.Pascal 7 & Objects/LR      - 83 -

                            Типизированные константы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

         описание типизированной константы
         і  ЪДДДДДДДДДДДДДї  ЪДДДї  ЪДДДї  ЪДДДї  ЪДДДДДДДДДДДДДДї
         АД>іидентификаторГД>і : ГД>ітипГД>і = ГД>ітипизированнаяГДД>
            АДДДДДДДДДДДДДЩ  АДДДЩ  АДДДЩ  АДДДЩ  і   константа  і
                                                  АДДДДДДДДДДДДДДЩ

         типизированная            ЪДДДДДДДДДДДДДДДДДДДї
         константа      ДДДДДДВДДД>і     константа     ГДДДДДДД>
                              і    АДДДДДДДДДДДДДДДДДДДЩ   ^
                              і    ЪДДДДДДДДДДДДДДДДДДДї   і
                              ГДДД>і адресная константаГДДДґ
                              і    АДДДДДДДДДДДДДДДДДДДЩ   і
                              і    ЪДДДДДДДДДДДДДДДДДДДї   і
                              ГДДД>і константа-массив  ГДДДґ
                              і    АДДДДДДДДДДДДДДДДДДДЩ   і
                              і    ЪДДДДДДДДДДДДДДДДДДї    і
                              ГДДД>і константа-запись ГДДДДґ
                              і    АДДДДДДДДДДДДДДДДДДЩ    і
                              і    ЪДДДДДДДДДДДДДДДДДДДї   і
                              ГДДД>і константа-объект  ГДДДґ
                              і    АДДДДДДДДДДДДДДДДДДДЩ   і
                              і    ЪДДДДДДДДДДДДДДДДДДДї   і
                              АДДД>іконстанта-множествоГДДДЩ
                                   АДДДДДДДДДДДДДДДДДДДЩ

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

             Кроме обычных   выражений-констант  значение  типизированной
        константы может задаваться с помощью адресного выражения-констан-
        ты. Адресное выражение-константа - это выражение, предусматриваю-
        щее получение адреса,  смещения или сегмента глобальной  перемен-
        ной, типизированной  константы,  процедуры или функции.  Адресные
        выражения-константы не могут ссылаться  на  локальные  переменные
        (расположенные в  стеке) или динамические переменные (размещенные
        в динамически распределяемой области памяти), поскольку их адреса
        нельзя вычислить на этапе компиляции.



         B.Pascal 7 & Objects/LR      - 84 -

                             Константы простого типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
             Описание типизированной  константы  с простым типом означает
        указание значения константы:

             const
               Maximum   : integer = 9999;
               Factor    : real = -0.1;
               Breakchar : char = #3;

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

             var
                Buffer: array[0..1023] of Byte;
             const
                BufferOfs: Word = Ofs(Buffer);
                BufferSeg: Word = Seg(Buffer);

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

             const
               Min : integer = 0;
               Max : integer = 99;
             type
               Vector = array[Min..Max] of integer;

             Описание Vector является недопустимым,  поскольку Min и  Max
        являются типизированными константами.


                            Константы строкового типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
             Описание типизированной  константы  строкового типа содержит
        максимальную длину строки и ее начальное значение:

             const
               Heading  : string[7] = 'Section';
               NewLine  : string[2] = #13#10;
               TrueStr  : string[5] = 'Yes';
               FalseStr : string[5] = 'No';

         B.Pascal 7 & Objects/LR      - 85 -


                           Константы структурного типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Описание константы  структурного  типа  определяет  значение
        каждого компонента структуры.  Borland Pascal поддерживает описа-
        ния констант типа массив, запись, множество и указатель. Констан-
        ты файлового типа и константы типа массив или запись,  содержащие
        компоненты файлового типа, не допускаются.




         B.Pascal 7 & Objects/LR      - 86 -

                              Константы типа массив
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Описание константы  типа массив содержит значения элементов,
        заключенные в скобки и разделенные запятыми.

                                  ЪДДДї     ЪДДДДДДДДДДДДДДї     ЪДДДї
            константа-массив  ДДД>і ( ГДДДД>ітипизированнаяГДДВД>і ) ГДД>
                                  АДДДЩ  ^  і   константа  і  і  АДДДЩ
                                         і  АДДДДДДДДДДДДДДЩ  і
                                         і      ЪДДДї         і
                                         АДДДДДДґ , і<ДДДДДДДДЩ
                                                АДДДЩ

             Приведем пример константы типа массив:

             type
               Status = (Active,Passive,Waiting);
               StatusMap = array[Status] of string[7];
             const
               StatStr: StatusMap = ('Active','Passive','Waiting');

             В этом примере определяется константа-массив StarStr,  кото-
        рая может использоваться для преобразования значений  типа Status
        в соответствующие им строковые представления.  Элементами массива
        StarStr являются:

             StatStr[Active]  =  'Active'
             StatStr[Passive] =  'Passive'
             StatStr[Waiting] =  'Waiting'

             Тип элемента константы-массива может быть любым,  кроме фай-
        лового  типа.  Упакованные  константы строкового типа (символьные
        массивы) могут быть определены и как  одиночные  символы,  и  как
        строки. Определение:

             const
             Digits:array[0..9] of
                  char=('0','1','2','3','4','5','6','7','8','9');

        можно представить в более удобном виде:

             const
               Digits: array[0..9] of char = '0123456789';

             При разрешении расширенного синтаксиса (с помощью  директивы
        компилятора {$X+})  массивы с нулевой базой могут инициализирова-
        ться строкой, которая короче, чем описанная длина массива, напри-
        мер:

             const
                FileName = array[0..79] of Char = 'TEXT.PAS';


         B.Pascal 7 & Objects/LR      - 87 -

             В таких случаях оставшиеся символы  устанавливаются  в  NULL
        (#0), и массив содержит строку с завершающим нулем.

                   Примечание: Подробнее  о  строках  с завершающим нулем
              рассказывается в Главе 18.

             При описании константы типа "многомерный  массив"  константы
        каждой  размерности  заключаются в отдельные скобки и разделяются
        запятыми.  Расположенные в середине константы соответствуют самым
        правым размерностям. Описание:

             type
               Cube = array[0..1,0..1,0..1] of integer;
             const
               Maze: Cube = (((0,1),(2,3)),((4,5),(6,7)));

        задает следующие начальные значения массива Maze:

             Maze[0, 0, 0] = 0
             Maze[0, 0, 1] = 1
             Maze[0, 1, 0] = 2
             Maze[0, 1, 1] = 3
             Maze[1, 0, 0] = 4
             Maze[1, 0, 1] = 5
             Maze[1, 1, 0] = 6
             Maze[1, 1, 1] = 7




         B.Pascal 7 & Objects/LR      - 88 -

                              Константы типа запись
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Описание константы типа запись содержит идентификатор и зна-
        чение каждого поля,  заключенные в скобки и разделенные точками с
        запятой.

         константа-запись
         і  ЪДДДї    ЪДДДДДДДДДДДДДї  ЪДДДї  ЪДДДДДДДДДДДДДДї    ЪДДДї
         АД>і ( ГДДД>іидентификаторГД>і : ГД>ітипизированнаяГДВД>і ) ГД>
            АДДДЩ ^  і     поля    і  АДДДЩ  і   константа  і і  АДДДЩ
                  і  АДДДДДДДДДДДДДЩ         АДДДДДДДДДДДДДДЩ і
                  і                   ЪДДДї                   і
                  АДДДДДДДДДДДДДДДДДДДґ ; і<ДДДДДДДДДДДДДДДДДДЩ
                                      АДДДЩ

             Приведем несколько примеров констант-записей:

             type
               Point  = record
                          x,y: real;
                        end;
               Vector = array[0..1] of Point;
               Month  =
                   (Jan,Feb,Mar,Apr,May,Jun,Jly,Aug,Sep,Oct,Nov,Dec);
               Date   = record
                          d: 1..31; m: Month; y: 1900..1999;
                        end;
             const
               Origin  : Point = (x: 0.0; y: 0.0);
               Line    : Vector = ((x: -3.1; y: 1.5),(x: 5.8; y: 3.0));
               SomeDay : Date = (d: 2; m: Dec; y: 1960);

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


         B.Pascal 7 & Objects/LR      - 89 -


                            Константы объектного типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             При описании  константы  объектного типа используется тот же
        синтаксис, что и при описании константы типа запись. Значения для
        элементов (компонентов) метода задаваться не могут. С учетом при-
        водимых ранее описаний объектных типов, приведем некоторые приме-
        ры констант объектного типа:

             const
                ZeroPoint: Point = (X: 0; Y: 0)
                ScreenRect: Rect = (A: (X: 0; Y: 0); B: (X: 80; Y: 25);
                CountField: NumField = (X: 5; Y: 20; Len: 4; Name: nil;
                  Value: 0; Min: -999; Max: 999);

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




         B.Pascal 7 & Objects/LR      - 90 -

                          Константы множественного типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                               ЪДДДї                               ЪДДДї
         константа-множество Д>і [ ГДВДДДДДДДДДДДДДДДДДДДДДДДДДДДД>і ] Г>
                               АДДДЩ і    ЪДДДДДДДДДДДДДДДДДї   ^  АДДДЩ
                                     АДДД>іконстанта-элементГДВДЩ
                                       ^  АДДДДДДДДДДДДДДДДДЩ і
                                       і        ЪДДДї         і
                                       АДДДДДДДДґ , і<ДДДДДДДДЩ
                                                АДДДЩ

                                ЪДДДДДДДДДї
         константа-элемент ДДДД>іконстантаГДДВДДДДДДДДДДДДДДДДДДДДДДДДД>
                                АДДДДДДДДДЩ  і  ЪДДї   ЪДДДДДДДДДї  ^
                                             АД>і..ГДД>іконстантаГДДЩ
                                                АДДЩ   АДДДДДДДДДЩ

             Приведем несколько примеров констант-множеств:

             type
               Digits  = set of 0..9;
               Letters = set of 'A'..'Z';
             const
               EvenDigits: Digits = [0,2,4,6,8];
               Vowels    : Letters = ['A','E','I','O','U','Y'];
               HexDigits : set of '0'..'z' =
              ['0'..'9','A'..'F','a'..'f'];




         B.Pascal 7 & Objects/LR      - 91 -

                            Константы ссылочного типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Описание константы  ссылочного  типа  может содержать только
        значение nil (пусто). Приведем несколько примеров:

             type
                TDirection = (Left, Right, Up, Down);
                TStringPtr = ^String;
                TNodePtr = ^Node;
                TNode = record
                          Next: NodePtr;
                          Symbol: StringPtr;
                          Value: Direction;
                        end;
             const
                  S1: string[4] = 'DOWN';
                  S2: string[2] = 'UP';
                  S3: string[5] = 'RIGHT';
                  S4: string[4] = 'LEFT';
                  N1: Node = (Next: nil; Symbol: @S1; Value: Down);
                  N2: Node = (Next: @N1; Symbol: @S2; Value: Up);
                  N3: Node = (Next: @N2; Symbol: @S3; Value: Right);
                  N2: Node = (Next: @N3; Symbol: @S4; Value: Left);
                  DirectionTable: NodePtr = @N4;

             Если разрешен расширенный синтаксис (указана директива  ком-
        пилятора {$X+}), типизированная константа типа PChar может иници-
        ализироваться строковой константой, например:

             const
                Message: PChar = 'Программа завершена';
                Prompt: PChar = 'Введите значения: ';
                Digits: array[0..9] of PChar = (
                    'Ноль', 'Один', 'Два', 'Три', 'Четыре',
                    'Пять', 'Шесть', 'Семь', 'Восемь', 'Девять');

             Результатом будет то,  что указатель теперь указывает на об-
        ласть памяти,  содержащую копию строкового литерала с завершающим
        нулем. Подробности вы можете найти в Главе 18 "Строки с завершаю-
        щим нулем".




         B.Pascal 7 & Objects/LR      - 92 -

                           Константы процедурного типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                                          ЪДДДДДДДДДДДДДДДДДї
         процедурная константа ДДДДДДВДДД>іконстанта-элементГДДДДДДДДДДД>
                                     і    АДДДДДДДДДДДДДДДДДЩ   ^
                                     і    ЪДДДДДДДДДДДДДДДДДї   і
                                     ГДДД>іконстанта-элементГДДДґ
                                     і    АДДДДДДДДДДДДДДДДДЩ   і
                                     і          ЪДДДї           і
                                     АДДДДДДДДД>іnilГДДДДДДДДДДДЩ
                                                АДДДЩ

             Приведем следующий пример:

             type
                ErrorProc = procedure(ErrorCode: Integer);

             procedure DefaultError(ErrorCode: Integer); far;
             begin
                  WriteLn('Error ', ErrorCode, '.');
             end;

             const
                  ErrorHandler: ErrorProc = DefaultError;




         B.Pascal 7 & Objects/LR      - 93 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                               Глава 6. Выражения
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Выражения состоят из операций и операндов.  Большинство опе-
        раций  в  языке Паскаль являются бинарными,  то есть содержат два
        операнда.  Остальные операции являются унарными и содержат только
        один операнд. В бинарных операциях используется обычное алгебраи-
        ческое представление, например: a+b. В унарных операциях операция
        всегда предшествует операнду, например: -b.

             В более  сложных  выражениях порядок,  в котором выполняются
        операции, соответствует приоритету операций (см. Таблицу 6.1).

                              Старшинство операций            Таблица 6.1
        ЪДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДї
        і    Операция        і      Приоритет      і     Вид операции   і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДґ
        і  @, not            і   первый (высший)   і   унарная операция і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДґ
        і  *, /, div, mod,   і       второй        і операция умножения,і
        і  and, shl, shr     і                     і деления, сдвига... і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДґ
        і  +, -, or, xor     і       третий        і  операция сложения і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДґ
        і  =, <>, <, >,      і  четвертый (низший) і операция отношения і
        і  <=, >=, in        і                     і                    і
        АДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДЩ

             Для определении старшинства операций  имеется  три  основных
        правила:

             1.  Во-первых, операнд, находящийся между двумя операциями с
                 различными приоритетами,  связывается с операцией, имею-
                 щей более высокий приоритет.

             2.  Во-вторых,  операция, находящаяся между двумя операциями
                 с равными приоритетами, связывается с той операцией, ко-
                 торая находится слева от него.

             3.  В-третьих, выражение, заключенное в скобки, перед выпол-
                 нением вычисляется, как отдельный операнд.

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




         B.Pascal 7 & Objects/LR      - 94 -

                               Синтаксис выражений
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Множитель имеет следующий синтаксис:

                                        ЪДДДДДДДДДДДДДДДї
           множитель ДДДВДДДДДДДДДДДДДД>і  ссылка на    ГДДДДДДДДДДД>
                        і               і  переменную   і      ^
                        і               АДДДДДДДДДДДДДДДЩ      і
                        і     ЪДДДДДДДДДї                      і
                        ГДДДД>іконстантаГДДДДДДДДДДДДДДДДДДДДДДґ
                        і     ібез знакаі                      і
                        і     АДДДДДДДДДЩ                      і
                        і     ЪДДДї     ЪДДДДДДДДДї    ЪДДДї   і
                        ГДДДД>і ( ГДДДД>івыражениеіДДД>і ) ГДДДґ
                        і     АДДДЩ     АДДДДДДДДДЩ    АДДДЩ   і
                        і     ЪДДДї     ЪДДДДДДДДДї            і
                        ГДДДД>іnotГДДДД>імножительГДДДДДДДДДДДДґ
                        і     АДДДЩ     АДДДДДДДДДЩ            і
                        і     ЪДДДДї    ЪДДДДДДДДДї            і
                        ГДДДД>ізнакГДДД>імножительГДДДДДДДДДДДДґ
                        і     АДДДДЩ    АДДДДДДДДДЩ            і
                        і     ЪДДДДДДДДДї                      і
                        ГДДДД>і  вызов  ГДДДДДДДДДДДДДДДДДДДДДДґ
                        і     і функции і                      і
                        і     АДДДДДДДДДЩ                      і
                        і     ЪДДДДДДДДДДДї                    і
                        ГДДДД>іконструкторГДДДДДДДДДДДДДДДДДДДДґ
                        і     і множества і                    і
                        і     АДДДДДДДДДДДЩ                    і
                        і     ЪДДДДДДДДДДДї                    і
                        ГДДДД>і  адресный ГДДДДДДДДДДДДДДДДДДДДґ
                        і     і множитель і                    і
                        і     АДДДДДДДДДДДЩ                    і
                        і     ЪДДДДДДДДДДДДДДї                 і
                        АДДДД>і  приведение  ГДДДДДДДДДДДДДДДДДЩ
                              ітипа значения і
                              АДДДДДДДДДДДДДДЩ

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

             Адресный множитель  вычисляет  адрес переменной,  процедуры,
        функции или метода. См. раздел "Операция @".


         B.Pascal 7 & Objects/LR      - 95 -

             Беззнаковая константа имеет следующий синтаксис:

                                           ЪДДДДДДДДДї
             константа без знака  ДДДВДДДД>і  число  ГДДДДДДДДДДДДД>
                                     і     ібез знакаі         ^
                                     і     АДДДДДДДДДЩ         і
                                     і     ЪДДДДДДДДДДї        і
                                     ГДДДД>ісимвольнаяГДДДДДДДДґ
                                     і     і  строка  і        і
                                     і     АДДДДДДДДДДЩ        і
                                     і     ЪДДДДДДДДДДДДДї     і
                                     ГДДДД>іидентификаторГДДДДДґ
                                     і     і  константы  і     і
                                     і     АДДДДДДДДДДДДДЩ     і
                                     і     ЪДДДї               і
                                     АДДДД>іnilГДДДДДДДДДДДДДДДЩ
                                           АДДДЩ

             Некоторые примеры множителей могут включать в себя:

            Х                                    { ссылка на переменную }
            @Х                                { указатель на переменную }
            15                                    { константа без знака }
            (Х+Y+Z)                                      { подвыражение }
            SIN(Х/2)                                    { вызов функции }
            ['0..''9','А'..'Z']                   { описатель множества }
            not Done                   { отрицание булевской переменной }
            сhar(Digit+48)                            { назначение типа }


         B.Pascal 7 & Objects/LR      - 96 -

             Термы используются в операциях умножения на множитель:

                                  ЪДДДДДДДДДї
                    терм ДДДДДДДД>імножительГДДДВДДДДДД>
                            ^     АДДДДДДДДДЩ   і
                            і     ЪДДДї         і
                            ГДДДДДґ * і<ДДДДДДДДґ
                            і     АДДДЩ         і
                            і     ЪДДДї         і
                            ГДДДДДґ / і<ДДДДДДДДґ
                            і     АДДДЩ         і
                            і     ЪДДДї         і
                            ГДДДДДґdivі<ДДДДДДДДі
                            і     АДДДЩ         і
                            і     ЪДДДї         і
                            ГДДДДДґmodі<ДДДДДДДДі
                            і     АДДДЩ         і
                            і     ЪДДДї         і
                            ГДДДДДґandі<ДДДДДДДДі
                            і     АДДДЩ         і
                            і     ЪДДДї         і
                            ГДДДДДґshlі<ДДДДДДДДі
                            і     АДДДЩ         і
                            і     ЪДДДї         і
                            АДДДДДґshrі<ДДДДДДДДЩ
                                  АДДДЩ


         B.Pascal 7 & Objects/LR      - 97 -


             Приведем несколько примеров термов:

             Х * Y
             Z / (1 - Z)
             Done or Error
             (Х <= Y) and (Y < Z)

             В простых выражениях к термам применяются  операции сложения
        и присваивания знака:

                                           ЪДДДДДДДї
                простое выражение ДДДДДДДД>і терм  ГДДДВДДДД>
                                     ^     АДДДДДДДЩ   і
                                     і     ЪДДДї       і
                                     ГДДДДДґ + і<ДДДДДДґ
                                     і     АДДДЩ       і
                                     і     ЪДДДї       і
                                     ГДДДДДґ - і<ДДДДДДґ
                                     і     АДДДЩ       і
                                     і     ЪДДДї       і
                                     ГДДДДДґ orі<ДДДДДДі
                                     і     АДДДЩ       і
                                     і     ЪДДДї       і
                                     АДДДДДґxorі<ДДДДДДЩ
                                           АДДДЩ

             Приведем несколько примеров простых выражений:

             Х + Y
             -Х
             Hue1 + Hue2
             I * J + 1


         B.Pascal 7 & Objects/LR      - 98 -


             В выражениях к простым выражениям применяются операции отно-
        шения.

                        ЪДДДДДДДДДї
         выражение ДДДД>і простое ГДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД>
                        івыражениеі  і                           ^
                        АДДДДДДДДДЩ  і  ЪДДДї       ЪДДДДДДДДДї  і
                                     ГД>і < ГДДДДДД>і простое ГДДЩ
                                     і  АДДДЩ  ^    івыражениеі
                                     і  ЪДДДї  і    АДДДДДДДДДЩ
                                     ГД>і<= ГДДґ
                                     і  АДДДЩ  і
                                     і  ЪДДДї  і
                                     ГД>і > ГДДґ
                                     і  АДДДЩ  і
                                     і  ЪДДДї  і
                                     ГД>і>= ГДДґ
                                     і  АДДДЩ  і
                                     і  ЪДДДї  і
                                     ГД>і = ГДДґ
                                     і  АДДДЩ  і
                                     і  ЪДДДї  і
                                     ГД>і<> ГДДґ
                                     і  АДДДЩ  і
                                     і  ЪДДДї  і
                                     АД>іin ГДДЩ
                                        АДДДЩ

             Приведем некоторые примеры выражений:

             Х = 1.5
             Done <> Error
             (I < J) = (J < К)
             C in Huel



         B.Pascal 7 & Objects/LR      - 99 -

                                    Операции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Операции подразделяются на арифметические операции, логичес-
        кие операции,  операции со строками,  операции  над  множествами,
        операции отношения и операцию @ (операция получения адреса).

                             Арифметические операции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В следующей таблице приведены типы  операндов  и  результаты
        для бинарных и унарных арифметических операций:

                        Бинарные арифметические операции      Таблица 6.2
        ЪДДДДДДДДДДДВДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДї
        і  Операция і  Действие    і  Типы операндов  і  Тип результата і
        ГДДДДДДДДДДДЕДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДґ
        і       +   і  Сложение    і     Целый        і      Целый      і
        і           і              і  Вещественный    і   Вещественный  і
        ГДДДДДДДДДДДЕДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДґ
        і       -   і  Вычитание   і     Целый        і      Целый      і
        і           і              і  Вещественный    і   Вещественный  і
        ГДДДДДДДДДДДЕДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДґ
        і       *   і  Умножение   і     Целый        і      Целый      і
        і           і              і  Вещественный    і   Вещественный  і
        ГДДДДДДДДДДДЕДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДґ
        і      /    і  Деление     і     Целый        і   Вещественный  і
        і           і              і  Вещественный    і   Вещественный  і
        ГДДДДДДДДДДДЕДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДґ
        і     div   і Целочисленноеі                  і                 і
        і           і  деление     і     Целый        і      Целый      і
        ГДДДДДДДДДДДЕДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДґ
        і     mod   і  Остаток     і     Целый        і      Целый      і
        АДДДДДДДДДДДБДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДЩ

                   Примечание: Операция + используется также,  как опера-
              ция для работы со строками и множествами. Операции +, - и *
              используются также для операций над множествами.



         B.Pascal 7 & Objects/LR     - 100 -

                Унарные арифметические операции
                                                            Таблица 6.3
        ЪДДДДДДДДДДДВДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДї
        і  Операция і   Действие   і  Тип операнда    і Тип результата  і
        ГДДДДДДДДДДДЕДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДґ
        і       +   і  Сохранение  і      Целый       і     Целый       і
        і           і    знака     і   Вещественный   і   Вещественный  і
        ГДДДДДДДДДДДЕДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДґ
        і       -   і   Отрицание  і      Целый       і     Целый       і
        і           і    знака     і   Вещественный   і   Вещественный  і
        АДДДДДДДДДДДБДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДЩ

             Любая операция,  включающая операнд,  тип которого  является
        подмножеством порядкового типа, обрабатывается также, как если бы
        он был порядкового типа.

             Если оба операнда в операциях +,  -, *, div или моd являются
        операндами целого типа, то тип результата будет таким же, как об-
        щий тип обоих операндов.  (Определение общего типа см.  в разделе
        "Целый тип" в Главе 3).

             Если один или более операндов в операциях +,  -, или * имеют
        вещественный тип,  то тип результата будет вещественным, если ис-
        пользована директива компилятора {$N-},  или типом  с  повышенной
        точностью при использовании директивы компилятора {$N+}.

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

             Значение выражения  х/у  всегда  будет  вещественного   типа
        (real) или с повышенной точностью (extended), независимо от типов
        операндов. Если у равно 0, то результат будет ошибочным.

             Значение выражение i div j представляет собой математическое
        частное от i/j,  округленное в меньшую сторону до значения целого
        типа. Если j равно 0, результат будет ошибочным.

             Операция mod  возвращает  остаток,  полученный путем деления
        двух ее операндов, то есть:

             i mod j = i - (i div j) * j

             Знак результата операции mod будет тем же, что и знак i. Ес-
        ли j равно нулю, то результатом будет ошибка.



         B.Pascal 7 & Objects/LR     - 101 -

                               Логические операции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Типы логических операций показаны в Таблице 6.4.

                               Логические операции            Таблица 6.4
        ЪДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДї
        і Операция і     Действие        іТипы операндові Тип результатаі
        ГДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДґ
        і     not  і Отрицание (битовое) і  Целый       і    Целый      і
        і     and  і    И (битовое)      і  Целый       і    Целый      і
        і     or   і    ИЛИ (битовое)    і  Целый       і    Целый      і
        і     xor  і Исключающее ИЛИ     і  Целый       і    Целый      і
        і          і    (битовое)        і              і               і
        і     shl  і   Сдвиг влево       і  Целый       і    Целый      і
        і     shr  і   Сдвиг вправо      і  Целый       і    Целый      і
        АДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДЩ

                   Примечание: Операция not является унарной операцией.

             Если операндом операции not является операнд целого типа, то
        результат будет также целого типа.

             Если оба  операнда в операциях or,  and или xor целого типа,
        то тип результата будет таким же, как тип обоих операндов.

             Операции i shl j и i shr j сдвигают  значение  i  влево  или
        вправо на j битов. Тип результата будет таким же, как тип i.


                               Булевские операции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Типы операндов и результат для булевских операций показаны в
        Таблице 6.5.

                         Таблица 6.5 Булевские операции
        ЪДДДДДДДДДДВДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДї
        і Операция і  Действие        і Типы операндов  і Тип результатаі
        ГДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДґ
        і     not  і     Отрицание    і   Булевский     і     Булевский і
        і     and  і   Логическое И   і   Булевский     і     Булевский і
        і     or   і  Логическое ИЛИ  і   Булевский     і     Булевский і
        і     xor  і   Логическое     і                 і               і
        і          і исключающее ИЛИ  і   Булевский     і     Булевский і
        АДДДДДДДДДДБДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДЩ

                   Примечание: Операция not является унарной операцией.

             Результаты этих операций соответствуют обычной булевой логи-
        ке. Например, выражение a and b является истинным (принимает зна-
        чение Тruе) только в том случае,  если оба операнда a и  b  имеют
        истинное значение (Тruе).

         B.Pascal 7 & Objects/LR     - 102 -


             В Borland Pascal поддерживаются две различные модели генера-
        ции  кода  для операций or и and - полное вычисление и вычисление
        по короткой схеме (частичное вычисление).

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

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

             while (I<=Lenght(S)) and (S[I]<>' ') do
                Inc(I);
             while (P<>nil) and (P^.Value<>5) do
                P:=P^.Next;

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

             Схему вычисления можно задавать с помощью директивы компиля-
        тора $B.  Значением по умолчанию является состояние  {$B-}  (пока
        оно не будет изменено с помощью "меню" возможностей компилятора).
        В этом случае генерируется код с вычислением по короткой схеме. В
        случае директивы {$B+} генерируется код с полным вычислением.

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




         B.Pascal 7 & Objects/LR     - 103 -

                              Операция со строками
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Типы операндов и результаты для операции со строками показа-
        ны в Таблице 6.6.

                              Операции со строками            Таблица 6.6
        ЪДДДДДДДДДДДВДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДї
        і Операция  і Действие     і  Типы операндов     іТип результатаі
        ГДДДДДДДДДДДЕДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДґ
        і      +    і Конкатенация і    Строковый,       і Строковый    і
        і           і              і  символьный или     і              і
        і           і              іупакованный строковыйі              і
        АДДДДДДДДДДДБДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДЩ

             Borland Pascal позволяет использовать операцию + для объеди-
        нения двух строковых операндов. Результатом операции s + t, где s
        и t имеют строковый тип,  символьный тип (Char)  или  упакованный
        строковый тип,  будет конкатенация s и t. Результат будет совмес-
        тим с любым строковым типом (но не с символьным Char и не с  упа-
        кованным строковым типом).  Если длина результирующей строки пре-
        вышает 255 символов, то она усекается до 255 символов.

         B.Pascal 7 & Objects/LR     - 104 -


                      Операции над символьными указателями
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Расширенный синтаксис  (разрешенный по директиве компилятора
        {$X+}) поддерживает несколько операций с  указателями  на  PChar.
        Для увеличения и уменьшения смещения указателя можно использовать
        операции + и -.  Минус можно также  использовать  для  вычисления
        расстояния (разности) между двумя символьными указателями. Если P
        и Q - это значения типа PChar,  а I - значение типа Word,  то до-
        пустимы следующие конструкции:

                          Допустимые конструкции PChar        Таблица 6.7
        ЪДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Операция   і                    Результат                  і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    P + I      і       Сложение I со смещением P.              і
        і    I + P      і       Сложение I со смещением P.              і
        і    P - I      і       Вычитание I из смещения P.              і
        і    P - Q      і       Вычитает смещение Q из смещения P.      і
        АДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Операции P  + I и I + P складывает I c адресом,  заданным P,
        создавая указатель, ссылающийся на I символов после P. Операция P
        - I вычитает I из адреса, заданного P, создавая указатель, ссыла-
        ющийся на I символов перед P.

             Операция P - Q вычитает расстояние между Q (младший адрес) и
        P (старший адрес),  создавая в результате значение типа Word, по-
        казывающее число символов между Q и P.  Эта операция подразумева-
        ет, что P и Q ссылаются на один символьный массив.  Если два сим-
        вольный указателя ссылаются на разные массивы, то результат будет
        не определен.



         B.Pascal 7 & Objects/LR     - 105 -

                            Операции над множествами
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Типы операндов для операций над множествами показаны в  Таб-
        лице 6.7.

                            Операции над множествами          Таблица 6.7
        ЪДДДДДДДДДДДДДДДВДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Операция   і  Действие   і              Типы операндов     і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і       +       і Объединение і Множества с совместимыми типами і
        і       -       і  Разность   і Множества с совместимыми типами і
        і       *       і Пересечение і Множества с совместимыми типами і
        АДДДДДДДДДДДДДДДБДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Результаты операций соответствуют правилам логики  работы  с
        множествами:

             1.  Порядковое  значение  c  содержится  в a+b только тогда,
                 когда оно содержится в a или в b.

             2.  Порядковое значение c содержится  в  a-b  только  тогда,
                 когда оно содержится в a и не содержится в b.

             3.  Порядковое  значение  c  содержится  в a*b только тогда,
                 когда он содержится в обоих множествах a и b.

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



         B.Pascal 7 & Objects/LR     - 106 -

                               Операции отношения
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Типы операндов  и  результаты операций отношения приведены в
        Таблице 6.8.

                         Таблица 6.8 Операции отношения
        ЪДДДДДДДДДВДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДї
        і Операцияі  Действие  і    Типы операндов      і Тип результатаі
        ГДДДДДДДДДЕДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДґ
        і     =   і     Равно  і Совместимый простой,   і    Булевский  і
        і         і            і указатель, множествен- і               і
        і         і            і ный строковый или упа- і               і
        і         і            і кованный строковый     і               і
        ГДДДДДДДДДЕДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДґ
        і    <>   і  Не равно  і Совместимый простой,   і    Булевский  і
        і         і            і указатель, множествен- і               і
        і         і            і ный, строковый или упа-і               і
        і         і            і кованный строковый     і               і
        ГДДДДДДДДДЕДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДґ
        і    <    і Меньше чем і Совместимый простой,   і    Булевский  і
        і         і            і указатель, множествен- і               і
        і         і            і ный, строковый или упа-і               і
        і         і            і кованный строковый     і               і
        ГДДДДДДДДДЕДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДґ
        і    >    і Больше чем і Совместимый простой,   і    Булевский  і
        і         і            і указатель, множествен- і               і
        і         і            і ный строковый или упа- і               і
        і         і            і кованный строковый     і               і
        ГДДДДДДДДДЕДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДґ
        і   <=    і  Меньше    і Совместимый простой,   і    Булевский  і
        і         і или равно  і указатель, множествен- і               і
        і         і            і ный строковый или упа- і               і
        і         і            і кованный строковый     і               і
        ГДДДДДДДДДЕДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДґ
        і   >=    і  Больше    і Совместимый простой,   і    Булевский  і
        і         і или равно  і указатель, множествен- і               і
        і         і            і ный строковый или упа- і               і
        і         і            і кованный строковый     і               і
        ГДДДДДДДДДЕДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДґ
        і   <=    іПодмножествоі Множества совместимых  і     Булевский і
        і         і            і      типов             і               і
        ГДДДДДДДДДЕДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДґ
        і   >=    іНадмножествоі Множества совместимых  і     Булевский і
        і         і            і      типов             і               і
        ГДДДДДДДДДЕДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДґ
        і   in    і  Элемент   і Левый операнд: любой   і     Булевский і
        і         і  множества і перечислимый тип t;    і               і
        і         і            і правый: множество,     і               і
        і         і            і совместимое с t.       і               і
        АДДДДДДДДДБДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 107 -

                             Сравнение простых типов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Когда операции =,  <>,  <, >, >= или <= применяются для опе-
        рандов простых типов,  то это должны быть совместимые типы. Одна-
        ко, если  один  операнд  имеет вещественный тип,  то другой может
        быть целого типа.


                                 Сравнение строк
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Операции отношения =,  <>,  <, >, >= или <= могут применятся
        для сравнения строк согласно порядку расширенного набора символов
        кода  ASСII.  Любые два значения строковых данных можно сравнить,
        поскольку все значения строковых данных совместимы.

             Значения символьного типа совместимы со значениями строково-
        го  типа,  и  при их сравнении символьное значение обрабатывается
        как строковое значение с длиной 1.  Когда со значением строкового
        типа  сравнивается упакованное строковое значение из N элементов,
        то оно обрабатывается, как значение строкового типа длиной N.


                           Сравнение упакованных строк
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Операции отношения =,  <>,  <, >, >= или <= могут применятся
        также для двух упакованных значений строкового типа, если они со-
        держат одинаковое число элементов.  Если число элементов равно n,
        то операция соответствует сравнению двух строк, каждая из которых
        имеет длину n.


                              Сравнение указателей
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Операции = и <> могут использоваться для сравнения операндов
        типа указатель. Два указателя равны только в том случае, если они
        ссылаются на один и тот же объект.



         B.Pascal 7 & Objects/LR     - 108 -

                         Сравнение символьных указателей
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             При разрешении по директиве компилятора  {$X+}  расширенного
        синтаксиса операции =,  <>,  <,  >,  >= или <= могут применятся к
        значениям PChar.  Заметим,  однако,  что эти  операции  отношения
        предполагают, что  два сравниваемые указателя ссылаются на один и
        тот же символьный массив..  По этой причине в сравнении участвуют
        только смещения двух значений-указателей. Если указатели ссылают-
        ся на разные символьные массивы, результат будет не определен.


                               Сравнение множеств
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Если операндами являются множества a и b,  то при их сравне-
        нии получаются следующие результаты:

             1.  Выражение a=b истинно (= True) только когда a и b содер-
                 жат одни и те же элементы, в противном случае a<>b.

             2.  Выражение a = b истинно,  когда каждый элемент множества
                 а является также элементом множества b.

             3.  Выражение a = b истинно,  когда каждый элемент множества
                 b является также элементом множества a.


                     Проверка на принадлежность к множеству
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Операция in возвращает истинное значение (True),  когда зна-
        чение элемента порядкового типа является элементом операнда  мно-
        жественного  типа,  в  противном  случае  он  возвращает значение
        False.



         B.Pascal 7 & Objects/LR     - 109 -

                                   Операция @
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Операция @ используется в адресном коэффициенте для вычисле-
        ния адреса переменной,  процедуры,  функции или метода. В Таблице
        6.9 показан операнд и типы результата.

         адресный коэффициент
         і  ЪДДДї        ЪДДДДДДДДДДДДДДДДДДДДДДї
         АДДі @ ГДДВДДДДДі ссылка не переменную ГДДДДДДДДДДДДДДДДДДДДДДД>
            АДДДЩ  і     АДДДДДДДДДДДДДДДДДДДДДДЩ              ^
                   і     ЪДДДДДДДДДДДДДДДДДДДДДДДДДї           і
                   ГДДДД>і идентификатор процедуры ГДДДДДДДДДДДґ
                   і     АДДДДДДДДДДДДДДДДДДДДДДДДДЩ           і
                   і     ЪДДДДДДДДДДДДДДДДДДДДДДДї             і
                   ГДДДД>і идентификатор функции ГДДДДДДДДДДДДДґ
                   і     АДДДДДДДДДДДДДДДДДДДДДДДЩ             і
                   і     ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї   і
                   АДДДД>і уточненный идентификатор метода ГДДДЩ
                         АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                           Операция создания указателя        Таблица 6.9
        ЪДДДДДДДДДДДДВДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДї
        і   Операция і Действие  і   Типы операндов      іТип результатаі
        ГДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДґ
        і       @    і Получение і Ссылка на переменную, і   Указатель  і
        і            і указателя і процедуру или иденти- і  (совмести-  і
        і            і           і фикатор функции.      і  мый с nil)  і
        АДДДДДДДДДДДДБДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДЩ

             Операция @ возвращает адрес операнда,  то есть строит значе-
        ние-указатель, ссылающееся на этот операнд.




         B.Pascal 7 & Objects/LR     - 110 -

                     Использование операции @ для переменной
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Использование операции @ для обычной переменной (не парамет-
        ра) не вызывает никаких сложностей.  Применение @ к ссылке на пе-
        ременную возвращает указатель на переменную. Введем описания:

             type
               TwoChar = array[0..1] of char;
             var
               Int: integer;
               TwoCharPtr: ^TwoChar;

        тогда оператор:

             TwoCharPtr := @Int;

        приводит к   тому,   что   TwoCharPtr  для  получения  ссылки  на
        TwoCharPtr^ становится повторной интерпретацией значения Int, как
        если бы оно было символьным массивом array[0..1].

             Тип получаемого в результате указатель управляется  директи-
        вой компилятора  $T:  в  состоянии {$T-} (по умолчанию) типом ре-
        зультата будет Pointer.  Другими словами,  результат ом  является
        нетипизированный указатель,  совместимый  со всеми другими типами
        указателей. В состоянии {$T+} типом результата будет ^T,  где T -
        тип ссылки на переменную.  То есть тип результата будет совместим
        со всеми другими указателями на тип этой переменной.

                   Примечание: К использованию операции @  с  процедурным
              типом  применяются  специальные  правила.  См.  ниже раздел
              "Процедурный типы в выражениях".




         B.Pascal 7 & Objects/LR     - 111 -

                            Использование операции @
                      для процедуры или функции или метода
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Вы можете применять операцию @ к процедуре,  функции или ме-
        тоду. При этом вы получите указатель на точку входа подпрограммы.
        Независимо от состояния $T, типом полученного в результате указа-
        теля всегда  будет Pointer.  Другими словами,  результатом всегда
        является нетипизированный указатель, совместимый со всеми другими
        ссылочными типами.

             При применении операции @ к методу метод должен задаваться с
        помощью уточненного идентификатора (идентификатора объектного ти-
        па, за которым следует точка и идентификатор метода).


                                 Вызовы функции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Вызовы функции приводят к активизации  функции,  заданной  с
        помощью идентификатора функции.  Идентификатором функции является
        любой идентификатор, использованный для обозначения функции.

             Если в соответствующем описании  функции  содержится  список
        формальных параметров то в вызове функции должен содержаться спи-
        сок фактических параметров.  Каждый параметр подставляется вместо
        соответствующего  формального  параметра в соответствии с набором
        правил, который вводится в Главе 9 ("Процедуры и функции").

                   Примечание: См.  выше разделы  "Активизация  методов",
              "Активизация уточненных методов" и "Процедурные типы".

                           ЪДДДДДДДДДДДДДї
         вызов функции ДВД>іидентификаторГДВВДДДДДДДДДДДДДДДДДДДДДДДДДДД>
                        і  і   функции   і іі                         ^
                        і  АДДДДДДДДДДДДДЩ іі   ЪДДДДДДДДДДДДДДДДДДї  і
                        і  ЪДДДДДДДДДДДДДї іАДД>ісписок фактическихГДДЩ
                        ГД>і десигнатор  ГДґ    і  параметров      і
                        і  і   метода    і і    АДДДДДДДДДДДДДДДДДДЩ
                        і  АДДДДДДДДДДДДДЩ і
                        і  ЪДДДДДДДДДДДДДї і
                        і  і  уточненный і і
                        ГД>і  десигнатор ГДґ
                        і  і    метода   і і
                        і  АДДДДДДДДДДДДДЩ і
                        і  ЪДДДДДДДДДДДДДї і
                        АД>і  ссылка на  ГДЩ
                           і  переменную і
                           АДДДДДДДДДДДДДЩ


         B.Pascal 7 & Objects/LR     - 112 -


                                 ЪДДДї      ЪДДДДДДДДДДДї     ЪДДДї
         список фактических ДДДД>і ( ГДДДДД>іфактическийГДДВД>і ) ГДДД>
         параметров              АДДДЩ   ^  і параметр  і  і  АДДДЩ
                                         і  АДДДДДДДДДДДЩ  і
                                         і   ЪДДДї         і
                                         АДДДґ , і<ДДДДДДДДЩ
                                             АДДДЩ

                                    ЪДДДДДДДДДДДДї
         фактический параметр ДДВДД>і выражение  ГДДДДДДДД>
                                і   АДДДДДДДДДДДДЩ   ^
                                і   ЪДДДДДДДДДДДДї   і
                                АДД>і ссылка на  ГДДДЩ
                                    і переменную і
                                    АДДДДДДДДДДДДЩ

             Приведем некоторые примеры вызовов функций:

             Sum(A,63)
             Maximum(147,J)
             Sin(X+Y)
             Eof(F)
             Volume(Radius, Height)

             В режиме  расширенного синтаксиса ($X+) вызовы функций можно
        использовать в качестве  операторов,  то  есть  результат  вызова
        функции может отбрасываться.



         B.Pascal 7 & Objects/LR     - 113 -

                               Описатели множества
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Описатель множества  определяет значения множественного типа
        и получается путем записи  выражений,  заключенных  в  квадратные
        скобки ([]). Каждое выражение определяет значение множества.

                       ЪДДДї                            ЪДДДї
         описатель ДДД>і [ ГДДВДДДДДДДДДДДДДДДДДДДДДДДД>і ] ГДДД>
         множества     АДДДЩ  і    ЪДДДДДДДДДДДДї    ^  АДДДЩ
                              АДДД>і   группа   ГДДВДЩ
                                ^  і  элементов і  і
                                і  АДДДДДДДДДДДДЩ  і
                                і    ЪДДДї         і
                                АДДДДґ , і<ДДДДДДДДЩ
                                     АДДДЩ

                             ЪДДДДДДДДДДДї
         группа элементов ДД>і выражение ГДДВДДДДДДДДДДДДДДДДДДДДДДДДДДД>
                             АДДДДДДДДДДДЩ  і                       ^
                                            і  ЪДДї   ЪДДДДДДДДДДДї і
                                            АД>і..ГДД>і выражение ГДЩ
                                               АДДЩ   АДДДДДДДДДДДЩ

             Обозначение [ ] означает пустое множество, тип которого сов-
        местим  по  присваиванию  с типом любого множества.  Любая группа
        элементов,  описанная,  как х..у,  объявляет элементами множества
        все значения в диапазоне х..у.  Если х больше,  чем у, то х..у не
        описывает никаких элементов и [x..y] обозначает пустое множество.

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

             Приведем некоторые примеры описателей множеств:

             [red, C, green]
             [1,5,10..K mod 12, 13, 23]
             ['A'..'Z', 'a'..'z', Chr(Digit+48)]



         B.Pascal 7 & Objects/LR     - 114 -

                            Приведение типа значений
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Тип выражения можно изменить на другой тип с помощью  приве-
        дения типа значений.

                          ЪДДДДДДДДДДДДДї   ЪДДДї   ЪДДДДДДДДДї   ЪДДДї
         приведение   ДДД>іидентификаторГДД>і ( ГДД>івыражениеГДД>і ) ГД>
         типа значения    і    типа     і   АДДДЩ   АДДДДДДДДДЩ   АДДДЩ
                          АДДДДДДДДДДДДДЩ

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

             Синтаксис приведения типа значений почти совпадает с синтак-
        сисом приведения типа переменных (см. раздел "Приведение типа пе-
        ременных" в Главе 5).  Однако при приведении типа значений опера-
        ции производятся со значениями,  а  не  с  переменными  и,  таким
        образом, могут не участвовать в ссылках на переменные. То есть за
        приведением типа значения не обязательно следуют квалификаторы. В
        частности, приведение типа значений не должно встречаться в левой
        части оператора присваивания.

             Некоторые примеры приведения типа значений включают  в себя:

             Intereg('A')
             Char(48)
             Boolean(0)
             Color(2)
             IntPtr(@Buffer)
             BytePtr(Ptr($40,$49))



         B.Pascal 7 & Objects/LR     - 115 -

                          Процедурные типы в выражениях
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В общем случае использование процедурной переменной в опера-
        торе  или выражении означает вызов процедуры или функции,  храня-
        щейся в этой переменной. Однако, имеется исключение. Когда компи-
        лятор видит,  что процедурная переменная находится в левой  части
        оператора присваивания,  он знает, что правая часть должна предс-
        тавлять собой процедурное значение. Рассмотрим в качестве примера
        следующую программу:

             type
                IntFunc = function: Integer;
             var
                F: IntFunc;
                N: Integer;

             function ReadInt: Integer; far;
             var
                I: Integer;
             begin
                Read(I);
                ReadInt := I;
             end;
             begin
                F := ReadInt;      { присваивание процедурного значения }
                N := ReadInt;      { присваивание результата функции }
             end.

             Первый оператор  основной  программы присваивает процедурное
        значение (адрес процедуры) ReadInt процедурной переменной F, вто-
        рой оператор вызывает ReadInt и присваивает N возвращаемое значе-
        ние.  Различие между получением процедурного значения или вызовом
        функции осуществляется по типу переменной,  которой присваивается
        значение (F или N).

             К сожалению,  есть ситуации, когда компилятор не может опре-
        делить из контекста желаемое действие. Например, в следующем опе-
        раторе для компилятора не очевидно,  что нужно сделать:  сравнить
        процедурное  значение в F с процедурным значением ReadInt,  чтобы
        определить,  что F указывает в данный момент на ReadInt, или выз-
        вать F и ReadInt, а затем сравнить возвращаемые значения:

             if F = ReadInt then
               WriteLn('Equal');

             Однако, стандартный синтаксис Паскаля определяет,  что вхож-
        дение  в  выражение  идентификатора  функции  означает вызов этой
        функции,  поэтому в результате предыдущего оператора будет выпол-
        нен  вызов  F и ReadInt,  а затем будут сравниваться возвращаемые
        значения.  Чтобы сравнить процедурное значение в F с  процедурным
        значением в ReadInt, нужно использовать следующую конструкцию:


         B.Pascal 7 & Objects/LR     - 116 -

             if @F = @ReadInt then
               WriteLn('Equal');

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

             Операция @ часто используется при  присваивании  процедурной
        переменной нетипизированного значения-указателя.  Например, опре-
        деленная в Windows (в  модуле  WinProcs)  функция  GetProcAddress
        возвращает адрес  экспортируемой функции в DLL как нетипизирован-
        ной значение-указатель. С помощью операции @ вызов GetProcAddress
        можно присвоить процедурной переменной:

             type
               TStrComp = function(Str1, Str2: PChar): Integer;
             var
               StrComp: TStrComp:
                 .
                 .
                 .
             begin
              .
              .
              .
              @StrComp := GetProcAddress(KernelHandle, 'Lstrcmpi');
                  .
                  .
                  .
             end.

             Чтобы получить адрес в памяти процедурной переменной,  а  не
        адрес,  в  ней  записанный,  используйте двойную операцию @ (@@).
        Например,  @P означает преобразование P в нетипизированный указа-
        тель-переменную,  в  @@P  означает возвращение физического адреса
        переменной P.



         B.Pascal 7 & Objects/LR     - 117 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                               Глава 7. Операторы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

         оператор ДДВДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДД>
                    і  ЪДДДДДї   ЪДДДї ^ і   ЪДДДДДДДДДДДДДДДДї  ^
                    АД>іметкаГДД>і : ГДЩ ГДД>іпростой операторГДДґ
                       АДДДДДЩ   АДДДЩ   і   АДДДДДДДДДДДДДДДДЩ  і
                                         і   ЪДДДДДДДДДДДДДДДДї  і
                                         АДД>і  структурный   ГДДЩ
                                             і   оператор     і
                                             АДДДДДДДДДДДДДДДДЩ

             Метка - это последовательность цифр в диапазоне от 0 до 9999
        или идентификатор.

             Существует два основных вида операторов: простые операторы и
        структурные операторы.


                                Простые операторы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                                   ЪДДДДДДДДДДДДДДДДДДДДДї
         простой оператор ДДДДВДДД>іоператор присваиванияГДДДДДДД>
                              і    АДДДДДДДДДДДДДДДДДДДДДЩ   ^
                              і    ЪДДДДДДДДДДДДДДДДДДДДДї   і
                              ГДДД>і оператор процедуры  ГДДДґ
                              і    АДДДДДДДДДДДДДДДДДДДДДЩ   і
                              і    ЪДДДДДДДДДДДДДДДДДДДДДї   і
                              АДДД>і оператор перехода   ГДДДЩ
                                   АДДДДДДДДДДДДДДДДДДДДДЩ




         B.Pascal 7 & Objects/LR     - 118 -

                              Оператор присваивания
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                           ЪДДДДДДДДДДДї       ЪДДї   ЪДДДДДДДДДї
         оператор ДДДДДВДД>іссылка на  ГДДДДДД>і:=ГДД>івыражениеГДД>
         присваивания  і   іпеременную і   ^   АДДЩ   АДДДДДДДДДЩ
                       і   АДДДДДДДДДДДЩ   і
                       і   ЪДДДДДДДДДДДДДї і
                       АДД>іидентификаторГДЩ
                           і   функции   і
                           АДДДДДДДДДДДДДЩ

             Выражение должно быть совместимо по присваиванию с типом пе-
        ременной  или  типом значения,  возвращаемого функцией в качестве
        результата (см. раздел "Совместимость типов" в Главе 4).

             Приведем некоторые примеры операторов присваивания:

             X := Y + Z
             Done := (I >= 1) and (I < 100);
             Huel := [blue, Succ(C)];
             I := Sqr(J) - I * K;

                          Присваивания объектного типа

             Правила совместимости по присваиванию объектных типов позво-
        ляют присваивать  экземпляру  объекта экземпляр любого из его до-
        черних типов.  Такое  присваивание  представляет  собой  проекцию
        потомка на  пространство  его предка.  В примере исходного кода в
        Главе 4 с учетом экземпляра F типа TField  и  экземпляра  Z  типа
        TZipField присваивание  F := Z копирует только поля X,  Y,  Len и
        Name.

             Присваивание экземпляру объектного  типа  не  инициализирует
        экземпляр. Например, в предыдущем примере присваивание F := Z оз-
        начает, что вызов конструктора для F можно опустить.



         B.Pascal 7 & Objects/LR     - 119 -

                               Операторы процедуры
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Оператор процедуры определяет активизацию процедуры, обозна-
        ченную  с помощью идентификатора процедуры.  Если соответствующее
        описание процедуры содержит список формальных параметров, то опе-
        ратор  процедуры должен содержать в себе соответствующий ему спи-
        сок фактических параметров (параметры,  список которых приводится
        в  определении,  являются формальными параметрами,  а в операторе
        вызова процедуры они являются фактическими параметрами).  При вы-
        зове  происходит передача фактических параметров формальным пара-
        метрам.

                        ЪДДДДДДДДДДДДДї
         оператор  ДДВД>іидентификаторГДВВДДДДДДДДДДДДДДДДДДДДДДДДДД>
         процедуры   і  і  процедуры  і іі  ЪДДДДДДДДДДДДДДДДДДї ^
                     і  АДДДДДДДДДДДДДЩ іАД>ісписок фактическихГДЩ
                     і  ЪДДДДДДДДДДДДДї і   і  параметров      і
                     ГД>і десигнатор  ГДґ   АДДДДДДДДДДДДДДДДДДЩ
                     і  і  метода     і і
                     і  АДДДДДДДДДДДДДЩ і
                     і  ЪДДДДДДДДДДДДДї і
                     ГД>і  уточненный ГДґ
                     і  і  десигнатор і і
                     і  і  метода     і і
                     і  АДДДДДДДДДДДДДЩ і
                     і  ЪДДДДДДДДДДДДДї і
                     АД>і  ссылка на  ГДЩ
                        і переменную  і
                        АДДДДДДДДДДДДДЩ

             Приведем некоторые примеры операторов процедур:

             PrintHeaing;
             Transpose(A,N,M);
             Fin(Name,Address);



         B.Pascal 7 & Objects/LR     - 120 -

                               Операторы перехода
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Оператор перехода goto вызывает передачу управления операто-
        ру, которому предшествует метка, указанная в данном операторе пе-
        рехода.  Синтаксическая схема оператора перехода имеет  следующий
        вид:

                                       ЪДДДДї    ЪДДДДДї
                 оператор перехода ДДД>іgotoГДДД>іметкаГДДД>
                                       АДДДДЩ    АДДДДДЩ

             При использовании оператора перехода должны соблюдаться сле-
        дующие правила:

             1.  Метка,  которая указывается в операторе перехода, должна
                 находиться в том же блоке или модуле, что и сам оператор
                 перехода.  Другими словами,  не допускаются переходы  из
                 процедуры или функции или внутрь нее.

             2.  Переход извне внутрь структурного оператора (то есть пе-
                 реход  на более глубокий уровень вложенности) может выз-
                 вать непредсказуемые эффекты,  хотя компилятор не выдает
                 сообщения об ошибке. Например, вы не должны переходить в
                 тело цикла for.

                   Примечание: Хорошая практика программирования  требует
              минимального использования переходов.

                              Структурные операторы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                                    ЪДДДДДДДДДДДДДДДДДДДДДДДї
              структурный ДДДДВДДДД>і  составной оператор   ГДДДДДДД>
              оператор        і     АДДДДДДДДДДДДДДДДДДДДДДДЩ   ^
                              і     ЪДДДДДДДДДДДДДДДДДДДДДДДї   і
                              ГДДДД>і   условный оператор   ГДДДґ
                              і     АДДДДДДДДДДДДДДДДДДДДДДДЩ   і
                              і     ЪДДДДДДДДДДДДДДДДДДДДДДДї   і
                              ГДДДД>і    оператор цикла     ГДДДґ
                              і     АДДДДДДДДДДДДДДДДДДДДДДДЩ   і
                              і     ЪДДДДДДДДДДДДДДДДДДДДДДДї   і
                              АДДДД>і оператор над записями ГДДДЩ
                                    АДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 121 -

                               Составные операторы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                             ЪДДДДДї       ЪДДДДДДДДї        ЪДДДї
             составной  ДДДД>іbeginГДДДДДД>іоператорГДДДДВДД>іendГДД>
             оператор        АДДДДДЩ   ^   АДДДДДДДДЩ    і   АДДДЩ
                                       і     ЪДДДї       і
                                       АДДДДДґ ; і<ДДДДДДЩ
                                             АДДДЩ

             Приведем пример составного оператора:

             begin
               Z := X;
               X := Y;
               Y := Z;
             end;

                               Условные операторы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Условные операторы  позволяют выбрать для выполнения один из
        составных операторов (или не выбрать ни одного).

                                       ЪДДДДДДДДДДДДДДДї
              условный оператор  ДДВДД>і оператор if   ГДДДДДДД>
                                   і   АДДДДДДДДДДДДДДДЩ   ^
                                   і   ЪДДДДДДДДДДДДДДДї   і
                                   АДД>і оператор case ГДДДЩ
                                       АДДДДДДДДДДДДДДДЩ




         B.Pascal 7 & Objects/LR     - 122 -

                              Оператор условия (if)
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Синтаксис оператора if можно представить  следующим образом:

                       ЪДДї   ЪДДДДДДДДДї   ЪДДДДї   ЪДДДДДДДДї
         оператор if Д>іifГДД>івыражениеГДД>іthenГДД>іоператорГДДВДДї
                       АДДЩ   АДДДДДДДДДЩ   АДДДДЩ   АДДДДДДДДЩ  і  і
                                        ЪДДДДДДДДДДДДДДДДДДДДДДДДЩ  і
                                        і   ЪДДДДї   ЪДДДДДДДДї     v
                                        АДД>іelseГДД>іоператорГДДДДДДДДД>
                                            АДДДДЩ   АДДДДДДДДЩ

             В выражении должен получаться результат, имеющий стандартный
        булевский тип.  Если результатом выражения является истинное зна-
        чение (True), то выполняется оператор, следующий за ключевым сло-
        вом then.

             Если результатом  выражения  является  значение False и при-
        сутствует ключевое слово else,  то выполнятся оператор, следующий
        за ключевым словом else. Если ключевое слово else отсутствует, то
        никакой оператор не выполняется.

             Синтаксическая неоднозначность, возникающая в конструкции:

             if e1 then e2 else e3

        разрешается путем следующей интерпретации этой конструкции:

             if e1 then
             begin
               if e2 then
                  s1
               else
                  s2
             end

                   Примечание: В  предшествующем операторе else двоеточие
              не указывается.

             В общем случае ключевое слово else связывается  с  ближайшим
        ключевым  словом  if,  которое  еще  не связано с ключевым словом
        else.

             Приведем два примера оператора if:

              if X < 1.5 then
                Z := X+Y
              else
                Z := 1.5;

               if P1 <> nil then
                 P1 := P1^.father;

         B.Pascal 7 & Objects/LR     - 123 -



                            Оператор варианта (case)
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Оператор варианта  (casе) состоит из выражения (переключате-
        ля) и списка операторов, каждому из которых предшествует одна или
        более констант (они называются константами выбора)  или  ключевое
        слово else.  Переключатель (селектор) должен иметь порядковый тип
        (размером в байт или слово). Таким образом, строковый тип и длин-
        ный  целый  тип являются недопустимыми типами переключателя.  Все
        константы выбора должны быть уникальными и иметь порядковый  тип,
        совместимый с типом переключателя.

                         ЪДДДДї   ЪДДДДДДДДДї   ЪДДї      ЪДДДДї
         оператор case Д>іcaseГДД>івыражениеГДД>іofГДДДДД>іcaseГДДВДДї
                         АДДДДЩ   АДДДДДДДДДЩ   АДДЩ  ^   АДДДДЩ  і  і
                                                      і   ЪДДДДї  і  і
                                                      АДДДґ ;  і<ДЩ  і
                                                          АДДДДЩ     і
                             ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
                             і                                  ЪДДДї
                             АДВДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДД>іendГДД>
                               і   ЪДДДДДДДДДДї  ^  і  ЪДДДї  ^ АДДДЩ
                               АДД>іветвь elseГДДЩ  АД>і ; ГДДЩ
                                   АДДДДДДДДДДЩ        АДДДЩ

                             ЪДДДДДДДДДДДДДДДДДДДДї
                 ЪДДДДДДДДДї і  ЪДДї  ЪДДДДДДДДДї v   ЪДДДї  ЪДДДДДДДДї
         case ДД>іконстантаГДБД>і..ГД>іконстантаГДДВД>і : ГД>іоператорГД>
              ^  АДДДДДДДДДЩ    АДДЩ  АДДДДДДДДДЩ  і  АДДДЩ  АДДДДДДДДЩ
              і                 ЪДДДї              і
              АДДДДДДДДДДДДДДДДДґ , і<ДДДДДДДДДДДДДЩ
                                АДДДЩ

                         ЪДДДДї    ЪДДДДДДДДї
         ветвь else ДДДД>іelseГДДД>іоператорГДДД>
                         АДДДДЩ    АДДДДДДДДЩ

             Оператор варианта case приводит к выполнению оператора,  ко-
        торому предшествует константа выбора,  равная значению переключа-
        теля или диапазону выбора,  в котором находится значение переклю-
        чателя.  Если такой константы выбора или такого диапазона  выбора
        не существует и присутствует ветвь else,  то выполнятся оператор,
        следующий за ключевым словом else.  Если же ветвь else отсутству-
        ет, то никакой оператор не выполняется.

         B.Pascal 7 & Objects/LR     - 124 -


             Приведем некоторые примеры оператора варианта:

             case Operator of
               plus:   X := X+Y;
               minus:  X := X-Y;
               times:  X := X*Y;
             end;

             case I of
                  0, 2, 4, 6, 8: Writeln('Четная цифра');
                  1, 3, 5, 7, 9: Writeln('Нечетная цифра');
                  10..100: Writeln('Между 10 и 100');
             end;



         B.Pascal 7 & Objects/LR     - 125 -

                                 Оператор цикла
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Оператор цикла задает повторное выполнение определенных опе-
        раторов.

                                        ЪДДДДДДДДДДДДДДДДДї
                 оператор цикла  ДДДВДД>і оператор repeat ГДДДДДД>
                                    і   АДДДДДДДДДДДДДДДДДЩ  ^
                                    і   ЪДДДДДДДДДДДДДДДДДї  і
                                    ГДД>і оператор while  ГДДґ
                                    і   АДДДДДДДДДДДДДДДДДЩ  і
                                    і   ЪДДДДДДДДДДДДДДДДДї  і
                                    АДД>і оператор  for   ГДДЩ
                                        АДДДДДДДДДДДДДДДДДЩ

             Если число повторений заранее известно,  то подходящей конс-
        трукций является оператор for. В противном случае следует исполь-
        зовать операторы while или repeat.

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


                     Оператор цикла с постусловием (repeat)
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В операторе  цикла  с  постусловием  (начинающимся  со слова
        repeat) выражение, которое управляет повторным выполнением после-
        довательности операторов содержится внутри оператора repeat.

                    ЪДДДДДДї     ЪДДДДДДДДї     ЪДДДДДї   ЪДДДДДДДДДї
         оператор Д>іrepeatГДДДД>іоператорГДДВД>іuntilГДД>івыражениеГДД>
         repeat     АДДДДДДЩ  ^  АДДДДДДДДЩ  і  АДДДДДЩ   АДДДДДДДДДЩ
                              і    ЪДДДї     і
                              АДДДДґ ; і<ДДДДЩ
                                   АДДДЩ

             Результат выражения должен быть булевского типа.  Операторы,
        заключенные  между ключевыми словами repeat и until,  выполняются
        последовательно до тех пор,  пока результат выражения  не  примет
        значение True.  Последовательность операторов выполнится по край-
        ней мере один раз,  поскольку вычисление  выражения  производится
        после каждого выполнения последовательности операторов.

         B.Pascal 7 & Objects/LR     - 126 -


             Приведем примеры оператора цикла с постусловием:

             repeat
               K := I mod J;
               I := J;
               J := K;
             until J = 0;

             repeat
               Write('Введите значение (0..9):');
               Readln(I);
             until (I >= 0) and (I <= 9);




         B.Pascal 7 & Objects/LR     - 127 -

                     Операторы цикла с предусловием (while)
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Оператор цикла с предусловием (начинающийся с ключевого сло-
        ва while) содержит в себе выражение,  которое управляет повторным
        выполнением  оператора (который может быть составным оператором).

                      ЪДДДДДї   ЪДДДДДДДДДї   ЪДДї   ЪДДДДДДДДї
         оператор ДДД>іwhileГДД>івыражениеГДД>іdoГДД>іоператорГДД>
         while        АДДДДДЩ   АДДДДДДДДДЩ   АДДЩ   АДДДДДДДДЩ

             Выражение, с помощью которого осуществляется управление пов-
        торением оператора,  должно иметь булевский тип.  Вычисление  его
        производится  до  того,  как  внутренний оператор будет выполнен.
        Внутренний оператор выполнятся повторно до тех пор,  пока выраже-
        ние принимает значение Тruе.  Если выражение с самого начала при-
        нимает значение False, то оператор, содержащийся внутри оператора
        цикла с предусловием, не выполняется.

             Примерами операторов цикла с предусловием могут служить сле-
        дующие операторы:

             while Data[I] <> X do I := I + 1;

             While I > 0 do
             begin
               if Odd(I) then Z := Z * X;
               I := I div 2;
               X := Sqr(X);
             end;

             while not Eof(InFile) do
             begin
               Readln(InFile,Line);
               Process(Line);
             end;




         B.Pascal 7 & Objects/LR     - 128 -

                       Операторы цикла с параметром (for)
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Операторы цикла с параметром (которые  начинаются  со  слова
        for)  вызывает  повторяющееся выполнение оператора (который может
        быть составным оператором) пока управляющей переменной присваива-
        ется возрастающая последовательность значений.

                      ЪДДДї   ЪДДДДДДДДДДДї   ЪДДї   ЪДДДДДДДДї
         оператор ДДД>іforГДД>іуправляющаяГДД>і:=ГДД>іисходноеГДДДї
         for          АДДДЩ   іпеременная і   АДДЩ   ізначениеі   і
                              АДДДДДДДДДДДЩ          АДДДДДДДДЩ   і
                 ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
                 і      ЪДДї
                 і   ЪД>іtoГДДДДДї   ЪДДДДДДДДї   ЪДДї   ЪДДДДДДДДї
                 АДДДґ  АДДЩ     ГДД>іконечноеГДД>іdoГДД>іоператорГДДД>
                     і  ЪДДДДДДї і   ізначениеі   АДДЩ   АДДДДДДДДЩ
                     АД>іdowntoГДЩ   АДДДДДДДДЩ
                        АДДДДДДЩ

                                    ЪДДДДДДДДДДДДДДДДДДДДДДДДї
         управляющая переменная ДДД>іидентификатор переменнойГДДД>
                                    АДДДДДДДДДДДДДДДДДДДДДДДДЩ

                                 ЪДДДДДДДДДї
         исходное значение  ДДДД>івыражениеГДДД>
                                 АДДДДДДДДДЩ

                                 ЪДДДДДДДДДї
         конечное значение  ДДДД>івыражениеГДДД>
                                 АДДДДДДДДДЩ

             В качестве   управляющей  переменной  должен  использоваться
        идентификатор переменой (без какого-либо  квалификатора), который
        обозначает переменную,  объявленную локальной в блоке,  в котором
        содержится оператор for.  Управляющая переменная должна иметь пе-
        речислимый  тип.  Начальное и конечное значения должны иметь тип,
        совместимый по присваиванию с перечислимым типом.

                   Примечание: О локальности и области действия рассказы-
              вается в Главе 8.

             Когда начинает выполняться оператор for,  начальное и конеч-
        ное значения определяются один раз, и эти значения сохраняются на
        протяжении всего выполнения оператора for.

             Оператор, который содержится в теле оператора for,  выполня-
        ется  один раз для каждого значения в диапазоне между начальным и
        конечным значением. Управляющая переменная всегда инициализирует-
        ся начальным значением. Когда работает оператор for, значение уп-
        равляющей переменной (счетчика циклов) увеличивается  при  каждом
        повторении на единицу. Если начальное значение превышает конечное
        значение, то содержащийся в теле оператора for оператор не выпол-

         B.Pascal 7 & Objects/LR     - 129 -

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

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

             Если принять во внимание эти ограничения, то оператор

             for V := Expr1 to Expr2 do Body;

        эквивалентен оператору:

             begin
               Temp1 := Expr1;
               Temp2 := Expr2;
             if Temp1 <= Temp2 then
             begin
               V := Temp1;
               Body;
                while V <> Temp2 do
                begin
                  V := Succ(V);
                  Body;
                end;
              end;
             end;

        и оператор цикла:

             for V := Expr1 downto Exp2 do Body;

        эквивалентен операторам:

             begin
               Temp1 := Expr1;
               Temp2 := Expr2;
               if Temp1 >= Temp2 then
              begin
                 V := Temp1;
                 Body;
                 while V <> Temp2 o
                 begin
                   V := Pred(V);
                   Body;
                 end;
               end;
              end;

         B.Pascal 7 & Objects/LR     - 130 -


        где Temp1 и Temp2 - вспомогательные переменные,  тип которых сов-
        падает с основным типом переменной V и которые не  встречаются  в
        другом месте программы.

             Приведем примеры оператора цикла с параметром:

             for I := 2 to 63 do
               if Data[I] > Max then Max := Data[I]

             for I := 1 to 10 do
               for J := 1 to 10 do
               begin
                 X := 0;
                 for K := 1 to 10 do
                   X := X + Mat1[I,K]*Mat2[K,J];
                 Mat[I,J] := X;
               end;

              for C := red to blue do Check(C);




         B.Pascal 7 & Objects/LR     - 131 -

                                  Оператор with
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В операциях над записями оператор with  удобно  использовать
        для  краткого обращения к полям записи.  В операторе with к полям
        одной или более конкретных переменных типа запись можно обращать-
        ся,  используя  только идентификаторы полей.  Оперaтор with имеет
        следующий синтаксис:

                     ЪДДДДї      ЪДДДДДДДДДДДДДДДї     ЪДДї   ЪДДДДДДДДї
         оператор ДД>іwithГДДДДД>і   ссылка на   ГДДВД>іdoГДД>іоператорГ>
         with        АДДДДЩ  ^   іпеременную типаі  і  АДДЩ   АДДДДДДДДЩ
                             і   і    запись     і  і
                             і   і  или объект   і  і
                             і   АДДДДДДДДДДДДДДДЩ  і
                             і        ЪДДДї         і
                             АДДДДДДДДґ , і<ДДДДДДДДЩ
                                      АДДДЩ

         ссылка на переменную        ЪДДДДДДДДДДДДДДДДДДДДї
         типа запись или объект  ДДД>іссылка на переменнуюГДД>
                                     АДДДДДДДДДДДДДДДДДДДДЩ

             Возьмем следующее описание:

             type
               TDate = record
                    Day   : Integer:
                    Month : Integer;
                    Year  : Integer:
               end;

             var OrderDate: TDate;

             С учетом данного описания приведем пример оператора with:

             with OrderDate do
               if Month = 12 then
               begin
                 Month := 1;
                 Year := Year + 1
               end else
                 Month := Month + 1;

             Это эквивалентно следующему:

             if OrderDate.Month = 12 then
             begin
               OrderDate.Month := 1;
               OrderDate.Year := TDate.Year + 1
             end
             else
               Date.month := TDate.Month + 1;

         B.Pascal 7 & Objects/LR     - 132 -


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

             Допустим описаны следующие переменные:

            type
              TPoint = record
                        x,y: Integer;
                      end;
              var
                x: Point;
                y: Integer;

             В этом случае и к x,  и к y можно обращаться, как к перемен-
        ной или как к полю записи. В операторе:

            with x do
            begin
              x := 10;
              y := 25;
            end;

        x между  ключевыми  словами with и dо относится к переменной типа
        указатель,  а в составном операторе x и y ссылаются на x.x и y.y.

             Оператор:

             with V1,V2,...Vn do s;

        эквивалентен операторам:

             with V1 do
               with V2 do
                ...
                  with Vn do
                   S;

             В обоих случаях,  если Vn является полем и v1,  и v2, то она
        интерпретируется как v2.Vn, а не как v1.Vn.

             Если выборка переменной типа запись связана с индексировани-
        ем массива или разыменованием указателя, то эти действия произво-
        дятся до того, как будет выполняться составной оператор.



         B.Pascal 7 & Objects/LR     - 133 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                 Глава 8. Блоки, локальность и область действия
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Блоки состоят из описаний, которые записаны и скомбинированы
        в любом порядке, и операторов. Каждый блок является частью описа-
        ния процедуры или функции,  или частью программы или модуля.  Все
        идентификаторы и метки,  объявленные в разделе описаний, являются
        для блока локальными.

                                    Синтаксис
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В общем виде любой блок имеет следующий формат:

                   ЪДДДДДДДДДДї     ЪДДДДДДДДДДї
         блок ДДДД>і  раздел  ГДДДД>і  раздел  ГДДДД>
                   і описания і     іоператорові
                   АДДДДДДДДДДЩ     АДДДДДДДДДДЩ

         раздел    ДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДД>
         объявления    ^     і                              ^     і
                       і     і    ЪДДДДДДДДДДДДДДДДДДї      і     і
                       і     ГДДД>і  раздел описания ГДДДДДДґ     і
                       і     і    і      меток       і      і     і
                       і     і    АДДДДДДДДДДДДДДДДДДЩ      і     і
                       і     і    ЪДДДДДДДДДДДДДДДДДДї      і     і
                       і     ГДДД>і  раздел описания ГДДДДДДґ     і
                       і     і    і     констант     і      і     і
                       і     і    АДДДДДДДДДДДДДДДДДДЩ      і     і
                       і     і    ЪДДДДДДДДДДДДДДДДДДї      і     і
                       і     ГДДД>і  раздел описания ГДДДДДДґ     і
                       і     і    і      типов       і      і     і
                       і     і    АДДДДДДДДДДДДДДДДДДЩ      і     і
                       і     і    ЪДДДДДДДДДДДДДДДДДДї      і     і
                       і     ГДДД>і  раздел описания ГДДДДДДґ     і
                       і     і    і    переменных    і      і     і
                       і     і    АДДДДДДДДДДДДДДДДДДЩ      і     і
                       і     і    ЪДДДДДДДДДДДДДДДДДДї      і     і
                       і     ГДДД>і оператор exports ГДДДДДДґ     і
                       і     і    АДДДДДДДДДДДДДДДДДДЩ      і     і
                       і     і    ЪДДДДДДДДДДДДДДДДДДї      і     і
                       і     АДДД>і  раздел описания ГДДДДДДЩ     і
                       і          іпроцедур и функцийі            і
                       і          АДДДДДДДДДДДДДДДДДДЩ            і
                       АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ


         B.Pascal 7 & Objects/LR     - 134 -


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


          раздел           ЪДДДДДДДї       ЪДДДДДДДї      ЪДДДї
          описания ДДДДДДД>і label ГДДДДДД>і метка ГДДВДД>і ; ГДДД>
          меток            АДДДДДДДЩ   ^   АДДДДДДДЩ  і   АДДДЩ
                                       і   ЪДДДї      і
                                       АДДДґ , ГДДДДДДЩ
                                           АДДДЩ

             Меткой может быть идентификатор или последовательность цифр.
        Используемая в качестве метки последовательность цифр должна  на-
        ходиться в диапазоне от 0 до 9999.

             Раздел описания констант содержит описания констант, локаль-
        ных для этого блока.

         раздел         ЪДДДДДДДї       ЪДДДДДДДДДДДДї
         описания ДДДДД>і const ГДДДДВД>і  описание  ГДДДДДДДДДДДВДДД>
         констант       АДДДДДДДЩ ^  і  і константы  і        ^  і
                                  і  і  АДДДДДДДДДДДДЩ        і  і
                                  і  і  ЪДДДДДДДДДДДДДДДДДДДї і  і
                                  і  і  і     описание      і і  і
                                  і  АД>і   типизированной  ГДЩ  і
                                  і     і     константы     і    і
                                  і     АДДДДДДДДДДДДДДДДДДДЩ    і
                                  АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Раздел описания типов включает описания всех типов в блоке.

         раздел         ЪДДДДДДДї       ЪДДДДДДДДДДДДї
         описания ДДДДД>і type  ГДДДДДД>і  описание  ГДДДДВДДД>
         типов          АДДДДДДДЩ  ^    і    типа    і    і
                                   і    АДДДДДДДДДДДДЩ    і
                                   АДДДДДДДДДДДДДДДДДДДДДДЩ


             Раздел описания переменных состоит из  описания  переменных,
        локальных для этого блока.

         раздел         ЪДДДДДї       ЪДДДДДДДДДДДДї
         описания ДДДДД>і var ГДДДДДД>і  описание  ГДДДДВДДД>
         переменных     АДДДДДЩ  ^    і переменной і    і
                                 і    АДДДДДДДДДДДДЩ    і
                                 АДДДДДДДДДДДДДДДДДДДДДДЩ


         B.Pascal 7 & Objects/LR     - 135 -


             Раздел описания  процедур и функций состоит из описания про-
        цедур и функций, локальных для этого блока.


         раздел                 ЪДДДДДДДДДДДДї
         описания ДДДДДДДДДДДВД>і  описание  ГДДДДДВДДДД>
         процедур и       ^  і  і процедуры  і  ^  і
         функций          і  і  АДДДДДДДДДДДДЩ  і  і
                          і  і  ЪДДДДДДДДДДДДї  і  і
                          і  АД>і  описание  ГДДЩ  і
                          і     і  функции   і     і
                          і     АДДДДДДДДДДДДЩ     і
                          і     ЪДДДДДДДДДДДДї     і
                          ГДДДД>і  описание  ГДДДДДґ
                          і     іконструктораі     і
                          і     АДДДДДДДДДДДДЩ     і
                          і     ЪДДДДДДДДДДДДї     і
                          ГДДДД>і  описание  ГДДДДДґ
                          і     ідеструктора і     і
                          і     АДДДДДДДДДДДДЩ     і
                          АДДДДДДДДДДДДДДДДДДДДДДДДЩ

             В операторе  exports  перечисляются все процедуры и функции,
        которые экспортируются данной программой или динамически компону-
        емой библиотекой.  Оператор exports допускается только во внешнем
        разделе описаний программы или динамически компонуемой библиотеки
        - в разделе описаний процедуры,  функции или модуля его использо-
        вать нельзя.

             Раздел операторов  определяет  операторы или алгоритмические
        действия, которые выполняются в блоке.

         раздел           ЪДДДДДДДДДДДї
         операторов ДДДДД>і составной ГДДДДД>
                          і  оператор і
                          АДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 136 -

                          Правила для области действия
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                           Область действия для блока
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

             program Outer;          { начало внешней области действия ъ
             type
               I = Integer;          { определяет I как Integer }
             var
               T: I;                 { определяет T как целочисленную
                                       переменную }
             procedure Inner;        { начало внутреннего блока }
             type
               T = I;                { переопределяет T с типом Integer }
             var
               I: T;                 { переопределяет I как целочисленную
                                       переменную }
             begin
               I := 1;               { конец вложенного блока }
             end;

             begin
               T := 1;               { конец внешнего блока }
             end.



         B.Pascal 7 & Objects/LR     - 137 -

                             Область действия записи
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Область действия идентификатора поля, описанного в определе-
        нии записи,  простирается от точки описания до конца  определения
        типа запись. Кроме того, область действия идентификаторов включа-
        ет десигнаторы поля и операторы with над ссылками  на  переменную
        данного типа записи.

                   Примечание: О типе запись рассказывается в Главе 4.

                              Область действия объекта
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Область действия идентификатора элемента,  описанного в объ-
        ектном типе,  простирается от точки описания до конца определения
        объектного типа и распространяется на все дочерние объектные типы
        и  блоки всех описаний методов объектного типа.  Область действия
        идентификаторов элемента включает десигнаторы  поля  и  операторы
        with над ссылками на переменную данного объектного типа.

                   Примечание: о типе запись рассказывается в Главе 4.

         B.Pascal 7 & Objects/LR     - 138 -


                             Область действия модуля
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Область действия идентификаторов,  описанных в  интерфейсной
        секции модуля,  подчиняется  правилам  области  действия  блока и
        распространяется на всех клиентов модуля.  Другими словами, прог-
        раммы и модули,  содержащие операторы uses (операторы использова-
        ния) имеют доступ к идентификаторам, которые описаны в интерфейс-
        ной части модулей, указанных в этих операторах uses.

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

             Идентификаторы встроенных констант,  типов, переменных, про-
        цедур и  функций  Borland Pascal действуют,  как если бы они были
        описаны в блоке, охватывающем все используемые модули и программу
        в целом. В действительности эти стандартные объекты описаны в мо-
        дуле System,  который используется любой программой  или  модулем
        прежде любого модуля,  указанного в операторе uses. Это означает,
        что любой модуль или программа могут  переопределить  стандартные
        идентификаторы,  а обращение к ним может быть выполнено с помощью
        уточненного (составного) идентификатора, например, System.Integer
        или System.Writeln.



         B.Pascal 7 & Objects/LR     - 139 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                          Глава 9. Процедуры и функции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                   Примечание: Определение блока вы можете найти в  Главе
              8 "Блоки, локальность и область действия".

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

                                Описания процедур
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД


         B.Pascal 7 & Objects/LR     - 140 -


             Описание процедуры позволяет связать идентификатор с  проце-
        дурным  блоком.  Процедуру  можно  затем активизировать с помощью
        оператора процедуры.

                      ЪДДДДДДДДДї   ЪДДДї   ЪДДДДДДДДДДДДї   ЪДДДї
         описание ДДД>ізаголовокГДД>і ; ГДД>і    тело    ГДД>і ; ГДД>
         процедуры    іпроцедурыі   АДДДЩ   іподпрограммыі   АДДДЩ
                      АДДДДДДДДДЩ           АДДДДДДДДДДДДЩ

                      ЪДДДДДДДДДї   ЪДДДДДДДДДДДДДї
         заголовок ДД>іprocedureГДВ>іидентификаторГДДї
         процедуры    АДДДДДДДДДЩ і АДДДДДДДДДДДДДЩ ^ГДДДДДДДДДДДДДДДДДД>
                                  і ЪДДДДДДДДДДДДДї іі  ЪДДДДДДДДДДї ^
                                  і і уточненный  і іі  і  список  і і
                                  А>іидентификаторГДЩАД>іформальныхГДЩ
                                    і   метода    і     іпараметрові
                                    АДДДДДДДДДДДДДЩ     АДДДДДДДДДДЩ

                                                        ЪДДДДДДї
         блок     ДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДД>імодульГДДДДДДДД>
         подпрограммыі   ЪДДДДДДДДДї      ЪДДДї   ^ і   АДДДДДДЩ    ^
                     ГДД>і near    ГДДДДД>і ; ГДДДЩ і   ЪДДДДДДДї   і
                     і   АДДДДДДДДДЩ  ^   АДДДЩ     іДД>іforwardГДДДґ
                     і   ЪДДДДДДДДДї  і             і   АДДДДДДДЩ   і
                     ГДД>і far     ГДДґ             і   ЪДДДДДДДДДї і
                     і   АДДДДДДДДДЩ  і             іДД>ідирективаГДґ
                     і   ЪДДДДДДДДДї  і             і   і externalі і
                     ГДД>і export  ГДДґ             і   АДДДДДДДДДЩ і
                     і   АДДДДДДДДДЩ  і             і   ЪДДДДДДДДї  і
                     і   ЪДДДДДДДДДї  і             АДД>іблок asmГДДґ
                     ГДД>іinterruptГДДЩ                 АДДДДДДДДЩ  і
                     і   АДДДДДДДДДЩ                    ЪДДДДДДДДДї і
                     АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД>ідирективаГДЩ
                                                        і inline  і
                                                        АДДДДДДДДДЩ

             Заголовки процедур  именуют идентификаторы процедур и задают
        формальные параметры (если они имеются).

                   Примечание: Синтаксис списка формальных параметров по-
              казан далее в этой главе в разделе "Параметры".

             Процедура активизируется с помощью  оператора  процедуры,  в
        котором содержатся имя процедуры и необходимые параметры.  Опера-
        торы, которые должны выполняться при запуске процедуры, содержат-
        ся  в  операторной части модуля процедуры.  Если в содержащемся в
        процедуре операторе внутри модуля процедуры используется  иденти-
        фикатор процедуры, то процедура будет выполняться рекурсивно (бу-
        дет при выполнении обращаться сама к себе).

         B.Pascal 7 & Objects/LR     - 141 -


             Приведем пример описания процедуры:

             procedure NumString(N: integer; var S: string);
             var
               V: integer;
             begin
               V := Abs(N);
               S := '';
               repeat
                 S := Chr(N mod 10 + Ord('0')) + S;
                 N := N div 10;
               until N = 0;
               if N < 0 then S := '-' + S;
             end;

                               Описания near и far
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Borland Pascal  поддерживает  две  модели  вызова процедур -
        ближнюю (near) и дальнюю (far). С точки зрения объема программы и
        скорости выполнения ближняя модель вызова более эффективна,  но с
        ней связаны ограничения:  процедуры типа  near  могут  вызываться
        только в том модуле,  где они описаны. Процедуры же с дальним ти-
        пом вызова можно вызывать из любого модуля,  но они несколько ме-
        нее эффективны.

                   Примечание: О вызовах ближнего и дальнего типа расска-
              зывается в Главе 22 "Вопросы управления".

             На основе описания процедуры компилятор будет  автоматически
        выбирать правильную модель вызова.  Для процедур, описанных в ин-
        терфейсной части модуля (interface),  используется дальняя модель
        вызова - их можно вызывать из других модулей.  Процедуры, описан-
        ные в секции реализации модуля  (implementation),  имеют  ближний
        тип вызова. Вызываться они могут только из программ данного моду-
        ля.

             Для некоторых  специальных целей может потребоваться исполь-
        зовать модель с дальним типом вызова.  Например, в оверлейных за-
        дачах обычно требуется, чтобы все процедуры и функции имели даль-
        ний  тип  вызова.  Аналогично,   если   процедура   или   функция
        присваивается процедурной переменной, то она также должна исполь-
        зовать дальний тип вызова.  Чтобы  переопределить  автоматический
        выбор  модели  вызова компилятором,  можно использовать директиву
        компилятора {$F+}. Процедуры и функции, компилируемые в состоянии
        {$F+}, всегда будут иметь дальний тип вызова (far), а в состоянии
        {$F-} компилятор автоматически  выбирает  корректную  модель.  По
        умолчанию используется директива {$F-}.


         B.Pascal 7 & Objects/LR     - 142 -

             Чтобы задать конкретную модель вызова,  в описании процедуры
        перед ее блоком можно указать директиву near или far. При наличии
        такой директивы она переопределяет директиву $F компилятора и ав-
        томатический выбор модели вызова.

                                 Описания export
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Процедуры и функции должны быть экспортируемыми в  следующих
        случаях:

             * Процедуры и функции экспортируются DLL (динамически компо-
               нуемой библиотекой).

             * Процедуры и функции системного вызова в программе Windows.

             О том, как экспортировать процедуры и функции в DLL, расска-
        зывается в  Главе  11 "Динамически компонуемые библиотеки".  Хотя
        процедура и функция компилируется с директивой export,  фактичес-
        кий экспорт процедуры или функции не происходит, пока подпрограм-
        ма не перечисляется в операторе exports библиотеки.

             Процедуры и функции системного вызова - это те  процедуры  и
        функции вашей  прикладной  программы,  которые  вызываются  самой
        Windows, а не вашей прикладной программой. Подпрограммы системно-
        го вызова должны компилироваться с директивой export, но в опера-
        торе exports их перечислять не нужно.  Приведем некоторые примеры
        процедур и функций системного вызова:

             * процедуры Windows;
             * диалоговые процедуры;
             * процедуры системного вызова для перечисления;
             * процедуры уведомления об обращении к памяти;
             * специализированные процедуры Windows (фильтры).

             Borland Pascal автоматически генерирует для процедур и функ-
        ций, экспортируемых программой Windows, эффективные системные вы-
        зовы. Эффективные  вызовы  ослабляют  необходимость использования
        при создании  подпрограмм  системного  вызова   подпрограмм   API
        Windows MakeProcInstance и FreeProcInstance.

                  Примечание: См. раздел "Код входа и выхода" в Главе 22.

         B.Pascal 7 & Objects/LR     - 143 -

                               Описания interrupt
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В описании процедуры перед блоком операторов может  указыва-
        ется директива interrupt.  Процедура в этом случае рассматривает-
        ся, как   процедура   прерывания.  Отметим  пока,  что  процедура
        interrupt не может вызываться из операторов процедуры, и что каж-
        дая процедура interrupt должна определять список параметров, нап-
        ример, следующим образом:

             procedure MyInt(Flags,  CS,  IP, AX, BX, CX, DX, SI, DI, DS,
                ES, BP: Word);
             interrupt;

                   Примечание: Не  используйте  директиву  interrupt  при
              разработке программ для Windows - это приведет к сбою.

             Список параметров  не обязательно должен совпадать с указан-
        ным синтаксисом - он может быть короче и использовать другие име-
        на, но регистры должны передаваться в указанном порядке.

                                Описание forward
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

                   Примечание: В  интерфейсной  части   модуля   описания
              forward не допускаются.

             Приведем следующий пример опережающего описания:

             procedure Walter(m,n : integer); forward;

             procedure Clara(x,y : real);
             begin
              .
              .
              .
             end;

         B.Pascal 7 & Objects/LR     - 144 -


             procedure Walter;
             begin
              .
              .
              Clara(8.3, 2.4);
              .
              .
             end;

             Определяющее описание  процедуры может быть внешним описани-
        ем.  Однако,  оно не может быть внутренним описанием  или  другим
        опережающим  описанием.  Определяющее описание также не может со-
        держать директиву  interrupt,  описания  assembler,  near,   far,
        export, inline или другое описание forward.



         B.Pascal 7 & Objects/LR     - 145 -

                                Описания external
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Описания external позволяют связывать  отдельно  скомпилиро-
        ванные процедуры и функции,  написанные на языке ассемблера. Опи-
        сания external позволяют также импортировать процедуры и  функции
        из DLL.

                   Примечание: Более   детальное  описания  компоновки  с
              программой на языке ассемблера содержится в Главе 25.

         директива external
         і  ЪДДДДДДДДДДї
         АД>і external ГВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД>
            АДДДДДДДДДДЩі ЪДДДДДДДДДДДДДДДДДДДї                        ^
                        А>істроковая константаГВДДДДДДДДДДДДДДДДДДДДДДДЩ
                          АДДДДДДДДДДДДДДДДДДДЩі ЪДДДДДДї  ЪДДДДДДДДДї^
                                               Г>і name ГД>істроковаяГґ
                                               і АДДДДДДЩ  іконстантаіі
                                               і           АДДДДДДДДДЩі
                                               і ЪДДДДДДДї ЪДДДДДДДДДїі
                                               А>і index Г>і  целая  ГЩ
                                                 АДДДДДДДЩ іконстантаі
                                                           АДДДДДДДДДЩ

             Директива external,  состоящая только из  зарезервированного
        слова  external,  используется  в  сочетании  с  директивами  {$L
        имя_файла} для компоновки с процедурами и функциями,  реализован-
        ными в файлах .OBJ.

             Приведем следующие примеры описаний внешних процедур:

             procedure MoveWord(var source,dest; count: longint);
               external;

             procedure MoveLong(var source,dest; count: longint);
               external;

             procedure FillWord(var dest,data: integer; count: longint);
               external;

             procedure FillLong(var dest,data: integer; count: longint);
               external;

             {$L BLOCK.OBJ}

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

             Директивы external, специфицирующие имя динамически компону-
        емой библиотеки  (и,  возможно,  импортируемое имя или порядковый

         B.Pascal 7 & Objects/LR     - 146 -

        номер импорта),  используются для импорта процедур и  функций  из
        динамически компонуемых библиотек.  Например, следующая директива
        external импортирует из DLL с именем KERNEL (ядро Windows)  функ-
        цию с именем GlobalAlloc:

             function GlobalAlloc(Flags: Word; Bytes: Longint): THandle;
              far; external 'KERNEL' index 15;

             В импортируемой процедуре или функции директива external за-
        нимает место описания и операторной части. В импортируемых проце-
        дурах или функциях должен использоваться дальний тип вызова,  за-
        даваемый с  помощью директивы far в описании процедуры или дирек-
        тивы компилятора {$F+}.  В остальном  импортируемые  процедуры  и
        функции аналогичны обычным процедурам и функциям.

                   Примечание: Подробнее  об импорте функций из DLL расс-
              казывается в Главе 11.

         B.Pascal 7 & Objects/LR     - 147 -

                               Описания assembler
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Описания assembler позволяют вам написать всю  процедуру или
        функцию на ассемблере.

                  Примечание: Более  подробно  о процедурах и функциях на
             Ассемблере рассказывается в Главе 24 "Встроенный ассемблер".

                   ЪДДДДДДДДДї   ЪДДДї   ЪДДДДДДДДДДї   ЪДДДДДДДДДДДДї
        блок asm Д>іassemblerГДД>і ; ГДД>і  раздел  ГДД>іasm операторГД>
                   АДДДДДДДДДЩ   АДДДЩ   і описания і   АДДДДДДДДДДДДЩ
                                         АДДДДДДДДДДЩ


                                 Описания inline
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Директивы inline  позволяют записывать вместо блока операто-
        ров инструкции в машинном коде. При вызове обычной процедуры ком-
        пилятор  создает код,  в котором параметры процедуры помещаются в
        стек,  а затем для вызова процедуры генерируется инструкция CАLL.

                             ЪДДДДДДДДДДДДДДДДДї
         директива inline ДД>і оператор inline ГДДДДДДДДДД>
                             АДДДДДДДДДДДДДДДДДЩ

             Когда вы вызываете подставляемую процедуру (inline),  компи-
        лятор  генерирует код с помощью директивы inline,  а не с помощью
        инструкции CALL.  Таким образом, поставляемая процедура "расширя-
        ется"  при каждом обращении к ней,  аналогично макроинструкции на
        языке ассемблера.  Приведем два небольших  примера  подставляемых
        процедур:

             procedure DisableInterrupts: inline($FA);  { CLI }
             procedure EnableInterrupts;  inline($FB);  { STI }

                   Примечание: Синтаксические диаграммы оператора  inline
              описаны подробно в Главе 25.


         B.Pascal 7 & Objects/LR     - 148 -

                                Описания функций
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Описание функции определяет часть программы,  в которой  вы-
        числяются и возвращается значение.

                       ЪДДДДДДДДДї   ЪДДДї   ЪДДДДДДДї   ЪДДДї
         описание  ДДД>ізаголовокГДД>і ; ГДД>і тело  ГДД>і ; ГДД>
         функции       і функции і   АДДДЩ   іфункцииі   АДДДЩ
                       АДДДДДДДДДЩ           АДДДДДДДЩ

                       ЪДДДДДДДДї  ЪДДДДДДДДДДДДДї
         заголовок ДДД>іfunctionГВ>іидентификаторГДДВДДДДДДДДДДДДДДДДДДДї
         функции       АДДДДДДДДЩі АДДДДДДДДДДДДДЩ^ і  ЪДДДДДДДДДДї  ^  і
                                 і ЪДДДДДДДДДДДДДїі і  ісписок    і  і  і
                                 А>і уточненный  ГЩ АД>іформальныхГДДЩ  і
                                   іидентификаторі     іпараметрові     і
                                   і  метода     і     АДДДДДДДДДДЩ     і
                                   АДДДДДДДДДДДДДЩЪДДДДДДДДДДДДДДДДДДДДДЩ
                                                  і  ЪДДДї   ЪДДДДДДДДї
                                                  АД>і : ГДД>ітип ре- ГДД>
                                                     АДДДЩ   ізультатаі
                                                             АДДДДДДДДЩ
                              ЪДДДДДДДДДДДДДї
         тип результата ДДВДД>іидентификаторГДДДДДДДДД>
                          і   і    типа     і     ^
                          і   АДДДДДДДДДДДДДЩ     і
                          і      ЪДДДДДДї         і
                          АДДДДД>іstringГДДДДДДДДДЩ
                                 АДДДДДДЩ

                   Примечание: Функция  не  может  возвращать процедурный
              тип или структурный тип.

             В заголовке функции определяется идентификатор функции, фор-
        мальные параметры (если они имеются) и тип результата функции.

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

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

             Если идентификатор функции используется при  вызове  функции

         B.Pascal 7 & Objects/LR     - 149 -

        внутри модуля-функции, то функция выполняется рекурсивно.

             Приведем далее примеры описаний функции:

             function Max(a: Vector; n: integer): extended;
             var
              x: extended;
              i: integer;
             begin
               x := a(1);
               for i := 2 to n do if x < a[i] then x := a[i];
               Max := x;
             end;

             function Power(x: extended; y: integer): extended;
             var
               z: extended;
               i: integer;
             begin
               z := 1.0; i := y;
               while i > 0 do
             begin
               if Odd(i) then z := z*x;
               x := Sqr(x);
             end;
             Power := z;
             end;

             Аналогично процедурам функции могут описываться, как с ближ-
        ним типом вызова (near),  с дальним типом вызова (far), опережаю-
        щие (forward),  внешние (external),  ассемблерные (assembler) или
        подставляемые (inline).  Однако функции прерываний (interrupt) не
        допускаются.



         B.Pascal 7 & Objects/LR     - 150 -

                                Описания методов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Описание метода внутри объектного типа соответствует  опере-
        жающему  описанию  (forward) этого метода.  Таким образом,  метод
        должен быть реализован где-нибудь после описания объектного  типа
        и внутри той же самой области действия метода путем определяющего
        описания.

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

             Для методов конструкторов и деструкторов определяющее описа-
        ний принимает форму описания процедурного метода, за тем исключе-
        нием,  что  зарезервированное слово procedure заменяется на заре-
        зервированное слово constructor или destructor. Определяющее опи-
        сание  метода может повторять (но не обязательно) список формаль-
        ных параметров заголовка метода в объектном типе.  В этом  случае
        заголовок  метода должен в точности повторять заголовок в объект-
        ном типе в порядке, типах и именах параметров и в типе возвращае-
        мого функцией результата, если метод является функцией.

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

             Область действия идентификатора компонента  объектного  типа
        распространяется  на  блоки  процедур,  функций,  конструкторов и
        деструктора,  которые реализуют методы данного  объектного  типа.
        Эффект  получается тот же,  как если бы в начало блока метода был
        вставлен оператор with в следующей форме:

             with Self do
             begin
              ...
             end;

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

             Ниже приводятся несколько примеров реализаций методов:

             procedure Rect.Intersect(var R: Rect);
             begin
                if A.X < R.A.X then A.X := R.A.X;
                if A.X < R.A.Y then A.Y := R.A.Y;

         B.Pascal 7 & Objects/LR     - 151 -

                if B.X > R.B.X then B.X := R.B.X;
                if B.Y < R.B.Y then B.Y := R.B.Y;
                if (A.X >= B.X) or (A.Y >= B.Y) then Init (0, 0, 0, 0);
             end;

             procedure Field.Display;
             begin
                GotoXY(X, Y);
                Write(Name^, ' ', GetStr);
             end;

             function NumField.PutStr(S: string): boolean;
             var
                E: integer;
             begin
                Val(S, Value, E);
                PutStr := (E = 0) and (Value >= Min) and (Value <= Max);
             end;

                           Конструкторы и деструкторы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Конструкторы и деструкторы являются специализированными фор-
        мами методов.  Используемые в  связи  с  расширенным  синтаксисом
        стандартных  процедур  New и Dispose,  конструкторы и деструкторы
        обладают способностью размещения и удаления  динамических  объек-
        тов. Кроме того, конструкторы имеют возможность выполнить требуе-
        мую инициализацию объектов,  содержащих виртуальные методы. Как и
        все другие методы,  конструкторы и деструкторы могут наследовать-
        ся,  а объекты могут содержать любое число конструкторов и  дест-
        рукторов.

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

                       ЪДДДДДДДДДДДДї   ЪДДДї   ЪДДДДДДДДДДДДї   ЪДДДї
         описание  ДДД>і  заголовок ГДД>і ; ГДД>і    блок    ГДД>і ; ГД>
         конструктора  іконструктораі   АДДДЩ   іподпрограммыі   АДДДЩ
                       АДДДДДДДДДДДДЩ           АДДДДДДДДДДДДЩ

                        ЪДДДДДДДДДДДї  ЪДДДДДДДДДДДДДї
         заголовок ДДДД>іconstructorГВ>іидентификаторГДВДДДДДДДДДДДДДДДД>
         конструктора   АДДДДДДДДДДДЩі АДДДДДДДДДДДДДЩ^і  ЪДДДДДДДДДДї ^
                                     і ЪДДДДДДДДДДДДДїіі  і  список  і і
                                     А>і уточненный  ГЩАД>іформальныхГДЩ
                                       іидентификаторі    іпараметрові
                                       і  метода     і    АДДДДДДДДДДЩ
                                       АДДДДДДДДДДДДДЩ


         B.Pascal 7 & Objects/LR     - 152 -

             Приведем несколько примеров конструкторов:

             constructor Field.Copy(var F: Field);
             begin
               Self := F;
             end;

             constructor Field.Init(FX, FY, FLen: integer; FName: string);
             begin
               X := FX;
               Y := FY;
               GetMem(Name, Length (FName) + 1);
               Name^ := FName;
             end;

             constructor TStrField.Init(FX, FY, FLen: integer; FName:
                                       string);
             begin
               inherited Init(FX, FY, FLen, FName);
               Field.Init(FX, FY, FLen, FName);
               GetMem(Value, Len);
               Value^ := '';
             end;

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

             Деструкторы ("сборщики мусора") являются противоположностями
        конструкторов и используются для очистки объектов  после  их  ис-
        пользования. Обычно очистка состоит из удаления всех полей-указа-
        телей в объекте.

                    Примечание: Деструктор может быть виртуальным и часто
              является таковым. Деструктор редко имеет параметры.

             Приведем несколько примеров деструкторов:

             destructor Field.Done;
             begin
               FreeMem(Name, Length (Name^) + 1);
             end;

             destructor StrField.Done;
             begin
               FreeMem(Value, Len);
               Field.Done;
             end;

             Деструктор дочернего  типа,   такой   как   указанный   выше

         B.Pascal 7 & Objects/LR     - 153 -

        TStrField.Done, обычно  сначала  удаляет  введенные в порожденном
        типе поля указателей,  а затем в качестве последнего действия вы-
        зывает соответствующий сборщик деструктор непосредственного роди-
        теля для удаления унаследованных полей-указателей объекта.



         B.Pascal 7 & Objects/LR     - 154 -

                       Восстановление ошибок конструктора
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Borland Pascal  позволяет вам с помощью переменной HeapError
        модуля System (см.  Главу 21) установить функцию обработки ошибки
        динамически распределяемой области.  Эта  функциональная  возмож-
        ность влияет на способ работы конструкторов объектного типа.

             По умолчанию,  когда для динамического экземпляра объекта не
        хватает памяти, вызов конструктора, использующий расширенный син-
        таксис стандартной процедуры New,  генерирует ошибку этапа выпол-
        нения 203. Если вы установили функцию обработки ошибки динамичес-
        ки распределяемой области, которая вместо стандартного результата
        функции 0 возвращает 1,  когда выполнить запрос невозможно, вызов
        конструктора через New возвращает nil (вместо прерывания програм-
        мы).

             Код, выполняющий  распределение памяти и инициализацию  поля
        таблицы виртуальных методов (VMT) динамического экземпляра объек-
        та является частью последовательности вызова конструктора.  Когда
        управление передается на оператор begin операторной  части  конс-
        труктора, память для экземпляра уже выделена,  и он инициализиро-
        ван. Если выделения памяти завершается неудачно,  и если  функция
        обработки ошибки  динамически распределяемой области памяти возв-
        ращает 1,  конструктор пропускает выполнение операторной части  и
        возвращает значение nil. Таким образом, указатель, заданный в вы-
        полняемом конструктором вызове New, устанавливается в nil.

             Когда управление передается на  оператор  begin  операторной
        части конструктора, для экземпляра объектного типа обеспечивается
        успешное выполнение памяти и инициализация. Сам конструктор может
        попытаться распределить динамические переменные для инициализации
        полей-указателей в экземпляре,  однако, такое распределение может
        завершиться неудачно.  Если это происходит, правильно построенный
        конструктор  должен отменять все успешные распределения и,  нако-
        нец,  освобождать выделенную для экземпляра объекта  память,  так
        что  результатом может стать указатель nil.  Для выполнения такой
        "отмены" Borland Pascal реализует стандартную процедуру Fail, ко-
        торая  не  требует  параметров и может вызываться только из конс-
        труктора. Вызов Fail приводит к тому, что конструктор будет осво-
        бождать  выделенную для динамического экземпляра память,  которая
        была выделена перед входом в конструктор,  и для указания неудачи
        возвращает указатель nil.

             Когда память для динамических экземпляров выделяется  с  по-
        мощью расширенного  синтаксиса  New,  результирующее значение nil
        в заданном указателе-переменной указывает,  что операция заверши-
        лась неудачно.  К сожалению, не существует такого указателя-пере-
        менной, которую можно проверить после построения статического эк-
        земпляра или  при вызове наследуемого конструктора.  Вместо этого
        Borland Pascal позволяет использовать конструктор в виде  булевс-
        кой функции в выражении:  возвращаемое значение True указывает на
        успешное выполнение,  а значение False - не неуспешное выполнение

         B.Pascal 7 & Objects/LR     - 155 -

        из-за вызова в конструкторе Fail.

             На диске  вы  можете  найти  две  программы - NORECVER.PAS и
        RECOVER.PAS. Оба программы реализуют два простых объектных  типа,
        содержащих указатели. Первая программа не содержит восстановления
        ошибок конструктора.

             Программа RECOVER.PAS  демонстрирует,  как  можно переписать
        исходный код для реализации восстановления ошибки.  Заметим,  что
        для отмены успешного выделения памяти перед вызовом Fail для ито-
        гового неуспешного выполнения используются соответствующие  дест-
        рукторы   в  Base.Init  и  Derived.Init.  Заметим  также,  что  в
        Derived.Init вызов Base.Init содержится внутри выражения, так что
        можно проверить успешность выполнения наследуемого конструктора.



         B.Pascal 7 & Objects/LR     - 156 -

                                    Параметры
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                               ЪДДДї      ЪДДДДДДДДДДї      ЪДДДї
         список формальных ДДД>і ( ГДДДДД>і описание ГДДВДД>і ) ГДД>
         параметров            АДДДЩ  ^   іпараметра і  і   АДДДЩ
                                      і   АДДДДДДДДДДЩ  і
                                      і      ЪДДДї      і
                                      АДДДДДДґ ; і<ДДДДДЩ
                                             АДДДЩ

                                   ЪДДДДДДДДДДДДДї
         описание  ДДВДДДДДДДДДДДД>ісписок иден- ГВДДДДДДДДДДДДДДДДДДДДД>
         параметра   і  ЪДДДї    ^ ітификаторов  іі                  ^
                     ГД>іvarГДДДДґ АДДДДДДДДДДДДДЩі ЪДДДї  ЪДДДДДДДї і
                     і  АДДДЩ    і                А>і : ГД>ітип па-ГДЩ
                     і  ЪДДДДДї  і                  АДДДЩ  іраметраі
                     АД>іconstГДДЩ                         АДДДДДДДЩ
                        АДДДДДЩ

             Существует три типа параметров: значение, переменная и нети-
        пизированная переменная. Они характеризуются следующим:

             1.  Группа  параметров  без  предшествующего ключевого слова
                 является списком параметров-значений.

             2.  Группа параметров, перед которыми следует ключевое слово
                 const и за которыми следует тип,  является списком пара-
                 метров-констант.

             3.  Группа параметров,  перед которыми стоит ключевое  слово
                 var и за которыми следует тип,  является списком нетипи-
                 зированных параметров-переменных.

             4.  Группа  параметров,  перед которыми стоит ключевое слово
                 var или const за которыми не следует тип, является спис-
                 ком нетипизированных параметров-переменных.

             Параметры строкового типа и массивы могут быть открытыми па-
        раметрами. Параметры-переменные,  описанные с помощью идентифика-
        тора OpenString или с использованием  ключевого  слова  string  в
        состоянии {$P+},  являются открытыми строковыми параметрами. Зна-
        чение,  константа  или  параметр-переменная,  описанные с помощью
        синтаксиса array of T, являются открытым параметром-массивом.

                   Примечание: Подробнее об открытых параметрах рассказы-
              вается ниже.

         B.Pascal 7 & Objects/LR     - 157 -


                               Параметры-значения
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

             Фактический параметр должен иметь тип,  совместимый по прис-
        ваиванию  с  типом формального параметра-значения.  Если параметр
        имеет строковый тип,  то формальный параметр будет иметь  атрибут
        размера, равный 255.


                               Параметры-константы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

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


                              Параметры-переменные
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Параметр-переменная используется,  когда значение должно пе-
        редаваться из процедуры или функции вызывающей  программе.  Соот-
        ветствующий фактический параметр в операторе вызова процедуры или

         B.Pascal 7 & Objects/LR     - 158 -

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

             Внутри процедуры  или функции любая ссылка на формальный па-
        раметр-переменную приводит к доступу к самому фактическому  пара-
        метру. Тип фактического параметра должен совпадать с  типом  фор-
        мального параметра-переменной (вы можете обойти это ограничение с
        помощью нетипизированного параметра-переменной).

                   Примечание: Файловый тип  может  передаваться  только,
              как параметр-переменная.

             Директива компилятора  $P  управляет смыслом параметра-пере-
        менной, описываемого с ключевым словом  string.  В  состоянии  по
        умолчанию ({$P-})  string соответствует строковому типу с атрибу-
        том размера 255. В состоянии {$P+} string указывает, что параметр
        является открытым строковым параметром (см. ниже).

             При ссылке  на фактический параметр-переменную,  связанную с
        индексированием массива или получением указателя на  объект,  эти
        действия выполняются перед активизацией процедуры или функции.

             Правила совместимости по присваиванию  для  объектного  типа
        применяются также  к  параметрам-переменным объектного типа.  Для
        формального параметра типа T1 фактический  параметр  должен  быть
        типа T2,  если T2 находится в домене T1.  Например, с учетом опи-
        саний Главы 4,  методу TField.Copy может  передаваться  экземпляр
        TField, TStrField,  TNumField, TZipField или любой другой экземп-
        ляр потомка TField.


                           Нетипизированные параметры
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Когда формальный параметр является нетипизированным парамет-
        ром-переменной, то  соответствующий  фактический  параметр  может
        представлять собой любую ссылку на переменную или константу,  не-
        зависимо от ее типа.  Нетипизированный параметр, описанный с клю-
        чевым словом var,  может модифицироваться, а нетипизированный па-
        раметр,  описанный  с  ключевым словом const,  доступен только по
        чтению.

             В процедуре  или функции у нетипизированного параметра-пере-
        менной тип отсутствует, то есть он несовместим с переменными всех
        типов,  пока  ему  не  будет  присвоен определенный тип с помощью
        присваивания типа переменной.

             Приведем пример нетипизированных параметров-переменных:

             function Equal(var source,dest; size: word): boolean;
             type

         B.Pascal 7 & Objects/LR     - 159 -

               Bytes = array[0..MaxInt] of byte;
             var
               N: integer;
             begin
               N := 0;
              while (N Bytes(source)[N]
                              do Inc(N);
               Equal := N = size;
             end;

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

            type
              Vector = array[1..10] of integer;
              Point = record
                        x,y: integer;
                      end;
             var
               Vec1, Vec2: Vector;
               N: integer;
               P: Point;

        и вызовов функций:

             Equal(Vec1,Vec2,SizeOf(Vector))
             Equal(Vec1,Vec2,SizeOf(integer)*N)
             Equal(Vec[1],Vec1[6],SizeOf(integer)*5)
             Equal(Vec1[1],P,4)

        сравнивается Vес1 с Vес2,  сравниваются первые N элементов Vес1 с
        первыми N элементами Vес2, сравниваются первые 5 элементов Vес1 с
        последними пятью элементами Vес2 и сравниваются Vес1[1] с  Р.х  и
        Vес2[2] с P.Y.

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




         B.Pascal 7 & Objects/LR     - 160 -

                               Открытые параметры
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Открытые параметры  позволяют передавать одной и той же про-
        цедуре или функции строки и массивы различных размеров.

                          Открытые строковые параметры
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Открытые строковые параметры могут описываться двумя  спосо-
        бами:

             - с помощью идентификатора OpenString;
             - с помощью ключевого слова string в состоянии {$P+}.

             Идентификатор OpenString описывается  в  модуле  System.  Он
        обозначает специальный строковый тип, который может использовать-
        ся только в описании строковых параметров.  В целях обратной сов-
        местимости OpenString  не является зарезервированным словом и мо-
        жет, таким образом,  быть переопределен как идентификатор, задан-
        ный пользователем.

             Когда обратная совместимость значения не имеет,  для измене-
        ния смысла ключевого слова string  можно  использовать  директиву
        компилятора {$P+}. В состоянии {$P+} переменная, описанная с клю-
        чевым словом string, является открытым строковым параметром.

             Для открытого строкового параметра фактический параметр  мо-
        жет быть переменной любого строкового типа. В процедуре или функ-
        ции атрибут размера (максимальная  длина)  формального  параметра
        будет тем же, что у фактического параметра.

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

             В следующем примере параметр S  процедуры  AssignStr  -  это
        открытый строковый параметр:

             procedure AssignStr(var S: OpenString;
             begin
               S := '0123456789ABCDEF';
             end;

             Так как S - это открытый строковый параметр, AssignStr можно
        передавать переменные любого строкового типа:

             var
               S1: string[10];
               S1: string[20];
             begin
               AssignStr(S1);           { S1 := '0123456789' }

         B.Pascal 7 & Objects/LR     - 161 -

               AssignStr(S2);           { S2 := '0123456789ABCDEF' }
             end;

             В AssingStr максимальная длина параметра S та же самая,  что
        у фактического  параметра.  Таким  образом,   в   первом   вызове
        AssingStr при присваивании параметра S строка усекается,  так как
        максимальная длина S1 равна 10.

             При применении к открытому строковому  параметру стандартная
        функция Low  возвращает  0,  стандартная  функция High возвращает
        описанную максимальную длину фактического  параметра,  а  функция
        SizeOf возвращает размер фактического параметра.

             В следующем  примере  процедура  FillString заполняет строку
        заданным символом до ее максимальной длины.  Обратите внимание на
        использование функции  High для получения максимальной длины отк-
        рытого строкового параметра.

             procedure FillStr(var S: OpenString; Ch: Char);
             begin
               S[0] := Chr(High(S));         { задает длину строки }
               FillChar(S[1], High(S), Ch);  { устанавливает число
                                               символов }
             emd;

             Значения и  параметры-константы,  описанные с использованием
        идентификатора OpenString или ключевого слова string в  состоянии
        {$P+}, не  являются  открытыми строковыми параметрами.  Они ведут
        себя также,  как если бы были описаны с максимальной длиной стро-
        кового типа  255,  а  функция  Hingh  для таких параметров всегда
        возвращает 255.




         B.Pascal 7 & Objects/LR     - 162 -

                           Открытые параметры-массивы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Формальный параметр, описанный с помощью синтаксиса:

             array of T

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

             arra[0..N - 1] of T

        где  N - число элементов в фактическом  параметре.  По  существу,
        диапазон индекса  фактического  параметра отображается в диапазон
        целых чисел от 0 до N - 1.  Если фактический параметр - это прос-
        тая переменная типа T,  то он интерпретируется как массив с одним
        элементом типа T.

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

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

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

             При применении  к  открытому  параметру-массиву  стандартная
        функция Low возвращает 0, стандартная функция High возвращает ин-
        декс последнего элемента в фактическом параметре-массиве, а функ-
        ция SizeOf возвращает размер фактического параметра-массива.

             Процедура Clear в следующем примере присваивает каждому эле-
        менту массива вещественных значений ноль, а функция Sum вычисляет
        сумму всех элементов массива вещественных чисел. Поскольку в обо-
        их случаях  параметр  A  является  открытым  параметром-массивом,
        подпрограммы могут работать с любым массивом элементов типа Real:

             procedure Clear(var A: array of Real);

         B.Pascal 7 & Objects/LR     - 163 -

             var
               I: Word;
             begin
               for I := 0 to High(A) do A[I] := 0;
             end;

             function Sum(const A: array of Real): Real;
             var
               I: Word;
               S: Real;
             begin
               S := 0;
               for I := 0 to High(A) do S := S + A[I];
               Sum := S;
             end;

             Когда типом элементов открытого  параметра-массива  является
        Char, фактический параметр может быть строковой константой.  Нап-
        ример, с учетом предыдущего описания:

             procedure PringStr(const S: array of Char);
             var
               I: Integer;
             begin
               for I := 0 to High(S) do
                   if S[I] <> #0 then Write(S[I]) else Break;
             end;

        и допустимы следующие операторы процедур:

             PrintStr('Hello word');
             PrintStr('A');

             При передаче  в  качестве открытого параметра-массива пустая
        строка преобразуется в строку с одним элементом,  содержащим сим-
        вол  NULL,  поэтому  оператор  PrintStr('')  идентичен  оператору
        PrintStr('#0').


                     Динамические переменные объектного типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Стандартные процедуры  New  и  Dispose  допускают в качестве
        второго параметра вызов конструктора или деструктора для  выделе-
        ния для памяти переменной объектного типа  или  ее  освобождения.
        При этом используется следующий синтаксис:

             New(P, Construct)
        и
             Dispose(P, Destruct)

        где P - это указатель на  переменную,  ссылающийся  на  объектный
        тип, а Construct и Destruct - это вызовы конструкторов и деструк-

         B.Pascal 7 & Objects/LR     - 164 -

        торов объектного типа. Для New эффект расширенного синтаксиса тот
        же, что и от выполнения операторов:

             New(P);
             P^.Construct;

        а для Dispose это эквивалентно операторам:

             P^.Dispose;
             Dispose(P);

             Без расширенного  синтаксиса  вам пришлось бы часто вслед за
        вызовом конструктора вызывать New,  или после вызова  деструктора
        вызывать Dispose.  Расширенный  синтаксис улучшает читаемость ис-
        ходного кода и генерирует более короткий и эффективный код.

             Приведенный пример иллюстрирует  использование  расширенного
        синтаксиса New и Dispose:

             var
               SP: PStrField
               ZP: PZipField
             begin
               New(SP, Init(1, 1, 25, 'Имя'));
               New(ZP, Init(1, 2, 5, 'Почтовый индекс'), 0, 99999));
               SP^.Edit;
               ZP^.Edit;
                 .
                 .
                 .
               Dispose(ZP, Done);
               Dispose(SP, Done);
             end;

             Вы можете также использовать New как функцию, распределяющую
        и возвращающую динамическую переменную заданного размера:

             New(T)
        или
             New(T, Construct)

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

             Приведем пример:

             var
               F1, F2: PField
             begin
               F1 := New(PStrField, Init(1, 1, 25, 'Имя'));
               F1 := New(PZipField, Init(1, 2, 5, 'Почтовый индекс', 0,

         B.Pascal 7 & Objects/LR     - 165 -

                          99999));
                   .
                   .
                   .
               WriteLn(F1^.GetStr);       { вызывает TStrField.GetStr }
               WriteLn(F2^.GetStr);       { вызывает TZipField.GetStr }
                   .
                   .
                   .
               Dispose(F2, Done);         { вызывает TField.Done }
               Dispose(F1, Done);         { вызывает TStrField.Done }
             end;

             Заметим, что хотя F1 и F2 имеют тип PField,  правила совмес-
        тимости по присваиванию расширенного указателя позволяют присваи-
        вать F1 и F2 указателю на любой потомок TField.  Поскольку GetStr
        и Done  являются виртуальными методами,  механизм диспетчеризации
        виртуального метода    корректно    вызывает,     соответственно,
        TStrString.GetStr,      TZipField.GetStr,      TField.Done      и
        TStrField.Done.


                             Процедурные переменные
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             var
               P: SwapProc;
               F: MathFunc;

             Как и целая переменная, которой можно присвоить значение це-
        лого типа, процедурной переменной можно присвоить значение проце-
        дурного типа.  Таким значением может быть, конечно, другая проце-
        дурная переменная,  но оно может также представлять собой иденти-
        фикатор процедуры или функции.  В таком контексте описания проце-
        дуры  или функции можно рассматривать,  как описание особого рода
        константы, значением которой является процедура или функция. Нап-
        ример, пусть мы имеем следующие описания процедуры и функции:

             procedure Swap(var A,B: integer);
             var
               Temp: integer;
             begin
               Temp := A;
               A := B;
               B := Temp;
             end.

             function Tan(Angle: real): real;

         B.Pascal 7 & Objects/LR     - 166 -

             begin
               Tan := Sin(Angle) / Cos(Angle);
             end.

             Описанным ранее переменным P и F теперь можно присвоить зна-
        чения:

             P := Swap;
             F := Tan;

             После такого присваивания обращение P(i,j) эквивалентно Swap
        (i,j) и F(X) эквивалентно Tan(X).

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

             Кроме того,  для обеспечения совместимости  по  присваиванию
        процедура и функция, если ее нужно присвоить процедурной перемен-
        ной, должна удовлетворять следующим требованиям:

             - Это не должна быть стандартная процедура или функция.
             - Такая процедура или функция не может быть вложенной.
             - Такая процедура не должна быть процедурой типа inline.
             - Она не должна быть процедурой прерывания (interrupt).

             Стандартными процедурами  и  функциями считаются процедуры и
        функции,  описанные в модуле System,  такие, как Writeln, Readln,
        Chr,  Ord.  Чтобы  получить  возможность использовать стандартную
        процедуру или функцию с процедурной переменной,  вы должны  напи-
        сать  для  нее специальную "оболочку".  Например,  пусть мы имеем
        процедурный тип:

             type
                IntProc = procedure(N: integer);

             Следующая процедура  для записи целого числа будет совмести-
        мой по присваиванию:

             procedure WriteInt(Number: Integer); far;
             begin
                Write(Number);
             end.

             Вложенные процедуры и функции с процедурными переменными ис-
        пользовать нельзя.  Процедура или  функция  считается  вложенной,
        когда она описывается внутри другой процедуры или функции. В сле-
        дующем примере процедура Inner вложена в процедуру Outer и поэто-
        му ее нельзя присваивать процедурной переменной:

         B.Pascal 7 & Objects/LR     - 167 -


             program Nested;
             procedure Outer;
             procedure Inner;
              begin
                Writeln('Процедура Inner является вложенной');
              end;
              begin
                Inner;
              end;
              begin
                Outer;
              end.

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

             type
               GotoProc   = procedure(X,Y: integer);
               ProcList   = array[1..10] of GotoProc;
               WindowPtr  = ^WindowRec;
               Window     = record
                              Next: WindowPtr;
                              Header: string[31];
                              Top,Left,Bottom,Right: integer;
                              SetCursor: GotoProc;
                            end;
             var
               P: ProcList;
               W: WindowPtr;

             С учетом этих описаний допустимы следующие вызовы процедур:

             P[3](1,1);
             W.SetCursor(10,10);

             Когда процедурной переменной присваивается значение процеду-
        ры, то на физическом уровне происходит следующее: адрес процедуры
        сохраняется  в  переменной.  Фактически,  процедурная  переменная
        весьма  напоминает переменную-указатель,  только вместо ссылки на
        данные она указывает на процедуру или функцию.  Как и  указатель,
        процедурная  переменная  занимает 4 байта (два слова),  в которых
        содержится адрес памяти.  В первом слове  хранится  смещение,  во
        втором - сегмент.




         B.Pascal 7 & Objects/LR     - 168 -

                           Параметры процедурного типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             program Tables;

             type
               Func = function(X,Y: integer): integer;

             function Add(X,Y: integer): integer; far;
             begin
                Add := X + Y;
              end;

             function Multiply(X,Y: integer): integer; far;
             begin
                Multiply := X*Y;
             end;

             function Funny(X,Y: integer): integer; far;
             begin
                 Funny := (X+Y) * (X-Y);
             end;

             procedure PrintTable(W,H: integer; Operation: Func);
             var
                X,Y : integer;
             begin
                for Y := 1 to H do
                begin
                  for X := 1 to W do Write(Operation(X,Y):5);
                  Writeln;
                end;
                Writeln;
             end;

             begin
               PrintTable(10,10,Add);
               PrintTable(10,10,Multiply);
               PrintTable(10,10,Funny);
             end.

         B.Pascal 7 & Objects/LR     - 169 -


             При работе программа Table выводит три  таблицы.  Вторая  из
        них выглядит следующим образом:

                    1   2   3   4   5   6   7   8   9   10
                    2   4   6   8  10  12  14  16  18   20
                    3   6   9  12  15  18  21  24  27   30
                    4   8  12  16  20  24  28  32  36   40
                    5  10  15  20  25  30  35  40  45   50
                    6  12  18  24  30  36  42  48  54   60
                    7  14  21  28  35  42  49  56  63   70
                    8  16  24  32  40  48  56  64  72   80
                    9  18  27  36  45  54  63  72  81   90
                   10  20  30  40  50  60  70  80  90  100

             Параметры процедурного типа особенно полезны в  том  случае,
        когда  над  множеством  процедур  или функций нужно выполнить ка-
        кие-то общие  действия.  В  данном  случае  процедуры  PrintTable
        представляет собой общее действие, выполняемое над функциями Add,
        Multiply и Funny.

             Если процедура или функция должны  передаваться  в  качестве
        параметра, они должны удовлетворять тем же правилам совместимости
        типа,  что и при присваивании. То есть, такие процедуры или функ-
        ции  должны  компилироваться с директивой far,  они не могут быть
        встроенными функциями, не могут быть вложенными и не могут описы-
        ваться с атрибутами inline или interrupt.



         B.Pascal 7 & Objects/LR     - 170 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                          Глава 10. Программы и модули
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

                               Синтаксис программ
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Программа в  Borland  Pascal состоит из заголовка программы,
        необязательного оператора uses и основного блока.

        программа
          і      ЪДДДДДДДДДї   ЪДДДї                      ЪДДДДї  ЪДДДї
          АДДДВД>ізаголовокГДД>і ; ГДДДВДДДДДДДДДДДДДДДДД>іблокГД>і . ГД>
              і  іпрограммыі   АДДДЩ ^ і  ЪДДДДДДДДДДДї ^ АДДДДЩ  АДДДЩ
              і  АДДДДДДДДДЩ         і АД>іпредложениеГДЩ
              АДДДДДДДДДДДДДДДДДДДДДДЩ    і   uses    і
                                          АДДДДДДДДДДДЩ


                               Заголовок программы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Заголовок программы определяет имя программы и ее параметры.

        заголовок программы
         і
         і   ЪДДДДДДДї   ЪДДДДДДДДДДДДДї
         АДД>іprogramГДД>іидентификаторГДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД>
             АДДДДДДДЩ   АДДДДДДДДДДДДДЩ і  ЪДДДї  ЪДДДДДДДДДї  ЪДДДї ^
                                         АД>і ( ГД>іпараметрыГД>і ) ГДЩ
                                            АДДДЩ  іпрограммыі  АДДДЩ
                                                   АДДДДДДДДДЩ

                                  ЪДДДДДДДДДДДДДДДї
         параметры программы ДДДД>і   список      ГДДДД>
                                  іидентификаторові
                                  АДДДДДДДДДДДДДДДЩ

             Если заголовок программы присутствует, он является чисто де-
        коративной деталью и компилятор его игнорирует.



         B.Pascal 7 & Objects/LR     - 171 -

                                  Оператор uses
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Оператор uses идентифицирует все модули,  используемые прог-
        раммой, включая непосредственно используемые модули и модули, ис-
        пользуемые этими модулями.

                             ЪДДДДї      ЪДДДДДДДДДДДДДї      ЪДДДї
         предложение uses ДД>іusesГДДВДД>іидентификаторГДДДДД>і ; ГДДД>
                             АДДДДЩ  і   АДДДДДДДДДДДДДЩ  ^   АДДДЩ
                                     і      ЪДДДї         і
                                     АДДДДД>і , ГДДДДДДДДДЩ
                                            АДДДЩ

             Модуль System всегда используется  автоматически.  Для  под-
        держки таких средств,  как файловый ввод-вывод,  обработка строк,
        операции с плавающей запятой, динамическое распределение памяти и
        других этот модуль реализует весь нижний уровень,  а также обслу-
        живающие фоновые программы.

             Паскаль, в свою очередь,  обслуживает многие стандартные мо-
        дули, такие,  как Dos и Crt.  Это не происходит автоматически: вы
        должны обязательно включить их в оператор uses. Например:

             uses Dos,Crt; { теперь могут быть доступны средства модулей
                             Dos и Crt }


             Чтобы найти файл, содержащий скомпилированный модуль, компи-
        лятор усекает  указанное  в  операторе  uses имя модуля до первых
        восьми файлов и добавляет расширение файла. Если целевой платфор-
        мой является DOS,  расширением будет .TPU. Если целевая платформа
        - Windows, то расширением файла будет .TPW. Если целевой платфор-
        мой является  защищенный  режим  DOS,  то расширением файла будет
        .TPP. Хотя имена файлов усекаются, в операторе uses должен указы-
        ваться полный идентификатор модуля.



         B.Pascal 7 & Objects/LR     - 172 -

                                Синтаксис модулей
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модули являются основой модульного программирования. Они ис-
        пользуются  для  создания  библиотек,  которые могут включаться в
        различные программы (при этом становится необязательным  иметь  в
        наличии  исходный код),  а большие программы могут подразделяться
        на логически связанные модули.

                         ЪДДДДДДДДДї   ЪДДДї   ЪДДДДДДДДДДї
           модуль  ДДДДД>ізаголовокГДД>і ; ГДД>іинтерфейс-ГДДДї
                         і модуля  і   АДДДЩ   іный разделі   і
                         АДДДДДДДДДЩ           АДДДДДДДДДДЩ   і
                       ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
                       і  ЪДДДДДДДДДДї    ЪДДДДДДДДДДДДДї   ЪДДДї
                       АД>і раздел   ГДДД>і раздел      ГДД>і . ГДД>
                          іреализацииі    іинициализацииі   АДДДЩ
                          АДДДДДДДДДДЩ    АДДДДДДДДДДДДДЩ

                                Заголовок модуля
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В заголовке модуля определяется имя модуля.

                              ЪДДДДї   ЪДДДДДДДДДДДДДДДДДДДДї
         заголовок модуля ДДД>іunitіДД>іидентификатор модуляіДДДД>
                              АДДДДЩ   АДДДДДДДДДДДДДДДДДДДДЩ

             Имя модуля используется при ссылке на модуль  в  предложении
        использования. Это имя должно быть уникальным, так как два модуля
        с одним именем не могут одновременно использоваться.

             Имя исходного  файла  модуля и двоичного файла должны совпа-
        дать с идентификатором модуля,  усеченным до первых  8  символов.
        Если это  не  так,  то  компилятор не сможет найти исходный и/или
        двоичный файл при компиляции использующей этот модуль программы.



         B.Pascal 7 & Objects/LR     - 173 -

                               Интерфейсная секция
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В интерфейсной секции описываются те константы,  типы, пере-
        менные,  процедуры и функции,  которые являются  глобальными,  то
        есть доступными основной программе (программе или модулю, которые
        используют данный модуль). Основная программа имеет доступ к этим
        элементам, как если бы они были описаны в модуле, являющимся вло-
        женным по отношению к данной программе.

         интерфейсная секция
         і
         і  ЪДДДДДДДДДї
         АД>іinterfaсeГДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДВД>
            і         і і  ЪДДДДДДДДДДДї^ ^ і  ЪДДДДДДДДДДДДДДДДДДї ^ і
            АДДДДДДДДДЩ АД>і  оператор ГЩ і ГД>і  раздел описания ГДґ і
                           і   uses    і  і і  і     констант     і і і
                           АДДДДДДДДДДДЩ  і і  АДДДДДДДДДДДДДДДДДДЩ і і
                                          і і  ЪДДДДДДДДДДДДДДДДДДї і і
                                          і ГД>і  раздел описания ГДґ і
                                          і і  і типов переменных і і і
                                          і і  АДДДДДДДДДДДДДДДДДДЩ і і
                                          і і  ЪДДДДДДДДДДДДДДДДДДї і і
                                          і ГД>і  раздел описания ГДґ і
                                          і і  і    переменных    і і і
                                          і і  АДДДДДДДДДДДДДДДДДДЩ і і
                                          і і  ЪДДДДДДДДДДДДДДДДДДї і і
                                          і АД>іраздел заголовков ГДЩ і
                                          і    іпроцедур и функцийі   і
                                          і    АДДДДДДДДДДДДДДДДДДЩ   і
                                          АДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

         раздел заголовков
         процедур и функций
          і        ЪДДДДДДДДДї           ЪДДДї
          АДДДДВДД>ізаголовокГДДДДДДДДДД>і ; ГДВДДДДДДДДДДДДДДДДДДДДДДД>
               і   іпроцедурыі        ^  АДДДЩ і  ЪДДДДДДДДДї   ЪДДДї ^
               і   АДДДДДДДДДЩ        і        АД>ідирективаГДД>і ; ГДЩ
               і  ЪДДДДДДДДДДДДДДДДДї і           і inline  і   АДДДЩ
               АД>ізаголовок функцииГДЩ           АДДДДДДДДДЩ
                  АДДДДДДДДДДДДДДДДДЩ

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


         B.Pascal 7 & Objects/LR     - 174 -

                                Секция реализации
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

         Секция реализации
         і
         і  ЪДДДДДДДДДДДДДДї                     ЪДДДДДДДДДДДДДДДДДДї
         АД>іimplementationГДВДДДДДДДДДДДДДДДДДД>і раздел описаний  ГДД>
            АДДДДДДДДДДДДДДЩ і  ЪДДДДДДДДДДДї^   АДДДДДДДДДДДДДДДДДДЩ
                             АД>і  оператор ГЩ
                                і   uses    і
                                АДДДДДДДДДДДЩ

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

             Допускается дублирование заголовков процедур  и  функций  из
        интерфейсной  части.  Вам  не нужно при этом задавать список фор-
        мальных параметров,  но если вы это делаете,  компилятор на этапе
        компиляции  в случае несовпадения описаний в интерфейсной части и
        секции реализации будет выдавать сообщение об ошибке.

         B.Pascal 7 & Objects/LR     - 175 -

                              Секция инициализации
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Секция инициализации является последней секцией  модуля. Она
        может  состоять либо из зарезервированного слова end (в этом слу-
        чае модуль не содержит кода инициализации),  либо из  операторной
        части, которая должна выполняться для инициализации модуля.

                                         ЪДДДї
             секция инициализации ДДДВДД>іendГДДДДДДДДДДДДДДДДДД>
                                     і   АДДДЩ              ^
                                     і  ЪДДДДДДДДДДДДДДДДДї і
                                     АД>іоператорная частьГДЩ
                                        АДДДДДДДДДДДДДДДДДЩ

             Секции инициализации модулей,  которые используются програм-
        мой,  выполняются в том же порядке, в каком модули указаны в опе-
        раторе uses.

                           Косвенные ссылки на модули
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Program Prog;
             uses Unit1, Unit2
             const a = b;
             begin
             end.
             end.

             unit Unit2;
             interface
             uses Unit1;
             const b = c;
             implementation
             end.

             unit Unit1;
             interface
             const c = 1;
             implementation
             const d = 2;
             end;

             В данном примере Unit12 непосредственно зависит от Unit1,  а
        Prog непосредственно зависит от Unit2.  Кроме того,  Prog зависит
        косвенно от Unit1 (через Unit1),  хотя ни  один  из  описанных  в
        Unit1 идентификаторов в Prog не доступен.

             Для компиляции программы компилятор должен иметь возможность

         B.Pascal 7 & Objects/LR     - 176 -

        находить все модули,  от которых она прямо или косвенно  зависит.
        Поэтому, для  компиляции Prog компилятор должен иметь возможность
        найти и Unit1, и Unit2, иначе возникнет ошибка.

             Когда в интерфейсную часть модуля вносятся изменения, другие
        модули,  использующие этот модуль, должны быть заново скомпилиро-
        ваны. При использовании команд Make или Build  компилятор  делает
        это автоматически. Однако, если изменения коснулись только секции
        реализации или секции инициализации,  то другие модули, в которых
        используется этот модуль,  перекомпилировать не нужно. В предыду-
        щем примере,  если интерфейсная  часть  модуля  Unit1  изменилась
        (например, с = 2), то модуль Unit2 нужно перекомпилировать. Изме-
        нение же секции реализации (например,  d = 1) не требует переком-
        пиляции Unit2.

             При компиляции модуля в Borland Pascal на основе контрольной
        суммы интерфейсной секции вычисляется номер версии модуля. В пре-
        дыдущем  примере  при  компиляции модуля Unit2 в скомпилированной
        версии модуля Unit2 сохраняется номер версии  модуля  Unit1.  При
        компиляции основной программы номер версии модуля Unit1 сравнива-
        ется с номером версии,  сохраненным в модуле Unit2.  Если  номера
        версий  не  совпадают,  что свидетельствует об изменении в интер-
        фейсной части модуля Unit1 со времени последней компиляции модуля
        Unit2, компилятор, в зависимости от режима компиляции, выдает со-
        общение об ошибке или перекомпилирует модуль Unit2 (в зависимости
        от режима компиляции).



         B.Pascal 7 & Objects/LR     - 177 -

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

             Размещение в  секции  реализации  оператора  uses  позволяет
        "скрыть" внутренние детали модуля,  поскольку используемые в сек-
        ции реализации модули оказываются "невидимыми" для того, кто этот
        модуль использует.  Более важным,  однако,  является то,  что это
        позволяет вам строить взаимозависимые модули.

             В следующей программе показаны два модуля,  которые "исполь-
        зуют" друг друга. Основная программа Circular использует модуль с
        именем Display. Модуль Display содержит в своей интерфейсной сек-
        ции одну программу WriteXY, которая имеет три параметра: пару ко-
        ординат (x,y) и сообщение для вывода на экран. WriteXY перемещает
        курсор в точку (x,y) и выводит там сообщение.  В противном случае
        она вызывает простую программу обработки ошибки.

             Пока мы не видим здесь ничего интересного: процедура WriteXY
        просто используется вместо процедуры Write.  Однако далее,  когда
        программа обработки ошибки будет выводить сообщение на экран, на-
        чинаются  перекрестные ссылки (ведь при этом она снова использует
        WriteXY).  Таким образом,  мы имеем процедуру WriteXY, вызывающую
        процедуру обработки ошибки SwapError,  которая в свою очередь вы-
        зывает WriteXY для вывода сообщения на экран.  Если у вас уже  от
        всего этого закружилась голова,  не беда.  Давайте рассмотрим ис-
        ходный код в примере и увидим, что все это не столь уж запутано.

             Основная программа Circular очищает экран  и  выполняет  три
        обращения к процедуре WriteXY:

             program Circular;
             { выводит текст, используя WriteXY }

             uses
                WinCrt, Display;

             begin
               ClrScr;
               WriteXY(1, 1, 'Левый верхний угол экрана');
               WriteXY(100, 100, 'За пределами экрана');
               WriteXY(81 - Lenght('Снова в экран..'), 15,
                                   'Снова в экран..');
             end.

             Взгляните на  координаты (x,y) при втором обращении к проце-
        дуре WriteXY.  В точке с координатами (100,100) на 80х25-символь-
        ном  экране  вывести текст невозможно.  Давайте теперь посмотрим,
        как работает процедура WriteXY.  Далее приведен  текст  исходного
        кода модуля Display, в котором содержится процедура WriteXY. Если
        координаты (x,y) являются допустимыми, она выводит на экран сооб-
        щение. В противном случае она выводит сообщение об ошибке.

             unit Display;

         B.Pascal 7 & Objects/LR     - 178 -

             { содержит простую программу вывода информации на экран }

             interface

             procedure WriteXY(X,Y : integer, Message : string);

             implementation
             uses
                Crt, Error;
             procedure WriteXY(X,Y : integer, Message : string);
             begin
               if (X in [1..80] and Y in [1..25] then
               begin
                 Goto(X,Y);
                 Write(Message);
               end;
               else
                 ShowError('Неверные координаты в процедуре WriteXY');
             end;

             end.

             Процедура ShowError, вызываемая в процедуре WriteXY, показа-
        на в приведенном далее исходном коде модуля Error. Она всегда вы-
        водит сообщение об ошибке на 25-й строке экрана.

             unit Error;
             { содержит простую программу сообщения об ошибке }

             interface

             procedure ShowError(ErrMsg : string);

             implementation

             uses
                Display;

             procedure ShowError(ErrMsg :string);
             begin
               WriteXY(1,25, 'Ошибка: '+ ErrMsg);
             end;

             end.

             Обратите внимание,  что  операторы  uses в секции реализации
        обоих модулей (Display и Error) ссылаются друг на друга.  Эти два
        модуля могут ссылаться друг на друга в секции реализации благода-
        ря тому,  что Borland Pascal может для  обеих  модулей  выполнять
        полную компиляцию интерфейсных секций.  Другими словами, компиля-
        тор воспринимает ссылку на частично скомпилированный модуль  A  в
        секции  реализации модуля В,  если интерфейсные секции модуля A и
        модуля В не зависят друг от друга (и,  следовательно, строго соб-

         B.Pascal 7 & Objects/LR     - 179 -

        людаются правила Паскаля, касающиеся порядка описания).

             В случае  взаимозависимости  интерфейсных  секций модулей вы
        получите ошибку из-за перекрестных ссылок.


                        Совместное использование описаний
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Можно модифицировать процедуру WriteXY таким образом,  чтобы
        она воспринимала дополнительный параметр,  задающий прямоугольное
        окно на экране:

             procedure WriteXY(SomeWindow : WindRec;
                               X, Y :       integer;
                               Message :    string);

             procedure ShowError(Somewindow : WindRec; ErrMsg : string);

             Нужно учитывать,  что две процедуры находятся в разных моду-
        лях. Даже если вы описываете WindData в интерфейсной секции одно-
        го модуля,  то нет такого допустимого способа, с помощью которого
        это описание могло бы быть доступно в другом модуле. Решение сос-
        тоит в том,  чтобы описать третий модуль,  в  котором  содержится
        только определение записи WindRec:

             unit WindData;
             interface

             type
               WindRec = record
                          X1, Y1, X2, Y2 : integer;
                          ForeColor,
                          BackColor      : byte;
                          Active         : boolean;
                         end;
             implementation
             end.

             В добавление к тому, что модификация кода процедур WriteXY и
        ShowError  позволяет использовать новый параметр,  в интерфейсной
        секции  модулей  Display  и  Error  теперь  может  использоваться
        WindData.  Это  допустимо,  так как модуль WindData не зависит от
        своего оператора uses, а модули Display и Error ссылаются друг на
        друга только в соответствующих секциях реализации.

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



         B.Pascal 7 & Objects/LR     - 180 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                  Глава 11. Динамически компонуемые библиотеки
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Динамически компонуемые  библиотеки (DLL) позволяют несколь-
        ким прикладным программа Windows или DOS защищенного режима  сов-
        местно использовать код и ресурсы. В Borland Pascal вы можете как
        использовать существующие DLL,  так и написать  свои  собственные
        DLL, которые можно применять в других программах.

                                 Что такое DLL?
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             DLL - это выполняемый модуль, содержащий программный код или
        ресурсы, используемые  другими  прикладными  программами или DLL.
        Концептуально динамически компонуемая библиотека аналогичная  мо-
        дулю - они обеспечивают для программ процедуры и функции.  Однако
        между DLL и модулями имеются существенные различия.  В частности,
        модули компонуются статически, а DLL - динамически.

             Когда программа  использует процедуру или функцию из модуля,
        копия кода этой процедуры или функции  статически  компонуется  с
        выполняемым файлом программы.  Если две программы выполняются од-
        новременно и используют одну и ту же процедуру и функцию  модуля,
        то в  системе  будет  присутствовать две копии этой подпрограммы.
        Эффективнее было бы использовать одну  копию.  Такую  возможность
        предоставляет DLL.

             В отличие  от  модуля  DLL не компонуется с использующей DLL
        программой. Вместо этого код и ресурсы DLL находятся в  отдельном
        выполняемом файле  с расширением .DLL.  Этот файл должен присутс-
        твовать при выполнении программы-клиента.  Вызываемые  программой
        процедуры и  функции  динамически  компонуются  со своими точками
        входа в используемой программе DLL.

             Другое отличие модулей от DLL состоит в том,  что модули мо-
        гут экспортировать  типы,  константы,  данные и объекты,  а DLL -
        только процедуры и функции.

             Чтобы ее можно было использовать в программе Borland Pascal,
        DLL не обязательно должна быть написана на Borland Pascal.  Кроме
        того, программы,  написанные на других языках, могут использовать
        DLL, написанные на Borland Pascal.  DLL,  таким образом, идеально
        подходит при программных проектах, реализуемых на нескольких язы-
        ках.


                                Использование DLL
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Чтобы модуль мог использовать процедуру или функцию  в  DLL,
        он должен  импортировать процедуру или функцию с помощью описания
        external. Например,  в следующем описании из DLL и именем  KERNEL
        (ядро Windows) импортируется функция с именем GlobalAlloc:

         B.Pascal 7 & Objects/LR     - 181 -


             function GlobalAlloc(Glags: Word; Bytes: Longint): THandle;
                 far; external 'KERNEL' index 15;

             В импортируемой процедуре или функции директива external за-
        нимает место описательной и операторной части, которые нужно было
        бы включить в противном  случае.  В  импортируемых  процедурах  и
        функциях должна  использоваться дальняя модель вызова,  выбранная
        ключевым словом far или директивой компилятора {$F+}; во всем ос-
        тальном их поведение не отличается от обычных процедур и функций.

             Borland Pascal  импортирует процедуры и функции тремя спосо-
        бами:

             - по имени;
             - по новому имени;
             - по порядковому номеру.

             Формат директив external для каждого из трех методов показан
        в приведенном ниже примере.

             Когда оператор index или name не указан, процедура или функ-
        ция экспортируются по имени.  Это имя совпадает с идентификатором
        процедуры или  функции.  В  данном примере процедура ImportByName
        импортируется из библиотеки 'TESTLIB' по имени 'IMPORTBYNAME':

             procedure ImportByName; external 'TESTLIB';

             Когда задан оператор name,  процедура или функция импортиру-
        ется  под именем,  отличным от имени идентификатора.  В следующем
        примере процедура  ImportByName   импортируется   из   библиотеки
        'TESTLIB' по имени 'REALNAME':

             procedure ImportByName; external 'TESTLIB'name 'REALNAME'

             Наконец, при  наличии  оператор  index процедура или функция
        импортируется по порядковому значению. Такой вид импорта уменьша-
        ет время  загрузки модуля,  так как отпадает необходимость поиска
        имени  в  таблице  имен  DLL.  В  следующем   примере   процедура
        ImportByOrd импортируется из библиотеки 'TESTLIB':

             procedure ImportByOrd; external 'TESTLIB' index 5;

             Имя DLL  задается  после  ключевого слова external,  а новое
        имя, заданное в операторе name,  не  обязано  представлять  собой
        строковые литералы.  Допускается  любое строковое выражение-конс-
        танта. Аналогично,  порядковый  номер,  задаваемый  в   операторе
        index, может быть любым целочисленным выражением-константой.

             const
                TestLib = TestLib;
                Ordinal = 5;


         B.Pascal 7 & Objects/LR     - 182 -

             procedure ImportByName; external TestLib;
             procedure ImportByName; external TestLibname 'REALNAME'
             procedure ImportByOrd; external TestLib index Ordinal;

             Хотя DLL может содержать переменные, импортировать их в дру-
        гие модули невозможно.  Любой доступ к переменным DLL должен осу-
        ществляться через процедурный интерфейс.


                                 Модули импорта
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Описания импортируемых процедур и функций  могут  помещаться
        непосредственно в программу, которая их импортирует. Однако обыч-
        но они объединяются в модуль импорта,  содержащий  описания  всех
        процедур и функций в DLL, а также все типы и константы, необходи-
        мые для интерфейса с DLL. Примерами таких модулей импорта являют-
        ся поставляемые  с  Borland  Pascal  модули WinTypes,  WinProcs и
        WinAPI. Модули импорта не обязательны для интерфейса  с  DLL,  но
        они значительно  упрощают обслуживание использующих множество DLL
        проектов.

             В качестве примера рассмотрим DLL с именем DATETIME.DLL, со-
        держащую четыре  подпрограммы  для  получения  и установки даты и
        времени с помощью типа записи, содержащей число, месяц, год и за-
        писи, которая содержит секунду, минуту и час. Вместо спецификации
        соответствующих описаний процедуры,  функции и типа в каждой  ис-
        пользующей DLL  программе вы можете построить наряду с DLL модуль
        импорта. В следующем примере создается файл .TPW  (в  предположе-
        нии, что целевой платформой является Windows), но отсутствуют код
        и данные для использующей его программы.

             unit DateTime;

             interface

             type
               TTimeRec = record
                   Second: Integer;
                   Minute: Integer;
                   Hour: Integer;
               end;

             type
               TDateRec
                  TDateRec = record
                    Day: Integer;
                    Month: Integer;
                    Year: Integer;
                  end;

             procedure SetTime(var Time: TTimeRec);
             procedure GetTime(var Time: TTimeRec);

         B.Pascal 7 & Objects/LR     - 183 -

             procedure SetDate(var Date: TDateRec);
             procedure GetDate(var Date: TDateRec);

             inplementation

             procedure SetTime; external 'DATETIME' index 1;
             procedure GetTime; external 'DATETIME' index 2;
             procedure SetDate; external 'DATETIME' index 3;
             procedure GetTime; external 'DATETIME' index 4;

             end.

             Любая программа,   использующая  DATETIME.DLL  может  теперь
        просто задать в своем операторе uses  модуль  DateTime.  Приведем
        пример программы Windows:

             program ShowTime;

             uses WinCrt, DateTime;

             var
               Time: TTimeRec;

             begin
               GetTime(Time);
               with Time do
                 WriteLn('Текущее время: ', Hour, ':', Minute, ':',
                    Second);
             end.

             Другим преимуществом  использования  модуля импорта,  такого
        как DateTime, является то, что при модификации DATETIME.DLL обно-
        вить требуется только модуль импорта DateTime.

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

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




         B.Pascal 7 & Objects/LR     - 184 -

                        Статический и динамический импорт
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Директива external обеспечивает возможность статического им-
        порта процедур и функций из DLL.  Статически импортируемая проце-
        дура и функция всегда ссылается на одну и ту  же  точку  входа  в
        DLL. Расширения  Windows и защищенного режима DOS Borland поддер-
        живает также динамический импорт,  при котором имя DLL и имя  или
        порядковый номер  импортируемой процедуры или функции задается во
        время выполнения.  Приведенная ниже программа ShowTime использует
        динамический импорт  для вызова процедуры GetTime в DATETIME.DLL.
        Обратите внимание на использование переменной  процедурного  типа
        для представления адреса процедуры GetTime.

             program ShowTime;

             uses WinProcs, WinTypes, WinCrt;

             type
               TTimeRec = record
                   Second: Integer;
                   Minute: Integer;
                   Hour: Integer;
               end;
               TGetTime = procedure(var Time: TTimeRec);

             var
               Time: TTimeRec;
               Handle: THAndle;
               GetTime: TGetTime;

             begin
               Handle := LoadLibrary('DATETIME.DLL');
               if Handle >= 32 then
               begin
                 @GetTie := GetProcAddress(Handle, 'GETTIME');
                 if @GetTime <> nil then
                  begin
                    GetTime(Time);
                    with Time do
                      WriteLn('Текущее время: ', Hour, ':', Minute, ':',
                               Second);
                   end;
                   FreeLibrary(Handle);
                 end;
             end;




         B.Pascal 7 & Objects/LR     - 185 -

                                  Написание DLL
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Структура DLL Borland Pascal идентичная структуре программы,
        но DLL начинается вместо заголовка program с  заголовка  program.
        Заголовок library указывает Borland Pascal, что нужно создать вы-
        полняемый файл с расширением .DLL, а не с расширением .EXE, и вы-
        полняемый файл помечается как DLL.

         библиотека
         і
         і   ЪДДДДДДДДДДДДДї   ЪДДДї                    ЪДДДДДДї
         АДД>і  заголовок  ГДД>і ; ГДВДДДДДДДДДДДДДДДДДДі блок ГДДДДДДД>
             і библиотеки  і   АДДДЩ і   ЪДДДДДДДДДДї ^ АДДДДДДЩ
             АДДДДДДДДДДДДДЩ         АДД>і оператор ГДЩ
                                         і   uses   і
                                         АДДДДДДДДДДЩ

                        ЪДДДДДДДДДї   ЪДДДДДДДДДДДДДДДї
         заголовок ДДДД>і library ГДД>і идентификатор ГДДДДД>
         процедуры      АДДДДДДДДДЩ   АДДДДДДДДДДДДДДДЩ

             В приведенном ниже примере приведена  очень  простую  DLL  с
        двумя экспортируемыми функциями Min и Max, которые вычисляют наи-
        меньшее и наибольшее из двух целочисленных значений.

             library MinMax;

             function Min(X, Y: Integer): Integer; export;
             begin
               if X < Y then Min := X else Min := Y;
             end;

             function Max(X, Y: Integer): Integer; export;
             begin
               if X > Y then Max := X else Max := Y;
             end;

             exports
                Min index 1,
                Max index 2;

             begin
             end.

             Обратите внимание на использование для подготовки Min и Max,
        для экспорта ключевого слова export,  и на оператор exports,  ис-
        пользуемый для фактического экспорта двух подпрограмм,  указываю-
        щий, для каждой из них, необязательный порядковый номер.

            Хотя предыдущий пример этого не показывает,  библиотека может
        состоять из  нескольких  модулей.  В  таких случаях исходный файл
        библиотеки часто сводится к оператору uses,  оператору exports  и

         B.Pascal 7 & Objects/LR     - 186 -

        коду инициализации библиотеки. Например:

             library Eritors;

             uses EdInit, EdInOut, EdFormat, EdPrint;

             exports
               InitEditors index 1,
               DoneEditors index 2,
               InsertText index 3,
               DeleteSelection index 4,
               FormatSelection index 5,
               PrintSelection index 6,
                    .
                    .
                    .
               SetErrorHandler index 53;

             begin
               InitLibrary;
             end.




         B.Pascal 7 & Objects/LR     - 187 -

                           Директива процедуры export
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Если процедуры и функции должны  экспортироваться  DLL,  они
        должны компилироваться с директивой компилятора export. Директива
        export принадлежит к тому же семейству процедурных директив,  что
        и near,  far,  inline  и interrupt.  Это означает,  что директива
        export, если она присутствует,  должна указываться  перед  первым
        заданием процедуры или функции - она не может указываться в опре-
        деляющем описании или в опережающем описании.

             Директива export делает процедуру или  функцию  экспортируе-
        мой. Она  принудительно  использует  для подпрограммы дальний тип
        вызова и подготавливает ее для экспорта,  генерируя для процедуры
        специальный код входа и выхода.  Заметим, однако, что фактический
        экспорт процедуры или функции не происходит, пока подпрограмма не
        перечисляется в операторе exports библиотеки.


                                Оператор exports
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Процедура или функция экспортируется DLL, когда она указыва-
        ется в операторе exports библиотеки.

         оператор exports
         і   ЪДДДДДДДДДї   ЪДДДДДДДДДДДДДДДДї            ЪДДДї
         АДД>і exports ГДД>і список экспортаГДДДДДДДДДДД>і ; ГДДДДДДД>
             АДДДДДДДДДЩ   АДДДДДДДДДДДДДДДДЩ            АДДДЩ

                              ЪДДДДДДДДДДДДДДДДї
         список экспорта ДДВД>і запись экcпортаГДДДДДДДДДДД>
                           і  АДДДДДДДДДДДДДДДДЩ  ^
                           і        ЪДДДї         і
                           АДДДДДДД>і ; ГДДДДДДДДДЩ
                                    АДДДЩ

         оператор exports
           і    ЪДДДДДДДДДДДДДДДї
           АДДД>і идентификатор ГДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
                АДДДДДДДДДДДДДДДЩ  і   ЪДДДДДДДї  ЪДДДДДДДДДДДДДДДДДї ^ і
                                   АДД>і index ГД>і целая константа ГДЩ і
                                       АДДДДДДДЩ  АДДДДДДДДДДДДДДДДДЩ   і
         ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
         АДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДД>
           і ЪДДДДДДї   ЪДДДДДДДДДДДДДДДДДДДДДї ^і  ЪДДДДДДДДДДї  ^
           А>і name ГДД>і строковая константа ГДЩАД>і resident ГДДЩ
             АДДДДДДЩ   АДДДДДДДДДДДДДДДДДДДДДЩ     АДДДДДДДДДДЩ

             Оператор exports  может встречаться в любом месте описатель-
        ной части программы или библиотеки и любое число раз.  Каждая за-
        пись в операторе exports задает идентификатор экспортируемой про-
        цедуры или функции. Однако, эта процедура или функция должна опи-

         B.Pascal 7 & Objects/LR     - 188 -

        сываться до оператора exports, и ее описание должно содержать ди-
        рективу export.  Перед идентификатором в операторе exports вы мо-
        жете указать  идентификатор модуля с точкой;  это называется пол-
        ностью уточненным идентификатором.

             Запись экспорта может также включать в себя оператор  index,
        который состоит из ключевого слова index,  за которым следует це-
        лочисленное значение в диапазоне от 1 до  32767.  Когда  задается
        оператор index,  для  экспортируемой процедуры или функции должно
        использоваться специальное порядковое  значение.  Если  в  записи
        экспорта оператор index отсутствует, то порядковое значение прис-
        ваивается автоматически.

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

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

             Программа может содержать оператор exports,  но это встреча-
        ется редко,  так как Windows не позволяет  прикладным  программам
        экспортировать функции,  используемые другие прикладными програм-
        мами.



         B.Pascal 7 & Objects/LR     - 189 -

                          Код инициализации библиотеки
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             DLL хранится в памяти,  пока ее счетчик использования больше
        нуля. Когда  счетчик использования становится нулевым,  указывая,
        что все использующие DLL прикладные программы  завершили  работу,
        она удаляется из памяти. При этом выполняется код процедуры выхо-
        да. Процедуры  выхода   регистрируются   с   помощью   переменной
        ExitProc, которая описывается в Главе 22 "Вопросы управления".

             Код инициализации  DLL обычно выполняет такие задачи как ре-
        гистрация класса окна для содержащихся в DLL оконных  процедур  и
        установка начальных значений для глобальных переменных DLL. Уста-
        новив в нулевое значение переменную ExitCode,  код  инициализации
        библиотеки может указать состояние ошибки (ExitCode описывается в
        модуле System).  По умолчанию ExitCode равна 1,  что указывает на
        успешную инициализацию. Если код инициализации устанавливает зна-
        чение этой переменной в 0,  то DLL выгружается из системной памя-
        ти,  и вызывающая прикладная программа уведомляется  о  неудачной
        загрузке DLL.

             Когда выполняется библиотечная процедура выхода,  переменная
        ExitCode не  содержит  код  завершения  процесса.  Вместо   этого
        ExitCode содержит  одно  из значений wep_System или wep_Free_DLL,
        определенных в модуле WinTypes.  wep_System указывает на заверше-
        ние работы Windows, а wep_Free_DLL указывает на то, что выгружена
        данная DLL.

             Приведем пример библиотеки с кодом инициализации и  процеду-
        рой выхода:

             library Test;

             {$S-}

             uses WinTypes, WinProcs;

             var
               SaveExit: Pointer;

             procedure LibExit; far;
             begin
                if ExitCode = wep_System_Exit then
                    begin
                      .
                      .

         B.Pascal 7 & Objects/LR     - 190 -

                      .
                    { выполняется завершение работы системы }
                      .
                      .
                      .
                   end else
                   begin
                     .
                     .
                     .
                   { разгружается DLL }
                     .
                     .
                     .
                   end;
                   ExitProcess : SaveExit;
             end;

             begin
               .
               .
               .
             { выполнить инициализацию DLL }
               .
               .
               .
             SaveExit := ExitProc;   { сохранить старый указатель
                                       процедуры выхода }
             ExitProc := @LibExit;   { установка процедуры выхода
                                       LibExit }
             end.

             В защищенном режиме DOS передаваемое  процедуре  выхода  DLL
        значение ExitCode всегда равно 0 и соответствует wep_FREE_DLL.

             После разгрузки DLL экспортируемая функция вызывает процеду-
        ру WEP (процедура выхода Windows)  DLL,  если  она  присутствует.
        Библиотека Borland Pascal автоматически экспортирует функцию WEP,
        которая продолжает вызывать записанный в переменной ExitProc  ад-
        рес,  пока ExitProc не примет значения nil.  Поскольку этот меха-
        низм процедур выхода соответствует работе с процедурами выхода  в
        программах Borland Pascal, и в программах, и в библиотеках вы мо-
        жете использовать одну и ту же логику процедур выхода.

             Поскольку операционная система при завершении DLL переключа-
        ет внутренний стек, процедуры выхода в DLL должны компилироваться
        с запрещением проверки стека (в состоянии {$S-}). Кроме того, ес-
        ли в  процедуре  выхода  DLL  происходит ошибка этапа выполнения,
        операционная система аварийно завершает работу,  поэтому  вы  для
        предотвращения  ошибок этапа выполнения вы должны включить в свой
        код достаточное количество проверок.



         B.Pascal 7 & Objects/LR     - 191 -

                     Замечания по программированию библиотек
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                           Глобальные переменные в DLL
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                       Глобальные переменные и файлы в DLL
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Как правило,  DLL не является "владельцем" каких-либо откры-
        ваемых ей  файлов  или получаемых ей от системы глобальных блоков
        памяти. Такими объектами владеет (прямо или косвенно) сама  прик-
        ладная программа, вызывающая DLL.

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

             В Windows глобальные блоки памяти,  распределенные с атрибу-
        том gmem_DDEShare (определенные в модуле  WinTypes),  принадлежат
        DLL, а  не  вызывающим прикладным программам.  Такие блоки памяти
        остаются распределенными, пока они явно не освобождаются DLL, или
        пока DLL не выгружается.

             Администратор памяти  защищенного режима DOS не поддерживает
        совместно используемых   блоков   памяти   и   игнорирует    флаг
        gmem_DDEShare. В  защищенном  режиме DOS распределяемые DLL блоки
        памяти всегда принадлежат вызывающей библиотеку DLL программе.

                               DLL и модуль System
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В продолжении  существования DLL переменная HInstance содер-
        жит описатель экземпляра DLL.  Переменные FPrevInst и  CmdShow  в
        DLL всегда равны 0 (как и переменная PrefixSeg), поскольку DLL не
        имеет префикса программного сегмента (PSP). В прикладной програм-

         B.Pascal 7 & Objects/LR     - 192 -

        ме PrefixSeg никогда не равна 0,  поэтому проверка PrefixSeg <> 0
        возвращает True,  если текущем модулем является прикладная  прог-
        рамма, и False, если текущим модулем является DLL.

             Чтобы обеспечить правильную работу администратора динамичес-
        ки распределяемой области, содержащегося в модуле System, код за-
        пуска библиотеки устанавливает переменную HeapAllocFlags в значе-
        ние gmem_Moveable + gmem_DDEShare. В Windows это приводит к тому,
        что все  блоки  памяти,  распределенные  через  процедуры  New  и
        GetMem, будут принадлежать DLL,  а не  вызывающей  ее  прикладной
        программе.

                   Примечание: Подробности  об  администраторе  памяти вы
              можете найти в Главе 21.

                          Ошибки этапа выполнения в DLL
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

             Если в DLL под Windows происходит ошибка  этапа  выполнения,
        то надежнее всего полностью выйти в Windows. Если вы просто пыта-
        етесь модифицировать и перестроить сбойный код DLL, а затем снова
        выполнить прикладную программу,  Windows не будет загружать новую
        версию,  если ошибочная версия уже находится в память. Выйдите из
        Windows  и перезапустите ее,  а Borland Pascal обеспечит загрузку
        корректной версии DLL.

                              DLL и сегменты стека
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В отличие  от прикладной программы DLL не имеет своего собс-
        твенного сегмента стека. Вместо этого она использует сегмент сте-
        ка вызывающей DLL прикладной программы. Это может создать пробле-
        мы в подпрограмме DLL,  которые полагают,  что регистры DS  и  SS
        ссылаются на один и тот же сегмент,  как это имеет место в модуле
        прикладной программы Windows.

             Borland Pascal никогда не  генерирует  код,  подразумевающий
        равенство DS  =  SS,  и  в библиотеке исполняющей системы Borland
        Pascal таких предположений не делается.  Если вы  пишете  код  на
        языке ассемблера,  то не полагайтесь на то,  что регистры DS и SS

         B.Pascal 7 & Objects/LR     - 193 -

        содержат одно и то же значение.

                       Создание совместно используемых DLL
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Borland Pascal поддерживает DLL, которые могут совместно ис-
        пользоваться в защищенном режиме DOS и в Windows.  Совместно  ис-
        пользуемые DLL совместимы на уровне двоичного кода. Это означает,
        что один и тот же файл .DLL  может  использоваться  в  прикладной
        программе защищенного  режима  DOS  или  в  прикладной  программе
        Windows.

             При компиляции совместно используемой DLL в качестве целевой
        платформы нужно выбирать Windows:

             * В  IDE выберите команду CompileіTarget и в диалоговом окне
               Target (Целевая платформа) укажите Windows.

             * При использовании компилятора,  работающего в  режиме  ко-
               мандной строки,  для  выбора  в качестве целевой платформы
               Windows используйте переключатель /CW.

             DLL, скомпилированная  для  защищенного  режима   DOS,   под
        Windows использоваться  не может,  так как библиотека исполняющей
        системы защищенного режима DOS использует отдельные  функциональ-
        ные вызовы DOS и DPMI, которые следует избегать в Windows.

             Совместно используемая  DLL может взаимодействовать с опера-
        ционной системой (DOS защищенного режиме или Windows) только  че-
        рез модуль  WinAPI.  Этот модуль представляет функции,  общие для
        защищенного режима DOS  и  Windows.  Другие  интерфейсные  модули
        Windows, такие  как WinTypes и WinProcs,  описывают большое число
        подпрограмм API, не поддерживаемых в защищенном режиме DOS.

                   Примечание: О модуле WinAPI рассказывается в Главе  17
              "Программирование в защищенном режиме DOS".

             Важно отметить,  что  хотя  совместно используемая DLL может
        выполняться одновременно и под Windows, в окне защищенного режима
        Windows DOS,  связь  через  DLL между двумя операционными средами
        невозможна. Реально в системе будет присутствовать две копии DLL,
        каждая из  которых защищена от другой и использует полностью изо-
        лированную область памяти.

         B.Pascal 7 & Objects/LR     - 194 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                Часть II. Глава 12. Библиотеки исполняющей системы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Borland Pascal включает в себя библиотеки исполняющей систе-
        мы для  защищенного  режима DOS,  реального режима DOS и Windows.
        Наиболее часто используемые библиотеки исполняющей системы  нахо-
        дятся в файлах TURBO.TPL (реальный режим DOS),  TPP.TPL (защищен-
        ный режим DOS) и TPW.TPL (Windows). Дополнительные модули постав-
        ляются в отдельных файлах .TPU, .TPP и .TPW.

             * Для реального режима DOS библиотека TURBO.TPL содержит мо-
               дули System,  Overlay,  Crt,  Dos и Printer. Кроме того, в
               отдельных файлах .TPU поставляются модули Graph,  Strings,
               WinDos, Turbo3 и Graph3.

             * Для защищенного режима DOS библиотека TPP.TPL содержит мо-
               дули System,  Crt, Dos, Printer, Strings, WinDos и WinAPI.
               Кроме того,  в виде отдельного файла .TPP поставляется мо-
               дуль Graph.

             * Для  Windows  библиотека  TPW.TPL  содержит модули System,
               Strings, WinTypes, WinProcs, Win31, WinAPI, WinDos, WinCrt
               и WinPrn. В виде исходного кода поставляются некоторые до-
               полнительные модули Windows.

             Кроме библиотек исполняющей системы, Borland Pascal включает
        в себя  прикладную среду Turbo Vision для реального и защищенного
        режима DOS и прикладную среду ObjectWindows для Windows. Эти биб-
        лиотеки описаны   в  "Руководстве  по  программированию  с  Turbo
        Vision" и в "Руководстве  по  программированию  с  использованием
        ObjectWindows".

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

                              Модули Borland Pascal
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Borland Pascal  обеспечивает  вам  доступ  к  большому числу
        встроенных констант,  типов данных,  переменных, процедур и функ-
        ций.  Некоторые из них специфичны для Borland Pascal, другие спе-
        цифичны для программирования прикладных  задач  для  Windows  или
        Dos. Их количество велико, однако, в своей программе вы редко ис-
        пользуете их все сразу.  Поэтому они разделены на связанные груп-
        пы,  называемые модулями. В этом случае можно использовать только
        те модули, которые необходимы в программе.

             Программный модуль (unit) представляет собой набор констант,
        типов данных,  переменных, процедур и функций. Каждый модуль ана-
        логичен отдельной программе на Паскале:  он может иметь  основное
        тело,  которое  вызывается  перед запуском вашей программы и осу-
        ществляет необходимую инициализацию. Короче говоря, модуль предс-
        тавляет собой библиотеку описаний, которую можно вставить в прог-

         B.Pascal 7 & Objects/LR     - 195 -

        рамму и которая позволит разбить программу на части,  компилируе-
        мые отдельно.

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

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


                                  Модуль System
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Модуль System содержит все стандартные и встроенные процеду-
        ры  и функции Borland Pascal.  Любая подпрограмма Borland Pascal,
        не являющаяся частью стандартного Паскаля и не находящаяся  ни  в
        каком другом модуле,  содержится в модуле System. Этот модуль ав-
        томатически используется во всех программах,  и его не  требуется
        указывать в операторе uses.


                               Модуль Dos и WinDos
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модули Dos и WinDos  реализуют  многочисленные  процедуры  и
        функции Паскаля, которые эквивалентны наиболее часто используемым
        вызовам DOS,  как например,  GetТime, SetТime, DiskSize и так да-
        лее. Кроме  того,  WinDos определяет две программы низкого уровня
        МsDos и Intr, которые позволяют активизировать любой вызов MS-DOS
        или  системное  прерывание.  Тип Registers представляет собой тип
        данных для параметра в МsDos и Intr. Кроме того, определяются не-
        которые другие константы и типы данных.  Ни одна из этих подпрог-
        рамм не определена в стандартном Паскале,  поэтому они помещены в
        свои собственные модули. Подробнее модули WinDos и Dos описывают-
        ся в Главе 16 "Интерфейс с DOS".


                                   Модуль Crt
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль Crt  реализует  ряд мощных программ,  предоставляющих

         B.Pascal 7 & Objects/LR     - 196 -

        вам полную возможность управления средствами компьютера РС, таки-
        ми,  как управление режимом экрана,  расширенные коды клавиатуры,
        цвета,  окна, и звуковые сигналы. Модуль Crt может использоваться
        только  в программах,  работающих на персональных компьютерах IBM
        РС, РС AT, РS/2 фирмы IBM и полностью совместимых с ними.

             Одним из основных преимуществ использования модуля Crt явля-
        ется большая скорость и гибкость при выполнении операций работы с
        экраном. Программы, не работающие с модулем Crt, выводят на экран
        информацию с помощью средств операционной системы DOS, что связа-
        но с дополнительными непроизводительными затратами. При использо-
        вании  модуля Crt выводимая информация посылается непосредственно
        в базовую систему ввода-вывода (ВIОS), или, для еще более быстрых
        операций, непосредственно в видеопамять.

             О модуле Crt рассказывает в Главе 14 "Ввод и вывод".


                                  Модуль WinCrt
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль WinCrt - это дpайвеp устpойства текстовых файлов, ко-
        тоpый  пеpеопpеделяет  вывод в пpокpучиваемое окно.  Хотя большая
        часть ваших пpогpамм для Windows,  как пpавило,  будет  создавать
        свои  собственные  окна,  модуль  WinCrt  можно  использовать для
        быстрых и простых программ,  базирующихся на текстах,  когда  вам
        нужно быстро  получить  результаты.  Модуль  WinCrt описывается в
        главе 14 "Ввод и вывод".


                                 Модуль Printer
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль Printer позволяет вам посылать стандартный вывод Пас-
        каля на принтер,  используя процедуры Write и WriteLn.  Подробнее
        он описывается в главе 14 "Ввод и вывод".


                                  Модуль WinPrn
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль WinPrn позволяет вам посылать своей  вашей  программы
        Windows  на принтер по вашему выбору.  Подробнее он описывается в
        главе 14 "Ввод и вывод".


                                 Модуль Overlay
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль Overlay  позволяет  вам уменьшить требования к памяти
        программы DOS реального  режима.  Фактически,  вы  можете  писать
        программы, превышающие общий объем доступной памяти,  поскольку в
        каждый момент в памяти будет находиться только часть вашей  прог-

         B.Pascal 7 & Objects/LR     - 197 -

        раммы.  Подробно  данный  модуль описан в Главе 20 "Использование
        оверлеев".


                                 Модуль Strings
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль Strings обеспечивает обработку новых строк,  заканчи-
        вающихся  пустым  символом.  Строки,  стандартные  для   Паскаля,
        обрабатываются модулем System.  Подробнее модуль Strings описыва-
        ется в Главе 18 "Использование строк с завершающим нулем".


                                  Модуль Graph
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль Graph  обеспечивает  ряд быстрых и мощных графических
        подпрограмм. Он реализует независимый  от  устройств  графический
        драйвер Borland,  поддерживающий графику CGA, EGA, VGA, Hercules,
        AT&T 400,  MCGA,  3270PC  и  8514.  Модуль  Graph  не  встроен  в
        TURBO.TPL, он находится на том же диске, что и файлы .BGI (графи-
        ческий интерфейс Borland) и .CHR (шрифты).

             Подробнее о модуле Graph рассказывается в Главе 19  "Исполь-
        зование графического интерфейса Borland".


                             Модули Turbo3 и Graph3
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модули Turbo3 и Graph3  предусмотрены  только  для  обратной
        совместимости. Turbo3  содержит две переменные и несколько проце-
        дур, которые больше не поддерживаются Borland Pascal.  Graph3 со-
        держит полный  набор  графических подпрограмм версии 3.0 - основ-
        ных,  продвинутых,  и использующих графику в относительных коман-
        дах. Информацию   об   этих   файлах  вы  можете  найти  в  файле
        TURBO3.INT.


                           Модули WinTypes и WinProcs
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль WinTypes  содержит все константы,  структуры данных и
        стили,  используемые в прикладном программном интерфейсе Windows.
        Модуль WinTypes подробно описывается в справочной системе Borland
        Pascal.

             Модуль WinProcs содержит все функции и процедуры, составляю-
        щие  прикладной  программный  интерфейс Windows.  Модуль WinProcs
        также подробно описывается в справочной системе.

             Совместно эти модули образуют прикладной программный  интер-
        фейс Windows (API).

         B.Pascal 7 & Objects/LR     - 198 -


                                  Модуль Win31
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль Win31 обеспечивает интерфейс с дополнительными  подп-
        рограммами API,  которые  можно  найти в Windows 3.1.  Прикладные
        программы, использующие Win31, не работают под Windows 3.0.


                                  Модуль WinAPI
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль WinAPI   определяет   подмножество   подпрограмм  API
        Windows, поддерживаемых и в Windows,  и в защищенном режиме  DOS.
        Подробнее об  этом модуле рассказывается в Главе 17 "Программиро-
        вание в защищенном режиме DOS".


                       Модули, поддерживающие Windows 3.1
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Borland Pascal  поддерживает API Windows 3.1 в следующих мо-
        дулях:

             ColorDlg              LZExpand              ShellAPI
             CommDlg               MMSystem              Stress
             Cpl                   OLE                   ToolHelp
             DDEML                 PenWin                Ver
             Dlgs                  Print                 WinMem32




         B.Pascal 7 & Objects/LR     - 199 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                    Глава 13. Стандартные процедуры и функции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В данной главе кратко описываются  стандартные  (встроенные)
        процедуры и  функции  Borland  Pascal и предописанные переменные,
        определенные в модуле System.  Более подробную информацию о конк-
        ретной процедуре,  функции или предописанной переменной вы можете
        найти в Главе 1 ("Справочник по библиотеке") в "Руководстве прог-
        раммиста".

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

                   Примечание: О  других  процедурах и функциях вы можете
              прочесть в Главе 14 "Ввод и вывод".

             В данной главе освещаются следующие темы:

             - Процедуры управления программой.

             - Функции преобразования.

             - Арифметические функции.

             - Порядковые процедуры и функции.

             - Строковые процедуры и функции.

             - Процедуры и функции динамического распределения памяти.

             - Прочие процедуры и функции.

             - Предописанные переменные модуля System.




         B.Pascal 7 & Objects/LR     - 200 -

                     Процедуры управления работой программы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Процедуры управления работой программы - это процедуры,  уп-
        равляющие логикой выполнения программы.

        ЪДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і  Процедура        і     Описание                              і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Break           і Завершает оператор for, while или repeat. і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Continue        і Продолжает итерацию оператора for,  while,і
        і                   і или repeat.                               і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Eхit            і Позволяет немедленно выйти из текущего мо-і
        і                   і дуля.                                     і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Наlt            і Останавливает выполнение программы и возв-і
        і                   і ращает управление операционной системе.   і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   RunError        і Останавливает выполнение программы и гене-і
        і                   і рирует ошибку этапа выполнения.           і
        АДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                             Функции преобразования
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Ниже перечислены функции преобразования.

        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Функция       і       Описание                             і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Chr            і Возвращает символ, заданный целым числом.  і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   High           і Возвращает старшее значение в диапазоне ар-і
        і                  і гумента.                                   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Low            і Возвращает младшее значение в диапазоне ар-і
        і                  і гумента.                                   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Оrd            і Возвращает порядковое число по значению пе-і
        і                  і речислимого типа.                          і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Rоund          і Округляет значение  вещественного  типа  доі
        і                  і значения, имеющего длинный целый тип.      і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Тrunс          і Усекает значение вещественного типа до зна-і
        і                  і чения, имеющего длинный целый тип.         і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 201 -

                             Арифметические функции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Эти функции полезно использовать для выполнения арифметичес-
        ких операций.

                    Примечание: Значения, возвращаемые процедурами опера-
               ций с  плавающей  запятой модуля System,  при компиляции в
               режиме числовой обработки (директива {$N+}),  имеют не ве-
               щественный тип (real), а расширенный (extended).

        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Функция       і       Описание                             і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Abs            і Возвращает абсолютное значение аргумента.  і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Аrctan         і Возвращает арктангенс аргумента.           і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Cоs            і Возвращает косинус аргумента.              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Eхp            і Возвращает экспоненту аргумента.           і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Frас           і Возвращает дробную часть аргумента.        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Int            і Возвращает целую часть аргумента.          і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Ln             і Возвращает натуральный логарифм аргумента. і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Pi             і Возвращает значение числа Pi               і
        і                  і (3.141592653897932385).                    і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Sin            і Возвращает синус аргумента.                і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Sqr            і Возвращает аргумент в квадрате.            і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Sqrt           і Возвращает квадратный корень аргумента.    і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 202 -

                         Порядковые процедуры и функции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і Процедура/функцияі            Описание                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і     Dес          і Уменьшает значение переменной.             і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і     Inс          і Увеличивает значение переменной.           і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і     Оdd          і Проверяет, является  ли  аргумент  нечетнымі
        і                  і числом.                                    і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і     Рred         і Возвращает предшествующее значение аргумен-і
        і                  і та.                                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і     Suсс         і Возвращает его последующее значение.       і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                          Строковые процедуры и функции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Следующие процедуры  и  функции  используются  для работы со
        строками Паскаля.

        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і   Процедура      і      Описание                              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Cоncat        і Выполняет конкатенацию   последовательностиі
        і                  і строк.                                     і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Cору          і Возвращает подстроку строки.               і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Delete        і Удаляет из строки подстроку.               і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Insert        і Добавляет в строку подстроку.              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Length        і Возвращает динамическую длину строки.      і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Pоs           і Производит поиск подстроки в строке.       і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Str           і Преобразует численное  значение в его стро-і
        і                  і ковое представление.                       і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Val           і Преобразует строковое значение в  его  чис-і
        і                  і ленное представление.                      і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 203 -

             Процедуры и функции динамического распределения памяти
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Эти процедуры  и функции используются для управления динами-
        чески распределяемой областью - областью памяти, которая занимает
        всю  свободную  память  или  ее часть,  остающуюся при выполнении
        программы.  Полное описание методов,  используемых для управления
        динамически  распределяемой  областью памяти приводится в разделе
        "Программа динамического распределения памяти" в Главе 21  ("Воп-
        росы управления памятью").

                  Процедуры динамического распределения памяти
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і Процедура/функцияі            Описание                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Dispose        і Уничтожает динамическую переменную.        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FrееМем        і Уничтожает динамическую  переменную данногоі
        і                  і размера.                                   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetМем         і Создает новую динамическую  переменную  за-і
        і                  і данного  размера и устанавливает на нее пе-і
        і                  і ременную-указатель.                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   МахАvail       і Возвращает размер  наибольшего непрерывногоі
        і                  і свободного модуля в динамически распределя-і
        і                  і емой области памяти, соответствующий разме-і
        і                  і ру наибольшей динамической переменной,  ко-і
        і                  і торая может быть выделена при  обращении  ві
        і                  і МахAvail.                                  і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   МемАvail       і Возвращает количество  имеющихся  в динами-і
        і                  і чески  распределяемой   области   свободныхі
        і                  і байт.                                      і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   New            і Создает новую динамическую переменную и ус-і
        і                  і танавливает на нее переменную-указатель.   і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 204 -

                   Функции для работы с указателями и адресами
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Ниже перечислены  функции для работы с указателями и адреса-
        ми.

        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Функции       і              Описание                      і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Аddr          і Возвращает адрес заданного объекта.        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    CSeg          і Возвращает текущее значение регистра CS.   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    DSeg          і Возвращает текущее значение регистра DS.   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Оfs           і Возвращает смещение для заданного объекта. і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Ptr           і Преобразует адрес базового сегмента и  сме-і
        і                  і щение в значение типа указатель.           і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Seg           і Возвращает сегмент для заданного объекта.  і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    SPtr          і Возвращает текущее значение регистра SР.   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    SSeg          і Возвращает текущее значение регистра SS.   і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 205 -

                           Прочие процедуры и функции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і Процедура/функцияі            Описание                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Exclude        і Исключает элемент из множества.            і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FillChar       і Заполняет заданное число следующих  друг заі
        і                  і другом бит указанным значением.            і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Hi             і Возвращает старший байт аргумента.         і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Include        і Включает элемент в множество.              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Lo             і Возвращает младший байт аргумента.         і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Моvе           і Копирует заданное  число непрерывных байт ві
        і                  і указанных границах из одного места  в  дру-і
        і                  і гое, границы которого также указываются.   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   ParamCount     і Возвращает   число  параметров,  переданныхі
        і                  і программе в командной строке.              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   ParamStr       і Возвращает параметр, заданный  в  команднойі
        і                  і строке.                                    і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Random         і Возвращает случайное число.                і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Rаndомizе      і Инициализирует встроенный генератор случай-і
        і                  і ных чисел случайным значением.             і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SizeOf         і Возвращает число байт, занимаемых  аргумен-і
        і                  і том.                                       і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Swap           і Меняет местами  старший и младший байты ар-і
        і                  і гумента.                                   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   TypeOf         і Указывает на  таблицу  виртуальных  методові
        і                  і объекта.                                   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   UpCase         і Преобразует символ в верхний регистр.      і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 206 -

                            Предописанные переменные
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Кроме процедур и функций в модуле  System  предусмотрен  ряд
        предописанных переменных.  Их  перечень зависит от библиотеки ис-
        полняющей системы, к которой относится модуль System.

             Следующие переменные описываются в модуле System  библиотеки
        TURBO.TPL -  библиотеке исполняющей системы для приложений реаль-
        ного режима DOS.

        ЪДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і Переменная    і   Тип          і     Описание                 і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і ErrorAddr     і Pointer        і адрес ошибки этапа  выполне- і
        і               і                і ния                          і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і ExitProc      і Pointer        і процедура выхода             і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і ExitCode      і Integer        і код выхода                   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і FileMode      і Byte           і режим открытия файла         і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і FreeList      і Pointer        і список свободных блоков  ди- і
        і               і                і намически распределяемой об- і
        і               і                і ласти памяти                 і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і FreeZero      і Pointer        і должен быть равен 0          і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HeapOrg       і Pointer        і начало динамически распреде- і
        і               і                і ляемой области               і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HeapPtr       і Pointer        і указатель  динамически  рас- і
        і               і                і пределяемой области          і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HeapError     і Pointer        і функция  ошибки  динамически і
        і               і                і распределяемой области памя- і
        і               і                і ти                           і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і Input         і Text           і стандартный файл ввода       і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і InOutRes      і Integer        і буфер   результата  операции і
        і               і                і ввода-вывода                 і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і Output        і Text           і стандартный файл вывода      і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і OvrCodeList   і Word           і список сегментов оверлейного і
        і               і                і кода                         і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і OvrDebugPtr   і Pointer        і используется   при   отладке і
        і               і                і оверлеев                     і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і OvrDosHandle  і Word           і описатель оверлея DOS        і

         B.Pascal 7 & Objects/LR     - 207 -

        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і OvrEmsHandle  і Word           і описатель оверлея EMS        і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і OvrHeapEnd    і Word           і конец оверлейного буфера     і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і OvrHeapOrg    і Word           і начало оверлейного буфера    і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і OvrHeapPtr    і Word           і указатель оверлейного буфера і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і OvrHeapSize   і Word           і начальный размер оверлейного і
        і               і                і буфера                       і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і OvrLoadList   і Word           і список загруженных оверлеев  і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і PrefixSeg     і Word           і префикс программного сегмен- і
        і               і                і та                           і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і RandSeed      і Longint        і случайное  число  (генериру- і
        і               і                і ется датчиком  случайных чи- і
        і               і                і сел)                         і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt00     і Pointer        і сохраненное прерывание $00   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt02     і Pointer        і сохраненное прерывание $02   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt1B     і Pointer        і сохраненное прерывание $1B   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt23     і Pointer        і сохраненное прерывание $23   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt24     і Pointer        і сохраненное прерывание $24   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt34     і Pointer        і сохраненное прерывание $34   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt35     і Pointer        і сохраненное прерывание $35   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt36     і Pointer        і сохраненное прерывание $36   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt37     і Pointer        і сохраненное прерывание $37   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt38     і Pointer        і сохраненное прерывание $38   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt39     і Pointer        і сохраненное прерывание $39   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt3A     і Pointer        і сохраненное прерывание $3A   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt3B     і Pointer        і сохраненное прерывание $3B   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt3C     і Pointer        і сохраненное прерывание $3C   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt3D     і Pointer        і сохраненное прерывание $3D   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt3E     і Pointer        і сохраненное прерывание $3E   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ

         B.Pascal 7 & Objects/LR     - 208 -

        і SaveInt3F     і Pointer        і сохраненное прерывание $3F   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt75     і Pointer        і сохраненное прерывание $75   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і Seg0040       і Word           і селектор сегмента $0040      і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SegA000       і Word           і селектор сегмента $A000      і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SegB000       і Word           і селектор сегмента $B000      і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SegC000       і Word           і селектор сегмента $C000      і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SelectorInc   і Word           і шаг увеличения селектора     і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і StackLimit    і Word           і указатель на нижнюю границу  і
        і               і                і стека                        і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і Test8086      і Byte           і результат  проверки  процес- і
        і               і                і сора 8086                    і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і Test8087      і Byte           і результат проверки сопроцес- і
        і               і                і сора 8087                    і
        АДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             PrefixSeg представляет собой переменную длиной в слово,  со-
        держащую адрес префикса программного сегмента (PSP), создаваемого
        при выполнении программы операционной системой DOS. Полное описа-
        ние PSP приведено в руководстве по операционной системе DOS.

             Переменная StackLimit содержит смещение начала стека относи-
        тельно сегмента стека, что соответствует минимальному допустимому
        значению регистра SP, после которого уже возникает ситуация пере-
        полнения стека. По умолчанию значение этой переменной равно 0, но
        если программа компилируется с директивами {$N+,$E+}, то эмулятор
        сопроцессора 8087 при отсутствии в системе сопроцессора  8087 для
        резервирования места в младших адресах сегмента стека будет уста-
        навливать ее в значение 224.

             Переменная InOutRes  используется  встроенными   программами
        ввода-вывода для сохранения значения, возвращаемого при следующем
        обращении к функции IOResult.

             В RandSeed сохраняется начальное  значение  для  встроенного
        генератора случайных чисел.  Если присваивать этой переменной оп-
        ределенное значение,  то функция Random будет генерировать задан-
        ную  последовательность случайных чисел.

         B.Pascal 7 & Objects/LR     - 209 -


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

             В переменной  Test8087 сохраняется результат работы алгорит-
        мов автоматического распознавания сопроцессора 8087,  которые на-
        чинают работать при запуске программы,  скомпилированной с дирек-
        тивой  {$N+}.

             Input и Оutput - это стандартные файлы ввода-вывода, необхо-
        димые в каждой реализации Паскаля.  По умолчанию они  связываются
        со стандартными входными и выходными файлами в Dos.


         B.Pascal 7 & Objects/LR     - 210 -


             Следующие переменные описываются в модуле System  библиотеки
        TPW.TPL - библиотеке исполняющей системы для приложений Windows.

        ЪДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і Переменная    і   Тип          і     Описание                 і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і CmdLine       і PChar          і указатель командной строки   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і CmdShow       і Integer        і параметр CmdShow для Create- і
        і               і                і Window                       і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і ErrorAddr     і Pointer        і адрес ошибки этапа  выполне- і
        і               і                і ния                          і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і ExitProc      і Pointer        і процедура выхода             і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і ExitCode      і Integer        і код выхода                   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і FileMode      і Byte           і режим открытия файла         і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і Input         і Text           і стандартный файл ввода       і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HeapAllocFlag і Word           і флаги   распределения  блока і
        і               і                і динамически   распределяемой і
        і               і                і области памяти               і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HeapBlock     і Word           і размер   блока   динамически і
        і               і                і распределяемой области памя- і
        і               і                і ти                           і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HearError     і Pointer        і функция  ошибки  динамически і
        і               і                і распределяемой области памя- і
        і               і                і ти                           і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HeapLimit     і Word           і размер наименьшего блока ди- і
        і               і                і намически распределяемой об- і
        і               і                і ласти памяти                 і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HeapList      і Word           і список сегментов динамически і
        і               і                і распределяемой области памя- і
        і               і                і ти                           і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HInstance     і Word           і описатель данного экземпляра і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HPrevInst     і Word           і описатель предыдущего экзем- і
        і               і                і пляра                        і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і InOutRes      і Integer        і буфер   результата  операции і
        і               і                і ввода-вывода                 і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і Output        і Text           і стандартный файл вывода      і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ

         B.Pascal 7 & Objects/LR     - 211 -

        і PrefixSeg     і Word           і префикс программного сегмен- і
        і               і                і та                           і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і RandSeed      і Longint        і случайное  число  (генериру- і
        і               і                і ется датчиком  случайных чи- і
        і               і                і сел)                         і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SelectorInc   і Word           і шаг увеличения селектора     і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і StackLimit    і Word           і указатель на нижнюю границу  і
        і               і                і стека                        і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і Test8086      і Byte           і результат  проверки  процес- і
        і               і                і сора 8086                    і
        АДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             HInstance содержит описатель экземпляра прикладной программы
        или библиотеки,  как это  предусматривается  операционной  средой
        Windows. В  программе  HPrevInst  содержит  предыдущий  экземпляр
        прикладной программы,  или 0,  если предыдущего экземпляра нет. В
        библиотеке HPrevInst всегда равно 0.

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

             В программе CmdShow содержит  значение  параметра,  передачу
        которого в ShowWindow ожидает Windows, когда прикладная программа
        создает основное окно.  В библиотеке эта переменная всегда  равна
        0.

             Подсистемой управления  динамически  распределяемой областью
        памяти для реализации программ динамического распределения памяти
        Borland Pascal   используются   переменные  HeapList,  HeapLimit,
        HeapBlock и HeapError.

             Для реализации  процедур  выхода   используются   переменные
        ExitProc, ErrorCode и ErrorAdr.

             Переменная PrefixSeg  представляет собой переменную длиной в
        слово,  содержащую адрес префикса  программного  сегмента  (PSP),
        создаваемого  при выполнении программы операционной системой DOS.
        Полное описание PSP приведено в руководстве по операционной  сис-
        теме DOS.

             Переменная InOutRes   используется  встроенными  программами
        ввода-вывода для сохранения значения, возвращаемого при следующем
        обращении к функции IOResult.

             Переменная FileMode позволяет изменять режим доступа к  отк-
        рытым типизованным и нетипизированным файлам.  Более подробно это
        описано в Главе 14 "Ввод и вывод".

         B.Pascal 7 & Objects/LR     - 212 -


             Следующие переменные описываются в модуле System  библиотеки
        TPP.TPL - библиотеке исполняющей системы для приложений  защищен-
        ного режима DOS.

        ЪДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і Переменная    і   Тип          і     Описание                 і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і ErrorAddr     і Pointer        і адрес ошибки этапа  выполне- і
        і               і                і ния                          і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і ExitProc      і Pointer        і процедура выхода             і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і ExitCode      і Integer        і код выхода                   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і FileMode      і Byte           і режим открытия файла         і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HeapAllocFlagsі Word           і флаги   распределения  блока і
        і               і                і динамически   распределяемой і
        і               і                і области памяти               і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HeapBlock     і Word           і размер   блока   динамически і
        і               і                і распределяемой области памя- і
        і               і                і ти                           і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HearError     і Pointer        і функция  ошибки  динамически і
        і               і                і распределяемой области памя- і
        і               і                і ти                           і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HeapLimit     і Word           і размер наименьшего блока ди- і
        і               і                і намически распределяемой об- і
        і               і                і ласти памяти                 і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HeapList      і Word           і список сегментов динамически і
        і               і                і распределяемой области памя- і
        і               і                і ти                           і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HInstance     і Word           і описатель данного экземпляра і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HPrevInst     і Word           і описатель предыдущего экзем- і
        і               і                і пляра                        і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і InOutRes      і Integer        і буфер   результата  операции і
        і               і                і ввода-вывода                 і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і Output        і Text           і стандартный файл вывода      і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і PrefixSeg     і Word           і префикс программного сегмен- і
        і               і                і та                           і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і RandSeed      і Longint        і случайное  число  (генериру- і
        і               і                і ется датчиком  случайных чи- і
        і               і                і сел)                         і

         B.Pascal 7 & Objects/LR     - 213 -

        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і RealModeRegs  і array[0..49] ofі регистры реального режима    і
        і               і  byte          і                              і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt00     і Pointer        і сохраненная   исключительная і
        і               і                і ситуация $00                 і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt02     і Pointer        і сохраненное прерывание $02   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt0C     і Pointer        і сохраненное   исключительная і
        і               і                і ситуация $0С                 і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt0D     і Pointer        і сохраненное прерывание $0D   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt1B     і Pointer        і сохраненное прерывание $1B   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt21     і Pointer        і сохраненное прерывание $21   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt23     і Pointer        і сохраненное       прерывание і
        і               і                і реального режима $23         і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt24     і Pointer        і сохраненное       прерывание і
        і               і                і реального режима $24         і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt34     і Pointer        і сохраненное прерывание $34   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt35     і Pointer        і сохраненное прерывание $35   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt36     і Pointer        і сохраненное прерывание $36   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt37     і Pointer        і сохраненное прерывание $37   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt3B     і Pointer        і сохраненное прерывание $38   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt39     і Pointer        і сохраненное прерывание $39   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt3A     і Pointer        і сохраненное прерывание $3A   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt3B     і Pointer        і сохраненное прерывание $3B   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt3C     і Pointer        і сохраненное прерывание $3C   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt3D     і Pointer        і сохраненное прерывание $3D   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt3E     і Pointer        і сохраненное прерывание $3E   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt3F     і Pointer        і сохраненное прерывание $3F   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SaveInt75     і Pointer        і сохраненное прерывание $75   і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і Seg0040       і Word           і селектор сегмента $0040      і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SegA000       і Word           і селектор сегмента $A000      і

         B.Pascal 7 & Objects/LR     - 214 -

        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SegB000       і Word           і селектор сегмента $B000      і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SegB800       і Word           і селектор сегмента $B800      і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і Test8086      і Byte           і результат  проверки  процес- і
        і               і                і сора 8086                    і
        ГДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і Test8087      і Byte           і результат проверки сопроцес- і
        і               і                і сора 8087                    і
        АДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Более подробную информацию об этих переменных вы можете най-
        ти в Главе 1 ("Справочник по библиотеке") в "Справочном руководс-
        тве программиста.



         B.Pascal 7 & Objects/LR     - 215 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                             Глава 14. Ввод и вывод
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В данной Главе кратко описываются стандартные (или  встроен-
        ные) функции и процедуры ввода-вывода Borland Pascal.  Эти проце-
        дуры и функции можно найти в модуле System.

                        Процедуры и функции ввода-вывода
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і   Функция        і      Описание                              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Append         і Открывает существующий  файл  для  добавле-і
        і                  і ния.                                       і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Assign         і Присваивает имя внешнего файла файловой пе-і
        і                  і ременной.                                  і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   BlockRead      і Считывает из  нетипизированного файла  однуі
        і                  і или более записей.                         і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   BlockWrite     і Записывает  в  нетипизированный  файл  однуі
        і                  і или более записей.                         і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   ChDir          і Выполняет смену текущего каталога.         і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Close          і Закрывает открытый файл.                   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Erase          і Стирает внешний файл.                      і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Eоf            і Возвращает для файла  состояние end-of-fileі
        і                  і (конец файла).                             і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FilePos        і Возвращает текущую  позицию  в  файле.  Дляі
        і                  і текстовых файлов не используется.          і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FileSize       і Возвращает текущий размер файла.  Для текс-і
        і                  і товых файлов не используется.              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Flush          і Сбрасывает буфер текстового файла вывода.  і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Getdir         і Возвращает текущий каталог на заданном дис-і
        і                  і ке.                                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   IОResult       і Возвращает целое значение,  являющееся сос-і
        і                  і тоянием последней выполненной операции вво-і
        і                  і да-вывода.                                 і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   MkDir          і Создает подкаталог.                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Read           і Считывает одно или более значений из  файлаі
        і                  і в одну или более переменных.               і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Readln         і Делает то же, что и Read, и выполняет  про-і

         B.Pascal 7 & Objects/LR     - 216 -

        і                  і пуск до начала следующей строки  текстовогоі
        і                  і файла.                                     і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Rеnаме         і Переименовывает внешний файл.              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Rеset          і Открывает существующий файл.               і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Rewritе        і Создает и открывает новый файл.            і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   RмDir          і Удаляет пустой подкаталог.                 і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Seek           і Перемещает текущую позицию в файле  на  за-і
        і                  і данный элемент. Для текстовых файлов не ис-і
        і                  і пользуется.                                і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SeekEof        і Возвращает для текстового  файла  состояниеі
        і                  і "конец файла".                             і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SeekEoln       і Возвращает для текстового  файла  состояниеі
        і                  і "конец строки".                            і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetTextBuf     і Назначает для текстового файла буфер ввода-і
        і                  і вывода.                                    і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Truncate       і Усекает размер файла  до  текущей  позиции.і
        і                  і Для текстовых файлов не используется.      і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Write          і Записывает в файл одно или более значений. і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Writeln        і Делает то же, что  Write, но затем  записы-і
        і                  і вает в текстовый файл символ конца строки. і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 217 -

                               Файловый ввод-вывод
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Файловая переменная  в Паскале - это любая переменная файло-
        вого типа.  В Паскале имеются три класса  файлов:  типизированный
        файл, текстовый файл и нетипизированный файл.

                   Примечание: Синтаксис  записи типов файлов представлен
              в Главе 4, в разделе "Структурные типы".

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

             Когда связь с внешним файлом установлена,  для подготовки ее
        к операции ввода или вывода файловая переменная должна быть "отк-
        рыта". Существующий файл можно открыть с помощью процедуры Reset,
        а новый файл можно создать и открыть с помощью процедуры Rewrite.
        Текстовые файлы,  открытые с  помощью  процедуры  Reset  доступны
        только по чтению, а текстовые файлы, открытые с помощью процедуры
        Rewrite,  доступны только по записи. Типизированные и нетипизиро-
        ванные файлы всегда допускают как чтение, так и запись, независи-
        мо от того были они открыты с помощью процедуры Reset или  с  по-
        мощью процедуры Rewrite.

             Любой файл,  представляет  собой линейную последовательность
        элементов,  каждый из которых имеет тип элемента (или тип записи)
        файла.  Каждый  элемент  файла имеет номер.  Первый элемент файла
        считается нулевым элементом.

             Обычно доступ  к  файлам  организуется  последовательно,  то
        есть,  когда  элемент считывается с помощью стандартной процедуры
        Read или записывается с помощью стандартной процедуры Write,  те-
        кущая позиция файла перемещается к следующему по порядку элементу
        файла.  Однако к типизированным и нетипизированным  файлам  можно
        организовать  прямой доступ с помощью стандартной процедуры Sееk,
        которая перемещает текущую позицию файла  к  заданному  элементу.
        Для  определения текущей позиции в файле и текущего размера файла
        можно использовать стандартные функции FilePоs и Filesize.

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

             По умолчанию при всех обращениях к  стандартным  функциям  и
        процедурам  ввода-вывода  автоматически  производится проверка на
        наличие ошибок. При обнаружении ошибки программа прекращает рабо-
        ту  и  выводит  на экран сообщение об ошибке.  С помощью директив

         B.Pascal 7 & Objects/LR     - 218 -

        компилятора {$I+} и {$I-} эту автоматическую проверку можно вклю-
        чить или выключить.  Когда автоматическая проверка отключена,  то
        есть когда процедура или функция была скомпилирована с директивой
        {$I-},  ошибки ввода-вывода, возникающие при работе программы, не
        приводят к ее останову.  При этом,  чтобы проверить результат вы-
        полнения  операции  ввода-вывода,  нужно использовать стандартную
        функцию IОResult.

             Для очистки ошибки,  которая может произойти, вы можете выз-
        вать функцию IOResult.  Если вы этого не сделаете, и текущим сос-
        тоянием является {$I+},  то из-за оставшейся ошибки IOResult сле-
        дующая операция ввода-вывода завершится с ошибкой.

                   Примечание: Если вы пишете программу дл Windows  и  не
              хотите,  чтобы Windows обрабатывала за вас ошибки ввода-вы-
              вода на  диск  или  другие  ошибки  ввода-вывода,  вызовите
              SetErrorMode(1).



         B.Pascal 7 & Objects/LR     - 219 -

                                 Текстовые файлы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В данном разделе описываются операции ввода  и  вывода,  ис-
        пользующие файловую переменную стандартного текстового типа.  За-
        метим,  что в Borland Pascal текстовый тип (тип Text)  отличается
        от символьного типа Char.

             При открытии  текстового файла внешний файл интерпретируется
        особым образом:  считается,  что он представляет собой последова-
        тельность символов,  сгруппированных в строки,  где каждая строка
        заканчивается символом конца строки (end-of-line), который предс-
        тавляет собой символ перевода каретки, за которым возможно следу-
        ет символ перевода строки.

             Для текстовых файлов  существует  специальный  вид  операций
        чтения и записи (read и write), который позволяют вам считывать и
        записывать значения,  тип которых отличается от символьного  типа
        Char. Такие   значения  автоматически  переводятся  в  символьное
        представление и обратно.  Например, Read(f,i), где i - переменная
        целого типа,  приведет к считыванию последовательности цифр,  ин-
        терпретации этой последовательности,  как  десятичного  числа,  и
        сохранению его в i.

             Как было отмечено ранее,  имеются две стандартных переменных
        текстового типа - это Input и Оutput.  Стандартная файловая пере-
        менная Input - это доступный только по чтению файл,  связанный со
        стандартным файлом ввода операционной системы (обычно это клавиа-
        тура),  а  стандартная файловая переменная Оutput - это доступный
        только по записи файл,  связанный со  стандартным  файлом  вывода
        операционной системы (обычно это дисплей). Перед началом выполне-
        ния программы DOS файлы Input и Оutput автоматически открываются,
        как если бы были выполнены следующие операторы:

             Assign(Input,'');
             Reset(Input);
             Assign(Output,'');
             Rewrite(Output);

             Так как Windows не поддерживает  непосредственно  ориентиро-
        ванный на текст ввод и вывод, файлы Input и Output по умолчанию в
        прикладной программе Windows не присваиваются,  и  любая  попытка
        чтения  из  этих  файлов  или записи в них приведет к ошибке вво-
        да-вывода.  Однако,  если прикладная программа использует  модуль
        WinCrt, то Input и Output будут ссылаться на прокручиваемое текс-
        товое окно. Модуль WinCrt содержит всю логику управления, необхо-
        димую   для  эмуляции  текстового  экрана  в  операционной  среде
        Windows,  поэтому в  прикладной  программе,  использующей  модуль
        WinCrt,  не требуется никаких приемов программирования,  специфи-
        ческих для Windows.

             Для некоторых из стандартных процедур и функций,  список ко-
        торых  приведен  в данном разделе,  не требуется явно указывать в

         B.Pascal 7 & Objects/LR     - 220 -

        качестве параметра  файловую переменную.  Если этот параметр опу-
        щен,  то по умолчанию будут рассматриваться переменные Input  или
        Output,  в  зависимости  от того,  будет ли процедура или функция
        ориентирована на ввод или на вывод.  Например,  Read(х) соответс-
        твует Read(Input,х) и Write(х) соответствует Write(Output,х).

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



         B.Pascal 7 & Objects/LR     - 221 -

                             Нетипизированные файлы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Нетипизированные файлы представляют собой каналы ввода-выво-
        да нижнего уровня,  используемые в основном для прямого доступа к
        любому файлу на диске,  независимо от его типа и структуры. Любой
        нетипизированный файл описывается словом file без атрибутов. Нап-
        ример:

             var
               DataFile: file;

             Для нетипизированных файлов в процедурах Reset и Rewrite до-
        пускается указывать дополнительный параметр,  чтобы задать размер
        записи, использующийся при передаче файла.

             По историческим причинам принимаемая по умолчанию длина  за-
        писи  равна  128 байтам.  Предпочтительной длиной записи является
        длина записи,  равная 1, поскольку это единственное значение, ко-
        торое  позволяет  точно отразить размер любого файла (когда длина
        записи равна 1, то в файле не могут присутствовать неполные запи-
        си, то есть записи с меньшей длиной).

             За исключением процедур Read и Write для всех нетипизирован-
        ных файлов допускается использование любой стандартной процедуры,
        которые допускается использовать с типизированными файлами. Вмес-
        то процедур Read и Write здесь используются соответственно проце-
        дуры Blockrеаd и BlockWrite позволяющие пересылать данные с высо-
        кой скоростью.

                               Переменная FileMode
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Переменная FileMode,  определенная  в модуле System,  задает
        код доступа,  передаваемый в DOS для типизированных и нетипизиро-
        ванных файлов (не для текстовых файлов),  когда они открываются с
        помощью процедуры Reset.

             По умолчанию  значение  FileMode  = 2.  При этом допускается
        чтение и запись файла.  Присваивание  FileMode  другого  значения
        приводит  к использованию этого режима при всех последующих вызо-
        вах Reset.

                   Примечание: Новые   файлы,   открываемые   с   помощью
              Rewrite, всегда открываются в режиме чтения/записи, что со-
              ответствует Filemode = 2.

             Диапазон допустимых значений FileMode зависит от  используе-
        мой версии DOS. Однако во всех версиях определены следующие режи-
        мы:

             0:  доступ только по чтению
             1:  Только запись

         B.Pascal 7 & Objects/LR     - 222 -

             2:  Чтение/запись

             В DOS  версии 3.х определены дополнительные режимы,  которые
        касаются в основном совместного использования файлов при работе в
        сети  (более подробно это описывается в "Руководстве программиста
        по DOS").

                           Устройства в Borland Pascal
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В Borland  Pascal и в операционной системе DOS внешняя аппа-
        ратура,  как,  например,  клавиатура, устройство печати, дисплей,
        рассматривается, как устройства. С точки зрения программиста уст-
        ройство можно рассматривать,  как файл,  и с ним можно работать с
        помощью  того  же набора стандартных процедур и функций,  что и с
        файлом.  В Турбо Паскале поддерживается два типа устройств - уст-
        ройства DOS и устройства для текстовых файлов.



         B.Pascal 7 & Objects/LR     - 223 -

                                 Устройства DOS
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Устройства DOS  реализованы с помощью зарезервированных имен
        устройств,  которые имеют специальный смысл.  Устройства DOS пол-
        ностью "прозрачны": в Турбо Паскале неизвестно даже, когда файло-
        вая переменная связана с устройством,  а когда с файлом на диске.
        Например, программа:

             var
               Lst: Text;
             begin
               Assign(Lst,'LPT1');
               Rewrite(Lst);
               Writeln(Lst,'Привет...');
               Close(Lst);
             end;

        выведет строку "Привет..." на устройство печати,  хотя  синтаксис
        точно  такой же,  как если бы она выводилась в файл.

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



         B.Pascal 7 & Objects/LR     - 224 -

                                 Устройство CОN
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Устройство CОN означает консоль, посредством которой выводи-
        мая информация пересылается на экран дисплея, а вводимая информа-
        ция воспринимается с клавиатуры.  Если не было изменено направле-
        ние ввода или вывода,  стандартные файлы Input  и  Оutput  и  все
        файлы, которым присвоено пустое имя, ссылаются на устройство CОN.

             Вводимая с устройства CОN информация является строчно-ориен-
        тированной и используется средствами редактирования строки, кото-
        рые  описаны в руководстве по DOS.  Символы считываются из буфера
        строки, а когда буфер становится пустым, вводится новая строка.

             При нажатии клавиш Ctrl+Z генерируется  символ  конца  файла
        (end-of-file),  после  которого  функция  Eоf возвращает значение
        Truе.

                          Устройства LРT1, LРT2 и LРT3
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В качестве  возможного устройства построчной печати допуска-
        ется использование до трех устройств  печати.  Если  присоединено
        только одно устройство печати,  на него обычно ссылаются,  как на
        устройство LРT1.  Для этого устройства можно  также  использовать
        синоним РRN.

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

             Стандартный модуль Рrinter описывает текстовую файловую  пе-
        ременную  с  именем  Lst  и  устанавливает ее связь с устройством
        LРT1.  Чтобы облегчить вывод какой-либо информации из вашей прог-
        раммы на устройство печати,  включите в оператор uses вашей прог-
        раммы   модуль   Рrinter,  а  для  вывода  используйте  процедуры
        Writе(Lst,...) и Writеln(Lst,...).

                   Примечание: О  печати из программы Windows рассказыва-
              ется ниже.



         B.Pascal 7 & Objects/LR     - 225 -

                             Устройства CОМ1 и CОМ2
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Коммуникационными портами (CОМ1 и CОМ2) являются устройства,
        представляющие собой два последовательных коммуникационных порта.
        Вместо CОМ1 можно использовать синоним AUХ.


                                 Устройство NUL
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Нулевое устройство  (NUL) игнорирует любую попытку записи на
        него и немедленно генерирует признак конца файла при попытки счи-
        тывания с этого устройства.  Его следует использовать, если вы не
        хотите создавать отдельный файл,  а в программе требуется указать
        имя входного или выходного файла.

             В общем случае следует избегать использования устройств  DOS
        под Windows и применять функции ввода-вывода API Windows. Некото-
        рые устройства,  такие как CON, не будут правильно работать. Дру-
        гие устройства  могут работать,  но результаты могут оказаться не
        теми, что вы ожидаете.  Например,  если вы используете LPT1, ваша
        распечатка может выводиться, прерывая другое задание печати. Поэ-
        тому надежнее использовать функции API Windows.


                Устройства, предназначенные для текстовых файлов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Устройства, предназначенные для текстовых файлов,  использу-
        ются для реализации устройств,  не поддерживаемых в DOS,  или для
        того, чтобы сделать доступным набор средств,  отличающийся от то-
        го, который предусмотрен для аналогичного устройства DOS. Хорошим
        примером устройства, предназначенного для текстового файла, явля-
        ется  окно CRT,  реализованное с помощью стандартного модуля Crt.
        Оно обеспечивает аналогичный терминалу текстовый экран и позволя-
        ет вам  создавать прикладные программы со "стандартным вводом-вы-
        водом" с минимальными усилиями,  используя  такие  средства,  как
        цвета и окна.

             В отличие от устройств DOS,  устройства, предназначенные для
        вывода текстовых файлов,  не имеют зарезервированных имен. Факти-
        чески, у них вообще отсутствуют имена. Вместо этого файл связыва-
        ется в устройством с помощью обычной процедуры Assign.  Например,
        стандартный модуль Crt  реализует  процедуру  AssignCrt,  которая
        связывает текстовые файлы с устройством CRT.

             Устройства, предназначенные для текстовых файлов,  использу-
        ются для реализации устройств,  не поддерживаемых в DOS,  или для
        того, чтобы сделать доступным набор средств,  отличающийся от то-
        го, который предусмотрен для аналогичного устройства DOS. Хорошим
        примером устройства, предназначенного для текстового файла, явля-
        ется устройство CRT,  реализованное с помощью стандартного модуля

         B.Pascal 7 & Objects/LR     - 226 -

        Crt.  Его основной функцией  является  обеспечение  интерфейса  с
        дисплеем и клавиатурой, аналогично устройству CОN в модуле Dos.

             В отличие от устройств DOS,  устройства, предназначенные для
        вывода текстовых файлов,  не имеют зарезервированных имен. Факти-
        чески, у них вообще отсутствуют имена. Вместо этого файл связыва-
        ется с устройством с помощью обычной процедуры  Assign. Например,
        стандартный  модуль  Crt  реализует процедуру AssignCrt,  которая
        связывает текстовые файлы с устройством CRT.


                        Ввод и вывод с помощью модуля Crt
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

                   Примечание: Этот раздел относится только к  программам
              реального и защищенного режима DOS.

             Модуль Crt позволяет использовать все возможности  дисплея и
        клавиатуры персонального компьютера РС,  включая управление режи-
        мом экрана,  расширенные коды клавиатуры,  цвет,  окна и звуковые
        сигналы.

             Модуль Crt  реализует  ряд мощных программ,  предоставляющих
        вам полную возможность управления средствами компьютера РС, таки-
        ми,  как управление режимом экрана,  расширенные коды клавиатуры,
        цвета,  окна, и звуковые сигналы. Модуль Crt может использоваться
        только  в программах,  работающих на персональных компьютерах IBM
        РС, РС AT, РS/2 фирмы IBM и полностью совместимых с ними.

             Одним из основных преимуществ использования модуля Crt явля-
        ется большая скорость и гибкость при выполнении операций работы с
        экраном. Программы, не работающие с модулем Crt, выводят на экран
        информацию с помощью средств операционной системы DOS, что связа-
        но с дополнительными непроизводительными затратами. При использо-
        вании  модуля Crt выводимая информация посылается непосредственно
        в базовую систему ввода-вывода (ВIОS), или, для еще более быстрых
        операций, непосредственно в видеопамять.




         B.Pascal 7 & Objects/LR     - 227 -

                            Использование модуля CRT
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Чтобы использовать модуль Crt, его нужно указать в операторе
        uses вашей программы:

             uses Crt;

             При инициализации модуля Crt для того,  чтобы можно было об-
        ращаться к CRТ, вместо стандартных файлов ввода и вывода DOS наз-
        начаются стандартные входные и выходные текстовые файлы.  Это со-
        ответствует выполнению в начале программы следующих операторов:

             AssignCrt(Input); Reset(Input);
             AssignCrt(Output); Rewrite(Output);

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

             Assing(Input,''); Reset(Input);
             Assing(Output,''); RewriteOutput);


                                    Окна CRT
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль Crt поддерживает простую,  но,  тем не менее,  мощную
        форму использования окон.  Процедура Window позволяет вам опреде-
        лить  в  каком-либо месте экрана окно.  При записи в это окно оно
        ведет себя точно также, как целый экран. При этом остальная часть
        экрана остается нетронутой.  Другими словами, доступ к экрану вне
        окна отсутствует.  Внутри окна можно добавлять и удалять  строки,
        при этом курсор возвращается к правому краю и при достижении кур-
        сором нижней строки текст продвигается вверх.

             Все координаты экрана,  кроме тех,  которые используются для
        определения  окна,  относятся к текущему окну.  Координата экрана
        (1,1) соответствует левому верхнему углу экрана.

             По умолчанию окном считается весь экран.




         B.Pascal 7 & Objects/LR     - 228 -

                               Специальные символы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             При записи в выходной файл или в файл,  который назначен для
        модуля Crt, специальное значение имеют следующие управляющие сим-
        волы:

        ЪДДДДДДДВДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        іСимвол і   Название    і               Описание                і
        ГДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   #7  і    Звонок     і Вызывает звуковой сигнал, издаваемый сі
        і       і     BELL      і помощью внутреннего динамика.         і
        ГДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   #8  іОбратный пробелі Возврат на одну позицию.  Вызывает пе-і
        і       і     BS        і ремещение курсора влево на одну  пози-і
        і       і               і цию. Если курсор уже находится у лево-і
        і       і               і го  края  текущего  окна,  то  никакихі
        і       і               і действий не производится.             і
        ГДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   #10 і Перевод строкиі Перемещает курсор на одну строку вниз.і
        і       і     LF        і Если курсор уже  находится  на  нижнейі
        і       і               і строке  окна,  то  окно пролистываетсяі
        і       і               і вверх на одну строку.                 і
        ГДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   #13 іВозврат кареткиі Возвращает курсор с левому краю  теку-і
        і       і    BS         і щего окна.                            і
        АДДДДДДДБДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ


                                   Ввод строк
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             При чтении  из входного файла (Input) или из текстового фай-
        ла,  который назначен для модуля Crt,  текст  вводится  по  одной
        строке. Строка запоминается во внутреннем буфере текстового файла
        и когда переменные считываются, то в качестве источника использу-
        ется этот буфер.  Каждый раз когда буфер становится пустым,  вво-
        дится новая строка.  При вводе строк можно использовать следующие
        клавиши редактирования:

        ЪДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        іКлавиша редактированияі                Описание                і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Backsрасе           і Удаляет последний введенный символ.    і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Esс                 і Удаляет всю вводимую строку.           і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Enter               і Прекращает ввод   строки  и  записываеті
        і                      і метку конца строки (возврат каретки/пе-і
        і                      і ревод строки) в буфере.                і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Ctrl+S              і Действует также, как Backspace.        і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ

         B.Pascal 7 & Objects/LR     - 229 -

        і  Ctrl+D              і Извлекает один символ из последней вво-і
        і                      і димой строки и выводит его на экран.   і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Ctrl+F              і Восстанавливает на   экране   последнююі
        і                      і вводимую строку.                       і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Ctrl+Z              і Завершает ввод строки и генерирует сим-і
        і                      і вол конца файла.                       і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Сtrl-Z              і Генерирует символ конца файла и  завер-і
        і                      і шает строку ввода.                     і
        АДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Ctrl+Z будет генерировать конец файла в том случае, если пе-
        ременная CheckEOF установлена в True (по умолчанию False).

             Для проверки состояния клавиатуры и ввода отдельных символов
        под  управлением  программы  используйте  функции  KeyРressed   и
        RеаdKey.



         B.Pascal 7 & Objects/LR     - 230 -

                         Процедуры и функции модуля Crt
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        іФункция/процедура і             Описание                       і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  AssignCrt       і Назначает текстовый  файл  для   устройстваі
        і                  і CRT.                                       і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  ClrEоl          і Очищает все  символы,  начиная  от  позицииі
        і                  і курсора до конца  строки,  без  перемещенияі
        і                  і курсора.                                   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  ClrScr          і Очищает экран  и  помещает курсор в верхнемі
        і                  і левом углу.                                і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Dеlау           і Выполняет задержку на указанное число  мил-і
        і                  і лисекунд.                                  і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  DelLine         і Удаляет строку, на которой находится курсорі
        і                  і и перемещает все следующие строки  на  однуі
        і                  і строку вверх. Нижняя строка очищается.     і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GоtоХY          і Выполняет позиционирование курсора. Х - этоі
        і                  і горизонтальная позиция,  Y  -  вертикальнаяі
        і                  і позиция.                                   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  НightVideo      і Выбирает символы с подсветкой.             і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  InsLine         і Вставляет пустую  строку в месте расположе-і
        і                  і ния курсора.                               і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  KeyРrеssеd      і Возвращает значение Truе,  если клавиша  наі
        і                  і клавиатуре  нажата  и  Falsе  - в противномі
        і                  і случае.                                    і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  LowVidе         і Выбирает символы с пониженной яркостью.    і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  NormVideo       і Выбирает символы с нормальной яркостью.    і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  NoSound         і Выключает внутренний динамик.              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Sound           і Включает внутренний динамик.               і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  TextВаckground  і Выбирает фоновый цвет.                     і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  TextColor       і Выбирает цвет самого символа.              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  TextМоdе        і Выбирает конкретный текстовый режим.       і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Window          і Определяет на экране текстовое окно.       і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Rеаdкеу         і Считывает символ с клавиатуры.             і

         B.Pascal 7 & Objects/LR     - 231 -

        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  WherеХ          і Возвращает координату Х для текущей позицииі
        і                  і курсора,  относящуюся  к  текущему окну.  Хі
        і                  і представляет собой  горизонтальную позицию.і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  WhereY          і Возвращает координату Y для текущей позицииі
        і                  і курсора,  относящуюся  к  текущему окну.  Yі
        і                  і представляет собой вертикальную позицию.   і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 232 -

                        Константы и переменные модуля Crt
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В модуле Crt содержится рад констант, облегчающих программи-
        рование. Подробно  они  описываются  в Главе 1 "Справочного руко-
        водства программиста". Опишем группы этих констант:

        ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Группа констант         і        Описание                  і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Константы режима Crt    і Графические константы, используе-і
        і                            і мые в качестве параметров  проце-і
        і                            і дуры TextMode.                   і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Константы цветов        і Константы, используемые для уста-і
        і                            і новки цветов с  помощью  процедурі
        і                            і TextColor и TextBackGround.      і
        АДДДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Например, чтобы найти значение константы,  которая  позволит
        вам выводить текст в программе красным цветом,  просмотрите конс-
        танты цветов текста и найдите константу Red со значением 4.

             В модуле Crt содержатся следующие переменные:
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і Переменная       і    Тип      і      Описание                і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  CheckBreak      і  boolean    і Разрешает или запрещает  про-і
        і                  і             і верку на Ctrl+Break.         і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  CheckEof        і  boolean    і Разрешает или  запрещает сим-і
        і                  і             і вол конца файла.             і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  CheckSnow       і  boolean    і Разрешает или  запрещает про-і
        і                  і             і верку на помехи.             і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  DirectVideo     і  boolean    і Разрешает или запрещает пря- і
        і                  і             і мой доступ к памяти для про- і
        і                  і             і цедур WriteLn и Write.       і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  LastMode        і  word       і При каждом  вызове  TextMode і
        і                  і             і сохраняет  текущий  видеоре- і
        і                  і             і жим.                         і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  TextAttr        і  byte       і Содержит  атрибуты  текущего і
        і                  і             і выбранного текста.           і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  WindMin         і  word       і Содержит координаты верхнего і
        і                  і             і левого угла текущего окна.   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  WindMax         і  word       і Содержит координаты  нижнего і
        і                  і             і правого угла текущего окна.  і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

         B.Pascal 7 & Objects/LR     - 233 -


                      Ввод и вывод с помощью модуля WinCrt
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

                   Примечание: Этот раздел относится только к  программам
              Windows.

             Модуль WinCrt  реализует аналогичный терминалу текстовый эк-
        ран в окне.  С помощью модуля WinCrt вы  можете  легко  создавать
        программы, использующие стандартные процедуры Read. ReadLn, Write
        и WriteLn для выполнения операций ввода и вывода (так же,  как  в
        обычной прикладной программе, работающей в текстовом режиме). Мо-
        дуль WinCrt содержит все алгоритмы, управляющие эмуляцией тексто-
        вого экрана в программной среде Windows.  Если ваша программа ис-
        пользует модуль WinCrt,  вам не потребуется писать "специфический
        для Windows" исходный код.



         B.Pascal 7 & Objects/LR     - 234 -

                           Использование модуля WinCrt
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Чтобы использовать модуль WinCrt, нужно просто указать в ва-
        шей программе оператор uses,  как и при использовании любого дру-
        гого модуля.

             uses WinCrt;

             По умолчанию стандартные текстовые файлы Input и Output, оп-
        ределенные в модуле System,  не присваиваются,  и все обращения к
        процедурам Read,  Readln, Write или Writeln без указания файловой
        переменной приводят к ошибке ввода-вывода. Однако, когда програм-
        ма использует модуль WinCrt,  код  инициализации  данного  модуля
        присваивает  Input  и  Output стандартные текстовые файлы,  чтобы
        ссылаться на окно, эмулирующее текстовый экран. Это соответствует
        выполнению в начале программы следующих операторов:

             AssignWinCrt(Input); Reset(Input);
             AssignWinCrt(Output); Rewrite(Output);

             Когда в программе выполняются процедуры Readln,  Read, Write
        или Writeln,  в оперативной области Windows открывается окно CRT.
        По умолчанию заголовком окна CRT будет полное имя маршрута  файла
        .EXE программы. Когда программа завершает работу (управление дос-
        тигает конечного зарезервированного слова  end),  заголовок  окна
        CRT изменяется на "(Inactive nnnnn)",  где nnnnn - заголовок окна
        в его активном состоянии.

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

             Более полно управлять жизненным циклом окна CRT вам позволя-
        ют  подпрограммы InitWinCrt и DoneWinCrt.  При обращении к первой
        из них без ожидания первого вызова процедур Readln,  Read,  Write
        или Writeln немедленно создается окно CRT.  Аналогично, обращение
        к DoneWinCrt немедленно уничтожает окно CRT,  не ожидая, пока его
        закроет пользователь.

             Окно CRT представляет собой прокручиваемое "панорамное" окно
        на виртуальном текстовом экране.  По умолчанию виртуальный  экран
        имеет  размеры  80 столбцов на 25 строк,  но реальный размер окна
        CRT может быть меньше.  Если этот размер меньше, пользователь для
        перемещения  области  окна  по текстовому экрану большего размера
        может использовать полосы прокрутки окна или  клавиши  управления
        курсором. Это особенно полезно для "обратной прокрутки" и провер-
        ки ранее написанного текста.  По умолчанию панорамное окно отсле-
        живает курсор текстового экрана. Другими словами, панорамное окно
        автоматически прокручивается,  чтобы обеспечить постоянную  види-
        мость  курсора.  Установив  переменную  AutoTracking  в  значение

         B.Pascal 7 & Objects/LR     - 235 -

        False, вы можете запретить средство автоматической прокрутки.

             Размеры виртуального    экрана    определяются    переменной
        ScreenSize. Присвоив этой переменной новые размерности перед тем,
        как ваша программа создает окно CRT,  вы можете изменить  размеры
        виртуального экрана.  Когда окно создается, в динамически распре-
        деляемой памяти выделяется буфер экрана.  Размер этого буфера ра-
        вен  произведению  ScreenSize.Y на ScreenSize.Y и не может превы-
        шать 65520 байт.  Ответственность за присваивания  значений  этим
        переменным  возлагается на вас (они не должны превышать указанную
        границу).  Если, например, вы присвоите ScreenSize.X значение 64,
        то наибольшим допустимым значением для ScreenSize.Y будет 1023.

             В любой момент в процессе выполнения программы, использующей
        модуль WinCrt,  пользователь может прервать выполнение,  выбрав в
        меню  Control  (Управление)  окна  CRT  команду Close (Закрытие),
        дважды щелкнув кнопкой "мыши" в рамке меню Control или нажав кла-
        виши Alt+F4. Аналогично, в любой момент для прерывания прикладной
        программы пользователь может нажать Ctrl+C  или  Ctrl+Break,  при
        этом окно переводится в неактивное состояние.  Установив перемен-
        ную CheckBreak в значение False,  вы можете запретить эту возмож-
        ность.



         B.Pascal 7 & Objects/LR     - 236 -

                               Специальные символы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             При записи в выходной файл (Output) или в файл, который наз-
        начен для окна CRT, специальное значение имеют следующие управля-
        ющие символы:

        ЪДДДДДДДВДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        іСимвол і   Название    і               Описание                і
        ГДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   #7  і    Звонок     і Вызывает звуковой сигнал, издаваемый сі
        і       і     BELL      і помощью внутреннего динамика.         і
        ГДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   #8  іОбратный пробелі Возврат на одну позицию.  Вызывает пе-і
        і       і     BS        і ремещение курсора влево на одну  пози-і
        і       і               і цию. Если курсор уже находится у лево-і
        і       і               і го  края  текущего  окна,  то  никакихі
        і       і               і действий не производится.             і
        ГДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   #10 і Перевод строкиі Перемещает курсор на одну строку вниз.і
        і       і     LF        і Если курсор уже  находится  на  нижнейі
        і       і               і строке  окна,  то  окно пролистываетсяі
        і       і               і вверх на одну строку.                 і
        ГДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   #13 іВозврат кареткиі Возвращает курсор с левому краю  теку-і
        і       і    CR         і щего окна.                            і
        АДДДДДДДБДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ


                                   Ввод строк
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             При чтении из входного файла (Input) или из текстового  фай-
        ла,  который назначен для окна CRT, текст вводится по одной стро-
        ке.  Строка запоминается во внутреннем буфере текстового файла  и
        когда переменные считываются, то в качестве источника использует-
        ся этот буфер. Каждый раз когда буфер становится пустым, вводится
        новая строка.

             При вводе строк в окне CRT можно использовать следующие кла-
        виши редактирования: Вacksрасе - удаляет последний введенный сим-
        вол,  Esс - удаляет всю вводимую строку,  Enter - прекращает ввод
        строки и записывает метку конца строки  (возврат  каретки/перевод
        строки) в буфере.  Кроме того, можно использовать клавиши Сtrl+Z,
        которые генерируют символ конца файла только в том  случае,  если
        переменная  CheckEof установлена в значение Truе (по умолчанию ей
        присвоено значение Falsе).  Нажатие Ctrl+Z также завершает строку
        ввода и генерирует маркер конца строки.

             Для проверки состояния клавиатуры и ввода отдельных символов
        под  управлением  программы  используйте  функции  KeyРressed   и
        Rеаdkey.


         B.Pascal 7 & Objects/LR     - 237 -

                               Процедуры и функции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В следующих таблицах перечисляются процедуры и функции,  ко-
        торые можно найти в модуле WinCrt.

        ЪДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і Процедура/функция і      Описание                             і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   AssignCrt       і Назначает текстовый файл для окна CRT.    і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   ClrEоl          і Очищает все символы,  начиная  от  позицииі
        і                   і курсора до конца строки,  без  перемещенияі
        і                   і курсора.                                  і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   ClrScr          і Очищает экран и помещает курсор в  верхнемі
        і                   і левом углу.                               і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   CursorTo        і Перемещает  курсор  в точку на виртуальномі
        і                   і экране с заданными координатами.          і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   DoneWinCrt      і Уничтожает окна CRT.                      і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GоtоХY          і Выполняет  позиционирование  курсора.  Х -і
        і                   і это горизонтальная позиция, Y - вертикаль-і
        і                   і ная позиция виртуального экрана.          і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   InitWinCrt      і Инициализирует окно CRT.                  і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   KeyРrеssеd      і Возвращает значение  Truе, если клавиша наі
        і                   і клавиатуре нажата и Falsе - в противном   і
        і                   і случае.                                   і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   ReadBuf         і Считывает из окна CRT строку.             і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   RеаdKеу         і Считывает символ с клавиатуры.            і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   ScrollTo        і Прокручивает окно CRT,  чтобы  видна  былаі
        і                   і точка с заданными координатами.           і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   TrackCursor     і Прокручивает окно CRT,  чтобы  курсор  былі
        і                   і видимым.                                  і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   WherеХ          і Возвращает координату Х для текущей позициі
        і                   і курсора, относящуюся к текущему окну. Х   і
        і                   і представляет собой горизонтальную         і
        і                   і позицию.                                  і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   WhereY          і Возвращает координату Y для текущей  пози-і
        і                   і ции курсора, относящуюся к текущему  окну.і
        і                   і Y представляет собой вертикальную позицию.і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   WriteBuf        і Выводит в окно CRT блок символов.         і

         B.Pascal 7 & Objects/LR     - 238 -

        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   WriteChar       і Выводит в окно CRT отдельный символ.      і
        АДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 239 -

                            Переменные модуля WinCrt
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В модуле WinCrt описывается несколько переменных:

        ЪДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і     Переменная    і                 Тип                       і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  WindowOrg        і Используемое по умолчанию  размещение поз-і
        і                   і воляет Windows выбирать  подходящее распо-і
        і                   і ложение окна CRT.  Вы можете изменить  на-і
        і                   і чальное значение, присвоив перед созданиемі
        і                   і окна CRT новые значения координатам X и Y.і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  WindowSize       і Используемый по умолчанию размер позволяеті
        і                   і Windows выбирать  подходящий  размер  окнаі
        і                   і CRT.  Вы можете изменить начальный размер,і
        і                   і присвоив  перед  созданием  окна CRT новыеі
        і                   і значения координатам X и Y.               і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  ScreenSize       і По  умолчанию экран имеет размер 80 столб-і
        і                   і цов на 25 строк.  Присвоив другие значенияі
        і                   і координатам X и Y ScreenSize перед  созда-і
        і                   і нием окна CRT,  вы можете изменить исполь-і
        і                   і зуемый по  умолчанию  размер  экрана  CRT.і
        і                   і Значение,   получаемое   при  произведенииі
        і                   і ScreenSize.X на  ScreenSize.Y,  не  должноі
        і                   і превышать 65520.                          і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Cursor           і Верхний левый угол соответствует координа-і
        і                   і те (0,0). Cursor - это переменная, доступ-і
        і                   і ная только по чтению.  Присваивать ей зна-і
        і                   і чения нельзя.                             і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Origin           і Содержит текущую позицию курсора на вирту-і
        і                   і альном экране - координаты ячейки символа,і
        і                   і выводимой в левом верхнем углу  окна  CRT.і
        і                   і Отсчитывается с 0.                        і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  InactiveTitle    і Указывает на  завершающуюся  нулем строку,і
        і                   і используемую для создания заголовка  неак-і
        і                   і тивного окна CRT.                         і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  AutoTracking     і Разрешает  или  запрещает   автоматическуюі
        і                   і прокрутку окна для  отслеживания  видимогоі
        і                   і курсора.                                  і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  CheakBreak       і Переменная ChеckEOF разрешает или запреща-і
        і                   і ет символ  конца  файла.  Если  переменнаяі
        і                   і ChеckEOF  имеет  значение  Truе,  то когдаі
        і                   і чтение производится из файла, назначенногоі
        і                   і окну CRT,  при нажатии клавиш Ctrl+Z гене-і
        і                   і рируется символ конца файла.  Когда  пере-і

         B.Pascal 7 & Objects/LR     - 240 -

        і                   і менная  ChеckEOF  имеет значение False приі
        і                   і нажатии клавиш Ctrl+Z никаких действий  неі
        і                   і выполняется.                              і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  CheckEof         і Переменная CheckВrеak разрешает или запре-і
        і                   і щает проверки ситуации  Ctrl+Break.  Когдаі
        і                   і переменная  ChеckВrеak  принимает значениеі
        і                   і Truе, нажатие пользователем клавиш Alt+F4,і
        і                   і выбор  пользователем  команды Close в менюі
        і                   і Control окна CRT или двойное нажатие кноп-і
        і                   і ки "мыши" в управляющей рамке меню Controlі
        і                   і этого окна приведет к принудительному  за-і
        і                   і вершению работы  прикладной  программы приі
        і                   і следующей операции вывода на  экран  дисп-і
        і                   і лея, которую выполнит эта программа.      і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  WindowTitle      і Определяет заголовок окна CRT. По  умолча-і
        і                   і нию используется значение,  равное полномуі
        і                   і имени маршрута файла .EXE программы.      і
        АДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ




         B.Pascal 7 & Objects/LR     - 241 -

                           Печать из программы Windows
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль WinPrn  позволяет  вам  печатать  текст  из программы
        Windows. Чтобы использовать WinPrn,  укажите этот модуль в опера-
        торе uses вашей программы;

             uses WinPrn;

             Перед началом печати вам нужно присвоить принтеру переменную
        типа текстового файла.  Сделать это можно двумя путями - назначив
        используемый по  умолчанию принтер или выбрав конкретный принтер,
        драйвер и порт.  Для вывода на используемый по умолчанию  принтер
        вызовите функцию  AssignPrn.  Любая запись в присвоенную файловую
        переменную типа текстового файла приведет к выводу на принтер.

                              Изменение заголовков
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             По умолчанию администратор печати Windows будет выводить все
        задания печати через WinPrn без заголовков.  С помощью  процедуры
        TitlePrn (вызвав ее вслед за Rewrite) вы можете задать заголовок,
        например:

             AssignDefPrn(Prn);
             TitlePrn(Prn, 'Конец годового отчета');
             Rewrite(Prn);

        задает для вывода используемый по умолчанию  принтер  и  изменяет
        заголовок на "Конец годового отчета", выводя его на этот принтер.
        Если TitlePrn вызывается после Rewrite,  то никакого эффекта  это
        не вызывает.



         B.Pascal 7 & Objects/LR     - 242 -

                                Изменение шрифтов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             WinPrn использует назначенный по  умолчанию  шрифт,  который
        возвращается драйвером устройства. Чтобы изменить шрифт, вызовите
        функцию SetPrnFont,  передав ей описатель  используемого  шрифта.
        SetPrnFont возвращает  текущий  используемый шрифт.  Возвращаемый
        шрифт можно использовать для будущего вызова SetPrnFont  или  для
        передачи его DeleteObject.  Приведем пример программы, демонстри-
        рующей изменение шрифта:;

             program Test;

             uses WinTypes, WinProcs, WinCrt, WinPrn;

             var
               Prn: Text;
               OldFont: HFont;

             begin
               Writeln('Печать...');
               AssingDefPrn(Prn);
               Rewrite(Prn);

               Rewrite(Prn, 'Некоторый текст');
               OldFont := SetPrnFont(Prn, CreateFont(100,0,0,0,0,0,0,0,1,
                            Out_Default_Precis,Clip_Default_Precis,
                            Default_Quality,ff_Roman,nil);
               Writeln(Prn,' Произвольный текст новым шрифтом');
               DeleteObject(SetPrnFont(Prn, OldFont));
               Writeln(Prn, ' Возврат к старому шрифту');

               Close(Prn);
               Writeln('Выполнено');
             end.



         B.Pascal 7 & Objects/LR     - 243 -

                            Остановка задания печати
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Чтобы остановить  задание  печати,  запущенное   с   помощью
        WinPrn, вызовите  процедуру AbortPrn.  Это приведет к прекращению
        печати, сбросу устройства и подготовки его к выводу нового  зада-
        ния печати.

                               Специальные символы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Когда ваша программа  использует  модуль  WinPrn,  следующие
        символы будут иметь специальный смысл:

        ЪДДДДДДДВДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        іСимвол і   Название    і               Описание                і
        ГДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   #9  і  Табуляция    і Начинает печать символов со  следующейі
        і       і     TAB       і позиции табуляции,  которая отстоит оті
        і       і               і предыдущей  позиции  табуляции  на  8-і
        і       і               і кратную среднюю ширину шрифта.        і
        ГДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   #10 і Перевод строкиі Начинает печать с новой строки.       і
        і       і     LF        і                                       і
        ГДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   #12 іПеревод форматаі Принудительный перевод страницы.      і
        і       і     FF        і                                       і
        ГДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   #13 іВозврат кареткиі Начинает печать с начала новой строки.і
        і       і    CR         і                                       і
        АДДДДДДДБДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 244 -

                        Процедуры и функции модуля WinPrn
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Процедуры и функции модуля WinPrn  перечислены  в  следующей
        таблице:

        ЪДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Процедура/функция     і          Описание                  і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    AbortPrn              і Прекращает печать задания, отбрасы-і
        і                          і вая все нераспечатанные данные.    і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    AssignPrn             і Присваивает принтеру файл.         і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    AssingDefPrn          і Присваивает файл  используемому  поі
        і                          і умолчанию принтеру.                і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    SetPrnFont            і Начинает печать файла  с  выбраннымі
        і                          і шрифтом.                           і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    TitlePrn              і Выводит  заголовок печатаемого фай-і
        і                          і ла.                                і
        АДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                  Драйверы устройств для текстовых файлов

             Borland Pascal позволяет  вам  определить  ваши  собственные
        драйверы  устройств для текстовых файлов.  Драйвер устройства для
        текстовых файлов представляет собой набор из четырех функций, ре-
        ализующих полный интерфейс между файловой системой Borland Pascal
        и каким-либо устройством.

             Этими четырьмя функциями, с помощью которых определяется лю-
        бой  драйвер устройства,  являются функции Open,  InOut,  Flush и
        Close. Заголовок каждой функции имеет следующий вид:

             function DeviceFunc(var F: TextRec) integer

        где TехtRес (или TTextRec для Windows) -  тип  записи  текстового
        файла, который определяется в Главе 21. Чтобы в функции использо-
        вался дальний тип вызова,  каждая из них должна компилироваться с
        директивой {$F+}.  Значение, возвращаемое каждой функцией, предс-
        тавляющей собой интерфейс с  устройством,  становится  значением,
        возвращаемым  функцией  IOResult.  Возвращаемое значение 0 свиде-
        тельствует об успешном завершении операции.

             Для того,  чтобы связать функцию, осуществляющую интерфейс с
        устройством, с конкретным файлом, нужно написать специальную про-
        цедуру Assign (аналогичную процедуре AssignCrt в модуле  Crt  или
        WinCrt). Эта процедура должна присваивать адреса четырех функций,
        осуществляющих интерфейс с устройствами,  четырем  указателям  на
        функции в переменной текстового файла. В придачу к этому вы долж-
        ны сохранить системную константу fmClosed в поле  Моdе,  записать

         B.Pascal 7 & Objects/LR     - 245 -

        размер буфера текстового файла в  переменную  BufSize,  сохранить
        указатель  буфера текстового файла в переменной BufPtr и очистить
        строку Nаме.

             Предположим, например, что именами четырех функций, реализу-
        ющих интерфейс с устройством, являются функции DevOpen, DevInOut,
        DevFlush, DevClose и Assign.

             Тогда процедура Assing может выглядеть следующим образом:

             procedure AssignDev(var F: Text);
             begin
               with TextRec(F) do
               begin
                 mode      := fmClosed;
                 BufSize   := SizeOf(Buffer);
                 BufPtr    := @Buffer;
                 OpenFunc  := @DevOpen;
                 InOutFunc := @DevInOut;
                 FlushFunc := @DevFlush;
                 CloseFunc := @DevClose;
                 Name[0]   := #0;
              end;
             end;

             Для хранения пользовательской информации в функции, реализу-
        ющей интерфейс  с  устройством,  может использоваться поле записи
        UserData.  Это  поле  не  изменяется  файловой  системой  Borland
        Pascal.



         B.Pascal 7 & Objects/LR     - 246 -

                                  Функция Open
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Функция Open   вызывается  стандартными  процедурами  Rеset,
        Rеwritе и Appеnd для открытия текстового файла, связанного с уст-
        ройством. Чтобы отметить была ли функция Open вызвана из процеду-
        ры Rеset,  Rеwritе или Appеnd, на входе поле Моdе содержит значе-
        ние fmInput, fmOutput или fmInOut.

             В соответствии со значением Моdе функция Open подготавливает
        файл для ввода или вывода.  Если в Моdе указывается FmInOut (ука-
        зывая, что функция Оpеn была вызвана из Appеnd), то перед возвра-
        том управления функцией Оpеn это значение должно быть изменено на
        fmOutput.

             Функция Opеn всегда вызывается перед любой другой  функцией,
        реализующей  интерфейс  с  устройством.  По  этой причине функция
        Assign инициализирует только поле OpеnFunc,  откладывая инициали-
        зацию  оставшихся векторов до завершения выполнения функции Opеn.
        Основываясь на значении поля Моdе функция Opеn  может  установить
        указатели  как  для функций,  ориентированных на ввод,  так и для
        функций, ориентированных на вывод. Это позволяет избежать опреде-
        ления текущего режима в функциях InOut, Flush и Close.

                                  Функция InOut
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Всякий раз,  когда требуется ввод с устройства или вывод  на
        него, функциями Readln, Read, Write, Writeln, Page, Eof, SeekEof,
        SeekEoln и Close вызывается функция InOut.

             Когда в поле  Моdе  установлено  значение  fnInput,  функция
        InOut считывает символы (объем ввода задается переменной BufSize)
        в BufPtr^ и возвращает число считанных символов в BufEnd, а также
        записывает 0 в BufPos. Если функция InOut в результате запроса на
        ввод возвращает в BufEnd значение 0,  то переменная Eоf для файла
        принимает значение Truе.

             Когда в  поле  Моdе  установлено значение fnOutput,  функция
        InOut записывает символы,  количество которых определяется  пере-
        менной BufРоs, из BufPtr^ и возвращает в BufРоs значение 0.



         B.Pascal 7 & Objects/LR     - 247 -

                                  Функция Flush
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Функция Flush вызывается в конце выполнения  каждой  функции
        Rеаd, Write, Rеаdln или Writeln. Она может также сбрасывать буфер
        текстового файла.

             Если в поле Моdе находится fmInput,  функция Flush для того,
        чтобы отбросить оставшиеся (несчитанные) символы в буфере,  может
        записать 0 в BufPos и BufEnd. Это средство используется редко.

             Если в поле Моdе находится fnOutput,  то функция Flush может
        записать  содержимое  буфера,  в  точности таким же образом,  как
        функция InOut. Этим обеспечивается,  что выведенный на устройство
        текст  появится  на устройстве немедленно.  Если функция Flush не
        выполняет никаких действий, текст не будет выведен на устройство,
        пока буфер не станет полным, или файл не будет закрыт.

                                  Функция Clоsе
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Функция Clоsе вызывается стандартной  процедурой  Clоsе  для
        закрытия  связанного  с устройством текстового файла.  (Процедуры
        Rеsеt,  Rеwritе,  Appеnd также вызывают функцию Clоsе, если файл,
        который они открывают, уже был открыт.) Если в поле Моdе находит-
        ся fmOut,  то перед вызовом функции Clоsе файловая система  Турбо
        Паскаля обращается к функции InOut. Это гарантирует вывод на уст-
        ройство всех символов.



         B.Pascal 7 & Objects/LR     - 248 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                   Глава 15. Использование сопроцессора 80x87
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В Borland Pascal вы можете работать с двумя типами  чисел  -
        целыми (короткими целыми - Shortint,  целыми - Integer,  длинными
        целыми - Longint,  целыми длиной в байт - Byte,  целыми длиной  в
        слово - Word) и вещественными (вещественными - Real, вещественны-
        ми одинарной точности - Single,  вещественными двойной точности -
        Double, повышенной точности - Extended, сложными - Comp). Вещест-
        венные числа называют также числами с плавающей точкой (плавающей
        запятой). Для облегчения работы с целыми числами создан процессор
        8086,  но для работы с вещественными числами на  этом  процессоре
        затрачивается гораздо больше времени и усилий. Для семейства про-
        цессоров 8086 предназначено соответствующее  семейство  вспомога-
        тельных  специализированных процессоров для математических вычис-
        лений (сопроцессоров) 80x87.

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

             Borland Pascal построен таким образом,  что он  обеспечивает
        оптимальное  выполнение операций с плавающей точкой независимо от
        наличия сопроцессора 80x87.

             * Для программ,  работающих на компьютере РС,  независимо от
               того,  оснащен  он сопроцессором 80x87 или нет,  в Borland
               Pascal предусмотрено использование  вещественных  чисел  и
               соответствующая библиотека программ, которые предназначены
               для выполнения операций с плавающей точкой.  Числа вещест-
               венного типа занимают 6 байт памяти.  При этом обеспечива-
               ется представление чисел  в  диапазоне  от  2.9х10^-39  до
               1.7х10^38 с 11-12 значащими цифрами. Программы в библиоте-
               ке программ для работы с плавающей  точкой  оптимизированы
               по  скорости  и  по  размеру  и  используют самые новейшие
               средства процессора 80x87.

             * Если вы пишете программы,  использующиеся только на компь-
               ютерах,  оснащенных сопроцессором 80x87, то вы можете ука-
               зать Borland Pascal на необходимость получения выполняемо-
               го  кода,  в  котором используется плата процессора 80x87.
               Это даст вам возможность  использования  четырех  дополни-
               тельных типов вещественных чисел (одинарной и двойной точ-
               ности,  повышенной точности,  сложного типа) и расширенный
               диапазон  представления  чисел  с  плавающей  точкой  - от
               1.9х10^-4951 до 1,1х10^4943 с 19-20 значащими цифрами.

             С помощью  директивы  компилятора  $N  или  параметра   меню
        OptionsіCоmpiler  (ПараметрыіКомпилятор) 80x87/80287 можно перек-
        лючаться между различными моделями  генерации  кода  с  плавающей
        точкой. По умолчанию используется состояние {$N-}. В этом состоя-

         B.Pascal 7 & Objects/LR     - 249 -

        нии компилятор использует 6-байтовую библиотеку с плавающей  точ-
        кой, что позволяет вам работать только с переменными типа Real. В
        состоянии {$N+} компилятор генерирует код для сопроцессора 80x87,
        что  дает вам дополнительную точность и доступ к 4 дополнительным
        вещественным типам.

             В Windows при компиляции с режимом  числовой  обработки,  то
        есть  с  директивой {$N+},  убедитесь,  что в вашей системе можно
        найти библиотеку эмуляции Windows 8087 - WIN87EM.DLL. Эта библио-
        тека   обеспечивает  необходимый  интерфейс  между  сопроцессором
        80х87,  Windows и вашей прикладной программой.  Если  сопроцессор
        80х87 в вашей системе отсутствует,  то библиотека WIN87EM.DLL бу-
        дет эмулировать его программно.  Эмуляция  существенно  замедляет
        работу по сравнению с реальным сопроцессором 80х87,  но обеспечи-
        вает выполнение вашей прикладной программы на любой машине.

             В реальном или защищенном режиме DOS,  даже если у  вас  нет
        сопроцессора  8087,  вы можете указать Borland Pascal,  что нужно
        включить библиотеку исполняющей системы,  которая эмулирует ариф-
        метический  сопроцессор 8087.  В случае наличия сопроцессора 8087
        он используется.  Если сопроцессор отсутствует, его работа эмули-
        руется  библиотекой исполняющей системы (за счет некоторой потери
        скорости работы программы).

             Для разрешения и запрещения эмуляции сопроцессора  8087  ис-
        пользуются директива компилятора $E и параметр Emulation  (Эмуля-
        ция)  меню OptionsіCompiler (ПараметрыіКомпилятор).  По умолчанию
        используется состояние {$E+}.  В этом состоянии в программу авто-
        матически включается полная эмуляция сопроцессора 8087. В состоя-
        нии {$E-} используется существенно  меньшая  часть  библиотеки  с
        плавающей точкой, а полученный в результате файл .EXE будет рабо-
        тать только на машинах с сопроцессором 8087.

             В приложении  Windows директива компилятора $E не действует.
        Не действует она также в модуле.  Более того, если программа ком-
        пилировалась с директивой {$N-},  а все модули программы компили-
        ровались с директивой {$N+},  то библиотека  исполняющей  системы
        для  сопроцессора  8087 не требуется,  и директива компилятора $E
        игнорируется.

             Прикладной программе Windows не требуется библиотека  испол-
        няющей системы 80x87. Вместо этого ей нужно поддерживающая библи-
        отека WIN87EM.DLL,  поставляемая с Windows,  которая обеспечивает
        необходимый интерфейс между вашей прикладной программой,  Windows
        и сопроцессором.  Таким образом, в Windows даже при наличии в ва-
        шей системе сопроцессора 80х87 для выполнения программ, скомпили-
        рованных в состоянии {$N+}, должна присутствовать библиотека эму-
        ляции WIN87EM.DLL  (данная  библиотека - это часть Windows,  а не
        Borland Pascal).  При отсутствии сопроцессора  WIN87EM.DLL  будет
        эмулировать его операции программным путем,  что замедляет выпол-
        нение программы и не гарантирует,  что  использующая  сопроцессор
        80x87 программа сможет работать на любой машине.


         B.Pascal 7 & Objects/LR     - 250 -

             Когда вы запускаете прикладную программу Windows,  cкомпили-
        рованную в состоянии {$N+}, убедитесь, что она может найти в сис-
        теме файл WIN87EM.DLL.

             Когда вы выполняете компиляцию в режиме кода 80х87 (директи-
        ва {$N+}),  то возвращаемые подпрограммы модуля Systем (Sqrt, Рi,
        Sin и т.д.) значения представляют собой не вещественные числа,  а
        числа типа Extended (с повышенной точностью).

               {$N+}

               begin
                 Writeln(Pi);                 { 3.14159265358979E+0000 }
               end.

               {$N-}

               begin
                 Writeln(Pi);                 { 3.1415926536E+00 }
               end.

             В оставшейся части данной главы обсуждаются специальные воп-
        росы,  касающиеся  использования  процессора  80x87  в программах
        Borland Pascal.



         B.Pascal 7 & Objects/LR     - 251 -

                          Типы данных процессора 80x87
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В дополнение к вещественному типу для программ, использующих
        средства процессора 80x87, предусматривается четыре новых вещест-
        венного типа:

             1.  Тип с одинарной точностью Single,  представляющий  собой
                 наименьший  формат,  который  вы можете использовать для
                 чисел с плавающей точкой.  Он занимает  4  байта  памяти
                 обеспечивает  диапазон представления чисел от 1.5х10^-45
                 до 3.4х10^48 с 7-8 значащими цифрами.

             2.  Тип с двойной точностью Double, занимающий 8 байт памяти
                 и  обеспечивающий  представление  чисел  в  диапазоне от
                 5.0х10^-334 до 1.7х10^308 с 15-16 значащими цифрами.

             3.  Тип с повышенной точностью Extended  представляет  собой
                 наибольший  формат представления чисел с плавающей запя-
                 той,  обеспечиваемый процессором 8087.  Он  занимает  10
                 байт памяти и обеспечивает диапазон  представления чисел
                 от  1.9х10^-4952 до 1.1х10^4932 с 19-20 значащими цифра-
                 ми.  Любые арифметические операции,  в которых участвуют
                 числа вещественного типа, выполняются с точностью и диа-
                 пазоном представления,  соответствующими типу с повышен-
                 ной точностью.

             4.  Числа сложного типа Comp используются для предварительно
                 объединенных значений в 8 байтах памяти, обеспечивая при
                 этом диапазон представления от -2^63+1  до  2^63-1,  что
                 составляет  приблизительно  от  -9.2х10^18 до 9.2х10^18.
                 Сложный тип можно сравнить с длинным целым типом  (двой-
                 ная точность),  но он считается вещественным типом, пос-
                 кольку при операциях с числами этого  типа  используется
                 сопроцессор 8087. Сложный тип хорошо подходит для предс-
                 тавления значений денежных единиц,  представляющих собой
                 сотни  и тысячи,  которые используются в прикладных ком-
                 мерческих программах.

             Независимо от того,  используете вы  сопроцессор  80x87  или
        нет,  6-битовый вещественный тип является допустимым. Таким обра-
        зом, при переходе к использованию сопроцессора 80 x87 вам не пот-
        ребуется изменять исходный текст программы, и вы можете использо-
        вать файлы данных,  созданные  программами,  которые  работают  с
        программно обеспечиваемыми операциями с плавающей точкой.

             Отметим, однако, что аппаратные вычисления с переменными ве-
        щественного типа выполняются несколько медленнее,  чем с перемен-
        ными  другого типа.  Это связано с тем,  что сопроцессор 80x87 не
        может непосредственно обрабатывать  вещественный  формат.  Вместо
        этого,  перед выполнением операций, для преобразования веществен-
        ных значений в числа с повышенной точностью требуются обращения к
        библиотечным  программам.  Если  вы заинтересованы в максимальной

         B.Pascal 7 & Objects/LR     - 252 -

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

                 Арифметические операции с повышенной точностью
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

              {$N+}
              var
                X, AA, B, C : real;
              begin
                X := (B + Sqrt(B*B - A*C))/A;
              end;

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

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

             var
               Sm : single;
               X,Y array[1..100] of single;
               I : integer;
               T : extended;            { для промежуточных результатов }
             begin
               T := 0.0;
               for I := 1 to 100 do T := T + X[I] * Y[I]
               Sum := T;
             end;

             Если бы переменная T была описана,  как переменная с одинар-
        ной точностью,  то при каждом цикле операции присваивания для пе-
        ременной  T были бы выполнены с ошибкой округления и ограничения-
        ми, соответствующими одинарной точности. Но, поскольку переменная

         B.Pascal 7 & Objects/LR     - 253 -

        T  является переменной с повышенной точностью,  то все ошибки ок-
        ругления (кроме операции, при которой значение переменной T прис-
        ваивается переменной Suм) имеют ограничения,  соответствующие по-
        вышенной точности.  Меньшие ошибки округления означают более точ-
        ный результат.

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

             function Area(Radius: extended): extended;
             begin
               Area := Pi * Radius * Radius;
             end;

                          Сравнение вещественных чисел
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Поскольку значения вещественного типа являются приблизитель-
        ными,  результат сравнения значений различного вещественного типа
        не  всегда можно предсказать.  Например,  если Х - переменная ве-
        щественного типа с одинарной точностью,  а Y - переменная вещест-
        венного типа с двойной точностью,  то результатом выполнения сле-
        дующих операторов будет значение False:

             X := 1/3;
             Y := 1/3;
             Writeln(X = Y);

             Причина этого состоит в том,  что Х имеет точность только до
        7-8 цифр, а Y - точность до 15-16 цифр, и когда оба значения пре-
        образуются к типу с повышенной точностью,  то  после  первых  7-8
        цифр остальные цифры будут различаться.  Аналогично,  результатом
        выполнения операторов:

             X := 1/3;
             Writeln(X = 1/3);

        будет значение False,  результат 1/3 в операторе Writeln вычисля-
        ется с точностью до 20 значащих цифр.


                       Стек вычислений сопроцессора 80x87
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             У сопроцессора 80x87 имеется внутренний стек вычислений, ко-
        торый  может быть глубиной до восьми уровней.  Доступ к значению,
        находящемуся в стеке сопроцессора  80x87  осуществляется  намного
        быстрее, чем доступ к переменной в памяти, поэтому для достижения
        максимально возможной производительности в Borland  Pascal  внут-
        ренний  стек сопроцессора 80x87 используется для хранения времен-
        ных результатов и для передачи параметров процедурам и функциям.

         B.Pascal 7 & Objects/LR     - 254 -


             Теоретически, слишком сложные выражения  вещественного  типа
        могут вызвать переполнение стека сопроцессора 80x87. Однако этого
        не может случиться, поскольку для этого потребовалось бы, чтобы в
        выражении получалось более восьми промежуточных результатов.

             Более весомая опасность таится во вложенных вызовах функций.
        Если такие конструкции составлены некорректно, то они, вполне ве-
        роятно, могут привести к переполнению стека сопроцессора 80x87.

             Рассмотрим, следующую функцию,  в которой с помощью рекурсии
        вычисляются числа Фибоначчи:

             function Fib(N: integer): extended;
             begin
               if N = 0 then
                  Fib := 0.0
               else
                 if N = 1 then
                    Fib := 1.0
                 else
               Fib := Fib(N-1) + Fib(N-2);
             end;

             Обращение к  данной версии процедуры Fib приведет к перепол-
        нению стека сопроцессора 80x87, так как значений N больше, чем 8.
        Причина  заключается  в том,  что последний оператор присваивания
        требует временного сохранения результата выполнения процедуры Fib
        (N-1)  в  стеке сопроцессора 80x87.  Каждое рекурсивное обращение
        выделяется одна ячейка стека и на  девятом  обращении  произойдет
        переполнение стека. Корректной конструкцией в этом случае будет:

             function Fib(N : integer) : extended;
             var
               F1,F2 : Extended;
             begin
               if N = 0 then
                      Fib := 0.0
                  else
                    if N = 1
                       then Fib := 1.0
                    else
                      begin
                         F1 := Fib(N-1); F2 := Fib(N-2);
                         Fib := F1 + F2;
                      end;
             end;

             Временные результаты  теперь  сохраняются в переменных,  для
        которых отводится стек процессора 8086. (Стек процессора 8086 ко-
        нечно  тоже  может  переполниться,  но это обычно требует гораздо
        большего числа рекурсивных вызовов).


         B.Pascal 7 & Objects/LR     - 255 -

                            Запись вещественных чисел
                      при использовании сопроцессора 80x87
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Если была указана директива {$N+},  то стандартные процедуры
        Write и Writeln, чтобы обеспечить представление в расширенном ди-
        апазоне,  выводят в строке с десятичными числами с плавающей точ-
        кой четыре цифры для показателя степени вместо двух.  Аналогично,
        стандартная процедура Str при выборе формата с  плавающей  точкой
        возвращает  значение  показателя  степени,  состоящее  из четырех
        цифр.


                Модули, в которых используется сопроцессор 80x87
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модули, в которых используется сопроцессор 80x87,  могут вы-
        зываться другими модулями или программами только  в  том  случае,
        если  эти  модули  или программы были скомпилированы с директивой
        {$N+}.  То, что модуль использует сопроцессор 80x87, определяется
        наличием в нем инструкций сопроцессора 80x87,  а не директивой $N
        во время компиляции.  Это позволяет компилятору быть более "снис-
        ходительным",  когда  вы  случайно компилируете модуль (в котором
        используется сопроцессор 80x87), не указав директиву {$N+}.

             Когда вы выполняете компиляцию в режиме кода 80х87 (директи-
        ва  {$N+}),  то  возвращаемые подпрограммами модуля Systем (Sqrt,
        Рi,  Sin и т.д.) значения представляют собой не вещественные чис-
        ла, а числа типа Extended (с повышенной точностью).




         B.Pascal 7 & Objects/LR     - 256 -

                Распознавание сопроцессора 80х87 в программах DOS
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Исполняющая библиотека Borland  Pascal,  встроенная  в  вашу
        программу  (скомпилированную  с директивой {$N+}) включает в себя
        код инициализации,  который автоматически  распознает  наличие  в
        системе микросхемы сопроцессора 8087.  Если сопроцессор 8087 име-
        ется, то программа будет его автоматически использовать. В случае
        же его отсутствия программа будет использовать эмулирующую библи-
        отеку исполняющей системы.  Если программа компилировалась с  ди-
        рективой {$E-} и по время начала ее работы сопроцессор не обнару-
        живается,  то программа завершает  работу  с  сообщением  Numeric
        coprocessor  required  ("Требуется сопроцессор арифметических вы-
        числений").

             Есть несколько случаев,  когда вы возможно захотите изменить
        такую принятую  по  умолчанию  логику автоматического обнаружения
        сопроцессора. Например, в вашей системе может присутствовать соп-
        роцессор 8087, но вы захотите проверить, как будет работать прог-
        рамма,  предназначенная для функционирования на системах без соп-
        роцессора.   Или  же  потребуется  запустить  вашу  программу  на
        системе, совместимой с компьютером РС, но на этой системе при ра-
        боте  алгоритма автообнаружения будет выводиться некорректная ин-
        формация (например, будет сообщаться о наличие сопроцессора, ког-
        да на самом деле его нет, или наоборот).

             В Borland  Pascal  предусмотрена возможность отмены принятой
        по умолчанию логики автоматического  распознавания.  Эта  возмож-
        ность задается переменной операционной среды 87.

             Вы можете  установить переменную операционной среды 87 в от-
        вет на подсказку DOS с помощью команды SET,  например,  следующим
        образом:

             SET 87=Y
        или
             SET 87=N

             Установка для  переменной  операционной  среды 87 значения N
        (Нет) указывает коду инициализации, что вы не хотите использовать
        сопроцессор 8087, хотя он может и присутствовать в системе. И на-
        оборот: установка для переменной 87 значения Y (Да) означает, что
        сопроцессор имеется,  и вы хотите,  чтобы ваша программа его  ис-
        пользовала.  Однако  при этом нужно помнить о том,  что установка
        для переменной 87 значения Y при отсутствии в системе сопроцессо-
        ра 8087 приведет к тому, что ваша программа аварийно завершит ра-
        боту или "зависнет".

             Если переменная операционной среды 87 определена, а вы хоти-
        те,  чтобы она стала неопределенной,  то можно ввести в ответ  на
        подсказку DOS:

             SET 87=

         B.Pascal 7 & Objects/LR     - 257 -


        и нажать клавишу Enter.

             Если в  операционной среде DOS присутствует запись 87=Y, или
        если код инициализации успешно распознает сопроцессор,  то  далее
        код  инициализации выполняет последующие проверки,  чтобы опреде-
        лить,  какой это сопроцессор (8087, 80287 или 80387). Это необхо-
        димо  для того,  чтобы Турбо Паскаль мог корректно работать с от-
        дельными несовместимостями,  которые имеются между сопроцессорами
        различных типов.

             Результат автоматического распознавания наличия сопроцессора
        и его модели сохраняется в переменной Test8087 (которая  описыва-
        ется в модуле System). Для нее определены следующие значения:

               ЪДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
               і  Значение    і   Определение                  і
               ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
               і       0      і   сопроцессор не обнаружен     і
               і       1      і   обнаружен сопроцессор 8087   і
               і       2      і   обнаружен сопроцессор 80287  і
               і       3      і   обнаружен сопроцессор 80387  і
               АДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

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


              Распознавание сопроцессора 80x87 в программе Windows
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Операционная среда Windows и библиотека эмуляции WIN87EM.DLL
        автоматически  распознает  наличие  в  системе платы сопроцессора
        80x87. Если сопроцессор 80x87 имеется, то программа будет его ав-
        томатически  использовать.  В  случае же его отсутствия программа
        будет использовать эмуляцию с помощью WIn87EM.DLL.  Чтобы опреде-
        лить наличие в системе сопроцессора 80х87, вы можете использовать
        функцию GetWinFlags (которая определена в модуле WinProcs) и  би-
        товую маску wf_80x87 (определенную в модуле WinTypes). Например:

             if GetWinFlags and wf_80x87 <> 0 then
                 Writeln('80x87 присутствует') else
                 Writeln('80x87 отсутствует');




         B.Pascal 7 & Objects/LR     - 258 -

                             Использование эмуляции
                     сопроцессора 80x87 на языке ассемблера
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Когда компоновка объектных файлов выполняется  с  директивой
        {$L имя_файла}, необходимо обеспечить, чтобы эти файлы компилиро-
        вать с разрешением эмуляции сопроцессора 80x87. Например, если вы
        используете инструкции сопроцессора 80x87 во  внешних  процедурах
        на языке ассемблера,  необходимо убедиться, что при ассемблирова-
        нии файлов .ASM в файлы .OBJ эмуляция разрешена. В противном слу-
        чае инструкции сопроцессора 80x87 не могут эмулироваться на маши-
        нах без сопроцессора 80x87.  Для разрешения эмуляции  используйте
        параметр командной строки Турбо Ассемблера /E.



         B.Pascal 7 & Objects/LR     - 259 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                              Глава 16. Модуль Dоs
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             С помощью модулей Dos и WinDos реализуется целый  ряд  прог-
        рамм операционной системы и программ обработки файлов. Ни одна из
        программ модуля Dos не определена в стандартном Паскале,  поэтому
        они помещаются в отдельный модуль.

             Более полное  описание операций DOS приведено в руководствах
        по DOS фирмы IBM.

             Основное различие модулей Dos и WinDos состоит  в  том,  что
        процедуры и функции модуля Dos используют стандартные строки Пас-
        каля, а процедуры и функции модуля WinDos - строки с  завершающим
        нулем. Стандартная  строка  Паскаля - это байт длины,  за которым
        следует последовательность символов. Строка с завершающим нулем -
        это последовательность  ненулевых символов с завершающим символом
        NULL (#0).

                   Примечание: Подробнее о различии этих строк  рассказы-
              вается в Главе 18.

             Если вы разрабатываете только программы Windows, используйте
        модуль WinDos.

             Если вы разрабатываете только программы DOS,  то  желательно
        пользоваться в программах модулем Dos,  так как большинство прог-
        рамм Паскаля традиционно работают со  строками  Паскаля.  Однако,
        если вы  разрабатываете  приложения для среды Windows,  то можете
        написать программу,  используемую в  обеих  платформах  -  DOS  и
        Windows, применяя для этого модули WinDos и Strings. Windows тре-
        бует использования строк с завершающим  нулем.  Вы  можете  также
        воспользоваться данными модулями, если у вас есть файл данных Си,
        и вы хотите его конвертировать.  В языке Си используются строки с
        завершающим нулем.



         B.Pascal 7 & Objects/LR     - 260 -

                         Процедуры и функции модуля Dos
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Ниже перечислены процедуры и функции модуля Dos.  Чтобы  ис-
        пользовать их, вы должны ссылаться на модуль Dos с помощью опера-
        тора программы uses.  См. также Главу 1 ("Справочник по библиоте-
        ке") в "Руководстве программиста".

                     Процедуры для работы с датой и временем
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і     Процедура    і        Описание                            і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetDate        і Возвращает текущую  дату,  установленную  ві
        і                  і операционной системе.                      і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetFTime       і Возвращает дату  и  время  последней записиі
        і                  і файла.                                     і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetTiме        і Возвращает текущее время,  установленное  ві
        і                  і операционной системе.                      і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   РackTiме       і Преобразует запись DateTiме в четырехбайто-і
        і                  і вое  упакованное  символьное  представлениеі
        і                  і даты и времени длинного целого типа,  кото-і
        і                  і рое используется в процедуре  SetTiме. Поляі
        і                  і записи  DateTiме не проверяются на допусти-і
        і                  і мость границ.                              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetDate        і Устанавливает для операционной системы  те-і
        і                  і кущую дату.                                і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetFTiме       і Устанавливает время и дату последней записиі
        і                  і файла.                                     і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetTiме        і Устанавливает в операционной системе  теку-і
        і                  і щее время.                                 і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   UnpackTiме     і Преобразует четырехбайтовое     упакованнойі
        і                  і символьное  представление  даты  и  времениі
        і                  і длинного целого типа,  возвращаемого проце-і
        і                  і дурами GetFTiме, FindFirst, FindNext в рас-і
        і                  і пакованную запись DateTiме.                і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                   Процедуры и функции обслуживания прерываний
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і   Процедура      і      Описание                              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    GetIntVес     і Возвращает адрес,  сохраненный  в  заданномі
        і                  і векторе прерываний.                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Intr          і Выполняет заданное  программное прерывание.і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ

         B.Pascal 7 & Objects/LR     - 261 -

        і    МsDos         і Выполняет вызов функции DOS.               і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    SetIntVес     і Устанавливает по  заданному адресу заданныйі
        і                  і вектор прерывания.                         і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                      Функции, проверяющие состояние диска
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і   Фуннкция       і       Описание                             і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    DiskFrее      і Возвращает число  свободных байт на диске ві
        і                  і заданном дисководе.                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    DiskSize      і Возвращает полный объем в  байтах заданногоі
        і                  і диска.                                     і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                           Процедуры обработки файлов
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і   Процедура      і      Описание                              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FExpand        і Воспринимает имя файла и  возвращает полноеі
        і                  і уточненное имя (диск, каталог, расширение).і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FSearch        і Ищет файл в списке каталогов.              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FindFirst      і Производит поиск в заданном  (или  текущем)і
        і                  і каталоге записи,  содержимое которой совпа-і
        і                  і дает с заданным именем файла  и атрибутами.і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FindNext       і Возвращает следующую запись,  имя  файла  иі
        і                  і атрибуты в которой совпадают с теми,  кото-і
        і                  і рые были заданы при предыдущем  обращении кі
        і                  і процедуре FindFirst.                       і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetFAttr       і Возвращает атрибуты файла.                 і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetFAttr       і Устанавливает атрибуты файла.              і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                     Функции управления операционной средой
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і      Функция     і         Описание                           і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і     EnvCount     і Возвращает число строк, содержащихся в опе-і
        і                  і рационной среде DOS.                       і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і     EnvStr       і Возвращает заданную   строку   операционнойі
        і                  і среды.                                     і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і     GetEnv       і Возвращает значение   заданной   переменнойі
        і                  і операционной среды.                        і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

         B.Pascal 7 & Objects/LR     - 262 -


                         Процедуры управления процессами
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і      Процедура   і         Описание                           і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Eхесutе       і Выполняет заданную  программу  с  указаннойі
        і                  і командной строкой.                         і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Keep          і Сохраняет (прекращает выполнение и сохраня-і
        і                  і ет в памяти) прекратившую работу программу,і
        і                  і оставляя ее резидентной в памяти.          і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    SwapVectors   і Меняет местами  содержимое сохраненных век-і
        і                  і торов прерываний и текущих векторов.       і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                           Прочие процедуры и функции
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        іПроцедура/функция і          Описание                          і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   DosVersion     і Возвращает номер версии операционной систе-і
        і                  і мы DOS.                                    і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetCBreak      і Возвращает проверяемое    DOS     состояниеі
        і                  і Ctrl+Break.                                і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetCBreak      і Устанавливает проверяемое   DOS   состояниеі
        і                  і Ctrl+Break.                                і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetVerify      і Возвращает состояние флага проверки в DOS. і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetVerify      і Устанавливает состояние  флага  проверки  ві
        і                  і DOS.                                       і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 263 -

                     Константы, типы и переменные модуля Dos
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В данном разделе кратко обсуждаются константы,  типы и пере-
        менные, определяемые в модуле Dos. Более детальная информация со-
        держится в разделе "Константы флагов" (значение FParity) в  Главе
        1  ("Справочник по библиотеке") "Справочного руководства програм-
        миста".

                                 Группы констант
        ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Группа констант         і        Описание                  і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Флаги                   і Используются для проверки отдель-і
        і                            і ных флагов после  вызова  функцийі
        і                            і Intr   или  MsDos.   Это   флаги:і
        і                            і FParity,    FAuxiliary,    FZero,і
        і                            і FSign, FOverflow, fCarry.        і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    fmXXXX                  і Определяет  допустимые   значенияі
        і                            і поля Mode записи TextRec  тексто-і
        і                            і вого  файла:  fmClosed,  fmInput,і
        і                            і fmOutput, fmInOut.               і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Атрибуты файла          і Используются для  построения  ат-і
        і                            і рибутов, применяемых в FindFirst,і
        і                            і GetFAttr и  SetFAttr.  Это  флагиі
        і                            і ReadOnly,     Hidden,    SysFile,і
        і                            і VolumeID,   Directory,   Archive,і
        і                            і AnyFile.                         і
        АДДДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                                      Типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В модуле Dos определяются следующие типы:

        ЪДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Тип                   і        Описание                    і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Тип записи файла       і Определения  записей, использующие-і
        і                          і ся в  Borland Pascal для внутреннихі
        і                          і целей,  описываются также в  модулеі
        і                          і Dos.  Тип  FilеRес используется какі
        і                          і для типизованных, так и для нетипи-і
        і                          і зованных  файлов,  в то время,  какі
        і                          і TехtRес представляет собой внутрен-і
        і                          і ний  формат  переменной  текстовогоі
        і                          і типа.                              і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Registers              і Переменные регистрового типа приме-і
        і                          і няются в  процедурах  Intr  и МsDosі
        і                          і для  задания  содержимого  входногоі

         B.Pascal 7 & Objects/LR     - 264 -

        і                          і регистра и проверки содержимого вы-і
        і                          і ходного регистра  при  прерываниях,і
        і                          і использующихся  в программном обес-і
        і                          і печении.                           і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   DateTime               і Переменные типа  DateTiме  (даты  иі
        і                          і времени) используются  в процедурахі
        і                          і UnраскТiме и РаскТiме для  анализа,і
        і                          і упаковки и построения четырехбайто-і
        і                          і вого значения,  содержащего дату  иі
        і                          і время. Это четырехбайтовое значениеі
        і                          і используется  затем  в   процедурахі
        і                          і GetFTiме,   SetTiме,   FindFirst  иі
        і                          і FindNехt.                          і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SearchRec              і Переменные типа SearchRес использу-і
        і                          і ются в   процедурах   FindFirst   иі
        і                          і Findnext  для  просмотра  каталогові
        і                          і файлов.                            і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Строковые типы         і Эти строковые типы определены в мо-і
        і   работы с файлами       і дуле Dos и используются для  работыі
        і                          і с именами  файлов  и  маршрутов приі
        і                          і вызове строковой процедуры  FSplit.і
        і                          і Это типы ComStr,  PathStr,  DirStr,і
        і                          і NameStr, ExtStr.                   і
        АДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                              Переменные модуля Dos
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Многими подпрограммами  модуля  Dos  для сообщения об ошибке
        используется переменная DosError.



         B.Pascal 7 & Objects/LR     - 265 -

                        Процедуры и функции модуля WinDos
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

              Процедуры для работы с датой и временем модуля WinDos
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і     Процедура    і        Описание                            і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetDate        і Возвращает текущую  дату,  установленную  ві
        і                  і операционной системе.                      і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetFTime       і Возвращает дату  и  время  последней записиі
        і                  і файла.                                     і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetTiме        і Возвращает текущее время,  установленное  ві
        і                  і операционной системе.                      і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   РackTiме       і Преобразует запись DateTiме в четырехбайто-і
        і                  і вое  упакованное  символьное  представлениеі
        і                  і даты и времени длинного целого типа,  кото-і
        і                  і рое используется в процедуре  SetTiме.     і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetDate        і Устанавливает для операционной системы  те-і
        і                  і кущую дату.                                і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetFTiме       і Устанавливает время и дату последней записиі
        і                  і файла.                                     і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetTiме        і Устанавливает в операционной системе  теку-і
        і                  і щее время.                                 і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   UnpackTiме     і Преобразует четырехбайтовое     упакованнойі
        і                  і символьное  представление  даты  и  времениі
        і                  і длинного целого типа,  возвращаемого проце-і
        і                  і дурами GetFTiме, FindFirst, FindNext в рас-і
        і                  і пакованную запись DateTiме.                і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                 Процедуры обслуживания прерываний модуля WinDos
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і   Процедура      і      Описание                              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    GetIntVес     і Возвращает адрес,  сохраненный  в  заданномі
        і                  і векторе прерываний.                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Intr          і Выполняет заданное  программное прерывание.і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    МsDos         і Выполняет вызов функции DOS.               і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    SetIntVес     і Устанавливает по  заданному адресу заданныйі

         B.Pascal 7 & Objects/LR     - 266 -

        і                  і вектор прерывания.                         і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

               Функции модуля WinDos, проверяющие состояние диска
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і   Фуннкция       і       Описание                             і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    DiskFrее      і Возвращает число  свободных байт на диске ві
        і                  і заданном дисководе.                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    DiskSize      і Возвращает полный объем в  байтах заданногоі
        і                  і диска.                                     і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                    Процедуры работы с файлами модуля WinDos
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і   Процедура      і      Описание                              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FileExpand     і Воспринимает имя файла и  возвращает полноеі
        і                  і уточненное имя (диск, каталог, расширение).і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FileSearch     і Ищет файл в списке каталогов.              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FileSplit      і Разбивает полное имя файла на три компонен-і
        і                  і та (диск, каталог, имя и расширение).      і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FindFirst      і Производит поиск в заданном  (или  текущем)і
        і                  і каталоге записи,  содержимое которой совпа-і
        і                  і дает с заданным именем файла  и атрибутами.і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FindNext       і Возвращает следующую запись,  имя  файла  иі
        і                  і атрибуты в которой совпадают с теми,  кото-і
        і                  і рые были заданы при предыдущем  обращении кі
        і                  і процедуре FindFirst.                       і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetFAttr       і Возвращает атрибуты файла.                 і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetFAttr       і Устанавливает атрибуты файла.              і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                  Процедуры  и функции для работы с каталогами
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і Процедура/функцияі          Описание                          і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    CreateDir     і Создает новый подкаталог.                  і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    GetCurDir     і Возвращает текущий каталог на заданном дис-і
        і                  і ке.                                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    RemoveDir     і Удаляет подкаталог.                        і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    SetCurDir     і Изменяет текущий каталог.                  і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

         B.Pascal 7 & Objects/LR     - 267 -


            Процедуры и функции обслуживания прерываний модуля WinDos
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і   Процедура      і      Описание                              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    GetArgCount   і Возвращает   число  параметров,  переданныхі
        і                  і программе в командной строке.              і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    GetArgStr     і Возвращает   заданный   аргумент  команднойі
        і                  і строки.                                    і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    GetEnvVar     і Возвращает указатель на  значение  заданнойі
        і                  і переменной операционной среды.             і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                    Прочие процедуры и функции модуля WinDos
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        іПроцедура/функция і          Описание                          і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   DosVersion     і Возвращает номер версии операционной систе-і
        і                  і мы DOS.                                    і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetCBreak      і Возвращает проверяемое    DOS     состояниеі
        і                  і Ctrl+Break.                                і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetCBreak      і Устанавливает проверяемое   DOS   состояниеі
        і                  і Ctrl+Break.                                і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetVerify      і Устанавливает состояние  флага  проверки  ві
        і                  і DOS.                                       і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 268 -

                   Константы, типы и переменные модуля WinDos
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В данном разделе кратко обсуждаются константы,  типы и пере-
        менные,  определяемые в модуле WinDos. Более детальная информация
        содержится в разделе "Константы флагов" (значение FParity) в Гла-
        ве 1 ("Справочник по библиотеке") "Справочного руководства  прог-
        раммиста".

                                 Группы констант
        ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Группа констант         і        Описание                  і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Флаги                   і Используются для проверки отдель-і
        і                            і ных флагов после  вызова  функцийі
        і                            і Intr   или  MsDos.   Это   флаги:і
        і                            і FParity,    FAuxiliary,    FZero,і
        і                            і FSign, FOverflow, fCarry.        і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    fmXXXX                  і Определяет  допустимые   значенияі
        і                            і поля Mode записи TextRec  тексто-і
        і                            і вого  файла:  fmClosed,  fmInput,і
        і                            і fmOutput, fmInOut.               і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    faXXXX                  і Используются для  построения  ат-і
        і                            і рибутов, их проверки и  измененияі
        і                            і в процедурах и функциях работы  сі
        і                            і файлами. Это константы  faHidden,і
        і                            і faSysFile, faVolumeID, faDirecto-і
        і                            і ry, faArchive, faAnyFile.        і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    fsXXXX                  і Максимальные   длины  компонентові
        і                            і имени файла, используемых в  под-і
        і                            і программах   FileSearch  и  File-і
        і                            і Expand. Это  константы: fsPathNa-і
        і                            і me,    fsDirectory,   fsFileName,і
        і                            і fsExtension.                     і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    fcXXXX                  і Флаги,   возвращаемые    функциейі
        і                            і FileSplit:  fcExtension,  fcFile-і
        і                            і Name, fcDirectory, fcWildcards.  і
        АДДДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 269 -

                                      Типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В модуле WinDos определяются следующие типы:

        ЪДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і         Тип              і             Описание               і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Тип записи файла       і Определения  записей, использующие-і
        і                          і ся в  Borland Pascal для внутреннихі
        і                          і целей,  описываются также в  модулеі
        і                          і Dos.  Тип TFilеRес используется какі
        і                          і для типизованных, так и для нетипи-і
        і                          і зированных файлов, в то время,  какі
        і                          і TTехtRес представляет  собой  внут-і
        і                          і ренний формат переменной текстовогоі
        і                          і типа.                              і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   TRegisters             і Переменные регистрового типа приме-і
        і                          і няются в  процедурах  Intr  и МsDosі
        і                          і для  задания  содержимого  входногоі
        і                          і регистра и проверки содержимого вы-і
        і                          і ходного регистра  при  прерываниях,і
        і                          і использующихся  в программном обес-і
        і                          і печении.                           і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   TDateTime              і Переменные типа TDateTiме  (даты  иі
        і                          і времени) используются  в процедурахі
        і                          і UnраскТiме и PаскТiме для  анализа,і
        і                          і упаковки и построения четырехбайто-і
        і                          і вого значения,  содержащего дату  иі
        і                          і время. Это четырехбайтовое значениеі
        і                          і используется  затем  в   процедурахі
        і                          і GetFTiме,   SetTiме,   FindFirst  иі
        і                          і FindNехt.                          і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   TSearchRec             і Переменные типа TSearchRес  исполь-і
        і                          і зуются в  процедурах  FindFirst   иі
        і                          і Findnext  для  просмотра  каталогові
        і                          і файлов.                            і
        АДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                            Переменные модуля WinDos
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Многими подпрограммами модуля WinDos для сообщения об ошибке
        используется переменная DosError.



         B.Pascal 7 & Objects/LR     - 270 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
               Глава 17. Программирование в защищенном режиме DOS
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Микропроцессор 80286 дает новый способ адресации  к  памяти:
        защищенный режим  виртуальной адресации или просто защищенный ре-
        жим. Этот новый режим адресации дает три основных преимущества:

             * Адресация к памяти объемом до 16 мегабайт.

             * Логическое адресное пространство, превышающее пространство
               физических адресов.

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

             С помощью Borland Pascal вы легко можете писать работающие в
        защищенном режиме прикладные программы DOS без необходимости при-
        менения дополнительного  "расширителя"  DOS.  Вы обнаружите,  что
        многие программы реального режима прекрасно работают в защищенном
        режиме. Данная глава поможет вам модифицировать те программы, ко-
        торые этого не делают,  и прояснит некоторые основные моменты за-
        щищенного режима и его отличия от реального режима.

                           Что такое защищенный режим?
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Процессор 80286 и более поздние процессоры поддерживают  два
        режима операций:  защищенный режим и реальный режим. Реальный ре-
        жим совместим с работой процессора 8086  и  позволяет  прикладной
        программе адресоваться к памяти объемом до одного мегабайта.  За-
        щищенный режим расширяет диапазон адресации до 16  мегабайт.  Ос-
        новное отличие  между реальным и защищенным режимом заключается в
        способе преобразования процессором логических адресов в  физичес-
        кие. Логические  адреса  - это адреса,  используемые в прикладной
        программе. Как в реальном, также и в защищенном режиме логический
        адрес  - это 32-разрядное значение,  состоящее из 16-битового се-
        лектора (адреса сегмента) и 16-битового смещения.  Физические ад-
        реса - это адреса, которые процессор использует для обмена данны-
        ми с компонентами системной памяти.  В реальном режиме физический
        адрес представляет собой 20-битовое значение,  а в защищенном ре-
        жиме - 24-битовое.


         B.Pascal 7 & Objects/LR     - 271 -


             Когда процессор обращается к памяти (для выборки  инструкции
        или записи переменной), он генерирует из логического адреса физи-
        ческий адрес. В реальном режиме генерация физического адреса сос-
        тоит из  сдвига  селектора (адреса сегмента) на 4 бита влево (это
        означает умножение на 16) и прибавления  смещения.  Полученный  в
        результате 20-разрядный  адрес  используется  затем для доступа к
        памяти.

                                    16МбЪДДДДДДДДДДДДДДДДї
                                        і                і
                          ЪДДДДДДДДї    і                і
                          іСмещениеГДї  і                і
                          АДДДДДДДДЩ і  і                і
                                     і  ГДДДДДДДДДДДДДДДДґї
                                     АДДЕДДДДД>±±±±±±±±±±іГ сегмент 64К
                                     ЪД>ГДДДДДДДДДДДДДДДДґЩ
                                     і  і                і
                                     і  і  Пространство  і
             ЪДДДДДДДДї ЪДДДДДДї     і  і    адресов     і
             іСелекторГДґ x 16 ГДДДДДЩ  і                і
             АДДДДДДДДЩ АДДДДДДЩ        і                і
                                       0АДДДДДДДДДДДДДДДДЩ


             Рис. 17.1 Генерация физического адреса в реальном режиме.


         B.Pascal 7 & Objects/LR     - 272 -


             Чтобы получить физический адрес в защищенном режиме,  селек-
        торная часть  логического  адреса используется в качестве индекса
        таблицы дескрипторов.  Запись  в  таблице  дескрипторов  содержит
        24-битовый базовый адрес,  к которому затем для образования физи-
        ческого адреса прибавляется смещение логического адреса.

                                    16МбЪДДДДДДДДДДДДДДДДї
                                        і                і
                          ЪДДДДДДДДї    і                і
                          іСмещениеГДї  і                і
                          АДДДДДДДДЩ і  і                і
                                     і  ГДДДДДДДДДДДДДДДДґї
                Таблица дескрипторов АДДЕДДДДД>±±±±±±±±±±іГ сегмент 64К
                          ЪДДДДДДї   ЪД>ГДДДДДДДДДДДДДДДДґЩ
                          ГДДДДДДґ   і  і                і
                          ГДДДДДДґ   і  і  Пространство  і
                          ГДДДДДДґ   і  і    адресов     і
                       ЪД>ГДДДДДДґДДДЩ  і                і
                       і  ГДДДДДДґ      і                і
                       і  ГДДДДДДґ     0АДДДДДДДДДДДДДДДДЩ
                       і  ГДДДДДДґ
                       і  ГДДДДДДґ
                       і  ГДДДДДДґ
                       і  ГДДДДДДґ
                       і  ГДДДДДДґ
                       і  ГДДДДДДґ
                       і  ГДДДДДДґ
                       і  ГДДДДДДґ
            ЪДДДДДДДДї і  ГДДДДДДґ
            іСелекторГДЩ  АДДДДДДЩ
            АДДДДДДДДЩ

             Рис. 17.2 Генерация физического адреса в защищенном режиме.

             Каждая запись в таблице дескрипторов называется дескриптором
        и определяет сегмент в памяти.  Запись таблицы дескрипторов зани-
        мает 8 байт, а записанная в дескрипторе информация включает в се-
        бя базовый адрес,  предельное значение и флаги полномочий доступа
        к сегменту.

             Записи предельного значения сегмента и полномочий доступа  в
        дескрипторе определяют  размер  и  тип  сегмента.  Сегменты могут
        иметь размер от 1 до 65536 байт и могут быть сегментами кода  или
        сегментами данных.  Сегменты кода могут содержать выполняемые ма-
        шинные инструкции и доступные только по  чтению  данные. Сегменты
        данных могут содержать данные,  доступные по чтению и записи. За-
        писывать данные в сегменты кода или выполнять инструкции  в  сег-
        ментах данных невозможно.  Любая попытка сделать это  или попытка
        доступа к данным вне границ  сегмента вызывает общий сбой по  на-
        рушению защиты  (сокращенно сбой GP).  Поэтому режим и называется
        защищенным.


         B.Pascal 7 & Objects/LR     - 273 -

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

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



         B.Pascal 7 & Objects/LR     - 274 -

                    Расширения Borland защищенного режима DOS
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Расширения защищенного режима Borland Pascal реализованы че-
        рез два компонента: DPMI-сервер (файл DPMI16BI.OVL) и администра-
        тор этапа выполнения (файл RTM.EXE).

                                   DPMI-сервер
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Интерфейс защищенного  режима  DOS  (DPMI)  - это отраслевой
        стандарт, позволяющий программам DOS аппаратно-независимым  путем
        получить  доступ  к  развитым средствам персональных компьютеров,
        реализованных на процессорах 80286,  80386  и  80486.  Определены
        функции DPMI  для обслуживания таблиц дескрипторов,  переключения
        режима, распределения расширенной памяти,  выделения памяти  DOS,
        управления подсистемой  прерываний и взаимодействия с программами
        реального режима.

             Расширения защищенного режима  Borland  Pascal  основаны  на
        спецификации DPMI 0.9. Хотя спецификация DPMI не поддерживает вы-
        зовы DOS из прикладных программ защищенного  режима,  DPMI-сервер
        Borland и  серверы  многих других фирм,  включая улучшенный режим
        Windows 3.x, поддерживают прерывание INT 21H и другие стандартные
        прерывания DOS и BIOS,  используемые обычно в приложениях DOS за-
        щищенного режима.

                         Администратор этапа выполнения
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Администратор этапа  выполнения (RTM.EXE) является надстрой-
        кой DPMI-сервера и обеспечивать для прикладных программ  защищен-
        ного режима несколько служебных функций.  Администратор этапа вы-
        полнения содержит загрузчик защищенного  режима  и  администратор
        памяти защищенного  режима  и  позволяет  под DPMI сосуществовать
        нескольким клиентам защищенного режима.

             Приложения защищенного режима Borland используют те же  фор-
        маты выполняемых файлов,  что и Windows 3.x и OS/2 1.x. Программ-
        ный загрузчик администратора этапа выполнения может загружать как
        выполняемые файлы (.EXE), так и динамически компонуемые библиоте-
        ки (.DLL).

             Администратор памяти защищенного режима позволяет прикладным
        программам защищенного режима распределять блоки динамической па-
        мяти. Администратор памяти поддерживает фиксированные, перемещае-
        мые и выгружаемые блоки,  а также обслуживает код и сегменты дан-
        ных прикладной программы.  Используя уникальные  для  защищенного
        режима средства,  администратор  памяти функционирует также в ка-
        честве администратора оверлеев, автоматически загружая и выгружая
        сегменты кода  (по  этой причине прикладной программе защищенного
        режима не требуется модуль Overlay).


         B.Pascal 7 & Objects/LR     - 275 -

             Прикладные программы могут получить доступ к программам  за-
        щищенного режима через модуль WinAPI.  Модуль WinAPI, описанный в
        следующем разделе, реализует подмножество функций API (прикладно-
        го  программного интерфейса) Windows,  обеспечивая управление па-
        мятью,  обслуживание программных модулей,  управление  ресурсами,
        загрузку  динамически компонуемых библиотек и доступ к селекторам
        на нижнем уровне.  Поскольку администратор этапа  выполнения  API
        является подмножеством API Windows,  вы можете написать совмести-
        мые на уровне двоичного кода динамически компонуемые  библиотеки,
        которые  можно  использовать  и  в  защищенном  режиме  DOS,  и в
        Windows.



         B.Pascal 7 & Objects/LR     - 276 -

              Разработка прикладных программ DOS защищенного режима
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Написание прикладной программы защищенного режима не  предс-
        тавляет собой сложной задачи.  Вам не нужно беспокоиться о селек-
        торах и  адресах  памяти.  Операционная  система  с  расширениями
        Borland все делает за вас. Фактически, большинство ваших программ
        реального режима может прекрасно работать в защищенном режиме.  В
        следующих разделах описывается некоторая разница между реальным и
        защищенным режимом,  о которых вы  должны  знать  при  разработке
        прикладной программы защищенного режима.


                  Надежное программирование в защищенном режиме
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Существует несколько приемов, используемых обычно в програм-
        мах реального режима, которые в программах защищенного режима бу-
        дут приводить к общему нарушению защиты (сбой GP). Borland Pascal
        при сбое GP выводит ошибку этапа выполнения 216. Сбой GP происхо-
        дит, когда вы пытаетесь получить доступ к памяти,  к которой ваша
        прикладная программа  обращаться  не может.  Операционная система
        останавливает прикладную  программу,  но сбоя системы не происхо-
        дит.  Хотя сбои GP и прекращают работу вашей  программы,  система
        "защищена" от сбоя. К сбою GP приводит следующее:

             * загрузка в сегментные регистры недопустимых значений;

             * обращение к памяти вне границы сегмента;

             * запись в сегмент кода;

             * разыменование указателей nil.

                   Примечание: Сбои по нарушению защиты предохраняют вашу
              систему от плохой практики программирования.



         B.Pascal 7 & Objects/LR     - 277 -

                              Загрузка в сегментные
                         регистры недопустимых значений
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Когда процессор работает в защищенном режиме, сегментные ре-
        гистры (CS,  DS,  ES и SS) могут содержать только селекторы. Пос-
        кольку селекторы являются индексами в таблице  дескрипторов,  они
        не имеют  физического  отношения к памяти,  на которую ссылается.
        Если вы пытаетесь загрузить  в  сегментный  регистр  произвольное
        значение, то  возможно  получите сбой GP,  поскольку это значение
        может не представлять допустимого дескриптора.

                            Функция Ptr и массивы Mem
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             При разыменовании указателей компилятор генерирует  код  для
        загрузки сегментного  регистра.  Если  вы строите указатели с по-
        мощью стандартной функции Ptr,  то нужно обеспечить,  чтобы  сег-
        ментная часть  указателя была допустимым селектором.  Аналогично,
        при работе с массивами Mem,  MemW и MemL вы вместо физических ад-
        ресов должны использоваться селекторы.  Например,  при доступе  к
        рабочей  области ROM BIOS (сегмент $0040) или к областям видеопа-
        мяти (сегменты $A000,  $B000 и $B800) следует использовать вместо
        абсолютных значений переменные SegXXXX.  (Переменные SegXXXX опи-
        сываются ниже.)

                              Абсолютные переменные
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В защищенном режиме вы не можете задавать  абсолютный  адрес
        переменной. Любой исходных код, где сегмент и смещение задаются в
        операторе absolute,  нужно переписать. Например, вам может потре-
        боваться построить указатель, используя переменные SegXXXX.



         B.Pascal 7 & Objects/LR     - 278 -

                              Операции с сегментами
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Добавление или вычитание значений из селекторной части  ука-
        зателя обычно не допускается.  Например, добавление к селекторной
        части указателя $1000 в реальном режиме увеличивает указатель  на
        64К, но  в защищенном режиме результирующий указатель будет недо-
        пустимым. Вместо этого для выделения и управления блоками  памяти
        следует использовать функцию GlobalXXXX модуля WinAPI.

             В Borland Pascal существует способ выполнения арифметических
        операций с селекторами с помощью переменной SelectorInc  (см. ни-
        же).

                             Использование сегментных
                    регистров в качестве временных переменных
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                       Доступ к памяти вне границ сегмента
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В реальном  режиме каждый сегмент имеет размер 64К.  В защи-
        щенном режиме дескриптор сегмента содержит поле,  специфицирующее
        предельный размер сегмента, и если вы пытаетесь обратиться к дан-
        ным вне границ сегмента,  по получите сбой GP. При загрузке прик-
        ладной программы администратор этапа выполнения устанавливает со-
        ответствующие предельные значения для сегментов  кода,  данных  и
        стека.  Кроме того, блок памяти, распределяемый с помощью функции
        GlobalAlloc модуля WinAPI,  имеет предельное  значение  сегмента,
        соответствующее размеру блока памяти.



         B.Pascal 7 & Objects/LR     - 279 -

                              Запись в сегмент кода
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В реальном  режиме можно записывать переменные в сегмент ко-
        да, поскольку реальные режим не определяет,  что может и  что  не
        может существовать  в  сегменте.  В защищенном режиме это не так.
        Селектор защищенного режима имеет флаг чтения/записи или  доступа
        только по чтению,  а селекторы кода всегда отмечены как доступные
        только по чтению. Если вы пытаетесь записывать в селектор сегмен-
        та кода,  происходит сбой GP. Однако вы можете использовать псев-
        доним и написать самомодифицирующийся код (см. ниже).

                          Разыменование указателей nil
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             При преобразовании  прикладной  программы реального режима в
        защищенный режим, в программе, которая уже годы работала без оши-
        бок,  возможно внезапное появление определенных ошибок. Например,
        вы можете случайно разыменовывать указатель nil,  или обнаружите,
        что ваша программа содержит "потерянные" указатели, которые разы-
        меновываются после их освобождения. В реальном режиме такие ошиб-
        ки не обязательно проявляются,  но в защищенном режиме они обычно
        приводят  к сбою GP.  Согласно своему названию,  защищенный режим
        значительно лучше предохраняет вас от ошибок,  связанных с указа-
        телями.

                             Сегменты кода и данных
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Аналогично программе Borland Pascal реального режима,  прог-
        рамма защищенного режима содержит несколько сегментов кода,  сег-
        мент данных  и сегмент стека.  При загрузке программы защищенного
        режима администратор этапа выполнения автоматически выделяет  се-
        лекторы для  сегментов кода,  данных и стека.  Для сегментов кода
        с помощью директивы компилятора $C можно управлять отдельными ат-
        рибутами. В частности,  сегменты кода можно сделать перемещаемыми
        или фиксированными в физической  памяти,  они  могут  загружаться
        предварительно или  по  запросу,  а также могут быть выгружаемыми
        или постоянными.

                   Примечание: Подробнее о директиве компилятора $C расс-
              казывается в Главе 21 данного руководства и в Главе 2 ("Ди-
              рективы компилятора") "Справочного руководства  программис-
              та".

             Атрибуты сегмента  кода позволяют вам обозначать сегмент как
        статический (перемещаемый,  предварительно загружаемый,  постоян-
        ный) или динамический (перемещаемый, загружаемый по запросу, выг-
        ружаемый). Таким образом,  в защищенном режиме вам не  нужно  ис-
        пользовать модуль Overlay и директиву компилятора $O,  и в версии
        модуля System для защищенного режима переменные OvrXXXXXX отсутс-
        твуют.


         B.Pascal 7 & Objects/LR     - 280 -

                  Управление динамически распределяемой памятью
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Администратор динамически  распределяемой   области   памяти
        Borland Pascal защищенного режима довольно существенно отличается
        от администратора  динамически  распределяемой   памяти   Borland
        Pascal реального   режима.   В   частности,  переменные  HeapOrg,
        HeapEnd, HeapPtr и FreeList в версии модуля System для защищенно-
        го режима  не определены.  Администратор этапа выполнения динами-
        чески распределяемой области памяти  Borland  Pascal  защищенного
        режима (который идентичен администратору этапа выполнения динами-
        чески распределяемой области памяти Borland Pascal  для  Windows)
        для выполнения  основных операций по выделению и освобождению па-
        мяти использует администратор этапа выполнения, а для оптимизации
        распределения небольших  блоков памяти включает в себя подсистему
        вторичного распределения сегмента.  Подробнее  об  администраторе
        динамически распределяемой  области памяти этапа выполнения расс-
        казывается в Главе 21.

                           Предопределенные селекторы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                           Предопределенные селекторы        Таблица 17.1
        ЪДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Селектор      і              Описание                      і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    Seg0040       і Используется для  доступа к области  данныхі
        і                  і BIOS $40 в младших адресах.                і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    SegA000       і Используется для  доступа к графической па-і
        і                  і мяти EGA и VGA по адресу сегмента $A000.   і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    SegB000       і Используется для  доступа к видеопамяти мо-і
        і                  і нохромного адаптера  по   адресу   сегментаі
        і                  і $A000.                                     і
        ГДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і    SegB800       і Используется   для  доступа  к  видеопамятиі
        і                  і цветного графического адаптера  по   адресуі
        і                  і сегмента $A000.                            і
        АДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             В реальном режиме переменные SegXXXX всегда содержат  значе-
        ния $0040,  $A000, $B000 и $B800 соответственно. В защищенном ре-
        жиме код запуска библиотеки исполняющей  системы  создает  четыре
        селектора, ссылающихся на конкретные области памяти реального ре-
        жима. При ссылке на эти области памяти вам  следует  использовать
        переменные SegXXXX. Например, если у вас был код следующего вида:

         B.Pascal 7 & Objects/LR     - 281 -


             CtrMode := Mem[$40: $49];

        то вместо него следует записать:

             CtrMode := Mem[Seg0040: $49];

             Используя переменные SegXXXX,  вы можете гарантировать,  что
        ваша программа без изменений будет работать в реальном и защищен-
        ном режимах.

                             Переменная SelectorInc
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Переменная SelectorInc модуля System содержит значение,  ко-
        торое должно  прибавляться к селектору или вычитаться из него для
        получения следующего или предыдущего селектора в таблице дескрип-
        торов. SelectorInc  полезно  использовать  при  работе с большими
        блоками памяти (превышающими 64К) и  при  доступе  к  псевдонимам
        сегментов.

             Для выделения блоков,  превышающих 64К (такие блоки называют
        также большими  блоками  памяти),  можно   использовать   функции
        GlobalAlloc и GlobalAllocPrt в модуле WinAPI.  Большие блоки неп-
        рерывны в физической памяти,  но из-за  16-разрядной  архитектуры
        процессора прикладная  программа  не  может получить к ним доступ
        целиком. Для большого блока памяти администратор памяти  выделяет
        несколько непрерывных  (следующих  подряд) селекторов,  каждый из
        которых (кроме последнего) ссылается на часть большого блока  па-
        мяти размером 64К. Например, чтобы выделить блока памяти размером
        в 220К,  администратор памяти создает четыре селектора,  при этом
        первые три  селектора ссылаются на блоки по 64К,  а последний се-
        лектор - на блок размером 28К. Прибавляя SelectorInc к селектору,
        принадлежащему большому блоку,  вы можете получить  селектор  для
        следующего сегмента, а вычитая SelectorInc - для предыдущего.

             При распределении большого блока функция GlobalAlloc  всегда
        возвращает описатель первого сегмента,  а GlobalAllocPtr - указа-
        тель на первый сегмент.

             Приведенная ниже функция GetPtr воспринимает указатель боль-
        шого блока  (возвращаемый функцией GlobalAllocPtr) и 32-разрядное
        смещение и возвращает указатель на заданное внутри  блока  смеще-
        ние.

             function GetPtr(P: Pointer; Offset: Longint): Pointer;
             type
                Long = record
                         Lo, Hi: Word;
                       end;

             begin
                GetPtr := Ptr(

         B.Pascal 7 & Objects/LR     - 282 -

                     Long(P).Hi + Long(Offset).Hi * SelectorInc,
                     Long(P).Lo + Long(Offset).Lo);
             end;

             Заметим, что старшее слово параметра Offset используется для
        определения того, сколько раз нужно увеличить селекторную часть P
        для получения корректного сегмента.  Например,  если Offset равно
        $24000, то  селекторная  часть  P  будет   увеличена   на   2   *
        SelectorInc, а смещение P - на $4000.

             Следующая функция LoadFile загружает в блок памяти весь файл
        и возвращает указатель на блок. Если файл превышает 64К, то выде-
        ляется большой блок памяти.

             function LoadFile(const FileName: string): Pointer;
             var
               Buffer: Pointer;
               Size, Offset, Count: Longint;
               F: file;
             begin
               Buffer := nil;
               Assign(F, FileName);
               Reset(F, 1);
               Size := FileSize(F);
               Buffer := GlobalAllocPtr(gmem_Moveable, Size);
               if Buffer <> nil then
               begin
                 Offset := 0;
                 while Offset < Size do
                 begin
                    Count := Size - Offset;
                    if Count > $8000 then Count := $8000;
                    BlockRead(F, GetPtr(Buffer, Offset)^, Count);
                    Inc(Offset, Count);
                 end;
               end;
               LoadFile := Buffer;
             end;

             Переменная SelectorInc  определена  также  в  версии  модуля
        System для реального режима.  В реальном режиме она всегда содер-
        жит значение $1000,  которое при сложении его с сегментной частью
        указателя реального режима увеличивает указатель на 64К.

             Другим образом вы можете использовать переменную SelectorInс
        только в программах DOS защищенного режима.  Используйте перемен-
        ную SelectorInc для доступа к псевдонимам  сегментов,  выделяемых
        администратором этапа выполнения при загрузке прикладной програм-
        мы.  Для каждого сегмента кода прикладной программы администратор
        этапа  выполнения создает селектор-псевдоним,  ссылающийся на тот
        же сегмент, но имеющий полномочия селектора данных. Для сегментов
        стека и данных селекторы-псевдонимы не создаются.


         B.Pascal 7 & Objects/LR     - 283 -

             Чтобы получить доступ к селектору-псевдониму для конкретного
        сегмента, добавьте к селектору сегмента SelectorInc. Предположим,
        например,  что P - это переменная типа Pointer, а Foo - процедура
        или функция. Тогда присваивание вида:

             P := Addr(Foo)

        приводит к  тому,  что P будет указывать на выполняемую доступную
        только по чтению точку входа Foo, а после оператора:

             P := Ptr(Seg(Foo) + SelectorInc, Ofs(Foo));

        P будет ссылаться на тот же адрес,  но  с  полномочиями  на  чте-
        ние/запись.



         B.Pascal 7 & Objects/LR     - 284 -

                                  Модуль WinAPI
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль WinAPI дает вам непосредственный доступ к расширениям
        Borland защищенного режима DOS. Чтобы облегчить написание перено-
        симых прикладных программ и совместимых на уровне двоичного  кода
        DLL, разработан интерфейс WinAPI, являющийся подмножеством интер-
        фейса API Windows.

             Модуль WinAPI  позволяет вам использовать функции управления
        памятью,  управления ресурсами,  модулями,  селекторами и  многие
        другие  функции API.  Ниже приведено их краткое описание.  Полное
        описание констант, типов, процедур и функций модуля WinAPI вы мо-
        жете найти в "Справочном руководстве программиста".

             При работе под Windows подпрограммы  API,  поддерживаемые  с
        помощью модуля WinAPI, находятся в динамически компонуемых библи-
        отеках KERNEL.DLL и USER.DLL.  В защищенном режиме DOS эти DLL не
        требуются, так как администратор этапа выполнения защищенного ре-
        жима содержит реализацию подпрограмм  KERNEL и USER, автоматичес-
        ки перенаправляя их вызовы администратору.

                               Управление памятью
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             При разработке программ,  работающих с динамической памятью,
        обычно используются стандартные процедуры New,  Dispose, GetMem и
        FreeMem. Однако получить доступ к администратору памяти  защищен-
        ного  режима Borland вы можете с помощью функций GlobalXXXX в мо-
        дуле WinAPI.

             Заметим, что функции GlobalXXXXPtr комбинируют в одной подп-
        рограмме общие  последовательности  вызовов  функций,  такие  как
        GlobalAlloc,  за которыми следуют вызовы GlobalLock, GlobalUnlock
        или GlobalFree.



         B.Pascal 7 & Objects/LR     - 285 -

                       Подпрограммы управления памятью API
                                                            Таблица 17.2
        ЪДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Функция          і                 Описание                і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetFreeSpace      і Определяет объем свободной памяти  в ди-і
        і                     і намически распределяемой области.       і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalAlloc       і Выделяет блок памяти в динамически расп-і
        і                     і ределяемой области.                     і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalAllocPtr    і Выделяет и блокирует блок памяти (с  по-і
        і                     і мощью вызовов GlobalAlloc и GlobalLock).і
        і                     і                                         і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalCompact     і Переупорядочивает  память,  распределен-і
        і                     і ную в динамической области,  так что ос-і
        і                     і вобождается заданный объем памяти.      і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalDiscard     і Выгружает заданный объект памяти.       і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalDosAlloc    і Распределяет память, к которой можно по-і
        і                     і лучить доступ в реальном режиме DOS. Этаі
        і                     і память будет существовать в первом мега-і
        і                     і байте линейного адресного пространства. і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalDosFree     і Освобождает память, выделенную  ранее  сі
        і                     і помощью GlobalDosAlloc.                 і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalFlags       і Получает информацию о блоке памяти.     і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalFree        і Освобождает разблокированный блок памятиі
        і                     і и делает его описатель недействительным.і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalFreePtr     і Разблокирует и освобождает  блок  памятиі
        і                     і с помощью GlobalUnlock и GlobalFree.    і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalHandle      і Получает описатель объекта в  памяти  поі
        і                     і заданному адресу сегмента.              і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalLock        і Увеличивает счетчик ссылки блока  памятиі
        і                     і и возвращает указатель на него.         і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalLockPtr     і То же, что и GlobalLock, но вместо  опи-і
        і                     і сателя воспринимает указатель.          і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalLRUNewest   і Перемещает объект в памяти на новую  не-і
        і                     і давно используемую позицию, минимизируя,і
        і                     і таким   образом,   вероятность  выгрузкиі
        і                     і объекта.                                і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalLRUOldest   і Перемещает  объект  в  памяти  на  самуюі
        і                     і "старую" недавно  используемую  позицию,і

         B.Pascal 7 & Objects/LR     - 286 -

        і                     і максимизирую вероятность  выгрузки  объ-і
        і                     і екта.                                   і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalNorify      і Вызывает адрес экземпляра процедуры уве-і
        і                     і домления, передавая описатель блока, ко-і
        і                     і торый нужно выгрузить.                  і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalPageLock    і Увеличивает значение счетчика  блокиров-і
        і                     і ки для памяти, связанной с данным селек-і
        і                     і тором.                                  і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalPageUnlock  і Уменьшает значение  счетчика  блокировкиі
        і                     і для памяти,  связанной с данным селекто-і
        і                     і ром.                                    і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalPtrHandle   і По заданному указателю  на  блок  памятиі
        і                     і возвращает описатель этого блока.       і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalReAlloc     і Перераспределяет блок памяти.           і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalReAllocPtr  і Разблокирует, перераспределяет и  блоки-і
        і                     і рует блок   памяти   (используя  функцииі
        і                     і GlobalUnlock,      GlobalReAlloc       иі
        і                     і GlobalLock).                            і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalSize        і Определяет текущий размер блока памяти. і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalUnfix       і Разблокирует блок памяти,  блокированныйі
        і                     і ранее с помощью GlobalLock.             і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GlobalUnockPtr    і То же,  что и  GlobalUnlock,  но  вместоі
        і                     і описателя воспринимает указатель.       і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   LockSegment       і Блокирует заданный выгружаемый сегмент. і
        ГДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   UnlockSegment     і Разблокирует сегмент.                   і
        АДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Функция GlobalAlloc используется  для  распределения  блоков
        памяти. Для их освобождения применяется функция GlobalFree. Адми-
        нистратор памяти поддерживает три типа блоков памяти: фиксирован-
        ный, перемещаемый  и  выгружаемый.  Фиксированный блок остается в
        одних и тех же адресах физической памяти. Перемещаемый блок может
        перемещаться в  физической  памяти и освобождать место для других
        запросов на выделение памяти,  а выгружаемые блоки  могут  выгру-
        жаться из памяти,  освобождая место для других блоков.  С помощью
        передаваемых GlobalAlloc флагов вы можете выбрать  один  из  этих
        трех типов:

             * gmem_Fixed                          (фиксированный)
             * gmem_Moveable                       (перемещаемый)
             * gmem_Moveable + gmem_Discardable    (выгружаемый)


         B.Pascal 7 & Objects/LR     - 287 -

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

             Перед тем как вы сможете получить доступ к памяти, его нужно
        заблокировать с помощью функции GlobalAlloc, а когда вы закончите
        к нему  обращаться,  его  нужно  разблокировать с помощью функции
        GlobalUnlock. GlobalLock возвращает полный 32-разрядный указатель
        на первый байт блока.  Смещение указателя всегда равно 0. В защи-
        щенном режиме DOS селектор указателя - это тоже самое, что описа-
        тель блока, но в Windows это не всегда так.

             Правильная последовательность вызовов для выделения,  блоки-
        ровки, разблокировки или освобождения блока показана в  приведен-
        ном ниже  примере.  В  данном  примере  H  -  это переменная типа
        THandle, а P - указатель:

             H := GlobalAlloc(gmem_Moveable, 8192);   { выделение блока }
             if H <> then                        { если память выделена }
             begin
                P := GlobalLock(H);                  { блокировка блока }
                    .
                    .                          { доступ к блоку через P }
                    .
                GlobalUnlock(H);                  { разблокировать блок }
                GlobalFree(H);                        { освободить блок }
             end;

             Блокировка и разблокировка блока при каждом обращении к нему
        достаточно утомительна и ведет к ошибкам, и реально она необходи-
        ма только  для  выгружаемых  блоков  и  в  прикладных  программах
        Windows, работающих в реальном режиме.  Во всех других  ситуациях
        лучшим решением является блокировка блока сразу после его выделе-
        ния и сохранение этого состояния до освобождения  блока.  С  этой
        целью модуль WinAPI включает в себя семейство подпрограмм-"оболо-
        чек" GlobalXXXXPtr.   Особый   интерес    представляет    функция
        GlobalAllocPtr, которая выделяет и блокирует блок памяти, и функ-
        ция GlobalFreePtr,  разблокирующая и освобождающая блок памяти. С
        помощью этих подпрограмм приведенный выше пример можно упростить:

             H := GlobalAlloc(gmem_Moveable, 8192);   { выделение блока }
             if H <> then                        { если память выделена }
             begin
                    .
                    .                                  { доступ к блоку }
                    .
                GlobalFreePtr(P);                     { освободить блок }
             end;

             Вызвав функцию GlobalReAlloc,  вы можете изменить размер или
        атрибуты блока   памяти,   сохранив   его   содержимое.   Функция

         B.Pascal 7 & Objects/LR     - 288 -

        GlobalReAlloc возвращает новый описатель блока, который может от-
        личаться от  передаваемого функции описателя,  если старый размер
        или новый размер блок превышает 64К.  Заметим, что в тех случаях,
        когда старый   размер  блока  и  новый  его  размер  меньше  64К,
        GlobalReAlloc всегда может изменить размер блока,  не изменяя его
        описателя.

             Функция GlobalReAlloc можно также использоваться для измене-
        ния   атрибутов   блока.   Это  можно  сделать,  задав  наряду  с
        gmem_Moveable или gmem_Discardable флаг gmem_Modify.

             Функция GlobalReAlloc   выполняет  те  же  действия,  что  и
        GlobalReAlloc, но обе они вместо описателей использует указатели.

             Имеется также   ряд   других,   менее   часто   используемых
        GlobalXXXX. Все  они  подробно  описаны в Главе 1 ("Справочник по
        библиотеке") "Справочного руководства программиста".



         B.Pascal 7 & Objects/LR     - 289 -

                               Управление модулем
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Администратор этапа  выполнения поддерживает следующие подп-
        рограммы обслуживания модулей:

                      Подпрограммы API обслуживания модулей Таблица 17.3
        ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і   Подпрограмма            і         Описание                  і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FreeLibrary             і Делает недействительным  загружен-і
        і                           і ный модуль библиотеки,  и освобож-і
        і                           і дает соответствующую память,  еслиі
        і                           і ссылок на модуль больше нет.      і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetModuleFileName       і Дает полный маршрут и имя выполня-і
        і                           і емого файла, задающий, откуда заг-і
        і                           і ружен модуль.                     і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetModuleHandle         і Определяет описатель заданного мо-і
        і                           і дуля.                             і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetModuleUsage          і Определяет счетчик  ссылок на  мо-і
        і                           і дуль.                             і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetProcAddress          і Определяет   адрес  экспортируемойі
        і                           і библиотечной функции.             і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   LoadLibrary             і Загружает  указанный  библиотечныйі
        і                           і модуль.                           і
        АДДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Некоторые из этих подпрограмм воспринимают в качестве  пара-
        метра описатель  модуля.  Описатель модуля самой прикладной прог-
        раммы хранится в переменной HInstance, описанной в модуле System.



         B.Pascal 7 & Objects/LR     - 290 -

                              Управление ресурсами
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Администратор этапа  выполнения поддерживает следующие подп-
        рограммы управления ресурсами:

                        Функции API управления ресурсами     Таблица 17.4
        ЪДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Функция           і                 Описание               і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   AccessResource     і Открывает заданный  выполняемый  файл иі
        і                      і перемещает указатель  файла  на  началоі
        і                      і заданного ресурса.                     і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FindResource       і Определяет  адрес  ресурса  в  заданномі
        і                      і файле ресурса.                         і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FreeResource       і Уменьшает счетчик ссылок для  загружен-і
        і                      і ного ресурса.  Когда   значение   этогоі
        і                      і счетчика становится равным нулю, то ис-і
        і                      і пользуемая ресурсом память освобождает-і
        і                      і ся.                                    і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   LoadResource       і Загружает заданный ресурс в память.    і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   LoadString         і Загружает заданную строку ресурса.     і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   LockResource       і Блокирует заданный ресурс  в  памяти  иі
        і                      і увеличивает его счетчик ссылок.        і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SizeOfResource     і Возвращает размер (в байтах)  заданногоі
        і                      і ресурса.                               і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   UnlockResource     і Разблокирует заданный ресурс и уменьша-і
        і                      і ет на 1 счетчик ссылок на ресурс.      і
        АДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Ресурсы могут компоноваться с прикладной  программой  с  по-
        мощью директив компилятора {$R имя_файла}. Указанные файлы должны
        быть файлами ресурсов Windows (.RES).  Обычно с прикладными прог-
        раммами  защищенного  режима DOS компонуются только строковые ре-
        сурсы и ресурсы, определенные пользователем. Другие типы ресурсов
        Windows к прикладной программе DOS обычно неприменимы.

                   Примечание: Ресурсы Turbo Vision  не  следуют  тем  же
              соглашениям, что ресурсы Windows, и к ним нельзя обращаться
              с помощью подпрограмм API.

             Некоторые подпрограммы API управления ресурсами требуют ука-
        зания описателя экземпляра, которым обычно является указатель эк-
        земпляра прикладной программы (который  содержится  в  переменной
        HInstance модуля System).


         B.Pascal 7 & Objects/LR     - 291 -

                              Управление селектором
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                     Подпрограммы API управления селектором  Таблица 17.5
        ЪДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Функция            і               Описание                і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   AllocDStoCSAlias    і Отображает селектор сегмента данных наі
        і                       і селектор сегмента кода.               і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   AllocSelector       і Выделяет новый селектор.              і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   ChangeSelector      і Генерирует селектор кода, соответству-і
        і                       і щий  заданному селектору  данных,  илиі
        і                       і генерирует  заданный  селектор,  соот-і
        і                       і ветствующий селектору кода.           і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FreeSelector        і Освобождает  селектор,   первоначальноі
        і                       і выделенный функциями  AllocDStoCSAliasі
        і                       і или AllocSelector.                    і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetSelectorBase     і Дает базовый адрес селектора.         і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetSelectorLimit    і Возвращает предельное значение для за-і
        і                       і данного селектора.                    і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   PrestoChangoSelectorі Генерирует селектор кода, соответству-і
        і                       і ющий заданному  селектору данных, либоі
        і                       і генерирует селектор данных,  соответс-і
        і                       і твующий селектору кода.               і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetSelectorBase     і Устанавливает базовый адрес селектора.і
        ГДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   SetSelectorLomit    і Устанавливает предельное  значение се-і
        і                       і лектора.                              і
        АДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 292 -

                             Другие подпрограммы API
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Администратор этапа выполнения поддерживает следующие допол-
        нительные подпрограммы API:

                             Прочие подпрограммы API         Таблица 17.6
        ЪДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Функция        і                   Описание                і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   DOS3Call        і Вызывает функцию прерывания DOS 21h; вызы-і
        і                   і вается только из подпрограмм ассемблера.  і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FatalExit       і Передает отладчику текущее  состояние опе-і
        і                   і рационной среды  защищенного  режима и вы-і
        і                   і выводит подсказку для ввода  инструкций  оі
        і                   і продолжении работы.                       і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetDOSEnviromentі Определяет  текущую   строку  операционнойі
        і                   і среды задачи.                             і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetVersion      і Дает  текущую  версию  операционной  средыі
        і                   і Windows или операционной системы DOS.     і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   GetWinFlags     і Дает используемые Windows флаги конфигура-і
        і                   і ции памяти.                               і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   MessageBox      і Создает, выводит  на  экран  и обслуживаеті
        і                   і окно сообщений.                           і
        АДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Совместно используемая DLL, чтобы определить, выполняется ли
        она в  защищенном режиме DOS или под Windows,  может использовать
        функцию GetWinFlags, например:

             if GetWinFlags and wf_DPMI <> 0 then
                   Message('Работа в защищенном режиме DOS')
             else
                   Message('Работа в среде Windows');



         B.Pascal 7 & Objects/LR     - 293 -

                          Прямой доступ к DPMI-серверу
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Прямой доступ к DPMI-серверу вы можете получить через преры-
        вание $31,  которое  непосредственно вызывает DPMI-сервер в обход
        администратора этапа выполнения.  Однако это опасный прием.  DPMI
        не поддерживает  очистку  ресурсов,  таких как векторы прерываний
        памяти; корректно с этими проблемами работает администратор этапа
        выполнения.  Вы должны глубоко понимать концепции защищенного ре-
        жима и знать о существенном риске,  с которым связано использова-
        ние данного метода доступа защищенного режима.

               Компиляция прикладной программы защищенного режима
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             * В  IDE выберите команду CompileіTarget и в диалоговом окне
               Target    Platform    (Целевая     платформа)     выберите
               Protected-mode Application.

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



         B.Pascal 7 & Objects/LR     - 294 -

                   Выполнение программы защищенного режима DOS
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Когда вы выполняете программу DOS защищенного режима,  нужно
        обеспечить наличие  в текущем каталоге или по маршруту DOS файлов
        DPMI16BI.OVL (сервер DPMI), RTM.EXE (администратор этапа выполне-
        ния) и всех DLL, с которыми работает ваша программа.

                   Примечание: Лицензионное   соглашение   позволяет  вам
              распространять файлы DPMI16BI.OVL и RTM.EXE вместе с  вашей
              программой.

             В выполняемом файле .EXE защищенного режима DOS используется
        тот же формат файла,  что и в Windows 3.x и OS/2 1.x. Этот формат
        файла является  надмножеством обычного формата .EXE DOS и состоит
        из обычного образа файла .EXE,  называемого фиктивным модулем, за
        которым следует расширенный заголовок и код, данные и ресурсы за-
        щищенного режима.  Ниже показана последовательность  событий  при
        выполнении программы защищенного режима DOS.

             1. DOS загружает фиктивный модуль реального режима и переда-
                ет ему управление.

             2. Если средства DPMI отсутствуют,  то фиктивный модуль заг-
                ружает DPMI-сервер из файла DPMI16BI.OVL. Некоторые новые
                администраторы  памяти  поддерживают  средства DPMI (как,
                например,  это делается в  окне  DOS  улучшенного  режима
                Windows  3.х).  В таких конфигурациях фиктивный модуль не
                загружает DPMI-сервер, но использует уже имеющийся.

             3. Далее,  если администратор этапа выполнения еще не загру-
                жен в память,  фиктивный модуль загружает  его  из  файла
                RTM.EXE. Если прикладная программа защищенного режима вы-
                полняет другую программу защищенного режима,  обе исполь-
                зуют одну копию администратора этапа выполнения.

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

             5. Загрузчик сначала загружает используемую прикладной прог-
                раммой DLL  (если она имеется),  затем загружает сегменты
                кода и данных прикладной  программы.  Наконец,  загрузчик
                передает управление на точку входа прикладной программы.

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


         B.Pascal 7 & Objects/LR     - 295 -

             Когда прикладная программа защищенного режима DOS выполняет-
        ся в окне DOS улучшенного режима  Windows,  вы  можете  управлять
        объемом расширенной памяти,  которую выделяет администратор этапа
        выполнения,  задав в файле .PIF прикладной  программы  предельное
        значение памяти XMS.


                   Управление объемом используемой RTM памяти
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             По умолчанию  администратор  этапа выполнения использует при
        загрузке всю доступную память.  Затем по запросам он выделяет па-
        мять своим  клиентам (через подпрограммы API администратора памя-
        ти).

             В защищенном режиме нет разницы между обычной памятью  (ниже
        1 мегабайта) и расширенной памятью (с адресами выше 1 мегабайта);
        для программ защищенного режима доступны оба типа памяти.  Однако
        администратор этапа  выполнение  отдает  предпочтение расширенной
        памяти. Только после того как вся расширенная память будет  выде-
        лена, или   когда  прикладная  программа  специально  запрашивает
        обычную память (например,  с помощью функции GlobalDosAlloc), ад-
        министратор этапа выполнения выделяет обычную память.

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

             Администратор этапа выполнения перед порождением  прикладной
        программы пытается  освободить  максимальный объем обычной памяти
        (например, перенеся перемещаемые блоки в расширенную память). Од-
        нако попытки  освобождения расширенной памяти не предпринимаются.
        Таким образом, если должны порождаться прикладные программы защи-
        щенного режима,  не использующие администратор этапа  выполнения,
        то  необходим споcоб управления распределением памяти администра-
        тором этапа выполнения.

             Чтобы управлять тем, сколько памяти может использовать адми-
        нистратор этапа выполнения,  в командной строке  DOS  добавьте  к
        строке операционной среды DOS переменную среды RTM:

             SET RTM={параметр nnnn}

             Возможные параметры перечислены в следующей таблице.  Значе-
        ние nnnn может быть десятичным или шестнадцатиричным числом в ви-
        де xAB54 или xab54.

         B.Pascal 7 & Objects/LR     - 296 -


                     Параметры переменной операционной
             среды RTM, используемые для управления памятью  Таблица 17.7
        ЪДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Параметр        і                 Описание                 і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   EXTLEAVE nnnn    і Всегда оставляет не менее  nnnn  килобайті
        і                    і доступной расширенной памяти.  По умолча-і
        і                    і нию это значение равно 640К.             і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   EXTMAX nnnn      і Не выделяет более nnnn килобайт расширен-і
        і                    і ной памяти.   По  умолчанию  используетсяі
        і                    і значение 4 гигабайта. В Windows использу-і
        і                    і емое по умолчанию значение равно половинеі
        і                    і доступной памяти.                        і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   EXTMIN nnnn      і Если после применения EXTMAX или EXTLEAVEі
        і                    і доступно менее nnnn килобайт, то програм-і
        і                    і ма завершается с  сообщением  о  нехваткеі
        і                    і памяти (Out of memory).  По умолчанию этоі
        і                    і значение равно 0.                        і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   REALLEAVE nnnn   і Всегда оставляет не менее nnnn параграфові
        і                    і доступной реальной  памяти.  По умолчаниюі
        і                    і это  значение равно 64К или 4096 парагра-і
        і                    і фов.                                     і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   REALMAX nnnn     і Не  выделяет более nnnn параграфов реаль-і
        і                    і ной памяти.  По  умолчанию  это  значениеі
        і                    і равно 1 мегабайту или 65535 параграфов.  і
        ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   REALMIN nnnn     і Если после применения REALMAX и REALLEAVEі
        і                    і доступно менее nnnn параграфов,  то прог-і
        і                    і рамма завершается с сообщением о нехваткеі
        і                    і памяти (Out of memory).  По умолчанию этоі
        і                    і значение равно 0.                        і
        АДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Следующая команда DOS ограничивает RTM 2 мегабайтами  расши-
        ренной  памяти  и  обеспечивает,  что нераспределенными останутся
        128К реальной памяти.

             SET RTM=EXTMAX 2048 REALLEAVE 8192

         B.Pascal 7 & Objects/LR     - 297 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                      Глава 18. Строки с завершающим нулем
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В Borland Pascal поддерживается класс символьных строк,  ко-
        торые называются строками, завершающимися нулем. Благодаря расши-
        ренному синтаксису Borland Pascal и модулю Strings ваши программы
        (как для DOS,  так и для Windows) могут использовать строки с за-
        вершающим нулем путем задания в операторе uses модуля Strings.

                      Что такое строка с завершающим нулем?
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В Borland  Pascal строки обычного типа (String) хранятся как
        байт длины,  за которым следует последовательность символов. Мак-
        симальная длина строки в Паскале равна 255 символам.  Таким обра-
        зом, строка Паскаля занимает от 1 до 256 байт памяти.

             Строки с завершающим нулем не содержат байта  длины.  Вместо
        этого  они  состоят из последовательности ненулевых символов,  за
        которыми следует символ NULL (#0).  Никаких ограничений на  длину
        строк с завершающим нулем не накладывается, но 16-разрядная архи-
        тектура DOS и Windows ограничивает их размер 65535 символами.

                             Функции модуля Strings
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Borland Pascal  не имеет встроенных подпрограмм,  предназна-
        ченных специально для работы со строками с завершающим нулем. Эти
        функции вы  можете  найти в модуле Strings.  Среди них вы найдете
        функцию StrPCopy,  которую  можно  использовать  для  копирования
        строки Паскаля в строку с завершающим нулем, и StrPos, используе-
        мую для преобразования строки с завершающим нулем в строку Паска-
        ля. Приведем краткое описание каждой функции:



         B.Pascal 7 & Objects/LR     - 298 -

                             Функции модуля Strings
        ЪДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і     Функция  і       Описание                                 і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrCat     і Добавляет исходную строку к концу целевой стро-і
        і              і ки и возвращает указатель на целевую строку.   і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrComp    і Сравнивает  две  строки  S1  и   S2. Возвращаеті
        і              і значение < 0, если S1 < S2, равное 0, если S1 =і
        і              і S2 и > 0, если S1 > S2.                        і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrCopy    і Копирует исходную строку  в  целевую  строку  иі
        і              і возвращает указатель на целевую строку.        і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrECopy   і Копирует исходную строку  в  целевую  строку  иі
        і              і возвращает указатель на конец целевой строки.  і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrIComp   і Сравнивает  две  строки  без  различия регистраі
        і              і символов.                                      і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrLCat    і Присоединяет  исходную  строку  к концу целевойі
        і              і строки. При этом обеспечивается,  что длина ре-і
        і              і зультирующей строки не превышает заданного мак-і
        і              і симума.  Возвращается указатель  на  строку-ре-і
        і              і зультат.                                       і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrLComp   і Сравнивает две строки с  заданной  максимальнойі
        і              і длиной.                                        і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrLCopy   і Копирует заданное число  символов  из  исходнойі
        і              і строки в  целевую строку и возвращает указательі
        і              і на целевую строку.                             і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrEnd     і Возвращает  указатель  на конец строки, то естьі
        і              і указатель на завершающий строку нулевой символ.і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrDispose і Уничтожает ранее выделенную строку.            і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrLen     і Возвращает длину строки.                       і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrLIComp  і Сравнивает две строки  с  заданной максимальнойі
        і              і длиной без различия регистра символов.         і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrLower   і Преобразует строку в нижний регистр и возвраща-і
        і              і ет указатель на нее.                           і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrMove    і Перемещает  блок  символов из исходной строки ві
        і              і целевую строку и возвращает указатель на  целе-і
        і              і вую строку. Два блока могут перекрываться.     і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrNew     і Выделяет  для  строки память в динамически рас-і
        і              і пределяемой области.                           і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ

         B.Pascal 7 & Objects/LR     - 299 -

        і   StrPas     і Преобразует строку с завершающим нулем в строкуі
        і              і Паскаля.                                       і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrPCopy   і Копирует  строку Паскаля в строку с завершающимі
        і              і нулем и возвращает указатель на строку с завер-і
        і              і шающим нулем.                                  і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrPos     і Возвращает указатель на первое вхождение задан-і
        і              і ной подстроки в строке, или nil, если подстрокаі
        і              і в строке не содержится.                        і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrRScan   і Возвращает  указатель  на  последнее  вхождениеі
        і              і указанного символа в строку, или nil, если сим-і
        і              і вол в строке отсутствует.                      і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrScan    і Возвращает  указатель  на первое вхождение ука-і
        і              і занного символа в строку,  или nil, если символі
        і              і в строке отсутствует.                          і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   StrUpper   і Преобразует  строку в верхний регистр и возвра-і
        і              і щает указатель на нее.                         і
        АДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                     Использование строк с завершающим нулем
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Строки с завершающим нулем хранятся в виде символьных масси-
        вов с нулевой базой (начинающихся с 0) с индексом целого типа, то
        есть в виде массива:

             array[0..X] of Char;

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

             type
                TIdentifier = array[0..15] of Char;
                TFileName   = array[0..79] of Char;
                TMemoText   = array[0..1023] of Char;


         B.Pascal 7 & Objects/LR     - 300 -

             Более всего  строки Паскаля и строки с завершающим нулем от-
        личаются интенсивностью использования указателей.  Borland Pascal
        выполняет  операции  с этими указателями,  используя набор правил
        расширенного синтаксиса.  Кроме того,  в Borland  Pascal  имеется
        встроенный  тип  PChar,  который  представляет собой указатель на
        строку с завершающим нулем. В модуле System тип PChar определяет-
        ся следующим образом:

             type PChar = ^Char;

             Правилами расширенного синтаксиса управляет директива компи-
        лятора $X. В состоянии {$X+} (по умолчанию) расширенный синтаксис
        разрешен. Правила расширенного синтаксиса описываются в следующих
        разделах.



         B.Pascal 7 & Objects/LR     - 301 -

                    Символьные указатели и строковые литералы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             При разрешении  расширенного  синтаксиса  строковый  литерал
        совместим по присваиванию с типом PChar.  Это означает, что пере-
        менной типа PChar можно присвоить строковый литерал. Например:

             var
                P: PChar;
                .
                .
             begin
                P := 'Привет...';
             end;

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

             const
                TempString: array[0..14] of Char = 'Привет...'#0;
             var
                P: PChar;
                .
                .
             begin
                P := @TempString;
             end;

             Когда соответствующие  формальные  параметры имеют тип Char,
        строковые литералы вы можете использовать как  фактические  пара-
        метры при вызовах процедур и функций. Например, если имеется про-
        цедура с описанием:

             procedure PrintStr(Str: PChar);

        то допустимы следующие вызовы процедуры:

             procedure PrintStr('Строка для проверки');
             PrintStr(#10#13);

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

             Наконец, типизированная константа типа PChar может инициали-
        зироваться строковой константой. Это справедливо также для струк-
        турных типов,  таких как массивы PChar и записи,  а также объекты
        PChar.


         B.Pascal 7 & Objects/LR     - 302 -

             const
                Message: PChar = 'Program terminated';
                Prompt: PChar = 'Enter values: ';
                Digits; array [0..9] of PChar = {
                 'Zero', 'One', 'Two', 'Three', 'Four', 'Five',
                 'Six', 'Seven', Eight', 'Nine'};

             Строковая выражение-константа всегда вычисляется как  строка
        Паскаля, даже  если она инициализируется как типизированная конс-
        танта типа PChar.  Таким образом,  строковое  выражение-константа
        всегда ограничено длиной в 255 символов.

                    Символьные указатели и символьные массивы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Если вы с помощью директивы $X разрешаете  расширенный  син-
        таксис,  то  символьный  массив с нулевой базой совместим с типом
        PChar.  Это означает,  что там,  где предполагается использование
        типа PChar,  может использоваться символьный массив с нулевой ба-
        зой.  Когда символьный массив используется вместо значения PChar,
        компилятор  преобразует  символьный массив в указатель-константу,
        значение которой соответствует адресу первого  элемента  массива.
        Например:

             var
                A: array[0..63] of Char;
                P: PChar;
                .
                .
                .
             begin
                P := A;
                PrintStr(A);
                PrintStr(P);
             end;

             Благодаря оператору присваивания P теперь указывает на  пер-
        вый элемент массива A, поэтому PrintStr вызывается дважды с одним
        и тем же значением.

             Вы можете инициализировать типизованную  константу,  имеющую
        тип символьного массива с нулевой базой, с помощью строкового ли-
        терала,  имеющего меньшую длину,  чем размер массива.  Оставшиеся
        символы устанавливаются в значение NULL (#0),  и массив будет со-
        держать строку с завершающим нулем.

             type
                TFileName = array[0..79] of Char;
             const
                FileNameBuf: TfileName = 'TEST.PAS';
                FileNamePtr: PCahr = FileNameBuf;



         B.Pascal 7 & Objects/LR     - 303 -

                      Индексирование символьного указателя
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Так как  символьный  массив с нулевой базой совместим с сим-
        вольным указателем, символьный указатель можно индексировать ана-
        логично символьному массиву с нулевой базой.

             var
                A: array[0..63] of Char;
                P: PChar;
                Ch: Char;
                .
                .
                .
             begin
                P := A;
                Ch := A[5];
                Ch := P[5];
             end;

             Оба последних присваивания присваивают Ch значение, содержа-
        щееся в шестом символе-элементе A.

             При индексировании символьного указателя индекс задает безз-
        наковое смещение, которое добавляется к указателю перед его разы-
        менованием.  Таким образом, P[0] эквивалентно P^ и задает символ,
        на который указывает P. P[1] задает символ справа от того, на ко-
        торый указывает P,  P[2] задает следующий символ и т.д. Для целей
        индексирования  PChar  ведет  себя таким образом,  как если бы он
        описывался:

             type
               TCharArray = array[0..65535] of Char;
               Pchar = ^TCharArray;

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

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

             function StrUpper(Srt: Pchar): Pchar;
             var
                I: Word;
             begin
                I := 0;
                while Str[I] <> #0 do
                begin
                  Str[I] := UpCase(Str[I]);
                  Inc(I);

         B.Pascal 7 & Objects/LR     - 304 -

                end;
                StrUpper := Str;
             end;

             Обратите внимание,  что StrUppper - это функция, а не проце-
        дура,  и что она всегда возвращает значение, которое передавалось
        ей в качестве параметра.  Так как расширенный синтаксис допускает
        игнорирование  результата  функции,  StrUpper может интерпретиро-
        ваться, как процедура:

             StrUpper(A);
             PrintStr(A);

             Однако, StrUpper всегда возвращает передаваемое ей значение,
        приведенные выше операторы можно скомбинировать в один:

             PrintStr(StrUpper(A));

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

                       Операции с символьными указателями
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Расширенный синтаксис Borland Pascal позволяет  использовать
        для работы с символьными указателями отдельные операции. Для уве-
        личения или уменьшения смещения в значении  указателя  можно  ис-
        пользовать операции плюс (+) и минус (-). Операцию минус (-) мож-
        но использовать для  вычисления  расстояния  (разности  смещений)
        между двумя символьными  указателями.  Предположим,  что  P  и  Q
        представляют собой значения тип PChar,  а I - значение типа Word.
        Тогда допустимы следующие конструкции:

             P + I     I прибавляется к смещению P
             I + P     I прибавляется к смещению P
             P - I     I вычитается из смещения P
             P - Q     Смещение Q вычитается из смещения P

             В операциях P + I и I + P I прибавляется к адресу,  задавае-
        мому  P.  При  этом получается указатель,  который указывает на I
        символов после P.  В операции P - I I вычитается из адреса, зада-
        ваемого P,  и получается указатель,  указывающий на I символов до
        P.

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


         B.Pascal 7 & Objects/LR     - 305 -

             Стандартный синтаксис Borland Pascal позволяет при сравнении
        указателей определять только их равенство или неравенство. Расши-
        ренный  синтаксис  (разрешенный  по  директиве компилятора {$X+})
        позволяет применять операции <, >, <= и <= к значениям PChar. За-
        метим,  однако,  что при таких проверках предполагается,  что два
        сравниваемых указателя указывают на один и тот же  массив  симво-
        лов. По этой причине сравниваются только смещения указателей. Ес-
        ли два указателя указывают на различные  символьные  массивы,  то
        результат не определен.

             var
                A, B: array[0..79] of Char;
                P, Q: PChar;
             begin
                P := A;                { P указывает на A[0] }
                Q := A + 5;            { Q указывает на A[5] }
                if P < Q then ...;     { допустимая проверка,
                                         результат - True }
                Q := B;                { Q указывает на B[0] }
                if P < Q then ...;     { результат не определен }
             end;

             Подробнее об операциях с PChar рассказывается в Главе 6.

               Строки с завершающим нулем и стандартные процедуры
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Расширенный синтаксис Borland Pascal позволяет  применять  к
        символьным  массивам  с нулевой базой стандартные процедуры Read,
        ReadLn и Val, а к символьным массива с нулевой базой и символьным
        указателям - стандартные процедуры Write,  WriteLn, Val, Assign и
        Rename. Более подробные описания этих процедур можно найти в Гла-
        ве 1  ("Справочник по библиотеке") "Справочного руководства прог-
        раммиста".



         B.Pascal 7 & Objects/LR     - 306 -

                Пример использования функций с завершающим нулем
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Приведем пример исходного кода,  показывающий, как можно ис-
        пользовать некоторые функции обработки строк. Этот пример исполь-
        зован при разработке функции FileSplit в модуле WinDos.

             { максимальные размеры компонентов имени файла }

             const
               fsPathName    = 79;            { имя маршрута }
               fsDirectory   = 67;            { имя каталога }
               fsFileName    = 8;             { имя файла }
               fsExtension   = 4;             { расширение имени файла }

             { флаги, возвращаемые FileSplit }

             const
                    fcWildcards   = $0008     { трафаретные символы }
                    fcDirectory   = $0004     { имя каталога }
                    fcFileName    = $0002     { имя файла }
                    fcExtension   = $0001     { расширение имени файла }

           { FileSplit разбивает имя файла,  заданное маршрутом,  на три }
           { компонента.  Dir  принимает  значение  диска  и  каталога с }
           { предшествующей и завершающей обратной  косой  чертой,  Name }
           { принимает  значение  имени  файла,  а  Ext  -  расширения с }
           { предшествующей  точкой.  Если  компонент   строки-параметра }
           { равен   NIL,   то   соответствующая   часть   маршрута   не }
           { записывается.  Если маршрут не содержит данного компонента, }
           { то    возвращаемая    строка   компонента   будет   пустой. }
           { Максимальные длины строк,  возвращаемых в Dir,  Name и Ext, }
           { определяются   битовыми  масками  fsDirectory,  fsFileName, }
           { fsExtension.  Возвращаемое  значение   представляет   собой }
           { комбинацию   битовых   масок   fсDirectory,   fсFileName  и }
           { fсExtension,  показывающую, какие компоненты присутствуют в }
           { маршруте.   Если  имя  и  расширение  содержат  трафаретные }
           { символы (* и ?), то в возвращаемом значении устанавливается }
           { флаг fcWildcards. }

             function FileSplit(Path, Dir, Name, Ext: PChar): Word;
             var
                DirLen, NameLEn, Flags: Word;
                NamePtr, ExtPtr: PChar;
             begin
                NamePtr := StrRScan(Path, '/');
                if NamePtr = nil then NamePtr := StrRScan(Path, ':');
                if NamePtr = nil then NamePtr := Path else Inc(NamePtr);
                ExtPtr := StrScan(NamePtr, '.');
                if ExtPtr = nil then ExtPtr := StrEnd(NamePtr);
                DirLen := NamePtr - Path;
                if DirLen > fsDirectory then DirLen := fsDirectory;
                NameLen := ExtPtr - NamePtr;

         B.Pascal 7 & Objects/LR     - 307 -

                if NameLen > fsFilename then NameLen := fsFileName;
                Flags := 0;
                if (StrScan(NamePtr, '?') <> nil) or
                   (StrScan(NamePtr, '*') <> nil) then
                   Falgs := fcWildcards;
                if DirLen <> 0 then Flags := Flags or fcDirectory;
                if NameLen <> 0 then Flags := Flags or fcFilename;
                if ExtPtr[0] <> #0 then Flags := Flags or fcExtension;
                if Dir <> nil then StrLCopy(Dir, Path, DirLen);
                if Name <> nil then StrLCopy(Name, NamePtr, NameLen);
                if Ext <> nil then StrLCopy(Ext, ExtPtr, fsExtension);
                FileSplit := Flags:
             end;



         B.Pascal 7 & Objects/LR     - 308 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
             Глава 19. Использование графического интерфейса Borland
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль Graph реализует полную библиотеку  из  более  чем  50
        графических  программ  -  от  вызовов процедур и функций высокого
        уровня, как, например, SetViewPort, Bаr3D, DrаwPoly, до программ,
        ориентированных  на  работу  с  битами,  таких,  как GetImage или
        РutImage. Поддерживается несколько видов закрашивания и типов ли-
        ний, и имеется несколько шрифтов, которые можно изменять по вели-
        чине,  выравнивать и ориентировать горизонтально или вертикально.

             Для компиляции программы,  использующей модуль Grаph, вам не
        потребуется  никаких  внешних файлов (кроме,  конечно,  исходного
        текста вашей программы, компилятора и доступа к стандартным моду-
        лям  в  библиотеке исполняющей системы).

                       Имена библиотек и модуля Graph   Таблица 19.1
            ЪДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДї
            і Тип программы     і Библиотека    і Имя модуля Graph і
            ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДґ
            і Реальный режим    і TURBO.TPL     і GRAPH.TPU        і
            і Защищенный режим  і TPP.TPL       і GRAPH.TPP        і
            АДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДЩ

             Для запуска программы,  использующей модуль Grарh, кроме ва-
        шей программы с расширением .EXE вам потребуются один  или  более
        графических драйверов (см. далее файлы .BGI). Кроме того вам пот-
        ребуется также один или более файлов шрифтов (.CНR), если в вашей
        программе используются какие-либо шрифты.

                   Примечание: В  соответствии  с лицензионными условиями
              вы можете распространять файлы .CHR и .BGI наряду со своими
              программами.

                                    Драйверы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Для перечисленных  ниже  графических  адаптеров  и полностью
        совместимых с ними предусмотрены следующие  графические драйверы:

                         CGA                  Неrcules
                         МСGA                 AT&T 400
                         EGA                  3270 PC
                         VGA                  IBM 8514

             Каждый драйвер  содержит выполняемый код и данные и хранится
        в отдельном файле на диске.  Во время работы процедура  InitGraph
        идентифицирует  графическую  аппаратуру  и  производит загрузку и
        инициализацию соответствующего графического  драйвера,  переводит
        систему в графический режим,  а затем возвращает управление вызы-
        вающей программе. Процедура CloseGraph выгружает драйвер из памя-
        ти  и  восстанавливает предыдущий видеорежим.  С помощью программ
        RеstoreCrtMode и SetGraphMode вы можете переключаться между текс-

         B.Pascal 7 & Objects/LR     - 309 -

        товым и графическим режимом.  См. Главу 1 в "Справочном руководс-
        тве программиста".

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

        ЪДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Драйвер   і           Аппаратура                           і
        ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  CGA.BGI     і Драйвер для адаптеров CGA, MCGA фирмы IBM.     і
        і  EGAVGA.BGI  і Драйвер для адаптеров EGA, VGA фирмы IBM.      і
        і  HERC.BGI    і Драйвер для монохромного адаптера Hercules фир-і
        і              і мы IBM.                                        і
        і  ATT.BGI     і Драйвер для AT&T 6300 (400 строк).             і
        і  PC3270.BGI  і Драйвер для IBM 3270 РС.                       і
        і  IBM8514.BGI і Драйвер для IBM 8514.                          і
        АДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 310 -

                          Поддержка устройства IBM 8514
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Borland Pascal поддерживает графическую плату IBM 8514,  ко-
        торая представляет собой новую графическую плату с высоким разре-
        шением,  позволяющую получить разрешающую способность до 1024х768
        точек  и  палитру,  содержащую  256 оттенков из 256 цветов.  Файл
        драйвера для этой графической платы называется IBM8514.BGI.

             Графическая плата IBM 8514 не может правильно распознаваться
        Borland Pascal  при автоматическом обнаружении (она будет распоз-
        наваться алгоритмами автообнаружения, как плата VGA). Таким обра-
        зом,  чтобы  использовать плату IBM 8514,  переменной GraphDriver
        при вызове InitGraph нужно присвоить  значение  IBM8514  (которое
        определено в модуле Graph).  При работе с платой IBM 8514 не сле-
        дует использовать с InitGraph DetectGraph или DETECT (если только
        вы не хотите эмулировать режим VGA).

            Для платы IBM 8514 поддерживаются следующие режимы: IBM8514LO
        (640х480 элементов изображения) и IBM8514HI  (1024х768  элементов
        изображения). Обе константы режима определены в интерфейсной час-
        ти GRAPH.TPU.

            Для определения цветов в  плате  IBM  8514  используются  три
        6-битовых значения. Для каждого определяемого цвета имеются 6-би-
        товые компоненты Red (красный), Green (зеленый) и Blue (голубой).
        Для того,  чтобы при работе с графической платой IBM 8514 пользо-
        ватель мог задавать цвета, в библиотеку BGI добавлена новая прог-
        рамма.  Эта  программа  определяется в модуле GRAPH.TPU следующим
        образом:

            procedure SetRGBPalette(ColorNum, Red, Green, Blue: Word);

            Аргумент ColorNum задает запись палитры, которую нужно загру-
        зить. Этот аргумент представляет собой целое значение в диапазоне
        от 0 до 255 (дес.). Аргументы Red, Green и Blue определяют компо-
        ненты  цветов в записи палитры.  Используется только младший байт
        этих значений и только 6 старших битов этого байта  загружаются в
        палитру.

            Другие программы,   модифицирующие   палитру  (SetAllPalette,
        SetPalette, GetPalette), при работе с графической платой IBM 8514
        использовать не следует.

            Для совместимости с графическими адаптерами фирмы IBM драйве-
        ры формата BGI определяют для первых 16 цветов палитры  IBM  8514
        значения цветов, принятые по умолчанию для адаптеров EGA/VGA. Эти
        значения могут использоваться в неизмененном виде или модифициро-
        ваться с помощью процедуры SetGRBPalette.



         B.Pascal 7 & Objects/LR     - 311 -

                                Система координат
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             По соглашению верхний левый  угол  экрана  имеет  координату
        (0,0).  У более правого столбца координата х больше, у более ниж-
        ней строки больше координата y. То есть координата х увеличивает-
        ся при перемещении вправо, а координата y - при перемещении вниз.
        Таким образом координаты каждого из четырех  углов  и  конкретной
        точки (середины экрана) будут выглядеть следующим образом:

                         (0,0)                   (319,0)
                            ЪДДДДДДДДДДДДДДДДДДДДДДДї
                            і                       і
                            і       (159,99)        і
                            і           .           і
                            і                       і
                            і                       і
                            і                       і
                            АДДДДДДДДДДДДДДДДДДДДДДДЩ
                          (0,199)                  (319,199)

             Рис. 19.1 Экран с координатами xy.


                                Текущий указатель
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Write('ABC');

         B.Pascal 7 & Objects/LR     - 312 -


             В текстовом режиме  предшествующий  оператор  Write  оставит
        курсор  в  колонке,  непосредственно следующим за буквой C.  Если
        буква C была введена в колонке 80,  то курсор перейдет на колонку
        1 следующей строки. Если буква c была введена в позиции 80 строки
        25, то произойдет пролистывание (прокрутка)  экрана  вверх  на  1
        строку и курсор будет находится в 1 позиции 25 строки.

             MoveTo(0,0);
             LineTo(20,20)

             В графическом режиме данный оператор LinеТо  оставит текущий
        указатель в последней заданной точке (20,20).  Если действует ре-
        жим отсечения,  то реально выводимая прямая будет отсечена до те-
        кущей точки.  Заметим, что текущий указатель никогда не отсекает-
        ся.

             Команда МоvеТо является эквивалентом команды GotoXY.  Единс-
        твенное ее назначение - это перемещение текущего указателя. Пере-
        мещение  текущего указателя может использоваться только в следую-
        щих командах,  использующих текущий указатель: MoveTo, InitGraph,
        MoveRel,  LineTo,  LineRel,  OutText,  SetGraphMode, ClearDevice,
        SetViewPort и ClearViewPort.  Последние 5 из них перемещают теку-
        щий указатель в точку (0,0).

         B.Pascal 7 & Objects/LR     - 313 -

                                      Текст
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

             Когда увеличивается  растровый шрифт,  то матрица умножается
        на масштабный коэффициент,  а когда этот  масштабный  коэффициент
        увеличивается, разрешение у символов становится более грубым. Для
        маленьких шрифтов растровый шрифт должен быть достаточно приемле-
        мым,  но для больших шрифтов вы,  вероятно, захотите выбрать век-
        торный шрифт.

             Выравнивание графического  текста   управляется   процедурой
        SetTextJustify.  Масштабирование  и выбор шрифта осуществляется с
        помощью процедуры SetTextStyle. Графический текст выводится с по-
        мощью  процедур ОutText или ОutTextХY.  Запрос о текущих установ-
        ленных для текста параметрах выполняется с  помощью  обращения  к
        процедуре GetTextSettings. Векторные шрифты хранятся каждый в от-
        дельном файле на диске и должны присутствовать там во время рабо-
        ты (при вызове процедуры SetTextStyle).  Размер векторного шрифта
        можно настроить с помощью процедуры SetUserCharSize.  Файлы шриф-
        тов (которые имеют расширение .CHR) могут загружаться с диска ав-
        томатически модулем Graph,  или их можно компоновать с программой
        пользователя  или  загружать  и "регистрировать" с помощью модуля
        Graph.

             Для преобразования файла шрифта (или любого другого предназ-
        наченного для этой цели двоичного файла данных) в файл .OBJ,  ко-
        торый можно компоновать с модулем или программой с помощью дирек-
        тивы компилятора  $L  в  Borland Pascal предусмотрена специальная
        утилита BINOBJ.EXE.  При этом становится возможным поместить  все
        файлы  шрифтов в выполняемый файл .EXE (см.  комментарии в начале
        примера программы BGILINK.PAS на дистрибутивном диске).

         B.Pascal 7 & Objects/LR     - 314 -

                        Графические изображения и их виды
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Для закрашивания  области  или многоугольника пересекающейся
        штриховкой или чем-либо более сложным можно использовать процеду-
        ры SetFillStyle, SetFloodPattern, FillPoly и FloodFill.

                       Области просмотра и двоичные образы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Для считывания  и вывода элементов изображения предусмотрены
        процедуры GetPixel и Putpixel.  Чтобы сохранить и восстановить на
        экране   прямоугольную   область,  можно  использовать  процедуры
        GetImage и PutImage.  Они обеспечивают полное выполнение операций
        процедуры ВitВlt (нормальное, хоr, оr, аnd, nоt).



         B.Pascal 7 & Objects/LR     - 315 -

                           Поддержка страниц и цветов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Имеется много других поддерживающих программ,  включая  под-
        держку  для  нескольких графических страниц (только для адаптеров
        EGA,  VGA и Неrcules;  это особенно полезно при  использовании  в
        мультипликации), палитры, цвета и так далее.

                                Обработка ошибок
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Внутренние ошибки   модуля   Graph   возвращаются   функцией
        GraphResult. Эта функция возвращает код ошибки, показывающий сос-
        тояние последней графической операции.  Коды  возврата  приведены
        в разделе  по  GraphResult в Главе 1 ("Справочник по библиотеки")
        "Справочного руководства программиста".

             Значение кода  возврата для функции GraphResult устанавлива-
        ется следующими процедурами:

              DetectGraph         SetTextStile          SetAllPalette
              InitGraph           SetGraphMode          SetFillPattern
              FloodFill           CloseGraph            SetFillStyle
              FillPoly            GetGraphMode          SetGraphBufSize
              DrawPoly            ImageSize             SetGraphMode
              Bar                 InstallUserDriver     SetLineStyle
              Bаr3D               InstallUserFont       SetPalette
              PieSlice            RegisterBGIDriver     SetTextJustify
              ClearViewPort       RegisterGBIFont

             Заметим, что функция GraphResult после обращения к ней сбра-
        сывает код ошибки в 0.  Таким образом, пользователь должен сохра-
        нить значение кода ошибки во временной переменной и затем  прове-
        рить его.



         B.Pascal 7 & Objects/LR     - 316 -

                                  Начало работы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Приведем пример простой графической программы:

             1 program GraphTest;
             2 uses
             3   Graph;
             4 var
             5   GraphDriver  : integer;
             6   GraphMode    : integer;
             7   ErrorCode    : integer;
             8 begin
             9   GraphDriver := Detect;    { Установить флаг: выполнить
                                             распознавание }
             10  InitGraph(GraphDriver, GraphMode, 'C:\DRIVERS');
             11  ErrorCode := GraphResult;
             12  if ErrorCode <> grOk then  { ошибка? }
             13  begin
             14    Writeln('Ошибка графики: ',GraphErrorMsg(ErrorCode);
             15    Writeln('Программа аварийно завершила работу...');
             16    Halt(1);
             17  end;
             18  Rectangle(0, 0, GetMaxX, GetMaxY); { нарисовать  рамку
                                                     размером в экран }
             19  SetTextJustify(CenterText, CenterText); {  центрирова-
                                                     ние текста }
             20  SetTextStyle(DefaultFont, HorizDir, 3);
             21  OutTextXY(GetMaxX div 2, GetMaxY div 2, { центр экрана }
             22         'Графический интерфейс фирмы Borland (BGI)');
             23  Readln;
             24  CloseGraph;
             25 end. { GraphTest }

             Программа начинается с обращения к процедуре InitGraph,  ко-
        торая автоматически проверяет наличие аппаратуры и загружает  со-
        ответствующий  графический  драйвер  (находящийся  в  каталоге C:
        DRIVERS). Если графическая аппаратура не распознана или в процес-
        се инициализации произошла ошибка,  то на экран выводится сообще-
        ние об ошибке и программа прекращает работу.  В противном  случае
        вдоль краев экрана рисуется прямоугольник и в центре экрана выво-
        дится текст.

             Плата AT&T  400  или IBM 8514 не распознается автоматически.
        Тем не менее, вы можете пользоваться драйвером графики AT&T путем
        отмены автоматической проверки, пересылки исполняемого кода драй-
        вера AT&T процедуре InitGraph и установки допустимого графическо-
        го режима.  Замените 8 и 9 строку в предыдущем примере следующими
        тремя строками:

             GraphDriver := ATT400;
             GraphMode := ATT400Hi;
             InitGraph(GraphDriver, GraphMode, 'C:\BP\BGI');

         B.Pascal 7 & Objects/LR     - 317 -


             Это укажет  графической  системе  на  необходимость загрузки
        драйвера устройства AT&T400, расположенного в каталоге C:\BP\BGI,
        и установит графический режим 640 на 400.

             Приведем еще один пример,  который показывает, как можно пе-
        реключаться между графическим и текстовым режимами:

             1 program GraphTest;
             2 uses
             3   Graph;
             4 var
             5   GraphDriver  : integer;
             6   GraphMode    : integer;
             7   ErrorCode    : integer;
             8 begin
             9   GraphDriver := Detect;    { Установить флаг: выполнить
                                             распознавание }
             10  InitGraph(GraphDriver, GraphMode, 'C:\DRIVERS');
             11  ErrorCode := GraphResult;
             12  if ErrorCode <> grOk then  { ошибка? }
             13  begin
             14    Writeln('Ошибка графики: ',GraphErrorMsg(ErrorCode);
             15    Writeln('Программа аварийно завершила работу...');
             16    Helt(1);
             17  end;
             18  OutText('Графический режим. Нажмите ');
             19  Readln;
             20  RestoreCrtMode;
             21  Write('Текстовый режим. Нажмите ');
             22  Readln;
             23  SetGraphMode(GraphMode);
             24  OutText('Снова графический режим. Нажмите ');
             25  Readln;
             26  CloseGraph;
             27 end. { GraphTest }

             Заметим, что вызов процедуры SetGraphMode на строке 23 сбра-
        сывает все графические параметры (палитра, текущий указатель, ос-
        новной  и  фоновый  цвета  и т.д.) и им присваиваются принятые по
        умолчанию значения.

             Вызов CloseGraph  восстанавливает первоначально обнаруженный
        видеорежим (InitGraph) и освобождает память,  используемую графи-
        ческим драйвером.



         B.Pascal 7 & Objects/LR     - 318 -

                           Пользовательские программы
                  управления динамически распределяемой памятью
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Для модуля  Graph предусмотрены две программы управления ди-
        намически распределяемой  областью  GraphFrееМем  и  GraphGetМем.
        Первая из них освобождает память, распределенную для драйверов, а
        вторая - распределяет память для драйверов графических устройств.
        Стандартные программы имеют следующий вид:

             procedure GraphGetMem(var P : Pointer; Size : word);
                { выделить память для драйверов графических устройств }

             procedure GraphFreeMem(var P : Pointer; Size : word);
                { освободить память для драйверов графических устройств }

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

             var
               GraphGetMemPtr  : pointer;
                  { указатель на программу распределения памяти }
               GraphFreeMemPtr : pointer;
                  { указатель на программу освобождения памяти }

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

             * для многоцелевых графических буферов, размер которых уста-
               навливается вызовов SegGraphBufSize (по умолчанию это 4К);

             * для  драйвера  устройства,  загружаемого  InitGraph (файлы
               *.BGI);

             * для файла  векторного  шрифта,  загруженного  SetTextStyle
               (файлы *.CHR).

             Графический буфер  всегда выделяется в динамически распреде-
        ляемой области памяти.  Память для драйвера устройства выделяется
        в динамической  памяти,  если  программа  не загружает его или не
        компонуется с ним вызовом RegisterBGIdriver. При выборе векторно-
        го шрифта  с помощью SetTextStyle также выделяется память в дина-
        мически распределяемой области (если ваша программа не компонует-
        ся со шрифтом и не использует RegisterBGIfont).

             Чтобы задать  ваше собственное управление памятью,  в модуле
        Graph вы можете изменить значения этих указателей так,  чтобы они
        ссылались  на  ваши  собственные программы.  Программы,  заданные
        пользователем, должны иметь тот же список параметров, что и стан-
        дартные  программы,  и должны иметь дальний тип вызова.  Приведем

         B.Pascal 7 & Objects/LR     - 319 -

        далее пример заданных пользователем программ распределения и  ос-
        вобождения памяти.  Заметим, что при использовании процедуры Eхit
        автоматически вызывается процедура CloseGraph.

              program UserHeapManegement;
              { программа показывает,  как пользователь может работать  с
                подпрограммами  управления динамически распределяемой об-
                ластью памяти, используемыми в модуле Graph }
              uses
                 Graph;
              var
                 GraphDriver, GraphMode : Integer;
                 ErrorCode              : Integer; { используется для
                           сохранения кода возврата функции GraphResult }
                 PreGraphExitProc       : Pointer { используется для сох-
                           ранения исходной процедуры выхода }
                 { процедуры пользователя должны использовать дальний тип
                   обращения }
                  procedure MyGetMem(var P : Pointer; Size : word); far;
                 { выделить память для драйверов графических устройств }
               begin
                 Write('Была вызвана процедура ',
                        'MyGetMem, нажмите :');
                 GetMem(P, Size);
               end; { MyGetMem }

               procedure MyFreeMem(ver P : Pointer; Size : word); far;
               { освободить память, занятую драйверами графических
                 устройств }
               begin
                 RestoreCRTMode;
                 Write('Была вызвана процедура MyFreeMem, нажмите ',
                        ':'); Readln;
                 if P <> Nil Then { не освобождать пустые указатели }
                 begin
                   FreeMem(P, Size);
                   P := Nil;
                 end; { MyFreeMem }

              procedure MyExitProc; far;
              { процедура всегда получает вызов при прекращении работы
                программы }
              begin
                ExitProc := PreGraphExitProc; { восстановить исходную
                                                процедуру выхода }
                CloseGraph;         { очистить динамически распределяемую
                                      область }
              end; { MyExitProc }

              begin
              { инициализировать программу очистки памяти }
                 PreGraphExitProc := ExitProc;
                 ExitProc := @MyExitProc;

         B.Pascal 7 & Objects/LR     - 320 -

                 GraphGetMemPtr := @MyGetMem ; { заменить распределение
                                                 памяти }
                 GraphFreeMemPtr := @MyFreeMem ; { заменить освобождение
                                                 памяти }
                 GraphDriver := Detect;
                 InitGraph(GraphDriver, GraphMode, '');
                 ErrorCode := GraphResult;
                 if ErrorCode <> grOk then
               begin
                Writeln('Графическая ошибка: ' GraphErrorMsg(ErrorCode);
                Readln;
                Halt(1);
               end;
               Line(0, 0, GetMaxX, GetMaxY);
               OutText(1, 1, 'Нажмите клавишу :');
               Readln;
              end. { UserHeapManegement }

             Если целевой  платформой  является защищенный режим DOS,  то
        при использовании подобных программ следует иметь в виду  следую-
        щее: вы  должны обеспечить,  что любой возвращаемый GetMem указа-
        тель должен иметь нулевое смещение.  Сделать это можно с  помощью
        функции GlobalAllocPtr:

             procedure MyGetMem(var P: Pointer; Size: Word); far;
             var
                P: Pointer;
             bagin
                P:= GlobalAllocPtr(HeapAllocFlags, Size);
                GetMem(P, 4096);
             end;  { MyGetMem }



         B.Pascal 7 & Objects/LR     - 321 -

                             Процедуры модуля Graph
                                                             Таблица 19.3
        ЪДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і   Подпрограмма    і                   Описание                і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Arс              і Рисует дугу окружности от  начального углаі
        і                   і до конечного угла;  точка (x,y) берется  ві
        і                   і качестве центра окружности.               і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Bаr              і Рисует столбец, используя текущий тип зак-і
        і                   і раски.                                    і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Bаr3D            і Рисует  трехмерный  столбец, используя те-і
        і                   і кущий тип закраски.                       і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Circlе           і Рисует окружность с центром в точке (x,y).і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  ClearDeviсе      і Сбрасывает  текущие параметры, установлен-і
        і                   і ные для устройства вывода, и подготавлива-і
        і                   і ет его для вывода.                        і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  ClearViewPort    і Очищает  текущую  область  просмотра (окноі
        і                   і экрана).                                  і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  CloseGraph       і Выполняет останов графической системы.    і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  DetectGraph      і Распознает аппаратуру и определяет,  какойі
        і                   і графический драйвер  и режим нужно исполь-і
        і                   і зовать.                                   і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  DrawPoly         і Рисует  многоугольник,  используя  текущийі
        і                   і тип линии и цвет.                         і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Ellipse          і Рисует  эллиптическую  дугу от  начальногоі
        і                   і угла до конечного угла,  использую  (Х,Y),і
        і                   і как точку центра.                         і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  FillPoly         і Закрашивает  многоугольник, используя пре-і
        і                   і образователь развертки.                   і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  FloodFill        і Закрашивает  ограниченную область, исполь-і
        і                   і зуя текущий образец закраски.             і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetArcCoords     і Позволяет  пользователю  запрашивать коор-і
        і                   і динаты последней команды Arс.             і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetAspectRatio   і Возвращает действующее  разрешение графи- і
        і                   і ческого экрана,  на  основе которого можеті
        і                   і быть вычислен  коэффициент  относительногоі
        і                   і удлинения (Хаsр,Yаsр).                    і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetBkСоlor       і Возвращает текущий фоновый цвет.          і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ

         B.Pascal 7 & Objects/LR     - 322 -

        і  GetCоlor         і Возвращает текущий цвет рисунка.          і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetDefaultPaletteі В записи типа  PaletteType  возвращает ис-і
        і                   і пользуемую по умолчанию палитру.          і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetDriverName    і Возвращает  строку,   содержащую   имя те-і
        і                   і кущего драйвера.                          і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetFillPattern   і Возвращает  последний образец заполнителя,і
        і                   і установленный с помощью обращения к проце-і
        і                   і дуре SetFillPattern.                      і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetFillSetting   і Позволяет  пользователю выполнить запрос оі
        і                   і текущем образце и цвете закраски, установ-і
        і                   і ленными  с помощью процедур SetFillStyle иі
        і                   і SetFillPattern.                           і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetImage         і Сохраняет  двоичный образ заданной областиі
        і                   і в буфере.                                 і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetGraphMode     і Возвращает текущий графический режим.     і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetLineSettings  і Возвращает текущий тип линии,  образец ли-і
        і                   і нии и толщину линии,  заданные  процедуройі
        і                   і SetLineStyle.                             і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetMaxColor      і Возвращает  максимальное  значение  цвета,і
        і                   і которое можно передать процедуре SetColor.і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetMAxMode       і Возвращает  максимальный  номер режима дляі
        і                   і текущего загруженного драйвера.           і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetМахХ          і Возвращает для текущего графического драй-і
        і                   і вера и режима самую правую колонку (разре-і
        і                   і шение по х).                              і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetМахY          і Возвращает для текущего графического драй-і
        і                   і вера и режима самую нижнюю строку  (разре-і
        і                   і шение по у).                              і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetPaletteSize   і Возвращает размер таблицы просмотра палит-і
        і                   і ры.                                       і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetPixel         і Возвращает значение элемента изображения ві
        і                   і точке Х,Y.                                і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetPalette       і Возвращает текущую палитру и  ее размер.  і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetTextSettings  і Возвращает текущий текстовый  шрифт,  нап-і
        і                   і равление, размер и выравнивание для  него,і
        і                   і установленные     с    помощью    процедурі
        і                   і SetTextStyle и SetTextJustify.            і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ

         B.Pascal 7 & Objects/LR     - 323 -

        і  GetViewSettings  і Позволяет пользователю выдать запрос о те-і
        і                   і кущей области изображения и параметрах от-і
        і                   і сечения изображения.                      і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetХ             і Возвращает  координату   Х текущей позицииі
        і                   і (текущего указателя).                     і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GetY             і Возвращает  координату  Y  текущей позицииі
        і                   і (текущего указателя).                     і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GraphErrorMsg    і Для заданного кода ошибки возвращает стро-і
        і                   і ку сообщения об ошибке.                   і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  GraphResult      і Возвращает   код ошибки для последней гра-і
        і                   і фической операции.                        і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  InitGraph        і Инициализирует  графическую  систему и пе-і
        і                   і реводит аппаратуру в графический режим.   і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  ImageSize        і Возвращает число  байт,  которые  требуют-і
        і                   і ся для  сохранения  прямоугольной  областиі
        і                   і экрана.                                   і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  InstallUserDriverі Устанавливает  добавленный   пользователемі
        і                   і драйвер в таблице драйверов устройств BGI.і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  InstallUserFont  і Устанавливает новый файл шрифта, не встро-і
        і                   і енный в графическую систему.              і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  InitGraph        і Инициализирует графическую систему и пере-і
        і                   і водит аппаратные  средства  в  графическийі
        і                   і режим.                                    і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Line             і Рисует  прямую  линию  из  точки (x1,y1) ві
        і                   і (x2,y2).                                  і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  LineRel          і Рисует прямую линию  до  точки,  представ-і
        і                   і ляющей собой  относительное  расстояние оті
        і                   і текущего указателя.                       і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  LinеTо           і Рисует   линию  из  текущего  положения  ві
        і                   і точку (x,y).                              і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  МоveRеl          і Перемещает  текущий  указатель на расстоя-і
        і                   і ние, являющееся относительным  расстояниемі
        і                   і от текущей позиции.                       і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  МоvеТо           і Перемещает   текущий   указатель  в  точкуі
        і                   і (x,y).                                    і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  ОutText          і Посылает  строку на устройство вывода, на-і
        і                   і чиная с текущего указателя.               і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ

         B.Pascal 7 & Objects/LR     - 324 -

        і  ОutTextХY        і Посылает строку на устройство вывода.     і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  PieSlice         і Рисует сектор.  Точка (Х,Y) используется ві
        і                   і качестве центра,  а сектор рисуется от на-і
        і                   і чального до конечного угла.               і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  РutImagе         і Выводит на экран двоичный образ.          і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  РutРiхеl         і Строит элемент изображения в точке x,y.   і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  Rесtanglе        і Рисует  прямоугольник,  используя  текущийі
        і                   і тип линии и цвет.                         і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  RegisterBGIDriverі Регистрирует  допустимый  драйвер (форматаі
        і                   і BGI) в графической системе.               і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  RegisterBGIFont  і Регистрирует в графической  системе допус-і
        і                   і тимый (формата BGI) шрифт.                і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  RеstoreCRTМоdе   і Восстанавливает  исходный  режим   экрана,і
        і                   і который был  установлен  при инициализацииі
        і                   і графики.                                  і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetActivePage    і Устанавливает для  графического вывода ак-і
        і                   і тивную страницу.                          і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetAllPalette    і Изменяет  все цвета палитры, как было ука-і
        і                   і зано.                                     і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetAspectRatio   і Изменяет принятый по умолчанию коэффициенті
        і                   і относительного удлинения.                 і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetBkСоlor       і Используя палитру,  устанавливает  текущийі
        і                   і фоновый цвет.                             і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetColor         і Используя палитру,  устанавливает  текущийі
        і                   і цвет рисунка.                             і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetFillPattern   і Выбирает образец закраски,  заданный поль-і
        і                   і зователем.                                і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetFillStyle     і Устанавливает образец закраски и ее цвет. і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetGraphBufSize  і Позволяет изменить размер  буфера, исполь-і
        і                   і зуемого для опроса и закраски.            і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetGraphMode     і Переключает  систему  в  графический режимі
        і                   і и очищает экран.                          і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetLineStyle     і Устанавливает  текущий  тип линии и ее ши-і
        і                   і рину.                                     і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetPalette       і Изменяет  один  цвет палитры, заданный пе-і

         B.Pascal 7 & Objects/LR     - 325 -

        і                   і ременными Colornum и Color.               і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetGRBPalette    і Позволяет  модифицировать   записи  палит-і
        і                   і ры для драйверов IBM 8514 и VGA.          і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetTextJustify   і С  помощью  ОutTеxt   и  ОutTехtХY   уста-і
        і                   і навливает значения для выравнивания  текс-і
        і                   і та.                                       і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetTextStyle     і Задает  текущий текстовый шрифт, его тип иі
        і                   і коэффициент размера символа.              і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetUserCharSize  і Позволяет вам для  векторных  шрифтов  из-і
        і                   і менить высоту и ширину символа.           і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetViewPort      і Для  графического   вывода   устанавливаеті
        і                   і текущую область вывода или окно.          і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetVisualPage    і Задает  визуальный номер графической стра-і
        і                   і ницы.                                     і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  SetWriteMode     і Устанавливает  режим вывода на экран  (ко-і
        і                   і пирование или с помощью операции XOR)  дляі
        і                   і линий, вычерчиваемых процедурами DrawPoly,і
        і                   і Line, LineRel, LineTo, Rectangle.         і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  TехtНеight       і Возвращает  высоту  страниц  в   элементахі
        і                   і изображения.                              і
        ГДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  TехtWidth        і Возвращает  ширину   строки  в   элементахі
        і                   і изображения.                              і
        АДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Подробное описание каждой процедуры и функции дано в Главе 1
        ("Справочник по библиотеке") "Справочного руководства программис-
        та".



         B.Pascal 7 & Objects/LR     - 326 -

                    Константы, типы и переменные модуля Graph
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В модуле Graph имеется много полезных описаний типов и конс-
        тант, на которое вы можете ссылаться.

                                    Константы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Константы модуля Graph можно сгруппировать по их назначению.
        Подробное описание каждой константы дано в Главе  1  ("Справочник
        по библиотеке") "Справочного руководства программиста".

                           Группы констант модуля Graph      Таблица 19.4
        ЪДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Группа констант      і           Описание                  і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Константы драйверов   і Константы, определяющие видеодрайве-і
        і   и режимов             і ры и режимы; используются в подпрог-і
        і                         і раммах   InitGraph,   DetectGraph  иі
        і                         і GetModeRange.                       і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   grXXXX                і Константы,   идентифицирующие    типі
        і                         і ошибки, возвращаемой GraphResult.   і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Константы цветов      і Константы,  определяющие  цвета. Ис-і
        і                         і пользуются в           подпрограммахі
        і                         і SetPalette и SetAllPalette.         і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Константы цветов      і Константы, используемые  в  подпрог-і
        і   для SetRGBPalette     і рамме SetGRBPalette  для  выбора  наі
        і                         і IBM 8514 стандартных цветов EGA.    і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Константы стиля       і Константы, используемые для  опреде-і
        і   линии                 і ления стиля и толщины линии; исполь-і
        і                         і зуются с      GetLineSettings      иі
        і                         і SetLineStyle.                       і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Константы шрифта      і Используются для идентификации шриф-і
        і                         і тов в  подпрограммах GetTextSettingsі
        і                         і и SetTextSetting.                   і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Константы выравниванияі Константы, управляющие  горизонталь-і
        і                         і ным и   вертикальным  выравниванием.і
        і                         і Используются в SetTextJustify.      і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Константы отсечений   і Константы,  управляющие  отсечением.і
        і                         і Используются в SetViewPort.         і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Константы столбцов    і Управляют   изображением   "вершины"і
        і                         і трехмерного столбца;  используются ві
        і                         і Bar3D.                              і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ

         B.Pascal 7 & Objects/LR     - 327 -

        і   Образцы закраски      і Определяют образец закраски области.і
        і                         і Используются в   GetFillSettings   иі
        і                         і SetFillStyle.                       і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   Операции BitBlt       і Операции (копирование, xor, or, and,і
        і                         і not), которые     используются     ві
        і                         і PutImage и SetWriteMode.            і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   MaxColors             і Константы, определяющие максимальноеі
        і                         і число цветов      в      GetPalette,і
        і                         і GetDefaultPalette и SetAllPalette.  і
        АДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 328 -

                                      Типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В модуле Graph определены следующие типы:

                                Типы модуля Graph            Таблица 19.5
        ЪДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і         Тип            і               Описание               і
        ГДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   PaletteType          і Запись, определяющая  размер и  цветаі
        і                        і палитры; используется  в  GetPalette,і
        і                        і GetDefaultPalette и SetAllPalette.   і
        ГДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   LineSettingsType     і Запись, определяющая стиль, образец иі
        і                        і толщину линии; используетcя          і
        і                        і GetLineSettings.                     і
        ГДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FillSettingsType     і Запись, определяющая текст. Использу-і
        і                        і ется в GetTextSettings.              і
        ГДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   FillPatternType      і Запись, определяющая  заданный  поль-і
        і                        і зователем образец   закраски.  Даннаяі
        і                        і запись    используется    процедурамиі
        і                        і GetFillPattern и SetFillPattern.     і
        ГДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   PointType            і Тип,  определенный для вашего удобст-і
        і                        і ва.                                  і
        ГДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   ViewPortType         і Запись, сообщающая о состоянии  теку-і
        і                        і щей области  просмотра;  используетсяі
        і                        і GetViewSettings.                     і
        ГДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   ArcCoordsType        і Запись  для  получения  информации  оі
        і                        і последнем вызове Arc или Ellipse; ис-і
        і                        і пользуется GetArcCoords.             і
        АДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                                   Переменные
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Модуль Graph содержит две переменные,  которые вы можете ис-
        пользовать: GraphGetMemPtr и GraphFreeMemPtr.  Они применяются  в
        подпрограммах управления  динамически распределяемой областью па-
        мяти. Прочитать о них можно в Главе 1 ("Справочник  по  библиоте-
        ке") "Справочного руководства программиста".



         B.Pascal 7 & Objects/LR     - 329 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                        Глава 20. Использование оверлеев
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Оверлеи полезны только в программах  DOS  реального  режима.
        Поскольку для программ  Windows памятью управляет сама Windows, а
        для программ защищенного режима - администратор этапа  выполнения
        (RTM.EXE), эти  средства включают в себя полный механизм обслужи-
        вания оверлеев,  и в программах Windows и программах  защищенного
        режима необходимость использования оверлеев отпадает.

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

             Borland Pascal управляет оверлеями на уровне модулей,  кото-
        рые являются наименьшей частью программы, образующей оверлей. При
        компиляции   программы,  имеющей  оверлейную  структуру,  Borland
        Pascal генерирует наряду с выполняемым файлом (который имеет рас-
        ширение  .EXE) оверлейный файл (имеющий расширение .OVR).  Файл с
        расширением .EXE содержит статические (не оверлейные) части прог-
        раммы,  а файл с расширением .OVR содержит все оверлейные модули,
        которые при выполнении программы будут подкачиваться в память или
        выводиться из нее на диск.

             За исключением нескольких правил,  касающихся его программи-
        рования,  оверлейный модуль полностью идентичен неоверлейному мо-
        дулю. Фактически, если вы соблюдаете эти правила, у вас нет необ-
        ходимости  перекомпилировать  модуль,  чтобы  образовать  из него
        оверлей. Решение о том, будет модуль оверлейным или нет, принима-
        ется программой, которая использует данный модуль.

            При загрузке  оверлеев  в  память они помещаются в оверлейный
        буфер, который размещается в памяти между сегментом стека и дина-
        мически распределяемой областью памяти. По умолчанию для оверлей-
        ного буфера выбирается минимальный возможный размер,  но во время
        выполнения  программы  его размер может быть легко увеличен путем
        выделения дополнительной области памяти из динамически  распреде-
        ляемой области. Аналогично сегменту данных и минимальному размеру
        динамически распределяемой области, оверлейный буфер принятого по
        умолчанию размера выделяется при загрузке файла .EXE. При отсутс-
        твии памяти необходимого объема модулем Dos  или  интегрированной
        программной средой  IDE  будет  выводиться  сообщение  об  ошибке
        (Program  too  big  to fit in memory - "Программа слишком велика,
        чтобы разместиться в памяти")  или  (Not  enough  memory  to  run
        program - "Для запуска программы не хватает памяти").

         B.Pascal 7 & Objects/LR     - 330 -


             Одной из очень  важных  возможностей  подсистемы  управления
        оверлеями  является  возможность  при наличии достаточного прост-
        ранства загружать  оверлейный  файл в дополнительную память.  Для
        этой цели в Borland Pascal поддерживается средство расширения па-
        мяти  EMS  (Lotus/Intel/Microsoft Expanded Memory Specification).
        При размещении оверлейного файла в  памяти  EMS  все  последующие
        загрузки оверлеев сводятся к быстрой передаче информации из памя-
        ти в память.

                             Администратор оверлеев
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Администратор оверлеев (или подсистема управления оверлеями)
        Borland Pascal реализуется с помощью стандартного модуля Overlay.
        В модуле Overlay используются усовершенствованные методы управле-
        ния буферами, что обеспечивает оптимальное выполнение программы в
        имеющейся области памяти. Например, подсистема управления оверле-
        ями сохраняет в оверлейном буфере столько оверлеев,  сколько воз-
        можно. Это позволяет уменьшить частоту считывания оверлеев с дис-
        ка.  После загрузки оверлея вызов одной из его подпрограмм выпол-
        няется также быстро, как обращение к неоверлейной программе. Кро-
        ме того,  когда у администратора оверлеев возникает необходимость
        вывести один оверлей, чтобы освободить место для другого, он сна-
        чала пытается вывести те оверлеи,  которые не являются  активными
        (то есть те, которые в данный момент времени не содержат активных
        программ).

             Для реализации  улучшенных  методов   управления   оверлеями
        Borland Pascal требует от вас при написании программы,  в которой
        используются оверлеи, соблюдать два важных правила:

             1.  Все оверлейные модули должны содержать  директиву {$O+},
                 приводящую к тому, что компилятор обеспечивает генериро-
                 вание оверлейного кода.

             2.  При  каждом обращении к оверлейной процедуре или функции
                 вы должны обеспечить использование всеми активными  про-
                 цедурами и функциями вызовов типа FAR (дальний тип вызо-
                 ва).

             Оба правила будут поясняться далее в разделе  под заголовком
        "Разработка оверлейных программ".  Сейчас мы просто отметим,  что
        вы можете легко удовлетворить  эти  правила,  поместив  в  начале
        оверлейных  модулей  директиву  компилятора {$O+,F+},  а в начале
        всех других модулей и основной программы - директиву {$F+}.

                   Примечание: Несоблюдение  требования обеспечения даль-
              него типа вызова в оверлейной программе вызовет  непредска-
              зуемые  и возможно катастрофические результаты при выполне-
              нии программы.

             Директива компилятора  {$O  имя_модуля} используется в прог-

         B.Pascal 7 & Objects/LR     - 331 -

        рамме для указания того,  какой из модулей будет оверлейным.  Эта
        директива должна размещаться за оператором uses программы, в кото-
        ром перед именами всех других оверлейных  модулей  должно  указы-
        ваться  имя стандартного модуля Overlay.  Приведем следующий при-
        мер:

             program Editor;
             {$F+}           { Все процедуры и функции будут использовать
                               дальний тип вызова }
             uses
               Overlay, Crt, Dos, EdInOut, EdFormat, EdPrint, EdFind,
                EdMain;
             {$O EdInOut }
             {$O EdFormat }
             {$O EdPrint }
             {$O EdFind }
             {$O EdMain }

             Если вы  пытаетесь  использовать  в качестве оверлейного мо-
        дуль, при компиляции которого не была указана директива {$O+}, то
        компилятор выведет сообщение об ошибке.  Что касается стандартных
        модулей, то оверлейным может быть только модуль Dos. Другие стан-
        дартные  модули не могут использоваться в качестве оверлейных.  К
        тому же программы,  содержащие оверлейные модули, при использова-
        нии IDE реального режима должны компилироваться на диск.  Если вы
        пытаетесь выполнить компиляцию таких программ в память, то компи-
        лятор выводит сообщение об ошибке.

                          Управление оверлейным буфером
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Оверлейный буфер Borland Pascal лучше  всего  описывается  в
        виде кольцевого буфера, в котором имеется указатель начала и ука-
        затель конца.  Оверлеи всегда загружаются в  начало  буфера.  При
        этом  более  "старые" оверлеи смещаются к его концу.  Когда буфер
        заполняется (то есть между его началом и концом не  будет  доста-
        точно свободного пространства),  то оверлеи в конце буфера выгру-
        жаются (освобождаются), и освобождается место для новых оверлеев.

             Поскольку обычная память по своей природе не имеет характера
        кольцевого буфера,  действительная реализация  кольцевого  буфера
        предусматривает несколько  шагов,  обеспечивающих,  чтобы   буфер
        действительно стал кольцевым.  Этот процесс показан на Рис. 20.1.
        Здесь изображен процесс загрузки оверлеев в  первоначально пустой
        оверлейный буфер.  Сначала загружается оверлей A, затем - оверлей
        B, потом C, и, наконец, D. Заштрихованные области показывают сво-
        бодное пространство в буфере.


         B.Pascal 7 & Objects/LR     - 332 -


                               Шаг 1                         Шаг 2
                           ЪДДДДДДДДДДДДї               ЪДДДДДДДДДДДДї
                           і °°°°°°°°°° і               і °°°°°°°°°° і
                           і °°°°°°°°°° і               і °°°°°°°°°° і
                           і °°°°°°°°°° і               і °°°°°°°°°° і
                           і °°°°°°°°°° і   Начало ДДД> ГДДДДДДДДДДДДґ
                           і °°°°°°°°°° і               і  Оверлей B і
              Начало ДДДД> ГДДДДДДДДДДДДґ               ГДДДДДДДДДДДДґ
                           і  Оверлей А і               і  Оверлей А і
              Конец  ДДДД> АДДДДДДДДДДДДЩ   Конец  ДДД> АДДДДДДДДДДДДЩ


                               Шаг 3                         Шаг 4
                           ЪДДДДДДДДДДДДї               ЪДДДДДДДДДДДДї
                           і °°°°°°°°°° і               і  Оверлей С і
                           і °°°°°°°°°° і               ГДДДДДДДДДДДДґ
              Начало ДДДД> ГДДДДДДДДДДДДґ               і  Оверлей В і
                           і  Оверлей С і   Конец  ДДД> ГДДДДДДДДДДДДґ
                           ГДДДДДДДДДДДДґ               і °°°°°°°°°° і
                           і  Оверлей В і               і °°°°°°°°°° і
                           ГДДДДДДДДДДДДґ   Начало ДДД> ГДДДДДДДДДДДДґ
                           і  Оверлей А і               і  Оверлей D і
              Конец  ДДДД> АДДДДДДДДДДДДЩ               АДДДДДДДДДДДДЩ

             Рис. 20.1 Загрузка и освобождение оверлеев.

             Как можно заметить, при переходе от шага 3 к шагу 4 происхо-
        дит несколько  интересных моментов.  Во-первых,  заголовок начала
        перемещается к концу оверлейного буфера, приводя к тому, что под-
        система управления  оверлеями  смещает все загруженные оверлеи (и
        указатель конца) вверх.  Это смещение необходимо, чтобы свободная
        область всегда  находилась  между  указателем начала и указателем
        конца. Во-вторых,  чтобы загрузить оверлей D, подсистеме управле-
        ния оверлеями  приходится выгрузить из конца буфера оверлей A.  В
        этом случае оверлей A является  оверлеем,  которых  был  загружен
        раньше всех,  поэтому  прежде чем продолжить работу,  лучше всего
        выгрузить именно его.  Администратор оверлеев продолжает освобож-
        дать  оверлеи  в конце буфера,  освобождая место в его начале для
        новых оверлеев. При этом каждый раз повторяется операция смещения
        и переноса указателя начала.

             Этот режим  операция  используется  администратором оверлеев
        Borland Pascal 0 по умолчанию.  Однако, Borland Pascal также поз-
        воляет  вам использовать возможность оптимизации алгоритма управ-
        ления оверлеями.

             Предположим, что оверлей A содержит некоторые часто  исполь-
        зуемые подпрограммы. Хотя некоторые из этих подпрограмм использу-
        ются все время,  существует  вероятность,  что  оверлей  A  будет
        выгружен из буфера и вскоре загружен в него снова. Проблема здесь
        состоит в том, что подсистема управления оверлеями ничего не зна-
        ет о  частоте  вызовов подпрограмм в модуле A.  Она знает только,

         B.Pascal 7 & Objects/LR     - 333 -

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

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

             Схема тестирования (проб/отказов) приводит к тому, что часто
        используемые  оверлеи  будут  сохраняться  в оверлейном буфере за
        счет того,  что будет перехватываться почти каждый  вызов,  когда
        оверлей приближается к концу оверлейного буфера.

             Механизмом тестирования  управляют  две  новые  подпрограммы
        подсистемы управления  оверлеями  -  OvrSetRetry  и  OvrGetRetry.
        Подпрограмма OvrGetRetry устанавливает размер области в  оверлей-
        ном буфере,  которую нужно тестировать,  а OvrGetRetry возвращает
        текущее состояние. Если оверлей смещается в последние OvrGetRetry
        байт перед  концом оверлейного буфера,  то он будет автоматически
        подвергаться тестированию.  Все свободное пространство в оверлей-
        ном буфере рассматривается,  как часть пробной  области  (области
        тестирования).



         B.Pascal 7 & Objects/LR     - 334 -

                       Процедуры и функции модуля Overlay
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В модуле Overlay определяются несколько процедур и  функций.
        Полные их описания вы можете найти в Главе 1 ("Справочник по биб-
        лиотеке") "Справочного руководства программиста".

                       Процедуры и функции модуля Overlay    Таблица 20.1
        ЪДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і    Подпрограмма         і                Описание             і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   OvrClearBuf           і Очищает оверлейный буфер.           і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   OvrGetBuf             і Возвращает текущий размер оверлейно-і
        і                         і го буфера.                          і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   OvrGetRetry           і Возвращает  текущий  размер  пробнойі
        і                         і области (последнее  значение,  уста-і
        і                         і новленное OvrSetRetry).             і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   OvtInit               і Эта процедура инициализирует подсис-і
        і                         і тему управления оверлеями и открыва-і
        і                         і ет оверлейный файл.                 і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   OvrInitEMS            і Данная процедура, если это возможно,і
        і                         і загружает оверлейный файл  в  памятьі
        і                         і EMS.  При  этом все последующие заг-і
        і                         і рузки оверлеев  сводятся  к  быстройі
        і                         і передаче  информации из памяти в па-і
        і                         і мять.                               і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   OvrSetBuf             і Устанавливает размер оверлейного бу-і
        і                         і фера.                               і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   OvrSetRetry           і Задает   размер  пробной  области  ві
        і                         і оверлейном буфере.                  і
        АДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

                      Константы и переменные модуля Overlay
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД


         B.Pascal 7 & Objects/LR     - 335 -


             В модуле Overlay определены пять переменных:

                            Переменные модуля Overlay         Таблица 20.2
        ЪДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і   Переменная         і                Описание                і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   OvrFileMode        і Определяет передаваемый DOS при  откры-і
        і                      і тии файла код доступа.                 і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   OvrLoadCount       і Данная   переменная  увеличивается  приі
        і                      і каждой загрузке оверлея.               і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   OvrReadBuf         і Эта  процедурная  переменная  позволяеті
        і                      і вам интерпретировать операции  загрузкиі
        і                      і оверлея.                               і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   OvrResult          і Перед  возвратом управления каждая про-і
        і                      і цедура в модуле Overlay сохраняет  свойі
        і                      і код результата в переменной OvrResult. і
        ГДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і   OvrTrapCount       і Каждый раз,  когда обращение к подпрог-і
        і                      і рамме оверлея перехватывается подсисте-і
        і                      і мой управления оверлеями (когда оверлеяі
        і                      і нет в памяти или он находится на тести-і
        і                      і ровании)       значение      переменнойі
        і                      і OvrTrapCount  увеличивается.  Начальноеі
        і                      і ее значение равно 0.                   і
        АДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Значения этих  переменных  вы можете найти в Главе 1 ("Спра-
        вочник по библиотеке") "Справочного руководства программиста".

                                 Коды результата
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Об ошибках   модуль   Overlay   сообщает   через  переменную
        OvrResult. См. константы ovrXXXX  в Главе 1 ("Справочник  по биб-
        лиотеке") "Справочного руководства программиста".

                         Разработка программ с оверлеями
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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



         B.Pascal 7 & Objects/LR     - 336 -

                           Генерация оверлейного кода
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Borland Pascal допускает  использование  модуля  в  качестве
        оверлейного только в том случае, если он генерировался с директи-
        вой {$O+}. Когда задана эта директива, генератор выполняемого ко-
        да,  при передаче строки из одной оверлейной процедуры в другую и
        задании постоянных параметров,  предпринимает особые меры предос-
        торожности.  Например,  если модуль UnitA содержит  процедуру  со
        следующим заголовком:

             procedure WriteStr(s: string);

        и модуль UnitB содержит оператор:

             WriteStr('Hello word...');

        то Borland Pascal  помещает строковую константу 'Hello word...' в
        сегмент кода модуля UnitB и передает указатель на  него процедуре
        WriteStr.  Однако,  если оба модуля являются оверлейными,  то это
        работать не будет, поскольку при обращении в WriteStr сегмент ко-
        да  модуля  UnitB может быть перекрыт модулем UnitA,  и ссылка на
        строку окажется недопустимой.  Для того, чтобы избежать эти проб-
        лемы, используется директива {$O+}.  Каждый раз, когда Турбо Пас-
        каль встречает обращение из одного  модуля,  скомпилированного  с
        директивой {$O+},  к другому модулю, скомпилированному с директи-
        вой {$O+},  компилятор перед передачей ссылок на них обеспечивает
        временное копирование всех размещенных в сегменте кода констант в
        стек.

             Указание в модуле директивы {$O+} не обязывает вас использо-
        вать  этот  модуль  как оверлейный.  Она просто указывает Borland
        Pascal на необходимость обеспечения,  если это нужно, использова-
        ния данного модуля в качестве оверлейного. Если вы разрабатываете
        модули, которые планируете использовать как в оверлейных, так и в
        неоверлейных прикладных программах, то компиляция их с директивой
        {$O+} обеспечивает использование одной версии  модуля  для  обоих
        случаев.



         B.Pascal 7 & Objects/LR     - 337 -

                 Требование использования дальнего типа вызовов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Как уже упоминалось ранее,  при любом обращении к оверлейной
        процедуре  или функции из другого модуля вы должны обеспечить для
        всех активных процедур и функций вызовы типа FAR (дальний тип вы-
        зова).

             Это можно  хорошо  проиллюстрировать  на  следующем примере.
        Предположим,  что OvrA представляет собой процедуру в  оверлейном
        модуле, а процедуры MainC и MainD - процедуры в основной програм-
        ме. Если основная программа вызывает MainC, которая вызывает про-
        цедуру MainB, которая в свою очередь обращается к процедуре OvrA,
        то во время обращения к процедуре OvrA процедуры  MainC  и  MainB
        являются активными (они еще не выполнили возврат управления), по-
        этому необходимо использовать для них дальний тип вызова. Описан-
        ные в основной программе, процедуры MainC и MainB в обычной ситу-
        ации используют ближний тип вызовов (NEAR).  С помощью  директивы
        компилятора {$F+} необходимо задать дальний тип вызовов.

             Самый легкий  способ удовлетворения требования использования
        дальнего типа вызовов состоит  в  размещении  в  начале  основной
        программы и в начале каждого модуля директивы {$F+}. Альтернатив-
        ный способ состоит в изменении принятой по умолчанию установки $F
        на {$F+}  с помощью директивы командной строки /$F+ или с помощью
        параметра Force Far Calls (Использовать дальний тип вызова) в ди-
        алоговом  меню  OptionsіCompiler (ПараметрыіКомпилятор) среды IDE
        интерактивного компилятора. По сравнению со смешанным использова-
        нием вызовов ближнего и дальнего типа использование вызовов толь-
        ко типа FAR не приводит к особенно большим дополнительным  затра-
        там памяти:  для этого требуется одно дополнительное слово прост-
        ранства стека на активную процедуру и один дополнительный байт на
        каждый вызов.



         B.Pascal 7 & Objects/LR     - 338 -

                      Инициализация администратора оверлеев
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Здесь мы рассмотрим некоторые примеры того,  как инициализи-
        руется администратор оверлеев (подсистема управления  оверлеями).
        Код  инициализации  должен быть помещен перед первым обращением к
        оверлейной программе.  Инициализацию обычно следует делать в опе-
        раторной части программы.

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

             begin
               OvrInit('EDITOR.OVR');
             end;

             Проверка на ошибки не делается. Поэтому если для оверлейного
        буфера  не  хватает памяти или оверлейный файл не найден,  то при
        попытке  вызова  оверлейной  программы  произойдет   ошибка   208
        (Overlay manager not installed - "Администратор оверлеев не уста-
        новлен").

             Приведем другой  небольшой  пример,  являющийся  расширением
        предыдущего.

             begin
               OvrInit('EDITOR.OVR');
               OvrInitEMS;
             end;

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

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

             Очевидно, решение заключается в том,  чтобы увеличить размер
        оверлейного буфера таким образом,  чтобы в любой заданный  момент
        времени имелось достаточно памяти для того, чтобы содержать в се-
        бе все оверлеи,  часто обращающиеся друг к другу. Следующая часть
        программы  показывает  использование для увеличения размера овер-
        лейного буфера процедуры OvrSetBuf:

             const

         B.Pascal 7 & Objects/LR     - 339 -

               OvrMaxSize = 80000;
             begin
               OvrInit('EDITOR.OVR');
               OvrInitEMS;
               OvrSetBuf(OvrMaxSize);
             end;

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

             Использование процедуры OvrInitEMS для размещения оверлейно-
        го файла в расширенной памяти не устраняет необходимости работы с
        оверлейным  буфером.  Ведь оверлеи перед выполнением тем не менее
        должны копироваться из расширенной памяти в обычную  (то  есть  в
        оверлейный буфер).  Однако,  поскольку такие передачи из памяти в
        память выполняются значительно быстрее,  чем чтение с  диска,  то
        необходимость  увеличения  размера  оверлейного буфера становится
        менее  очевидной.

             Нужно также помнить о том,  что процедура OvrSetBuf увеличи-
        вает размер оверлейного буфера за счет уменьшения размера динами-
        чески распределяемой области памяти.  Таким образом,  динамически
        распределяемая   область  должна  быть  пустой,  иначе  процедура
        OvrSetBuf не окажет никакого действия. Если вы используете модуль
        Graph,  убедитесь в том, что вы обращаетесь к процедуре OvrSetBuf
        перед вызовом процедуры InitGraph,  которая выделяет память в ди-
        намически распределяемой области.

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

             const
               OvrMaxSize = 80000;
             var
               OvrName: string[79];
               Size: Longint;
             begin
               OvrName:='EDITOR.OVR';
               repeat
                 OvrInit(OvrName);
                 if OvrResult=ovrNotFound then
                 begin
                   WriteLn('Оверлейный файл не найден');
                   WriteLn('Введите правильное имя оверлейного файла:');
                   ReadLn(OvrName);
                 end;
                until OvrResult<>ovrNotFound;
                if OvrResult<>ovrOk then
                begin
                  WriteLn('Ошибка администратора оверлеев.')

         B.Pascal 7 & Objects/LR     - 340 -

                  Halt(1);
                end;
                OvrInEMS;
                if OvrResult<>OvrOk then
                begin
                  case OvrResult of
                    ovrIOError:      Write('Ошибка ввода-вывода',
                                            ' оверлейного файла');
                    ovrNoEMSDriver:  Write('Драйвер EMS не',
                                            ' установлен');
                    ovrNoEMSMemory:  Write('Не хватает расширенной',
                                            ' памяти');
                end;
                Write('. Нажмите клавишу Enter...');
                ReadLn;
              end;
              OvrSetBuf(OvrMaxSize);
             end;

             Сначала, если  принятое  по  умолчанию имя оверлейного файла
        было неверным,  пользователю будет выводиться подсказка на введе-
        ние правильного имени файла.

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

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

             Наконец, для задания значения  размера  оверлейного  буфера,
        определенного  с  помощью  анализа  или эксперимента с конкретной
        прикладной программой,  вызывается процедура  OvrSetBuf.  Ошибки,
        которые могут возникнуть при выполнении данной процедуры, игнори-
        руются, хотя OvrResult может возвращать код возврата по ошибке -3
        (OvrNoMemory).  Если  памяти недостаточно,  подсистема управления
        оверлеями будет просто продолжать использовать буфер минимального
        размера, выделенный при запуске программы.



         B.Pascal 7 & Objects/LR     - 341 -

                   Разделы инициализации в оверлейных модулях
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

             unit EdInit;
             interface
             implementation
             uses Overlay;
             const
               OvrMaxSize = 80000;
             begin
               OvrInit('EDITOR.OVR');
               OvrInitEMS;
               OvrSetBuf(OvrMaxSize);
             end.

             В операторе uses программы модуль  EdInit  должен  следовать
        перед всеми оверлейными модулями:

             program Editor;
             {$F}
             uses
              Overlay,Crt,Dos,EdInit,EdInOut,EdFormat,EdPrint,EdMain;
             {$O EdInOut }
             {$O EdFormat }
             {$O EdPrint }
             {$O EdFind }
             {$O EdMain }

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

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

             Намного более  привлекательный  подход состоит в том,  чтобы

         B.Pascal 7 & Objects/LR     - 342 -

        собрать весь код инициализации в оверлейный модуль инициализации,
        который вызывается только один раз при загрузке программы и к ко-
        торому затем программа не обращается.

                Что не должно использоваться в качестве оверлеев
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             1.  Модули, скомпилированные с директивой {$O-}. Если вы пы-
                 таетесь использовать как оверлейный модуль,  который  не
                 был скомпилирован с директивой {$O+},  то компилятор вы-
                 дает сообщение об ошибке.  Такими неоверлейными модулями
                 являются модули System,  Overlay,  Crt,  Graph, Turbo3 и
                 Graph3.

             2.  Модули,  которые содержат драйверы прерываний. Из-за то-
                 го, что сама операционная система DOS имеет неоверлейную
                 структуру,   модули,  реализующие  процедуры  прерываний
                 (interrupt), не должны быть оверлейными. В качестве при-
                 мера  такого  модуля  можно  привести стандартный модуль
                 Crt, реализующий драйвер обработки прерывания, возникаю-
                 щего при нажатии клавиш Ctrl+Break.

             3.  Драйверы  BGI  или шрифты,  зарегистрированные с помощью
                 вызова      подпрограмм      RegisterBGIdriver       или
                 RegisterBGIfont.

             Администратором оверлеев Borland Pascal полностью  поддержи-
        вается вызов оверлейных процедур с помощью указателей процедур. В
        качестве примеров использования указателей процедур можно привес-
        ти  процедуры  завершения и драйверы устройств для текстовых фай-
        лов.

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



         B.Pascal 7 & Objects/LR     - 343 -

                                Отладка оверлеев
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Большинство отладчиков обладают весьма ограниченными возмож-
        ностями отладки оверлеев,  если они вообще обладают такими средс-
        твами. Этого нельзя сказать о Borland Pascal  и  Турбо  отладчике
        (Turbo Debugger).  Встроенный отладчик полностью поддерживает при
        работе с оверлеями пошаговый режим и  точки  останова,  используя
        при этом метод,  полностью прозрачный для пользователя. С помощью
        оверлеев вы легко можете конструировать и  отлаживать  прикладные
        пакеты большого объема.  Все это можно делать как с помощью Турбо
        отладчика, так и из интерактивной среды компилятора IDE.


                          Внешние программы в оверлеях
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Аналогично обычным процедурам и функциям Borland Pascal  при
        использовании  внешних программ на языке ассемблера для обеспече-
        ния корректной работы подсистемы управления оверлеями должны соб-
        людаться определенные правила программирования.

             Если в  программе на языке ассемблера осуществляется обраще-
        ние к любой оверлейной процедуре или функции,  то в программе ас-
        семблера должен  использоваться  дальний тип вызова,  и с помощью
        регистра BP должны  быть  установлены  границы  стека.  Например,
        предположим,  что OtherProc является оверлейной процедурой в дру-
        гом модуле и ее вызывает программа ExternProc на языке  ассембле-
        ра.  Тогда программа ExternProc должна иметь дальний тип вызова и
        устанавливать границы стека следующим образом:

             ExternProc      PROC       FAR
                   PUSH      bp         ; сохранить регистр ВР
                   mov       bp,sp      ; установить границы стека
                   SUB       sp,LocalSize ; выделить локальные
                                        ;   переменные
                   ...
                   CALL      OtherProc  ; вызвать другой оверлейный
                                        ; модуль
                   ...
                   mov       sp,bp      ; отменить локальные переменные
                   pop       bp         ; восстановить регистр ВР
                   RET       ParamSize  ; возврат управления
             ExternProc      ENDP

        где LocalSize представляет собой размер локальных  переменных,  а
        ParamSize  - размер параметров.  Если значение LocalSize равно 0,
        то две строки,  в которых выделяются и уничтожаются локальные пе-
        ременные, можно опустить.

             Если в  программе  ExternProc  имеются  косвенные  ссылки на
        оверлейные процедуры и функции,  то эти требования остаются  теми
        же. Например, если процедура OtherProc вызывает оверлейные проце-

         B.Pascal 7 & Objects/LR     - 344 -

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

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

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



         B.Pascal 7 & Objects/LR     - 345 -

                         Задание функции чтения оверлея
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Чтобы установить свою собственную  функцию  чтения  оверлея,
        вам нужно  сначала сохранить предыдущее значение OvrReadBuf в пе-
        ременной типа OvrReadFunc,  а  затем  присвоить  OvrReadBuf  вашу
        функцию чтения  оверлея.  В  своей функции чтения вам следует для
        выполнения фактической  операции  загрузки  вызвать   сохраненную
        функцию чтения  оверлея.  Любые  нужные вам проверки допустимости
        (такие как проверка наличия сменного диска) следует выполнять пе-
        ред вызовом сохраненной функции чтения,  а все проверки на ошибки
        следует выполнять после вызова.

                   Примечание: Не пытайтесь  вызывать  из  своей  функции
              чтения  оверлея  какие-либо  оверлейные  подпрограммы - это
              приведет к сбою системы.

             Код для установки функции чтения  оверлея  должен  следовать
        непосредственно после  вызова  OvrInit;  в этот момент OvrReadBuf
        будет содержать адрес используемой по умолчанию функции чтения  с
        диска.

             Если вы  также  вызываете  OvrInitEMS,  она  использует вашу
        функцию чтения для чтения оверлеев с диска в память EMS, и в слу-
        чае отсутствия  ошибок  сохраняет адрес используемой по умолчанию
        функции чтения в EMS в OvrReadBuf. Если вы хотите также переопре-
        делить функцию  чтения  в  EMS,  просто  повторите  после  вызова
        OvrInitEMS процесс установки.

             Используемая по умолчанию функция чтения с  диска  в  случае
        успешного выполнения возвращает 0. В противном случае возвращает-
        ся код ошибки DOS.  Аналогично, используемая по умолчанию функция
        чтения из EMS в случае успешного выполнения возвращает 0.  В про-
        тивном случае возвращается код ошибки EMS (от $80 до  $FF).  Под-
        робно коды ошибок DOS описываются в "Справочном руководстве прог-
        раммиста". Коды ошибок EMS можно найти в документации по EMS.

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


         B.Pascal 7 & Objects/LR     - 346 -

             Все ошибки  передаются процедурам DOSError или EMSError (ко-
        торые здесь не показаны),  которые могут вывести ошибку пользова-
        телю. Заметим,  что параметр OvrSeg просто передается сохраненной
        функции чтения оверлея и не обрабатывается непосредственно  новой
        функцией чтения оверлея.

             uses Overlay;
             var
                SaveOvrRead: OvrReadFunc;
                UsingEMS: Boolean;

             function MyOvrRead(OvrSeg: Word): Integer: far;
             var
               E: Integer;
             begin
                repeat
                  E := SaveOvrRead(OvrSeg);
                     if E <> 0 then
                         if UsingEMS then
                            EMSError(E) else DOSError(E);
                until E = 0;
                MyOvrRead := 0;
             end;

             begin
                OvrInit('MYPROG.OVR');
                SaveOvrRead := OvrReadBuf;  { сохранить }
                OvrReadBuf := MyOvrRead;    { установить свою }
                UsingEMS := False;
                OvrInitEMS;
                if OvrResult = OvrOK then
                   begin
                     SaveOvrRead := OvrReadBuf   { сохранение }
                     OvrReadBuf := MyOvrRead;    { установить свою }
                     UsingEMS := True;
                   end;
                    .
                    .
                    .
             end.



         B.Pascal 7 & Objects/LR     - 347 -

                              Оверлеи в файлах .EXE
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Borland Pascal также позволяет вам записывать оверлеи в  ко-
        нец выполняемого файла .EXE прикладной программы,  а не в отдель-
        ный файл .OVR.  Чтобы присоединить файл .OVR к концу файла  .EXE,
        используйте  команду  DOS  COPY с параметром командной строки /B,
        например:

             COPY/B MYPROG.EXE + MYPROG.OVR

             Вы должны убедиться,  что файл .EXE компилировался без вклю-
        чения в него информации для отладки.  Таким образом, в интегриро-
        ванной интерактивной  среде IDE в меню OptionsіCompiler (Парамет-
        рыіКомпилятор) проверьте параметр Standalone  (Автономная  отлад-
        ка). При использовании компилятора, работающего с командной стро-
        кой, укажите параметр /V.

             Для чтения оверлея не из отдельного файла .OVR,  а из  конца
        файла .EXE просто задайте при вызове OvrInit имя файла .EXE. Если
        вы работаете под управлением DOS версии 3.х,  то можете использо-
        вать для получения имени файла .EXE стандартную функцию ParamStr,
        например:

             OvrInit(ParamStr(0));



         B.Pascal 7 & Objects/LR     - 348 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                        Часть III. В среде Borland Pascal
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД


                         Глава 21. Использование памяти
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В данной главе описывается, как программы Borland Pascal ис-
        пользуют память.  Borland Pascal может создавать прикладные прог-
        раммы  для  реального  режима  DOS,  защищенного  режима  DOS,  и
        Windows;  в  каждом типе прикладной программы память используется
        по-разному. В данной главе поясняется, как использует память каж-
        дый из этих типов программ. Мы рассмотрим также внутренние форма-
        ты данных,  подсистему управления динамически распределяемой  об-
        ластью памяти и прямой доступ к памяти.

              Использование памяти программами реального режима DOS
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             На Рис.  21.1 приведена схема распределения памяти программы
        Borland Pascal, для реального режима DOS.

             Префикс программного сегмента (PSP) - это область длиной 256
        байт,  которая строится операционной системой  DOS  при  загрузке
        файла .EXE.  Адрес  PSP  сохраняется  в  предописанной переменной
        Borland Pascal длиной в слово с именем PrefixSeg.

             Каждой программе (которая включает в себя основную программу
        и каждый модуль) соответствует сегмент ее кода. Основная програм-
        ма  занимает первый сегмент кода.  Следующие сегменты кода заняты
        модулями (в порядке,  обратном тому, в котором они указаны в опе-
        раторе uses).  Последний сегмент кода занят библиотекой исполняю-
        щей системы (модуль System).  Размер отдельного сегмента не может
        превышать 64К,  однако общий размер кода ограничен только объемом
        имеющейся памяти.


         B.Pascal 7 & Objects/LR     - 349 -


                              Верхняя граница памяти DOS
              HeapEnd   ДД>ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
                           і                            і
                           і   свободная память         і
                           і                            і
              HeapPtr   ДД>і............................і
                           і динамически распределяемая і
                           і      область памяти        і
                           і      (растет вверх) ^      і
              HeapOrg   ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ<ДД  OvrHeapEnd
                           і      оверлейный буфер      і
                           ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ<ДД  OvrHeapOrg
                           і     стек (растет вниз) v   і
              SSeg:SPtr ДД>і............................і
                           і       свободный стек       і
              SSeg:0000 ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                           і   глобальные переменные    і
                           і............................і<ДДДДДДДї
                           і   типизированные константы і        і
              DSeg:0000 ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ        і
                           і   кодовый сегмент          і        і
                           і    модуля System           і        і
                           і............................і        і
                           і   кодовый сегмент          і        і
                           і    первого модуля          і        і
                           і............................і        і
                           АДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ    содержимое
                           .   кодовый сегмент          .      образа
                           .   других   модулей         .    файла .EXE
                           ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДї        і
                           і............................і        і
                           і   кодовый сегмент          і        і
                           і последнего  модуля         і        і
                           ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ        і
                           і   кодовый сегмент          і        і
                           і  главной программы         і        і
                           ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ<ДДДДДДДЩ
                           і префикс сегмента программы і
                           і        (PSP)               і
              PrefixSeg ДД>АДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Рис. 21.1 Схема памяти для программы реального режима DOS.

             Сегмент данных  (адресуемый  через  регистр DS) содержит все
        типизированные константы,  за которыми следуют все глобальные пе-
        ременные.  В  процессе выполнения программы регистр DS никогда не
        изменяется. Размер сегмента данных не может превышать 64К.

             При входе в программу регистр сегмента стека (SS)  и  указа-
        тель стека (SР) загружаются так,  что пара регистров SS:SР указы-
        вает на первый байт,  следующий за сегментом стека.  Регистр SS в
        процессе  выполнения программы никогда не изменяется,  а SP может

         B.Pascal 7 & Objects/LR     - 350 -

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

             Оверлейный буфер  используется  стандартным  модулем Overlay
        для хранения оверлейного кода.  По умолчанию  размер  оверлейного
        буфера соответствует размеру наибольшего оверлея в программе. Ес-
        ли программа не имеет оверлеев,  то размер оверлейного буфера бу-
        дет нулевым.  Размер оверлейного буфера можно увеличить с помощью
        вызова подпрограммы OvrSetBuf модуля Overlay.  В этом случае раз-
        мер динамически   распределяемой  области  памяти  соответственно
        уменьшается, а HeapOrg перемещается вверх.

             В динамически распределяемой области сохраняются  динамичес-
        кие переменные,  то есть переменные,  выделенные при обращениях к
        стандартным процедурам New и GetMem.  Она занимает всю  свободную
        память  или  часть  свободной  памяти,  оставшуюся при выполнении
        программы.  Действительный размер динамически распределяемой  об-
        ласти  зависит от максимального и минимального значений,  которые
        можно установить для динамически распределяемой области с помощью
        директивы компилятора $М.  Гарантированный минимальный размер ди-
        намически распределяемой области не может быть меньше минимально-
        го значения,  установленного для этой области. По умолчанию мини-
        мальные размер динамически распределяемой области равен 0 байт, а
        максимальный - 640К;  это означает,  что по умолчанию динамически
        распределяемая область занимает всю доступную память.

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

           Администратор динамически распределяемой области памяти DOS
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Динамически распределяемая область -  это  похожая  на  стек
        структура,  которая увеличивается, начиная от младших адресов па-
        мяти. При  этом  используется  сегмент динамически распределяемой
        области. Нижняя граница динамически распределяемой области  запо-
        минается  в  переменной  HеаpOrg,  а  верхняя граница динамически
        распределяемой области соответствует нижней границе свободной па-
        мяти и сохраняется в переменной НеаpPtr. При каждом выделении ди-
        намической переменной в динамически распределяемой  области  под-
        система динамического распределения памяти (администратор динами-
        чески распределяемой области) перемещает переменную HeapPtr вверх
        на размер переменной, как бы организуя при этом стек динамических
        переменных, в котором одна переменная размещается над другой.

             Переменная НеаpPtr после каждой операции как правило  норма-
        лизуется,  и смещение, таким образом, принимает значения в диапа-
        зоне от $0000 до $000F.  Так как каждая переменная должна целиком
        содержаться в одном сегменте, максимальный размер отдельной пере-

         B.Pascal 7 & Objects/LR     - 351 -

        менной, которая может быть размещена в динамически распределяемой
        области,  составляет  65521  байт (что соответствует $10000 минус
        $000F).



         B.Pascal 7 & Objects/LR     - 352 -

                               Методы освобождения
                   областей динамически распределяемой памяти
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Динамические переменные, сохраняемые в динамически распреде-
        ляемой области, освобождаются одним из двух следующих способов:

             1.  С помощью процедур Dispose или FrееМем.

             2.  С помощью процедур Маrk и Rеlеаsе.

             Простейшей схемой использования  процедур  Маrk  и  Rеlеаsе,
        например, является выполнение следующих операторов:

             New(Ptr1);
             New(Ptr2);
             Mark(P);
             New(Ptr3);
             New(Ptr4);
             New(Ptr5);

             Схема динамически распределяемой области при этом будет выг-
        лядеть, как показано на Рис. 21.2.

          HeapEnd   ДД>ЪДДДДДДДДДДДДДДДДДДДДДДДДДДї Верхняя граница
                       і                          і памяти
                       і                          і
          HeapPtr   ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr5^       і
              Ptr5  ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr4^       і
              Ptr4  ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr3^       і
              Ptr3  ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr2^       і
              Ptr2  ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr1^       і
              Ptr1  ДД>АДДДДДДДДДДДДДДДДДДДДДДДДДДЩ Нижняя граница памяти

             Рис. 21.2  Метод освобождения областей динамически распреде-
        ляемой области помощью процедур Маrk и Rеlеаsе.

             Оператор Маrk(P) отмечает состояние динамически распределяе-
        мой  области непосредственно перед выделением памяти для перемен-
        ной Ptr3 (путем сохранения текущего значения переменной НеаpPtr в
        P).  Если  выполняется оператор Rеleаsе(P),  то схема динамически
        распределяемой области становится такой,  как  показано  на  Рис.
        21.3.  При  этом,  поскольку  производится  обращение к процедуре
        Маrk, освобождается память, выделенная под все указатели.

                   Примечание: Выполнение процедуры Rеleаsе(НеаpОrg) пол-
              ностью освобождает динамически распределяемую область памя-
              ти, поскольку переменная НеаpOrg указывает на нижнюю грани-

         B.Pascal 7 & Objects/LR     - 353 -

              цу динамически распределяемой области.

          HeapEnd   ДД>ЪДДДДДДДДДДДДДДДДДДДДДДДДДДї Верхняя граница
                       і                          і памяти
                       і                          і
                       і                          і
                       і                          і
                       і                          і
                       і                          і
          HeapPtr   ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr2^       і
              Ptr2  ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr1^       і
              Ptr1  ДД>АДДДДДДДДДДДДДДДДДДДДДДДДДДЩ Нижняя граница памяти

             Рис. 21.3  Схема  динамически распределяемой области при вы-
        полнении процедуры Rеleаsе(P).

             Применение процедур Маrk и Rеlеаsе для  освобождения памяти,
        выделенной для динамических переменных, на которые ссылаются ука-
        затели, выполняемое в порядке,  в точности обратном порядку выде-
        ления памяти,  весьма эффективно.  Однако в большинстве  программ
        имеется тенденция в более случайному выделению и освобождению па-
        мяти, отведенной для динамических переменных, на которые ссылают-
        ся указатели, что влечет за собой необходимость использования бо-
        лее тонких методов управления памятью,  которые реализованы с по-
        мощью процедур Dispose и FrееMem. Эти процедуры позволяют в любой
        момент освободить память, выделенную для любой динамической пере-
        менной, на которую ссылается указатель.

             Когда с помощью процедур Dispose и FrееМем освобождается па-
        мять,  отведенная для динамической переменной, не являющаяся "са-
        мой верхней" переменной в динамически распределяемой  области, то
        динамически  распределяемая область становится фрагментированной.
        Предположим, что выполнялась та же последовательности операторов,
        что  и  в  предыдущем  примере.  Тогда после выполнения процедуры
        Dispose(Ptr3) в центре динамически распределяемой  области памяти
        образуется незанятое пространство ("дыра").  Это показано на Рис.
        21.4.


         B.Pascal 7 & Objects/LR     - 354 -


          HeapEnd   ДД>ЪДДДДДДДДДДДДДДДДДДДДДДДДДДї Верхняя граница
                       і                          і памяти
                       і                          і
          HeapPtr   ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr5^       і
              Ptr5  ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr4^       і
              Ptr4  ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і±±±±±±±±±±±±±±±±±±±±±±±±±±і
                       і±±±±±±±±±±±±±±±±±±±±±±±±±±і
                       ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr2^       і
              Ptr2  ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr1^       і
              Ptr1  ДД>АДДДДДДДДДДДДДДДДДДДДДДДДДДЩ Нижняя граница памяти

             Рис. 21.4 Создание незанятой области ("дыры")  в динамически
        распределяемой области памяти.

             Если в данный момент выполняется процедура New(Ptr3), то это
        опять приведет к выделению той же области памяти. С другой сторо-
        ны, выполнение процедуры Dispose(Ptr4) увеличит размер свободного
        блока,  так как Ptr3 и Ptr4  были  соседними  блоками  (см.  Рис.
        21.5).

          HeapEnd   ДД>ЪДДДДДДДДДДДДДДДДДДДДДДДДДДї Верхняя граница
                       і                          і памяти
                       і                          і
          HeapPtr   ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr5^       і
              Ptr5  ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і±±±±±±±±±±±±±±±±±±±±±±±±±±і
                       і±±±±±±±±±±±±±±±±±±±±±±±±±±і
                       і±±±±±±±±±±±±±±±±±±±±±±±±±±і
                       і±±±±±±±±±±±±±±±±±±±±±±±±±±і
                       ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr2^       і
              Ptr2  ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr1^       і
              Ptr1  ДД>АДДДДДДДДДДДДДДДДДДДДДДДДДДЩ Нижняя граница памяти

             Рис. 21.5 Увеличение размера незанятого блока памяти.

             В конечном итоге выполнение процедуры Dispose(Ptr5) приведет
        сначала  к  созданию  незанятого блока большего размера,  а затем
        НеаpPtr переместится в более  младшие  адреса  памяти.  Поскольку
        последним  допустимым  указателем  теперь  будет  Ptr2 (см.  Рис.
        21 6),  то это приведет к действительному освобождению незанятого
        блока.

          HeapEnd   ДД>ЪДДДДДДДДДДДДДДДДДДДДДДДДДДї Верхняя граница
                       і                          і памяти

         B.Pascal 7 & Objects/LR     - 355 -

                       і                          і
                       і                          і
                       і                          і
                       і                          і
                       і                          і
                       і                          і
                       і                          і
          HeapPtr   ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr2^       і
              Ptr2  ДД>ГДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                       і   содержимое Ptr1^       і
              Ptr1  ДД>АДДДДДДДДДДДДДДДДДДДДДДДДДДЩ Нижняя граница памяти

             Рис. 21.7 Освобождение незанятого блока памяти.

             Как показано  на Рис.  21.7,  динамически распределяемая об-
        ласть памяти теперь находится в том же самом состоянии,  в  каком
        она  находилась бы после выполнения процедуры Rеlеаsе(P).  Однако
        создаваемые и освобождаемые при таком  процессе  незанятые  блоки
        отслеживаются для их возможного повторного использования.


                             Список свободных блоков
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Адреса и размеры свободных блоков,  созданных при  операциях
        Dispose  и FrееМем,  хранятся в списке свободных блоков,  который
        увеличивается вниз, начиная со старших адресов памяти, в сегменте
        динамически  распределяемой области.  Каждый раз перед выделением
        памяти для динамической переменной,  перед тем,  как  динамически
        распределяемая  область будет расширена,  проверяется список сво-
        бодных блоков.  Если имеется блок  соответствующего  размера  (то
        есть размер которого больше или равен требуемому размеру),  то он
        используется.

             Процедура Rеlеаsе всегда очищает  список  свободных  блоков.
        Таким образом,  программа динамического распределения памяти "за-
        бывает" о незанятых блоках,  которые могут существовать ниже ука-
        зателя динамически распределяемой области.  Если вы чередуете об-
        ращения к процедурам Маrk и Rеlеаsе с  обращениями  к  процедурам
        Dispose и FrееМем, то нужно обеспечить отсутствие таких свободных
        блоков.

             Переменная FreeList модуля System указывает на  первый  сво-
        бодный  блок  динамически  распределяемой области памяти.  Данный
        блок содержит указатель на следующий свободный блок и  т.д.  Пос-
        ледний  свободный  блок содержит указатель на вершину динамически
        распределяемой области (то есть адрес,  заданный  HeapPtr).  Если
        свободных блоков в списке свободных блоков нет, то FreeList будет
        равно HeapPtr.

             Формат первых  8  байт  свободного  блока   задается   типом
        TFreeRec:

         B.Pascal 7 & Objects/LR     - 356 -


            type
               PFreeRec = ^TFreeRec;
               TFreeRec = record
                              Next: PFreeRec;
                              Size: Pointer;
                          end;

             Поле Next указывает на следующий свободный блок,  или на  ту
        же ячейку,  что и HeapPtr, если блок является последним свободным
        блоком.  В поле Size записан размер свободного блока.  Значение в
        поле  Size  представляет собой не обычное 32-битовое значение,  а
        "нормализованное" значение-указатель с числом свободных  парагра-
        фов  (16-байтовых  блоков)  в старшем слове и счетчиком свободных
        байт (от 0 до 15) в младшем слове.  Следующая  функция  BlockSize
        преобразует значение поля Size в обычное значение типа Longint:

            function BlockSize(Size: Pointer): Longint;
            type
               PtrRec = record Lo, Hi: Word end;
            begin
               BlockSize := Longint(PtrRec(Size)).Hi)*16+PtrRec(Size).Lo
            end;

            Чтобы обеспечить, что в начале свободного блока всегда имеет-
        ся место для TFreePtr,  подсистема управления динамически распре-
        деляемой областью памяти округляет размер каждого блока, выделен-
        ного подпрограммами New и GetMem  до  8-байтовой  границы.  Таким
        образом,  8  байт выделяется для блоков размером 1..8,  16 байт -
        для блоков размером 9..16 и т.д. Сначала это кажется непроизводи-
        тельной тратой памяти.  Это в самом деле так, если бы каждый блок
        был размером 1 байт. Но обычно блоки имеют больший размер, поэто-
        му относительный размер неиспользуемого пространства меньше.

              8-байтовый коэффициент  раздробленности  обеспечивает,  что
        при большом числе случайного выделения и освобождения блоков  от-
        носительно небольшого размера (что типично для записей переменной
        длины в программах обработки текста) не приведет к сильной  фраг-
        ментации  динамически распределяемой области.  В качестве примера
        предположим,  что занимается и  освобождается  блок  размером  50
        байт.  После  его  освобождения  запись о нем включается в список
        свободных блоков.  Этот блок округляется до 56 (7*8) байт. Если в
        дальнейшем потребуется блок размером от 49 до 56 байт,  то данный
        блок будет полностью повторно использован, а не останется от 1 до
        7 байт памяти (использование который маловероятно), которые будут
        только фрагментировать динамически распределяемую область.


                              Переменная HeapError
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Переменная HeapError позволяет вам реализовать функцию обра-
        ботки ошибки динамически распределяемой области памяти. Эта функ-

         B.Pascal 7 & Objects/LR     - 357 -

        ция вызывается каждый раз,  когда программа динамического распре-
        деления  памяти  не  может  выполнить запрос на выделение памяти.
        НеаpЕrror является указателем,  который ссылается на  функцию  со
        следующим заголовком:

             function HeapFunc(Size: Word): Integer; far;

             Заметим, что директива far указывает функции обработки ошиб-
        ки динамически распределяемой области не необходимость  использо-
        вать дальнюю модель вызова.

             Функция обработки ошибки  динамически распределяемой области
        реализуется путем присваивания ее адреса переменной НеаpEror:

             HeapError := @HeapFunc;

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

             В зависимости от успеха выполнения этой попытки функция  об-
        работки ошибки динамически распределяемой области возвращает зна-
        чения 0,  1 или 2. Возвращаемое значение 0 свидетельствует о неу-
        дачной попытке, что немедленно приводит к возникновению ошибки во
        время выполнения программы.  Возвращаемое значение 1 также свиде-
        тельствует о неудачной попытке, но вместо ошибки этапа выполнения
        оно приводит к тому,  что процедуры GetМем или FrееМем возвращают
        указатель nil.  Наконец,  возвращаемое значение 2 свидетельствует
        об  удачной  попытке и вызывает повторную попытку выделить память
        (которая также может привести к вызову функции  обработки  ошибки
        динамически распределяемой области).

             Стандартная обработки функция ошибки динамически распределя-
        емой области всегда возвращает значение 0,  приводя,  таким обра-
        зом, к ошибке всякий раз, когда не могут быть выполнены процедуры
        New или GetМем.  Однако для многих прикладных программ более под-
        ходящей  является  простая  функция  обработки ошибки динамически
        распределяемой области, пример которой приведен ниже:

             function HeapFunc(Size: Word): Integer; far;
             begin
               HeapFunc := 1;
             end;

             Если такая функция реализована,  то  вместо  принудительного
        завершения  работы программы в ситуации,  когда процедуры New или
        GetМем не могут выполнить запрос,  она  будет  возвращать  пустой
        указатель (указатель nil).


         B.Pascal 7 & Objects/LR     - 358 -

             Вызов функции  ошибки динамически распределяемой области па-
        мяти со значением параметра Size, равным 0, показывает, что удов-
        летворение запроса на выделение памяти привело к расширению дина-
        мически распределяемой области памяти путем  перемещения  HeapPtr
        вверх.  Это происходит,  когда в списке свободных блоков нет сво-
        бодных блоков,  или когда все свободные блоки  слишком  малы  для
        удовлетворения данного запроса.  Вызов со значением Size,  равным
        0,  не указывает на состояние ошибки,  поскольку между HeapPtr  и
        HeapEnd достаточно пространства для расширения,  однако такой вы-
        зов  служит  предупреждением,  что  неиспользуемая  область  выше
        HeapPtr сократилась,  и подсистема управления динамически распре-
        деляемой областью памяти игнорирует  значение,  возвращаемое  при
        вызове такого типа.



         B.Pascal 7 & Objects/LR     - 359 -

                              Использование памяти
                       в программах DOS защищенного режима
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В данном разделе поясняется использование память в  програм-
        мах Borland Pascal для защищенного режима.

                                  Сегменты кода
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Прикладная программа и каждая библиотека в прикладной  прог-
        рамме или  DLL имеет свой собственный сегмент кода.  По умолчанию
        модули с аналогичными атрибутами группируются в  сегментах  кода.
        Вы можете  управлять таким группированием с помощью директив $S и
        $G имя_модуля.  Размер одного сегмента кода  не  может  превышать
        64К, но  общий размер кода ограничен только объемом доступной па-
        мяти.

                                Атрибуты сегмента
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                           Атрибуты MOVEABLE или FIXED
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Когда сегмент  кода  имеет  атрибут MOVEABLE (перемещаемый),
        администратор памяти может перемещать сегмент в физической  памя-
        ти, чтобы удовлетворить другие запросы распределения памяти. Ког-
        да сегмент кода имеет атрибут FIXED (фиксированный),  он  ни  при
        каких обстоятельствах не перемещается в физической памяти.  Пред-
        почтительным атрибутом является MOVEABLE,  и пока не будет  абсо-
        лютно необходимо хранить сегмента в одних и тех же адресах памяти
        (это имеет место,  например, для обработчика прерываний), следует
        использовать этот  атрибут.  Когда  вам потребуется фиксированный
        сегмент кода,  такой сегмент кода следует сделать по  возможности
        маленьким.

                         Атрибуты PRELOAD или DEMANDLOAD
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Сегмент кода, имеющий атрибут PRELOAD (предварительно загру-
        жаемый), автоматически  загружается  при  активизации  прикладной
        программы или библиотеки. Атрибут DEMANDLOAD (загружаемый по зап-
        росу) откладывает загрузку сегмента или программы до фактического
        вызова сегмента.  Хотя это требует больше времени,  но  позволяет
        прикладной программе экономить память.

                       Атрибуты DISCARDABLE или PERMAMENT
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Когда сегмент имеет атрибут DIASCARDABLE (выгружаемый),  ад-

         B.Pascal 7 & Objects/LR     - 360 -

        министратор памяти защищенного режима может освободить занимаемую
        сегментом память,  когда  требуется дополнительная память.  Когда
        сегмент имеет атрибут PERMANENT (постоянный),  он все время  хра-
        нится в  памяти.  Когда  прикладная  программа  вызывает  сегмент
        DISCARDABLE, отсутствующий  в  памяти,  администратор защищенного
        режима сначала загружает его из файла .EXE.  Это  требует  больше
        времени, чем если бы сегмент имел атрибут PERMANENT, но позволяет
        выполнять прикладную программу в меньшем объеме памяти.

             Сегмент DISCARDABLE  в программе DOS защищенного режима ана-
        логичен оверлейному сегменту в программе DOS, в то время как сег-
        мент PERMANENT  в защищенном режиме DOS аналогичен сегменту прог-
        раммы DOS, не являющемуся оверлейным.



         B.Pascal 7 & Objects/LR     - 361 -

                             Сегменты данных и стека
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Каждая прикладная  программа защищенного режима DOS или биб-
        лиотека содержит сегмент данных,  которые может иметь  размер  до
        64К. На сегмент всегда указывает регистр  сегмента  данных  (DS).
        Этот сегмент содержит типизированные константы и глобальные пере-
        менные.

             Кроме сегмента данных,  прикладная программа защищенного ре-
        жима DOS имеет сегмент стека,  который используется для  хранения
        локальных переменных,  распределенных процедурами и функциями. На
        входе в прикладную программу регистр сегмента стека (SS) и указа-
        тель стека (SP) загружены таким образом, что пара регистров SS:SP
        указывает  на первый байт после сегмента стека.  Когда вызываются
        процедуры и функции,  SP для выделения пространства для  парамет-
        ров,  адреса  возврата  и локальных переменных перемещается вниз.
        Когда подпрограмма возвращает управление,  процесс изменяется  на
        обратный:  указатель стека увеличивается до значения,  которое он
        имел перед вызовом. По умолчанию размер сегмента стека равен 16К,
        но с помощью директивы компилятора $M его можно изменить.

             В отличие от прикладной программы, DDL DOS защищенного режи-
        ма не имеет сегмента стека.  Когда в DLL вызывается процедура или
        функция, регистр DS изменяется, чтобы указывать на сегмент данных
        DLL, но  пара  регистров SS:SP не модифицируется.  Таким образом,
        DLL всегда использует сегмент стека вызывающей  прикладной  прог-
        раммы.

                               Изменение атрибутов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Используемые по умолчанию атрибуты сегмента кода - это атри-
        буты MOVEABLE,  DEMANDLOAD и DISCARDABLE.  Но с помощью директивы
        компилятора $C  вы можете задать другие используемые по умолчанию
        атрибуты, например:

             {$C MOVEABLE PRELOAD PERMANENT}

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

                   Примечание: Подробности  о  директиве  компилятора  $C
              можно найти в Главе 2 ("Директивы компилятора") в "Справоч-
              ном руководстве программиста".



         B.Pascal 7 & Objects/LR     - 362 -

                            Администратор динамически
                        распределяемой области памяти DOS
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Расширения Borland защищенного режима DOS  включают  в  себя
        полный администратор памяти защищенного  режима.  При  выполнении
        программы защищенного режима DOS вся доступная память превращает-
        ся в глобальную динамически распределяемую область памяти,  кото-
        рая  управляется  администратором  памяти (подсистемой управления
        памятью) защищенного режима.  Прикладная программа может получить
        доступ к глобальной динамически распределяемой области памяти че-
        рез подпрограммы GlobalXXXX модуля WinAPI.  Хотя можно  распреде-
        лять  блоки глобальной памяти любого размера,  глобальная динами-
        чески распределяемая  область  памяти  предназначена  только  для
        больших блоков (1024 байт или более).  Для каждого блока глобаль-
        ной памяти требуется дополнительно 32 байта (это непроизводитель-
        ные  затраты),  а  общее  число блоков глобальной памяти не может
        превышать 8192.

                   Примечание: Подробнее  расширения  Borland защищенного
              режима DOS описываются в Главе 17 "Программирование в защи-
              щенном режиме DOS".

             Borland Pascal включает в себя администратор памяти (который
        называют также подсистемой управления памятью), реализующий стан-
        дартные процедуры New,  Dispose,  GetMem и FreeMem. Администратор
        памяти  использует для всех распределений памяти глобальную дина-
        мически распределяемую область.  Поскольку глобальная динамически
        распределяемая  область  памяти ограничена 8192 блоками (что оче-
        видно меньше,  чем может потребоваться для  некоторых  прикладных
        программ), администратор памяти Borland Pascal реализует алгоритм
        вторичного распределения сегментов,  который улучшает  производи-
        тельность  и  допускает  распределение существенно большего коли-
        чества блоков.

                   Примечание: Borland Pascal для расширенного режима DOS
              не поддерживает схему распределения с помощью процедур MArk
              и Release, предусмотренную для реального режима DOS.

             Алгоритм вторичного  распределения блоков работает следующим
        образом. При выделении большого блока администратор памяти просто
        выделяет глобальную  память  с  помощью подпрограммы GlobalAlloc.
        При выделении маленького блока администратор выделяет более круп-
        ный блок памяти, а затем разбивает его (вторично распределяет) по
        требованию на более мелкие блоки.  Перед тем,  как  администратор
        памяти выделяет  новый  блок глобальной памяти,  который,  в свою
        очередь, будет распределяться повторно, при распределении малень-
        ких  блоков повторно используется все доступное пространство вто-
        ричного распределения.

                   Примечание: Об использовании администратора  памяти  в
              DLL подробнее рассказывается в Главе 11 "Динамически компо-
              нуемые библиотеки".

         B.Pascal 7 & Objects/LR     - 363 -


             Переменная HeapLimit  определяет  порог  между  маленькими и
        большими блоками динамически распределяемой памяти.  По умолчанию
        ее значение равно 1024 байтам.  Переменная  HeapBlock  определяет
        размер, используемый  администратором  памяти  при  распределении
        блоков, выделенных для  вторичного  распределения.  По  умолчанию
        значение HeapBlock  равно  8192 байтам.  Значения этих переменных
        изменять не следует, но если вы это сделаете, убедитесь, что зна-
        чение HeapBlock  составляет  не  меньше  четырехкратного  размера
        HeapLimit.

             Переменная HeapAllocFpals определяет значение флагов атрибу-
        тов, передаваемых GlobalAlloc, когда администратор памяти распре-
        деляет блоки глобальной памяти.  По умолчанию ее  значение  равно
        gmem_Moveable.

                              Переменная HeapError
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             function HeapFunc(Size: word): integer; far;

             Заметим, что директива far указывает функции обработки ошиб-
        ки динамически распределяемой области не необходимость  использо-
        вать дальнюю модель вызова.

             Функция обработки ошибки  динамически распределяемой области
        реализуется путем присваивания ее адреса переменной НеаpEror:

             HeapError := @HeapFunc;

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

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

             В зависимости от успеха выполнения этой попытки функция  об-
        работки ошибки динамически распределяемой области возвращает зна-

         B.Pascal 7 & Objects/LR     - 364 -

        чения 0,  1 или 2. Возвращаемое значение 0 свидетельствует о неу-
        дачной попытке, что немедленно приводит к возникновению ошибки во
        время выполнения программы.  Возвращаемое значение 1 также свиде-
        тельствует о неудачной попытке, но вместо ошибки этапа выполнения
        оно приводит к тому, что процедуры New или GetМем возвращают ука-
        затель nil.  Наконец,  возвращаемое значение 2 свидетельствует об
        удачной попытке и вызывает повторную попытку выделить память (ко-
        торая также может привести к вызову функции обработки ошибки  ди-
        намически распределяемой области).

             Стандартная обработки функция ошибки динамически распределя-
        емой области всегда возвращает значение 0,  приводя,  таким обра-
        зом, к ошибке всякий раз, когда не могут быть выполнены процедуры
        New или GetМем. Однако для многих прикладных задач более подходя-
        щей является простая функция обработки ошибки динамически распре-
        деляемой области, пример которой приведен ниже:

             function HeapFunc(Size: Word): Integer; far;
             begin
               HeapFunc := 1;
             end;

             Если такая функция реализована,  то  вместо  принудительного
        завершения  работы программы в ситуации,  когда процедуры New или
        GetМем не могут выполнить запрос,  она  будет  возвращать  пустой
        указатель (указатель nil).



         B.Pascal 7 & Objects/LR     - 365 -

                    Использование памяти в программах Windows
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В данном разделе поясняется использование памяти в  програм-
        мах Borland Pascal для Windows.

                               Атрибуты сегментов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                           Атрибуты MOVEABLE или FIXED
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Когда сегмент  является  перемещаемым  (MOVEABLE),  Windows,
        чтобы удовлетворить потребности в  распределяемой  памяти,  может
        перемещать сегмент в физической памяти. Когда сегмент кода фикси-
        рованный (FIXED),  он не перемещается в физической памяти.  Более
        предпочтителен атрибут MOVEABLE,  и если нет абсолютной необходи-
        мости хранить сегмент кода по одному и тому же адресу в  физичес-
        кой  памяти  (как  бывает в том случае,  если он содержит драйвер
        прерываний), следует использовать атрибут MOVEABLE.

                         Атрибуты PRELOAD или DEMANDLOAD
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Сегмент кода, имеющий атрибут PRELOAD, при активизации прик-
        ладной программы или библиотеки загружается автоматически.  Атри-
        бут DEMANDLOAD откладывает загрузку сегмента  до  тех  пор,  пока
        подпрограмма в сегменте действительно не будет вызвана.

                       Атрибуты DISCARDABLE или PERMANENT
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Когда сегмент имеет атрибут DISCARDABLE, Windows при необхо-
        димости выделения дополнительной памяти может освобождать память,
        занимаемую данным сегментом. Когда прикладная программа обращает-
        ся к выгружаемому сегменту (DISCARDABLE),  которого нет в памяти,
        Windows загружает его сначала из файла .EXE. Это занимает большее
        время,  чем если бы сегмент был постоянным (PERMANENT), но позво-
        ляет прикладной программе при выполнении занимать меньше места.

             Грубо говоря,  сегмент  DISCARDABLE  в  прикладной программе
        Windows очень напоминает оверлейный сегмент в программе DOS.

                               Изменение атрибутов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             По умолчанию сегменту кода  назначаются  атрибуты  MOVEABLE,
        PRELOAD и PERMANEMT, но с помощью директивы компилятора $C вы мо-
        жете их изменить. Например:


         B.Pascal 7 & Objects/LR     - 366 -

             {$C MOVEABLE DEMANDLOAD DISCARDABLE}

                   Примечание: Более подробно о директиве $C  рассказыва-
              ется в Главе 2 ("Директивы компилятора") "Справочного руко-
              водства программиста".

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



         B.Pascal 7 & Objects/LR     - 367 -

                      Сегмент локальных динамических данных
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Каждая прикладная  программа  или библиотека имеет один сег-
        мент данных,  который называется сегментом локальных динамических
        данных и может занимать до 64К. На сегмент локальных динамических
        данных  всегда указывает регистр сегмента данных DS.  Он разделен
        на четыре части:

                      Сегмент локальных динамических данных
                      ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
                      і                                   і
                      і Локальная динамически распределя- і
                      і емая область памяти               і
                      і                                   і
                      ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                      і                                   і
                      і             Стек                  і
                      і                                   і
                      ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                      і                                   і
                      і       Статические данные          і
                      і                                   і
                      ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
                      і                                   і
                      і         Заголовок задачи          і
                      і                                   і
                      АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Рис. 21.7 Сегмент локальных динамических данных.

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

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

             Сегмент стека используется для хранения  локальных  перемен-
        ных,  распределяемых процедурами и функциями. На входе в приклад-
        ную программу регистр сегмента стека SS и указатель стека SP заг-
        ружаются таким образом,  что SS:SP указывает на первый байт после
        области стека в сегменте локальных динамических данных. При вызо-
        ве  процедур  и функций SP перемещается вниз,  выделяя память для
        параметров,  адреса возврата и локальных переменных.  Когда подп-
        рограмма  возвращает управление,  процесс изменяется на обратный:
        SP увеличивается и принимает то значение,  которое было перед вы-
        зовом. Используемый по умолчанию размер области стека в автомати-
        ческом сегменте данных равен 8К,  но с помощью директивы компиля-
        тора $M это значение можно изменить.

             В отличие  от прикладной программы библиотека в сегменте ло-

         B.Pascal 7 & Objects/LR     - 368 -

        кальных динамических данных не имеет области стека.  При вызове в
        динамически  компонуемой библиотеке DLL процедуры или функции ре-
        гистр DS указывает на сегмент локальных динамических данных  биб-
        лиотеки,  но  пара регистров SS:SP не изменяется.  Таким образом,
        библиотека всегда использует стек вызывающей прикладной  програм-
        мы.

             Последняя часть  в  сегменте локальных динамических данных -
        локальная динамически распределяемая область.  Она  содержит  все
        локальные  динамические данные,  которые распределялись с помощью
        функции LocalAlloc в Windows.  По умолчанию локальная динамически
        распределяемая область имеет размер 8К, но это значение можно из-
        менить с помощью директивы компилятора $M.

             Windows допускает, чтобы сегмент локальных динамических дан-
        ных  был  перемещаемым,  но Borland Pascal этого не поддерживает.
        Сегмент локальных динамических данных  прикладной  программы  или
        библиотеки Borland Pascal всегда блокируется,  этим обеспечивает-
        ся, что селектор (адрес сегмента) сегмента локальных динамических
        данных никогда не изменяется. При работе в стандартном или расши-
        ренном режиме это не приводит ни к  какому  ухудшению,  поскольку
        сегмент сохраняет тот же селектор даже при перемещении в физичес-
        кой памяти.  Однако в реальном режиме,  если требуется расширение
        локальной динамически распределяемой области,  Windows, возможно,
        не сможет этого сделать, поскольку сегмент локальных динамических
        данных перемещаться не может.  Если ваша прикладная программа ис-
        пользует локальную динамически распределяемую  область  памяти  и
        должна выполняться в реальном режиме, то следует обеспечить, что-
        бы начальный размер локальной динамически распределяемой  области
        был таким,  чтобы он удовлетворял всем потребностям в распределе-
        нии локальной динамической области (для этого используется дирек-
        тива компилятора $M).


             Администратор динамически распределяемой области памяти
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Windows поддерживает  динамическое  распределение  памяти  в
        двух  различных  динамически распределяемых областях:  глобальной
        динамически распределяемой области и локальной динамически  расп-
        ределяемой области.

                   Примечание: Более  подробно  о  локальной и глобальной
              динамически распределяемой области рассказывается в  "Руко-
              водстве программиста по Windows".

             Глобальная динамически  распределяемая область - это пул па-
        мяти,  доступный для всех прикладных программ.  Хотя могут  выде-
        ляться блоки глобальной памяти любого размера, глобальная динами-
        чески распределяемая  область  памяти  предназначена  только  для
        "больших" областей памяти (256 байт или более).  Каждый блок гло-
        бальной памяти имеет избыточный размер 20 байт,  и при  работе  в
        стандартной  среде Windows в улучшенном режиме 386 существует ог-

         B.Pascal 7 & Objects/LR     - 369 -

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

             Локальная динамически  распределяемая  область  памяти - это
        пул памяти,  доступной только для вашей прикладной программы  или
        библиотеки. Она расположена в верхней части сегмента данных прик-
        ладной программы или библиотеки.  Общий размер  блоков  локальной
        памяти,  которые могут выделяться в локальной динамически распре-
        деляемой области,  равен 64К, минус размер стека прикладной прог-
        раммы и статических данных. По этой причине локальная динамически
        распределяемая область памяти лучше подходит для "небольших" бло-
        ков памяти (26 байт или менее). По умолчанию размер локальной ди-
        намически распределяемой области равен 8К, но с помощью директивы
        компилятора $M это значение можно изменить.

                   Примечание: Borland  Pascal  не  поддерживает механизм
              распределения памяти с помощью процедур Mark и Release, ко-
              торые предусмотрены в версии для DOS.

             Borland Pascal включает в себя подсистему управления динами-
        чески распределяемой памятью (администратор памяти), которая реа-
        лизует стандартные процедуры New,  Dispose, GetMem и FreeMem. Для
        всех выделений памяти подсистема динамически управления распреде-
        ляемой областью памяти использует глобальную динамически  распре-
        деляемую область. Поскольку глобальная динамически распределяемая
        область памяти имеет системное ограничение в 8192 блока (что  оп-
        ределенно меньше,  чем может потребоваться в некоторых прикладных
        задачах),  подсистема управления динамически  распределяемой  об-
        ластью  памяти  Borland Pascal для улучшения производительности и
        обеспечения выделения существенно большего числа блоков  включает
        в себя алгоритм вторичного распределения сегмента.

                   Примечание: Более подробно об  этом  рассказывается  в
              Главе 11 "Динамически компонуемые библиотеки".

             Алгоритм вторичного  выделения  сегмента  работает следующим
        образом: при  распределении  большого блока администратор динами-
        чески распределяемой области памяти  просто  выделяет  глобальный
        блок памяти,  используя подпрограмму Windows ClobalAlloc. При вы-
        делении маленького блока администратор динамически распределяемой
        области памяти выделяет больший блок памяти, а затем делит его на
        более мелкие блоки (как  требуется).  При  выделении  "маленьких"
        блоков  перед  тем,  как администратор динамически распределяемой
        области памяти выделит блок глобальной динамически распределяемой
        памяти  (который будет в свою очередь разбит на блоки),  повторно
        используются все доступные мелкие блоки.

             Границу между маленькими и большими блоками определяется пе-
        ременной  HeapLimit.  По умолчанию она имеет значение 1024 байта.
        Переменная HeapBlock определяет размер,  который использует  под-
        система управления динамически распределяемой областью памяти при
        выделении блоков для вторичного разбиения. По умолчанию она имеет
        значение 8192 байта.  Изменять эти значения вам незачем,  но если

         B.Pascal 7 & Objects/LR     - 370 -

        вы решите это сделать,  убедитесь что HeapBlock имеет значение по
        крайней мере в четыре раза превышающее HeapLimit.

             Переменная HeapAllocFlags определяет значение флагов атрибу-
        тов, передаваемых GlobalAlloc, когда администратор памяти распре-
        деляет глобальные  блоки.  В  программе по умолчанию используется
        значение gmem_Moveable,  а  в  библиотеке   -   gmem_Moveable   +
        gmem_SSEShure.

             Блоки глобальной памяти,  выделяемые администратором динами-
        чески распределяемой области памяти,  всегда  блокируются  непос-
        редственно  после  своего выделения (с помощью GlobalLock) немед-
        ленно после своего выделения и не разблокируются,  пока не  будут
        освобождены.  Этим обеспечивается,  что селекторы (адреса сегмен-
        тов) блоков не изменяются. В стандартной среде Windows и улучшен-
        ных режимах процессора 386 фиксированные блоки могут,  тем не ме-
        нее,  перемещаться в физической памяти, освобождая место для дру-
        гих запросов по выделению памяти,  поэтому это не ухудшает произ-
        водительности администратора динамически  распределяемой  области
        памяти Borland Pascal.  Однако в реальном режиме, если от Windows
        требуется расширение локальной динамически распределяемой  облас-
        ти, администратор памяти Windows, возможно, не сможет переместить
        их,  чтобы выделить другие блоки.  Если ваша прикладная программа
        использует  локальную динамически распределяемую область и должна
        выполняться в реальном режиме,  можно рассмотреть  при  выделении
        блоков  динамической  памяти  возможность  использования  средств
        распределения памяти, предоставляемых Windows.


                              Переменная HeapError
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             function HeapFunc(Size: word): integer; far;

             Заметим, что директива far указывает функции обработки ошиб-
        ки  динамически распределяемой области не необходимость использо-
        вать дальнюю модель вызова.

             Функция обработки ошибки динамически распределяемой  области
        реализуется путем присваивания ее адреса переменной НеаpEror:

             HeapError := @HeapFunc;

             Функция обработки  ошибки динамически распределяемой области
        памяти получает управление,  когда при обращении к процедурам New
        или GetМем запрос не может быть выполнен.  Параметр Size содержит

         B.Pascal 7 & Objects/LR     - 371 -

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

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

             В зависимости  от успеха выполнения этой попытки функция об-
        работки ошибки динамически распределяемой области возвращает зна-
        чения 0,  1 или 2. Возвращаемое значение 0 свидетельствует о неу-
        дачной попытке, что немедленно приводит к возникновению ошибки во
        время выполнения программы.  Возвращаемое значение 1 также свиде-
        тельствует о неудачной попытке, но вместо ошибки этапа выполнения
        оно приводит к тому, что процедуры New или GetМем возвращают ука-
        затель nil.  Наконец,  возвращаемое значение 2 свидетельствует об
        удачной попытке и вызывает повторную попытку выделить память (ко-
        торая также может привести к вызову функции обработки ошибки  ди-
        намически распределяемой области).

             Стандартная обработки функция ошибки динамически распределя-
        емой области всегда возвращает значение 0,  приводя,  таким обра-
        зом, к ошибке всякий раз, когда не могут быть выполнены процедуры
        New или GetМем. Однако для многих прикладных задач более подходя-
        щей является простая функция обработки ошибки динамически распре-
        деляемой области, пример которой приведен ниже:

             function HeapFunc(Size: word) integer; far;
             begin
               HeapFunc := 1;
             end;

             Если такая  функция  реализована,  то вместо принудительного
        завершения работы программы в ситуации,  когда процедуры New  или
        GetМем  не  могут  выполнить запрос,  она будет возвращать пустой
        указатель (указатель nil).



         B.Pascal 7 & Objects/LR     - 372 -

                    Форматы внутреннего представления данных
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Далее описываются  форматы  внутреннего представления данных
        Borland Pascal.

                               Целочисленные типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Формат, выбираемый для представления переменной целого типа,
        зависит от ее минимальной и максимальной границ:

             1.  Если  обе  границы  находятся   в   диапазоне  -128..127
                 (Shotrint - короткое целое), то переменная хранится, как
                 байт со знаком.

             2.  Если обе границы находятся в диапазоне  0..255  (Byte  -
                 байтовая  переменная),  то переменная хранится, как байт
                 без знака.

             3.  Если обе границы  находятся  в  диапазоне  -32768..32767
                 (Integer - целое),  то переменная хранится, как слово со
                 знаком.

             4.  Если обе границы находятся в диапазоне 0..65535  (Word -
                 переменная длиной в слово),  то переменная хранится, как
                 слово.

             5.  В противном случае переменная хранится, как двойное сло-
                 во со знаком (Longint - длинное целое).

                                 Символьный тип
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Символьный тип или поддиапазон  (отрезок)  символьного  типа
        (Char) хранится, как байт без знака.

                                  Булевский тип
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Значения и переменные булевского типа Boolean  хранятся  как
        байт,  WordBool  - как слово,  а LongBool - как значение Longint.
        При этом подразумеваются,  что они  могут  принимать  значения  0
        (Falsе) или 1 (Тruе).

                                Перечислимый тип
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Значения перечислимого  типа  хранятся,  как байт без знака,
        если нумерация не превышает 256. В противном случае они хранятся,
        как слово без знака.



         B.Pascal 7 & Objects/LR     - 373 -

                             Типы с плавающей точкой
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Типы значений  с  плавающей  точкой  Real,  Single,  Double,
        Extended и Comp (вещественный,  с одинарной точностью,  с двойной
        точностью, с повышенной точностью и сложный) хранятся в виде дво-
        ичного представления знака (+ или -), показателя степени и знача-
        щей части числа. Представляемое число имеет значение:

             +/- значащая_часть Х 2^показатель_степени

        где значащая часть числа представляет собой отдельный  бит  слева
        от двоичной  десятичной точки (то есть 0 <= значащая часть <= 2).

             В следующей далее схеме слева расположены  старшие  значащие
        биты, а справа - младшие значащие биты. Самое левое значение хра-
        нится в самых старших адресах.  Например, для значения веществен-
        ного типа e сохраняется в первом байте, f - в следующих пяти бай-
        тах, а s - в старшем значащем бите последнего байта.

                                Вещественный тип
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Шестибайтовое (48-битовое) вещественное число (Real) подраз-
        деляется на три поля:

                            1        39           8
                          ЪДДДВДДДДДД..ДДДДДДДВДДДДДДДДї
                          і s і      f        і   e    і
                          АДДДБДДДДДД..ДДДДДДДБДДДДДДДДЩ
                              msb          lsb msb   lsb

             Значение v числа определяется с помощью выражений:

             if 0 < e <= 255, then v = (-1)^s * 2^(e-129)*(l.f).
             if e = 0,        then v = 0.

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

             Здесь и  далее msb означает более значащий бит (старшие раз-
        ряды),  lsb - менее значащий (младшие разряды).



         B.Pascal 7 & Objects/LR     - 374 -

                         Тип числа с одинарной точностью
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Четырехбайтовое (32-битовое) число типа Single подразделяет-
        ся на три поля:

                           1    8           23
                         ЪДДДВДДДДДДВДДДДДДД..ДДДДДДДДДї
                         і s і  e   і        f         і
                         АДДДБДДДДДДБДДДДДДД..ДДДДДДДДДЩ
                             msb   lsb msb            lsb

             Значение v этого числа определяется с помощью выражений:

             if 0 < e < 255,      then v = (-1)^s * 2^(e-12) * (l.f).
             if e = 0 and f <> 0, then v = (-1)^s * 2^(126) * (o.f).
             if e = 0 and f = 0,  then v = (-1)^s * O.
             if e = 255 and f = 0, then v = (-1)^s * Inf.
             if e = 255 and f <> 0, then v = NaN.

                          Тип числа с двойной точностью
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Восьмибайтовое (64-битовое) число типа Double подразделяется
        на три поля:

                         1    11          52
                       ЪДДДВДДДДДДВДДДДДДД..ДДДДДДДДї
                       і s і  e   і        f        і
                       АДДДБДДДДДДБДДДДДДД..ДДДДДДДДЩ
                          msb  lsb msb             lsb

             Значение v этого числа определяется с помощью выражений:

             if 0 < e < 2047,   then v = (-1)^s * 2^(e-1023) * (l.f).
             if e = 0 and f <> 0, then v = (-1)^s * 2^(1022) * (o.f).
             if e = 0 and f = 0,  then v = (-1)^s * O.
             if e = 2047 and f = 0, then v = (-1)^s * Inf.
             if e = 2047 and f <> 0, then v = NaN.




         B.Pascal 7 & Objects/LR     - 375 -

                        Тип числа с повышенной точностью
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Десятибайтовое (80-битовое) число типа Extended  подразделя-
        ется на четыре поля:

                         1    15      1          63
                       ЪДДДВДДДДДДДДВДДДВДДДДДДДД..ДДДДДДДї
                       і s і  e     і i і        f        і
                       АДДДБДДДДДДДДБДДДБДДДДДДДД..ДДДДДДДЩ
                           msb     lsb  msb              lsb

             Значение v этого числа определяется с помощью выражений:

             if 0 < e < 32767,  then v = (-1)^s * 2^(e-1023) * (l.f).
             if e = 32767 and f = 0, then v = (-1)^s * Inf.
             if e = 32767 and f <> 0, then v = NaN.

                                   Сложный тип
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Восьмибайтовое (64-битовое) число сложного типа (Comp)  под-
        разделяется на два поля:

                         1             63
                       ЪДДДВДДДДДДДДДДД..ДДДДДДДДДДДДДДї
                       і s і           d               і
                       АДДДБДДДДДДДДДДД..ДДДДДДДДДДДДДДЩ
                           msb                        lsb

             Значение v этого числа определяется с помощью выражений:

             if s = 1 and d = 0, then v = NaN.

        в противном случае v представляет собой 64-битовое значение,  яв-
        ляющееся дополнением до двух.

                             Значения типа указатель
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Значение типа  указатель хранится в виде двойного слова, при
        этом смещение хранится в младшем слове,  а  адрес  сегмента  -  в
        старшем  слове.  Значение  указателя nil хранится в виде двойного
        слова, заполненного 0.



         B.Pascal 7 & Objects/LR     - 376 -

                            Значения строкового типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Строка занимает  столько  байт,  какова  максимальная  длина
        строки, плюс один байт. Первый байт содержит текущую динамическую
        длину  строки,  а последующие байты содержат символы строки.  Бит
        длины и символы рассматриваются,  как значения без знака.  Макси-
        мальная   длина   строки   -   255   символов,  плюс  байт  длины
        (string[255]).

                          Значения множественного типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Множество - это массив бит,  в котором каждый бит указывает,
        является элемент принадлежащим множеству  или  нет.  Максимальное
        число элементов множества - 256, так что множество никогда не мо-
        жет занимать более 32 байт.  Число байт,  занятых отдельным  мно-
        жеством, вычисляется, как:

             ByteSize = (Max div 8) - (Min div 8) + 1

        где Мin и Мах - нижняя и верхняя граница базового типа этого мно-
        жества.  Номер байта для конкретного элемента  E  вычисляется  по
        формуле:

             ByteNumber = (E div 8) - (Min div 8)

        а номер бита внутри этого байта по формуле:

             BitNumber = E mod 8

        где E обозначает порядковое значение элемента.

                              Значения типа массив
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Массив хранится в виде непрерывной последовательности  пере-
        менных,  каждая из которых имеет тип массива. Элементы с наимень-
        шими индексами хранятся в  младших  адресах  памяти.  Многомерный
        массив хранится таким образом, что правый индекс возрастает быст-
        рее.

                              Значения типа запись
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Поля записи хранятся, как непрерывная последовательность пе-
        ременных.  Первое поле хранится в младших адресах памяти.  Если в
        записи  содержатся различные части,  то каждая часть начинается с
        одного и того же адреса памяти.



         B.Pascal 7 & Objects/LR     - 377 -

                                 Объектные типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Внутренний формат данных объекта имеет сходство с внутренним
        форматом записи.  Поля объекта записываются в порядке их описаний
        как непрерывная последовательность переменных.  Любое поле, унас-
        ледованное от родительского (порождающего) типа, записывается пе-
        ред новыми полями, определенными в дочернем (порожденном) типе.

             Если объектный тип определяет виртуальные методы,  конструк-
        тор или деструктор,  то компилятор размещает в объектном типе до-
        полнительное поле данных.  Это 16-битовое поле,  называемое полем
        таблицы виртуальных методов (VMP),  используется для  запоминания
        смещения таблицы виртуальных методов в сегменте данных. Поле таб-
        лицы виртуальных методов следует  непосредственно  после  обычных
        полей  объектного типа.  Если объектный тип наследует виртуальные
        методы, конструкторы или деструкторы  (сборщики  мусора),  то  он
        также наследует и поле таблицы виртуальных методов, благодаря че-
        му дополнительное поле таблицы виртуальных методов не выделяется.

             Инициализация поля таблицы  виртуальных  методов  экземпляра
        объекта осуществляется конструктором (или конструкторами) объект-
        ного типа.  Программа никогда не инициализирует поле таблицы вир-
        туальных методов явно и не имеет к нему доступа.

             Следующие примеры  иллюстрируют  внутренние  форматы  данных
        объектных типов.

             type
               PLocation = ^TLocation;
               TLocation = object
               X,Y: integer;
               procedure Init(PX, PY: Integer);
               function GetX: Integer;
               function GetY: Integer;
             end;

             PPoint = ^TPoint;

             TPoint = object(TLocation)
               Color: Integer;
               constructor Init(PX, PY, PColor: Integer);
               destructor Done; virtual;
               procedure Show; virtual;
               procedure Hide; virtual;
               procedure MoveTo(PX, PY: I+nteger); virtual;
             end;

             PCircle = ^TCircle;
             TCircle = object(TPoint)
               Radius: Integer;
               constructor Init(PX, PY, PColor, PRadius: Integer);
               procedure Show; virtual;

         B.Pascal 7 & Objects/LR     - 378 -

               procedure Hide; virtual;
               procedure Fill; virtual;
             end;

             Рисунок 21.8   показывает   размещение   экземпляров   типов
        TLocation, TPoint и TCircle:  каждый прямоугольник  соответствует
        одному слову памяти.

                   TLocation          TPoint           TCircle
                 ЪДДДДДДДДДДї     ЪДДДДДДДДДДДї     ЪДДДДДДДДДДДї
                 і X        і     і X         і     і X         і
                 ГДДДДДДДДДДґ     ГДДДДДДДДДДДґ     ГДДДДДДДДДДДґ
                 і Y        і     і Y         і     і Y         і
                 АДДДДДДДДДДЩ     ГДДДДДДДДДДДґ     ГДДДДДДДДДДДґ
                                  і Color     і     і Color     і
                                  ГДДДДДДДДДДДґ     ГДДДДДДДДДДДґ
                                  і VMT       і     і VMT       і
                                  АДДДДДДДДДДДЩ     ГДДДДДДДДДДДґ
                                                    і Radius    і
                                                    АДДДДДДДДДДДЩ

             Рис. 21.8  Схема  экземпляров  типов  TLocation,  TPoint   и
        TCircle.

             Так как  TPoint  является  первым типом в иерархии,  который
        вводит виртуальные методы,  то поле таблицы  виртуальных  методов
        размещается сразу после поля Color.


                           Таблица виртуальных методов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Каждый объектный тип, содержащий или наследующий виртуальные
        методы,  конструкторы или деструкторы, имеет связанную с ним таб-
        лицу виртуальных методов, в которой запоминается инициализируемая
        часть сегмента данных программы.  Для каждого объектного типа (но
        не  для каждого экземпляра) имеется только одна таблица виртуаль-
        ных методов,  однако два различных объектных типа никогда не раз-
        деляют одну таблицу виртуальных методов, независимо от того, нас-
        колько эти типы идентичны.  Таблицы виртуальных методов создаются
        автоматически  компилятором, и  программа никогда не манипулирует
        ими непосредственно. Аналогично, указатели на таблицы виртуальных
        методов  автоматически запоминаются в реализациях объектных типов
        с помощью конструкторов программа никогда  не  работает  с  этими
        указателями непосредственно.

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

             Второе слово  таблицы  виртуальных  методов содержит отрица-

         B.Pascal 7 & Objects/LR     - 379 -

        тельный размер экземпляров соответствующего объектного  типа  эта
        информация   используется  ратификационным  (т.е.  подтверждающим
        действительность) механизмом вызова виртуального метода для выяв-
        ления инициализируемых объектов (экземпляров,  для которых должен
        выполняться конструктор) и для проверки  согласованности  таблицы
        виртуальных методов. Когда разрешена ратификация виртуального вы-
        зова (с помощью директивы {$R+} компилятора,  которая расширена и
        включает в себя проверку виртуальных методов), компилятор генери-
        рует вызов программы ратификации таблицы виртуальных методов  пе-
        ред  каждым  вызовом  виртуального метода.  Программа ратификации
        таблицы виртуальных методов проверяет,  что первое слово  таблицы
        виртуальных методов не равно нулю и что сумма первого  и  второго
        слов равна нулю. Если любая из проверок неудачна, то генерируется
        ошибка 210 исполняющей системы Borland Pascal.

             Разрешение проверок  границ  диапазонов  и  проверок вызовов
        виртуальных методов замедляет выполнение программы  и  делает  ее
        несколько  больше,  поэтому используйте {$R+} только во время от-
        ладки и переключите эту директиву в состояние {$R-} в окончатель-
        ной версии программы.

             Наконец, начиная  со  смещения 4 таблицы виртуальных методов
        следует список 32-разрядных указателей методов, один указатель на
        каждый  виртуальный  метод в порядке их описаний.  Каждая позиция
        содержит адрес точки входа соответствующего  виртуального метода.


         B.Pascal 7 & Objects/LR     - 380 -


             На Рис.  21.9 показано размещение таблиц виртуальных методов
        типов Point и Circle (тип Location не имеет  таблицы  виртуальных
        методов, т.к. не содержит в себе виртуальных методов, конструкто-
        ров и деструкторов): каждый маленький прямоугольник соответствует
        одному слову памяти, а каждый большой прямоугольник - двум словам
        памяти.

                      Point VMT                 Circle VMT
                  ЪДДДДДДДДДДДДДДДї         ЪДДДДДДДДДДДДДДДДї
                  і 8             і         і 8              і
                  ГДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДґ
                  і -8            і         і -8             і
                  ГДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДґ
                  і 0             і         і 0              і
                  ГДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДґ
                  і 0             і         і 0              і
                  ГДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДґ
                  і               і         і                і
                  і @TPoint.Done  і         і @TPoint.Done   і
                  і               і         і                і
                  ГДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДґ
                  і               і         і                і
                  і @TPoint.Show  і         і @TCircle.Show  і
                  і               і         і                і
                  ГДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДґ
                  і               і         і                і
                  і @TPoint.Hide  і         і @TCircle.Hide  і
                  і               і         і                і
                  ГДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДґ
                  і               і         і                і
                  і @TPoint.MoveToі         і @TPoint.MoveTo і
                  і               і         і                і
                  АДДДДДДДДДДДДДДДЩ         ГДДДДДДДДДДДДДДДДґ
                                            і                і
                                            і @TCircle.Fill  і
                                            і                і
                                            АДДДДДДДДДДДДДДДДЩ

             Рис. 21.9  Схемы  таблиц  виртуальных  методов  для TPoint и
        TCircle.

             Обратите внимание на то, как TCircle наследует методы Done и
        MoveTo типа TPoint и как он переопределяет Show и Hide.

             Как уже  упоминалось,  конструкторы объектных типов содержат
        специальный код,  который запоминает смещение таблицы виртуальных
        методов объектного типа в инициализируемых экземплярах. Например,
        если имеется экземпляр P типа TPoint и экземпляр C типа  TCircle,
        то  вызов  P.Init будет автоматически записывать смещение таблицы
        виртуальных методов типа TPoint в поле таблицы виртуальных  мето-
        дов  экземпляра  P,  а вызов C.Init точно так же запишет смещение
        таблицы виртуальных методов типа TCircle в поле таблицы виртуаль-

         B.Pascal 7 & Objects/LR     - 381 -

        ных методов экземпляра C.  Эта автоматическая инициализация явля-
        ется частью кода входа конструктора,  поэтому если управление пе-
        редается в начало операторной секции, то поле Self таблицы вирту-
        альных методов также будет установлено.  Таким образом,  при воз-
        никновении необходимости,  конструктор может выполнить вызов вир-
        туального метода.

                          Таблица динамических методов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Таблица виртуальных  методов  объектного  типа  содержит для
        каждого описанного в объектном типе  виртуального  метода  и  его
        предков четырехбайтовую запись.  В тех случаях, когда в порождаю-
        щих типах (предках) определяется большее число виртуальных  мето-
        дов,  в  процессе создания производных типов может использоваться
        достаточно большой объем памяти,  особенно если  создается  много
        производных типов. Хотя в производных типах могут переопределять-
        ся только некоторые из наследуемых методов,  таблица  виртуальных
        методов  каждого  производного типа содержит указатели метода для
        всех наследуемых виртуальных методов,  даже если они  не  изменя-
        лись.

             Динамические методы обеспечивают в таких ситуациях альтерна-
        тиву.  В Borland Pascal имеется формат таблицы  методов  и  новый
        способ диспетчеризации методов с поздним связыванием.  Вместо ко-
        дирования для всех методов объектного типа с поздним связыванием,
        в таблице динамических методов кодируются только те методы, кото-
        рые были в объектном типе переопределены.  Если в наследующих ти-
        пах переопределяются только некоторые из большого числа методов с
        поздним связыванием,  формат таблицы динамических методов исполь-
        зует  меньшее пространство,  чем формат таблицы виртуальных мето-
        дов.

         B.Pascal 7 & Objects/LR     - 382 -


             Формат таблицы динамических методов  иллюстрируют  следующие
        два объектных типа:

             type
                TBase = object
                   X: Integer;
                   constructor Init;
                   destructor Done; virtual;
                   procedure P10; virtual 10;
                   procedure P20; virtual 20;
                   procedure P30; virtual 30;
                   procedure P30; virtual 30;
                end;

             type
                TDerived = object(TBase)
                   Y: Integer;
                   constructor Init;
                   destructor Done; virtual;
                   procedure P10; virtual 10;
                   procedure P30; virtual 30;
                   procedure P50; virtual 50;
                end;


         B.Pascal 7 & Objects/LR     - 383 -


             На Рис. 21.10 и 21.11 показаны схемы таблицы виртуальных ме-
        тодов и таблицы динамических методов для TBase и TDerived. Каждая
        ячейка соответствует слову памяти, а каждая большая ячейка - двум
        словам памяти.

                   ТВМ TBase                    ТДМ TBase
                   ЪДДДДДДДДДДДДДДДДДДї         ЪДДДДДДДДДДДДДДДДДДї
                   і 4                і         і 0                і
                   ГДДДДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДДДґ
                   і -4               і         і индекс в кэш     і
                   ГДДДДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДДДґ
                   і Смещ. ТДМ TBase  і         і смещение записи  і
                   ГДДДДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДДДґ
                   і 0                і         і 4                і
                   ГДДДДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДДДґ
                   і                  і         і 10               і
                   і @TBase.Done      і         ГДДДДДДДДДДДДДДДДДДґ
                   і                  і         і 20               і
                   АДДДДДДДДДДДДДДДДДДЩ         ГДДДДДДДДДДДДДДДДДДґ
                                                і 30               і
                                                ГДДДДДДДДДДДДДДДДДДґ
                                                і 40               і
                                                ГДДДДДДДДДДДДДДДДДДґ
                                                і                  і
                                                і @TBase.P10       і
                                                і                  і
                                                ГДДДДДДДДДДДДДДДДДДґ
                                                і                  і
                                                і @TBase.P20       і
                                                і                  і
                                                ГДДДДДДДДДДДДДДДДДДґ
                                                і                  і
                                                і @TBase.P30       і
                                                і                  і
                                                ГДДДДДДДДДДДДДДДДДДґ
                                                і                  і
                                                і @TBase.P40       і
                                                і                  і
                                                АДДДДДДДДДДДДДДДДДДЩ

             Рис. 21.10 Схемы таблицы виртуальных методов и таблицы дина-
        мических методов для TBase.


         B.Pascal 7 & Objects/LR     - 384 -


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

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

                   ТВМ TDerived                         ТДМ TDerived
                   ЪДДДДДДДДДДДДДДДДДДДї        ЪДДДДДДДДДДДДДДДДДДї
                   і 6                 і        і Смещ. ТДМ TBase  і
                   ГДДДДДДДДДДДДДДДДДДДґ        ГДДДДДДДДДДДДДДДДДДґ
                   і -6                і        і индекс в кеше    і
                   ГДДДДДДДДДДДДДДДДДДДґ        ГДДДДДДДДДДДДДДДДДДґ
                   і Смещ. ТДМ TDerivedі        і смещение записи  і
                   ГДДДДДДДДДДДДДДДДДДДґ        ГДДДДДДДДДДДДДДДДДДґ
                   і 0                 і        і 3                і
                   ГДДДДДДДДДДДДДДДДДДДґ        ГДДДДДДДДДДДДДДДДДДґ
                   і                   і        і 10               і
                   і @TBase.Done       і        ГДДДДДДДДДДДДДДДДДДґ
                   і                   і        і 30               і
                   АДДДДДДДДДДДДДДДДДДДЩ        ГДДДДДДДДДДДДДДДДДДґ
                                                і 50               і
                                                ГДДДДДДДДДДДДДДДДДДґ
                                                і                  і
                                                і @TDerived.P10    і
                                                і                  і
                                                ГДДДДДДДДДДДДДДДДДДґ
                                                і                  і
                                                і @TDerived.P30    і
                                                і                  і
                                                ГДДДДДДДДДДДДДДДДДДґ
                                                і                  і
                                                і @TDerived.T50    і
                                                і                  і
                                                АДДДДДДДДДДДДДДДДДДЩ

             Рис. 21.11.  Схемы таблицы виртуальных методов и таблицы ди-
        намических методов для TDerived.

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

             Второе и третье слово таблицы динамических методов использу-
        ется в кеш-буфере просмотра динамических методов (см. далее).

             Четвертое слово таблицы динамических методов содержит  счет-
        чик  записи таблицы динамических методов.  Непосредственно за ним
        следует список слов, каждое из которых содержит индекс динамичес-

         B.Pascal 7 & Objects/LR     - 385 -

        кого  метода,  а затем список соответствующих указателей методов.
        Длина каждого списка задается счетчиком записи таблицы динамичес-
        ких методов.

                             Значения файлового типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Значения файлового типа представляются в виде записей. Типи-
        зированные и  нетипизированные  файлы занимают 128 байт,  которые
        располагаются по следующей схеме:

              type
                TFileRec = record
                            Handle     : word;             { описатель }
                            Mode       : word;                 { режим }
                            RecSize    : word;         { размер записи }
                            Private    : array[1..26] of byte;
                            UserData   : array[1..16] of byte;
                            Name       : array[0..79] of char;
                          end;

             Текстовые файлы занимают 256 байт со следующей схемой распо-
        ложения:

             type
               TTextBuf = array[0..127] of char;
               TTextRec = record
                            Handle     : word;
                            Mode       : word;
                            BufSize    : word;
                            Private    : word;
                            BufPos     : word;
                            BufEnd     : word;
                            BufPtr     : ^TTextBuf;
                            OpenFunc   : pointer;
                            InOutFunc  : pointer;
                            FlushFunc  : pointer;
                            CloseFunc  : pointer;
                            UserData   : array[1..16] of Byte;
                            Name       : array[0..79] of Char;
                            Buffer     : TTextBuf;
                        end;

             В переменной Наndlе содержится номер описателя  файла (когда
        файл открыт). Это значение возвращается DOS.

             Поле Моdе считается равным одному из следующих значений:

             const
                fmClosed = $D7B0;
                fmInput  = $D7B1;
                fmOutput = $D7B2;
                fmInOut  = $D7B3;

         B.Pascal 7 & Objects/LR     - 386 -


             Значение fmClosed  показывает,  что  файл  закрыт.  Значения
        fmInput и fmOutput показывают, что файл является текстовым файлом
        и что для него  была  выполнена  процедура  Reset  (fmInput)  или
        Rewrite (fmOutput).  Значение fmOutput показывает, что переменная
        файлового типа  является типизированным или нетипизированным фай-
        лом, для которого была выполнена процедура Reset или Rewrite. Лю-
        бое  другое  значение говорит о том,  что для файловой переменной
        присваивание не было выполнено (и она,  таким образом, не инициа-
        лизирована).

             Поле UserData  в Borland Pascal недоступно,  и пользователь-
        ские программы могут сохранять в нем данные.

             Поле Nаме  содержит  имя  файла,  которое представляет собой
        последовательность  символов,  оканчивающуюся  нулевым   символом
        (#0).

             Для типизированных и нетипизированных полей RесSizе содержит
        длину записи в байтах, а поле Рrivate зарезервировано, но являет-
        ся свободным.

             Для текстовых  файлов  BufPtr  является  указателем на буфер
        размером BufSize,  BufPоs представляет  собой  индекс  следующего
        символа  в  буфере,  который должен быть записан или прочитан,  а
        BufEnd  -  счетчик  допустимых  символов  в   буфере.   Указатели
        OpenFunc,  InOutFunc,  FlushFunc и CloseFunc служат для ссылки на
        программы ввода-вывода и используются для  управления  файлом.  В
        Главе  14 в разделе под заглавием "Драйверы устройств для тексто-
        вых файлов" приводится дополнительная информация по этому  вопро-
        су.



         B.Pascal 7 & Objects/LR     - 387 -

                                Процедурные типы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                             Прямой доступ к памяти
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В Borland  Pascal  реализованы  три предопределенных массива
        Mem,  MemW и MemL, которые используются для прямого доступа к па-
        мяти.  Каждый компонент массива Mem представляет собой байт, каж-
        дый компонент массива MemW - слово,  а каждый  компонент  MemL  -
        значение длинного целого типа (Longint).

             Для индексирования массива Mem используется специальный син-
        таксис. Два выражения целочисленного типа Word, разделенные запя-
        тыми, используются для задания базового сегмента и смещения ячей-
        ки памяти, к которой производится доступ. Например:

             Mem[$0040:$0049] := 7;
             Data := MemW[Seg(V):Ofs(V)];
             MemLong := MemL[64:3*4];

             Первый оператор записывает  значение  7  в  байт  по  адресу
        $0040:$0049.  Второй оператор помещает значение типа Word,  запи-
        санное в первые 2 байта переменной V,  в переменную Data.  Третий
        оператор  помещает  значение  типа Longint,  записанное по адресу
        $0040:$000C, в переменную MemLong.

                             Прямой доступ к портам
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Для доступа к портам данных процессора 80х86 Borland  Pascal
        реализует два  предопределенных  массива - Port и PortW.  Оба эти
        массива являются одномерными массивами, где каждый элемент предс-
        тавляет порт данных, адрес которого соответствует индексу. Индекс
        имеет тип Word. Элементы массива Port имеют типа Byte, а элементы
        массива PortW - Word.

             Когда элементами массива Port или PortW присваивается значе-
        ние, оно выводится в выбранный порт.  Когда на элементы этих мас-
        сивов имеются ссылки в выражениях, то значение вводится из задан-
        ного порта.

             Использование массивов Port и PortW ограничено только  прис-
        ваиванием и ссылками в выражениях, то есть элементы этих массивов
        не могут использоваться в качестве  параметров-переменных.  Кроме
        того, ссылки  на  весь массив Port или PortW (без индекса) не до-
        пускаются.



         B.Pascal 7 & Objects/LR     - 388 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                          Глава 22. Вопросы управления
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В данной главе подробно описываются различные способы реали-
        зации в Borland Pascal управления программой.  Сюда включены сог-
        лашения по вызовам,  процедуры выхода, обработка прерываний и об-
        работка ошибок.

                              Соглашения по вызовам
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Параметры процедурам и функциям передаются через стек. Перед
        вызовом  процедуры  или функции параметры помещаются в стек в по-
        рядке их описания. Перед выходом из процедуры или функции все па-
        раметры извлекаются из стека.

             Примерный вызов процедуры или функции можно представить сле-
        дующим образом:

             PUSH Param1
             PUSH Param2
              .
              .
              .
             PUSH ParamX
             Call ProcOrFunc

             Параметры могут передаваться по ссылке или по значению. Ког-
        да параметр передается по ссылке, то указатель, который ссылается
        на реальную ячейку памяти,  помещается в стек. Когда параметр пе-
        редается  по значению,  в стек помещается само фактическое значе-
        ние.

                              Параметры-переменные
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Параметры-переменные (параметры  var)  всегда  передаются по
        ссылке,  то есть указатель ссылается на ячейку памяти с фактичес-
        ким значением.

                               Параметры-значения
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Параметры-значения передаются по значению или по  ссылке,  в
        зависимости  от  их  типа и размера.  В общем случае,  если пара-
        метр-значение занимает 1,  2 или 4 байта,  то значение помещается
        непосредственно в стек. В противном случае в стек помещается ука-
        затель на значение, а процедура или функция копирует затем значе-
        ние в локальную ячейку памяти.

             В процессоре 8086 не поддерживаются байтовые инструкции РUSН
        и РОР,  поэтому байтовые параметры всегда передаются в стеке, как
        слова. Младший байт слова содержит значение, а старший байт слова

         B.Pascal 7 & Objects/LR     - 389 -

        свободен (и неопределен).

             Значение или параметр целого типа передается как байт, слово
        или двойное слово. При этом используется такой же формат, как для
        представления переменной целого типа.  (Для двойных слов  старшее
        слово  помещается  в  стек перед младшим словом,  так что младшее
        слово размещается в более младших адресах.)

             Параметр символьного типа (Char) передается,  как  байт  без
        знака.

             Параметр булевского  типа (Boolean) передается,  как байт со
        значением 0 или 1.

             Параметр перечислимого типа передается,  как байт без знака,
        если нумерация не превышает 256.  В противном случае он передает-
        ся, как слово без знака.

             Параметр вещественного типа  (Real,  значения  с  одинарной,
        двойной  или  повышенной  точностью  или  сложного типа - Single,
        Double, Extended, Comp), передаются через стек как 4, 6, 8 или 10
        байт.  Это  является  исключением из того правила,  что 1-,  2- и
        4-байтовые значение передаются непосредственно в стеке.

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

             Параметр строкового типа передается, как указатель на значе-
        ние.

             Параметр множественного типа передается в виде  байта  (если
        границы элемента  установлены  в  диапазоне  от 0 до 7) или слова
        (если границы элемента установлены в диапазоне от  0  до  15).  В
        противном  случае оно передается в виде указателя на "неупакован-
        ное" множество длиной 32 байта.

             Массив или запись из 1,  2 или 4 байт помещается  непосредс-
        твенно в стек.  Другие массивы и записи передаются, как указатели
        на значения.

                          Открытые строковые параметры
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Открытые параметры-массивы передаются занесением в стек сна-
        чала указателя на массив, а затем слова, содержащего атрибут раз-
        мера (число элементов массива минус 1).


         B.Pascal 7 & Objects/LR     - 390 -

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

             procedure FillString(var Str: OpenString; Chr: Char);
                                     assebmler;
             asm
                  LES      DI,Str         { ES:DI = @Str }
                  MOV      CX,Str,Str.Word[-2]  { Cx = igh(Str) }
                  MOV      AL,CL
                  CLD
                  STOSB                   { установить Str[0] }
                  MOV      AL,Chr
                  REP      STOSB          { установить Str[1..High] }
             end;

                               Результаты функций
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Результаты функций порядкового типа возвращаются в регистрах
        центрального процессора:  байты возвращаются в регистре AL, слова
        -  в регистре AХ,  двойные слова - в DX:AX (старшее слово - в DХ,
        младшее - в AХ).

             Результаты функций вещественного типа (значения вещественно-
        го типа  Real) возвращаются в регистрах DХ:ВХ:AX (старшее слово -
        в регистре DХ,  среднее слово - в регистре ВХ,  младшее слово - в
        AX).

             Результаты функции,  имеющие один из типов, использующихся в
        процессоре 8087,  (значения с одинарной,  двойной или  повышенной
        точностью или сложного типа - Single,  Double,  Extended и Comp),
        возвращаются в регистре вершины стека сопроцессора 8087 (SТ(0)).

            Результаты функции типа указатель возвращаются в регистре DХ:
        AX (адрес сегмента - в DХ, а смещение - в AX).

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



         B.Pascal 7 & Objects/LR     - 391 -

                         Ближние и дальние типы вызовов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В центральном  процессоре 8086 поддерживается два типа вызо-
        вов и  инструкций  возврата управления - ближние (NEAR) и дальние
        (FAR). Ближние вызовы передают управление другой ячейке в  преде-
        лах того же программного сегмента, а дальние вызовы позволяют пе-
        рейти в другой программный сегмент.

             Инструкция ближнего  обращения CALL помещает в стек 16-бито-
        вый адрес возврата (только смещение), а инструкция дальнего вызо-
        ва  помещает  в  стек 32-битовый адрес возврата (адрес сегмента и
        смещение). Соответствующая  инструкция  RET  извлекает  из  стека
        только смещение или адрес сегмента и смещение.

             На основе описания процедуры в Borland Pascal будет  автома-
        тически выбираться правильный тип обращения. Процедуры, описанные
        в интерфейсной секции модуля соответствуют дальнему  обращению  и
        могут вызываться из других блоков.  Процедуры,  описанные в прог-
        рамме в секции реализации модуля (implementation), являются ближ-
        ними  и могут вызываться только из этой программы или данного мо-
        дуля.

             Для некоторых конкретных целей можно потребовать, чтобы про-
        цедура  имела  дальний  тип вызова.  Например,  процедура выхода,
        драйверы устройств для текстовых файлов и  другие  средства,  ис-
        пользующие  указатели  на процедуры.  Директива компилятора {$F+}
        указывает на необходимость использования дальнего  типа  вызовов.
        Процедуры или  функции,  скомпилированные  с  данной  директивой,
        всегда будут  иметь  дальний  тип  вызова.  При  использовании  в
        Borland  Pascal директивы {$F-} правильная схема вызова будет вы-
        бираться автоматически. По умолчанию назначается режим {$F-}.


                          Вложенные процедуры и функции
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Процедура или функция считается вложенной,  когда она описы-
        вается внутри другой процедуры или функции.  По умолчанию вложен-
        ные  процедуры  и  функции  всегда  используют ближний тип вызова
        (NEAR),  поскольку они доступны только внутри определенной проце-
        дуры или функции в том же сегменте кода.  Однако в оверлейных за-
        дачах обычно для того, чтобы обеспечить для всех процедур и функ-
        ций дальний тип вызова (FAR), используется директива {$F+}.

             При вызове вложенной процедуры или функции компилятор непос-
        редственно перед инструкцией CALL генерирует инструкцию  PUSH BP,
        фактически  передавая  регистр BP вызывающей программы в качестве
        дополнительного параметра.  После того,  как вызываемая процедура
        установит свой собственный регистр BP, регистр ВР вызывающей про-
        цедуры доступен,  как слово,  сохраненное в [BP+4] или  в  [BP+6]
        (если процедура имеет дальний тип вызова).  Используя связь через
        [BP+4] и [BP+6], вызываемая процедура может получить доступ к ло-

         B.Pascal 7 & Objects/LR     - 392 -

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

             procedure A; near;
               var IntA: integer;

             procedure B; far;
               var IntB: integer;

             procedure C; near;
               var IntC: integer;
             begin
             inline(
               $8B/$46//      { MOV AX,[BP+IntC]     ;AX = IntC   }
               $8B/$5E/$04/         { MOV BX,[BP+4]        ;BX = стек В }
               $36/$8b/$47//  { MOV AX,SS:[BX+IntB]  ;AX = IntB   }
               $8B/$5E/$04/         { MOV BX,[BP+4]        ;BX = стек B }
               $36/8B/$5F/$06/      { MOV BX,SS:[BX+6]     ;BX = стек A }
               $36/$8B/$47/); { MOV AX,SS:[BX+IntA]  ;AX =IntA    }
             end;

             begin C end;

             begin B end;

                  Примечание: Вложенные процедуры и функции нельзя описы-
             вать с помощью директивы external,  и они не могут иметь па-
             раметры процедурного типа.

             Примечание: Блок inline в приведенном примере можно записать
        также в виде:

             begin
               asm
                  MOV AX,[BP+IntC]     { AX = IntC   }
                  MOV BX,[BP+4]        { BX = стек В }
                  MOV AX,SS:[BX+IntB]  { AX = IntB   }
                  MOV BX,[BP+4]        { BX = кадр стек B }
                  MOV BX,SS:[BX+6]     { BX = кадр стек A }
                  MOV AX,SS:[BX+IntA]  { AX =IntA    }
                end;
             end;

                          Соглашения о вызовах методов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Методы используют те же соглашения о вызовах,  что и обычные
        процедуры и функции,  за тем исключением,  что каждый метод имеет
        неявный дополнительный параметр Self, который соответствует пара-
        метру-переменной того же типа,  что и объектный тип данного мето-
        да. Параметр Self всегда передается последним и всегда имеет фор-
        му 32-разрядного  указателя на экземпляр,  из которого вызывается

         B.Pascal 7 & Objects/LR     - 393 -

        метод. Например, если переменная PP имеет тип PPoint, как опреде-
        лено выше,  то вызов PP^.MoveTo (10, 20) кодируется следующим об-
        разом:

             mov      ax, 10          ; загрузить 10 в  AX
             push     ax              ; передать PX как параметр
             mov      ax, 20          ; загрузить 20 в AX
             push     ax              ; передать PY как параметр
             les      di, PP          ; загрузить PP в ES:DI
             push     es              ; передать, как параметр Self
             push     di
             mov      di, es:[di + 6] ; извлечь смещение ТВМ из поля ТВМ
             call     DWORD PTR [di + 16] ; вызвать запись ТВМ для MoveTo

             Во время возврата метод должен удалить параметр Self из сте-
        ка точно так же, как он удаляет обычные параметры.

             Методы всегда используют дальний тип вызова,  независимо  от
        состояния директивы $F компилятора.



         B.Pascal 7 & Objects/LR     - 394 -

                           Вызовы виртуальных методов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Для вызова  виртуального  метода  компилятор генерирует код,
        который выбирает адрес таблицы виртуальных методов из поля табли-
        цы виртуальных методов объекта, и затем вызывает метод, используя
        связанную с ним точку входа.  Например,  если дана переменная  PP
        типа Point, то вызов PP^.Show будет генерировать следующий код:

             les    di, PP             ; загрузить PP в ES:DI
             push   es                 ; передать, как параметр Self
             push   di
             mov    di, es:[di + 6]    ; извлечь смещение ТВМ из поля ТВМ
             call   DWORD PTR [di + 12] ; вызвать запись ТВМ для  Show

             Правила совместимости типов для объектных типов позволяют PP
        указывать на Point и на TCircle  или  на  любых  других  потомков
        TPoint.  И если вы просмотрите показанные здесь таблицы виртуаль-
        ных методов,  то вы увидите,  что для типа TPoint точка входа  со
        смещением   12   в   таблицы  виртуальных  методов  указывает  на
        TPoint.Show. Таким образом, в зависимости от фактического во вре-
        мя выполнения типа PP, инструкция CALL вызывает либо TPoint.Show,
        либо TCircle.Show, либо метод любого другого потомка TPoint.

             Если Show  является  статическим  методом,  то  для   вызова
        PP.Show будет генерироваться следующий код:

             les    di, PP        ; загрузить PP в ES:DI
             push   es            ; передать, как параметр Self
             push   di
             call   TPoint.Show   ; непосредственно вызвать TPonit.Show

             В данном случае не имеет значения,  на что указывает  PP,  и
        код всегда будет вызывать метод TPoint.Show.



         B.Pascal 7 & Objects/LR     - 395 -

                           Вызовы динамических методов
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Диспетчеризация вызова динамического метода несколько  более
        сложна и требует больше времени, чем диспетчеризация виртуального
        метода.  Вместо использования инструкции CALL  для  вызова  через
        указатель  метода  по статическому смещению в таблице виртуальных
        методов, таблица динамических методов объектного типа  и  таблица
        динамических  методов  его предка должны просматриваться в поиске
        "самого верхнего" вхождения индекса конкретного динамического ме-
        тода, а вызов затем должен выполняться через соответствующий ука-
        затель метода.  Этот процесс  требует  использования  существенно
        большего числа инструкций,  которые можно записать, как "встроен-
        ные" (inline),  поэтому Турбо Паскаль  обеспечивает  подпрограмму
        диспетчеризации, используемую при вызове динамического метода.
             Если бы метод Show показанного выше типа TPoint
        описывался как динамический метод (с индексом динамического
        метода 200), то вызов PP^.Show, где PP имеет тип TPointPtr,
        привел бы к генерации следующего кода:

             les      di,PP            ; загрузка PP в ED:DI
             push     es               ; передача, как параметра
                                       ; Self
             push     di
             mow      di,es:[di+6]     ; извлечение смещения
                                       ; таблицы виртуальных методов
                                       ; из поля таблицы
                                       ; виртуальных методов
             mov      ax,200           ; загрузка в AX индекса
                                       ; динамического метода
             call     Dispatch         ; вызов подпрограммы
                                       ; диспетчеризации

             Диспетчер выбирает сначала смещение таблицы динамических ме-
        тодов  от  таблицы виртуальных методов,  на которое указывает ре-
        гистр DI. Затем используется "индекс в кеше" - поле таблицы дина-
        мических методов. Диспетчер проверяет, является ли индекс вызван-
        ного динамического метода индексом того динамического метода, ко-
        торый вызывался последним.  Если это так,  он немедленно передает
        этому методу управление (путем перехода с помощью указателя мето-
        да,  записанного по смещению, заданному полем "смещение записи").

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


         B.Pascal 7 & Objects/LR     - 396 -

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

                           Конструкторы и деструкторы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Для конструкторов параметр таблицы виртуальных  методов  со-
        держит  смещение таблицы виртуальных методов для запоминания поля
        Self таблицы виртуального метода, чтобы инициализировать Self.

             Более того, если конструктор вызывается для размещения дина-
        мического  объекта  с помощью расширенного синтаксиса стандартной
        процедуры New,  через параметр Self передается указатель nil. Это
        заставляет конструктор размещать новый динамический объект, адрес
        которого передается вызывающей программе через DX:AX при возврате
        из конструктора.  Если конструктор не может разместить объект, то
        в DX:AX возвращается пустой указатель nil.  (См. далее "Обнаруже-
        ние ошибок конструктора").

             Наконец, если  конструктор вызывается с использованием уточ-
        ненного идентификатора метода (т.е.  идентификатора типа объекта,
        за которым следуют точка и идентификатор метода),  то в параметре
        таблицы виртуальных методов передается нулевое значение.  Это яв-
        ляется указанием конструктору на то, что ему не следует инициали-
        зировать поле Self таблицы виртуальных методов.  Для деструкторов
        нулевое значение параметра таблицы виртуальных  методов  означает
        обычный вызов, а ненулевое указывает, что деструктор был вызван с
        использованием  расширенного  синтаксиса  стандартной   процедуры
        Dispose.  Это  заставляет деструктор удалить Self непосредственно
        перед возвратом (размер Self определяется из первого слова Self в
        ТВМ).

                         Стандартный код входа и выхода
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Каждая процедура и функция Borland Pascal начинается  и  за-
        канчивается стандартным набором операторов, которые позволяют ак-
        тивизировать и деактивизировать процедуру или функцию.

             Стандартным входом служит следующая группа операторов:

             PUSH BP              ; сохранить регистр ВР

         B.Pascal 7 & Objects/LR     - 397 -

             MOV BP,SP            ; установить границы стека
             SUB SP,LocalSize     ; выделить память для локальных  пере-
                                  ; менных

             В этом примере LocalSize - это размер  локальных переменных.
        Инструкция SUВ присутствует только в том случае,  когда LocalSize
        не равно нулю.  Если тип обращения к процедуре является  ближним,
        то параметры начинаются с BP+4, если для вызова процедуры исполь-
        зуется дальний тип обращения, то они начинаются с BP+6.

             Для программ  DOS  код входа и выхода для подпрограммы,  ис-
        пользующей дальнюю модель вызова,  тот же, что и для подпрограммы
        с ближним типом вызов,  но для возврата из подпрограммы использу-
        ется  инструкция  RETF.  Это  справедливо  также  для   программы
        Windows, cкомпилированной в состоянии {$W-}.

                   Примечание: Об использовании процедур входа и выхода в
              DLL рассказывается в Главе 11 "Динамически компонуемые биб-
              лиотеки".

             Стандартной группой операторов выхода является:

             MOV SP,BP           ; освободить память, выделенную для
                                 ; локальных переменных
             POP BP              ; восстановить регистр ВР
             RET ParamSize       ; удалить параметры и выполнить возврат
                                 ; управления

             Здесь РаrамSizе - это размер параметров.  Инструкция RET яв-
        ляется  инструкцией ближнего или дальнего типа,  в зависимости от
        типа обращения к процедуре.

             В состоянии {$W+} (по умолчанию) в подпрограмме,  использую-
        щей дальнюю модель вызова, код выхода и выхода выглядит следующим
        образом:

             INC BP               ; указывает на кадр стека FAR
             PUSH BP              ; сохранить регистр ВР
             MOV BP,SP            ; установить кадр стека
             PUSH DS              ; сохранить DS
             SUB SP,LocalSize     ; выделить память для локальных переменных
                .
                .
                .
             MOV SP,BP            ; освободить память, выделенную для
                                  ; локальных переменных
             POP BP               ; восстановить регистр ВР
             DEC PB               ; настроить BP
             RETF ParamSize       ; удалить параметры и выполнить возврат
                                  ; управления

             Код входа и выхода для экспортируемой подпрограммы
        (процедуры или функции, скомпилированной с директивой

         B.Pascal 7 & Objects/LR     - 398 -

        компилятора export) выглядит следующим образом:

             mov     AXC,DS      ; загрузить селектор DS в AX
             nop                 ; дополнительное пространство для
                                 ; корректировок
             inc     BP          ; указывает на дальний кадр стека
             push    BP          ; сохранить BP
             mov     BP,SP       ; установить кадр стека
             push    DS          ; сохранить DS
             mov     DS,AX       ; инициализация регистра DS
             sub     SP,LocalSize; распределении локальных переменных
                .                ; (если они имеются)
                .
                .
             pop     DI          ; восстановить DI
             pop     SI          ; восстановить SI
             lea     SP,[BP-2]   ; освободить память, выделенную для
                                 ; локальных переменных
             pop     DS          ; восстановить DS
             pop     BP          ; восстановить BP
             dec     BP          ; настроить регистр BP
             retf    ParamSize   ; удаление параметров и возврат
                                 ; управления

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

             При работе в реальном  режиме,  чтобы  различать  ближний  и
        дальний кадр стека, Windows требует, чтобы все кадры стека (вклю-
        чая кадры стека экспортируемых подпрограмм) сохраняли в слове  по
        адресу [BP+0] нечетное значение BP.  Кроме того, Windows требует,
        чтобы слово по адресу [BP-2] содержало селектор  сегмента  данных
        вызывающей программы.  Это объясняет использование инструкций INC
        BP, PUSH DS и DEC BP (сгенерированных в состоянии {$W+}) на входе
        и выходе для подпрограмм far и export.

             Заметим, что  использование  {$W+}  требуют  только реальный
        режим Windows.  Если вы не поддерживаете реальный режим,  укажите
        {$W-}. Вы получите программу меньшего размера и некоторый выигрыш
        в скорости.

             При разработке программы защищенного  режима  Windows  может
        оказаться полезным   использование   состояния  {$W+}.  Некоторые
        средства отладки,  отличные от средств Borland, требуют этого для
        корректной работы.

             По умолчанию  Borland Pascal автоматически генерирует эффек-
        тивные системные вызовы для процедур  и  функций,  экспортируемых
        прикладной программой. При компоновке прикладной программы в сос-
        тоянии {$K+} (по умолчанию) отладчик ищет в каждой экспортируемой
        точке входа последовательность инструкций MOV AX,DS с последующей
        инструкцией NOP,  заменяя их на MOV AX.DS на MOV AX,SS. Это изме-

         B.Pascal 7 & Objects/LR     - 399 -

        нение  ослабляет  требование  использования при создании программ
        системного  вызова  подпрограмм  API  Windows  MakeProcInstanc  и
        FreeProcInstance (хотя это не возбраняется). Можно также вызывать
        экспортируемые точки входа из самой прикладной программы.

             В состоянии {$K-} при создании динамически компонуемой  биб-
        лиотеки компоновщик  Borland  Pascal  не модифицирует код входа и
        выхода экспортированной точки входа. Если подпрограмма системного
        вызова в  приложении должна вызываться из другой прикладной прог-
        раммы, выбирать состояние {$K-} не следует.

             При загрузке прикладной программы или динамически  компонуе-
        мой  библиотеки  Windows ищет в каждой экспортируемой точке входа
        последовательность инструкций MOV AX,DS с последующей инструкцией
        NOP. Для  прикладной  программы Windows изменяет первые три байта
        на три инструкции NOP, чтобы подготовить подпрограмму для исполь-
        зования  ее  функцией  Windows  MakeProcInstance.  Для  библиотек
        Windows изменяет первые три байта в инструкции MOV  AX,xxxx,  где
        xxxx  - селектор (адрес сегмента) сегмента динамических локальных
        данных библиотеки.



         B.Pascal 7 & Objects/LR     - 400 -

                       Соглашения по сохранению регистров
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В процедурах  и функциях следует сохранять регистры BP,  SP,
        SS и DS. Значения всех других регистров можно изменять. Кроме то-
        го,  экспортируемые  подпрограммы  должны сохранять регистры SI и
        DI.

                                Процедуры выхода
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Реализовать процедуру выхода вам позволяет переменная-указа-
        тель EхitProc.  Процедура выхода всегда получает вызов при завер-
        шении работы программы,  независимо от того,  является ли это за-
        вершение  нормальным  окончанием  работы  программы,  завершением
        после обращения к функции Наlt, или работа программы прекратилась
        из-за ошибки во время выполнения.

             Параметры для процедуры выхода не  требуются,  и  для  того,
        чтобы использовался дальний тип вызова, она должна компилировать-
        ся с указанием директивы компилятора {$F+}.

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

             Чтобы сохранить  цепочку  выхода  в  неприкосновенности,  вы
        должны перед изменением указателя EхitPrос на адрес  вашей  собс-
        твенной  процедуры  сохранить текущее содержимое этого указателя.
        Далее,  непосредственно перед возвратом управления ваша процедура
        выхода должна восстановить сохраненное значение EхitProc.  В сле-
        дующей программе показаны основы метода реализации такой процеду-
        ры выхода.

             program Testexit;
             var
               ExitSave: Pointer;

             procedure MyExit; far

         B.Pascal 7 & Objects/LR     - 401 -

             begin
               ExitProc := ExitSave;    { всегда восстанавливает сначала
                                          старый вектор }
               .
               .
               .
             end;

             begin
               ExitProc := ExitSave;
               ExitProc := @MyExit;
               .
               .
               .
             end.

             При входе в  программу  содержимое  EхitProc  сохраняется  с
        EхitSave,  а  затем следует процедура выхода МуEхit.  После того,
        как она будет вызвана в качестве элемента процесса завершения ра-
        боты программы, процедура МуEхit восстановит предыдущую процедуру
        выхода.

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

             Процедура выхода может распознавать причину завершения рабо-
        ты программы путем проверки целочисленной переменной  EхitCode  и
        переменной-указателя ErrorAddr. В случае нормального завершения в
        EхitCode содержится нулевое значение и ErrorAddr  имеет  значение
        nil. В   случае  завершения  через  обращение  к  процедуре  Наlt
        EхitCode содержит значение,  переданное функции Наlt, а ErrorAddr
        имеет значение nil. Наконец, в случае прекращения работы програм-
        мы из-за ошибки во время  ее  выполнения  EхitCode  содержит  код
        ошибки, а ErrorAddr содержит адрес ошибочного оператора.

         B.Pascal 7 & Objects/LR     - 402 -


                   Примечание: О процедурах выхода для DLL рассказывается
              в Главе 11.

             Последняя процедура выхода (которая содержится  в библиотеке
        исполняющей  системы) закрывает файлы Input и Output и восстанав-
        ливает векторы прерываний,  которые были перехвачены Турбо Паска-
        лем.  При этом, если указатель ErrorAddr имеет значение, отличное
        от nil,  то процедура выхода выводит сообщение об ошибке во время
        выполнения  программы.  Если  вы хотите выводить свои собственные
        сообщения об ошибках во время выполнения,  используйте  процедуру
        выхода, которая проверяет ErrorAddr и выводит сообщение об  ошиб-
        ке,  если  его  значение отлично от nil.  В добавок к этому перед
        возвратом  управления  необходимо  обеспечить,  чтобы   указатель
        ErrorAddr был установлен в значение nil, чтобы сообщение об ошиб-
        ке не выдавалось снова другой процедурой выхода.

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



         B.Pascal 7 & Objects/LR     - 403 -

                              Обработка прерываний
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Библиотека исполняющей системы Borland Pascal и код,  созда-
        ваемый компилятором, являются полностью прерываемыми. Большинство
        из программ библиотеки исполняющей системы являются также реенте-
        рабельными,  что позволяет вам писать на Borland Pascal программы
        обработки прерываний.

             Для Windows подпрограммы обработки прерываний писать не сле-
        дует. Если вы это сделаете, последствием может быть сбой системы.

                    Разработка процедур обработки прерываний
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Процедуры обработки прерываний описываются с помощью  дирек-
        тивы  Interrupt.  В  каждой процедуре обработки прерываний должен
        определяться следующий заголовок процедуры (или,  как будет пояс-
        няться далее, его подмножество):

             procedure IntHandler(Flags,CS,IPAX,BX,CX,DX,SI,DI,DS,ES,BP:
                               Word);
             interrupt;
             begin
               .
               .
               .
             end;

             Как можно видеть, все регистры передаются в качестве псевдо-
        параметров,  так что вы можете их использовать и изменять в своей
        программе. Вы можете опустить некоторые из параметров или все па-
        раметры,  начиная  с параметра Flag и кончая ВР.  Попытка описать
        большее количество параметров или попытка опустить отдельный  па-
        раметр без пропуска также того параметра,  за которым он следует,
        является ошибкой, хотя сообщения о ней не выдается. Например:

             procedure IntHandler(DI,ES,BP : Word);  { недопустимый
                                                       заголовок }
             procedure IntHandler(SI,DI,DS,ES,BP : Word);  { допустимый
                                                       заголовок }

             При входе в нее процедура обработки прерываний автоматически
        сохраняет все регистры (независимо от заголовка процедуры) и ини-
        циализирует регистр DS:

             PUSH AX
             PUSH BX
             PUSH DX
             PUSH SI
             PUSH DI
             PUSH DS
             PUSH ES

         B.Pascal 7 & Objects/LR     - 404 -

             PUSH BP
             MOV  BP,SP
             SUB  SP,LocalSize
             MOV  AX,SEG DATA
             MOV  DS,AX

             Обратите внимание на отсутствие процедуры СLI,  чтобы разре-
        шить дальнейшие прерывания.  С помощью оператора inline вы можете
        написать ее сами (если это необходимо).  Набор операторов  выхода
        восстанавливает регистры и выполняет функцию возврата прерывания:

             MOV SP,BP
             POP BP
             POP ES
             POP DS
             POP DI
             POP SI
             POP DX
             POP CX
             POP BX
             POP AX
             IRET

             Процедура обработки прерываний может модифицировать свои па-
        раметры.  Когда обработчик прерываний возвратит управление, изме-
        нение описанных параметров приведет к изменению содержимого соот-
        ветствующих регистров.  Это может оказаться  полезным,  когда  вы
        используете  обработчик  прерываний  в качестве пользовательского
        сервисного средства,  аналогичного вызову функции DOS по инструк-
        ции INТ 21Н.

             В процедурах обработки прерываний, обслуживающих прерывания,
        получаемые от аппаратных схем,  следует воздерживаться от исполь-
        зования каких-либо  программ ввода-вывода Турбо Паскаля или прог-
        рамм распределения памяти,  поскольку они не  являются  реентера-
        бельными.  Из-за их нереентерабельности нельзя также использовать
        никакие функции DOS.



         B.Pascal 7 & Objects/LR     - 405 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
                      Глава 23. Автоматическая оптимизация
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В Borland Pascal выполняется несколько различных типов опти-
        мизации  кода,  начиная  от свертывания констант и вычисления бу-
        левских выражений по короткой схеме и кончая  эффективной  компо-
        новкой. Рассмотрим некоторые виды оптимизации.

                              Свертывание констант
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Если участвующие  в  операции  операнды  представляют  собой
        константы перечислимого типа, то в Borland такое выражение вычис-
        ляется во время компиляции. Например, выражение:

             Х := 3 + 4 * 2

        приведет к генерации такого же кода, как выражение Х := 11, а вы-
        ражение:

             S := 'In' + 'Out'

        генерирует тот же код, что S := 'InOut'.

             Аналогично, если операнды функций Abs, Sqr, Succ, Pred, Odd,
        Lo, Hi и Swap представляют собой константы перечислимого типа, то
        функция вычисляется во время компиляции.

             Если индексом массива является константа или выражение, сос-
        тоящее из констант, то адрес элемента вычисляется во время компи-
        ляции.  Например,  доступ к элементу Dаtа[5,5] так же эффективен,
        как доступ к простой переменной.

                                Слияние констант
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Использование одной и той же строковой константы два или бо-
        лее раз приводит к генерации только одной копии константы. Напри-
        мер, два или более оператора Write('Dоnе') в одной и той же части
        программы приведет к ссылке на одну и ту же копию строковой конс-
        танты 'Donе'.

                          Вычисление по короткой схеме
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В Borland Pascal реализуется вычисление булевского выражения
        по короткой схеме.  Это означает, что вычисление булевского выра-
        жения прекращается, как только результат всего булевского выраже-
        ния  становится  очевидным.  При  этом обеспечивается минимальное
        время выполнения и,  обычно,  минимальный размер объектного кода.
        Вычисление  по  короткой  схеме делает также возможным вычисление
        конструкций, которые иначе были бы недопустимыми. Например:


         B.Pascal 7 & Objects/LR     - 406 -

             while (I<=Length(S)) and (S[I]<>' ') do
               Inc(I);
             while (P<>nil) and (P^.Value<>5) do
               P:=P^.Next;

             В обоих случаях,  если первая проверка имеет значение Falsе,
        вторая проверка не вычисляется.

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

                               Параметры-константы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Параметры-константы более эффективны,  чем  параметры-значе-
        ния,  поскольку компилятору не приходится генерировать копии фак-
        тических параметров на входе в процедуры и функции.  Значения па-
        раметров должны быть скопированы в локальные переменные,  так что
        модификации формальных параметров не приведут к модификации  фак-
        тических параметров. Поскольку формальные параметры-константы мо-
        дифицироваться не могут, компилятору нет необходимости копировать
        фактические параметры, что экономит код и пространство в стеке.

                    Устранение избыточной загрузки указателей
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             В определенных ситуациях генератор кода Borland Pascal может
        устранить избыточные инструкции загрузки указателей, уменьшая тем
        самым размер кода и обеспечивая  более  быстрое  его  выполнение.
        Когда генератор  кода  может  обеспечить,  что указатель остается
        постоянным на участке линейного кода (кода,  не содержащего пере-
        ходов на  него),  и когда указатель уже загружен в пару регистров
        (например, ES:DI),  генератор кода  устраняет  ненужные  загрузки
        указателей в блоке кода.

             Указатель считается константой,  если он получается из пара-
        метра-переменной (параметры-переменные всегда передаются как ука-
        затели) или из ссылки на переменную оператор with. Поэтому опера-
        тор with часто является более эффективным (но  никогда  не  будет
        менее эффективным),  чем запись для каждой ссылки на элемент пол-
        ностью уточненной переменной.


         B.Pascal 7 & Objects/LR     - 407 -

                    Подстановка констант множественного типа
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
             Когда правая  часть оператор in является константой множест-
        венного типа,  компилятор генерирует включение проверки с помощью
        команд CMP. Такие поставляемые проверки более эффективны чем код,
        генерируемый в противном случае соответствующими булевскими выра-
        жениями с использованием операций отношения. Например, оператор:

             if ((Ch >= 'A') and (Ch <: 'Z')) or
                  ((Ch >= 'a') and (Ch <= 'z')) then ...;

        менее читаем и менее эффективен чем

             if Ch in ['A'..'Z', 'a'..'z'] then ...;

             Поскольку свертывание констант применяется к константам мно-
        жественного типа  также как к константам других типов,  можно ис-
        пользовать описания const без потери эффективности.

             const
                Upper = ['A'..'Z'];
                Lower = ['a'..'z'];
                Alpha = Upper + Lower;

             С учетом  данных описаний оператор if генерирует тот же код,
        что и в случае предыдущего оператор if:

             if Ch in Alpha then ... ;

                                 Малые множества
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
             Для операций  с  малыми  множествами  компилятор  генерирует
        очень эффективный код.  Малое множество - это множество с  нижним
        порядковым значением в диапазоне 0..7 и верхним порядковым значе-
        нием в диапазоне 0..15.  Например, следующие множества TByteSet и
        TWordSet являются малыми множествами:

             type
                TByteSet = set of 0..7;
                TWordSet = set of 0..15;

             Операции с  малыми  множествами,  такие как объединение (+),
        разность (-),  пересечение (*) и проверка на включение in генери-
        руют с помощью операций AND, OR, NOT и TEST вместо вызова библио-
        тек исполняющей системы инструкции  машинного  кода.  Аналогично,
        стандартные процедуры Include и Exclude генерируют при применении
        к малым множествам поставляемый код.

                               Порядок вычисления
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
             Стандартами Паскаля допускается,  что операнды  в  выражении

         B.Pascal 7 & Objects/LR     - 408 -

        часто вычисляются в порядке,  отличном от того, в котором они за-
        писаны (слева направо). Например, оператор:

             I := F(J) div G(J)

        где F и G - функции целого типа,  приводит к тому, что G вычисля-
        ется перед вычислением F, так как это позволяет компилятору полу-
        чить более оптимальный объектный код. Важно, поэтому, чтобы выра-
        жение  никогда  не  зависело  от  какого-то  конкретного  порядка
        вычисления встроенных функций.  Если вернуться к предыдущему при-
        меру, то для того, чтобы вызвать функцию F перед функцией G, мож-
        но использовать временную переменную:

             T := F(J);
             I := T div G(J);

             Исключением из этого правила является вычисление по короткой
        схеме (разрешенное директивой компилятора {$B-}, при котором опе-
        ранды булевского типа,  связанные операциями and или  оr,  всегда
        вычисляются слева направо.

                         Проверка на допустимость границ
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Присваивание константы  переменной и использование константы
        в качестве значения параметра проверяется во время  компиляции на
        допустимость нахождения в заданных границах. При этом генерирует-
        ся такой код, что во время выполнения таких проверок не делается.
        Например,  Х  :=  999,  где Х - переменная байтового типа (Bytе),
        приводит к ошибке компиляции.

                      Использование сдвига вместо умножения
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Операция X*C,  где C - константа,  являющаяся степенью числа
        2,  приводит к генерации объектного кода,  в котором используется
        инструкция Shl (сдвиг влево).

             Аналогично, когда  размерность  массива  представляет  собой
        степень числа 2,  то для вычисления индексных выражений использу-
        ется инструкция Shl (а не инструкция Мul).

                  Автоматическое выравнивание на границу слова
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             По умолчанию Borland Pascal выравнивает все переменные и ти-
        пизованные константы,  превышающие по размеру 1 байт,  на границу
        машинного слова. На всех 16-разрядных процессорах семейства 80х86
        выравнивание на границу слова означает более быстрое  выполнение,
        поскольку  доступ к элементам размером в слово или четным адресам
        осуществляется быстрее, чем к словам по нечетному адресу.

             Выравнивание данных  управляется  директивой компилятора $A.

         B.Pascal 7 & Objects/LR     - 409 -

        По умолчанию в состоянии {$A+} переменные и типизованные констан-
        ты выравниваются указанным выше образом.  В состоянии {$A-} ника-
        ких действий по выравниванию не производится.

                   Примечание: Дальнейшие подробности приведены в Главе 2
              ("Директивы компилятора") "Справочного руководства програм-
              миста".

                          Удаление неиспользуемого кода
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             if false then
                  statement         { оператор }
              while false do
                  statement

                             Эффективная компоновка
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Компоновщик Borland Pascal автоматически удаляет неиспользу-
        емый код (по процедурам), то есть процедуры и функции, являющиеся
        частью скомпилированной программы, но к которым нет обращений, не
        включаются в файл типа .EXE. Процедуры, функции, переменные и ти-
        пизованные константы, участвующие в процессе компиляции, но ссыл-
        ки на которые отсутствуют,  удаляются из файлa .EXE. Удаление не-
        используемого кода выполняется по процедурам,  а  удаление  неис-
        пользуемых данных - по секциям, где эти данные описываются.

             Рассмотрим следующую программу:

             program SmartLink;
             const
                H: array[0..15] of char = '0123456789ABCDEF';
             var
                I,J : integer;
                X,Y : real;
             var
                S: string[79];
             var
                A: array[1..10000] of integer;

             procedure P1:
             begin
               A[1] = 1;
             end;

             procedure P2;
             begin
                I := 1;

         B.Pascal 7 & Objects/LR     - 410 -

             end;

             procedure P3;
             begin
                S := 'Borland Pascal';
                P2;
             end;

             begin
                P3;
             end;

             Основная программа вызывает процедуру P3,  которая  вызывает
        процедуру  P2,  поэтому  обе  процедуры P2 и P3 включаются в файл
        .EXE.  Поскольку P2 ссылается на первый раздел описания  перемен-
        ных,  а P3 ссылается на второй раздел описание переменных,  пере-
        менные I,  J, X, Y, S также включаются в выполняемый файл. Однако
        на  процедуру  P1 никаких ссылок нет,  а включенные в выполняемый
        файл процедуры не ссылаются на переменные Н и A, поэтому эти объ-
        екты удаляются.

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



         B.Pascal 7 & Objects/LR     - 411 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
           Часть IV. Использование Borland Pascal с языком ассемблера
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД


                         Глава 24. Встроенный ассемблер
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Встроенный ассемблер Borland Pascal позволяет вам непосредс-
        твенно в программах Паскаля записывать код ассемблера процессоров
        8087/8087 и 80286/80287.  Вы,  конечно, если требуется чередовать
        код  Паскаля и ассемблера,  можете преобразовать код ассемблера в
        машинные инструкции вручную и воспользоваться  затем  операторами
        inline,  либо выполнять компоновку с файлами .OBJ, которые содер-
        жат внешние процедуры и функции (external).

             Встроенные операторы  ассемблера  представляют собой большое
        подмножество синтаксиса, поддерживаемого Турбо Ассемблером и Мак-
        роассемблером фирмы Microsoft.  Встроенный ассемблер поддерживает
        все коды операций процессором 8086/8087 и 80286/80287 и некоторые
        из операций, используемых в выражениях Турбо Ассемблера.

             За исключением директив DB (определить байт), DW (определить
        слово) и  DD  (определить двойное слово) никакие другие директивы
        Турбо Ассемблера,  типа EQU, STRUC, SEGMENT или MACRO, встроенным
        ассемблером не поддерживаются.  Однако,  операции,  реализуемые с
        помощью директив Турбо Ассемблера, близко соответствуют конструк-
        циям Borland Pascal. Например, большинство директив EQU соответс-
        твуют описаниям Borland Pascal const,  var и type, директива PROC
        -  описаниям  procedure  и  function,  а  директива STRUC - типам
        record Borland Pascal.  Фактически,  встроенный ассемблер Borland
        Pascal можно рассматривать,  как компилятор языка ассемблера, ис-
        пользующий для всех описаний синтаксис Паскаля.

                                  Оператор asm
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Встроенный ассемблер становится доступным с помощью операто-
        ров asm. Оператор asm имеет следующий синтаксис:

          asm оператор_ассемблера < разделитель оператор_ассемблера > end

        где "оператор_ассемблера" представляет собой оператор ассемблера,
        а "разделитель " - это точка с запятой,  новая строка или коммен-
        тарий Паскаля. Приведем некоторые примеры операторов asm:

                 asm
                  mov   ah,0        { считать с клавиатуры код функции }
                  int   16H         { для чтения клавиши вызвать BIOS }
                  mov   CharCode,al { сохранить код ASCII }
                  mov   ScanCode,ah { сохранить код опроса }
                 end;

                 asm

         B.Pascal 7 & Objects/LR     - 412 -

                  push  ds          { сохранить DS }
                  lds   si,Source   { загрузить указатель источника }
                  les   di,Dest     { загрузить указатель приемника }
                  mov   cx,Count    { загрузить размер блока }
                  cld               { переместить }
                  rep   movsb       { скопировать блок }
                  pop   ds          { восстановить DS }
                end;

             Заметим, что на одной строке можно разместить несколько опе-
        раторов ассемблера,  разделив их точками с  запятой.  Кроме  того
        следует  отметить,  что  если операторы ассемблера размещаются на
        разных строках,  разделять их точками с запятой не требуется. За-
        метим также, что точка с запятой не говорит  о том, что остальная
        часть строки представляет собой комментарий.  Комментарии следует
        записывать, используя синтаксис Паскаля: с помощью { и } или (* и
        *).

                             Использование регистров
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Правила использования регистров в операторе asm  в  основном
        совпадают с этими правилами для внешних процедур и функций.  Опе-
        ратор asm должен сохранять регистры BP,  SP,  SS и DS,  но  может
        свободно изменять AX, BX, CX, DX, SI, DI, ES и регистр флагов. На
        входе в оператор asm BP указывает на текущую рамку стека, SP ука-
        зывает на вершину стека, SS содержит адрес сегмента стека, а DS -
        адрес сегмента данных.  За исключением регистров BP,  SP, SS и DS
        оператор  asm  не может делать никаких предположений относительно
        содержимого других регистров на входе в этот оператор.

                         Синтаксис операторa ассемблера
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Оператор ассемблера имеет следующий синтаксис:

        [ метка":" ] < префикс > [код_операции [операнд < "," операнд >]]

        где "метка" - это идентификатор метки,  "префикс" - префикс  кода
        операции ассемблера. "Код_операции" - код инструкции или директи-
        ва ассемблера, а "операнд" - выражение ассемблера.

             Между операторами ассемблера (но не в них) допускается вклю-
        чать комментарии. Допустимо, например, следующее:

             asm
               mov   ax,1                 { начальное значение }
               mov   cx,100               { счетчик }
             end;

        однако следующая запись ошибочна:

             asm

         B.Pascal 7 & Objects/LR     - 413 -

               mov   { начальное значение }  ax,1
               mov   cx, { счетчик } 100
             end;

                                      Метки
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Метки в ассемблере определяются также,  как в Паскале: перед
        оператором записывается идентификатор метки и двоеточие.  Как и в
        Паскале, метки в ассемблере должны описываться в объявлении label
        того блока, который содержит оператор asm. Однако из этого прави-
        ла есть одно исключение. Это локальные метки.

             Локальные метки - это метки, которые начинаются с символа @.
        Поскольку этот  символ не может быть частью идентификатора Паска-
        ля,  такие локальные метки автоматически ограничиваются использо-
        ванием их в операторах asm. Локальная метка известна только в оп-
        ределяющем ее операторе asm (то есть область  действия  локальной
        метки  начинается от ключевого слова asm и заканчивается ключевым
        словом end оператора asm, который ее содержит).

             В отличие от обычной метки, локальную метку перед ее исполь-
        зованием не требуется описывать в объявлении label.

             Идентификатор локальной метки состоит из символа @, за кото-
        рым  следует одна или более букв (A..Z) цифр (0..9) символов под-
        черкивания или символов @.  Как и все метки, идентификатор завер-
        шается двоеточием.

         s                        Коды инструкций
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Встроенный ассемблер   поддерживает  инструкции  процессоров
        8086/8087 и  80286/80287.  Инструкции  процессора  8087  доступны
        только  в состоянии {$N+} (разрешено использование сопроцессора),
        инструкции процессора 80286 - только в состоянии {$G+} (разрешена
        генерация  кода для процессора 80286),  а инструкции сопроцессора
        80287 - только в состоянии {$G+,N+}.

             Полное описание каждой инструкции  содержится  в  справочных
        материалах по процессорам 80х86 и 80х87.

                              Размер инструкции RET
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Инструкция REP генерирует код машинной  инструкции  возврата
        ближнего или дальнего типа,  в зависимости от модели вызова теку-
        щей процедуры или функции.

             procedure NearProc; near;
             begin
               asm
                 ret      { генерируется ближний возврат }

         B.Pascal 7 & Objects/LR     - 414 -

               end;
             end;

            procedure FarProc; far
             begin
               asm
                 ret      { генерируется дальний возврат }
               end;
             end;

             С другой стороны,  инструкции RETN и RETF всегда  генерируют
        ближний или  дальний возврат соответственно,  независим от модели
        вызова текущей процедуры или функции.

                   Автоматическое определение размера перехода
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Если не указывается противное,  встроенный ассемблер оптими-
        зирует инструкции перехода, автоматически выбирая наиболее корот-
        кую,  и, следовательно, наиболее эффективную форму инструкции пе-
        рехода.  Такое  автоматическое   определение   размера   перехода
        применяется  к инструкции безусловного перехода (JMP) и всем инс-
        трукциям условного перехода,  когда переход выполняется на метку,
        а не процедуру или функцию.

             Для инструкции  безусловного  перехода  встроенный ассемблер
        генерирует короткий переход (один байт кода операции,  за которым
        следует один байт смещения), если расстояние до целевой метки на-
        ходится в границах от -128 до 127 байт.  В противном случае гене-
        рируется  ближний  переход  (один байт кода операции,  за которым
        следую два байта смещения).

             Для инструкций условного  перехода  короткий  переход  (один
        байт кода операции,  за которым следует один байт смещения) гене-
        рируется,  если расстояние до целевой метки находится в  пределах
        от -128 до 127 байт,  в противном случае встроенный ассемблер ге-
        нерирует короткий переход с обратным условием, который выполняет
        переход  на целевую метку через ближний переход (в общем случае 5
        байт). Например, оператор ассемблера:

             JC    Stop

        где Stop не находится в границах короткого перехода, преобразует-
        ся в последовательность машинных кодов,  соответствующих инструк-
        циям:

             jnc   Skip
             jmp   Stop
             Skip:

             Переходы на точки входа в процедуру или функцию всегда имеют
        ближний или дальний тип (но не короткий),  а условные переходы на
        процедуру или функцию не допускаются.  Вы можете указать встроен-

         B.Pascal 7 & Objects/LR     - 415 -

        ному ассемблеру, что нужно генерировать ближний или дальний пере-
        ход, используя конструкцию NEAR PTR или FAR PTR. Например, опера-
        торы ассемблера:

             jmp      NEAR PTR Stop
             jmp      FAR PTR Stop

        будут всегда генерировать соответственно ближний и дальний  пере-
        ход,  даже  если  на метку Stop можно перейти с помощью короткого
        перехода.

                              Директивы ассемблера
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Встроенный ассемблер  Borland Pascal поддерживает три дирек-
        тивы ассемблера: DB (определить байт), DW (определить слово) и DD
        (определить двойное слово).  Каждая из них генерирует данные, со-
        ответствующие разделенным запятым операндам,  которые следуют  за
        директивой.

             Директива DB генерирует последовательность байт. Каждый опе-
        ранд может представлять собой выражение-константу со значением от
        -128 до 255, или строку символов любой длины. Выражение-константа
        генерирует 1 байт кода,  а строки  генерируют  последовательность
        байт со значениями, соответствующим коду ASCII каждого символа.

             Директива DW генерирует последовательность слов. Каждый опе-
        ранд может представлять собой выражение-константу со значением от
        -32768 до 65535,  или адресное выражение. Для адресного выражения
        встроенный ассемблер генерирует указатель ближнего типа, что есть
        слово, содержащие смещения адреса.

             Директива DD  генерирует  последовательность  двойных  слов.
        Каждый операнд может представлять  собой  выражение-константу  со
        значением  от  -2147483648  до 4294967295 или адресное выражение.
        Для адресного выражения встроенный ассемблер генерирует указатель
        дальнего типа, что есть слово, содержащие смещения адреса, за ко-
        торым следует слово, содержащее сегментную часть адреса.

             Данные, генерируемые по директивам DB, DW и DD, всегда запи-
        сываются в сегмент кода,  аналогично коду,  генерируемому другими
        операторами встроенного ассемблера. Чтобы сгенерировать инициали-
        зированные или неинициализированные данные в сегменте данных, вам
        следует использовать обычные описания Паскаля типа var или const.

             Приведем некоторые примеры директив DB, DW и DD:

             asm
               DB      00FH                                   { 1 байт }
               DB      0,99                                  { 2 байта }
               DB      'A'                                   { Ord('A) }
               DB      'Пример',0DH,OAH             { строка, за которой
                              следуют возврат каретки и перевод строки }

         B.Pascal 7 & Objects/LR     - 416 -

               DB      12,"Borland Pascal"            { строка Паскаля }
               DW      0FFFFH                                { 1 слово }
               DW      0,9999                                { 2 слова }
               DW      'A'                     { эквивалентно DB 'A',0 }
               DW      'BA'                  { эквивалентно DB 'A','B' }
               DW      MyVar                          { смещение MyVar }
               DW      MyProc                        { смещение MyProc }
               DD      0FFFFFFFH                     { 1 двойное слово }
               DD      0,99999999                    { 2 двойных слова }
               DD      'A'                 { эквивалентно DB 'A',0,0,0 }
               DD      'DBCA'        { эквивалентно DS 'A','B','C','D' }
               DD      MyVar                      { указатель на MyVar }
               DD      MyProc                    { указатель на MyProc }
             end;

             В Турбо Ассемблере,  когда перед идентификатором указывается
        DB, DW или DD,  это приводит к генерации в том месте, где указана
        директива,  переменной размером в байт,  слово или двойное слово.
        Например, Турбо Ассемблер допускает следующее:

             ByteVar        DB          ?
             WordVar        DW          ?
               .
               .
               .
                            mov         al,ByteVar
                            mov         bx,WordVar

             Встроенный ассемблер не поддерживает такие описания перемен-
        ных. В Borland Pascal единственным видом идентификатора,  который
        можно определить в  операторе  встроенного  ассемблера,  является
        метка.  Все  переменные  должны  описываться с помощью синтаксиса
        Паскаля, и предыдущая конструкция соответствует следующему:

             var
               ByteVar:    Byte;
               WordWat:    Word;
                 .
                 .
                 .
               asm
                 mov       al,ByteVar
                 mov       bx,WordVar
               end;



         B.Pascal 7 & Objects/LR     - 417 -

                                    Операнды
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Во встроенном ассемблере предопределенный смысл имеют следу-
        ющие зарезервированные слова:

             AH        CL          FAR          SEG
             AL        CS          HIGH         SHL
             AND       CX          LOW          SHR
             AX        DH          MOD          SI
             BH        DI          NEAR         SP
             BL        DL          NOT          SS
             BP        DS          OFFSET       ST
             BX        DWORD       OR           TBYTE
             BYTE      DX          PTR          TYPE
             CH        ES          WQORD        WORD
                                                XOR

             Зарезервированные слова всегда имеют больший  приоритет, чем
        определенные пользователем идентификаторы. Например, во фрагменте
        программы:

             var
               ch: Char;
               ...
             asm
               mov   ch,1
             end;

        1 будет загружаться в регистр CH,  а не в переменную CH. Для дос-
        тупа к определенному пользователем имени нужно  использовать  ам-
        персанд - операцию переопределения идентификатора (&).

             asm
               mov        &ch,1
             end;

             Мы настоятельно  рекомендуем  не  использовать  определенные
        пользователем идентификаторы с теми же именами,  что и зарезерви-
        рованные  слова встроенного ассемблера,  поскольку такая путаница
        имен может легко приводить к очень трудноуловимым ошибкам.

                                    Выражения
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Встроенный ассемблер вычисляет все выражения, как 32-разряд-

         B.Pascal 7 & Objects/LR     - 418 -

        ные значения-указатели.  Он не поддерживает значения с  плавающей
        точкой и строковые значения, за исключением строковых констант.

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


                 Различия между выражениями Паскаля и ассемблера
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             const
               X = 10;
               Y = 20;
             var
               Z: Integer;

        следующий оператор является во встроенном ассемблере допустимым:

             asm
               mov       Z,X+Y
             end;

             Поскольку X и Y - это константы, выражение X + Y представля-
        ет собой просто удобный способ записи константы 30,  и полученная
        в  результате  инструкция помещает непосредственное значение 30 в
        переменную Z размером в слово.  Но если вы опишете X и Y, как пе-
        ременные:

             var
               X, Y: Integer;

        то встроенный ассемблер не сможет на этапе  компиляции  вычислить
        значение X + Y.  Корректной конструкцией встроенного ассемблера в
        этом случае будет:

             asm
               mov     ax,X
               add     ax,Y
               mov     Z,ax
             end;

             Другим важным отличием выражений Паскаля и  встроенного  Ас-
        семблера  является  способ интерпретации переменных.  В выражении
        Паскаля ссылка не переменную интерпретируется, как содержимое пе-
        ременной,  но  в выражении встроенного ассемблера ссылка на пере-

         B.Pascal 7 & Objects/LR     - 419 -

        менную означает адрес переменной. Например, в Паскале выражение X
        +  4,  где X - переменная,  означает содержимое X,  плюс 4,  а во
        встроенном ассемблере это означает содержимое в слове  по  адресу
        на 4 байта выше, чем адрес X. Поэтому, хотя допустима запись:

             asm
               mov      ax,X+4
             end;

        этот код не загружает значения X, плюс 4 в AX, а загружает значе-
        ние слова,  записанного через 4 байта после X. Корректной записью
        сложения 4 с содержимым X будет:

             asm
               MOV   AX,X
               ADD   AX,4
             end;


                               Элементы выражений
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Основными элементами  выражения являются константы, регистры
        и идентификаторы.



         B.Pascal 7 & Objects/LR     - 420 -

                                    Константы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Встроенный ассемблер поддерживает два типа констант:  число-
        вые константы и строковые константы.

                               Числовые константы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Числовые константы должны быть целыми и принимать значения в
        диапазоне от -2147483648 до 4294967295.

             По умолчанию числовые константы являются десятичными, однако
        встроенный ассемблер поддерживает также двоичные,  восьмеричные и
        шестнадцатиричные константы.  Двоичное представление обозначается
        записью после числа B, восьмеричное - записью буквы O, а шестнад-
        цатиричное - записью после числа H или указанием перед  числом $.

             В выражениях Паскаля суффиксы B,  O и H  не  поддерживаются.
        Выражения  Паскаля  допускают  только десятичную (по умолчанию) и
        шестнадцатиричную запись (используется префикс $).

             Числовые константы должны начинаться с  одной  из  цифр  или
        символа $.  Таким образом, когда вы записываете шестнадцатиричную
        константу с помощью суффикса H,  то если первой  значащей  цифрой
        является  одна из шестнадцатиричных цифр от A до F,  то требуется
        дополнительный ноль.  Например, 0BAD4H и $BAD4 представляют собой
        шестнадцатиричные константы, а BAD4H - это идентификатор, так как
        он начинается с буквы, а не с цифры.


                               Строковые константы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             'Z'
             'Borland Pascal'
             "That's all folks"
             '"That''s all falks," he said.'
             '100
             '"'
             "'"

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

             В директивах  DB  допускаются строковые кавычки любой длины.
        Это приводит к выделению последовательности байт, содержащих зна-

         B.Pascal 7 & Objects/LR     - 421 -

        чения (ASCII) символов строки.  Во всех других случаях  строковые
        константы не могут превышать четырех символов и обозначают число-
        вое значение,  которое может участвовать в  выражениях.  Числовое
        значение строки вычисляется следующим образом:

            Ord(Ch1) + Ord(Ch2) shl 8 + Ord(Ch3) shl 16 + Ord(Ch4) shl 24

        где Ch1 - это самый правый (последний) символ,  а Ch4 - самый ле-
        вый (первый) символ.  Если строка короче 4 символов, то самые ле-
        вые (первые) символы считаются нулевыми.  Приведем некоторые при-
        меры строковых констант и их значений:

                           Примеры строк и их значения
                                               Таблица 24.1
                     ЪДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДї
                     і   Строка     і    Значение         і
                     ГДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДґ
                     і   'a'        і    00000061H        і
                     і   'ba'       і    00006261H        і
                     і   'cba'      і    00636261H        і
                     і   'dcba'     і    64636261H        і
                     і   'a'        і    00006120H        і
                     і   ' a'       і    20202061H        і
                     і   'a'*2      і    000000E2H        і
                     і   'a'-'A'    і    00000020H        і
                     і   not 'a'    і    FFFFFF9EH        і
                     АДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДЩ




         B.Pascal 7 & Objects/LR     - 422 -

                                    Регистры
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Следующие зарезервированные  идентификаторы  обозначают  ре-
        гистры ЦП:

                               Регистры ЦП                   Таблица 24.2
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
        16-разрядные регистры общего назначения:        AX  BX  CX  DX
        8-разрядные младшие полурегистры:               AL  BL  CL  DL
        8-разрядные старшие полурегистры:               AH  BH  CH  DH
        16-разрядные указатели или индексные регистры:  SP  BP  SI  DI
        16-разрядные сегментные регистры:               CS  DS  SS  ES
        регистр стека процессора 8087                   ST
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Базовые регистры (BX или BP) и индексные  регистры  (SI  или
        DI)  можно  записывать в квадратных скобках для указания индекса-
        ции.  Допустимым сочетанием базового/индексного регистра являются
        [BX], [BP], [SI], [DI], [BX+SI], [BX+DI], [BP+SI] и [BP+DI].

             Сегментные регистры (ES,  CS,  SS и DS) могут использоваться
        вместе с операцией переопределения сегмента (:)  и  указывать  на
        другой сегмент,  отличный от того,  который процессор выбирает по
        умолчанию. На каждый из 8 регистров с плавающей точкой можно ссы-
        латься с помощью ST(x),  где x - константа от 0 до 7, указывающая
        на расстояние от вершины стека регистров.

                                 Идентификаторы
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             @Code                @Data               @Result

             Идентификаторы @Code  и  @Data представляют текущие сегменты
        кода и данных соответственно.  Их следует использовать  только  в
        сочетании с операцией SEG:

             asm
               mov      ax,SEG @Data
               mov      ds,ax
             end;


         B.Pascal 7 & Objects/LR     - 423 -

             Идентификатор @Result в операторной части функции переменную
        - результат функции. Например, в функции:

             function Sum(X, Y: Integer): Integer;
             begin
                Sum := X + Y;
             end;

        в операторе, присваивающем результат функции переменной Sum, мож-
        но было бы при записи на встроенном ассемблере использовать пере-
        менную @Result:

             function Sum(X, Y: Integer): Integer;
             begin
               asm
                 mov   ax,X
                 add   ax,Y
                 mov   @Result,ax
               end;
             end;

             В выражениях встроенного ассемблера нельзя использовать сле-
        дующие идентификаторы:

             - стандартные процедуры и функции (например, WriteLn, Chr);

             - специальные массивы Mem, MemW, MemL, Port, PortW;

             - строки,  значения с плавающей точкой и константы  множест-
               венного типа;

             - метки, которые не описаны в текущем блоке;

             - идентификатор @Result вне функции.

             В Таблице  24.3  приведены значение,  класс и тип различного
        вида идентификаторов,  которые можно  использовать  в  выражениях
        встроенного  ассемблера  (классы  и  типы выражений описываются в
        следующем разделе):


         B.Pascal 7 & Objects/LR     - 424 -


                 Значения, классы и типы идентификаторов     Таблица 24.3
        ДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДВДДДДДДДДДДДДї
        іИдентификат.і     Значение       і     Класс      і     Тип    і
        ГДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДґ
        і Метка      і Адрес метки        і Память         і SHORT      і
        і Константа  і Значение константы і Непосредствен- і  0         і
        і            і                    і ный            і            і
        і Тип        і 0                  і Память         і Размер типаі
        і Поле       і Смещение поля      і Память         і Размер типаі
        і Переменная і Адрес переменной   і Память         і Размер типаі
        і Процедура  і Адрес процедуры    і Память         і  NEAR / FARі
        і Функция    і Адрес функции      і Память         і  NEAR / FARі
        і Модуль     і 0                  і Непосредствен- і  0         і
        і            і                    і ный            і            і
        і @Code      і Адрес сегмента кодаі Память         і 0FFF0H     і
        і @Data      і Адрес сегмента     і Память         і 0FFF0H     і
        і            і  данных            і                і            і
        і @Result    і Смещение перемен-  і Память         і Размер типаі
        і            і ной результата     і                і            і
        АДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДБДДДДДДДДДДДДЩ

             Локальные переменные (переменные,  описанные в процедурах  и
        Функциях)  всегда  распределяются в стеке и доступны относительно
        SS:BP, а значение идентификатора локальной переменной представля-
        ет собой ее смещение со знаком от SS:BP.  ассемблер автоматически
        добавляет [BP] к ссылкам на  локальные  переменные.  Например,  с
        учетом описаний:

             procedure Test;
             var
               Count: Integer;

        инструкции:

             asm
               mov    ax,Count
             end;

        ассемблируются в MOV AX,[BP-2].

             Встроенный ассемблер всегда интерпретирует параметр-перемен-
        ную,  как 32-разрядный указатель,  а размер  параметра-переменной
        всегда равен 4 (размеру 32-разрядного указателя).  В Паскале син-
        таксис для доступа к параметру-переменной и к  значению параметра
        одинаков. В случае встроенного ассемблера это не так. Поэтому для
        доступа к содержимому параметра-переменной вам  сначала  придется
        загрузить 32-разрядный указатель, а затем обратиться к ячейке, на
        которую он указывает. Например, если X и Y - параметры-переменные
        приведенной  выше  функции Sum,  то она может выглядеть следующим
        образом:

             function Sum(var X, Y: Integer): Integer;

         B.Pascal 7 & Objects/LR     - 425 -

             begin
               asm
                 les       bx,X
                 mov       ax,es:[bx]
                 les       bx,Y
                 add       ax,es:[bx]
                 mov       @Result,ax
               end;
             end;

             Некоторые идентификаторы, такие, как переменные типа запись,
        имеют область действия,  позволяющую обращаться к ним  с  помощью
        операции выбора элементы структуры - точки (.).  Например, с уче-
        том описаний:

             type
               Point = record
                 X, Y: Integer;
               end;
               Rect = record
                 A, B: Point;
               end;
             var
               P: Point;
               R: Rect;

        для доступа к полям в переменных P и R можно использовать следую-
        щие конструкции:

             asm
               mov      ax,P.X
               mov      dx,P.Y
               mov      cx,R.A.X
               mov      bx,R.B.Y
             end;

             Для непосредственного  построения переменной можно использо-
        вать идентификатор типа.  Каждая из приведенных  ниже  инструкций
        генерирует   один  и  тот  же  машинный  код,  загружающий  в  AX
        ES:[DI+4]:

             asm
               mov      ax,(Rect PTR es:[di]).B.X
               mov      ax,Rect(es:[di].B.X
               mov      ax,es:Rect[di].B.X
               mov      ax,Rect[es:di].B.X
               mov      ax,es:[di].Rect.B.X
             end;

             Область действия задается типов, полем и идентификатором пе-
        ременной типа записи или объектного типа. Кроме того, идентифика-
        тор модуля открывает область  действия  конкретного  модуля  (как
        полностью уточненный идентификатор в Паскале).

         B.Pascal 7 & Objects/LR     - 426 -


                                Классы выражений
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

             Выражение, состоящее только из имени регистра,  является ре-
        гистровым значением.  Примерами регистровых значений являются AX,
        CL, DI и ES. Используемые в качестве операндов, регистровые выра-
        жения указывают ассемблеру на необходимость генерировать инструк-
        ции, которые работают с регистрами ЦП.

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

             Выражения, которые не являются регистровыми и не  связаны  с
        ячейками памяти,  представляют  собой  непосредственные значения.
        Эта группа включает в себя нетипизированные константы и идентифи-
        каторы типа.

             Непосредственные значения и ссылки на память при использова-
        нии их в качестве операндов приводят к генерации различного кода.
        Например:

             const
               Start = 10;
             var
               Count: Integer;
                .
                .
                .
             asm
               mov        ax,Start           { MOV AX,xxxx }
               mov        bx,Count           { MOV BX,[xxxx] }
               mov        cx,[Start]         { MOV CX,[xxxx] }
               mov        dx,OFFSET Count    { MOV DX,xxxx }
             end;

             Поскольку Start - это непосредственное значение, первая инс-
        трукция  MOV ассемблируется в непосредственную инструкцию. Однако
        вторая инструкция MOV транслируется в инструкцию,  ссылающуюся на
        память,  так как Count - это ссылка на память. В третьей инструк-
        ции MOV для преобразования Start в ссылку  на  память  (в  данном
        случае слово со смещением 10 в сегменте данных) используется опе-
        рация квадратных скобок.  В четвертой инструкции MOV для преобра-
        зования  Count в непосредственное значение (смещение Count в сег-
        менте данных) используется операция OFFSET.

             Как вы  можете  видеть,  квадратные скобки и операция OFFSET
        дополняют друг друга.  В терминах результирующего машинного  кода

         B.Pascal 7 & Objects/LR     - 427 -

        следующий  оператор asm идентичен первым двум строкам предыдущего
        оператора asm:

             asm
               mov       ax,OFFSET [Start]
               mov       bx,[OFFSET Count]
             end;

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

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

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


                                 Типы выражений
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Каждое выражение встроенного ассемблера имеет  соответствую-
        щий тип,  или, если говорить точнее, размер, поскольку встроенный
        Ассемблер рассматривает тип выражения просто как его размер в па-
        мяти.  Например, тип (размер) переменной Integer равен 2, так как
        она занимает два байта.

             Там, где это возможно,  встроенный ассемблер выполняет  про-
        верку типов, поэтому в инструкциях:

             var
               QuitFlag: Boolean;
               OutBufPtr: Word;
                .
                .
                .
             asm
               mov       al,QuitFlag
               mov       bx,OutBufPtr
             end;

        встроенный ассемблер проверяет,  что  размер  QuitFlag  равен   1

         B.Pascal 7 & Objects/LR     - 428 -

        (байт), а размер OutBufPtr - двум (слово). Если проверка типа об-
        наруживает несоответствие,  возникает ошибка. Например, следующее
        недопустимо:

             asm
               mov     dl,OutBufPtr
             end;

        так как DL - это байтовый регистр, а OutBufPtr - слово. Тип ссыл-
        ки на память можно изменить с помощью назначения типа. Корректным
        способом записи предыдущих инструкций будет следующий:

             asm
               mov     dl,BYTE PTR OutBufPtr
               mov     dl,Byte(OutBufPtr)
               mov     dl,OutBufPtr.Byte
             end;

             Все эти инструкции ссылаются на первый (менее значащий) байт
        переменной OutBufPtr.

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

             asm
               mov     al,[100H]
               mov     bx,[100H]
             end;

             Встроенный ассемблер  допускает обе этих функции,  поскольку
        выражение [100H] не имеет соответствующего типа, оно просто озна-
        чает  "содержимое по адресу 100H в сегменте данных",  а тип можно
        определить из первого операнда (байт для AL, слово для BX). В том
        случае, когда тип нельзя определить из другого операнда, встроен-
        ный ассемблер требует явного назначения типа:

             asm
               mov     BYTE PTR [100H]
               mov     WORD PTR [100H]
             end;


         B.Pascal 7 & Objects/LR     - 429 -


             В Таблице 24.4 приведены предопределенные идентификаторы ти-
        па,  которые предусмотрены во встроенном ассемблере дополнительно
        к типам, описанным в Паскале:

                  Предопределенные идентификаторы типа   Таблица 24.4
             ЪДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
             і  Идентификатор     і         Тип                     і
             ГДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
             і  BYTE              і         1                       і
             і  WORD              і         2                       і
             і  DWORD             і         4                       і
             і  QWORD             і         8                       і
             і  TBYTE             і         10                      і
             і  NEAR              і         0FFFEH                  і
             і  FAR               і         0FFFFH                  і
             АДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Заметим в частности,  что NEAR и FAR - это псевдотипы, кото-
        рые используются с идентификаторами процедур и функций для указа-
        ния их модели вызова. Вы можете использовать назначения типа NEAR
        и FAR аналогично другим идентификаторам. Например, если FarProc -
        процедура с дальним типом вызова (FAR):

             procedure FarProc; far;

        и если вы записываете код встроенного ассемблера в том же модуле,
        где  находится  FarProc,  то вы можете использовать для ее вызова
        более эффективную инструкцию NEAR:

             asm
               push      cs
               call      NEAR PTR FarProc
             end




         B.Pascal 7 & Objects/LR     - 430 -

                              Операции в выражениях
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                        Встроенные операции ассемблера       Таблица 24.5
        ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        і  Операция                    і Комментарий                    і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  &                           і Операция переопределения  иден-і
        і                              і тификатора.                    і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  (), [], *                   і Выбор элемента структуры.      і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  HIGH, LOW                   і Унарные операции.              і
        і  +, -                        і                                і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  :                           і Операция  переопределения  сег-і
        і                              і мента.                         і
        і  OFFSET, SEG, TYPE, PTR,     і                                і
        і  *, /, MOD, SHL, SHR         і                                і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  +, -                        і Бинарные операции сложения/вы- і
        і                              і читания.                       і
        ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і  NOT, AND, OR, XOR           і Поразрядные операции.          і
        АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ


         B.Pascal 7 & Objects/LR     - 431 -


               Определения операций  встроенного ассемблера  Таблица 24.6
        ЪДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        іОпер. і                          Описание                      і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і &    і Переопределение идентификатора.  Идентификатор,  непос-і
        і      і редственно следующий за  амперсантом, интерпретируется,і
        і      і как идентификатор, определяемый пользователем, даже ес-і
        і      і ли он соответствует зарезервированному слову встроенно-і
        і      і го ассемблера.                                         і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і (...)і Подвыражение. Выражение  в скобках полностью вычисляет-і
        і      і ся,  после чего интерпретируется, как один элемент. Вы-і
        і      і ражению  в  скобках может предшествовать другое выраже-і
        і      і ние.  Результатом в этом случае  будет  сумма  значенийі
        і      і двух выражений с типом первого выражения.              і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і [...]і Ссылка на  память.  Выражение в квадратных скобках пол-і
        і      і ностью вычисляется,  после чего  интерпретируется,  какі
        і      і один элемент. Выражение в квадратных скобках может ком-і
        і      і бинироваться с регистрами BX, BP, SI, DI с помощью опе-і
        і      і рации  +,  что указывает на индексирование регистра ЦП.і
        і      і Выражению в  квадратных  скобках  может  предшествоватьі
        і      і другое выражение. Результатом в этом случае будет суммаі
        і      і значений двух выражений с типом первого выражения.  Ре-і
        і      і зультатом всегда будет ссылка на память.               і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і .    і Выбор элемента структуры. Результатом будет сумма выра-і
        і      і жения перед точкой и выражения после точки с типом  вы-і
        і      і ражения после точки.  Идентификаторы, относящиеся к об-і
        і      і ласти действия,  и указанные в выражении  перед  точкойі
        і      і доступны в выражении после точки.                      і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і HIGH і Возвращает старшие  8  бит  выражения размером в слово,і
        і      і следующего за операцией. Выражение должно  представлятьі
        і      і собой непосредственное абсолютное значение.            і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і LOW  і Возвращает младшие  8  бит  выражения размером в слово,і
        і      і следующего за операцией. Выражение должно  представлятьі
        і      і собой непосредственное абсолютное значение.            і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і +    і Унарный плюс.  Возвращает следующее за плюсом выражениеі
        і      і без изменений.  Выражение должно представлять собой не-і
        і      і посредственное абсолютное значение.                    і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і -    і Унарный минус.  Возвращает следующее за минусом выраже-і
        і      і ние с обратным знаком.  Выражение  должно  представлятьі
        і      і собой непосредственное абсолютное значение.            і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і :    і Переопределение сегмента. Указывает ассемблеру, что вы-і
        і      і ражение после двоеточия относится к сегменту, заданномуі
        і      і именем сегментного регистра (CS,  DS,  SS или ES) переді
        і      і двоеточием.  Результатом является ссылка на  память  соі

         B.Pascal 7 & Objects/LR     - 432 -

        і      і значением выражения после двоеточия.  Когда переопреде-і
        і      і ление сегмента используется в операнде инструкции, инс-і
        і      і трукции  предшествует соответствующий префикс переопре-і
        і      і деления  сегмента,  обеспечивающий   выбор   указанногоі
        і      і сегмента.                                              і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        іOFFSETі Возвращает смещение  следующего  за операцией выраженияі
        і      і (младшее  слово).  Результатом  будет  непосредственноеі
        і      і значение.                                              і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SEG  і Возвращает сегмент  следующего  за  операцией выраженияі
        і      і (старшее  слово).  Результатом  будет  непосредственноеі
        і      і значение.                                              і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і TYPE і Возвращает тип (размер в байтах) следующего за операци-і
        і      і ей выражения. Типом непосредственного значения будет 0.і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і PTR  і Операция назначения типа.  Результатом будет ссылка  наі
        і      і память со значением выражения,  следующего за операциейі
        і      і и типом выражения перед операцией.                     і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і *    і Умножение. Оба выражения должны представлять собой  не-і
        і      і посредственные  абсолютные значения.  Результатом будеті
        і      і непосредственное абсолютное значение.                  і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і /    і Целочисленное деление.  Оба выражения должны  представ-і
        і      і лять  собой  непосредственные абсолютные значения.  Ре-і
        і      і зультатом будет непосредственное абсолютное значение.  і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і MOD  і Остаток целочисленного деления.  Оба  выражения  должныі
        і      і представлять  собой  непосредственные абсолютные значе-і
        і      і ния. Результатом будет непосредственное абсолютное зна-і
        і      і чение.                                                 і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SHL  і Логический сдвиг влево.  Оба выражения должны представ-і
        і      і лять собой непосредственные  абсолютные  значения.  Ре-і
        і      і зультатом будет непосредственное абсолютное значение.  і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і SHR  і Логический сдвиг вправо. Оба выражения должны представ-і
        і      і лять собой непосредственные  абсолютные  значения.  Ре-і
        і      і зультатом будет непосредственное абсолютное значение.  і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і +    і Сложение. Выражения могут представлять собой непосредс-і
        і      і твенные абсолютные значения или ссылки  на  память,  ноі
        і      і перемещаемым  значением  может быть только одно выраже-і
        і      і ние. Если одно из выражений - перемещаемое значение, тоі
        і      і результатом также будет перемещаемое значение. Если од-і
        і      і но из выражений - ссылка на память, то результатом так-і
        і      і же будет ссылка на память.                             і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і -    і Вычитание. Первое  выражение может иметь любой класс, аі
        і      і второе выражение должно быть непосредственным  абсолют-і
        і      і ным выражением.  Результат имеет тот же тип, что и пер-і

         B.Pascal 7 & Objects/LR     - 433 -

        і      і вое выражение.                                         і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і NOT  і Поразрядное отрицание.  Выражение  должно  представлятьі
        і      і собой непосредственные абсолютные значения. Результатомі
        і      і будет непосредственное абсолютное значение.            і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і AND  і Поразрядная операция  AND  (И).  Оба  выражения  должныі
        і      і представлять  собой  непосредственные абсолютные значе-і
        і      і ния. Результатом будет непосредственное абсолютное зна-і
        і      і чение.                                                 і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і OR   і Поразрядная операция  OR  (ИЛИ).  Оба  выражения должныі
        і      і представлять собой непосредственные  абсолютные  значе-і
        і      і ния. Результатом будет непосредственное абсолютное зна-і
        і      і чение.                                                 і
        ГДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
        і XOR  і Поразрядная операция XOR (исключающее ИЛИ). Оба выраже-і
        і      і ния должны представлять собой непосредственные абсолют-і
        і      і ные значения.  Результатом будет непосредственное абсо-і
        і      і лютное значение.                                       і
        АДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ



         B.Pascal 7 & Objects/LR     - 434 -

                         Процедуры и функции ассемблера
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             До сих пор мы рассматривали конструкцию asm...end,  как опе-
        ратор с обычной частью begin...end. Директива assembler в Borland
        Pascal позволяет вам писать на встроенном ассемблере целиком про-
        цедуры  и функции без необходимости begin...end.  Приведем пример
        функции на ассемблере:

             function LongMul(X, Y: Integer) : Longint; assembler;
             asm
               mov            ax,X
               imul           Y
             end;

             Директива assembler приводит к тому,  что Borland Pascal вы-
        полняет при генерации кода следующую оптимизацию:

             - Компилятор не  генерирует  код  для  копирования  парамет-
               ров-значений в локальные переменные. Это влияет на все па-
               раметры-значения строкового типа и  другие  значения-пара-
               метры,  размер которых не равен 1,  2 или 4 байтам. Внутри
               процедуры или функции такие параметры должны интерпретиро-
               ваться, как если бы они были параметрами-переменными.

             - Компилятор  не  выделяет память для результата функции,  и
               ссылка на  идентификатор  @Result  будет  ошибкой.  Однако
               строковые  функции являются исключением из этого правила -
               они всегда имеют указатель @Result, который распределяется
               пользователем.

             - Для процедур и функций,  не имеющих параметров и локальных
               переменных, компилятор не генерирует кадров стека.

             - Для процедуры и функции на ассемблере автоматически  гене-
               рируется код выхода:

                 push   bp        ; присутствует, если Locals <> 0 или
                                  ; Params <> 0
                 mov    bp,sp     ; присутствует, если Locals <> 0 или
                                  ; Params <> 0
                 sub    sp,Locals ; присутствует, если Locals <> 0
                 ...
                 mov    sp,bp     ; присутствует, если Locals <> 0
                 pop    bp        ; присутствует, если Locals <> 0 или
                                  ; Params <> 0
                 ret    Params    ; всегда присутствует

               где Locals - размер локальных переменных,  а Params - раз-
               мер параметров.  Если и Locals и Params = 0, то кода входа
               не будет, и код выхода состоит просто из инструкции RET.

             Функции, использующие директиву assembler, должны возвращать

         B.Pascal 7 & Objects/LR     - 435 -

        результат следующим образом:

             - результаты   функции   порядкового  типа  (Integer,  Char,
               Boolean, перечислимые типы) возвращаются в AL (8-разрядное
               значение),  AX  (16-разрядное значение) или DX:AX (32-раз-
               рядное значение);

             - результаты функции вещественного типа  (Real) возвращаются
               в DX:BX:AX;

             - результаты функции типов 8087 (Single,  Double,  Extended,
               Comp) возвращаются в  ST(0)  (регистр  стека  сопроцессора
               8087);

             - результаты функции типа указатель возвращаются в DX:AX;

             - результаты функции строкового типа возвращаются во времен-
               ной ячейке, на которую указывает @Result.

             Директива assembler во многом похожа на  директиву external.
        Процедуры и функции на ассемблере должны должны  подчиняться  тем
        же правилам,  что и процедуры и функции типа external.  Следующие
        примеры показывают некоторые отличия  операторов  asm  в  обычных
        процедурах и функциях от процедур и функций ассемблера.  В первом
        примере оператор asm используется в обычной функции для  преобра-
        зования строки в верхний регистр. Заметим, что значение параметра
        Str в этом случае ссылается на  локальную  переменную,  поскольку
        компилятор автоматически генерирует код входа,  копирующий факти-
        ческий параметр в локальную память.

             function UpperCase(Str: String): String;
             begin
               asm
                 cld
                 lea        si,Str
                 les        di,@Result
                 SEGSS      lodsb
                 stosb
                 xor        ah,ah
                 xchg       ax,cx
                 jcxz       @3
             @1:
                 SEGSS      lodsb
                 cmp        al,'a'
                 ja         @2
                 cmp        al,'a'
                 ja         @2
                 cmp        al,'z'
                 jb         @2
                 sub        al,20H
             @2:
                 stosb
                 loop       @1

         B.Pascal 7 & Objects/LR     - 436 -

             @3:
              end;
             end;

             Второй пример на ассемблере представляет собой версию  функ-
        ции  UpperCase.  В  этом случае Str не копируется в локальную па-
        мять, и  функция должна интерпретировать Str,  как параметр-пере-
        менную.

             function UpperCase(S: String): String; assembler;
             asm
               push        ds
               cld
               lds         si,Str
               les         di@Result
               lodsb
               stosb
               xor         ah,ah
               xchg        ax,cx
               jcxz        @3
             @1:
               lodsb
               cmp         al,'a'
               ja          @2
               cmp         al,'z'
               jb          @2
               sub         al,20H
             @2:
               stosb
               loop       @1
             @3:
               pop        ds
             end;



         B.Pascal 7 & Objects/LR     - 437 -

ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
             Глава 25. Компоновка с программами на языке ассемблера
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             С помощью директивы компилятора $L можно выполнить компонов-
        ку программ или модулей на языке Паскаль и процедур и  функций на
        языке ассемблера.  Из исходного файла на языке ассемблера можно с
        помощью ассемблера получить объектный файл (с  расширением .OBJ).
        Используя компоновщик, несколько объектных файлов можно скомпоно-
        вать с программой или модулем.  При этом  используется  директива
        компилятора $L.

             В программе  или модуле на языке Паскаль процедуры или функ-
        ции, написанные  на  языке  ассемблера,  должны  быть описаны как
        внешние. Например:

             function LoCase(Ch : Char): Char; external;

             В соответствующем  файле  на  языке ассемблера все процедуры
        или функции должны находиться в сегменте с именем CОDЕ  или CSEG,
        или  в  сегменте,  имя  которого заканчивается на _TEXT,  а имена
        внешних процедур и  функций  должны  быть  указаны  в  директивах
        PUВLIC.

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

             В исходном  файле на языке ассемблера могут описываться ини-
        циализированные переменные,  содержащиеся  в  сегменте  с  именем
        CONST или в сегменте,  оканчивающемся на _DAТA, и неинициализиро-
        ванные переменные в сегменте с именем DATA или DSEG,  или в  сег-
        менте,  имя  которого  оканчивается на _BSS.  В исходном файле на
        языке ассемблера эти переменные являются частными, и на них нель-
        зя ссылаться из модуля или программы на Паскале. Они, однако, на-
        ходятся в том же сегменте, что и глобальные переменные Паскаля, и
        доступны через регистр сегмента DS.

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

             Когда объектный  файл  указывается  в директиве $L,  Borland
        Pascal преобразует файл из формата перемещаемых объектных модулей
        (.OBJ) фирмы Intel в свой собственный внутренний формат перемеща-
        емых модулей. Это преобразование возможно лишь при соблюдении не-
        которых правил:

             1.  Все процедуры и функции должны быть помещены в сегмент с
                 именем CODЕ или CSEG,  или в сегмент, имя которого окан-
                 чивается на _TEXT.  Все инициализированные частные пере-

         B.Pascal 7 & Objects/LR     - 438 -

                 менные  должны помещаться в сегмент с именем Const или в
                 сегмент,  имя которого оканчивается на _DATA. Все неини-
                 циализированные  частные переменные должны быть помещены
                 в сегмент, имя которого оканчивается на _DAТA. Неинициа-
                 лизированные локальные переменные  должны  помещаться  в
                 сегмент с именем DATA или DSEG, или в сегмент, имя кото-
                 рого оканчивается на _BSS. Все другие сегменты игнориру-
                 ются,  поэтому  имеется директива GRОUР.  В определениях
                 сегмента может задаваться выравнивание на границу  слова
                 или байта (WORD или ВYTE). При компоновке они всегда вы-
                 равниваются на границу слова.  В определениях  сегментов
                 могут указываться директивы PUВLIС и имя класса (они иг-
                 норируются).

             2.  Borland Pascal игнорирует все данные для  сегментов, от-
                 личных  от  сегмента  кода (CODE,  CSEG или xxxx_TEXT) и
                 инициализированного   сегмента   данных    (CONST    или
                 xxxx_DATA).  Поэтому  при описании переменных в сегменте
                 неинициализированных данных (DAТA,  DSEG  или  xxxx_BSS)
                 для определения значения всегда используйте вопроситель-
                 ный знак (?). Например:

                  Count   DW  ?
                  Buffer  DB  128 DUP(?)

             3.  Байтовые  ссылки на идентификаторы типа EXTRN недопусти-
                 мы.  Это означает,  например,  что операторы НIGНТ и LОW
                 нельзя использовать с идентификаторами типа EXTRN.

                        Турбо Ассемблер и Borland Pascal
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Турбо Ассемблер  (TASM)  значительно  облегчает   разработку
        программ  на  языке  ассемблера  и организации в них интерфейса с
        программами Borland Pascal. Турбо Ассемблер поддерживает специфи-
        ческое использование сегментов, схему памяти и языковую поддержку
        для программистов, работающих на Borland Pascal.

             Используя ключевое  слово  PASCAL и директиву .MODEL,  можно
        обеспечить соблюдение соглашений о вызовах с Borland Pascal,  оп-
        ределить имена сегментов,  выполнить инструкции  PUSH  BP  и  MOV
        PB,SP, а также обеспечить возврат управления с помощью операторов
        POP BP и RET N (где N - это число байт параметра). Директива
        .MODEL имеет следующий синтаксис:

             .MODEL xxxx, PASCAL

        где xxxx - это модель памяти (обычно LARGE).

             Задание в  директиве  .MODEL  языка  PASCAL  сообщает  Турбо
        Ассемблеру, что параметры были занесены в стек слева-направо -  в
        том порядке, в котором они обнаружены в исходном операторе, вызы-
        вающем процедуру.

         B.Pascal 7 & Objects/LR     - 439 -


             Директива PROC позволяет вам задать параметры в том  же  по-
        рядке, как они определены в программе Borland Pascal. Если вы оп-
        ределяете функцию,  которая возвращает строку,  обратите внимание
        на  то,  что директива PROC имеет опцию RETURNS,  позволяющую вам
        получить доступ к временному указателю строки в стеке и не оказы-
        вающую  влияния на число байт параметра,  добавляемых в операторе
        RET.

             Приведем примеры  кода,  в  которых  используются  директивы
        .MODEL и PROC:

             .MODEL LARGE, PASCAL
             .CODE
             MyProc PROC  FAR 1:BYTE, j : BYTE RETURNS result : DWORD
              PUBLIC MyProc
              les di,result            ; получить адрес временной строки
              mov al,i                 ; получить первый параметр i
              mov bl,j                 ; получить второй параметр j
                .
                .
                .
              ret

             Определение функции в Borland Pascal будет выглядеть следую-
        щим образом:

             function MyProc(i,j : char) : string; external;



         B.Pascal 7 & Objects/LR     - 440 -

                      Примеры программ на языке ассемблера
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Следующая программа  является примером модуля и представляет
        собой две программы на ассемблере,  предназначенные для обработки
        строк.  Функция  UppеrCаsе преобразует символы строки в прописные
        буквы,  а функция StringOf возвращает  строку  символов  заданной
        длины.

             unit Strings;
             interface
             function UpperCase(S: string): string;
             function StringOf(Ch: char; Count: byte): string;
             inplementation
             {$L STRS}
             function UpperCase; external;
             function StringOf; external;
             end.

             Далее приведен файл на языке ассемблера,  в котором реализо-
        ваны программы StringOf и  UppеrCаsе.  Перед  компиляцией  модуля
        Strings этот файл должен  быть  ассемблирован  в  файл  с  именем
        STRS.OBJ. Обратите внимание на то,  что в программах используется
        дальний тип вызова,  так как они описаны  в  интерфейсной  секции
        блока.

              CODE SEGMENT BYTE PUBLIC
                   ASSUME CS:CODE
                   PUBLIC UpperCase, StringOf    ; объявить имена
              function Uppercase(S: String): String
              UpperRes        EQU  DWORD PTR [BP+10]
              UpperStr        EQU  DWORD PTR [BP+6]
              Uppercase       PROC FAR
                    PUSH BP            ; сохранить регистр BP
                    MOV  BP,SP         ; установить стек
                    PUSH DS            ; сохранить регистр DS
                    LDS  SI,UpperStr   ; загрузить адрес строки
                    LES  DI,UpperRes   ; загрузить адрес результата
                    CLD                ; переместить строку
                    LODSB              ; загрузить длину строки
                    STOSB              ; скопировать результат
                    MOV CL,AL          ; поместить длину строки в СХ
                    XOR CH,CH
                    JCXZ U3            ; пропустить в случае пустой
                                       ; строки
              U1:   LODSB              ; пропустить, если символ отличен
                                       ; от 'а'...'z'
                    CPM AL,'a'
                    JB  U2
                    CPM AL,'z'
                    JA  U2             ; переместить строку
                    SUB AL,'a'-'A'     ; преобразовать в прописные буквы
              U2:   STOBS              ; сохранить результат

         B.Pascal 7 & Objects/LR     - 441 -

                    LOOP U1            ; цикл по всем символам
              U3:   POP  DS            ; восстановить регистр DS
                    POP  BP            ; восстановить регистр ВР
                    RET  4             ; удалить параметры и возвратить
                                       ; управление
              UpperCase   ENDP
              ; function StringOf(Ch: Char; Count: Byte): String
              StrOfRes        EQU  DWORD PTR [BP + 10]
              StrOfChar       EQU  BYTE  PTR [BP + 8]
              StrOfCOunt      EQU  BYTE  PTR [BP + 6]
               StringOf       PROC FAR
                 PUSH BP               ; сохранить регистр ВР
                 MOV  BP,SP            ; установить границы стека
                 LES  DI,StrOfRes      ; загрузить адрес результата
                 MOV  AL,StrOfCount    ; загрузить счетчик
                 CLD                   ; продвинуться на строку
                 STOSB                 ; сохранить длину
                 MOV  CL,AL            ; поместить значение счетчика в CX
                 XOR  CH,CH
                 MOV  AL,StrOfChar     ; загрузить символ
                 REP  STOSB            ; сохранить строку символов
                 POP                   ; восстановить ВР
                 RET                   ; извлечь параметры и выйти
              SrtingOf    ENDP
              CODE       ENDS
                         END

             Чтобы ассемблировать  этот  пример  и скомпилировать модуль,
        можно использовать следующие команды:

             TASM STR5
             BPC stringer


                           Методы на языке ассемблера
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Методы, реализованные на языке ассемблера,  можно  скомпоно-
        вать с программами Borland Pascal с помощью директивы компилятора
        $L и зарезервированного ключевого слова external.  Описание внеш-
        него метода  в  объектном  типе не отличается от обычного метода;
        однако в реализации метода перечисляется только заголовок метода,
        за которым  следует зарезервированной слово external.  В исходном
        тексте на ассемблере вместо точки (.) для записи уточненных иден-
        тификаторов следует  использовать  операцию @ (точка в ассемблере
        уже имеет другой смысл и не может  быть  частью  идентификатора).
        Например, идентификатор Паскаля Rect.Init записывается на ассемб-
        лере как Rest@Init.  Синтаксис @ можно использовать как в иденти-
        фикаторах PUBLIC, так и EXTRN.




         B.Pascal 7 & Objects/LR     - 442 -

                             Включаемый машинный код
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Для небольших подпрограмм на языке ассемблера  очень  удобно
        использовать внутренние  директивы  и  операторы  Borland  Pascal
        (операторы inline).  Они позволяют вставлять инструкции машинного
        кода непосредственно в программу или текст  блока,  вместо  того,
        чтобы использовать объектный файл.


                                Операторы Inline
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Оператор inline состоит из зарезервированного слова  Inline,
        за которым следует одна или более встроенных записей (записей ма-
        шинного кода),  разделенных косой чертой и заключенных в  круглые
        скобки:

             inline(10/$2345/Count+1/Data-Offset);

             Оператор inline имеет следующий синтаксис:

                          ЪДДДДДДДДї  ЪДДДї     ЪДДДДДДДДДДї    ЪДДДї
         подставляемый ДД>і inline ГД>і ( ГДДДД>і запись в ГДВД>і ) ГД>
         оператор         АДДДДДДДДЩ  АДДДЩ ^   і машинном і і  АДДДЩ
                                            і   і   коде   і і
                                            і   АДДДДДДДДДДЩ і
                                            і      ЪДДДї     і
                                            АДДДДДДґ / і<ДДДДЩ
                                                   АДДДЩ

             Каждый оператор inline состоит из необязательного специфика-
        тора размера,  < или >, и константы или идентификатора переменой,
        за  которой  следуют  ноль или более спецификаторов смещения (см.
        описанный далее синтаксис).  Спецификатор смещения состоит  из  +
        или -, за которым следует константа.

                                           ЪДДДДДДДДДДДї
         запись во ДДВДДДДДДДДДДДДДДДДДДДД>і константа ГДДДДДДДДДДДДДДД>
         встроенном  і   ЪДДДї      ^      АДДДДДДДДДДДЩ       ^
         машинном    ГДД>і < ГДДДДДДґ                          і
         коде        і   АДДДЩ      і                          і
                     і   ЪДДДї      і                          і
                     ГДД>і > ГДДДДДДЩ                          і
                     і   АДДДЩ                                 і
                     і  ЪДДДДДДДДДДДДДДДї                      і
                     АД>і идентификатор ГДВДДДДДДДДДДДДДДДДДДДДЩ
                        і  переменной   і і                  ^
                        АДДДДДДДДДДДДДДДЩ і                  і
                                     ЪДДДДЩ                  АДДДДДДДДДї
                                     і      ЪДДДДї   ЪДДДДДДДДДї       і
                                     АДДДДД>ізнакГДД>іконстантаіДДВДДДДЩ
                                        ^   АДДДДЩ   АДДДДДДДДДЩ  і

         B.Pascal 7 & Objects/LR     - 443 -

                                        АДДДДДДДДДДДДДДДДДДДДДДДДДЩ

             Каждая запись  inline  порождает 1 байт или одно слово кода.
        Значения вычисляется,  исходя из значения  первой  константы  или
        смещения идентификатора переменной, к которому добавляется или из
        которого вычитается значение каждой из последующих констант.

             Если запись  в  машинном  коде состоит только из констант и,
        если ее значение лежит в 8-битовом диапазоне (0..255), то она по-
        рождает один байт кода.  Если значение выходит за границу 8-бито-
        вого диапазона или если запись inline ссылается на переменную, то
        генерируется одно слово кода (младший байт следует первым).

             Операции < и > могут использоваться для отмены  автоматичес-
        кого  выбора  размера,  который  был описан ранее.  Если оператор
        inline начинается с операции <,  то в код включается только млад-
        ший  значащий  байт значения,  даже если это 16-битовое значение.
        Если оператор inline начинается с операции >, то в код включается
        всегда слово,  даже если старший значащий байт равен 0. Например,
        оператор:

             inline(<$1234/>$44);

        гененирует код длиной три байта: $34,$44,$00.

             Значение идентификатора переменной в записи inline представ-
        ляет собой адрес смещения переменной внутри ее базового сегмента.
        Базовый сегмент глобальных переменных (переменных,  описанных  на
        самом внешнем уровне в модуле или программе) и типизованные конс-
        танты, доступ к которым организован через регистр DS, представля-
        ют  собой  сегмент  данных.  Базовый сегмент локальных переменных
        (переменных, описанных  внутри  подпрограммы)  является сегментом
        стека. В этом случае смещение переменной относится к регистру ВР,
        что автоматически влечет за собой выбор сегмента стека.

                   Примечание: Регистры BP, SP, SS и DS должны сохранять-
              ся с помощью операторов inline.  Значение всех  других  ре-
              гистров можно изменять.

             В следующем примере оператора inline  генерируется  машинный
        код  для записи заданного числа слов или данных в указанную пере-
        менную.  При вызове процедуры FillWord Count  слов  со  значением
        Data записывается в памяти, начиная с первого байта, обозначенно-
        го как Dest.

             procedure FillWord(var Dest, Count, Data: word);
             begin
               inline(
                 $C4/$BE/Dest/                { LES DI,Dest[BP]  }
                 $8B/$8e/Count/               { MOV CX,Xount[BP] }
                 $8B/$86/Data/                { MOV AX,Data[BP]  }
                 $FC/                         { CLD              }
                 $F3/$AB);                    { REP STOSW        }

         B.Pascal 7 & Objects/LR     - 444 -


             В операторной  части  блока  операторы inline могут свободно
        чередоваться с другими операторами.

                                Директивы inline
        ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

             Директивы inline позволяют писать процедуры и функции, кото-
        рые преобразуются при каждом вызове в заданную последовательность
        инструкций, представляющих собой машинный код. Синтаксис у дирек-
        тивы inline такой же, как у оператора inline:

                                              ЪДДДДДДДДДДДДї
             директива ДДДДДДДДДДДДДДДДДДДДДД>і  оператор  ГДДДДДДДДДДДД>
              inline                          і  inline    і
                                              АДДДДДДДДДДДДЩ

             При вызове обычной процедуры или функции (включая те,  кото-
        рые содержат в себе операторы inline)  компилятором  генерируется
        такой  код,  в  котором параметры (если они имеются) помещаются в
        стек, а затем уже для обращения к процедуре или функции генериру-
        ется  инструкция CALL.  Однако,  когда вы обращаетесь к процедуре
        или функции типа inline,  компилятор вместо инструкции CALL гене-
        рирует код из директивы inline. Вот короткий пример двух директив
        inline:

             procedure DisableInterrupts; inline($FA); { CLI }
             procedure EnableInterrupts; inline($FB); { STI }

             Когда вызывается  процедура DisableInterrupt то генерируется
        один байт кода - инструкция CLI.

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

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

             function LongMul(X,Y : Integer): Longint;
               inline(
                 $58/                    { POP DS ; извлечь из стека Y }
                 $5A/                    { POP AX ; извлечь из стека X }
                 $F7/$EA);               { IMUL DX ; DX:AX = X*Y }

             Обратите внимание  на отсутствие инструкций входа и выхода и
        инструкции возврата управления. Их присутствия не требуется, пос-
        кольку  при  вызове  этой функции содержащиеся в ней четыре байта
        просто включаются в текст программы.

         B.Pascal 7 & Objects/LR     - 445 -


             Директивы inline предназначены  только  для  очень  коротких
        (менее 10 байт) процедур и функций.

              Из-за того, что процедуры и функции типа inline имеют харак-
         тер макроопределений,  они не могут использоваться в качестве ар-
         гумента операции @ или в функциях Addr, Offs и Seg.



Яндекс цитирования