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



 

Часть 5


                            Г Л А В А  6
                            ============

                           ОПИСАНИЕ ЯЗЫКА
                           ==============

         В главе дается краткое описание языка JPI Modula-2. Глава составлена компактно и долж-
    на изучаться тщательно. Стиль описания материала контрастирует с теоретическими разработка-
    ми, в которых содержится больше информации и пояснений.
         Программы должны соответствовать синтаксису языка  Modula-2.  Синтаксис  устанавливает
    базовую текстовую структуру пригодных к применению программ. Компилятор принимает для обра-
    ботки только синтаксически правильные программы.
         Во-вторых, программы должны соответствовать семантике времени компиляции (статической)
    языка Modula-2.  Это имеет отношение к значению,  связанному с идентификаторами программы и
    способу  их использования.  Кроме всего прочего это включает контроль типов.  Ошибки в этих
    случаях также определяются с помощью компилятора.
         И, наконец,  программы должны соответствовать семантике времени выполнения (динамичес-
    кой) Modula-2.  Под этим подразумевается действительное  поведение  выполняемой  программы.
    Например,  требуется,  чтобы величины индексов массивов находились в определенных пределах.
    Выполнение этих правил не является обязательным во время выполнения программы.  Если они не
    соблюдаются, то это может привести к неопределенным результатам, но может быть использовано
    в целях получения побочных эффектов.
         Базовая архитектура  машины  относится к семейству 8086 с адресным пространством 2**20
    (1 Мбайт) байт по 8 бит. Физический адрес формируется с помощью 16-битового сегмента и 16 -
    битового смещения; абсолютный адрес байта: (16 * сегмент) + смещение.
         Для иллюстрации каждой концепции будут использоваться примеры;  некоторые из них будут
    относиться к приведенным ранее примерам.

                             О ТЕКСТАХ
                             =========

                              Лексемы
                              -------

         Лексемы представляют  собой базовые текстовые элементы,  на которых основана структура
    Modula-2. Лексема представляет собой последовательность символов кода ASCII. Лексемы разде-
    ляются на 4 класса:
         - ключевые слова;
         - ограничители;
         - родовые лексемы;
         - разделители.
         Ключевые слова и ограничители состоят из фиксированных последовательностей  символов в
    то время, как для каждой общей лексемы возможно множество последовательностей символов.
         Используются следующие ключевые слова:

         AND          FOR               OR
         ARRAY        FORWARD           POINTER
         BEGIN        FROM              PROCEDURE
         BY           GOTO              RECORD
         CASE         IF                REPEAT
         CONST        IMPLEMENTATION    RETURN
         DEFINITION   IMPORT            SET
         DIV          IN                THEN
         DO           LABEL             TO
         ELSE         LOOP              TYPE
         ELSIF        MOD               UNTIL
         END          MODULE            VAR
         EXIT         NOT               WHILE
         EXPORT       OF                WITH

         Используются следующие ограничители:

         +   -   *   /   :=   &   .   ,   ;
         :   (   )   [   ]    {   }   ^   ~
         =   #   <>  <   <=   >   >=  <<  >>
         |   ..

         Используются следующие общие лексемы:

                           Идентификатор
                           -------------

         - последовательность букв (от "A" до "Z", от "a" до "z" и "_") и цифр (от "0" до "9"),
    который должен начинаться с буквы,  исключая 42 ключевых  слова,  приведенных  выше.  Буквы
    верхнего и нижнего регистров считаются различными. Например:

          X  HelloThere  Agent_007  _main

                        Десятичный  литерал
                        -------------------

         - последовательность цифр.

                   12345  0  255

                        Восьмеричный литерал
                        --------------------

         - последовательность восьмеричных цифр (от "0" до "7"),  за которой следует буква "В":

               10В (=8) 377В (=255)

                     Шестнадцатеричный литерал
                     -------------------------

         - последовательность цифр и шестнадцатеричных букв (от "A" до "F"), за которой следует
    буква "H", эта последовательность должна начинаться с цифры.

                10Н (=16) OFFH (=255)

                       Действительный литерал
                       ----------------------

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

                 3.14   12.3Е-3 (=0,0123)

                         Строковый литерал
                         -----------------

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

                  'Hi'   "that's ok"   101C (='A')

         Используются следующие разделители:

         - пробелы - любая последовательность пробелов,  символы табуляции и ограничитель стро-
    ки;
         - комментарии - любая последовательность символов,  заключенных в '(*' и '*)'. Коммен-
    тарии могут использоваться и продлеваться за пределы ограничителей строки.
         Лексемы "#" и "<>" могут использоваться одна вместо другой также, как и AND и "&", NOT
    и "~".
         Идентификаторы используются для обозначения объектов, определяемых пользователем.
         Десятичные, восьмеричные и шестнадцатеричные лексемы обозначают целые числа.
         Действительные лексемы обозначают действительные числа.
    Экспоненциальная часть обозначает умножение на указанную степень числа 10.
         Каждая лексема содержит как можно большее число символов: 123 - это один литерал, сос-
    тоящий из трех цифр, а не три литерала, состоящих каждый из одной цифры.
         Разделители, исключая комментарии,  начинающиеся с '(*$' (см.  ГЛАВУ 7),  не влияют на
    программу, за исключением отдельных лексем.

                             Синтаксис
                             ---------

         Синтаксис языка Modula-2 описывает,  как группировать последовательности лексем, чтобы
    получить правильный текст программы.  Синтаксис содержит набор синтаксических конструкций и
    правил. Правила устанавливают, как конструкции и литералы должны соединяться, чтобы образо-
    вать  новые  конструкции.  Каждой  конструкции соответствует несколько продуктов по выбору,
    каждый из которых выражает возможное применение данной конструкции; различные варианты про-
    дуктов будут приводиться, где это уместно и не группой.
         При образовании правил используются следующие мета-символы:  скобки - [ и ],  фигурные
    скобки - { и }, черта - | и символ определения ::=.
         Скобки используются для заключения в них необязательных частей; в фигурные скобки зак-
    лючаются те части, которые могут повторяться 0 и более раз, а черта используется для разде-
    ления возможных вариантов.  Символ определения используется для отделения определяемой син-
    таксической   конструкции  от  ее  расширения.  Смешанный  регистр  используется  для  имен
    конструкций,  верхний - для ключевых слов, разделители показаны в апострофах. Общие лексемы
    называются: Идент, ЦелоеЧисло, ДействитЧисло и Строка.
         Продуцирующие правила образуют основу языка и должны "читаться" как обычные  утвержде-
    ния; текст, следующий за каждым правилом, будет относиться к его составляющим. Так

         СписокИдент ::= Идент{','Идент}

    определяет список из одного или более идентификаторов, разделенных запятыми.
         Примеры:

         HelloThere, _main , X
         Agent_007

                   Объявления и область действия
                   -----------------------------

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

         Имя ::= Идент

         Объявления идут по списку:

         СписокОбъявлений ::={Объявление}

         Идентификаторы должны быть объявлены перед их использованием. Единственным исключением
    являются типы,  обозначаемые указателями, которые затем должны объявляться в том же перечне
    (списке) объявлений;  перед этим запрещается производить операции, требующие знания обозна-
    чаемого типа,  т.е. любые операции, включающие разыменование. Все идентификаторы, объявлен-
    ные в списке объявления, должны быть различимы.
         Объявление действует  в сфере его влияния.  Сфера влияния определяется непосредственно
    от места объявления на весь оставшийся список объявлений и на все  последующие утверждения,
    связанные со списком объявлений.  Списки объявлений могут образовываться с помощью процедур
    и модулей,  и возможно переобъявление идентификаторов в  таких  внутренних  областях.  WITH
    -объявления представляют собой другой способ образования таких гнездовых областей. В каждом
    частном случае использования идентификатора он обозначает объект,  объявленный ранее в наи-
    более глубокой вложенной области; она содержит объекты, обозначенные тем же самым идентифи-
    катором внешних областей.
         Пример:

         MODULE M;
         VAR I,J: CARDINAL;     (* Две переменные, принадл. М *)
           PROCEDURE P;
           VAR I,K: INTEGER;    (* Две переменные, принадл. Р *)
           BEGIN
             I := 7;      (* I принадл. Р *)
             J := 8;      (* J принадл. М *)
             K := 9;      (* К принадл. Р *)
           END P;
         BEGIN
           I := 10;       (* I принадл. М *)
           J := 11;       (* J принадл. М *)
           (* К здесь невидима *)
         END M;

         Алиасные объявления не служат для объявления новых объектов, но вводят новые имена для
    уже существующих:

         Объявление ::= CONST {Идент ':' ':=' Имя ';'}

         Имя может обозначать любой объект.

         Пример: CONST VisibleVersion ::= AboutToBeHidden;

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

         ABS         DEC       LONGCARD     ORD         WORD
         ADDRESS     DISPOSE   LONGINT      PROC        VSIZE
         ADR         EXCL      LONGREAL     REAL
         BITSET      FALSE     LONGWORD     SHORTADDR
         BOOLEAN     FLOAT     MAX          SHORTCARD
         BYTE        HALT      MIN          SHORTINT
         CAP         HIGH      NEW          SIZE
         CARDINAL    INC       NIL          TRUE
         CHAR        INCL      NULLPROC     TRUNC
         CHR         INTEGER   ODD          VAL


                                Типы
                                ----

         Тип определяет множество значений. Язык Modula-2 включает ряд предопределенных типов и
    конструкций для определения новых типов.  Имена новым типам можно назначить при  объявлении
    типа:

         Объявление ::= TYPE {Идент '=' ОписаниеТипа ';'}

         Некоторые типы называются простыми:

               ОписаниеТипа::= ПростойТип

         Тип может быть только именем типа:

                   ПростойТип ::= Имя

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

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

         Пример: TYPE JustCardinal = CARDINAL;


                           Числовые типы
                           -------------

         Язык Modula-2 содержит три предопределенных основных типа,  величины которых представ-
    ляют собой беззнаковые целые числа в следующих пределах:
         CARDINAL  : от 0 до 65535 (от 0 до 2**16 - 1)
         SHORTCARD : от 0 до 255 (от 0 до 2**8 - 1)
         LONGCARD  : от 0 до 4294967295 (от 0 до 2**32 - 1)

         Существует три предопределенных целых типа, величины которых представляют собой знако-
    вые целые числа в пределах:
         INTEGER:   -32768 до + 32767     (-2**15 до 2**15 - 1)
         SHORTINT:  -128 до + 127           (-2**7 до 2**7 - 1)
         LONGINT:  -2147483648 до + 2147483647 (-2**31 до 2**31-1)

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

         REAL: +/- 1.2E-38 до 3.4+38, с точностью до 6 цифр;
         LONGREAL: +/- 2.e- до 1.7 до 308, с точностью до 15 цифр.
         Все три, описанные выше типа, называются числовыми типами.

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

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

         ПростойТип ::= '('СписокИдент')'

         Пример:
         TYPE Color  = (Red,Yellow,Green,Brown,Blue,Pink,Black);
              Gender = (Male,Female);

         Modula-2 включает один предопределенный тип перечисления,  содержащий истинные величи-
    ны:

         TYPE BOOLEAN = (FALSE,TRUE);

         Целые, основные, символьные, перечислимые типы вместе называются перечислимыми типами;
    они имеют целочисленные перечислимые значения. Перечислимые литералы исчисляются последова-
    тельно,  начиная с нуля. Так же как и для символьного типа, короткие перечислимые типы иск-
    лючают LONGCARD и LONGINT.

                           Типы-диапазоны
                           --------------

         При задании перечислимого типа можно определить тип-диапазон этого базового типа.

         ПростойТип ::= [Имя] '['Выраж'..' Выраж']'

         Два выражения должны быть постоянными и одного и того же типа.  Они ограничивают вели-
    чины типа путем указания нижней и верхней границы (нижняя <= верхней). Если имя присутству-
    ет,  то оно именует базовый тип;  в противном случае, если величины выражения принадлежат к
    неуказанному целочисленному типу,  базовый тип принимается целым, если первое выражение от-
    рицательно, в противном случае - целым положительным (CARDINAL).
         Примеры:

    TYPE Year = [1900..2001];          (* Базовый тип CARDINAL *)
         MyInt = [-1000..+1000];        (* Базовый тип INTEGER *)
         Digits = ['0'..'9'];              (* Базовый тип CHAR *)
         IntYear = INTEGER [1900..2001]; (* Базовый тип INTEGER *)
         LongYear = LONGCARD[101900..102001];
         HighColor = [Blue..Black];     (* Базовый тип COLOR *)

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


                           Типы множеств
                           -------------

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

         ОписаниеТипа ::= SET OF ПростойТип

         Минимальная величина именованного типа элемента набора должна иметь нуль упорядоченной
    величины. Тип набора содержит любое подмножество величин типа элемента набора.

         Пример: TYPE Chars = SET OF CHAR;

         Имеется один предопределенный тип набора:

                 TYPE BITSET = SET OF [0..15];


                           Типы массивов
                           -------------

         Типы массивов  обеспечивают  отображения  с короткого перечислимого индексного типа на
    любой тип элемента массива:

         ОписаниеТипа ::= ARRAY СписокИндексов OF ОписаниеТипа

         СписокИндексов ::= ПростойТип {',' ПростойТип}

         Определение типа множества с более, чем одним индексным типом эквивалентно определению
    расширенного типа:

         ARRAY Индекс1 OF ARRAY Индекс2 ... OF ОписаниеТипа

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

         TYPE NameString = ARRAY [0..24] OF CHAR;
              IntArray = ARRAY BOOLEAN OF INTEGER;


                            Типы записей
                            ------------

         Типы записей представляют собой совокупность отдельных полей:

         ОписаниеТипа ::= RECORD { ОписаниеПоля } END

         ОписаниеПоля ::= СписокИдент ':' ОписаниеТипа ';'

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

         TYPE Person = RECORD
                         First,Last:  NameString;
                         Age:         SHORTCARD [0..125];
                       END;
              AdrPair = RECORD Ofz,Seg: CARDINAL; END;

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

         ОписаниеПоля ::= ЧастьВарианта ';'

         ЧастьВарианта ::= CASE [Идент] ':' Имя OF { '|' Вариант}
                        [ELSE {ОписаниеПоля} ] END

         Вариант ::= СписокВыбора ':' {ОписаниеПоля}

         СписокВыбора ::= Выбор { ',' Выбор }

         Выбор ::= Выраж ['..' Выраж]

         Знак "|", стоящий перед первым вариантом, может быть опущен.
         Идентификатор признака,  который  может указываться после CASE,  сопровождается именем
    перечислимого типа признака.  Если идентификатор признака присутствует, он определяет дейс-
    твительное поле такого типа.
         Варианты и необязательная часть ELSE,  каждая, определяют список полей определений, но
    поле только одной из них присутствует в каждом значении типа вариантной записи.
         Альтернативные выражения должны быть постоянны и типа признака и не  должны  содержать
    перекрывающихся величин.  Альтернатива с двумя выражениями обозначает все величины диапазо-
    на.  Каждый альтернативный список должен определять величины признака,  для которых имеется
    соответствующий вариант,  часть ELSE покрывает оставшиеся величины. Присутствие или отсутс-
    твие полей признака является только логическим;  они всегда досягаемы, но разделяют память.
         Пример:

         TYPE Location =
                RECORD
                  Value: BYTE;
                  CASE Simple: BOOLEAN OF
                    | TRUE: ByteOfz: LONGCARD;
                    | FALSE: SegOfz: AdrPair;
                  END:
                END;

                          Типы указателей
                          ---------------

         Величины типа  указателей представляют собой пути доступа к объектам обозначаемого ти-
    па:

         ОписаниеТипа ::= POINTER [ Выраж ] TO ОписаниеТипа

         Если выражение опущено,  определяется абсолютный тип указателя;  величины  этого  типа
    представляют собой полные 32- х битовые физические адреса вида сегмент/смещение.
         Базовый тип указателя определяется путем  включения  (после  POINTER)  выражения  типа
    CARDINAL.  Такие  значения содержат только ту часть физического адреса,  которая называется
    смещением.  Сегментная часть получается преобразованием выражения каждый раз, когда обозна-
    чаемый объект доступен. Поэтому базовые указатели коротки - 16 бит.
         Базовые указатели обеспечивают ссылку на настраиваемые объекты только путем  модифика-
    ции базовой (сегментной) величины (оставляя смещение неизменным).
         Примеры:

         TYPE ListPtr  = POINTER TO  ListNode;
              ListNode = RECORD
                           Value: CARDINAL; (* значение элемента
                                                              *)
                           NextNode: ListPtr;  (* следующий эле-
                                                         мент *)
                         END;
              ShortPtr = POINTER Base TO ListNode;

         Имеется два предопределенных типа указателей:

         TYPE ADDRESS = POINTER TO WORD;
         SHORTADDR =  Pointer  O TO WORD;(* нулевой базовый сег-
                                                         мент *)

         Величины типа  указателя получаются либо как адреса (абсолютные) существующих объектов
    обозначаемого типа или же они могут представлять собой исходные адреса памяти, полученные с
    помощью администратора памяти (см. ГЛАВУ 8).
         Типы массивов,  записей и указателей вместе называются составными типами;  все осталь-
    ные, за исключением типов множества, являются простыми типами.


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

         В некоторых ситуациях требуется совместимость типов;  здесь есть три дестабилизирующих
    момента.
         Наиболее жестким является требование идентичности типов;  это означает, что они должны
    быть определены одним типом.
         Следующим идет совместимость.  Она включает требования совместимости подчиненных типов
    с их базовыми типами и другими подчиненными типами того же базового типа. ADDRESS совместим
    с любым абсолютным указателем, а SHORTADDR - с любым базовым указателем.
         И, наконец,  совместимость присваиванием имеет место  между  парами  CARDINAL/INTEGER,
    SHORTCARD/SHORTINT, LONGCARD/ LONGINT.
         Существует три предопределенных типа,  называемых BYTE, WORD и LONGWORD. Они относятся
    к 1,  2, и 4 битам памяти, соответственно, и являются совместимыми по присвоению с общими и
    целыми типами одинакового размера.
         Специальные правила совместимости применяются к формальным параметрам.


                         ОБЪЕКТЫ И ЗНАЧЕНИЯ
                         ==================

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

         Объявление ::=  VAR  {ПеремИдент { ',' ПеремИдент } ':'
                               ОписаниеТипа ';' }

         ПеремИдент ::= Идент

         Каждое объявление провозглашает все идентификаторы списка переменными описанного типа.
    Их первоначальные величины идентифицированы.
         Примеры:

         VAR I,J,N,M:  CARDINAL;
             Base:     CARDINAL;
             L:        LONGCARD;
             X,Y:      LONGREAL;
             P:        POINTER TO INTEGER;
             S:        ARRAY [1..100] OF CHAR;
             R:        RECORD  X,Y:  INTEGER; END;
             C:        CHAR;
             Z:        Chars;
             Loc:      Location;
             Persons:  ARRAY BOOLEAN OF POINTER TO Person;

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

         ПеремИдент ::= Идент '[' Выраж ':' Выраж ']'


         Пример:

         VAR ColorScreen [0B800H:0] : ARRAY [1..25] OF
                                        ARRAY [1..80] OF
                                          RECORD
                                            Chr: CHAR;
                                            Atr: SHORTCARD;
                                          END;

                            Константы
                            ---------

         Постоянные литералы обозначают наиболее базовые величины:
         Значение ::= ЦелоеЧисло
         Значение ::= ДействитЧисло
         Значение ::= Строка

         Целые числа являются возможными величинами для целых  и  общих  типов,  действительные
    числа - для действительных типов, а массив литер - для символьных типов (массив в этом слу-
    чае должен иметь длину 1) и для типов формы: ARRAY...OF CHAR.
         Величины постоянных записей и величины массивов формируются с агрегатами:

         Значение ::= Имя '(' Выраж { ',' Выраж } ')'

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

         Объявление ::= CONST { Идент '=' Выраж ';' }

         Имеется предопределенная константа, NIL, совместимая с любым абсолютным типом указате-
    ля.
          Ни литералы, ни именованные константы не являются объектами.
         Примеры:

         CONST Pi = 3.14159;
               Ratio = 360.0 / (2.0 * Pi);
               K = 1024;
               P = Person("Donald","Duck",50);
               LastLoc = Location(0,FALSE,AdrPair(0FFFFH,0FH));
               X = IntArray(-12345,16*K)


                          Значения множеств
                          -----------------

         Величины набора формируются с помощью построителя набора.

         Значение ::= [ Имя ] '{' [ СписокВыбора] '}'

         Выражения для выборов представляют собой величины типа набора элементов; они не должны
    быть постоянными.  Имя обозначает тип набора; если же его пропустить, то это будет означать
    BITSET.

         Пример: Chars { 'A'..'Z' , 'a'..'z' , '_' }


                            Назначения
                            ----------

         Назначения используются для обозначения объектов. Компонентные объекты составного объ-
    екта назначаются путем добавления суффиксов к  назначению  составного  объекта.  Добавление
    суффиксов  используется  также  для назначения компонентов именованных агрегатных констант.
    Использование назначения в качестве величины обозначает величину назначаемого объекта:

         Значение ::= Назначение

         Наипростейшая форма назначения - это просто имя объекта:

         Назначение ::= Имя

         Это представляет собой также способ использования перечислимых литералов и именованных
    констант как величин только лишь путем их наименования.
         Индексация используется для назначения компонентов объектов типа массива:

         Назначение ::= Назначение '[' Выраж { ',' Выраж } ']'

         Перечень индексных выражений эквивалентен перечню отдельных индексов: X[A,B,C] эквива-
    лентно X[A][B][C]. Все пояснения подразумевают единственное индексное выражение.
         Величина выражения должна иметь типовое присваивание, сравнимое с индексным типом; при
    этом происходит выбор соответствующего компонентного объекта.

         Пример: S[I+7]

         Выбор поля используется для назначения компонентов объектов типов записи:

         Назначение ::= Назначение '.' Идент

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

         Пример: R.Y

         Разыменование используется для назначения объекта, на который указывает, объектами ти-
    па указатель:

         Назначение ::= Назначение '^'

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

         Пример: P^

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

         Persons[TRUE]^.Last[0] (* первая буква последного имени *)

         Конструктор указателя  используется  для  объединения  целых  положительных   значений
    (CARDINAL) сегмента и смещения в физический адрес:

         Назначение ::= '[' Выраж ':' Выраж [ Имя ] ']'

         Имя обозначает результирующий тип абсолютного указателя;  если оно опущено, то имеется
    в виду тип ADDRESS.
         Пример:

         [ListSeg:FirstNode+N ListPtr]^.Value


                             ВЫРАЖЕНИЯ
                             =========

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

         Выраж ::= ПростоеВыраж [ОперацияОтношения ПростоеВыраж]

         ПростоеВыраж ::= [ОперацияЗнаковая] Терм
                          {ОперацияСложения Терм}

         Терм ::= Фактор {ОперацияУмножения Фактор}

         Фактор ::= '(' Выраж ')'

         Фактор ::= NOT Фактор

         Фактор ::= Значение

         ОперацияОтношения ::= '=' | '#' | '<' | '<=' | '>' |
                              '>=' | IN

         ОперацияЗнаковая ::= '+' | '-'

         ОперацияСложения ::= '+' | '-' | OR

         ОперацияУмножения ::= '*' | '/' | DIV | MOD | AND |
                              '<<' |  '>>'

         Операция, обозначенная оператором, зависит как от оператора, так и от типов операндов.
         Все операторы, исключая IN, требуют операндов совместимых типов.
         Операции сравнения и IN в результате обеспечивают тип BOOLEAN.  Остальные обеспечивают
    такой же результат, как и операнды.
         Операторы '=' и '#' определены для всех типов и сравнивают на (не)равенство.
         Операторы '<','<=','>','>=' определены для перечислимых и действительных типов и пред-
    назначены  для  относительного  упорядочения.  '<='  и '>=' определены для типов множеств и
    сравнивают подмножества и множества высшего порядка.
         Знаковый оператор '+' определен для числовых типов; он невыполняем.
         Знаковый оператор '-' определяется для целых и действительных типов,  отрицая операнд.
         Операторы сложения  '+' и '-' определены для численных типов и означают сложение и вы-
    читание.  Они также определены для типов множеств и обозначают объединение множеств и  раз-
    ность множеств. В конечном счете '+' также определен для любой комбинации постоянных симво-
    лов и строчных литералов,  объединяя их  в  одну  строчную  константу.  Оператор  OR  берет
    операнды BOOLEAN и вычисляет логическую сумму;  если левый операнд является ложным (FALSE),
    то вычисляется только правый операнд.
         Операторы умножения  '*',  DIV и MOD определены для целых и целых положительных типов,
    обеспечивая вычисление частного (округленного до нуля) и остатка (от деления).  '<<' и '>>'
    определены для целых положительных типов,  обеспечивая вычисление логического левого и пра-
    вого сдвига левого операнда на величину правого операнда. '*' и '/' определены для действи-
    тельных  типов,  обеспечивая (приближенное) вычисление произведения и частного .  '*' и '/'
    определены для типов массивов,  обеспечивая вычисление пересечения множеств и  симметричной
    разности множеств.  AND определяется для операндов типа BOOLEAN, обеспечивая вычисление ло-
    гического результата, правый операнд вычисляется в том случае, если левый является истинным
    (TRUE).
         Операнд NОT берет операнд BOOLEAN и дополняет его. Операнд IN берет величины типа мно-
    жество, как  правые  операнды  и величины типа элементы множеств,  как левые операнды:  это
    обеспечивает проверку, находится ли значение элемента в значении множества.
         Множества представляются как битовые карты,  в которых один бит предоставляется каждой
    возможной величине элемента (указывая на его присутствие),  таким  образом,  что  операторы
    множества '+',  '*',  '/' и '-' соответствуют поразрядным булевым операциям OR,  AND, XOR и
    AND NOT соответственно.
         Примеры:

         (J = 0) OR (I MOD J = I - (I DIV J)*J) (* Всегда TRUE*)
         X * Y / Ratio
         R.X + 1
         S[1] IN Z * (Chars{'A'..'F'} + Chars{'0'..'9'})
         'Line terminated with cr/lf' + CHR(13) + CHR(10)


                             ОПЕРАТОРЫ
                             =========

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

         СписокОпер ::= {Опер ';'}

         Знак ';', стоящий после последнего оператора, можно ставить, а можно не ставить.


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

         Оператор присваивания используется для изменения величины объекта:

         Опер ::= Назначение ':=' Выраж

         Выражение вычисляется и его величина замещает старую величину  обозначаемого  объекта.
    Выражение должно представлять собой присваивание, совместимое с типом объекта.
         Строчные литералы представляют собой специальный случай:  они могут быть присвоены лю-
    бому объекту, который имеет тип ARRAY...OF CHAR и является достаточно длинным, чтобы содер-
    жать строку;  если объект более длинный,  то после величины строки включается пустой символ
    (ОС).
         Примеры:

         X := 0.0;
         I := J + 1;
         Z := Z - Chars{'a'..'z'};
         Persons[I>7]^.First := "Kurt";




                            Оператор IF
                            -----------

         Оператор IF используется для выбора списка операторов, условно зависящего от выражений
    типа BOOLEAN, условий:

         Опер  ::=  IF Выраж THEN СписокОпер {ELSIF Выраж THEN
                            СписокОпер}

                     [ELSE СписокОпер] END

         Выполняется максимум один из операторов списка,  а именно, следующий за первым выраже-
    нием, устанавливающимся в TRUE, где ELSE трактуется как ELSIF TRUE THEN.
         Пример:

         IF     I > J THEN
           M := I;
         ELSIF I < J THEN
           M := J;
         ELSE (* I должно быть равно J *)
           B := TRUE;
           M := I;
         END;


                           Оператор CASE
                           -------------

         Оператор выбора осуществляет выбор между альтернативными списками операторов в зависи-
    мости от величины выражения выбора короткого перечислимого типа:

         Опер::= CASE Выраж OF {'|'Выбор} [ELSE СписокОпер] END

         Выбор ::= CписокАльтернатив ':' СписокОпер

         Обозначение '|' перед первым выбором является необязательным.
         Типы альтернативных выражений должны быть совместимы с  типом  выражения  выбора;  они
    должны быть постоянны и их величины не должны перекрываться.  Выполненный список операторов
    такой,  список альтернатив которого включает значение выражения выбора;  если  ни  один  не
    включает, то выполняется необязательный список операторов (после ELSE).
         Пример:

         CASE S[I] OF
           | '.':          I := 999;
           | 'A'..'Z':     L := L + 1;
                           U := U + 1;
           | 'a'..'z':     L := L + 1;
           | '[',']':      X := X + 1;
         ELSE              TheEnd := TRUE;
         END;


                           Оператор WHILE
                           --------------

         Оператор WHILE  используется для выполнения списка операторов от нуля до более раз,  в
    зависимости от величины условия:

         Опер ::= WHILE Выраж DO СписокОпер END

         Выражение вычисляется перед каждым выполнением списка операторов;  повторение заканчи-
    вается, как только величина является ложной (FALSE).
         Пример:

         WHILE (I > 0) AND (I MOD 2 = 0) DO
           I := I DIV 2;
         END;


                          Оператор REPEAT
                          ---------------

         Оператор REPEAT используется для выполнения перечня операторов один или  более  раз  в
    зависимости от величины условия:

         Опер ::= REPEAT СписокОпер UNTIL Выраж

       Выражение вычисляется после каждого выполнения списка операторов;  повторение останавли-
    вается, как только величина является истинной (TRUE).
         Пример:

         REPEAT
           I := I MOD N + 1;
         UNTIL S[I] = ' ';


                           Оператор LOOP
                           -------------

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

         Опер :: LOOP СписокОпер END

         Опер ::= EXIT

         Оператор EXIТ является только одним оператором внутри оператора цикла,  который допус-
    кается использовать; он завершает самый внутренний вложенный цикл.



         Пример:

         LOOP
           IF I = J THEN EXIT; END;
           WHILE I < J DO
             I := (I * J) MOD N;
             IF I = 0 THEN
               I := J;
               EXIT; (* Выйти из LOOP, а не из WHILE. *)
             END;
           END;
           I := I DIV 2;
         END;
         (* Осуществлен выход из LOOP. *)


                            Оператор FOR
                            ------------

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

         Опер ::= FOR Идент ':=' Выраж TO Выраж [BY Выраж] DO
                                           СписокОпер END

         Первые два  выражения  вычисляются  для получения значений начала и конца;  они должны
    иметь типы,  совместимые с перечислимым типом идентификатора.  Выражение, стоящее после ВУ,
    значение  шага,  должно быть постоянным целым числом;  если же оно опущено,  то принимается
    равным +1.
         Переменная управления принимает перечислимые величины,  начиная с начальной величины и
    увеличивается на величину шага.  Оператор FOR прекращает свою работу, когда последующая ве-
    личина превысит величину шага;  список операторов может вообще не выполняться.  Направление
    наращивания определяется знаком величины шага.
          Величина переменной  управления не должна изменяться внутри списка операторов,  и она
    не определена после оператора FOR.
         Пример:

         FOR Ball := Black TO Yellow BY -2 DO
           LastBall := Ball; (* Выбираются: Black(Черный),Blue
                                (Голубой),Green(Зеленый) *)
         END;


                           Оператор WITH
                           -------------

         Оператор WITH применяется для создания локальной области,  в которой имена полей  типа
    записи  могут использоваться непосредственно для обозначения полей определенного обозначен-
    ного объекта этого типа:

         Опер ::= WITH Назначение DO СписокОпер END

         Пример:

         WITH Persons [TRUE]^ DO
           IF Age < 4 THEN
             First := "baby";
           ELSIF Age < 15 THEN
             First := "junior";
           END;
         END;


                           Оператор GOTO
                           -------------

         Оператор GOTO используется для перемены потока (направления) выполнения:

         Опер ::= GOTO Идент

         Конечная точка скачка устанавливается идентификатором метки, которая должна находиться
    в той же самой программной единице :

         Опер ::= Идент ':' [Опер]

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

         Объявление ::= LABEL СписокИдент ';'


                             ПРОЦЕДУРЫ
                             =========

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

         ЗаголовокПроцедуры ::= PROCEDURE Идент[ФормальныйСписок
                                [':' Имя]]';'

         ФормальныйСписок ::='('[ФормальнаяСекция
                                        {';'ФормальнаяСекция}]')'

         ФормальнаяСекция ::= [VAR] СписокИдентификаторов
                              ':' ФормальныйТип

         ФормальныйТип ::= [ARRAY OF] Имя

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

         PROCEDURE NewLine;
         PROCEDURE PrintNumber (N: INTEGER; Width: SHORTCARD );
         PROCEDURE Accumulate (VAR X: LONGREAL; Delta: LONGREAL);
         PROCEDURE HypSquare (A,B: LONGREAL): LONGREAL;
         PROCEDURE PrintMessage (M: ARRAY OF CHAR);
         PROCEDURE GetChar (): CHAR;


                                Тела
                                ----

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

         Объявление ::= ЗаголовокПроцедуры Тело Идент ';'

         Объявление ::= ЗаголовокПроцедуры FORWARD ';'

         Тело ::= СписокОбъявлений [BEGIN СписокОпер] END

         Идентификатор повторяет имя процедуры.  Процедура, объявленная как FORWARD, должна за-
    вершаться позднее в том же описательном списке путем полного объявления процедуры, повторяя
    заголовок процедуры и прилагая ее тело.
         Список объявления объявляет объекты, которые являются локальными по отношению к проце-
    дуре; они должны иметь имена, отличные от формальных параметров.
         Формальные параметры формального типа "массив типа" (ARRAY OF  Type),  т.е.  параметры
    открытого массива, считаются локальными массивами, индексированными с помощью целых положи-
    тельных чисел, начиная с 0; верхняя граница индекса получается с помощью функции HIGH.
         Локальные переменные  появляются,  когда процедуры вызываются и исчезают при возврате.
    Процедуры могут прямо или косвенно вызывать сами себя, вызывая одновременное появление нес-
    кольких наборов локальных переменных.
         Назначение любой локальной переменной относится к экземпляру  из  наиболее  последнего
    активного вызова этой процедуры.
         Параметр формального значения считается обычной локальной переменной, величина которой
    инициализируется  при вызове процедуры.  Формальные параметры VAR обозначают действительные
    объекты, которые идентифицируются вызывающей процедурой при вызове процедуры.
         Открытые массивы можно использовать как действительные параметры для других формальных
    параметров открытого массива;  в противном случае с ними можно работать только поэлементно.
         Список операторов  устанавливает действия процедуры.  Только одним допустимым способом
    выхода из процедуры является выполнение оператора RETURN.  Собственно процедура может  осу-
    ществить возврат также путем достижения конца списка операторов.

         Опер ::= RETURN [Выраж]

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

         PROCEDURE Max (X,Y: LONGREAL): LONGREAL;
         BEGIN
           IF X > Y THEN
             RETURN X;
           ELSE
             RETURN Y;
           END;
         END Max;
         PROCEDURE HypSquare( A,B: LONGREAL): LONGREAL; FORWARD;

         PROCEDURE Accumulate(VAR X: LONGREAL; Y: LONGREAL);
         VAR Z: LONGREAL;
         BEGIN
           Z := HypSquare ( Y, 10.0-Y);
           X := X +Max ( Z*Z, -999.99);
         END Accumulate;

         PROCEDURE HypSquare ( A,B: LONGREAL ): LONGREAL;
         BEGIN
           RETURN A*A + B*B;
         END HypSquare;


                           Вызов процедур
                           --------------

         Собственно процедуры вызываваются в операторах call:

         Опер ::= Назначение [ ФактическийСписок]

         ФактическийСписок ::= '('[Выраж{',' Выраж}]')'

         Список фактических  параметров  должен  обеспечивать  одну величину или назначение для
    каждого соответствующего формального параметра.  Выражение для параметра  типа  VAR  должно
    представлять  собой назначение объекта с типом идентичным формальному типу;  для параметров
    величин любое выражение типа совместимого по присваиванию  является  допустимым.  Строковые
    литералы являются допустимыми для любого значения параметра типа ARRAY ... OF CHAR.
         Формальный тип ARRAY OF Type считается идентичным любому типу массива  с  таким  типом
    элементов;  индексный  диапазон фактического параметра отображается на целые положительные,
    начиная с 0.  Выражение элементного типа также допустимо (и обрабатывается как массив с од-
    ним элементом).
         Формальные типы BYTE,  WORD и LONGWORD совместимы с любым типом  идентичного  размера.
    Формальные типы ARRAY OF BYTE,  ARRAY OF WORD и ARRAY OF LONGWORD совместимы с любыми, поз-
    воляя процедуре обрабатывать фактический параметр, как неструктурированную память.

         Примеры:

         NewLine;
         PrintMessage("Don't panic");
         Accumulate( X, 7.0 * Y );

         Функции вызываютя в выражениях:

         Значение ::= Назначение ФактическийСписок

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

         Примеры:

         X := HypSquare( 10.0, Y );
         C := GetChar();

         Некоторые процедуры могут быть также вызваны с использованием инфиксной нотации.

         Инфикс ::= '\' Назначение '\'


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

         Выраж' ::= Выраж { Инфикс Выраж }

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

         Опер ::= Выраж Инфикс Выраж'


         Примеры:

         X \Accumulate\ 1.0+(5.0\HypSquare\ Y-1.0);
         Accumulate (X, 1.0+HypSquare(5.0, Y-1.0));


                           Типы процедур
                           -------------

         Тип процедуры обозначает семейство процедур с идентичными характеристиками вызова:

         ОписаниеТипа ::=PROCEDURE['('[СписокФормальногоТипа]')'
                                      [':'Имя]]

         СписокФормальногоТипа ::=[VAR]ФормальныйТип{','
                                  [VAR]ФормальныйТип}

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

         Пример:

         TYPE  PutProc = PROCEDURE ( ARRAY OF CHAR );
         VAR G: ARRAY BOOLEAN OF PROCEDURE (): CHAR;
             P: PutProc;

         Имеется один предопределенный тип процедур:

         TYPE PROC = PROCEDURE; (* Процедуры без параметров *)

         Одно предопределенное значение процедуры, NULLPROC, является совместимым с любым типом
    процедур. При ее вызове происходит ошибка во время выполнения.
         Значения процедур обозначаются назначениями без списков параметров.

         Примеры:

         P := PrintMessage; (* P теперь обозначает PrintMessage*)
         P ("Hi, there");   (* Вызвать ее *)
         G [TRUE] := GetChar; (* G[TRUE] теперь обозначает
                                                      GetChar *)
         C := G[TRUE] ();     (* Вызвать ее *)


                     Предопределенные процедуры
                     --------------------------

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

         Предопределенные функциональные процедуры:

         ABS(X) - абсолютная величина числовых операндов.

         ADR(X) - физический адрес объекта X.

         CAP(C) - символ C, изменяющий 'a'..'z' to 'A'..'Z'.

         CHR(X) - CHAR с порядковой величиной X.

         FLOAT(C) - действительное значение CARDINAL C.

         HIGH(A) - верхняя индексная граница открытого массива A.

         MAX(T) - максимальная величина порядкового/действительного типа T.

         MIN(T) - минимальная величина порядкового/действительного типа T.

         ODD(X) - TRUE, если перечислимая величина X нечетна.

         ORD(X) - CARDINAL, короткая перечислимая величина X.

         SIZE(T) - размер в байтах типа или объекта T.

         TRUNC(R) - CARDINAL, усеченная величина действительного T.

         VAL(T,X) - величина X, преобразованная к типу T.

         VSIZE(R.F) - размер типа записи R, включающий поле F.

         Предопределенные правильные процедуры:

         DEC(X) - убывающий перечислимый объект X.

         DEC(X,N) - убывающий перечислимый объект X с количеством N.

         EXCL(S,E) - исключение элемента E из объекта множества S.

         HALT - прерывание выполнения программы.

         INC(X) - возрастающий перечислимый объект X.

         INC(X,N) - возрастающий перечислимый объект X с количеством N.

         INCL(S,E) - включение элемента E в объект множества S.

         VAL может превращать величины между двумя численными и перечислимыми типами.

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

         Примеры:

         I := CARDINAL(BITSET(I) *  BITSET(J));  (*  поразрядное
                                                    умножение *)
         L := LONGCARD(SegOfz); (* запись -> целое положительное *)
         SegOfz := ArdPair(L); (* целое положительное -> запись *)
         P := ADDRESS(L);       (* Не адрес L! *)


                               МОДУЛИ
                               ------

         Модули включают сопутствующие объявления.  Исполняющая программа состоит  из  главного
    модуля  и  ряда обслуживающих модулей.  Обслуживающие модули делятся на определяющую часть,
    видимую для пользователей,  и часть выполнения,  которая прячет внутренние детали от клиен-
    тов.
         Модули представляют общее средство для использования (введения) свойств,  которые явно
    не представляются языком:  ввод и вывод,  операции со строкой, организация памяти, паралле-
    лизм, доступ к операционной системе и т.д. (см. ГЛАВУ 8).
         Модули представляют собой базовые единицы компиляции:

         Компиляция ::= ОпределениеМодуля '.'

         Компиляция ::= [IMPLEMENTATION] Moдуль '.'

         Модуль ::= MODULE Идент [Приоритет] ';' {Импорт}
                                 [Экспорт] Тело Идент


         ОпределениеМодуля ::=  DEFINITION  MODULE Идент  ';'
                         {Импорт} СписокОбъявлений END Идент

         Приоритет ::= '['Выр']'

         Каждый идентификатор именует определяемый модуль.
         Модули могут иметь приоритет типа CARDINAL,  используемый с модулем SYSTEM (см.  ГЛАВУ
    8).
         Модуль компиляции без применения IMPLEMENTATION представляет собой главный модуль.


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

         Определительная часть  обслуживающего модуля объявляет объекты доступные пользователю.
    Легальными являются только объявления CONST,  TYPE и VAR в дополнение к двум следующим, ко-
    торые являются легальными только в определительных частях:

         Объявление ::= ЗаголовокПроцедуры

         Объявление ::= TYPE {Идент ['=' ОпределениеТипа} ';'}

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

         Пример:

         DEFINITION MODULE Str; (* Бит управляющей строки *)
           CONST MaxWidth = 20;
           TYPE Buffer = ARRAY [1..MaxWidth] OF CHAR;
           VAR  Width: [1..MaxWidth];
           PROCEDURE Put ( C: CARDINAL ): Buffer;
           PROCEDURE SetFill ( C: CHAR );
         END Str.

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

         Пример:

         IMPLEMENTATION MODULE Str;
           VAR FillChar: CHAR;

           PROCEDURE Put ( C: CARDINAL ): Buffer;
             VAR P: [0..MaxWidth];
                 S: Buffer;
           BEGIN
             P := Width;
             REPEAT
               S[P] := CHR( ORD('0') + C MOD 10 );
               C := C DIV 10;
               DEC( P );
             UNTIL (C = 0) OR (P = 0);
             WHILE P > 0 DO
               S[P] := FillChar;
               DEC( P );
             END;
             RETURN S;
           END Put;

           PROCEDURE SetFill ( C: CHAR );
           BEGIN
             FillChar := C;
           END SetFill;
         BEGIN
           FillChar := ' ';
         END Str.


                           Импортирование
                           --------------

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

         Импорт ::= [ FROM Идент ] IMPORT СписокИдент ';'

         Форма FROM получает один модуль и перечень идентификаторов,  именующих объекты в  нем.
    Эти  имена  считаются  объявлениями тех идентификаторов и таким образом обеспечивают прямую
    видимость именованных объектов.  Импортирование перечислимого типа также импортирует  пере-
    числимые литералы.
         Форма без выражения FROM импортирует каждый из именованных модулей. Установленные име-
    на используются для определения объектов в этих модулях:

         Имя ::= Идент '.' Идент

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


         Пример:

         FROM Str IMPORT Put, Width;
         IMPORT Str;
         VAR S: Str.Buffer;
         ...
         Str.SetFill(' ');
         Width := Str.MaxWidth DIV 2;
         S := Put( I+7 );


                          Локальные модули
                          ----------------

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

         Объявление ::= Модуль ';'

         Локальные модули  подчиняются  правилам  специальной  области.  Любой требуемый объект
    (кроме предопределенных объектов),  расположенный вне локального модуля, должен быть импор-
    тирован и должен сразу быть видимым вне локального модуля.  Таким образом импорт без "FROM"
    может именовать любой объект (не только вспомогательные модули).  Использование формы  FROM
    требует видимости именованного вспомогательного модуля (и таким образом уже импортированно-
    го) сразу же вне локального модуля.
         Экспортирование разрешается только в локальных модулях:

         Экспорт ::= EXPORT СписокИдент ';'

       Перечисленные идентификаторы  объявляются в окружающей (внешней) области для того, чтобы
    сделать эти области непосредственно доступными. Уточнение может быть использовано для обес-
    печения доступа к любому объекту.
         Возможные списки операторов локальных модулей выполняются (в той последовательности, в
    которой появляются) перед списком операторов внешней области.
         Уточненный экспорт был оставлен в самом позднем варианте ("официальном")  Modula-2, но
    он  не входит в JPI Modula-2;  это излишне,  поскольку все идентификаторы локальных модулей
    доступны с помощью установленных имен как угодно.
         На этом описание языка JPI Modula-2 заканчивается.


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