Глава 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 ссылаются друг на

        друга только в соответствующих секциях реализации.

 

             Взаимозависимые модули могут быть полезны в отдельных ситуа-

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

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

        вать, и она будет больше подвержена ошибкам.

Hosted by uCoz