



                          ГЛАВА 9

                     Программы и модули

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

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

             ---------------------    ---        ----------
Программа -->!заголовок программы!-->( ; )-------! модуль !->
           ! ---------------------    ---  ^ ! ^ ----------
           !                               ! ! !
           --------------------------------- ! !
                                     --------- ---------
                                     !    -----------  !
                                     !    ! предло- !  !
                                     ---->! жение   !---
                                          ! исполь- !
                                          ! зования !
                                          ! (uses)  !
                                          -----------

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

     Заголовок программы определяет имя программы и ее пара-
метры.
               ---------   -----------------
 Заголовок -->( program )->! идентификатор !----------------->
               ---------   ----------------- !           ^
                                             !           !
                ------------------------------           !
                !                                        !
                !   ---   -----------------------   ---  !
                -->( ( )->! параметры программы !->( ) )--
                    ---   -----------------------   ---


                                - 2 -


                        --------------------------
 Параметры программы -->! список идентификаторов !-------->
                        --------------------------

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

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

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

                   ------    -----------------       ---
  Предложение --->( uses )-->! идентификатор !----->( ; )->
 использования     ------  ^ -----------------   !   ---
                           !        ---          !
                           --------( , )<---------
                                    ---

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

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

     Стандартные модули описаны в Главе 12, в разделе "Стан-
дартные модули".
     Чтобы найти модули, заданные в  предложении использова-

                                - 3 -


ния,  компилятор  сначала  проверяет  резидентные модули, то
есть такие модули,  которые  были загружены в память при за-
пуске компилятора из файла  ТURВО.ТРL. Если модуль не найден
в списке резидентных модулей, то компилятором подразумевает-
ся, что он должен находиться на диске. При этом подразумева-
ется, что имя файла должно совпадать с именем модуля и иметь
расширение .ТРU.  Сначала поиск производится с текущем ката-
логе файлов,  затем - в каталогах, заданных в списке катало-
гов файлов в меню "Опции/Компилятор/Модули"  (О/D/Unit)  или
директивой  /U в командной строке компилятора ТРС. Например,
выражение:

  uses Memory;

где Memory не является резидентным модулем, приводит к тому,
что  компилятор будет искать файл МЕМОRY.ТРU в текущем ката-
логе файлов, а затем в каталогах модулей.
     Директива  {$U имя-файла}  позволит  вам переопределить
имя файла, которое выбирается компилятором.  Если данная ди-
ректива  используется  в  предложении  uses  непосредственно
перед именем модуля, то компилятор вместо имени  модуля  ис-
пользует заданное имя файла. Например, выражение:

 uses {$U MEM} Memory;

приведет к тому, что  компилятор будет искать модуль  Memоry
в файле МЕМ.ТРU. Директива {$U имя_файла} задает только сим-
вольную метку дисковода и маршрут доступа к каталогу файлов,
а поиск модуля выполняется в указанном каталоге.
     При  использовании  команд Сомрilе/Маке и Сомрilе/Вuild
при  описании модулей в предложении uses поиск исходных фай-
лов производится также, как файлов  .ТРU, и подразумевается,
что имя исходного файла  совпадает  с именем  модуля и имеет
расширение .РАS. Если вы хотите использовать другие расшире-
ния, их нужно задать в  директиве  {$U имя-файла}. Например,
выражение:

  uses {$U MEMORY.LIB} Memory;

                                - 4 -



приводит к тому, компилятор будет искать исходный  текст мо-
дуля Мемоry в файле МЕМОRY.LIВ.

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

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

            --------------------
 Модуль --->! заголовок модуля !------------
            --------------------           !
    ----------------------------------------
    !
    !    ---   -----------  ----------  ----------
    --->( ; )->!  интер- !  ! секция !  ! секция !   ---
         ---   ! фейсная !->! реали- !->! иници- !->( . )-->
               !  секция !  ! зации  !  ! ализа- !   ---
               -----------  ----------  ! ции    !
                                        ----------

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

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

                ------    ------------------------
 Заголовок --->( unit )-->! идентификатор модуля !----->
  модуля        ------    ------------------------

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


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

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

интерфейсная секция
  -----------
 ( interface )----------------------------------------------->
  ----------- ! ^ ^ !                                    ^ !
              ! ! ! !   -------------------------------- ! !
              ! ! ! !-->!   секция описания констант   !-! !
              ! ! ! !   -------------------------------- ! !
              ! ! ! !   -------------------------------- ! !
 -------------- ! ! !-->!     секция описания типов    !-! !
 !              ! ! !   -------------------------------- ! !
 !              ! ! !   -------------------------------- ! !
 !              ! ! !-->!  секция описания переменных  !-! !
 !              ! ! !   -------------------------------- ! !
 ! -----------  ! ! !   -------------------------------- ! !
 ! ! предло- !  ! ! --->!   секция заголовков процедур !-- !
 ! ! жение   !  ! !     !           и функций          !   !
 ->! исполь- !--- !     --------------------------------   !
   ! зования !    !                                        !
   -----------    ------------------------------------------


                                - 6 -


                        -------------
  Секция заголовков --->! заголовок !    ---
  процедур и функций !  ! процедуры !-->( ; )--------------->
         -------------  ------------- ^  ---     !   ^
         !                            !          !   !
         !   -----------------------  !          !   !
         --->!   заголовок функции !---          !   !
             -----------------------             !   !
                   -------------------------------   !
                   !    -------------------    ---   !
                   ---->!    директива    !-->( ; )---
                        !      inline     !    ---
                        -------------------

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

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

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


 Секция реализации
  ----------------
 ( implementation )---------------------------------------->
  ---------------- ! ^ ! !  -------------------------  ^ !
                   ! ! ! !->! раздел описания меток !->! !
   ----------------- ! ! !  -------------------------  ! !
   !                 ! ! !  -------------------------  ! !
   !                 ! ! !->!     раздел описания   !  ! !
   !                 ! ! !  !         констант      !->! !
   ! --------------- ! ! !  -------------------------  ! !
   ! ! предложение ! ! ! !  -------------------------  ! !
   ->!   uses      !-- ! !->! раздел описания типов !->! !
     ---------------   ! !  -------------------------  ! !
                       ! !  -------------------------  ! !
                       ! !->!    раздел описания    !  ! !
                       ! !  !        переменных     !->! !
                       ! !  -------------------------  ! !
                       ! !  -------------------------  ! !
                       ! -->!    раздел описания    !  ! !
                       !    !   процедур и функций  !--- !
                       !    !                       !    !
                       !    -------------------------    !
                       !                                 !
                       -----------------------------------

                            ----------------------
  Раздел описания  -------->! описание процедуры !-------->
 процедур и функций   !     ----------------------     ^
                      !     ----------------------     !
                      ----->!  описание функции  !------
                            ----------------------

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


                                - 8 -


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

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

                                       -----
 Секция инициализации --------------->( еnd )------------->
                        !              -----            ^
                        !  ---------------------------- !
                        -->!    операторная часть     !--
                           ----------------------------

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

               Косвенное использование модулей

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

  Program Host;         unit Unit;        unit Unit2;
  uses Unit1, Unit2     interface         interface
  const a = b;          const c = 1;      uses Unit1;
  begin                 implementation    const b = c;
  end.                  const d = 2;      implementation;
  end.                  end;

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


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

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

     Размещение секции реализации предложения uses позволяет
"скрыть"  внутренние детали модуля, поскольку используемые в
секции реализации модули оказываются "невидимыми" для  того,
кто  этот модуль использует.  Более важным, однако, является
то, что это позволяет вам строить взаимнозависимые модули.
     В следующей программе показаны два модуля, которые "ис-
пользуют" друг друга. Основная программа Circular использует
модуль с именем Display. Модуль Display содержит в своей ин-
терфейсной  секции одну программу WriteXY, которая имеет три
параметра: пару координат (x,y) и сообщение  для  вывода  на
экран. WriteXY перемещает курсор в точку (x,y) и выводит там
сообщение. В противном случае она вызывает простую программу
обработки ошибки.
     Пока мы не видим здесь  ничего  интересного:  процедура
WriteXY  просто используется  вместо процедуры Write. Однако

                                - 10 -


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

  program Circular;
  { выводит текст, используя WriteXY }

  uses
     Crt, 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

                                - 11 -



 procedure WriteXY(X,Y : integer, Message : string);

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

  inplementation

  uses
     Display;

  procedure ShowError(ErrMsg :string);
  begin
    WriteXY(1,25, 'Ошибка: '+ ErrMsg);

                                - 12 -


  end;

  end.

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

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

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

  procedure WriteXY(SomeWindow : WindRec;
                    X, Y :       integer;
                    Message :    string);

  procedure ShowError(Somewindow : WindRec;
                      ErrMsg : string);

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

 unit WindData;
 integface

                                - 13 -


 type
   WindRec = record
               X1, Y1, X2, Y2 : integer;
               ForeColor,
               BackColor      : byte;
               Active         : boolean;
             end;
  inplementation
  end.

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


