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



 

Часть 8


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

     Данное руководство  посвящено используемому в 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;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                  Программа 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;                                                   іі
     іАДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩі
     АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

     Рис. 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. Печать отчета.

     Основная логика   программы   заключена  в  последнем  блоке
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;

     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

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

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

     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 }

     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 имеет раздел описа-
ний, в котором описывается переменная.  Процедуры и функции могут
содержать разделы описаний также как программы и модули.

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

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

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

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

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

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

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

     Программа 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,  ваша прог-
рамма может получить доступ к нескольким подпрограммам операцион-
ной системы и подпрограммам работы с файлами.

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

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

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

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

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

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

                       Глава 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 і
           АДВДЩ          АДВДЩ          АДВДЩ          АДВДЩ
             і              і              і              і
             АДДДДДДДДДДДДДДБДДДДДДДДДДДДДДБДДДДДДДДДДДДДДБДДДД>


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

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

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

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

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

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

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

                    Зарезервированные слова
             и стандартные директивы 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
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

     Меткой является  последовательность цифр в диапазоне от 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

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

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

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

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

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

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

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

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

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

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

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

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

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


                      Глава 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).

     За исключением  этих ограничений для выражений-констант соб-
людаются те же синтаксические правила,  что и для обычных выраже-
ний (описанных в Главе 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;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

     В 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-битовую точность в соот-
ветствии со следующими правилами:

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

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

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

     - Любые операнды размером в байт преобразуются к промежуточ-
       ному операнду размером в слово,  который  совместим  перед
       выполнением  арифметической  операции  с  типами Integer и
       Word.

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

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

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

     Существует 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.

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

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

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

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

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

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

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

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

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

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

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

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

     При применении функции Ord к значению перечислимого типа Ord
возвращает целое число, которое показывает, какое положение зани-
мает это значение в отношении других значений этого перечислимого
типа.  Согласно предшествующим описаниям, 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);

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

     К вещественному типу относится подмножество вещественных чи-
сел, которые могут быть представлены в формате с плавающей точкой
с фиксированным числом цифр.  Запись значения в формате с плаваю-
щей запятой обычно включает три значения - 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.

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

     В состоянии {$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".

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

     Массивы содержат фиксированное число элементов одного  типа,
так называемого типа элемента.  На приводимой ниже синтаксической
диаграмме тип элемента следует за словом 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

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

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

     packed array[M..N] of Char

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

     Массив вида:

     array[0..X] of Char

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

     record
       firstName,lastName : string[40];
       birthDate : Date;
       case citizen : boolean of
         True  : (birthPlace: string[40]);
         False : (country   : string[20];
                  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.


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

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

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

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

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

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

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

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

     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;

     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;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

     Экземпляр объекта  создается посредством описание переменной
или константы  объектного  типа  или путем применения стандартной
процедуры 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-}), то первый виртуаль-
ного метода неинициализированного объекта может привести  к  неп-
редсказуемому поведению.

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

     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 типа.

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

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

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

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

     Экземпляр, обозначенный десигнатором метода,  становится не-
явным фактическим параметром метода; он соответствует формальному
параметру-переменной с именем 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 активизации метода.

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

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

 і   ЪДДДДДДДДДДДДДДДДДДДДДДї ЪДДДї        ЪДДДДДДДДДДДДДДДДДДДДї
 АДВ>і    идентификатор     Г>і . ГДДДДДДД>іидентификатор методаГ>
   і і   объектного типа    і АДДДЩ    ^   АДДДДДДДДДДДДДДДДДДДДЩ
   і АДДДДДДДДДДДДДДДДДДДДДДЩ          і
   і ЪДДДДДДДДДДДДДДДДДДДДДДї          і
   А>і      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;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

     type PChar = ^Char;

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

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

     В стандартном  Паскале  процедуры  и функции рассматриваются
только как части программы, которые можно выполнять с помощью вы-
зова процедуры или функции.  В 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 не позволяет описывать функции, которые возв-
ращают значения процедурного типа.  Результат функции должен быть
строкового,  вещественного, целого, символьного, булевского типа,
указателем  или иметь перечислимый тип,  определенный пользовате-
лем.

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

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

     * значениями 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 проверяется, а не вызывается.

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

     Чтобы они считались совместимыми,  процедурные  типы  должны
иметь одно и то же число параметров,  а параметры в соответствую-
щих позициях должны иметь  тождественные  типы.  При  определении
совместимости процедурных типов имена параметров значения не име-
ют. Значение 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 описан как эквива-
лентный типу, тождественному 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 - нет.


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

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

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

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

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

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

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

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

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

     * Один тип является строковым типом,  а другой  -  строковым
       типом, упакованным строковым типом или типом 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).

     * 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;
       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 выражений-констант.

        Глава 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;

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

        Глава 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;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

     CrtMode   : byte absolute $0040:$0049;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

     Results

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

     Results[Current+1]

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

     Results[Current+1].Data

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

      Results[Current+1].Data^

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

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

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

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

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

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

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

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

     Matrix[I][J]

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

     Matrix[I,J]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

     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.

     Обратите внимание на использование для доступа к  младшим  и
старшим байтам слова типа 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 }

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

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

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

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

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

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

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

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

     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';

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

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

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

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

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

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

     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';

     В таких случаях оставшиеся символы  устанавливаются  в  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

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

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

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

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

     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);

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

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

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

     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);

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

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

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

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

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

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

     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'];

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

     Описание константы  ссылочного  типа  может содержать только
значение 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 "Строки с завершаю-
щим нулем".

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

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

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

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

     type
        ErrorProc = procedure(ErrorCode: Integer);

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

     const
          ErrorHandler: ErrorProc = DefaultError;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

       Унарные арифметические операции
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

                                                    Таблица 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 равно нулю, то результатом будет ошибка.

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

     Типы логических операций показаны в Таблице 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е).

     В 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+} генерируется код с полным вычислением.

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




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

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

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

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

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

     Расширенный синтаксис  (разрешенный по директиве компилятора
{$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 ссылаются на один символьный массив.  Если два сим-
вольный указателя ссылаются на разные массивы, то результат будет
не определен.

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

     Типы операндов для операций над множествами показаны в  Таб-
лице 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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

     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 -
тип ссылки на переменную.  То есть тип результата будет совместим
со всеми другими указателями на тип этой переменной.

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

     Тип выражения можно изменить на другой тип с помощью  приве-
дения типа значений.

                  ЪДДДДДДДДДДДДДї   ЪДДДї   ЪДДДДДДДДДї   ЪДДДї
 приведение   ДДД>іидентификаторГДД>і ( ГДД>івыражениеГДД>і ) ГД>
 типа значения    і    типа     і   АДДДЩ   АДДДДДДДДДЩ   АДДДЩ
                  АДДДДДДДДДДДДДЩ

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

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

     Некоторые примеры приведения типа значений включают  в себя:

     Intereg('A')
     Char(48)
     Boolean(0)
     Color(2)
     IntPtr(@Buffer)
     BytePtr(Ptr($40,$49))

                 Процедурные типы в выражениях
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

     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, нужно использовать следующую конструкцию:

     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.

                      Глава 7. Операторы
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

 оператор ДДВДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДД>
            і  ЪДДДДДї   ЪДДДї ^ і   ЪДДДДДДДДДДДДДДДДї  ^
            АД>іметкаГДД>і : ГДЩ ГДД>іпростой операторГДДґ
               АДДДДДЩ   АДДДЩ   і   АДДДДДДДДДДДДДДДДЩ  і
                                 і   ЪДДДДДДДДДДДДДДДДї  і
                                 АДД>і  структурный   ГДДЩ
                                     і   оператор     і
                                     АДДДДДДДДДДДДДДДДЩ

     Метка - это последовательность цифр в диапазоне от 0 до 9999
или идентификатор.

     Существует два основных вида операторов: простые операторы и
структурные операторы.

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

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

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

                     Оператор присваивания
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

     Выражение должно быть совместимо по присваиванию с типом пе-
ременной  или  типом значения,  возвращаемого функцией в качестве
результата (см. раздел "Совместимость типов" в Главе 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 можно опустить.

                      Операторы процедуры
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

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

     PrintHeaing;
     Transpose(A,N,M);
     Fin(Name,Address);

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

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

                               ЪДДДДї    ЪДДДДДї
         оператор перехода ДДД>іgotoГДДД>іметкаГДДД>
                               АДДДДЩ    АДДДДДЩ

     При использовании оператора перехода должны соблюдаться сле-
дующие правила:

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

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

           Примечание: Хорошая практика программирования  требует
      минимального использования переходов.

                     Структурные операторы
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

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

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

                     ЪДДДДДї       ЪДДДДДДДДї        ЪДДДї
     составной  ДДДД>іbeginГДДДДДД>іоператорГДДДДВДД>іendГДД>
     оператор        АДДДДДЩ   ^   АДДДДДДДДЩ    і   АДДДЩ
                               і     ЪДДДї       і
                               АДДДДДґ ; і<ДДДДДДЩ
                                     АДДДЩ

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

     begin
       Z := X;
       X := Y;
       Y := Z;
     end;


                      Условные операторы
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     Условные операторы  позволяют выбрать для выполнения один из
составных операторов (или не выбрать ни одного).

                               ЪДДДДДДДДДДДДДДДї
      условный оператор  ДДВДД>і оператор if   ГДДДДДДД>
                           і   АДДДДДДДДДДДДДДДЩ   ^
                           і   ЪДДДДДДДДДДДДДДДї   і
                           АДД>і оператор case ГДДДЩ
                               АДДДДДДДДДДДДДДДЩ

                     Оператор условия (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;

                   Оператор варианта (case)
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                 ЪДДДДї   ЪДДДДДДДДДї   ЪДДї      ЪДДДДї
 оператор case Д>іcaseГДД>івыражениеГДД>іofГДДДДД>іcaseГДДВДДї
                 АДДДДЩ   АДДДДДДДДДЩ   АДДЩ  ^   АДДДДЩ  і  і
                                              і   ЪДДДДї  і  і
                                              АДДДґ ;  і<ДЩ  і
                                                  АДДДДЩ     і
                     ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
                     і                                  ЪДДДї
                     АДВДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДД>іendГДД>
                       і   ЪДДДДДДДДДДї  ^  і  ЪДДДї  ^ АДДДЩ
                       АДД>іветвь elseГДДЩ  АД>і ; ГДДЩ
                           АДДДДДДДДДДЩ        АДДДЩ

                     ЪДДДДДДДДДДДДДДДДДДДДї
         ЪДДДДДДДДДї і  ЪДДї  ЪДДДДДДДДДї v   ЪДДДї  ЪДДДДДДДДї
 case ДД>іконстантаГДБД>і..ГД>іконстантаГДДВД>і : ГД>іоператорГД>
      ^  АДДДДДДДДДЩ    АДДЩ  АДДДДДДДДДЩ  і  АДДДЩ  АДДДДДДДДЩ
      і                 ЪДДДї              і
      АДДДДДДДДДДДДДДДДДґ , і<ДДДДДДДДДДДДДЩ
                        АДДДЩ

                 ЪДДДДї    ЪДДДДДДДДї
 ветвь else ДДДД>іelseГДДД>іоператорГДДД>
                 АДДДДЩ    АДДДДДДДДЩ

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

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

     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;



                        Оператор цикла
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     Оператор цикла задает повторное выполнение определенных опе-
раторов.

                                ЪДДДДДДДДДДДДДДДДДї
         оператор цикла  ДДДВДД>і оператор repeat ГДДДДДД>
                            і   АДДДДДДДДДДДДДДДДДЩ  ^
                            і   ЪДДДДДДДДДДДДДДДДДї  і
                            ГДД>і оператор while  ГДДґ
                            і   АДДДДДДДДДДДДДДДДДЩ  і
                            і   ЪДДДДДДДДДДДДДДДДДї  і
                            АДД>і оператор  for   ГДДЩ
                                АДДДДДДДДДДДДДДДДДЩ

     Если число повторений заранее известно,  то подходящей конс-
трукций является оператор for. В противном случае следует исполь-
зовать операторы while или repeat.

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

            Оператор цикла с постусловием (repeat)
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     В операторе  цикла  с  постусловием  (начинающимся  со слова
repeat) выражение, которое управляет повторным выполнением после-
довательности операторов содержится внутри оператора repeat.

            ЪДДДДДДї     ЪДДДДДДДДї     ЪДДДДДї   ЪДДДДДДДДДї
 оператор Д>іrepeatГДДДД>іоператорГДДВД>іuntilГДД>івыражениеГДД>
 repeat     АДДДДДДЩ  ^  АДДДДДДДДЩ  і  АДДДДДЩ   АДДДДДДДДДЩ
                      і    ЪДДДї     і
                      АДДДДґ ; і<ДДДДЩ
                           АДДДЩ

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

     Приведем примеры оператора цикла с постусловием:

     repeat
       K := I mod J;
       I := J;
       J := K;
     until J = 0;

     repeat
       Write('Введите значение (0..9):');
       Readln(I);
     until (I >= 0) and (I <= 9);

            Операторы цикла с предусловием (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;

              Операторы цикла с параметром (for)
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

              ЪДДДї   ЪДДДДДДДДДДДї   ЪДДї   ЪДДДДДДДДї
 оператор ДДД>іforГДД>іуправляющаяГДД>і:=ГДД>іисходноеГДДДї
 for          АДДДЩ   іпеременная і   АДДЩ   ізначениеі   і
                      АДДДДДДДДДДДЩ          АДДДДДДДДЩ   і
         ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
         і      ЪДДї
         і   ЪД>іtoГДДДДДї   ЪДДДДДДДДї   ЪДДї   ЪДДДДДДДДї
         АДДДґ  АДДЩ     ГДД>іконечноеГДД>іdoГДД>іоператорГДДД>
             і  ЪДДДДДДї і   ізначениеі   АДДЩ   АДДДДДДДДЩ
             АД>іdowntoГДЩ   АДДДДДДДДЩ
                АДДДДДДЩ

                            ЪДДДДДДДДДДДДДДДДДДДДДДДДї
 управляющая переменная ДДД>іидентификатор переменнойГДДД>
                            АДДДДДДДДДДДДДДДДДДДДДДДДЩ

                         ЪДДДДДДДДДї
 исходное значение  ДДДД>івыражениеГДДД>
                         АДДДДДДДДДЩ

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

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

           Примечание: О локальности и области действия рассказы-
      вается в Главе 8.

     Когда начинает выполняться оператор for,  начальное и конеч-
ное значения определяются один раз, и эти значения сохраняются на
протяжении всего выполнения оператора for.

     Оператор, который содержится в теле оператора for,  выполня-
ется  один раз для каждого значения в диапазоне между начальным и
конечным значением. Управляющая переменная всегда инициализирует-
ся начальным значением. Когда работает оператор for, значение уп-
равляющей переменной (счетчика циклов) увеличивается  при  каждом
повторении на единицу. Если начальное значение превышает конечное
значение, то содержащийся в теле оператора for оператор не выпол-
нятся.  Когда  в  операторе  цикла  используется  ключевое  слово
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;

где 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);

                         Оператор 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;

     В операторе 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.

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



        Глава 8. Блоки, локальность и область действия
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                           Синтаксис
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     В общем виде любой блок имеет следующий формат:

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

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


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


  раздел           ЪДДДДДДДї       ЪДДДДДДДї      ЪДДДї
  описания ДДДДДДД>і label ГДДДДДД>і метка ГДДВДД>і ; ГДДД>
  меток            АДДДДДДДЩ   ^   АДДДДДДДЩ  і   АДДДЩ
                               і   ЪДДДї      і
                               АДДДґ , ГДДДДДДЩ
                                   АДДДЩ

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

     Раздел описания констант содержит описания констант, локаль-
ных для этого блока.

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

     Раздел описания типов включает описания всех типов в блоке.

 раздел         ЪДДДДДДДї       ЪДДДДДДДДДДДДї
 описания ДДДДД>і type  ГДДДДДД>і  описание  ГДДДДВДДД>
 типов          АДДДДДДДЩ  ^    і    типа    і    і
                           і    АДДДДДДДДДДДДЩ    і
                           АДДДДДДДДДДДДДДДДДДДДДДЩ


     Раздел описания переменных состоит из  описания  переменных,
локальных для этого блока.

 раздел         ЪДДДДДї       ЪДДДДДДДДДДДДї
 описания ДДДДД>і var ГДДДДДД>і  описание  ГДДДДВДДД>
 переменных     АДДДДДЩ  ^    і переменной і    і
                         і    АДДДДДДДДДДДДЩ    і
                         АДДДДДДДДДДДДДДДДДДДДДДЩ


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


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

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

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

 раздел           ЪДДДДДДДДДДДї
 операторов ДДДДД>і составной ГДДДДД>
                  і  оператор і
                  АДДДДДДДДДДДЩ

                 Правила для области действия
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                  Область действия для блока
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

     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.

                    Область действия записи
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

           Примечание: О типе запись рассказывается в Главе 4.

                     Область действия объекта
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

           Примечание: о типе запись рассказывается в Главе 4.

                    Область действия модуля
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

     Идентификаторы встроенных констант,  типов, переменных, про-
цедур и  функций  Borland Pascal действуют,  как если бы они были
описаны в блоке, охватывающем все используемые модули и программу
в целом. В действительности эти стандартные объекты описаны в мо-
дуле System,  который используется любой программой  или  модулем
прежде любого модуля,  указанного в операторе uses. Это означает,
что любой модуль или программа могут  переопределить  стандартные
идентификаторы,  а обращение к ним может быть выполнено с помощью
уточненного (составного) идентификатора, например, System.Integer
или System.Writeln.

                 Глава 9. Процедуры и функции
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

           Примечание: Определение блока вы можете найти в  Главе
      8 "Блоки, локальность и область действия".

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

                        Описания процедур
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД


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

              ЪДДДДДДДДДї   ЪДДДї   ЪДДДДДДДДДДДДї   ЪДДДї
 описание ДДД>ізаголовокГДД>і ; ГДД>і    тело    ГДД>і ; ГДД>
 процедуры    іпроцедурыі   АДДДЩ   іподпрограммыі   АДДДЩ
              АДДДДДДДДДЩ           АДДДДДДДДДДДДЩ

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

                                                ЪДДДДДДї
 блок     ДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДД>імодульГДДДДДДДД>
 подпрограммыі   ЪДДДДДДДДДї      ЪДДДї   ^ і   АДДДДДДЩ    ^
             ГДД>і near    ГДДДДД>і ; ГДДДЩ і   ЪДДДДДДДї   і
             і   АДДДДДДДДДЩ  ^   АДДДЩ     іДД>іforwardГДДДґ
             і   ЪДДДДДДДДДї  і             і   АДДДДДДДЩ   і
             ГДД>і far     ГДДґ             і   ЪДДДДДДДДДї і
             і   АДДДДДДДДДЩ  і             іДД>ідирективаГДґ
             і   ЪДДДДДДДДДї  і             і   і externalі і
             ГДД>і export  ГДДґ             і   АДДДДДДДДДЩ і
             і   АДДДДДДДДДЩ  і             і   ЪДДДДДДДДї  і
             і   ЪДДДДДДДДДї  і             АДД>іблок asmГДДґ
             ГДД>іinterruptГДДЩ                 АДДДДДДДДЩ  і
             і   АДДДДДДДДДЩ                    ЪДДДДДДДДДї і
             АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД>ідирективаГДЩ
                                                і inline  і
                                                АДДДДДДДДДЩ

     Заголовки процедур  именуют идентификаторы процедур и задают
формальные параметры (если они имеются).

           Примечание: Синтаксис списка формальных параметров по-
      казан далее в этой главе в разделе "Параметры".

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

     Приведем пример описания процедуры:

     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-}.

     Чтобы задать конкретную модель вызова,  в описании процедуры
перед ее блоком можно указать директиву near или far. При наличии
такой директивы она переопределяет директиву $F компилятора и ав-
томатический выбор модели вызова.

                        Описания export
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

     * Процедуры и функции экспортируются DLL (динамически компо-
       нуемой библиотекой).

     * Процедуры и функции системного вызова в программе Windows.

     О том, как экспортировать процедуры и функции в DLL, расска-
зывается в  Главе  11 "Динамически компонуемые библиотеки".  Хотя
процедура и функция компилируется с директивой export,  фактичес-
кий экспорт процедуры или функции не происходит, пока подпрограм-
ма не перечисляется в операторе exports библиотеки.

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

     * процедуры Windows;
     * диалоговые процедуры;
     * процедуры системного вызова для перечисления;
     * процедуры уведомления об обращении к памяти;
     * специализированные процедуры Windows (фильтры).

     Borland Pascal автоматически генерирует для процедур и функ-
ций, экспортируемых программой Windows, эффективные системные вы-
зовы. Эффективные  вызовы  ослабляют  необходимость использования
при создании  подпрограмм  системного  вызова   подпрограмм   API
Windows MakeProcInstance и FreeProcInstance.

          Примечание: См. раздел "Код входа и выхода" в Главе 22.

                      Описания 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;

     procedure Walter;
     begin
      .
      .
      Clara(8.3, 2.4);
      .
      .
     end;

     Определяющее описание  процедуры может быть внешним описани-
ем.  Однако,  оно не может быть внутренним описанием  или  другим
опережающим  описанием.  Определяющее описание также не может со-
держать директиву  interrupt,  описания  assembler,  near,   far,
export, inline или другое описание forward.

                       Описания 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, специфицирующие имя динамически компону-
емой библиотеки  (и,  возможно,  импортируемое имя или порядковый
номер импорта),  используются для импорта процедур и  функций  из
динамически компонуемых библиотек.  Например, следующая директива
external импортирует из DLL с именем KERNEL (ядро Windows)  функ-
цию с именем GlobalAlloc:

     function GlobalAlloc(Flags: Word; Bytes: Longint): THandle;
      far; external 'KERNEL' index 15;

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

           Примечание: Подробнее  об импорте функций из DLL расс-
      казывается в Главе 11.

                      Описания 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.

                       Описания функций
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

               ЪДДДДДДДДДї   ЪДДДї   ЪДДДДДДДї   ЪДДДї
 описание  ДДД>ізаголовокГДД>і ; ГДД>і тело  ГДД>і ; ГДД>
 функции       і функции і   АДДДЩ   іфункцииі   АДДДЩ
               АДДДДДДДДДЩ           АДДДДДДДЩ

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

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

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

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

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

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

     Приведем далее примеры описаний функции:

     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) не
допускаются.



                       Описания методов
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     Описание метода внутри объектного типа соответствует  опере-
жающему  описанию  (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;
        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ГВ>іидентификаторГДВДДДДДДДДДДДДДДДД>
 конструктора   АДДДДДДДДДДДЩі АДДДДДДДДДДДДДЩ^і  ЪДДДДДДДДДДї ^
                             і ЪДДДДДДДДДДДДДїіі  і  список  і і
                             А>і уточненный  ГЩАД>іформальныхГДЩ
                               іидентификаторі    іпараметрові
                               і  метода     і    АДДДДДДДДДДЩ
                               АДДДДДДДДДДДДДЩ

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

     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;

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

              Восстановление ошибок конструктора
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     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 - не неуспешное выполнение
из-за вызова в конструкторе Fail.

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

     Программа RECOVER.PAS  демонстрирует,  как  можно переписать
исходный код для реализации восстановления ошибки.  Заметим,  что
для отмены успешного выделения памяти перед вызовом Fail для ито-
гового неуспешного выполнения используются соответствующие  дест-
рукторы   в  Base.Init  и  Derived.Init.  Заметим  также,  что  в
Derived.Init вызов Base.Init содержится внутри выражения, так что
можно проверить успешность выполнения наследуемого конструктора.

                           Параметры
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                       ЪДДДї      ЪДДДДДДДДДДї      ЪДДДї
 список формальных ДДД>і ( ГДДДДД>і описание ГДДВДД>і ) ГДД>
 параметров            АДДДЩ  ^   іпараметра і  і   АДДДЩ
                              і   АДДДДДДДДДДЩ  і
                              і      ЪДДДї      і
                              АДДДДДДґ ; і<ДДДДДЩ
                                     АДДДЩ

                           ЪДДДДДДДДДДДДДї
 описание  ДДВДДДДДДДДДДДД>ісписок иден- ГВДДДДДДДДДДДДДДДДДДДДД>
 параметра   і  ЪДДДї    ^ ітификаторов  іі                  ^
             ГД>іvarГДДДДґ АДДДДДДДДДДДДДЩі ЪДДДї  ЪДДДДДДДї і
             і  АДДДЩ    і                А>і : ГД>ітип па-ГДЩ
             і  ЪДДДДДї  і                  АДДДЩ  іраметраі
             АД>іconstГДДЩ                         АДДДДДДДЩ
                АДДДДДЩ

     Существует три типа параметров: значение, переменная и нети-
пизированная переменная. Они характеризуются следующим:

     1.  Группа  параметров  без  предшествующего ключевого слова
         является списком параметров-значений.

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

     3.  Группа параметров,  перед которыми стоит ключевое  слово
         var и за которыми следует тип,  является списком нетипи-
         зированных параметров-переменных.

     4.  Группа  параметров,  перед которыми стоит ключевое слово
         var или const за которыми не следует тип, является спис-
         ком нетипизированных параметров-переменных.

     Параметры строкового типа и массивы могут быть открытыми па-
раметрами. Параметры-переменные,  описанные с помощью идентифика-
тора OpenString или с использованием  ключевого  слова  string  в
состоянии {$P+},  являются открытыми строковыми параметрами. Зна-
чение,  константа  или  параметр-переменная,  описанные с помощью
синтаксиса array of T, являются открытым параметром-массивом.

           Примечание: Подробнее об открытых параметрах рассказы-
      вается ниже.

                      Параметры-значения
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

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

                      Параметры-константы
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

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

                     Параметры-переменные
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

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

     Директива компилятора  $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
       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.

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

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

                 Открытые строковые параметры
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     Открытые строковые параметры могут описываться двумя  спосо-
бами:

     - с помощью идентификатора 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' }
       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.

                  Открытые параметры-массивы
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     Формальный параметр, описанный с помощью синтаксиса:

     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);
     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 - это вызовы конструкторов и деструк-
торов объектного типа. Для 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,
                  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;
     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 и поэто-
му ее нельзя присваивать процедурной переменной:

     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 байта (два слова),  в которых
содержится адрес памяти.  В первом слове  хранится  смещение,  во
втором - сегмент.

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

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

     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.

     При работе программа 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.

                 Глава 10. Программы и модули
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

                       Синтаксис программ
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     Программа в  Borland  Pascal состоит из заголовка программы,
необязательного оператора uses и основного блока.

программа
  і      ЪДДДДДДДДДї   ЪДДДї                      ЪДДДДї  ЪДДДї
  АДДДВД>ізаголовокГДД>і ; ГДДДВДДДДДДДДДДДДДДДДД>іблокГД>і . ГД>
      і  іпрограммыі   АДДДЩ ^ і  ЪДДДДДДДДДДДї ^ АДДДДЩ  АДДДЩ
      і  АДДДДДДДДДЩ         і АД>іпредложениеГДЩ
      АДДДДДДДДДДДДДДДДДДДДДДЩ    і   uses    і
                                  АДДДДДДДДДДДЩ

                      Заголовок программы
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     Заголовок программы определяет имя программы и ее параметры.

заголовок программы
 і
 і   ЪДДДДДДДї   ЪДДДДДДДДДДДДДї
 АДД>іprogramГДД>іидентификаторГДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД>
     АДДДДДДДЩ   АДДДДДДДДДДДДДЩ і  ЪДДДї  ЪДДДДДДДДДї  ЪДДДї ^
                                 АД>і ( ГД>іпараметрыГД>і ) ГДЩ
                                    АДДДЩ  іпрограммыі  АДДДЩ
                                           АДДДДДДДДДЩ

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

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

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

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

                     ЪДДДДї      ЪДДДДДДДДДДДДДї      ЪДДДї
 предложение uses ДД>іusesГДДВДД>іидентификаторГДДДДД>і ; ГДДД>
                     АДДДДЩ  і   АДДДДДДДДДДДДДЩ  ^   АДДДЩ
                             і      ЪДДДї         і
                             АДДДДД>і , ГДДДДДДДДДЩ
                                    АДДДЩ

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

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

     uses Dos,Crt; { теперь могут быть доступны средства модулей
                     Dos и Crt }


     Чтобы найти файл, содержащий скомпилированный модуль, компи-
лятор усекает  указанное  в  операторе  uses имя модуля до первых
восьми файлов и добавляет расширение файла. Если целевой платфор-
мой является DOS,  расширением будет .TPU. Если целевая платформа
- Windows, то расширением файла будет .TPW. Если целевой платфор-
мой является  защищенный  режим  DOS,  то расширением файла будет
.TPP. Хотя имена файлов усекаются, в операторе uses должен указы-
ваться полный идентификатор модуля.

                       Синтаксис модулей
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

                 ЪДДДДДДДДДї   ЪДДДї   ЪДДДДДДДДДДї
   модуль  ДДДДД>ізаголовокГДД>і ; ГДД>іинтерфейс-ГДДДї
                 і модуля  і   АДДДЩ   іный разделі   і
                 АДДДДДДДДДЩ           АДДДДДДДДДДЩ   і
               ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
               і  ЪДДДДДДДДДДї    ЪДДДДДДДДДДДДДї   ЪДДДї
               АД>і раздел   ГДДД>і раздел      ГДД>і . ГДД>
                  іреализацииі    іинициализацииі   АДДДЩ
                  АДДДДДДДДДДЩ    АДДДДДДДДДДДДДЩ

                       Заголовок модуля
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     В заголовке модуля определяется имя модуля.

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

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

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

                      Интерфейсная секция
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

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

 раздел заголовков
 процедур и функций
  і        ЪДДДДДДДДДї           ЪДДДї
  АДДДДВДД>ізаголовокГДДДДДДДДДД>і ; ГДВДДДДДДДДДДДДДДДДДДДДДДД>
       і   іпроцедурыі        ^  АДДДЩ і  ЪДДДДДДДДДї   ЪДДДї ^
       і   АДДДДДДДДДЩ        і        АД>ідирективаГДД>і ; ГДЩ
       і  ЪДДДДДДДДДДДДДДДДДї і           і inline  і   АДДДЩ
       АД>ізаголовок функцииГДЩ           АДДДДДДДДДЩ
          АДДДДДДДДДДДДДДДДДЩ

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

                       Секция реализации
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

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

 Секция реализации
 і
 і  ЪДДДДДДДДДДДДДДї                     ЪДДДДДДДДДДДДДДДДДДї
 АД>іimplementationГДВДДДДДДДДДДДДДДДДДД>і раздел описаний  ГДД>
    АДДДДДДДДДДДДДДЩ і  ЪДДДДДДДДДДДї^   АДДДДДДДДДДДДДДДДДДЩ
                     АД>і  оператор ГЩ
                        і   uses    і
                        АДДДДДДДДДДДЩ

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

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

                     Секция инициализации
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     Секция инициализации является последней секцией  модуля. Она
может  состоять либо из зарезервированного слова 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 не доступен.

     Для компиляции программы компилятор должен иметь возможность
находить все модули,  от которых она прямо или косвенно  зависит.
Поэтому, для  компиляции Prog компилятор должен иметь возможность
найти и Unit1, и Unit2, иначе возникнет ошибка.

     Когда в интерфейсную часть модуля вносятся изменения, другие
модули,  использующие этот модуль, должны быть заново скомпилиро-
ваны. При использовании команд Make или Build  компилятор  делает
это автоматически. Однако, если изменения коснулись только секции
реализации или секции инициализации,  то другие модули, в которых
используется этот модуль,  перекомпилировать не нужно. В предыду-
щем примере,  если интерфейсная  часть  модуля  Unit1  изменилась
(например, с = 2), то модуль Unit2 нужно перекомпилировать. Изме-
нение же секции реализации (например,  d = 1) не требует переком-
пиляции Unit2.

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

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

     Размещение в  секции  реализации  оператора  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;
     { содержит простую программу вывода информации на экран }

     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 и
модуля В не зависят друг от друга (и,  следовательно, строго соб-
людаются правила Паскаля, касающиеся порядка описания).

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


               Совместное использование описаний
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     Можно модифицировать процедуру 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 ссылаются друг на
друга только в соответствующих секциях реализации.

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

         Глава 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:

     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;

     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);
     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 следует компилировать отдельно.

               Статический и динамический импорт
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     Директива 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;

                         Написание 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  и
коду инициализации библиотеки. Например:

     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.

                  Директива процедуры export
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     Если процедуры и функции должны  экспортироваться  DLL,  они
должны компилироваться с директивой компилятора export. Директива
export принадлежит к тому же семейству процедурных директив,  что
и near,  far,  inline  и interrupt.  Это означает,  что директива
export, если она присутствует,  должна указываться  перед  первым
заданием процедуры или функции - она не может указываться в опре-
деляющем описании или в опережающем описании.

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

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

     Процедура или функция экспортируется DLL, когда она указыва-
ется в операторе exports библиотеки.

 оператор exports
 і   ЪДДДДДДДДДї   ЪДДДДДДДДДДДДДДДДї            ЪДДДї
 АДД>і exports ГДД>і список экспортаГДДДДДДДДДДД>і ; ГДДДДДДД>
     АДДДДДДДДДЩ   АДДДДДДДДДДДДДДДДЩ            АДДДЩ

                      ЪДДДДДДДДДДДДДДДДї
 список экспорта ДДВД>і запись экcпортаГДДДДДДДДДДД>
                   і  АДДДДДДДДДДДДДДДДЩ  ^
                   і        ЪДДДї         і
                   АДДДДДДД>і ; ГДДДДДДДДДЩ
                            АДДДЩ

 оператор exports
   і    ЪДДДДДДДДДДДДДДДї
   АДДД>і идентификатор ГДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
        АДДДДДДДДДДДДДДДЩ  і   ЪДДДДДДДї  ЪДДДДДДДДДДДДДДДДДї ^ і
                           АДД>і index ГД>і целая константа ГДЩ і
                               АДДДДДДДЩ  АДДДДДДДДДДДДДДДДДЩ   і
 ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
 АДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДД>
   і ЪДДДДДДї   ЪДДДДДДДДДДДДДДДДДДДДДї ^і  ЪДДДДДДДДДДї  ^
   А>і name ГДД>і строковая константа ГДЩАД>і resident ГДДЩ
     АДДДДДДЩ   АДДДДДДДДДДДДДДДДДДДДДЩ     АДДДДДДДДДДЩ

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

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

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

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

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

     Операторная часть  библиотеки  состоит из кода инициализации
библиотеки. Код  инициализации  выполняется  только  один раз при
первоначальной загрузке библиотеки. Когда другие прикладные прог-
раммы будут использовать уже загруженную библиотеку,  код инициа-
лизации повторно не выполняется, но увеличивается счетчик исполь-
зования 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
              .
              .
              .
            { выполняется завершение работы системы }
              .
              .
              .
           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  происходит ошибка этапа выполнения,
операционная система аварийно завершает работу,  поэтому  вы  для
предотвращения  ошибок этапа выполнения вы должны включить в свой
код достаточное количество проверок.

            Замечания по программированию библиотек
ДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД

     В следующих разделах описаны некоторые важные моменты, кото-
рые следует иметь в виду при работе с 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). В прикладной програм-
ме 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
содержат одно и то же значение.

              Создание совместно используемых 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,
каждая из  которых защищена от другой и использует полностью изо-
лированную область памяти.



Яндекс цитирования