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



 

Часть 2


                          ГЛАВА 4

                         Переменные

                    Описания переменных

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

            -----------    -    -----                     -
описание--->!список   !-->(:)-->!тип!------------------->(;)-->
переменной  !идентифи-!    -    ----- !                ^  -
            !каторов  !               !  ------------- !
            -----------               -->!абсолютное !--
                                         !предложение!
                                         -------------

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

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: aaray[1..10,1..10] of real;

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

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

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

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

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

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

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

              --------    -----------    -   -----------
абсолютное-->(absolute)-->!целое без!-->(:)--!целое без!---->
предложение   -------- !  !знака    !    -   !знака    ! ^
                       !  -----------        ----------- !
                       !    --------------------------   !
                       ---->!идентификатор переменной!----
                            --------------------------

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

CrtMode   : byte absolute $0040:$0049;
monochrome Buffer : array[1..25,1..80] of
record
  character,
  attribute : char
end
absolute  $B000:$0000;

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

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

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

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

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

                 ---------------
ссылка на------->!идентификатор!----------------------------->
переменную   !   !переменной   !       ^ ^                 !
             !   ---------------       ! ! --------------  !
             !   -----------------     ! --!квалификатор!<--
             !-->!приведенный тип!-----!   --------------
             !   !переменной     !     !
             !   -----------------     !
             !   ---------------    -  !
             --->!вызов функции!-->(^)--
                 ---------------    -

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

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

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

                  --------
квалификатор----->!индекс!--------------------->
                ! --------              ^
                !   -----------------   !
                !-->!десигнатор поля!---!
                !   -----------------   !
                !            -          !
                ----------->(^)----------
                             -

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

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

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

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

                       -     --------------------
десигнаторы полей---->(.)--->!идентификатор поля!----->
                       -     --------------------

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

Today.year Results[1].count Result[1].when.month

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

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

     Значением переменной-указателя  является  или  nil  (то
есть  пустое  значение),  или адрес значения, указывающий на
динамическую переменную.
     Ссылка на динамическую переменную, на которую указывает
переменная-указатель,  записывается в виде переменной-указа-
теля, после которой ставится символ указателя (^).
     Динамические переменные и значения их указателей созда-
ются  с помощью стандартных процедур New и GetMem. Вы можете
использовать операцию @ и стандартную функцию Ptr для созда-
ния  значений  указателя, которые рассматриваются как указа-
тели динамических переменных.
     Значение nil не указывает ни на какую  переменную.  Ре-
зультат  будет  неопределенным, если вы попытаетесь получить
доступ к динамической переменной при неопределенном значении
указателя или указателе, равном nil.
     Приведем несколько примеров ссылок (указателей) на  ди-
намические переменные:

P1 P1.sibling Results[1].data

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

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

                  ---------------    -    ------------    -
приведение типа-->!идентификатор!-->(()-->!ссылка на !-->())-->
переменной        !типа         !    -    !переменную!    -
                  ---------------         ------------

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

type
  ByteRec = record
             lo, hi: byte;
            end;
  WordRec = record
             low, high: word;
            end;
  PtrRec = record
            ofs, seg: word;
           end;
  BytePtr = ^Byte;
var
  B: byte;
  W: word;
  L: longint;
  P: pointer;
begin
  W := $1234;
  B := ByteRec(W).lo;
  ByteRec(W).hi := 0;
  L := $1234567;
  W := WordRec(L).lo;
  B := BytePtr(L)^;
  P := Ptr($40,$49);
  W := PtrRec(P).seg;
  Inc(PtrRec(P).seg;
end.

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




                          ГЛАВА 5


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

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

описание       ---------    -    -----    -    --------------
типизованной-->!иденти-!-->(:)-->!тип!-->(=)-->!типизованная!->
константы      !фикатор!    -    -----    -    !константа   !
               ---------                       --------------

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

                  Константы простого типа

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

const
  Maximum   : integer = 9999;
  Factor    : real = -0.1;
  Breakchar : char = #3;

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

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

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

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

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

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

                    -      ------------------------      -
константа-массив-->(()---->!типизованная константа!---->())-->
                    -  ^   ------------------------ !    -
                       !             -              !
                       -------------(,)--------------
                                     -

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

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',12','3','4','5','6','7','8','9');

можно представить в более удобном виде:

const
  Digits: array[0..9] of char = '0123456789';

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

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

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

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

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

константа-    -----------
элемент-------!константа!----------------------------->
              -----------  !                      ^
                           !   --    -----------  !
                           -->(..)-->!константа!---
                               --    -----------

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

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
  NamePtr = ^NameRec;
  NameRec = record
              Next: NamePtr;
              Name: string[31];
            end;
const
  NameList: NamePtr = nil;
  NoName: NameRec = (Next: nil; Name: '');




                          ГЛАВА 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)

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

                                           --------
 простое выражение------------------------>! терм !------->
                                       ^   --------   !
                                       !              !
                                       !     ----     !
                                       !----(  + )<---!
                                       !     ----     !
                                       !     ----     !
                                       !----(  . )<---!
                                       !     ----     !
                                       !     ----     !
                                       !----( оr )<---!
                                       !     ----     !
                                       !     -----    !
                                       -----( хоr )<---
                                             -----

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

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

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

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

          ---------------------
выражение-! простое выражение !---------------------------->
          --------------------- !                        ^
                                !   ---    ------------- !
                                !->( < )-->! простое   !--
                                !   ---  ^ ! выражение !
                                !   ---  ! -------------
                                !->(<= )-!
                                !   ---  !
                                !   ---  !
                                !->( > )-!
                                !   ---  !
                                !   ---  !
                                !->( = )-!
                                !   ---  !
                                !   ---  !
                                !->(>= )-!
                                !   ---  !
                                !   ---  !
                                !->(<> )-!
                                !   ---  !
                                !   ---  !
                                -->(in )--
                                    ---


                          Операции

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

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

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

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

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

        Унарные арифметические операции        Таблица 6.3
----------------------------------------------------------
 Операция    Действие     Тип операнда      Тип результата
----------------------------------------------------------
    +    Сохранение знака     Целый            Целый
                           Вещественный      Вещественный
    -    Отрицание знака      Целый            Целый
                           Вещественный      Вещественный
----------------------------------------------------------

     Любая операция, включающая операнд, тип которого  явля-
ется подмножеством перечислимого типа, обрабатывается также,
как если бы он был перечислимого типа.
     Если оба операнда в операциях +, -, *, div или моd  яв-
ляются операндами целого типа, то тип результата будет таким
же, как общий тип обоих операндов. (Определение общего  типа
см. в разделе "Целый тип" в Главе 3).
     Если один или более операндов в операциях +, -,  или  *
имеют  вещественный  тип, то тип результата будет веществен-
ным, если использована директива компилятора $N-, или  типом
с  повышенной точностью при использовании директивы компиля-
тора $N+.
     Если при использовании операции  сохранения  знака  или
операции отрицания знака операнд имеет целый тип, то резуль-
тат будет тоже целого типа. Если операнд вещественного типа,
то  тип результата будет вещественным или типом с повышенной
точностью.
     Значение выражения х/у всегда будет вещественного  типа
или  с  повышенной точностью, независимо от типов операндов.
Если у равно 0, то результат будет ошибочным.
     Значение выражение i div j представляет собой математи-
ческое частное от i/j, округленное в меньшую сторону до зна-
чения целого типа. Если j равно 0, результат  будет  ошибоч-
ным.
     Операция mod возвращает остаток, полученный путем деле-
ния двух ее операндов, то есть:

  i mod j = i - (i div j) * j

     Знак результата операции mod будет тем же, что  и  знак
i. Если j равно нулю, то результатом будет ошибка.

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

     Типы логических операций показаны в Таблице 6.4.
     Если операндом операции  not  является  операнд  целого
типа, то результат будет также целого типа.
     Если оба операнда в операциях or, and  или  xor  целого
типа,  то  тип результата будет таким же, как тип обоих опе-
рандов.

             Логические операции               Таблица 6.4
----------------------------------------------------------
 Операция   Действие        Типа операндов  Тип результата
----------------------------------------------------------
 not    Отрицание (битовое)    Целый            Целый
 and       И (битовое)         Целый            Целый
 or        ИЛИ (битовое)       Целый            Целый
 xor    Исключающее ИЛИ        Целый            Целый
           (битовое)
 shl      Сдвиг влево          Целый            Целый
 shr      Сдвиг вправо         Целый            Целый
----------------------------------------------------------

      Примечание: Операция not является унарной операцией.

     Операции 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е).
     В Турбо-Паскале поддерживаются две различные модели ге-
нерации кода для операций 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, вычисление второго выражения не выпол-
няется.
     Схему  вычисления  можно задавать  с помощью  директивы
компилятора  $В.  Значением  по умолчанию является состояние
{$В-} (пока оно не будет изменено с помощью  "меню"  возмож-
ностей компилятора). В этом случае генерируется код с вычис-
лением по короткой схеме. В случае директивы {$В+} генериру-
ется код с полным вычислением.
     Поскольку в стандартном Паскале не определяется,  какую
схему  следует использовать для вычисления булевских выраже-
ний, то программы, зависящие от действия какой-либо конкрет-
ной схемы, в действительности не являются переносимыми.  Од-
нако, если пожертвовать переносимостью, то очень часто можно
получить  значительный выигрыш во времени выполнения и прос-
тоте, которую позволяет получить вычисление по короткой схе-
ме.

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

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

            Операции со строками              Таблица 6.6
---------------------------------------------------------
 Операция    Действие     Типы операндов   Тип результата
---------------------------------------------------------
    +      Конкатенация    Строковый,        Строковый
                         символьный или
                      упакованный строковый
---------------------------------------------------------

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

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

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

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

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

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

     Операции отношения =, <>, <, >, >= или <= могут  приме-
нятся  для сравнения строк согласно порядку расширенного на-
бора символов кода АSСII. Любые два значения строковых  дан-
ных  можно сравнить, поскольку все значения строковых данных
совместимы.
     Значения  символьного  типа  совместимы  со  значениями
строкового  типа, и при их сравнении символьное значение об-
рабатывается как строковое значение с  длиной  1.  Когда  со
значением строкового типа сравнивается упакованное строковое
значение из n элементов, то оно обрабатывается, как значение
строкового типа длиной n.

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

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

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

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

      Примечание: При сравнении указателей  в  Турбо-Паскале
      просто  сравниваются сегменты и смещения. В соответст-
      вии со схемой размещения сегментов  процессоров  80х86
      два  логически  различных  указателя  могут фактически
      указывать на одну и ту же  физическую  ячейку  памяти.
      Например $0040:$0049 и $0000:$0449 являются указателя-
      ми  с  одинаковыми  физическими  адресами.  Указатели,
      возвращаемые  стандартными  процедурами  New и  GetMem
      всегда нормализованы (смещение находится  в  диапазоне
      от  $0000  до  $000F)  и,  таким образом, всегда будут
      сравниваться корректно. При создании указателей с  по-
      мощью стандартной функции Рtr, и последующем сравнении
      таких указателей нужно принимать во внимание указанный
      особый случай.

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

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

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

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

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

                         Операция @

     С помощью операции @ можно создать указатель  на  пере-
менную. В Таблице 6.9 показан операнд и типы результата.

                 Операция создания указателя      Таблица
 6.9
------------------------------------------------------------
 Операция   Действие          Типы операндов   Тип
 результата
------------------------------------------------------------
    @      Получение       Ссылка на переменную,   Указатель
           указателя       процедуру или иденти-  (совмести-
                           фикатор функции        мый с nil)
------------------------------------------------------------

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

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

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

 type
   TwoChar = array[0..1] of char;
 var
   Int: integer;
   TwoCharPtr: ^TwoChar;

тогда оператор

  TwoCharPtr := @Int;

приводит к тому,  что TwoCharPtr  для  получения  ссылки  на
TwoCharPtr^ становится повторной интерпретацией значения Int,
как если бы оно было символьным массивом array[0..1].

      Использование операции @ для параметра-значения

     Использование операции @ для формального параметра-зна-
чения  приводит к тому, что будет построен указатель, указы-
вающий на ячейку стека,  в  которой  содержится  фактическое
значение параметра. Предположим, что Fоо является формальным
параметром-значением процедуры, а FооРtr^ является  указате-
лем-переменной. Если в процедуре выполняется операция:

  FooPtr := @Foo;

то FооРtr^ будет ссылкой на значение Fоо. Однако, FооРtr^ не
указывает  на  сам  параметр Fоо, поскольку он  указывает на
значение Fоо, которое было взято из Fоо и сохранено в стеке.

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

     Применение операции @ к  параметру-переменной  приведет
к тому, что будет сформирован указатель на фактический пара-
метр (указатель берется из стека). Предположим,  что  Оnе  -
параметр-переменная  процедуры, Тwо - переменная, передавае-
мая в процедуру в качестве фактического параметра-переменной
Оnе, а ОnеРtr является указателем на переменную. Если в про-
цедуре выполняется оператор:

  OnePtr := @One;

то ОnеРtr является указателем на переменную Тwо, а ОnеРtr^ -
ссылка на саму переменную Тwо.

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

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

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

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

                 -------------------------
Вызов функции -->! идентификатор функции !----------------->
                 ------------------------- !             ^
                                     -------             !
                                     ! ----------------  !
                                     ! !   список     !  !
                                     ->! фактических  !---
                                       ! параметров   !
                                       ----------------

                  ---    ------------------------    ---
Список факти- -->( ( )-->! фактический параметр !-->( ) )-->
 ческих пара-     ---  ^ ------------------------ !  ---
 метров                !          ---             !
                       ----------( , )<------------
                                  ---
                         -------------
Фактический параметр --->! выражение !-------------->
                      !  -------------            ^
                      !  ------------------------ !
                      ---! ссылка на переменную !--
                         ------------------------

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

  Sum(A,63)
  Maximum(147,J)
  Sin(X+Y)ь
  Зрз(И)
  Шрнцож(Фгекцф,Кжкийх)

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

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

                      ---                              ---
Описатель множества->( [ )----------------------------( ] )->
                      ---  !                        ^  ---
                           !  --------------------  !
                           -->! группа элементов !---
                            ^ -------------------- !
                            !        ---           !
                            --------( , )<----------
                                     ---


                   -------------
Группа элементов ->! выражение !--------------------------->
                   ------------- !                      ^
                                 !  ----   -----------  !
                                 ->( .. )->!выражение!---
                                    ----   -----------

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

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

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

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

                -------------   ---   -----------   ---
Приведение ---->!идент. типа!->( ( )->!выражение!->( ) )-->
типа значений   -------------   ---   ----------    ---

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

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





                          ГЛАВА 7

                         Операторы

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

 Оператор -------------------------------------------------->
           ! -------   ---  ^ !    --------------------   ^
           ->!метка!->( : )-! !--->! простой оператор !---!
             -------   ---    !    --------------------   !
                              !    ---------------------  !
                              ---->!    структурный    !---
                                   !      оператор     !
                                   ---------------------

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

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

                             -------------------------
 Простой оператор ---------->! оператор присваивания !----->
                      !      -------------------------    ^
                      !      -------------------------    !
                      !----->!   оператор процедуры  !----!
                      !      -------------------------    !
                      !      -------------------------    !
                      ------>!   оператор перехода   !-----
                             -------------------------

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

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

               ------------------------        ----
 Оператор  --->! ссылка на переменную !------>( := )--
присваивания ! ------------------------     ^  ----  !
             ! -------------------------    !        !
             ->! идентификатор функции !-----        !
               -------------------------  ------------
                                          !  -------------
                                          -->! выражение !->
                                             -------------

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

  X := Y + Z
  Done := (I>=1) and (I<100);
  Huel := [blue,Succ(C)];
  I := Sqr(J) - I*K;

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

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

              ---------------------------
 Оператор --->! идентификатор процедуры !------------------>
 процедуры    --------------------------- !            ^
                                          ! ---------- !
                                          ! ! список ! !
                                          ! ! факти- ! !
                                          ->! ческих !--
                                            ! пара-  !
                                            ! метров !
                                            ----------

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

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


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

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

                          -------        ---------
 Оператор перехода ----->( gоtо  )------>! метка !------>
                          -------        ---------

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

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

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

                             ----------------------
 Структурный оператор ------>! составной оператор !-------->
                        !    ----------------------      ^
                        !    ----------------------      !
                        !--->!  условный оператор !----->!
                        !    ----------------------      !
                        !   ------------------------     !
                        !-->!    оператор цикла    !---->!
                        !   ------------------------     !
                        !   -------------------------    !
                        --->! оператор над записями !-----
                            -------------------------

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

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

                        -------    ------------    -----
 Составной оператор -->( begin )-->! оператор !-->( end )-->
                     ^  -------    ------------ !  -----
                     !                 ---      !
                     -----------------( ; )<-----
                                       ---

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

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

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

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

                                 -----------------
Условный оператор -------------->! оператор if   !-------->
                    !            -----------------    ^
                    !   ----------------------        !
                    --->!   оператор case    !---------
                        ----------------------

                        Оператор if

     Синтаксис оператора if можно представить  следующим об-
разом:

              ----   -----------   ------   ----------
Оператор if->( if )->!выражение!->( then )->!оператор!-----
              ----   -----------   ------   ----------  ! !
                    ------------------------------------- !
                    !   ------     --------------         !
                    -->( else )--->!  оператор  !----------->
                        ------     --------------

     В выражении должен  получаться результат, имеющий стан-
дартный  булевский тип.  Если результатом выражения является
истинное значение (Тrue), то выполняется оператор, следующий
за ключевым словом then.
     Если  результатом  выражения  является значение False и
присутствует ключевое слово else,  то  выполнятся  оператор,
следующий за ключевым словом else. Если ключевое слово  else
отсутствует, то никакой оператор не выполняется.
     Синтаксическая неоднозначность, возникающая в конструк-
ции:

  if e1 then e2 else e3

разрешается путем следующей интерпретации этой конструкции:

 if e1 then
 begin
   if e2 then
      s1
   else
      s2
 end

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

               ------    -----------   ----    --------
 Оператор --->( casе )-->!выражение!->( оf )---! casе !----
 варианта      ------    -----------   ----  ^ -------- ! !
                                             !   ---    ! !
                                             ---( ; )---- !
                                                 ---      !
        ---------------------------------------------------
        !                                          -----
        ----------------------------------------->( еnd )-->
         !  --------------    ^   !    ---    ^    -----
         -->! ветвь else !----!   --->( ; )---!
            --------------             ---

                     ----------------------->
                     !                      !
       ------------- !  ----   -----------  !  ---
casе ->! константа !-->( .. )->!константа!--->( : )---
     ^ -------------    ----   -----------  !  ---   !
     !                  ----                ! --------
     ------------------( ,  )<--------------- ! ------------
                        ----                  ->! оператор !->
                                                ------------

                   ------    ------------
ветвь else ------>( else )-->! оператор !-------------->
                   ------    ------------

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

  case Operator of
    plus:   X := X+Y;
    minus:  X := X-Y;
    times:  X := X*Y;
  end;

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

     Оператор цикла задает повторное выполнение определенных
операторов.
                             -------------------
 Оператор цикла ------------>! оператор repeat !---------->
                        !    -------------------    ^
                        !    -------------------    !
                        !--->!  оператор while !----!
                        !    -------------------    !
                        !    -------------------    !
                        ---->!   оператор for  !-----
                             -------------------

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

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

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

           --------    ----------    -------   ----------
Оператор->( repeat )---!оператор!-->( until )->!оператор!-->
 цикла с   --------  ^ ---------- !  -------   ----------
пост-условием        !     ---    !
                     -----( ; )<---
                           ---

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

  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)-->!выражение!->( dо )->!оператор!--->
с пред-условием  -----    -----------   ----   ----------

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

                           ----------------------------
 Управляющая переменная -->! идентификатор переменной !--->
                           ----------------------------

                           -------------
 Начальное значение ------>! выражение !------------------>
                           -------------

                           -------------
 Конечное значение ------->! выражение !------------------>
                           -------------

     В качестве управляющей переменной должен использоваться
идентификатор переменой (без какого-либо квалификатора), ко-
торый обозначает  переменную, объявленную локальной в блоке,
в котором содержится  оператор  for.  Управляющая переменная
должна иметь перечислимый тип. Начальное и конечное значения
должны иметь тип, совместимый по присваиванию с перечислимым
типом.
     Когда начинает выполняться оператор  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 )-->! ссылка на пере-    !-->( dо )--
 присоединения   ------  ^ ! менную типа запись ! !  ----  !
                         ! ---------------------- !        !
                         !          ---           !        !
                         ----------( , )<----------        !
                                    ---                    !
                             -------------------------------
                             !    --------------------
                             ---->!     оператор     !--->
                                  --------------------

                             ------------------------
 Ссылка на переменную ------>! ссылка на переменную !----->
     типа запись             ------------------------

     Приведем пример оператора with:

   with Date do
     if month = 12 then
     begin
       month := 1;
       year := year + 1
     end else
       month := month + 1;

     Это эквивалентно следующему:

   if Date.month = 12 then
   begin
     Date.month := 1;
     Date.year := Date.year + 1
   end else
     Date.month := Date.month + 1;

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

  type
    Point = 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

                    Процедуры и функции

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

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

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

             -------------   -   ------------------   -
 Описание -->! заголовок !->(;)->! тело процедуры !->(;)-->
процедуры    ! процедуры !   -   ------------------   -
             -------------

              -----------   ---------------
 Заголовок ->( procedure )->!идентификатор!----------------->
процедуры     -----------   ---------------  !            ^
                                     ---------            !
                                     ! ------------------ !
                                     ! !     список     ! !
                                     --!   формальных   !--
                                       !   параметров   !
                                       ------------------

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

                       ----------------------
 Тип параметра ------->! идентификатор типа !--------->
                 ^     ----------------------    !
                 !            --------           !
                 ------------( строка )<----------
                              --------

                                           --------
   Тело    ------------------------------->! блок !---->
 процедуры  !    ------------    ---  ^ !  --------  ^
            !-->( interrupt  )->( ; )-! !            !
            !    ------------    ---    !            !
            !            ----------------            !
            !            !   ---------               !
            !            !->( forward )------------->!
            !            !   ---------               !
            !            !   ----------              !
            !            !->( external )------------>!
            !                ----------              !
            !      --------------------------        !
            ----->(     директива 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;

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

  procedure MyInt(Flags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP):
                    word);
  interrupt;

     Вместо блока операторов в описании процедуры или  функ-
ции можно записать опережающее описание (описание  forward),
внешнее описание (описание external) или внутреннее описание
(описание inline).

               Опережающее описание (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.
     Опережающие описания не допускаются в интерфейсной час-
ти модуля.

                 Внешние описания (external)

     Описания external позволяют связывать отдельно  скомпи-
лированные  процедуры  и функции, написанные на языке ассем-
блера. С помощью команды "$L имя_файла" для внешней програм-
мы должны быть установлены связи с программой или модулем на
языке Паскаль. Более детальное описания компоновки  с  прог-
раммой на языке ассемблера содержится в Главе 15.
     Приведем следующие примеры описаний внешних процедур:

  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}

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

                    Описания inline

     Директивы inline позволяют записывать  вместо блока опе-
раторов инструкции в машинном коде. При вызове обычной проце-
дуры  компилятор  создает  код, в котором параметры  процеду-
ры помещаются в стек, а затем для вызова процедуры  генериру-
ется инструкция  САLL.  Когда  вы вызываете процедуру inline,
компилятор  генерирует  код  с помощью директивы inline, а не
с помощью инструкции САLL.  Таким  образом,  процедура inline
"расширяется"  при  каждом обращении к ней, аналогично макро-
инструкции на языке ассемблера. Приведем два небольших приме-
ра процедур типа inline:

 procedure DisableInterrupts: inline($FA);  { CLI }
 procedure EnableInterrupts;  inline($FB);  { STI }

     Процедуры типа  inline описаны  подробно  в  Главе 15
("Внутренняя организация Турбо-Паскаля").

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

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

            -------------   -    --------------    -
 Описание-->! заголовок !->(;)-->!тело функции!-->(;)---->
  функции   !  функции  !   -    --------------    -
            -------------

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

                           ----------------------
Тип результата ----------->! идентификатор типа !---------->
                     !     ----------------------      !
                     !           --------              !
                     ---------->( строка )--------------
                                 --------

                        --------
Тело функции ---------->! блок !-------------------------->
                 !      --------               ^
                 !      ---------              !
                 !---->( forward )------------>!
                 !      ---------              !
                 !      ----------             !
                 !---->( external )----------->!
                 !      ----------             !
                 !     --------------------    !
                 ----->! директива inline !-----
                       --------------------

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

  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;

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

                         Параметры

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

                   ---    -----------------------    ---
 Список фор- ---->( ( )-->! описание параметров !-->( ) )-->
 мальных пара-     ---  ^ ----------------------- !  ---
   метров               !          ---            !
                        ----------( ; )<-----------
                                   ---

                          --------------------------
  Описание -------------->! список идентификаторов !-------->
 параметров   !         ^ -------------------------- !    ^
              !  -----  !      -----------------------    !
              ->( var )--      !  ---   ----------------- !
                 -----         ->( : )->! тип параметра !--
                                  ---   -----------------

                          ----------------------
Тип параметра ------------! идентификатор типа !--------->
                  !       ----------------------     ^
                  !             --------             !
                  !----------->( string )------------!
                  !             --------             !
                  !              ------              !
                  ------------->( file )--------------
                                 ------

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

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

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

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

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

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

            Нетипизованные параметры-переменные

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

  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.

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

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

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

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

                              -----------------------
                        ----->! заголовок процедуры !---
                        !     -----------------------  !
 процедурный тип -------!                              !--->
                        !     -----------------------  !
                        ----->!   заголовок функции !---
                              -----------------------

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

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

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

                   Процедурные переменные

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

  var
    P: SwapProc;
    F: MathFunc;

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

  {$F+}

  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.

  {$F-}

Описанным ранее переменным P и F теперь можно присвоить зна-
чения:

     P := Swap;
     F := Tan;

     После такого присваивания обращение P(i,j) эквивалентно
Swap(i,j) и F(X) эквивалентно Tan(X).
     Как и при любом другом присваивании переменная слева  и
значение в правой части должны быть совместимы по присваива-
нию. Процедурные типы, чтобы они были совместимы по присваи-
ванию,  должны  иметь одно и то же число параметров, а пара-
метры на соотвествующих  позициях  должны  быть  одинакового
типа.  Как  упоминалось  ранее,  имена параметров в описании
процедурного типа никакого действия не вызывают.
     Кроме того, для обеспечения совместимости по присваива-
нию процедура и функция, если ее нужно присвоить процедурной
переменной, должна удовлетворять следующим требованиям:

     - Она должна компилироваться в состоянии {$F+}.
     - Это не должна быть стандатная процедура или функция.
     - Такая процедура или функция не может быть вложенной.
     -  Такая  процедура  не  должна  быть  процедурой  типа
inline.
     - Она не должна быть процедурой прерывания (interrupt).

     Простейший  способ  удовлетворения  первого  требования
состоит  в  размещении  директивы компилятора {$F+} в начале
исходного  текста  (или  в  установке  меню  "Опции/Компиля-
тор/Дальний  тип  вызова" (O/C/Force Far Calls) в интегриро-
ванной интерактивной среде.
     Стандартными процедурами и функциями считаются процеду-
ры и функции, описанные в модуле System, такие, как Writeln,
Readln, Chr, Ord. Чтобы  получить  возможность  использовать
стандартную  процедуру или функцию с процедурной переменной,
вы должны написать для нее специальную "оболочку". Например,
пусть мы имеем процедурный тип:

  type
    IntProc = procedure(N: integer);

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

  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;

  {$F+}

  function Add(X,Y: integer): integer;
   begin
     Add := X + Y;
   end;

  function Multiply(X,Y: integer): integer;
   begin
     Multiply := X*Y;
   end;

   function Funny(X,Y: integer): integer;
    begin
      Funny := (X+Y) * (X-Y);
    end;

   {$F-}

   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.
     Если процедура или функция должны  передаваться  в  ка-
честве  параметра,  они должны удовлетворять тем же правилам
совместимости типа, что и при присваивании. То  есть,  такие
процедуры  или  функции  должны компилироваться с директивой
компилятора {$F+}, они не могут быть встроенными  функциями,
не могут быть вложенными и не могут описываться с атрибутами
inline или interrupt.

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

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

  {$F+}

  type
    IntFunc = function: integer;

  var
    F: IntFunc;
    N: integer;

  function ReadInt: integer;
  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,  а  затем
сравнить их значения:

     if F = ReadInt then Writeln('Равны');

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

 if @F = @ReadInt then Writeln('Равны');

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

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

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

  type
    func = function(X: integer): integer;
  var
    F: Func;
    P: Pointer;
    N: integer;

можно построить следующие присваивания:

  F := Func(P);  { присвоить значения процедуры в Р F }
  Func(P) := F;  { присвоить значение процедуры в F P }
  @F := P;       { присвоить значение указателя в P F }
  P := @F;       { присвоить значение указателя в F P }
  N := F(N);     { вызвать функцию через F }
  N := Func(P)(N);     { вызвать функцию через P }

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




                          ГЛАВА 9

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 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);
  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;
 interface
 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 ссылаются друг на друга только в соответст-
вующих секциях реализации.






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