                             ГЛАВА 9.

                        ПРОГРАММЫ И МОДУЛИ.


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

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


программа
  |      +—————————+   +—+                        +————+   +—+
  +———+—Ў|заголовок+——Ў|;+————+——————————————————Ў|блок+——Ў|.+——Ў
      |  |программы|   +—+ °  |  +———————————+ °  +————+   +—+
      |  +—————————+       |  +—Ў|предложение+—+
      +————————————————————+     |   uses    |
                                 +———————————+


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

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


заголовок программы
 |
 |   +———————+   +—————————————+
 +——Ў|program+——Ў|идентификатор+—+——————————————————————————————Ў
     +———————+   +—————————————+ |  +—+   +—————————+   +—+ °
                                 +—Ў|(+——Ў|параметры+——Ў|)+—+
                                    +—+   |программы|   +—+
                                          +—————————+

                          +———————————————+
параметры программы  ————Ў|   список      +————Ў
                          |идентификаторов|
                          +———————————————+


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


                         Предложение uses.

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


                     +————+      +—————————————+      +—+
предложение uses ———Ў|uses+——+——Ў|идентификатор+—————Ў|;+———Ў
                     +————+  |   +—————————————+  °   +—+
                             |      +—+           |
                             +—————Ў|,+———————————+
                                    +—+

     Модуль System   всегда   используется   автоматически.  System
реализует весь   нижний   уровень,   поддержку   программ   времени
выполнения для  поддержки  таких средств,  как файловый ввод/вывод,
обработка  строк,  операции  с  плавающей   запятой,   динамическое
распределение памяти и других. Кроме System, Turbo Pascal реализует
многие стандартные модули,  такие как Printer,  Dos и Crt.  Они  не
используются автоматически:  Вы  должны  обязательно  включить их в
предложение uses, например:

     uses Dos, Crt; {теперь получен доступ к средствам Dos и Crt}

     Порядок перечисления модулей  в  uses  определяет  порядок  их
инициализации. См. раздел "Раздел инициализации".


                        Cинтаксис модулей.

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


              +—————————+   +—+   +——————————+
модуль  —————Ў|заголовок+——Ў|;+——Ў|интерфейс-+———+
              | модуля  |   +—+   |ный раздел|   |
              +—————————+         +——————————+   |
            +————————————————————————————————————+
            |  +——————————+    +—————————————+   +—+
            +—Ў| раздел   +———Ў| раздел      +——Ў|.+——Ў
               |реализации|    |инициализации|   +—+
               +——————————+    +—————————————+



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

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


                     +————+   +————————————————————+
заголовок модуля ———Ў|unit|——Ў|идентификатор модуля|————Ў
                     +————+   +————————————————————+


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


                       Интерфейсный раздел.

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

интерфейсный раздел
 |
 |  +—————————+
 +—Ў|interfaсe+—+——————————————————————————————————————————————+—Ў
    |         | |  +———————————+° ° |  +——————————————————+  ° |
    +—————————+ +—Ў|предложение++ | +—Ў|раздел объявления +——+ |
                   |   uses    |  | |  |   констант       |  | |
                   +———————————+  | |  +——————————————————+  | |
                                  | |  +——————————————————+  | |
                                  | +—Ў|раздел объявления +——+ |
                                  | |  |типов переменных  |  | |
                                  | |  +——————————————————+  | |
                                  | |  +——————————————————+  | |
                                  | +—Ў|раздел объявления +——+ |
                                  | |  |переменных        |  | |
                                  | |  +——————————————————+  | |
                                  | |  +——————————————————+  | |
                                  | +—Ў|раздел заголовков +——+ |
                                  |    |процедур и функций|    |
                                  |    +——————————————————+    |
                                  +————————————————————————————+

раздел заголовков
процедур и функций
  |        +—————————+           +—+
  +————+——Ў|заголовок+——————————Ў|;+—+———————————————————————Ў
       |   |процедуры|        °  +—+ |  +—————————+   +—+ °
       |   +—————————+        |      +—Ў|директива+——Ў|;+—+
       |  +—————————————————+ |         | inline  |   +—+
       +—Ў|заголовок функции+—+         +—————————+
          +—————————————————+


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


                        Раздел реализации.

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


раздел реализации
 |
 |  +—————————+
 +—Ў|implemen-+—+————————————————————+—————————————————————————+—>
    | tation  | |  +———————————+ ° ° |  +——————————————————+ ° |                       ° |
    +—————————+ +—>|предложение+—+ | +—>|раздел объявления +—+ |
                   |   uses    |   | |  |    меток         | | |
                   +———————————+   | |  +——————————————————+ | |
                                   | |  +——————————————————+ | |
                                   | +—>|раздел объявления +—+ |
                                   | |  |    констант      | | |
                                   | |  +——————————————————+ | |
                                   | |  +——————————————————+ | |
                                   | +—>|раздел объявления +—+ |
                                   | |  |типов переменных  | | |
                                   | |  +——————————————————+ | |
                                   | |  +——————————————————+ | |
                                   | +—>|раздел объявления +—+ |
                                   | |  |переменных        | | |
                                   | |  +——————————————————+ | |
                                   | |  +——————————————————+ | |
                                   | +—>|раздел объявления +—+ |
                                   |    |процедур и функций|   |
                                   |    +——————————————————+   |
                                   +———————————————————————————+

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

     Примечание: Заголовки    процедур   и   функций   могут   быть
сдублированы  из  интерфейсного  раздела.  Необязательно   задавать
список формальных параметров,  но если вы сделали это,  то в случае
несоответствия  объявления  в  интерфейсном   разделе   и   разделе
реализации компилятор выдаст ошибку времени компиляции.


                       Раздел инициализации.

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


                            +———+
раздел инициализации ———+——>|end+——————————————————>
                        |   +———+              °
                        |  +—————————————————+ |
                        +—>|операторная часть+—+
                           +—————————————————+

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


             Косвенные ссылки на используемые модули.

     В предложении  uses  в  программе или модуле указываются имена
только тех модулей,  которые явно используются  этим  модулем  (или
программой).
     Рассмотрим следующий пример:

               program Prog;
               uses Unit2;
               const a = b;
               begin
               end.

               unit Unit2;
               interfase
               uses Unit1;
               const b = c;
               implementation
               end.

               unit Unit1;
               interfase
               const c = 1;
               implementation
               const d = 2;
               end.

     В приведенном выше примере Unit2 явно зависит от Unit1, а Prog
явно  зависит  от Unit2.  Более того,  Prog неявно зависит от Unit1
(через Unit2),  хотя ни  один  из  идентификаторов,  объявленных  в
Unit1, недоступен Prog.
     Чтобы откомпилировать модуль,  Turbo Pascal должен  найти  все
модули,  от  которых  этот  модуль зависит (явно или неявно).  Так,
чтобы откомпилировать Prog,  компилятор должен найти Unit1 и Unit2,
в противном случае произойдет ошибка.
     Когда в интерфейсную часть модуля вносятся  изменения,  другие
модули,    использующие    этот    модуль,   должны   быть   заново
откомпилированы. Однако,  если изменения коснулись  только  раздела
реализации или раздела инициализации,  то другие модули,  в которых
используется этот модуль,  перекомпилировать не нужно. В предыдущем
примере,  если интерфейсная часть модуля Unit1 изменялась (например
С = 2),  то модуль  Unit2  нужно  перекомпилировать.  Изменение  же
раздела реализации (например, D=1) не требует перекомпиляции Unit2.
     При компиляции модуля в Turbo  Pascal  на  основе  контрольной
суммы  интерфейсного  раздела  вычисляется  номер версии модуля.  В
предыдущем примере при компиляции модуля Unit2  в откомпилированной
версии  модуля  Unit2  сохраняется  номер версии модуля Unit1.  При
компиляции   основной   программы   номер   версии   модуля   Unit1
сравнивается  с  номером версии,  сохраненным в модуле Unit2.  Если
номера версий не совпадают,  что  свидетельствует  об  изменении  в
интерфейсной  части  модуля  Unit1  со времени последней компиляции
модуля Unit2,  то компилятор,  в зависимости от режима  компиляции,
выдает сообщение об ошибке или перекомпилирует модуль Unit2.


                     Круговые ссылки модулей.

     Включение предложения  uses  в   разделе   реализации   модуля
позволяет  вам  скрыть внутренние элементы модуля,  так как модули,
используемые в разделе реализации, невидимы для пользователей этого
модуля.  Еще более важно, однако, что это также позволяет создавать
взаимно зависимые модули.
     Следующая программа   показывает,   как   два   модуля   могут
"использовать" друг друга. Основная программа, Circular, использует
модуль Display.  Display содержит одну программу,  WriteXY, которая
имеет три параметра: пару координат (X,Y) и текстовое сообщение для
вывода.  Если  точка  с координатами (X,Y) находится на экране,  то
WriteXY передвигает курсор в (X,Y) и выводит сообщение, в противном
случае она вызывает простую программу - обработчик ошибок.
     До сих пор нет ничего сложного - WriteXY  находится  в  Write.
Где   же   здесь   встречается   круговая   ссылка  модулей  и  как
программа-обработчик  ошибок  выведет  свое  сообщение  об  ошибке?
Использованием  WriteXY  снова.  Таким  образом,  имеется  WriteXY,
которая вызывает программу  обработчик  ошибок  ShowError,  которая
вызывает WriteXY, чтобы поместить сообщение об ошибке на экран.
     Если ваша  голова  закружилась,  посмотрите  на  исходный  код
примера, и вы увидите, что здесь нет ничего хитрого.
     Основная программа Circular,  очищает экран и трижды  вызывает
WriteXY :

          program Circular;
          {выводит на экран текст, используя WriteXY}
          uses
             Crt, Display;
          begin
             ClrScr;
             WriteXY(1, 1, 'Верхний левый угол экрана');
             WriteXY(100, 100, 'За пределами экрана');
             WriteXY(81 - Length('Возврат на экран'), 15,
                                 'Back to reality');
          end.


     Посмотрите на  координаты  (X,Y)  во  втором  вызове  WriteXY.
Трудно вывести текст в точке (100,100) на экран 80x25 строк. Далее,
давайте посмотрим,  как работает WriteXY.  Приведем исходный  текст
модуля Display, содержащий процедуру WriteXY. Если координаты (X,Y)
действительны, то он выводит на экран сообщение; в противном случае
WriteXY выводит сообщение об ошибке :

          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
                GoToXY(X, Y);
                Write(Message);
             end;
             else
                ShowError('Неправильные координаты WriteXY');
           end;
           end.

     Процедура ShowError,    вызываемая     процедурой     WriteXY,
объявлена в  модуле Еrror.  ShowError всегда выводит свое сообщение
об ошибке на 25 строке экрана :

               unit Error;
               {содержит простую программу-обработчик ошибок}
               interface
               procedure ShowError(ErrMsg: String);
               implementation
               uses
                  Display;
               procedure ShowError(ErrMsg: String);
               begin
                  WriteXy(1, 25, 'Error: ' + ErrMsg);
               end;
               end.

     Заметим, что  предложение uses в разделах реализаций Display и
Error ссылаются друг на друга.
     Эти два  модуля могут ссылаться друг на друга в своих разделах
реализации, потому что  Turbo  Pascal  может  компилировать  полные
разделы interface  для обоих модулей,  другими словами Turbo Pascal
допускает ссылку на частично откомпилированный модуль А  в  разделе
реализации  модуля  В,  пока  интерфейсные разделы модулей А и В не
зависят друг от друга (и это следует строгим правилам  Паскаля  для
порядка объявления).


                   Разделение других объявлений.

     Предположим, что Вы захотели изменить WriteXY и ShowError так,
чтобы ввести дополнительный параметр,  который задает прямоугольное
окно на экране :

    procedure WriteXY(SomeWindow: WindRec; X, Y: Integer;
                      Message: String);
    Procedure ShowError (SomeWindow: WindRec;
                         ErrMsg: String);

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

               unit WindData;
               interface
               type
                  WindRec = record
                     X1, Y1, X2, Y2: Integer;
                     ForeColor, BackColor: Byte;
                     Activ: Boolean;
                  end;
               implementation
               end.

     Вдобавок к  модификации   кода   WriteXY   и   ShowError   для
использования  нового  параметра,  интерфейсные  разделы  и  модуля
Display,  и модуля Error могут теперь "использовать" WindData.  Это
стало возможным потому, что модуль WindData не имеет зависимостей в
предложении uses,  а модуль Display и Error ссылаются друг на друга
только в соответствующих разделах реализации.
