ASIS-для-GNAT User's Guide

ASIS-для-GNAT User's Guide ( GNAT-3.15p )

(C) Copyright 2000, Ada Core Technologies, Inc.

Перевод Copyright (C) 2003 А.Гавва.
Коммерческое распространение перевода, без разрешения автора перевода, запрещено.


Содержание


Об этом руководстве

Это руководство преследует две цели. Во-первых, ознакомить Вас со Спецификацией Семантического Интерфейса Ады (Ada Semantic Interface Specification, сокращенно - ASIS) и продемонстрировать Вам как, с помощью ASIS, можно строить различные инструментальные средства. Во-вторых, описать реализацию ASIS для Ada95-компилятора GNAT.


Что содержится в данном руководстве

Это руководство содержит следующие главы:


Что Вам необходимо знать перед чтением этого руководства

Это руководство пользователя ASIS предполагает, что Вы знакомы с языком программирования Ada95 и что Вы имеете неготорое представление о программировании на языке Ада в среде компилятора GNAT.

Это руководство также предполагает, что вы обладаете правильно установленным ASIS-для-GNAT для вашего компилятора GNAT, и что Вы знакомы со структурой дистрибутива ASIS-для-GNAT (если нет, то ознакомтесь с содержимым файла README из вашего дистрибутива, секция 2).

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


Дополнительная информация

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

Для того, чтобы знать как правильно установить реализацию ASIS для вашего компилятора GNAT, следует обратиться к руководству по инсталяции ASIS-для-GNAT.

Описание ASIS 95 в настоящее время присутствует в международном стандарте ISO/IEC International Standard 15291.

Для получения дополнительной информации об ASIS, посетите WEB-страничку рабочей группы ASIS (http://www.acm.org/sigada/wg/asiswg).

Для дальнейшего чтения этого руководства вам также потребуется Справочное руководство по ASIS-для-GNAT (ASIS-для-GNAT Reference Manual) и/или Справочное руководство по компилятору GNAT (GNAT Reference Manual).


1. Введение

1.1 Что такое ASIS?

Спецификация семантического интерфейса Ады (The Ada Semantic Interface Specification, сокращенно - ASIS) является определением интерфейса между окружением языка программирования Ада (которое описано в ISO/IEC 8652:1995) и любыми инструментальными средствами, которые нуждаются в информации от него. Окружение Ады содержит богатую коллекцию семантической и синтаксической информации. ASIS является открытым и доступным интерфейсом, который обеспечивает доступ к этой информации CASE-средствам и разработчикам приложений. ASIS разрабатывался как интерфейс, который не зависит от внутренней архитектуры используемой Ада-системы, обеспечивая, таким образом, переносимость средств программной инженерии, и освобождая разработчиков этих средств от необходимости понимания сложностей архитектуры и внутреннего представления Ада-системы.

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

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


1.2 Область применения ASIS: какие средства можно построить с помощью ASIS?

Следующие свойства ASIS определяют область использования ASIS:

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


2. Беглое знакомство с ASIS

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


2.1 Постановка задачи

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


2.2 Приложение ASIS для решения поставленной задачи

    
    
    with Ada.Wide_Text_IO;        use Ada.Wide_Text_IO;
    with Ada.Characters.Handling; use Ada.Characters.Handling;
    
    --  спецификаторы контекста, характерные для ASIS:
    with Asis;
    with Asis.Implementation;
    with Asis.Ada_Environments;
    with Asis.Compilation_Units;
    with Asis.Exceptions;
    with Asis.Errors;
    
    procedure Example1 is
       My_Context : Asis.Context;
       --  ASIS Context является абстракцией какого-либо окружения Ады,
       --  он описывает множество компилируемых модулей ASIS,
       --  которые доступны через запросы ASIS
    
    begin
       --  во-первых, при инициализации какой-либо реализации ASIS,
       --  нам необходимо подготовить ее к непосредственной работе
       Asis.Implementation.Initialize;
    
       --  затем, мы описываем наш контекст Context, осуществляя
       --  ассоциирование с "физическим" окружением:
       Asis.Ada_Environments.Associate
        (My_Context, "My Asis Context", "-CA");
       --  См. ASIS-для-GNAT Reference Manual, чтобы получить сведения
       --  о параметрах запроса Associate, а также главу "Контекст ASIS"
       --  чтобы узнать о различных видах контекста ASIS при использовании
       --  ASIS-для-GNAT
    
       --  при открытии контекста, мы подготавливаем его к обработке
       --  запросами ASIS
       Asis.Ada_Environments.Open (My_Context);
    
       Processing_Units: declare
          Next_Unit : Asis.Compilation_Unit;
          --  ASIS Compilation_Unit является абстракцией, которая представляет
          --  компилируемые модули Ады, как описано в RM 95
    
          All_Units : Asis.Compilation_Unit_List :=
          --  ASIS Compilation_Unit_List является одномерным
          --  неограниченным массивом.
          --  Следовательно, при определении какого-либо объекта
          --  этого типа, нам необходимо предусмотреть или ограничение,
          --  или явное выражение инициализации.
    
             Asis.Compilation_Units.Compilation_Units (My_Context);
          --  запрос Compilation_Units возвращает список всех модулей,
          --  которые содержатся в контексте ASIS Context
       begin
          Put_Line
            ("A Context contains the following compilation units:");
          New_Line;
          for I in All_Units'Range loop
             Next_Unit := All_Units (I);
             Put ("   ");
    
             --  для получение имени модуля нам необходим простой запрос
             --  Unit_Full_Name. В качестве строк ASIS использует 
             --  Wide_String, следовательно, нам необходимо выполнить
             --  преобразование в тип String, чтобы использовать
             --  Ada.Text_IO
             Put (Asis.Compilation_Units.Unit_Full_Name (Next_Unit));
    
             --  для получения дополнительной информации о модуле,
             --  мы опрашиваем о его классе и о его источнике
    
             case Asis.Compilation_Units.Unit_Kind (Next_Unit) is
                when Asis.A_Library_Unit_Body =>
                   Put (" (body)");
                when Asis.A_Subunit =>
                   Put (" (subunit)");
                when others =>
                   Put (" (spec)");
             end case;
    
             case Asis.Compilation_Units.Unit_Origin (Next_Unit) is
                when Asis.An_Application_Unit =>
                   Put_Line (" - user-defined unit");
                when Asis.An_Implementation_Unit =>
                   Put_Line (" - implementation-specific unit");
                when Asis.A_Predefined_Unit =>
                   Put_Line (" - Ada predefined unit");
                when Asis.Not_An_Origin =>
                   Put_Line
                     (" - unit does not actually exist in a Context");
             end case;
    
          end loop;
       end Processing_Units;
    
       --  Очистка: нам необходимо закрыть контекст Context, разорвать
       --  его ассоциацию с внешним окружением и очистить нашу реализацию
       --  ASIS для освобождения всех использованных ресурсов:
       Asis.Ada_Environments.Close (My_Context);
       Asis.Ada_Environments.Dissociate (My_Context);
       Asis.Implementation.Finalize;
    
    exception
       when Asis.Exceptions.ASIS_Inappropriate_Context |
            Asis.Exceptions.ASIS_Inappropriate_Compilation_Unit |
            Asis.Exceptions.ASIS_Failed =>
    
          --  мы делаем проверку не для всех исключений, которые определены
          --  в ASIS, а только тех, которые могут быть возбуждены в нашем
          --  приложении ASIS
          --
          --  Если возбуждено какое-либо исключение ASIS, мы выводим
          --  статус ошибки ASIS и строку диагностики ASIS:
    
          Put_Line ("ASIS exception is raised:");
          Put_Line ("ASIS diagnosis is:");
          Put_Line (Asis.Implementation.Diagnosis);
          Put      ("ASIS error status is: ");
          Put_Line
            (Asis.Errors.Error_Kinds'Wide_Image
               (Asis.Implementation.Status));
    end Example1;
    


2.3 Требуемая последовательность вызовов

Приложение ASIS должно использовать следующую последовательность вызовов:

  1. Asis.Implementation.Initialize (...);

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

  2. Asis.Ada_Environments.Associate (...);

    Этого вызова подгазумевает определение значения переменной лимитированного приватного типа ASIS Context. Такое значение является несколько особенной ассоциацией контекста (Context) ASIS с "внешним миром". Способ создания такой ассоциации и смысл соответствующих параметров запроса Associate определяются реализвцией, однако, после осуществления такой ассоциации и открытия переменной контекста, контекст ASIS, обозначенный этой переменной, может рассматриваться как множество модулей компиляции ASIS (ASIS Compilation Units) доступных для запросов ASIS.

  3. Asis.Ada_Environments.Open (...);

    Открытие переменной контекста ASIS создает соответствующий контекст Context, который доступен для всех запросов ASIS.

    После открытия контекста, приложение ASIS может стартовать получение из этого контекста модулей компиляции ASIS (ASIS Compilation Units), и осуществлять дальнейший анализ путем декомпозиции этих модулей в элементы (Elements) ASIS и т.д.

    ASIS полагается на содержимое контекста, которое остается "замороженным" пока контекст Context остается открытым. Какие-либо изменения, с помощью не-ASIS-программ, структур данных используемых реализацией ASIS для описания и реализации этого контекста, в то время когда контекст Context открыт, приведут к ошибке.

  4. Asis.Ada_Environments.Close (...);

    После закрытия контекста становится невозможным получение от него какой-либо информации. Все значения объектов ASIS, принадлежащих к типам Compilation_Unit, Element и Line, и полученных когда этот контекст Context был открыт, становятся устаревшими, а их использование после закрытия контекста может привести к ошибке. Реальный контекст для контекста Context не обязан оставаться "замороженным", когда контекст Context остается закрытым. Следует заметить, что закрытый контекст Context сохраняет свою ассоциацию с "внешним миром" и он может быть открыт вновь, используя ту же самую ассоциацию. Также следует заметить, что содержимое (то есть, соответствующее множество модулей компиляции ASIS (ASIS Compilation Units)) контекста Context может отличаться от предыдущего, поскольку "внешний мир" мог измениться пока контекст Context оставался закрытым.

  5. Asis.Ada_Environments.Dissociate (...);

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

  6. Asis.Implementation.Finalize (...);

    Этот вызов освобождает все ресурсы, которые использовались реализацией ASIS.

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

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


2.4 Построение исполняемого модуля ASIS-приложения

Остаток этой секции предполагает, что Вы обладаете правильно установленным ASIS-для-GNAT.

Для получения исполняемого модуля приложения ASIS из секции 1.2 (предполагается, что исходный текст этого приложения храниться в текущем каталоге в файле с именем example1.adb), Вам необходимо запустить утилиту gnatmake следующим образом:

    
    
    gnatmake example1[.adb] -largs -lasis
    

Процесс компиляции и построения исполняемых модулей для приложений ASIS в среде ASIS-для-GNAT более подробно рассматривается в главе 10. Компиляция, связывание и компоновка приложений с ASIS-для-GNAT.


2.5 Генерация деревьев для ввода

Для получения от окружения Ады информации, которая необходима для обработки, ASIS-для-GNAT обрабатывает, так называемые, файлы деревьев. Файл дерева генерируется компилятором GNAT, и он содержит "снимок" внутренних структур данных компилятора. Более подробно это рассматривается в секции 4.1 Файлы контекста и дерева ASIS этого руководства.

Чтобы создать файл дерева для модуля, содержащегося в каком-либо файле с исходным текстом, необходимо откомпилировать этот модуль используя опции компилятора -gnatc -gnatt Чтобы применить приложение, которое описывается в секции 2.2 Приложение ASIS для решения поставленной задачи, к нему же, необходимо откомпилировать исходный текст этого приложения с помощью следующей команды:

    
    
    gcc -c -gnatc -gnatt example1.adb
    

В результате этого в текущем каталоге будет получен файл дерева с именем example1.adt.

Более подробные объяснения того как генерировать и использовать файлы деревьев содержатся в главах 4. Контекст ASIS и 7. Учебные примеры ASIS.


2.6 Запуск ASIS-приложения

Чтобы завершить рассмотрение нашего примера, необходимо запустить на выполнение наше приложение ASIS. Если Вы следовали всем шагам, которые рассматривались в главе 2. Беглое знакомство с ASIS, то теперь у Вас, в текущем каталоге, должны присутствовать исполняемый модуль example1 и файл дерева example1.atd (следует заметить, что файл дерева содержит информацию о модуле для которого он был создан и обо всех модулях от которых этот модуль семантически зависит). Если мы запустим наше приложение оно обработает весь контекст ASIS, который описан в единственном файле дерева example1.adt (определение контекста ASIS более подробно рассматривается в главе 4. Контекст ASIS этого руководства). Результат запуска будет иметь следующий вид:

    
    
       A Context contains the following compilation units:
    
          Standard (spec) - Ada predefined unit
          Example1 (body) - user-defined unit
          Ada.Text_IO (spec) - Ada predefined unit
          Ada (spec) - Ada predefined unit
          Ada.IO_Exceptions (spec) - Ada predefined unit
          Ada.Streams (spec) - Ada predefined unit
          System (spec) - Ada predefined unit
          System.File_Control_Block (spec) - Ada predefined unit
          System.Parameters (spec) - Ada predefined unit
          Ada.Characters.Handling (spec) - Ada predefined unit
          Ada.Characters (spec) - Ada predefined unit
          Asis (spec) - user-defined unit
          A4G.A_Types (spec) - user-defined unit
          A4G (spec) - user-defined unit
          Ada.Characters.Latin_1 (spec) - Ada predefined unit
          A4G.Int_Knds (spec) - user-defined unit
          Types (spec) - user-defined unit
          Unchecked_Deallocation (spec) - Ada predefined unit
          Asis.Implementation (spec) - user-defined unit
          Asis.Errors (spec) - user-defined unit
          Asis.Ada_Environments (spec) - user-defined unit
          Asis.Compilation_Units (spec) - user-defined unit
          Asis.Ada_Environments.Containers (spec) - user-defined unit
          Asis.Exceptions (spec) - user-defined unit
    

В текущей реализации, реализация компонентов ASIS рассматривается как модули определяемые пользователем, а не модули определяемые реализацией. Следует также заметить, что некоторые компоненты библиотеки времени выполнения GNAT (GNAT Run-Time Library) могут быть неявно указаны в спецификаторе контекста withed внутри некоторых Ада-модулей, и, следовательно, они могут быть представлены в файле дерева. Благодаря этому Вы видете System.File_Control_Block в показанном выше списке.


3. Обзор ASIS

Эта глава содержит краткий обзор определений ASIS, которые приводятся в стандарте ASIS ISO/IEC 15291:1999 ASIS Standard. Цель этого обзора заключается в том, чтобы помочь новым пользователям ASIS в поиске необходимой информации среди определений ASIS и дать им общее представление структуре ASIS.

Для получения более подробных сведений следует непосредственно обратиться к определениям ASIS, а чтобы получить общее начальное представление - используйте учебные примеры ASIS (см. 7. Учебные примеры ASIS).


3.1 Главные абстракции ASIS

ASIS основывается на трех главных абстракциях, используемых для описания Ада-программ:

Контекст Context
Контекст ASIS - это логический дескриптор окружения Ады, которое описывается в RM 95 Chapter 10. Во избежание трудностей языкового уровня, при попытке понять формальное отношение между контекстом ASIS и окружением Ады, разработчик приложения ASIS может рассматривать контекст ASIS как способ определения набора компилируемых модулей, которые доступны через запросы ASIS.

Модуль компиляции Compilation Unit
Модуль компиляции ASIS - это логический дескриптор компилируемого модуля Ады. Он, практически, один-в-один отражает все свойства компилируемых модулей, которые описываются в RM 95, а также отражает некоторые свойства "физических объектов", трактуемых используемой реализацией Ады как компилируемые модули (таких как время последней модификации, имя некоторого объекта трактуется как содержащее исходный текст модуля). Модуль компиляции ASIS предусматривает для компилируемого модуля представление в виде "черного ящика", рассматривая компилируемый модуль как единое целое. Модуль компиляции можно декомпозировать и анализировать как "белый ящик" в терминах элементов ASIS.

Элемент Element
Элемент ASIS - это логический дескриптор синтаксического компонента модуля компиляции ASIS (как явный, так и неявный).

Некоторые компоненты ASIS используют дополнительные абстракции, которые необходимы для определенных фрагментов функциональности предусматриваемых этими компонентами:

Контейнер Container
Контейнер ASIS (определенный и используемый пакетом Asis.Ada_Environments.Containers) обеспечивает осмысленное структурирование содержимого контекста ASIS путем группировки модулей компиляции ASIS в контейнеры.

Строка Line
Строка ASIS (определенная и используемая пакетом Asis.Text) является абстракцие строки исходного текста Ады. Строка ASIS обладает длиной, образом строки и номкром.

Интервал Span
Интервал ASIS (определенный и используемый пакетом Asis.Text) определяет размещение элемента, модуля компиляции или всей компиляции в соответствующем исходном тексте.

Идентификатор Id
Идентификатор ASIS (определенный и используемый пакетом Asis.Ids) предусматривает способ хранения некоторого "образа" элемента ASIS вне приложения ASIS. Приложение может создать значение идентификатора Id из значения элемента Element и сохранить его в файле. После этого, это же или другое приложение может прочитать такое значение идентификатора Id и попытаться преобразовать его обратно, в соответствующее значение элемента Element.


3.2 Иерархия пакетов ASIS

ASIS описывается как иерархия спецификации пакетов Ады. Ниже приводится краткое описание этой иерархии.

Asis - это корневой пакет иерархии. Он определяет главные абстракции ASIS (Context, Compilation_Unit и Element) как приватные типы. Он также содержит ммножество перечислимых типов, которые описывают классификационную иерархию для элементов ASIS (что близко отражает синтаксис Ады, описанный в RM 95) и классификацию модулей компиляции ASIS. Этот пакет не содержит ни одного запроса;

Asis.Implementation - содержит подпрограммы, которые управляют реализацией ASIS: инициируют и очищают ее, получают и переустанавливают диагностическую информацию. Его дочерний пакет Asis.Implementation.Permissions содержит логические запросы, которые скажут Вам как определяемые реализацией средства ASIS реализованы в вашей реализации ASIS;

Asis.Ada_Environments - содержит запросы, которые взаимодействуют с контекстом ASIS: ассоциируют и разрушают ассоциацию, открывают и закрывают контекст;

Asis.Compilation_Units - содержит запросы, которые работают с модулями компиляции ASIS: получение модулей от контекста, получение семантической зависимости между модулями и свойствами модуля как "черного ящика";

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

Asis.Elements - содержит запросы, которые работают с элементами и реализуют основные свойства элементов: запросы доступа из модулей компиляции ASIS к элементам ASIS, запросы описывающие позицию элемента в иерархии классификации элементов, запросы, которые определяют для данного элемента его объемлющий модуль компиляции и его объемлющий элемент. Он также содержит запросы, которые работают с программами;

Asis.Declarations, Asis.Definitions, Asis.Statements, Asis.Expressions и ASIS.Clauses - каждый из этих пакетов содержит запросы работы с элементами соответствующего вида, то есть, обеспечивающие представление определений, описаний, инструкций, выражений и предложений Ады соответственно;

Asis.Text - содержит запросы, которые возвращают информацию о представлении исходного текста модулей компиляции и элементов ASIS;

Asis.Exceptions - определяет исключения ASIS;

Asis.Errors - определяет возможные статусы ошибки ASIS.


3.3 Структурные и семантические запросы

Запросы, которые работают с элементами и возвращают элементы или списки элементов, делятся на структурные и семантические запросы.

Каждый структурный запрос (кроме Enclosing_Element) реализует один шаг декомпозиции (от предка к потомку) Ада-программы, в соответствии с иерархией классификации элементов ASIS. Запрос Asis.Elements.Enclosing_Element реализует обратный шаг - от потомка к предку (для неявных элементов, полученных в качестве результатов семантических запросов, объемлющий элемент может не соответствовать тому, что ожидается получить от синтаксиса Ады и описываемой в RM 95 семантики, в таком случае, документация семантического запроса описывает также эффект Enclosing_Element, примененного к его результату).

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

Например, если у нас есть элемент El представляющий инструкцию присваивания:

    
    
        X := A + B;
    

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

    
    
       El_Var  := Asis.Statements.Assignment_Variable_Name (El); --  X
       El_Expr := Asis.Statements.Assignment_Expression    (El); --  A + B
    

Затем, мы можем выполнить анализ семантических свойств имени переменной, представленной с помощью El_Var, и выражения, представленного с помощью El_Expr, подразумевая подходящие семантические запросы:

    
    
       El_Var_Def   :=
          Asis.Expressions.Corresponding_Name_Definition (El_Var);
       El_Expt_Type :=
          Asis.Expressions.Corresponding_Expression_Type (El_Expr);
    

Как результат, El_Var_Def будет принадлежать к виду A_Defining_Identifier и будет представлять случай описания X, когда El_Expt_Type вида An_Ordinary_Type_Declaration будет представлять определение типа выражения A + B.

Если мы применим Asis.Elements.Enclosing_Element для El_Var или El_Expr, то мы получим элемент, который представляет инструкцию присваивания.

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


3.4 Политика обработки ошибок ASIS

Только те исключения, которые определены в ASIS (и предопределенное исключение Ады Storage_Error) могут распространяться за пределы запросов ASIS. Исключения ASIS определены в пакете Asis.Exceptions.

При возбуждении исключения ASIS, ASIS устанавливает статус ошибки (возможные условия ошибки ASIS определены как значения типа Asis.Errors.Error_Kinds) и формирует строку диагностики. Приложение может опросить текущее значение статуса ошибки ASIS с помощью запроса Asis.Implementation.Status, а текущее содержимое строки диагностики с помощью запроса Asis.Implementation.Diagnosis. Кроме этого, приложение может переустанавливать содержимое статуса ошибки и строки диагностики с помощью процедуры Asis.Implementation.Set_Status.


3.5 Динамическая проверка допустимости запросов ASIS

ASIS имеет только один тип (Element) для всех видов синтаксических конструкций Ады, и только один тип (Compilation_Unit) для всех видов компилируемых модулей Ады. Однако, многие запросы, обрабатывающие элементы ASIS и модули компиляции ASIS. могут соответственно применяться только для определенных видов элементов ASIS и модулей компиляции ASIS (например, не имеет смысла и будет недопустимым запрос Assignment_Variable_Name для элемента, имеющего вид An_Ordinary_Type_Declaration).

ASIS является интерфейсом с динамической проверкой допустимости/корректности (dynamic validity checking interface). Если запрос обработки элемента обладает документированным списком элементов подходящего вида, то это подразумевает, что такой запрос может обрабатывать только те элементы чей вид указан в списке. При вызове подобных запросов для обработки элементов, вид которых не содержится в списке элементов подходящего вида, будет возбуждаться исключение Asis.Exceptions.ASIS_Inappropriate_Element со статусом ошибки Asis.Errors.Value_Error.

Если запрос обработки модуля компиляции обладает документированным списком модулей компиляции подходящего вида, то такой запрос может обрабатывать только те модули компиляции чей вид указан в списке. При вызове подобных запросов для обработки модулей компиляции, вид которых не содержится в списке модулей компиляции подходящего вида, будет возбуждаться исключение Asis.Exceptions.ASIS_Inappropriate_Compilation_Unit со статусом ошибки Asis.Errors.Value_Error.

Если запрос обладает докуменированным списком ожидаемых видов элементов или модулей компиляции, то, при вызове с любыми аргументами, такой запрос не будет возбуждать никаких исключений. Однако, возвращаемые подобным запросом результаты будут иметь смысл только для тех аргументов, вид которых указан в списке. Например, если запрос Asis.Elements.Statement_Kind вызван для аргумента с видом A_Declaration, то он просто вернет результат Not_A_Statement, не возбуждая при этом никаких исключений.


3.6 ASIS-итератор

ASIS предусматривает мощный механизм сканирования Ада-кода, обеспечиваемый настраиваемой процедурой Asis.Iterator.Traverse_Element. Эта процедура осуществляет сканирование дерева ASIS сверху-вниз слева-на-право (таким образом, синтаксические структуры Ада-кода представлены иерархией элементов ASIS). В направлении сканирования, эта процедура применяет к каждому элементу формальную процедуру Pre_Operation, когда впервые "посещает" элемент, и формальную процедуру Post_Operation, когда "покидает" элемент. Предусматривая свои собственные экземпляры процедур Pre_Operation и Post_Operation, пользователь имеет возможность автоматической обработки всех элементов ASIS, которые обнаружены в данном дереве ASIS.

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

    
    
        X := F (Y);
    

При вызове для элемента ASIS, который представляет показанную выше инструкцию, настроенный экземпляр Traverse_Element выполняет следующее (ниже, Pre_Op и Post_Op являются фактическими процедурами, которые указаны для формальных параметров настройки Pre_Operation и Post_Operation, а числа индицируют последовательность вызовов Pre_Op и Post_Op в процессе сканирования):

    
    
                 (1 Pre_Op)  X := F (Y) (10 Post_Op)
                                 |
                                 |
               -----------------------------------
               |                                 |
    (2 Pre_Op) X (3 Post_Op)                     |
                                                 |
                                    (4 Pre_Op) F(Y) (9 Post_Op)
                                                 |
                                                 |
                                    ---------------------------
                                    |                         |
                        (5 Pre_Op)  F (6 Post_Op)  (7 Pre_Op) Y (8 Post_Op)
    

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


3.7 Навигация по спецификации ASIS

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

  1. Используйте краткий обзор пакетов ASIS, который приводится в секции 3.2 Иерархия пакетов ASIS, чтобы ограничить поиски меньшим числом пакетов ASIS (например, если Вас интересует, что может быть выполнено с модулями компиляции Compilation_Units - следует ограничить поиски только пакетом Asis.Compilation_Units, если Вы ищете запросы, которые могут быть использованы для декомпозиции и анализа определений (declarations), ограничьте ваши поиски пакетом Asis.Declarations).

  2. Внутри пакетов ASIS, определенные виды (Asis.Declarations, Asis.Definitions, Asis.Statements, Asis.Expressions и ASIS.Clauses) запросов элементов ASIS упорядочены в соответствии с порядком описания соответствующих конструкций в RM 95 (например, пакет Asis.Statements начинается с запроса получения меток, а заканчивается запросом декомпозиции инструкции).

  3. Имена всех семантических запросов начинаются с Corresponding_... или Implicit_....

  4. Используйте ограничительные комментарии (comment sentinels), показанные в спецификации пакетов ASIS. Ограничительный комментарий вида "--|ER" (от "Element Reference") вводит новый вид элемента, и он сопровождается группой ограничительных комментариев вида "--|CR" (от "Child Reference"), которые перечисляют запросы вызывающие дочерние элементы для только что введенного элемента.


4. Контекст ASIS

4.1 Файлы контекста и дерева ASIS

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

В случае ASIS-для-GNAT, реализация ASIS базируется на генерируемых компилятором файлах деревьев (или просто - файлах деревьев). При запуске GNAT со специальной опцией (-gnatt), он создает и выводит файл дерева в случае, когда в процессе компиляции не было обнаружено ошибки. Файл дерева является своеобразным "снимком" внутренних структур данных компилятора (основанном на Абстрактном Синтаксическом Дереве (Abstract Syntax Tree, сокращенно - AST)), полученным в самом конце успешно выполненной компиляции. После этого, ASIS читает файл дерева и воссоздает свои внутренние структуры данных в соответствие с образом, который имел компилятор в самом конце соответствующей успешно выполненной компиляции.

Одним из важных следствий модели компиляции GNAT, которая основана на исходных текстах, является то, что AST содержит полную информацию не только об откомпилированном модуле, но также и обо всех модулях от которых этот модуль зависит семантически. Следовательно, обладая прочитанным файлом дерева, ASIS может предоставить информацию более чем об одном модуле. При обработке файла дерева, может быть представлена информация о модуле для которого это дерево было создано, а также обо всех модулях от которых этот модуль семантически зависим. Однако, для обработки нескольких модулей, ASIS, в некоторых случаях, должен изменять обрабатываемое дерево (в частности, когда приложение переключается между модулями, которые семантически не зависимы друг от друга). Следовательно, в ходе работы приложения ASIS, ASIS может читать различные файлы деревьев, и он может перечитывать один и тот же файл дерева несколько раз.

Имя файла дерева формируется из имени компилируемого файла с исходным текстом, путем замены суффикса на '.adt'. Например, файл дерева для foo.adb будет иметь имя foo.adt.


4.2 Создание файлов дерева для использования с ASIS

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

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

    
    
        gcc -c -gnatc -gnatt foo.adb
    

Показанная выше команда сгенерирует файл foo.adt, при этом подразумевается, что файл foo.adb содержит исходный текст допустимого компилируемого модуля Ады. Опция -gnatt указывает на необходимость генерации файла дерева, а опция -gnatc - отключает расширение дерева. ASIS использует файлы деревьев, которые созданы без расширения дерева, в то время как GNAT нуждается в расширенном AST, при создании объектных файлов. Следовательно, одновременная генерация файлов деревьев и объектных файлов - невозможна.

Следует помнить несколько важных моментов при генерации и работе с файлами деревьев:

  1. ASIS-для-GNAT поставляется для конкретной версии компилятора GNAT. Все деревья, которые будут обрабатываться приложением ASIS, должны генерироваться этой версией компилятора.

  2. При создании файла дерева для ASIS, используйте раздельное указание опций -gnatc и -gnatt. Не следует комбинировать их в одиночную опцию -gnatct или -gnattc, поскольку это приведет к генерации фиктивного объектного файла.

  3. Если в процессе компиляции была обнаружена ошибка, то файл дерева не будет создан.

  4. В отличие от объектных файлов, файл дерева может быть сгенерирован для любого допустимого компилируемого модуля Ады, включая описания библиотечных пакетов, которые требуют наличие тел и подчиненных модулей.

  5. Набор файлов деревьев, обрабатываемых ASIS (или приложением ASIS) может быть несогласованным. Например, два файла деревьев могут быть созданы при использовании разных версий исходного текста одного и того же модуля. Это приведет к несогласованностям в соответствующем контексте ASIS. За более подробными сведениями следует обратиться к секции 4.4 Проблема согласованности.

  6. Не перемещайте самостоятельно файлы деревьев, объектные файлы и файлы с исходными текстами по каталогам используемой файловой системы! Это мможет "запутать" ASIS, и он может обнаружить несогласованность между файлами деревьев и файлами с исходными текстами, при открытии контекста, или Вы можете получить плохой результат при запросе файла с исходными текстами или объектного файла для указанного модуля компиляции ASIS.

  7. При запуске gcc или gnatmake, для создания файлов деревьев, все имена файлов и каталогов, которые содержат информацию об относительных путях, должны начинаться с "./" или "../" (".\" и "..\" соответственно в Windows NT/95). Таким образом, для создания файла дерева для файла с исходным текстом foo.adb, который расположен во вложенном каталоге с именем "inner", необходимо запустить gcc с помощью команды:

      
      
           >gcc -c -gnatc -gnatt .\inner\foo.adb
      

    но не команды:

      
      
           >gcc -c -gnatc -gnatt inner\foo.ads
      

    иначе ASIS "запутается".

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

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

  10. Для файлов деревьев существует только одно расширение имени файла - .adt, в то время как стандартные соглашения GNAT по наименованию файлов с исходными текстами Ады используют различные расширения имен файлов для файлов спецификаций (.ads) и для файлов тел (.adb). Это подразумевает, что сначала, для получения дерева, Вы компилируете тело:

      
      
           >gcc -c -gnatc -gnatt foo.adb
      

    а затем - соответствующую спецификацию:

      
      
           >gcc -c -gnatc -gnatt foo.ads
      

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

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

    • если множество требующих обработки Ада-компонентов составляет законченный раздел программы, то следует использовать утилиту gnatmake (за подробностями обратитесь к секции 8.4 Использование gnatmake для создания файлов дерева);
    • в противном случае, сначала следует создать файлы деревьев для спецификаций, а затем - для тел:

        
        
               >gcc -c -gnatc -gnatt *.ads
               >gcc -c -gnatc -gnatt *.adb
        

  11. Чтение файлов деревьев является операцией, которая затратна по времени. Следует пытаться минимизировать число обрабатываемых приложением файлов деревьев и стараться избегать ненужных обменов деревьев. (См. главу 8. Как построить эффективное приложение ASIS).

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


4.2.1 Создание дерева для дополнения декомпозиции данных

Использование Дополнения Декомпозиции Данных ASIS (ASIS Data Decomposition Annex, сокращенно - DDA) не требует от пользователя ASIS выполнения каких-либо специальных действий, за исключением следующего. Реализация ASIS DDA базируется на некоторой специальной аннотации, которая добавляется компилятором к используемым ASIS деревьям. Пользователь ASIS должен позаботится о том факте, что деревья, которые созданы для подчиненных модулей, не обладают этой специальной аннотацией, следовательно запросы ASIS DDA не работают корректно на деревьях, которые созданы для подчиненных модулей (и такие запросы могут работать не корректно, когда набор файлов деревьев составляющих контекст содержит дерево, которое создано для подчиненного модуля).

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

Лучшим способом создания деревьев, при использовании ASIS DDA, является использование утилиты gnatmake - она никогда не будет создавать для подчиненных модулей отдельные деревья.


4.3 Различные способы определения контекста ASIS в ASIS-для-GNAT

Запрос Asis.Ada_Environments.Associate, который определяет контекст Context, имеет следующий профиль:

    
    
        procedure Associate
                     (The_Context : in out Asis.Context;
                      Name        : in     Wide_String;
                      Parameters  : in     Wide_String := Default_Parameters);
    

В ASIS-для-GNAT аргумент Name не обладает никаким специальным смыслом, а все свойства ассоциируемого контекста определяются установкой строки параметров Parameters.

При осуществлении ассоцоорования контекста ASIS, в ASIS-для-GNAT, Вы можете использовать в запросе Asis.Ada_Environments.Associate аргумент строки параметров Parameters для спецификации следующего:

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

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

Для определения набора файлов деревьев составляющих контекст Context возможно использование следующих опций:

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

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

Опциями по умолчанию являются -CA, -FT и -SA.

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

Использование опции -I, для определения контекста ASIS, подобно использованию опции -I при вызове GNAT. Опция -T используется аналогичным образом, но для файлов деревьев, подпробности использования опций -T и -I описываются в Справочном руководстве по ASIS-для-GNAT (IS-для-GNAT Reference Manual). Следует заметить, что опция -T используется только для поиска существующих файлов деревьев, и она не имеет эффекта для контекста -FS. С другой стороны, опция -I используется только для построения набора аргументов когда ASIS запускает GNAT для создания файлов деревьев "на лету". Опция -I не имеет эффекта для контекста -FT, и она не может быть использована для указания ASIS - где необходимо искать файлы с исходными текстами для модулей компиляции ASIS.


4.4 Проблема согласованности

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

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

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


4.4.1 Несогласованные версии ASIS и GNAT

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

Будьте внимательны при использовании в ваших приложениях ASIS обработчика исключений "when others": не используйте его с целью отлавливания не-ASIS исключений и подавления их без какого-либо анализа.


4.4.2 Согласованность набора деревьев и файлов с исходными текстами

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

При открытии контекста Context (запрос Asis.Ada_Environmens.Open), ASIS осуществляет следующие проверки для всех файлов деревьев, которые образуют контекст Context:

Если какая-либо из этих проверок неудачна, в результате попытки открытия контекста Context будет возбуждаться исключение Asis_Failed. Если контекст Context был успешно открыт, то это гарантирует, что ASIS будет обрабатывать согласованный набор файлов деревьев и объектных файлов, вплоть до закрытия контекста Context (учитывая это, набор этих файлов не должен быть изменен каким-либо внешним по отношению к ASIS действием).


4.5 Одновременная обработка нескольких контекстов

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


5. ASIS-интерпретатор asistant

5.1 Знакомство с asistant

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

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

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

Хотя asistant изначально является интерактивным средством, он также способен интерпретировать последовательности команд, которые записаны в файл (называемый далее скриптом). Также, asistant может сохранять в файле протокол (log) интерактивной сессии, который впоследствии может быть использован как скрипт-файл.

Полная документация к asistant содержится в руководстве пользователя asistant - "asistant Users' Guide" (файл asistant.ug в каталоге исходных текстов asistant). Здесь приводится только краткий обзор использования asistant.

Исполняемый модуль asistant создается в каталоге исходных текстов asistant, как часть процесса инсталляции ASIS-для-GNAT в качестве дополнительной Ада-библиотеки. Поместите этот исполняемый модуль в ваш путь поиска исполняемых файлов, а затем введите команду 'asistant', для запуска asistant в интерактивном режиме. В результате, программа выдаст о себе краткую информацию, а затем появится строка приглашения asistant '>'. Вцелом, это будет выглядеть следующим образом:

    
    
    ASIStant - ASIS Tester And iNTerpreter, v1.2
    (C) 1997-1999, Free Software Foundation, Inc.
      Asis Version: ASIS 2.0.R
    
    >
    

Теперь, пользователь может вводить команды asistant (в своем командном языке, asistant поддерживает такую же форму комментариев как и язык Ада, имена являются не зависимыми от регистра):

    
    
    >Initialize ("") -- Запрос инициализации ASIS вызывается с
                     -- пустой строкой в качестве параметра
    
    >set (Cont) --  Создание не-инициализированной переменной контекста Cont
                --  типа ASIS Context
    
    >Associate (Cont, "", "") --  Вызов запроса ассоциирования ASIS
                              --  с двумя пустыми строками, в качестве параметров,
                              --  для переменной контекста Cont
    
    >Open (Cont)  --  Вызов запроса ASIS Open для переменной контекста Cont
    
    >set (C_U, Compilation_Unit_Body ("Test", Cont)) --  Создание переменной
      --  модуля компиляции C_U типа ASIS Compilation_Unit и ее инициализация
      --  результатом вызова запроса ASIS Compilation_Unit_Body.
      --  В результате, C_U будет представлять компилируемый модуль
      --  с именем "Test", содержащийся в контексте ASIS именуемом Cont.
    
    >set (Unit, Unit_Declaration (C_U))  --  Создание переменной элемента Unit
      --  типа ASIS Element и ее инициализация результатом вызова запроса ASIS
      --  Unit_Declaration
    
    >print (Unit) --  в результате выполнения этой команды, ASIS отобразит
                  --  образ отладки текущего значения Unit:
    
    Element Debug_Image:
    A_PROCEDURE_BODY_DECLARATION
    located in Test (body, Unit_Id = 2, Context_Id = 1)
    text position : 1 : 1 - 9 : 7
       Nodes:
          Node            : 1363 - N_SUBPROGRAM_BODY
          R_Node          : 1363 - N_SUBPROGRAM_BODY
          Node_Field_1    : 0 - N_EMPTY
       Rel_Sloc           : -10
       obtained from the tree .\test.atb (Tree_Id = 1)
    
    --  предположим теперь, что мы делаем ошибку - мы вызываем запрос ASIS
    --  для не-подходящего элемента:
    
    >set (Elem, Assignment_Expression (Unit))
    
    --  ASIS возбудит исключение, и asistant отобразит отладочную информацию ASIS:
    
    Exception is raised by ASIS query ASSIGNMENT_EXPRESSION.
    Status : VALUE_ERROR
    Diagnosis :
    Inappropriate Element Kind in Asis.Statements.Assignment_Expression
    
    --  это не изменит состояния ни одной из существующих переменных,
    --  и asistant вновь запросит ввод команды пользователя:
    
    > ...
    


5.2 Команды asistant

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


5.3 Переменные asistant

Переменные asistant использую (простые) имена в стиле Ады. Переменные могут иметь любой тип ASIS, а также обычные целочисленные (integer), логические (boolean) и строковые (string) типы. Все переменные и их значения создаются и присваиваются динамически, путем использования команды Set. Предопределенные переменные отсутствуют.

В asistant отсутствует проверка типов: каждый вызов команды Set может рассматриваться как создание (заново) первого аргумента и его инициализация значением, которое предусматривается вторым аргументом.


5.4 Просмотр дерева ASIS

Визуализатор вызывается путем обращения к сервисной функции BROWSE. BROWSE блокирует интерпретатор команд asistant и активирует интерпретатор команд визуализатора. Команда визуализатора 'Q' осуществляет обратное переключение - к среде интерпретатора команд asistant, и блокирует интерпретатор команд визуализатора.

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

    
    
    > set (e0, Browse (e1))
    

он стартует визуализацию (отображение) дерева ASIS начиная с элемента e1, и при завершении визуализации, e0 будет представлять последний элемент, который был посещен в процессе визуализации.

Когда пользователь вводит команду:

    
    
    > Browse (e1)
    

он имеет возможность визуализировать дерево ASIS, но последний элемент визуализации будет отброшен.

Визуализатор отображает тот элемент ASIS, на который он в текущий момент указывает, и он ожидает одну из следующих клавишных команд:

Визуализатор немедленно интерпретирует клавишную команду и отображает новый текущий элемент. При этом возможны случаи появления сообщения "Cannot go in this direction.", которое подразумевает, что сканирование дерева ASIS в указанном направлении из текущего узла не возможно (то есть, текущий узел является терминальным элементом и перемещение вниз не возможно, или текущий узел является крайним левым или правым компонентом какого-либо элемента и перемещение влево или вправо не возможно, или текущий узел является самым верхним элементом объемлющей структуры модуля и перемещение вверх не возможно).

Существует возможность обращения к обычным запросам ASIS из визуализатора (например, к семантическим запросам). При этом, допустимыми запросами являются те запросы, которые принимают один параметр типа Element и возвращают элемент Element в качестве результата.

Когда пользователь нажимает пробел (<SPACE>), он запрашивает ввод имени запроса. Если запрос является допустимым, текущий элемент заменяется результатом вызова заданного запроса с текущим элементом в качестве параметра.


5.5 Пример

Предположим, что мы имеем компилируемый модуль ASIS - Demo, в файле с исходным текстом, чье имя - demo.adb:

    
    
        procedure Demo is
           function F (I : Integer) return Integer;
    
           function F (I : Integer) return Integer is
           begin
              return (I + 1);
           end F;
    
           N : Integer;
    
        begin
            N := F (3);
        end Demo;
    

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

    
    
    initialize ("")
    
    --  создание и открытие контекста, который формируется
    --  всеми файлами деревьев в текущем каталоге;
    
    Set (Cont)
    Associate (Cont, "", "")
    Open (Cont)
    
    --  получение из этого контекста Context модуля компиляции
    --  Compilation_Unit (тело) именуемого "Demo";
    Set (CU, Compilation_Unit_Body ("Demo", Cont))
    
    --  переход внутрь структуры модуля (в тело модуля)
    --  и установка на выражение в правой части инструкции присваивания:
    Set (Unit, Unit_Declaration (CU))
    Set (Stmts, Body_Statements (Unit, False))
    Set (Stmt, Stmts (1))
    Set (Expr, Assignment_Expression (Stmt))
    
    --  вывод образа отладки и текстового образа выражения:
    Print (Expr)
    Print (Element_Image (Expr))
    
    --  это выражение имеет вид A_Function_Call, таким образом, можно
    --  запросить описание вызываемой функции:
    Set (Corr_Caled_Fun, Corresponding_Called_Function (Expr))
    
    --  вывод образа отладки и текстового образа
    --  описания вызываемой функции:
    Print (Corr_Caled_Fun)
    Print (Element_Image (Corr_Caled_Fun))
    
    --  закрытие сессии asistant:
    Quit
    


6. Шаблоны приложений ASIS

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

Обратитесь к учебным примерам ASIS, которые предусматривают пример использования этих шаблонов.

Кроме того, дополнительная информация, о шаблонах приложений ASIS, содержится в файле README подкаталога 'templates'.


7. Учебные примеры ASIS

Подкаталог 'tutorial' дистрибутива ASIS содержит набор простых учебных примеров ASIS, которые могут быть полезны для знакомства с ASIS. Набор учебных примеров ASIS включает перечень простых задач, базирующихся на инструменте asistant и наборе шаблонов приложений ASIS, которые предоставлены как часть дистрибутива ASIS. Для всех простых задач предусматриваются законченные решения.

В настоящий момент, документация к учебным примерам существует как множество файлов README в подкаталоге 'tutorial' и его подкаталогах. В будущем эта документация будет перенесена в это руководство.


8. Как построить эффективное приложение ASIS

8.1 Обмен деревьев как причина плохой производительности приложения

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

В основном, существует две причины обмена деревьев:

  1. Обработка семантически независимых модулей. Предположим, что в контексте Cont существуют модули P и Q, которые не зависят друг от друга, и контекст Cont не содержит какого-либо третьего модуля, который зависит от обоих модулей P и Q. Это подразумевает, что P и Q не могут быть представлены одним и тем же деревом. Для получения некоторой информации о модуле P, ASIS нуждается в доступе к дереву p.adt, а для получения какой-либо информации о модуле Q, ASIS нуждается в доступе к дереву q.adt. Следовательно, когда приложение получило информацию от P, и затем стартует обработку Q, то ASIS должен прочитать дерево q.adt.

  2. Возможность присутствия одного и того же модуля более чем в одном дереве. Какой-либо модуль может быть представлен деревом, которое непосредственно создано для него самого, и он также может быть представлен всеми деревьями, созданными для модулей, которые семантически от него зависят. Предположим, что у нас есть библиотечная процедура Proc, которая зависит от библиотечного пакета Pack, и в наборе деревьев формирующих наш контекст Context мы имеем деревья pack.adt и proc.adt. Предположим, что в процессе доступа ASIS к дереву pack.adt мы получили какой-то элемент Element, представляющий какой-то компонент пакета Pack, а также предположим, что в процессе каких-либо других действий, выполняемых приложением, ASIS изменил дерево на proc.adt, которое доступно в текущий момент времени. Предположим теперь, что приложению необходимо выполнить какие-либо действия с элементом Element, представляющим какой-то компонент пакета Pack, полученным из дерева pack.adt. Хотя модуль Pack представлен доступным в текущий момент деревом proc.adt, ASIS должен переключиться обратно к дереву pack.adt, поскольку все ссылки в структуру дерева, сохраненные как часть значения элемента Element, допустимы только для дерева pack.adt.


8.2 Запросы которые могут вызвать обмен деревьев

В настоящее время, в ASIS-для-GNAT, обмен деревьев имеет место только при обработке запросов, которые описаны в:

    
    
        Asis.Elements
        Asis.Declarations
        Asis.Definitions
        Asis.Statements
        Asis.Clauses
        Asis.Expressions
        Asis.Text
    

за исключением запросов, которые возвращают результаты перечислимого или логического типов. Для любой конкретизации Asis.Iterator.Traverse_Element, сканирование, само по себе, может вызвать как минимум однократное чтение дерева для получения дерева, подходящего для обработки сканируемого элемента Element. Однако, процедуры, которые предусматриваются как фактические параметры настройки (для Pre_Operation и Post_Operation) могут также вызвать дополнительные обмены деревьев.


8.3 Как избежать ненужный обмен деревьев

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

  1. Следует пытаться минимизировать набор файлов деревьев, обрабатываемых приложением ASIS. В частности, старайтесь избегать наличия отдельных деревьев, которые созданы для подчиненных модулей.

    Минимизация набора файлов деревьев, обрабатываемых приложением ASIS, одновременно уменьшает время затрачиваемое на открытие контекста. Старайтесь использовать утилиту gnatmake для создания подходящего набора файлов деревьев Ада-программы.

  2. Выбирайте правильный способ определения контекста ядл вашего приложения. Например, используйте контекст, который формируется одним деревом (-C1), для приложений, которые ограничены обработкой одиночных модулей (подобных pretty printer или gnatstub). При обработке файла дерева, созданного для такого модуля, ASIS способен получить всю синтаксическую и семантическую информацию об этом модуле. При использовании определения контекста, который формируется одним деревом, приложение должно будет прочитать только один файл дерева, в процессе открытия контекста, и во время работы приложения не понадобится чтение других файлов деревьев. Контекст, формируемый из N деревьев, является естественным расширением для контекста, формируемого одним деревом, для приложений, которым в перспективе известно какие модули будут обрабатываться. При этом, однако, открытие контекста будет более длительным, и ASIS, в процессе работы приложения, может осуществлять обмен среди различных файлов деревьев. Используйте контекст, который формируется из всех файлов деревьев, только для тех приложений, которые не нацелены на обработку определенного модуля (или определенного набора модулей), а подразумевают обработку всех доступных модулей, или в случае, когда приложение должно обрабатывать большую систему, состояшую из большого количества модулей. При использовании приложения основанного на контексте, формируемом их всех деревьев, используйте описанный выше способ создания файлов деревьев, для минимизации набора файлов деревьев для обработки.

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

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

  5. Чтобы увидеть "профиль обмена деревьев" вашего приложения, следует при инициализации ASIS использовать отладочный флаг -dt (Asis.Implementation.Initialize ("-dt")). Полученная в результате выполнения приложения информация может подсказать Вам - как можно избежать обмена деревьев.


8.4 Использование gnatmake для создания файлов дерева

Для создания необходимого набора файлов деревьев, можно использовать утилиту gnatmake. GNAT создает файлы ALI при каждой успешной компиляции, вне зависимости от фактической генерации объектного кода. Следовательно, существует возможность запуска утилиты gnatmake (с опциями -gnatc и -gnatt) для создания набора файлов деревьев, представляющих все компилируемые модули, которые необходимы модулю, для компиляции которого была запущена gnatmake. Ниже мы будем использовать gnatmake для создания набора файлов деревьев законченной Ада-программы (раздела). Вы можете адаптировать подобный подход для неполной программы или для раздела без главной подпрограммы, применяя gnatmake для некоторых (группы) компонентов.

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

Существует два различных способа использования gnatmake для создания набора файлов деревьев.

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

    
    
       gnatmake -f -c ... main_subprogram.adb -cargs -gnatc -gnatt
    

или команды:

    
    
       gnatmake -f -c -gnatc -gnatt ... main_subprogram.adb
    

то это создаст деревья, которые представляют всю программу, для которой main_subprogram является главной процедурой. Все деревья будут созданы заново, то есть, если какие-либо файлы деревьев уже существовали, то они будут переписаны заново. Это вызвано тем, что gnatmake вызывается с указанием опции -f (force recompilation). Использование gnatmake, для создания файлов деревьев без указания опции -f, когда выши файлы деревьев располагаются в том же каталоге, что и объектные файлы - не является надежным, поскольку объектные файлы и файлы деревьев "разделяют" одно и то же множество файлов ALI, и в случае, когда объектный файл существует и согласован с файлом ALI и файлом исходного текста, исходный текст не будет перекомпилирован для создания файла дерева если опция -f не указана.

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

    
    
       gnatmake -c ... main_subprogram.adb -cargs -gnatc -gnatt
    

или команды:

    
    
       gnatmake -c -gnatc -gnatt ... main_subprogram.adb
    

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

Следующая секция описывает детали, которые характерны для компилируемых модулей Ады относящихся к прекомпилированным Ада-библиотекам.


9. Обработка Ада-библиотеки с помощью средств основанных на ASIS

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

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

  1. Когда при использовании инструментального средства нет необходимости в обработке компонентов Ада-библиотек, набор файлов деревьев для этого средства может быть создан с помощью запуска gnatmake без указания опции -a (это является обычным способом использования gnatmake). Когда инструментальное средство обнаруживает Compilation_Which, что представляет спецификацию какого-либо библиотечного модуля, и для которого запрос Asis.Compilation_Units.Is_Body_Required возвращает результат True, а запрос Asis.Compilation_Units.Corresponding_Body возвращает результат вида A_Nonexistent_Body, то инструментальное средство может сделать вывод, что этот библиотечный модуль принадлежит к какой-либо прекомпилированной Ада-библиотеке.

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

  3. Для фильтрации компонентов RTL, может быть использован запрос Asis.Compilation_units.Unit_Origin.


10. Компиляция, связывание и компоновка приложений с ASIS-для-GNAT

Если Вы инсталлировали ASIS-для-GNAT как Ада-библиотеку и добавили каталог, который содержит все исходные тексты, файлы ALI и библиотечные файлы к значениям переменных окружения ADA_INCLUDE_PATH и ADA_OBJECTS_PATH (что является рекомендуемым способом инсталляции ASIS-для-GNAT), Вам не понадобится указывать компилятору GNAT (то есть, для запуска gcc) и редактору связей gnatbind никаких дополнительных опций, специфичных для ASIS, при работе с вашими приложениями ASIS. Однако, при запуске компоновщика gnatlink, Вы должны предусматривать дополнительный параметр "-lasis":

    
    
       gnatlink my_application -lasis
    

При сипользовании gnatmake, Вы также должны предусматривать этот параметр компоновщика, когда запуск gnatmake предполагает последующий запуск gnatlink:

    
    
       gnatmake ... my_application -largs -lasis
    

Указание этого параметра для компоновщика не нужно, когда запуск gnatmake не создает исполняемый модуль:

    
    
       gnatmake -c ... my_application
    

Если Вы установили ASIS-для-GNAT без построения библиотеки library, то, при работе над кодом вашего приложения ASIS, Вы должны выполнить следующее:

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


11. Предупреждающие сообщения ASIS-для-GNAT

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

Также, ASIS-для-GNAT генерирует предупреждающие сообщения когда он рассматривает некоторые ситуации, возникающие в процессе обработки запросов ASIS, как потенциально ошибочные, а описание ASIS, в этом случае, не требует возбуждения исключения. Обычно подобными случаями являются случаи возникновения фактических или потенциальных проблем в функциональной части ASIS, которая определяется реализацией, такими как предоставление определяемых реализацией параметров для запросов Initialize, Finalizes и Associate, или при открытии контекста ASIS.

В ASIS-для-GNAT существуе три режима предупреждающих сообщений:

по умолчанию (default)
предупреждающие сообщения генерируются на стандартное устройство вывода ошибок (stderr);
подавление (suppress)
предупреждающие сообщения подавляются;
трактовать как ошибки (treat as error)
предупреждающие сообщения будут трактоваться как ошибки ASIS-для-GNAT: вместо посылки сообщения на стандартное устройство вывода ошибок, ASIS-для-GNAT возбуждает исключение Asis_Failed и преобразует предупреждающее сообщение в строку диагностики ASIS (ASIS Diagnosis string). Статус ошибки ASIS (ASIS Error Status) зависит от причины предупреждающего сообщения.

Режим предупреждающих сообщений ASIS-для-GNAT может быть установлен при инициализации реализации ASIS. Параметр "-ws" запроса Asis.Implementation.Initialize подавляет предупреждающие сообщения, а параметр "-we" - указывает на необходимость трактовать все предупреждающие сообщения как ошибки. После установки, режим предупреждающих сообщений остается одинаковым для всех обрабатываемых контекстов, вплоть до очистки реализации ASIS-для-GNAT.


12. Соглашения по наименованию файлов и пространство имен приложения

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

ASIS-для-GNAT включает полную спецификацию стандарта ASIS ISO/IEC 15291:1999 ASIS Standard.

Следующие дочерние пакеты (для пакета Asis) добавлены в ASIS-для-GNAT:

Все остальные компоненты реализации ASIS-для-GNAT принадлежат иерархии возглавляемой пакетом с именем A4G (производное от ASIS-for-GNAT) и имеют имена, начинающиеся с "A4G.".

Кроме того, ASIS-для-GNAT включает следующие компоненты GNAT, как часть реализации ASIS:

    
    
       Alloc
       Atree
       Casing
       Csets
       Debug
       Einfo
       Elists
       Fname
       Gnatvsn
       Hostparm
       Krunch
       Lib
         Lib-List
         Lib-Sort
       Namet
       Nlists
       Opt
       Output
       Repinfo
       Scans
       Sinfo
       Sinput
       Snames
       Stand
       Stringt
       Table
       Tree_In
       Tree_Io
       Types
       Uintp
       Uname
       Urealp
       Widechar
    

Таким образом, в своем приложении ASIS, Вы можете использовать для ваших Ада-компонентов любые имена, кроме: имен пакетов определенных в ASIS как имена интерфейсных пакетов ASIS (Asis.Extensions, Asis.Set_Get, Asis.Text.Set_Get), любых имен иерархии, возглавляемой пакетом A4G, и любых имен компонентов GNAT, список которых был показан выше.

Все файлы с исходными текстами Ады, формирующие реализацию ASIS для GNAT (включая компоненты GNAT, являющиеся частью ASIS-для-GNAT) следуют соглашениям GNAT по наименованию файлов без каких-либо усечений имен файлов (file name krunching).