- •Часть I. Работа в среде
- •Глава 1. Интегрированная среда
- •1.1. Окно просмотра результатов Output
- •1.2. Окно просмотра переменных Watch
- •1.3. Структура меню
- •1.3.1. Пункт File (работа с файлами)
- •1.3.2. Пункт Edit (работа с редактором)
- •1.3.3. Пункт Run (запуск на выполнение)
- •1.3.4. Пункт Compile (компиляция)
- •1.3.5. Пункт Options (установка параметров системы)
- •1.3.6. Пункт Debug (установки отладчика)
- •1.3.7. Пункт Break/Watch (точки останова/обзор)
- •1.4. Интерактивная справка
- •Глава 2. Настройка системы
- •2.1. Система настройки среды программирования
- •2.2. Принятые в системе расширения имен файлов
- •Часть II. Язык турбо паскаль
- •Глава 3. Построение программ
- •3.1. Алфавит языка и зарезервированные слова
- •3.2. Общая структура программ
- •3.3. Комментарии и ключи компиляции
- •3.4. Условная компиляция программ
- •Глава 4. Введение в систему типов языка
- •4.1. Простые типы языка
- •4.1.1. Целочисленные типы
- •4.1.2. Вещественные числа
- •4.1.3. Логический тип
- •4.1.4. Символьный тип
- •4.1.5. Строковый тип
- •4.1.6. Адресный тип
- •4.1.7. Перечислимые типы
- •4.1.8. Ограниченные типы (диапазоны)
- •4.2. Сложные типы языка
- •Глава 5. Константы и переменные
- •5.1. Простые константы
- •5.2. Переменные
- •5.2.1. Совмещение адресов директивой absolute
- •5.2.2. Переменные со стартовым значением или типизированные константы
- •5.3. Операция присваивания и совместимость типов и значений
- •5.4.Изменение (приведение) типов и значений
- •Глава 6. Управляющие структуры языка
- •6.1. Простой и составной операторы
- •6.2. Условный оператор (if...Then...Else)
- •If Условие then Оператор1 else Оператор2;
- •6.3. Оператор варианта (case)
- •6.4. Оператор цикла с предусловием (while)
- •6.6. Оператор цикла с параметром (for...Do)
- •6.7. Оператор безусловного перехода Goto
- •6.8. Операторы Exit и Halt
- •6.9. Процедуры и функции
- •6.9.1. Параметры. Глобальные и локальные описания
- •6.9.2. Опережающее описание процедур и функций
- •6.9.3. Объявление внешних процедур
- •6.9.4. Процедуры и функции как параметры
- •6.9.5. Переменные-процедуры и функции
- •6.9.6. Специальные приемы программирования
- •6.10. Модули. Структура модулей
- •6.11. Особенности работы с модулями
- •6.12. Система библиотечных модулей языка
- •Часть III. Средства языка турбо паскаль
- •Глава 7. Массивы, записи и множества в деталях
- •7.1. Массивы (Array) и работа с ними
- •7.2. Тип «запись» (Record) и оператор присоединения With
- •7.3. Тип «множество» (Set). Операции с множествами
- •Глава 8. Обработка символов и строк
- •8.1. Символьный и строковый типы (Char и String)
- •8.2. Операции над символами
- •8.3. Операции над строками
- •8.3.1. Редактирование строк
- •8.3.2. Преобразование строк
- •8.3.2.1. Процедура Str( X [: Width [: dec ] ]; var s : String)
- •Глава 9. Математические возможности Турбо Паскаля
- •9.1. Базовые операции
- •9.2. Битовая арифметика
- •9.3. Логические вычисления и операции отношения
- •9.4. Математические процедуры и функции
- •9.4.1. Обсуждение математических функций языка
- •9.4.2. Генераторы случайных чисел
- •9.4.3. Оптимизация сложения и вычитания
- •9.5. Использование математического сопроцессора 80x87
- •Глава 10. Код программы, данные, адреса
- •10.2. Распределение памяти при выполнении программ
- •10.3. Анализ расположения кода и областей данных программы
- •10.5. Средства для работы с адресами
- •10.5.1. Определение адреса переменных
- •10.5.2. Создание адреса функцией Ptr
- •10.5.3. Определение размеров типов и переменных
- •Глава 11. Ссылки, динамические переменные и структуры
- •11.1. Ссылочные переменные
- •11.2. Операция разыменования
- •11.3. Организация памяти области кучи
- •11.4. Управление размерами области кучи и стека
- •11.5. Процедуры управления кучей
- •11.5.1. Размещение динамических переменных.
- •11.5.2. Освобождение динамических переменных.
- •11.5.3. Управление состоянием кучи.
- •11.5.4. Анализ состояния кучи.
- •11.5.5. Более детальный анализ состояния кучи
- •11.5.6. Обработка ошибок распределения памяти
- •11.6. Ссылки, работающие не с кучей
- •11.7. Как организовать структуры, большие чем 64к?
- •11.8. Практический пример построения стека
- •Глава 12. Ввод-вывод данных и файловая система
- •12.1. Понятие логического файла
- •12.2. Физические файлы в ms-dos
- •12.3. Понятие буфера ввода-вывода
- •12.4. Файловые типы Турбо Паскаля
- •12.5. Общие процедуры для работы с файлами
- •12.5.1. Связывание файлов
- •12.5.2. Открытие файлов
- •12.5.3. Закрытие файлов
- •12.5.4. Переименование файлов
- •12.5.5. Удаление файлов
- •12.5.6. Анализ состояния файлов
- •12.6. Текстовые файлы
- •12.6.1. Текст-ориентированные процедуры и функции
- •12.6.2. Операции ввода-вывода в текстовые файлы
- •123 1.23 [Клавиша ввода]
- •123 [Клавиша ввода] 1.23 [Клавиша ввода]
- •12.7. Типизированные файлы и операции ввода-вывода
- •12.8. Бестиповые файлы и операции ввода-вывода
- •12.9. Последовательный и прямой доступ к файлам
- •12.9.1. Опрос размеров файлов и позиции в них
- •12.9.2. Позиционирование в файлах
- •12.9.3. Усечение файлов
- •12.10. Процедуры для работы с каталогами
- •12.11. Обработка ошибок ввода-вывода
- •12.11.1. Функция ioResult
- •12.11.2. Примеры обработки ошибок ввода-вывода
- •12.11.3. Сводка номеров ошибок ввода-вывода
- •Глава 13. Объектно-ориентированное программирование
- •13.1. Определения объектов
- •13.2. Область действия полей объекта и параметр Self
- •13.3. Наследование
- •13.4. Присваивание объектов
- •13.5. Полиморфизм
- •13.5.1. Статические методы
- •13.5.2. Виртуальные методы
- •13.5.3. Выбор вида метода
- •13.6. Динамические объекты
- •13.6.1. Создание динамических объектов
- •13.6.2. Освобождение объектов. Деструкторы
- •13.6.3. Обработка ошибок при работе с динамическими объектами
- •13.7. Функции TypeOf и SizeOf
- •13.8. Задание стартовых значений объектам
- •13.9. Модули, экспортирующие объекты
- •Глава 14. Специальные средства языка
- •14.1. Работа с командной строкой. Функции ParamCount и ParamStr
- •14.2. Доступ к памяти пэвм. Массивы Mem, MemW, MemL
- •14.3. Доступ к портам ввода-вывода. Массивы Port и PortW
- •14.4. Процедура заполнения FillChar
- •14.5. Процедура перемещения данных Move
- •14.6. Функции обработки машинных слов Lo, Hi и Swap
- •14.7. Вставки машинного кода в программе
- •14.7.1. Оператор inline
- •14.7.2. Процедуры с директивой inline
- •14.8. Процедура завершения и обработка ошибок программ
- •14.8.1. Оператор RunError
- •14.8.2. Сводка номеров фатальных ошибок
- •Часть IV. Специальные библиотеки языка
- •Глава 15. Модуль crt
- •15.1. Вывод специальных символов
- •15.2. Модификация операторов Read, ReadLn
- •15.3. Системные переменные модуля crt
- •15.3.1. Переменные управления выводом на дисплей
- •15.3.2. Переменные управления работой клавиатуры
- •15.3.3. Переменная TextAttr
- •15.4. Процедуры и функции модуля crt
- •15.4.1. Работа с экраном в целом
- •15.4.2. Позиционирование курсора
- •15.4.3. Работа со строками
- •15.4.4. Настройка цвета
- •15.4.5. Подача звуковых сигналов
- •15.4.6. Использование встроенного таймера
- •15.4.7. Опрос клавиатуры
- •If KeyPressed then Действие ;
- •15.4.8. Переназначение стандартных файлов
- •Глава 16. Модуль dos
- •16.1. Опрос и установка параметров ms-dos
- •16.1.1. Управление параметрами break и verify 16.1.1.1.
- •16.1.2. Опрос системных переменных ms-dos
- •16.2. Работа с часами и календарем
- •16.2.1. Опрос и назначение даты
- •16.2.3. Работа с датой создания файлов
- •16.3. Анализ ресурсов дисков
- •16.4. Работа с каталогами и файлами
- •16.4.1. Типы и константы модуля dos для работы с файлами
- •16.4.2. Переменная DosError
- •16.4.3. Процедуры поиска файлов на диске
- •16.4.4. Работа с атрибутами файлов
- •16.4.5. Анализ имен файлов
- •16.5. Работа с прерываниями ms-dos
- •16.5.1. Чтение и перестановка адресов подпрограмм прерываний
- •16.5.2. Вызов прерывания процедурой Intr
- •16.5.3. Процедура MsDos
- •6.6. Организация субпроцессов и резидентных программ
- •16.6.1. Программирование субпроцессов
- •Глава 17. Модуль Printer
- •7.1. Содержимое модуля Printer
- •17.2. Низкоуровневые средства работы с принтером
- •17.3. Работа с двумя принтерами одновременно
- •Глава 18. Модуль Overlay
- •18.1. Оверлейное построение программ
- •18.2. Правила оформления оверлейных программ
- •18.3. Инициализация работы оверлеев
- •18.3.1. Включение администратора оверлеев
- •18.3.2. Анализ результата инициализации
- •18.3.3. Размещение оверлейного файла в ems-памяти
- •18.4. Управление оверлейным буфером
- •18.4.1. Опрос размера буфера
- •18.4.2. Установка размера буфера
- •18.4.3. Принудительная очистка буфера
- •18.5. Оптимизация работы оверлеев
- •18.5.1. Установка размера области испытаний
- •18.5.2. Подсчет вызовов оверлеев
- •18.6. Предопределенные переменные для работы с оверлеями
- •18.7. Включение оверлеев в ехе-файлы
- •Глава 19. Модуль Graph
- •19.1. Файлы bgi и содержимое модуля Graph
- •19.2. Управление графическими режимами
- •19.2.1. Инициализация и закрытие графического режима
- •19.2.2. Обработка ошибок инициализации
- •19.2.3. Классификация и анализ графических режимов
- •19.2.4. Очистка экрана и переключение режимов
- •19.2.5. Управление режимом вывода отрезков на экран
- •19.3. Системы координат и «текущий указатель»
- •19.3.1. Координаты устройства и мировые координаты
- •19.3.2. Управление «текущим указателем»
- •19.4. Рисование графических примитивов и фигур
- •19.4.1. Линии и их стили
- •1100110011001100 — Всего 16 разрядов.
- •19.4.2. Коэффициент сжатия изображения
- •19.4.3. Окружности, эллипсы и дуги
- •19.4.4. Построение прямоугольников и ломаных
- •19.5. Управление цветами и шаблонами заливки (заполнения)
- •19.5.1. Немного о цветах
- •19.5.2. Задание типа заливки
- •19.5.3. Заливка областей изображения
- •19.5.4. Опрос и установка цветов пера и фона
- •19.5.5. Управление палитрой
- •19.6. Битовые графические операции
- •19.6.1. Битовые операции
- •19.6.2. Работа с фрагментами изображений
- •19.7. Управление видеостраницами
- •19.8. Графические окна
- •19.9. Вывод текста
- •19.9.1. Выбор шрифта и стиля
- •19.9.2. Предварительная загрузка и регистрация шрифтов
- •19.9.3. Непосредственный вывод строк
- •19.9.4. Размер букв и его масштабирование
- •19.9.5. Опрос стиля и ориентации шрифтов
- •19.10. Включение шрифтов и драйверов в ехе-файл
- •19.11. Подключение новых драйверов
- •19.12. Один полезный совет
- •Часть V. Практические
- •Глава 20. Профессиональная работа с
- •20.1. Программный опрос режимов текстового дисплея
- •20.2. Организация доступа к видеопамяти
- •20.3. Запоминание окон экрана и их восстановление
- •20.3.1. Общие принципы работы с окном
- •20.3.2. Модуль Win
- •20.4. Работа с образом экрана на диске
- •20.5. Крупные надписи на экране
- •20.6. Управление формой курсора
- •Глава 21. Как осуществить полный доступ к клавиатуре
- •21.1. Как организовать опрос алфавитно-цифровой клавиатуры
- •21.2. Опрос клавиши в регистре Ctrl
- •21.3. Опрос расширенных кодов и функциональных клавиш
- •21.4. Опрос служебных клавиш
- •21.5. Анализ клавиш регистров и их состояния
- •21.6. Скэн-коды клавиатуры и работа с ними
- •21.7. Эффект обратной записи в буфер ввода
- •Глава 22. Работа с оперативной
- •22.1. Многобитовое и многоплоскостное озув
- •22.2. Карта дисплейной памяти
- •22.3. Вывод текста на графический экран
- •22.4. Работа с графическими образами на диске
- •Приложение 2 Ключи и директивы компилятора
- •Ключи режимов компиляции
- •Директивы с параметрами
- •Приложение 3
- •Файл tpc.Cfg
- •Приложение 4 Список утилит пакета Турбо Паскаль (версия 5.5)
- •Программа администрирования библиотек
- •Утилита поиска текстов grep
- •Утилита преобразования двоичных файлов binobj
- •Приложение 5
- •Основные команды перемещения курсора
- •Расширенный набор команд перемещения курсора
- •Команды вставки и удаления
- •Команды работы с блоками
- •Поиск и замена
- •Прочие команды
- •Приложение 6
- •If False then Оператор;
- •Приложение 7
- •Глава 6. Управляющие структуры языка
- •Глава 8. Обработка символов и строк
- •Глава 9. Математические возможности Турбо Паскаля
- •Глава 16. Модуль dos
- •Глава 17. Модуль Printer
- •Глава 18. Модуль Overlay
- •Глава 19. Модуль Graph
- •Глава 20. Профессиональная работа с текстовыми изображениями
- •Глава 21. Как осуществить полный доступ к клавиатуре
- •Глава 22. Работа с оперативной памятью видеоадаптеров
- •Литература
- •Оглавление
- •Часть I. Работа в среде программирования
- •Часть II. Язык турбо паскаль
- •Часть III. Средства языка турбо паскаль
- •Часть IV. Специальные библиотеки языка
- •Часть V. Практические приемы работы с пэвм
14.7.2. Процедуры с директивой inline
Вставки машинных кодов в программу могут производиться и другим способом: посредством описания процедур или функций директивой inline, содержащей машинные коды, как и оператор inline, рассмотренный в предыдущем разделе. Такие процедуры, собственно, уже не столько процедуры, сколько ассемблерные макросы. Механизм их работы существенно изменяется.
Когда вызывается обычная процедура или функция, не имеющая директивы inline, происходят предварительные действия по размещению локальных переменных в стеке, затем выполняется тело процедуры, после чего освобождается стек и управление передается вызывающей части программы. Но при вызове inline-процедуры или функции просто будут выполнены коды, указанные в директиве inline, без каких-либо предварительных или последующих манипуляций. Пример объявления такой процедуры:
PROCEDURE PrintScreen; inline( $CD / 05 );
Вызов такой процедуры PrintScreen эквивалентен выполнению ассемблерной команды INT 05.
Inline-процедуры и функции не могут иметь тела. Все их содержимое описывается кодами в директиве inline. Но они могут иметь параметры, которые, впрочем, нельзя указывать по имени совместно с кодами (это не относится к глобальным идентификаторам).
Директивы inline предназначены только для очень коротких (менее 10 байтов) процедур и функций в машинных кодах. Из-за того, что процедуры и функции с директивой inline являются макроопределениями, к ним неприменимы операции взятия адреса (оператор @, функции Addr, Ofs и Seg).
14.8. Процедура завершения и обработка ошибок программ
Если действия написанной программы вступают в противоречие с вычислительными возможностями ПЭВМ или требуют невозможного от ее ресурсов, то они, как правило, прерываются с выдачей сообщения типа «Runtime Error NNN». В таком случае мы говорим о фатальной ошибке времени счета (или во время счета). Такие ошибки могут возникать при запросах на размещение динамических переменных при малом объеме свободной памяти, попытках записи на переполненный диск, чтении с пустых дисководов, делениях на нуль или при нарушениях области допустимых значений аргументов функций Sqrt, Ln и т.д. Список этот можно продолжить. Общим для всех этих причин является то, что неизвестно, где и как они могут {307} возникнуть. Как правило, ошибки, не связанные с вводом-выводом, возникают из-за недосмотров в логическом построении программ. Причем хорошо, если все закончится выдачей текста «Runtime Error...», ведь программа может «зависнуть» так, что разблокировать ПЭВМ можно будет только полным перезапуском...
Все ошибки времени счета можно разделить на условно и безусловно фатальные. Условно фатальные ошибки — это те, которые могут блокироваться соответствующими режимами компиляции. Например, ошибка при проверке диапазонов с кодом 201 (Range Check Error) может появиться лишь, если программа откомпилирована в режиме {$R+}, ошибка 202 — переполнение стека (Stack Overflow) — в режиме {$S+}. К условно фатальным можно отнести все ошибки, связанные с вводом-выводом (коды ошибок 2-199), подробно рассмотренные в гл. 12. Отключение соответствующих режимов контроля ошибок вовсе не повышает безошибочность программ. Оно всего лишь загоняет «болезнь» программы внутрь и дает лишний повод усомниться в корректности выдаваемых программой ответов. Безусловно фатальные ошибки — это такие, которые нельзя ничем заблокировать. Сюда относятся все ошибки вычислений с плавающей точкой и некоторые другие.
Мы уже обсуждали способы обработки ошибок ввода-вывода и ошибок при распределении памяти (см. разд. 12.11, 11.5.6). Ниже будет рассмотрен способ обработки фатальных ошибок.
Турбо Паскаль дает возможность перехватить стандартную цепочку завершения программы и подставить свою собственную процедуру, которая будет выполнять любые действия вместо выдачи малоинформативного «Runtime Error...». Восстановить нормальную работу программы при возникновении фатальной ошибки уже нельзя, и после выполнения предписанных действий программа все равно прервется, но перед этим она сможет «нормальным» языком объяснить причину останова, восстановить видеорежимы, цвета, размеры курсора и т.п.
Механизм подстановки процедуры несложен. Вот его алгоритм:
Пишется процедура завершения программы. Это вполне обычная процедура. Требования к ней таковы: она не должна иметь параметров и должна быть откомпилирована в режиме {$F+}. Кроме того, в ней необходимо предпринять ряд действий по обработке ошибок и восстановлению системных адресов.
2. Объявляется переменная, например, с именем OldExitProc, имеющая тип Pointer. {308}
3. В самом начале программы запоминается значение предопределенной системной переменной ExitProc — адрес стандартной процедуры завершения. Оно записывается в объявленную ранее переменную (у нас — в OldExitProc). А в ExitProc записывается значение адреса новой процедуры выхода.
4. Тело новой процедуры завершения должно начинаться с восстановления старого значения ExitProc. Далее, необходимо как бы обнулить системный указатель на фатальную ошибку (даже если ее не будет в действительности, это не повредит), записав в системную переменную ErrorAddr значение nil. Если этого не сделать, то после выполнения анализа ошибки и других действий на экран может вылезти уже не нужное «Runtime Error...».
Подставленная таким образом процедура всегда будет выполняться при завершении программы: будь то естественное завершение, выход по команде Halt или останов из-за ошибки.
Хотя по определению процедура выхода не содержит параметров, ей доступно значение кода ошибки и кодов завершения, посылаемых оператором Halt(N). Они хранятся в системной переменной ExitCode типа Integer. Совместно со значением адреса ErrorAddr переменная ExitCode определяет причину остановки программы (N — значение ExitCode):
|
ExitCode=0 |
ExitCode<>0 |
ErrorAddr= nil |
Естественное завершение |
Выход по Halt(N) |
ErrorAddr<> nil |
Не может быть |
Ошибка N |
Если программа была прервана пользователем с помощью комбинации клавиш Ctrl+Break, то в ExitCode запишется значение 255. Рассмотрим пример подстановки процедуры завершения (рис. 14.7).
Программа на рис. 14.7 всегда будет чистить за собой экран и заканчивать свою работу выдачей одного из предписанных сообщений. Если выполнимый код программы создан в режимах $R- и $I-, то варианты 2..199 и 201 могут никогда не сработать. Можно было использовать условную компиляцию для изъятия их из текста при необходимости.
В принципе возможно создать целую цепочку процедур завершения. Для этого надо лишь в каждой процедуре присваивать {309}
USES CRT; { используется модуль CRT } VAR OldExitProc : Pointer; { здесь запомнится ExitProc } {$F+} { режим компиляции $F+ } PROCEDURE NewExit; { новая процедура выхода } BEGIN ExitProc := OldExitProc; { восстановление пути выхода } TextAttr := White; { задание белого цвета (CRT) } ClrScr; { очистка всего экрана (CRT) } if ErrorAddr <> nil { Выход из-за ошибки? } then { Да. Обрабатывается ее код. } case ExitCode of 2..199:WriteLn('Ошибка ввода-вывода.' ); 200 :WriteLn('ДЕЛЕНИЕ НА 0.Проверьте входные данные'); 201 :WriteLn('Переполнение диапазона.' ); 203 :begin WriteLn('HE ХВАТАЕТ СВОбОДНОЙ ПАМЯТИ.' ); WriteLn('Освободите память и повторите запуск'); end; 205 :WriteLn('Переполнение в вещественном числе.'); 206 :WriteLn('Потеря порядка в вещественном числе.' ); else WriteLn ('Ошибка ', ExitCode, '. ', 'Смотрите описание TURBO PASCAL 5.5') end {case и then} else (Нет. Нормальное завершение } case ExitCode of 255 :WriteLn('Программа прервана.’); else WriteLn('Код завершения программы : ', ExitCode ) end; {case и else} ErrorAddr := nil; { "обнуление" адреса ошибки } END; {$F-} { можно вернуть режим $F- } { == ОСНОВНОЙ БЛОК ПРОГРАММЫ == } BEGIN OldExitProc:= ExitProc; {запоминается адрес ExitProc } ExitProc:= @NewExit; {назначается новая процедура } {...любые остальные действия программы... } END. |
Рис. 14.7
переменной ExitProc адрес следующей процедуры, написанной по тем же правилам, и лишь в самой последней из них восстановить исходное значение ExitProc. {310}
Иногда удобно оформлять процедуры завершения как модули. Программу на рис. 14.7 очень легко переделать в модуль. Надо лишь вписать слова unit Имя, interface и implementation. Тогда при его подключении к основной программе инициализирующая часть настроит процедуру завершения еще до начала выполнения основной программы. Подключать такой модуль надо будет одним из первых в списке раздела USES.
