Copyright (C) А.Гавва V-0.4w май 2004

1. Элементарные понятия.

1.1 "Сюрпризы" переводной терминологии

Прежде чем приступить к непосредственному знакомству с Адой, есть необходимость заметить, что в англоязычной литературе, посвященной вычислительной технике в целом и программированию в частности, достаточно часто встречаются такие английские термины как operator, operation и statement. При сложившейся практике перевода такой документации на русский язык, эти термины, как правило, переводят следующим образом:

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

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

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

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

1.2 Первая программа

Для того, чтобы дать "почувствовать", что представляет из себя программа написанная на языке Ада рассмотрим простую программу. Традиционно, первая программа - это программа которая выводит на экран приветствие: "Hello World!". Не будем нарушать традицию. Итак, на Аде такая программа будет иметь следующий вид:

    
    
    with Ada.Text_IO;
    use Ada.Text_IO;
    
    procedure Hello is
    begin
        Put_Line("Hello World!");
    end Hello;
    

Давайте детально рассмотрим из каких частей состоит текст этой программы. Строка "procedure Hello is" является заголовком процедуры и она указывает имя нашей процедуры. Далее, между зарезервированными словами begin и end, располагается тело процедуры Hello. В этом примере тело процедуры очень простое и состоит из единственной инструкции "Put_Line("Hello World!");". Эта инструкция осуществляет вывод приветствия на экран, вызывая процедуру Put_Line. Процедура Put_Line располагается в пакете текстового ввода/вывода Ada.Text_IO, и становится доступной благодаря спецификации контекста в инструкциях "with Ada.Text_IO;" и "use Ada.Text_IO;" (спецификация контекста необходима для указания используемых библиотечных модулей). Здесь, спецификатор контекста состоит из двух спецификаторов: спецификатора совместности with и спецификатора использования use. Cпецификатор совместности with указывает компоненты которые будут использоваться в данном компилируемом модуле. Cпецификатор использования use делает имена используемых объектов непосредственно доступными в данном компилируемом модуле.

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

    
    with ... ;
    use  ... ;
       спецификаторы контекста, указывающие используемые модули (могут отсутствовать)
            
    procedure < имя процедуры > ... is
       спецификация процедуры, определяющая имя процедуры и ее параметры (если они есть)
            
        . . .
      описательная (или декларативная) часть, которая может содержать описания типов, переменных, констант и подпрограмм
            
    begin 
        
        . . .
       исполняемая часть процедуры, которая описывает алгоритм работы процедуры
            
    end < имя процедуры >;
       здесь, указание имени процедуры не является обязательным

Необходимо заметить, что в отличие от языков С/C++, которые имеет функцию main, и языка Паскаль, который имеет program, в Аде, любая процедура без параметров может быть подпрограммой main (другими словами - головной программой). Таким образом, процедура без параметров может быть выбрана как головная программа во время линковки.

Теперь, приведем еще один простой пример, в котором, для выдачи сообщения приветствия, используется ранее рассмотренная процедура Hello:

    
    
    with Hello;    -- указывает на использование показанной ранее
                   -- процедуры Hello
    
    procedure Use_Hello is
    begin
        Hello;            -- вызов процедуры Hello
    end Use_Hello;
    

1.3 Библиотека и компилируемые модули

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

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

1.4 Лексические соглашения

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

1.4.1 Комментарии

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

    
    
      -- это комментарий
      --- это тоже комментарий
    

1.4.2 Идентификаторы

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

  1. Идентификатор может состоять из букв, цифр и символов подчеркивания.
  2. Идентификатор обязан начинаться с символа.
  3. В идентификаторе нельзя использовать несколько символов подчеркивания подряд.
  4. Символ подчеркивания не может быть первым и последним символом в идентификаторе.
  5. Все идентификаторы в ADA не зависят от регистра символов.

Например:

    
    
    Apple, apple, APPLE     -- один и тот же идентификатор
    Max_Velocity_Attained
    Minor_Number_           -- недопустимо, завершающий символ - подчеркивание
    Minor__Revision         -- недопустимо, последовательность подчеркиваний
    

1.4.3 Литералы

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

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

Примеры целочисленных литералов, представляющих значение числа 2000:

    
    
      2000
      2_000
      2E3       -- для целочисленных литералов разрешена экспоненциальная форма
      2E+3    
    

Возможно представление чисел в разных системах счисления, например, представление десятичного числа 12 может быть задано следующими литералами:

    
    
      2#1100#   -- двоичная система счисления
      8#14#     -- восьмеричная
      10#12#    -- десятичная (здесь, указана явно)
      16#C#     -- шестнадцатиричная
      7#15#     -- семиричная
    

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

    
    
      3.14
      100.0
      0.0
    

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

    
    
      'a'
      'b'
    

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

    
    
      "это строковый литерал"
      "a"                     -- это тоже строковый литерал, хотя и односимвольный
    

1.4.4 Зарезервированные слова

Некоторые слова, такие как with, procedure, is, begin, end и т.д., являются частью самого языка программирования. Такие слова называют зарезервированными (или ключевыми) и они не могут быть использованы в программе в качестве имен идентификаторов. Полный список зарезервированных слов Ады приводится ниже:

    
    
      abort         else             new              return
      abs           elsif            not              reverse
    * abstract      end              null           
      accept        entry                             select
      access        exception                         separate
    * aliased       exit             of               subtype
      all                            or             
      and           for              others         * tagged
      array         function         out              task
      at                                              terminate
                    generic          package          then
      begin         goto             pragma           type
      body                           private        
                    if               procedure      
      case          in             * protected      * until
      constant      is                                use
                                     raise          
      declare                        range            when
      delay         limited          record           while
      delta         loop             record           while
      digits                         renames        
      do            mod            * requeue          xor
    

1.5 Методы Ады: подпрограммы, операции и знаки операций

Методами Ады являются подпрограммы (процедуры и функции), а также операции и знаки операций (возможно более корректно будет звучать: с помощью подпрограмм осуществляется реализация действий, выполняемых операциями и знаками операций). Необходимо отметить, что стандарт Ады строго различает понятия знаков операций (operators) и операций (operations).

Знаки операций представляются следующими символами (или комбинациями символов): "=", "/=", "<", ">", "<=", ">=", "&", "+", "-", "/", "*". Другие знаки операций выражаются зарезервированными словами: "and", "or", "xor", "not", "abs", "rem", "mod", - или могут состоят из нескольких зарезервированных слов: "and then", "or else". Ада позволяет осуществлять программисту совмещение (overloading) знаков операций (в современной литературе по Си++ это часто называется как "перегрузка операторов").

Использование "use type" делает знаки операций именованных типов локально видимыми. Кроме того, их можно сделать локально видимыми используя локальное переименование.

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

Следует заметить, что Ада накладывает некоторые ограничения на использование совмещений: совмещения не допускаются для операций присваивания и проверки принадлежности диапазону, а также для знаков операций "and then" и "or else".

Операция присваивания обозначается комбинацией символов ":=". Она предопределена для всех нелимитированных типов. Операция присваивания не может быть совмещена или переименована. Присваивание запрещено для лимитированных типов. Необходимо подчеркнуть, что операция присваивания в Аде, в отличие от языков C/C++, не возвращает значение и не обладает побочными эффектами.

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

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

1.6 Инструкции, выражения и элаборация

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

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

    
    
    procedure P( ... ) is
        I: Integer := 1;    -- описательная часть
        . . .
    begin
        . . .               -- последовательность инструкций
        I := I * 2;
        . . .
    end P;
    

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

После завершения элаборации, осуществляется исполнение последовательности инструкций, в порядке их следования (за исключением случаев, когда осуществляется передача управления в какое-либо другое место, отличное от последующей инструкции). Инструкция присваивания позволяет заменить значение переменной результатом вычисления выражения того же самого типа. Обычно, присваивание осуществляется простым побитовым копированием значения, которое получено в результате вычисления выражения. Однако, в случае нелимитированных контролируемых типов, после осуществления побитового копирования, пользователь (при необходимости) может определить дополнительную последовательность действий. Инструкции case и if позволяют осуществлять выбор выполнения определенной последовательности инструкций, полагаясь на результат вычисления какого-нибудь выражения. Инструкция loop позволяет повторять выполнение последовательности каких-либо инструкций, согласно выбранной схемы итерации, или до обнаружения инструкции exit. Инструкция goto осуществляет передачу управления в место отмеченное соответствующей меткой.

Выражения могут быть использованы в различном контексте, как в описаниях, так и в инструкциях. Используемые в языке Ада выражения, во многом подобны выражениям, которые используются в большинстве современных языков программирования. Они могут содержать обращения к переменным, константам и литералам, кроме того они могут использовать любые операции, которые возвращают значения. Результатом вычисления любого выражения является значение. Каждое выражение имеет определенный тип, который известен на этапе компиляции.

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

1.7 Директивы компилятора

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

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

    
    
    pragma < имя_директивы > ( < параметры_директивы > );
    

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

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


Copyright (C) А.Гавва V-0.4w май 2004