Шпаргалка

Простейший ввод-вывод

  • Ada.Text_IO.Put_Line(«text»); — Вывод текстового сообщения на экран и перевод курсора в начало следующей строки.
  • Ada.Text_IO.Put(«text»); — Вывод текстового сообщения на экран.
  • Ada.Text_IO.New_Line; — перевод курсора в начало следующей строки.
  • Ada.Text_IO.Get_Immediate(); - считывает символ с клавиатуры, но не отображает его на экране (без эха)

[свернуть]
Целый тип

Объявление переменных целого типа:

x, y : Integer;
z : Integer := 5;

Основные операции, используемые с целыми числами: +, -, *, **, /, =, >, <, >=, <=, rem, mod.

Приведение числовых типов к типу IntegerInteger(Переменная_Числового_Типа);

Абсолютное значение (модуль) числа - команда abs(): abs(-1) = 1, abs(1) = 1...

[свернуть]
Ввод-вывод целых чисел

  • Ada.Integer_Text_IO.Get(); — Ввод числа с клавиатуры.
  • Ada.Integer_Text_IO.Put(); — Вывод числа на экран
  • Ada.Integer_Text_IO.Put(Item => X, Width => Len); — Вывод на экран с явным указанием полей для переменной и ширины для вывода.
  • Ada.Integer_Text_IO.Put(X, Len); — Вывод на экран с указанием переменной и ширины поля для вывода.
  • Ada.Text_IO.Put(Integer’image(X) & Integer’image(Y)); — Форматированный вывод нескольких переменных с использованием «текстового» вывода и преобразованием переменных целого типа в строку.

[свернуть]
Создание типов и подтипов целых чисел

  • subtype Название_Подтипа is Название_Родительского_Типа range Диапазон_значений; — создание подтипа.
  • type Название_Типа is New Название_Родительского_Типа range Диапазон_значений; — создание производного типа.
  • type A_Type range 1..100; — создание анонимного типа.
  • B : range 0..1000; — объявление целой переменной анонимного типа с диапазоном значений от 0 до 1000.

[свернуть]
Плавающий тип

  • В языке Ада существуют следующие предопределённые плавающие типы: Float, Long_Float, Long_Long_Float.
  • Общее описание плавающего типа (в квадратных скобках приведены необязательные элементы):

type Т is digits D [range L .. R];

  • Определение плавающего типа Float:
type Float is digits 6 range -16#0.FFFF_FF#E+32 .. 16#0.FFFF_FF#E+32; -- -3.40282E+38 ..  3.40282E+38
  • Float'Floor(); - это округление вниз, то есть, если число положительное, то округление произойдёт до предыдущего целого числа, а если отрицательное - то до следующего целого.
  • Float'Rounding(); - округление числа по правилам математики.

[свернуть]
Ввод-вывод плавающих чисел

  • Get(X); — Ввод числа плавающего типа с клавиатуры.
  • Put(Item => X, [Fore => Num_1, Aft => Num_2, Exp => Num_3]); — Вывод числа плавающего типа на экран

где

  • Item — это само выводимое число.
  • Fore — количество цифр до точки (если указать их количество меньше, чем содержится в самом числе, то поле Fore будет автоматически расширено до нужной ширины)
  • Aft — количество цифр, выводимых после точки.
  • Exp — экспоненциальное представление числа (если 0, то вывод будет в обычной форме)
  • В квадратных скобках представлены необязательные поля.

[свернуть]
Создание типов и подтипов плавающих чисел

type COEFFICIENT is digits 10 range -1.0 .. 1.0; --создается тип COEFFICIENT, точность которого 10
                                                 --цифр после точки, диапазон значений от -1.0 до 1.0
type REAL is digits 8; --создается тип REAL, с точностью 8 цифр после точки, диапазон значений не указан
type MASS is digits 7 range 0.0 .. 1.0E35;
subtype SHORTCOEFF is COEFFICIENT digits 5;   --подтип SHORTCOEFF типа COEFFICIENT с  меньшей точностью
subtype PROBABILITY is REAL range 0.0 .. 1.0; --подтип типа REAL

[свернуть]
Фиксированный тип. Создание типов и подтипов

Общее описание фиксированного типа выглядит так: type T is delta D range L .. R

Для работы с данными фиксированного типа в Аде существует предопределенный вещественный тип с фиксированной точкой Duration:

type Duration is delta 0.000000001 range -((263 - 1) * 0.000000001) .. +((263 - 1) * 0.000000001);

Можно создавать типы и подтипы для данных фиксированного типа:

type VOLT is delta 0.125 range 0.0 .. 255.0;   --погрешность - 0.125
subtype ROUGH_VOLTAGE is VOLT delta 1.0;       --диапазон, как у VOLT, погрешность - 1.0

[свернуть]
Ввод-вывод переменных фиксированного типа

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

type myFixType is Delta 0.01 range 0.0..10_000.0;
...
--Создаем пакет для работы с нашим типом
package myFixType_IO is new Ada.Text_IO.Fixed_IO(myFixType)
...
--Вывод на экран
myFixType_IO.Put(...);
--Ввод с клавиатуры
myFixType_IO.Get()

[свернуть]
Символьный тип

Тип Character используется для работы с простыми символами (ASCII, не Unicode);

Переменные типа Character объявляются следующим образом:

  • ch : Character := 'a';
  • Num : Character := '1'

Некоторые атрибуты типа Character:

  • Character'Pos(ch) — возвращает код символа, содержащегося в переменной ch
  • Character'Val('97') — возвращает символ, соответствующий коду, переданному в качестве параметра функции

Is_Digit() - проверяет, является ли функция числом.

To_Upper() - преобразует символ к верхнему регистру.

To_Lower() - преобразует символ к нижнему регистру.

[свернуть]
Ввод-вывод переменных символьного типа

Пусть есть переменная ch типа Character и переменная More типа Boolean:

ch : Character;
More : Boolean;
  • Put(ch); — вывод символа на экран.
  • Get(ch); — считывание символа с клавиатуры.
  • Get_Immediate(ch); — считывание символа с клавиатуры без эха, т.е. символ будет считан в переменную ch сразу, без отображения на экране, не дожидаясь нажатия клавиши <Enter>. Эта функция работает как в Windows, так и в Linux.
  • Get_Immediate(ch, More); - Если была нажата служебная клавиша (код которой состоит из нескольких чисел), то в буфере клавиатуры после первого Get_Immediate (см. выше) останется "хвост". Для проверки его наличия используется процедура Get_Immediate с двумя переменными. Если буфер клавиатуры не пуст (т.е. хвост есть), то More будет True. Таким образом можно обработать нажатие служебной клавиши.

[свернуть]
Строки String

Для работы с простыми строками в  Аде используется тип String:

  • with Ada.Strings; use Ada.Strings;

Переменные типа String объявляются следующим образом:

  • str_1 : String(1..10); — под переменную str выделяется 10 символов. Сейчас строка str_1 заполнена «мусором»
  • str_2 : String := «hello!»; — Границы строки не задаются, т.к. её длина определена при инициализации.
  • str_1 : String(1..10) := (others => 'a'); — Вся строка сразу же заполняется символами 'a'.

Узнать длину строки можно с помощью атрибута String’Length. Он покажет сколько всего символов может вместить строка.

Строки можно сравнивать: str_1 = str_2. Можно сравнивать между собой участки строк (т.н. срезы), например: str_1(1..4) = str_2(5..8). Также можно присвоить одну строку другой: str_1 := str_2. При этом строки должны быть одной длины. Также можно присваивать участок одной строки участку другой: str_1(1..2) = str_2(3..4).

Строки можно соединять. Например, пусть у нас есть строка str_1 длиной 10 символов и строка str_2длиной 5 символов. Пусть строка str_1 содержит 5 символов. Тогда для присоединения строки str_2 к строке str_1 можно использовать оператор запись: str_1 := str_1(1..5) & str_2; т.е. оператор & — это оператор конкатенации («склеивания» строк). При этом нужно помнить, что в итоговой строке должно быть достаточно места для того, чтобы вместить обе "склеиваемые" строки.

Преобразование строки к целому типу:

n : Integer := Integer'Value("2345");

После этого переменная n будет иметь значение 2345.

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

if name_len = name'Last then --Здесь name_len - это количество реально прочитанных символов, а атрибут
                             --name'Last содержит количество символов, выделенных под строку
	Skip_Line;               --Отбросить остаток ввода
end if;

[свернуть]
Ввод вывод строк String

Для ввода строки с клавиатуры используется функция Get_Line(name, name_len) где name - переменная типа String, в которую считывается строка, а name_len - переменная типа Integer, в которую записывается количество прочитанных символов.

Для вывода строки используются функции Put() и Put_Line(). При этом следует использовать срезы, т.к. будет выведена вся строка, и если она при вводе была заполнена не полностью, то остаток будет содержать мусор:

  • Put(str(1..str_len)); - str_len - переменная типа Integer, которая содержит реально прочитанное функцией Get_Line(str, str_len) число символов. То есть, здесь строка str будет выводится с первого символа и до символа с номером str_len.

[свернуть]
Строки неопределенной длины Unbounded_String

Для работы со строками неопределённой длины (Unbounded_String) используется пакет Ada.Strings.Unbounded:

  • with Ada.Strings.Unbounded;

* Объявление строк Unbounded_String::

  • Str1 : Ada.Strings.Unbounded.Unbounded_String; - полная запись (т.е. если не используется use Ada.Strings.Unbounded_String)
  • Str2 : Unbounded_String; - если используется use Ada.Strings.Unbounded_String;

* Преобразование типов String и Unbounded_String: Для преобразования обычной строки String к Unbounded_String используется функция To_Unbounded_String(); Для обратного преобразования используется функция To_String():

--Преобразование к Unbounded_String:
ustr : Ada.Strings.Unbounded.Unbounded_String := Ada.Strings.Unbounded.To_Unbounded_String("Hello, all!");
--Преобразование к String:
str : String := Ada.Strings.Unbounded.To_String(ustr);

Длина строки: функция  Ada.Strings.Unbounded.Length(S); возвращает длину строки Unbounded_String.

* Сравнение строк Unbounded_String: Если Вы хотите сравнивать строки Unbounded_String друг с другом, то для того, чтобы использовать знак равенства ('=') в операциях сравнения нужно либо прописать использование пакета Ada.Strings.Unbounded через use:

with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;

так как по умолчанию компилятор будет брать оператор сравнения для строк String и ругаться, либо оператор '=' можно использовать так:

Ada.Strings.Unbounded."="(str_1, str_2);

Пример:

with Ada.Strings.Unbounded;
with Ada.Text_IO.Unbounded_IO;
 
procedure main is
    ustr : Ada.Strings.Unbounded.Unbounded_String := Ada.Strings.Unbounded.To_Unbounded_String("Hello, all!");
    str : String := Ada.Strings.Unbounded.To_String(ustr);
begin
    Ada.Text_IO.Unbounded_IO.Get_Line(Item => ustr);
    if Ada.Strings.Unbounded."="(ustr,Ada.Strings.Unbounded.To_Unbounded_String("Hello, world!")) then
        Ada.Text_IO.Unbounded_IO.Put_Line(ustr);
    end if;
end main;

[свернуть]
Ввод-вывод Unbounded_String

Пусть есть строка Unbounded_String:

USTR : Ada.Strings.Unbounded.Unbounded_String;

1. Ввод-вывод строк Unbounded можно осуществлять как с помощью пакета Ada.Text_IO, с предварительным преобразованием типа Unbounded_String к типу String (Get(), Put(), Put_Line()):

  • USTR := Ada.Text_IO.Unbounded.To_Unbounded_String(Ada.Text_IO.Get_Line); --Получить строку. Ada.Text_IO.Get_Line считывает обычную строку, а Ada.Text_IO.Unbounded_String.To_Unbounded_String преобразует её к типу Unbounded_String.
  • Ada.Text_IO.Put(Ada.Text_IO.Unbounded.To_String(USTR); --Вывод строки USTR, с её предварительным преобразованием к типу String.

2. Также для операций ввода-вывода строк типа Unbounded можно использовать пакет Ada.Text_IO.Unbounded_IO Он предоставляет подпрограммы Get_Line(), Put(), Put_Line() для обработки строк неопределённой длины: with Ada.Text_IO.Unbounded_IO;

USTR : Ada.Strings.Unbounded.Unbounded_String;
...
--ФУНКЦИЯ Get_Line считывает строку в переменную USTR (До нажатия Enter):
USTR := Ada.Text_IO.Unbounded_IO.Get_Line;
--ПРОЦЕДУРА Get_Line считывает строку в переменную USTR (До нажатия Enter):
Ada.Text_IO.Unbounded_IO.Get_Line(USTR);
--Вывод на экран строки USTR (правильнее сказать содержимое переменной USTR)
Ada.Text_IO.Unbounded_IO.Put_Line(USTR); --аналогично можно использовать Put()

[свернуть]
Массив строк Unbounded_String

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

type Week is array(1..N) of UStr.Unbounded_String; --Массив строк неопределённой длины
weekday : Week;
...
--Заполнение массива строк
weekday := (Ustr.To_Unbounded_String("Понедельник"),
			Ustr.To_Unbounded_String("Вторник"),
			Ustr.To_Unbounded_String("Среда"),
			Ustr.To_Unbounded_String("Четверг"),
			Ustr.To_Unbounded_String("Пятница"),
			Ustr.To_Unbounded_String("Суббота"),
			Ustr.To_Unbounded_String("Воскресенье")
			);

[свернуть]
Условный оператор if

if Условие_1 then
        Действие_1
elsif Условие_2 then
        Действие_2
else
        Действие_3
end if;

[свернуть]
Оператор выбора case

case Y is
	when -1 => Действие/я_1;     --Если Y = -1, то выполнить действие/я_1
	when 0 | 1 => Действие/я_2;  --Если Y = 0 или Y = 1, то выполнить действие/я_2
	when 2..10 => Действие/я_3;  --Если Y лежит в диапазоне от 2 до 10, то выполнить действие/я_3
	when others => Действие/я_4; --Во всех остальных случаях выполнить действие/я_4
end case;

[свернуть]
Алгоритм обмена переменных местами (обмен значениями)

a, b, tmp : Integer;
a := 3;
b := 5;
tmp := a;     --Теперь tmp = 3 и a = 3
a := b;       --Теперь a = 5 и b = 5;
b := tmp;     --Теперь b = 3

[свернуть]
Задержка выполнения действий

Оператор delay позволяет установить задержку при выполнении каких-то действий:

  • delay 0.5; --Задержка вывода 0,5 сек.

[свернуть]
Генератор случайных чисел (Discrete_Random)

Для использования генератора случайных чисел нужны следующие шаги:

with Ada.Numerics.Discrete_Random; --Будем использовать генератор случайных чисел
...
    package ANDR is new Ada.Numerics.Discrete_Random(Integer); --Дженерик (создаем пакет для генерации переменной типа Integer)
    ...
    num: Integer;
    g : ANDR.generator; --Объявляем генератор
    ...
begin
    ...
    ANDR.reset(g); --Запуск генератора случайных чисел
    num := ANDR.random(g); --Непосредственно генерация числа
    ...

Вместо Integer можно создать свой тип со своими ограничениями и использовать его.

[свернуть]
Обработка нажатия клавиши Backspace

--Обработка Backspace. Что такое BS и DEL cм. объяснение в блоке "Пакеты"
if ch = Character'Val(BS) or ch = Character'Val(DEL) then
	Put(BS); --Возвращаемся по строке на одну позицию назад
	Put(' '); --Затираем текущий символ пробелом
	Put(BS); --Снова возвращаемся на одну позицию назад
end if;

[свернуть]
Циклы. Метки циклов. Выход из цикла

Создание простейших циклов:

loop
    exit when <проверка условия выхода из цикла>
end loop;

Цикл while:

while <Условие> loop;    --Пока выполняется условие,
    <Действия>           --Совершать заданные действия
end loop;

 Циклы можно помечать метками:

LOOP_MAIN: while <Условие> loop
               <Действия>
           end loop;

Выход из цикла:

exit без уточнений, выход из самого внутреннего цикла, содержащего этот оператор
exit L выход из цикла, помеченного L
exit when condition выход из самого внутреннего цикла при выполнении условия condition
exit L when condition выход из цикла L при выполнении условия condition

Например:

L_ONE: while <Условие> loop
L_TWO:     while <Условие> loop
               <Действия>
               --Выход из внешнего цикла при выполнении <Условия_Выхода>
               exit L_ONE when <Условие_Выхода>;
           end loop;
       end loop;

Цикл for:

For i in 1..10 loop
	<Действия>
end loop;

Перебор элементов в обратном порядке:

for i in reverse 1..10 loop
...
end loop;

[свернуть]

Одномерные массивы

  • Одномерный массив (вектор) - это участок памяти (которому присвоено имя), который содержит несколько переменных одного типа, расположенных последовательно, одна за другой. Для создания массива в Аде используется ключевое слово array:
array(1..100) of Integer; --Объявлен массив с индексами от 1 до 100, который может содержать
                          --максимум 100 чисел типа Integer
  • В Аде для работы с массивом принято сначала создать тип этого массива, а затем уже объявлять переменные (массивы) этого типа:
...
procedure main is
	type VECTOR is array(1..5) of Integer; --Создание типа VECTOR, который определяет массивы с 5 элементами
	V, W : VECTOR;                         --Объявление двух массивов типа VECTOR
begin
...
end main;
  • В Аде можно работать как с целым массивом, так и с каждым элементом массива отдельно, а также можно использовать так называемые непозиционные составные значения (задание элементов массива с помощью диапазона индексов (вырезки или срезы)):
	V(6..10) := (0,0,0,0,0);      --Присвоить срезу с 6 по 10 элемент значение 0
	V(16..20) := V(6..10);        --Присвоить один срез другому

Некоторые атрибуты одномерного массива:

V'Last   -- последний элемент массива V
V'First  -- первый элемент массива V
V'Length -- Число элементов массива V
V'Range  -- Размерность массива (границы, фактически то же, что и V'First..F'Last)

[свернуть]

Двумерные массивы

Объявление типа двумерного массива:

type Matrix is array(1..N, 1..M) of Integer;

Двумерные массивы поддерживают работу со срезами (вырезками): пусть V — одномерный массив (вектор), а M — двумерный массив (матрица). Тогда, например, в результате операции:

V(5..9) := M(2)(6..10);

элементы 2 строки матрицы с индекса 6 по индекс 10 будут равны элементам вектора с индекса 5 по индекс 9. Срез по столбцам таким образом получить нельзя.

Некоторые атрибуты многомерных массивов:

Matrix'First(I)  --нижняя граница I-го индекса для типа Matrix.
                 --В случае двумерного массива I = 1 будет означать строку, I = 2 - столбец
Matrix'Last(I)   --верхняя граница I-го индекса для типа Matrix.
Matrix'Range(I)  --размерность I-го индекса (1 - строки, 2 - столбца) для типа Matrix.
Matrix'Length(I) --длина по I-му индексу для типа Matrix.

[свернуть]
Массивы с неуточненными границами

type Index is range 1..100;
type Vector is array(Index) of Integer;
V1 : Vector(1..100);
V2 : Vector(1..10);
  • Если размер массива становится известным только в ходе выполнения программы, тогда его можно объявить в теле программы используя блок declare... begin... end; При объявлении типа такого массива используется конструкция:
type Vector is array(Integer range <>) of Integer;

Выражение в скобках указывает на то, что размер массива изначально неизвестен.

  • Объявление двумерного массива с неуточнёнными границами:
type N is range 1..10;
type M is range 1..20;
type Matrix is array(1..N, 1..M) of Integer;

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

type Matrix is array(Integer range <>, Integer range <>) of Integer;

[свернуть]
Объявление переменных в теле программы: declare

declare
    X : Integer;
begin
    X := ...
    ...
end;

Таким образом можно объявить любую переменную не в блоке объявления переменных (между is и begin), а в любом месте программы. Единственное ограничение - переменная не будет видна вне блока declare.

[свернуть]
Логический тип Boolean

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

X : Boolean := True;
Y : Boolean := False;

[свернуть]
Перечисления

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

type Days_Of_Week is(Mon, Tue, Wen, Thu, Fri, Sat, Sun)

Таким образом, переменные этого типа могут принимать только те значения, которые указаны в скобках (от Mon до Sun).

[свернуть]
Подпрограммы

Подпрограммы в Аде делятся на процедуры (procedure) и функции (function). Procedure - объявление процедуры, function - объявление функции.

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

function Num(a, b : Integer) return integer is
	res : Integer;
begin
	res := a * a + b * b;
	return res;
end Num;

При этом вызов функции будет выглядеть, например, так: Integer n := Num(5, 3);

При использовании процедуры для каждого её параметра нужно указать вид связи. Видов связи всего три: in, out, in out

  • in означает, что переменную можно использовать в операциях, но нельзя изменять её значение.
  • out означает, что можно изменить значение переменной, но использовать её в операциях нельзя. При этом после выхода из процедуры переменная будет содержать новое значение.
  • in out означает, что с переменной можно делать всё, что угодно.
procedure Change(a, b : in out Integer) is...

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

Для прерывания любой подпрограммы (процедур или функции) служит оператор return без параметров.

[свернуть]
Родовые подпрограммы (обобщённые). Дженерик

Родовые (обобщённые) подпрограммы - аналог шаблонов (templates) в других языках программирования. Их параметры представляют собой переменные любого типа. Эти подпрограммы нельзя использовать напрямую, он используются в качестве шаблонов для создания подпрограмм под определённые типы данных:

generic
	type T is private;
procedure Change(a, b : in out T) ;
 
procedure Change(a, b : in out T) is
	tmp : T;
	begin
	tmp := a;
	b := a;
	a := tmp;
end Change;

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

generic
	type T is private;

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

Для вызова такой процедуры её предварительно нужно конкретизировать:

procedure Change_Integer is new Change(Integer);
procedure Change_Float is new Change(Float);

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

При конкретизации можно для всех процедур задать одно и то же имя. Единственное условие – это имя не должно совпадать с именем родовой подпрограммы:

procedure New_Change is new Change(Integer);
procedure New_Change is new Change(Float);

[свернуть]
Текстовые файлы

  • My_File : File_Type; - Объявление файла
  • Ada.Text_IO.Create(File => File_Type, Mode => <Режим_доступа>, Name => "Имя_Файла"); - Создание файла
  • Ada.Text_IO.Open(File => File_Type, Mode => <Режим_доступа>, Name => "Имя_Файла"); - Открытие файла
  • Ada.Text_IO.Close(File_Type); - Закрытие файла
  • Ada.Text_IO.Delete(File_Type); - Удаление файла. При этом файл будет удален и связанная с ним переменная обнулена.
  • Ada.Text_IO.Reset(File_Type); - Возвращает позицию чтения (или записи) в начало файла.
  • Ada.Text_IO.Reset(File_Type, File_Mode); - Возвращает позицию чтения (или записи) в начало файла и переустанавливает режим (фактически это переоткрытие файла в другом режиме).
  • Ada.Directories.Delete_File(Name => "Имя_Файла"); - Удаление файла по его имени.
  • Ada.Directories.Rename(Old_Name => "Текущее имя файла", New_Name => "Новое имя файла"); - Переименование файла

Режимы доступа

  • In_File - чтение файла
  • Out_File - запись в файл
  • Append_File - запись в конец файла

Основные функции, возвращающие статус файла:

  • End_of_File - Возвращает True если курсор находится в конце текущего файла.
  • End_of_Line - Возвращает True если курсор находится в конце обрабатываемой строки текста.
  • Is_Open - Возвращает True если текущий файл открыт.
  • Mode - Возвращает режим использования файла.
  • Name - Возвращает имя файла.
  • Line - Возвращает номер текущей строки в файле (в которой находится курсор), который в данный момент обрабатывается.

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

[свернуть]
Файловый ввод-вывод

  • Get_Line(File => File_Type, Item => String/Unbounded_String, Last: Natural); - считывание строки в переменную String из файла File_Type. Переменная Last содержит количество прочитанных символов.
  • str : String := Get_Line(File => File_Type); - одновременное создание строковой переменной и считывание в неё строки из файла.
  • Get(File => File_Type, Item => Character); - считывание символьной переменной
  • Put_Line(File => Num_File, Item => String/Unbounded_String/Character); - Запись строковой или символьной переменой в файл с переходом на новую строку.
  • Ada.Text_IO.Put(File => Num_File, Item => String/Unbounded_String/Character); - Запись строковой или символьной переменой в файл без перехода на новую строку.

[свернуть]
Бинарные файлы

Для файловых операций (чтение и запись) со сложными типами данных в Аде предназначены два пакета: Ada.Sequential_IO и Ada.Direct_IO. Они отличаются тем, что Ada.Direct_IO позволяет получить доступ к конкретной записи внутри файла по индексу, а Ada.Sequential_IO обращается к файлу последовательно. Плюс Ada.Direct_IO добавляет режим доступа к файлу InOut_File - режим чтения и записи. То есть, можно одновременно считывать информацию из файла и записывать информацию в файл Оба пакета похожи на Ada.Text_IO, но операции Get и Put заменены на Read и Write соответственно, а также отсутствуют подпрограммы End_Of_Line, Skip_Line и New_Line. Единственное условие использования этих пакетов - все переменные, используемые внутри нашего составного типа (записи) должны быть конечны. Т.е. типы вроде Unbounded_String не работают.

Пусть есть запись:

type Student is Record
    Name : String(1..25); --Имя студента
    Name_Len : Integer; --Длина имени (см. работу со строками)
    Sex : Character; --Пол
    Age : Integer range 1..100; --Возраст
end Record;

Ada.Sequential_IO: 

--"Создание" пакета для файлового ввода-вывода переменных типа Student
package Seq_IO is new Ada.Sequential_IO (Student);
--Создание трех переменных типа Student для записи их в файл
St_1, St_2, St_3 : Student;
--Создание переменной для чтения данных из файла.
tmp : Student;
--Файл, для работы с пакетом Sequential_IO;
My_File : Seq_IO.File_Type;
...
--Создание файла в режиме записи
Seq_IO.Create(File => My_File, Mode => Seq_IO.Out_File, Name => "records.dat");
--запись трех переменных в файл
Seq_IO.Write(My_File, St_1);
Seq_IO.Write(My_File, St_2);
Seq_IO.Write(My_File, St_3);
--Перематываем файл в начало и меняем режим на "чтение"
Seq_IO.Reset(My_File, Mode => Seq_IO.In_File);
--Seq_IO может считывать переменные только последовательно, одну за одной
--т.е. сначала St_1, затем St_2 и только после этого St_3
Seq_IO.Read(My_File, St_1);
--Закрытие файла
Seq_IO.Close(My_File);

Ada.Direct_IO (Пусть информация в файл уже записана, см. предыдущий пример):

--"Создание" пакета для файлового ввода-вывода переменных типа Student
package Dir_IO is new Ada.Direct_IO (Student);
--Создание переменной для чтения данных из файла.
tmp : Student;
--Файл, для работы с пакетом Direct_IO;
My_File : Dir_IO.File_Type;
...
--Открываем файл для чтения и записи
Dir_IO.Open(File => My_File, Mode => Dir_IO.InOut_File, Name => "records.dat");
--Пусть нам нужно прочитать вторую запись из файла (не затрагивая первую)
--Высчитываем размер одной записи и устанавливаем курсор на нужную нам запись
Dir_IO.Set_Index(File => My_File, To => Dir_IO.Positive_Count(2)); 
--Считываем вторую запись (в данном случае это информация о Петре Петрове)
Dir_IO.Read(My_File, tmp);
...Обработка полученной переменной...
--Опять переносим курсор на вторую запись
Dir_IO.Set_Index(File => My_File, To => Dir_IO.Positive_Count(2));
--и записываем её в файл
Dir_IO.Write(My_File, tmp);
--закрыть файл
Dir_IO.Close(My_File);

[свернуть]
Пакеты

Пакеты позволяют объединить какие-то логически связанные элементы и повторно использовать однажды написанный код. В программе пакеты подключаются с помощью ключевых слов with и use (использование use не обязательно, но тогда для доступа к элементам пакета нужно будет использовать оператор 'точка': Имя_Пакета.Элемент_Пакета.

Пакет состоит из двух файлов с одинаковыми названиями, но разными расширениями (ads и adb). Например, my_pack.ads  и my_pack.adb

В файле *.ads объявляются типы и подпрограммы, а в файле *.adb реализуются подпрограммы:

Файл my_pack.ads:

package My_Pack is --имя пакета совпадает с именем файла (кроме расширения)
    type Short is new Integer range 0..100; --Объявляется тип Short
    function Add(a, b : in Short) return Short; --Объявляется функция Add
end my_pack;

Файл my_pack.adb:

package body My_Pack is
    --Реализация функции Add
    function Add(a : in Short; b : in Short) return Short is
        c : Short;
    begin
        c := a + b;
        return c;
    end Add;
begin
    NULL;
end My_Pack;

В основном фале пакет my_pack подключается так: with my_pack; use my_pack;

[свернуть]
Приватные типы

Объявление приватного типа (ну и заодно константы этого типа):

package My_Pack is
    type Short is private; --Тип объявлен как приватный. Он будет реализован в приватной части пакета
    N : constant Short; --Объявлена константа, но значение ей не присвоено
    function Add(a, b : in Short) return Short;
private --Приватная часть пакета
    type Short is new Integer range 0..100;
    N : constant Short := 10; --Константе присвоено значение
end My_Pack;

Таким образом, мы ограничили операции над типом Short только функцией Add(), а также операциями присваивания (:=) и равенства (=), которые определяются по умолчанию. Для того, чтобы исключить из списка операций присваивание (:=) и равенство (=), тип Short нужно объявить не как private, а как limited private(ограниченный приватный):

type Short is limited private;

[свернуть]
Записи

Для хранения нескольких логически связанных друг с другом переменных в одной переменной используются "Записи":

type Pupil is Record --Объявление записи Pupil
    Name: String(1..25); --Имя
    Surname: String(1..25); --Фамилия
    Patronymic: String(1..30); --Отчество
    Age : Integer; --Возраст
    Sex : Character; --Пол (мужской/женский)
end Record;
...
Person : Pupil; --Объявление переменной типа Pupil

Доступ к полям этой записи осуществляется с помощью точки:

Person.Name := "Иван";
Person.Surname := "Иванов";
Person.Patronymic := "Иванович";
Person.Age := "20";
Person.Sex := "M";

Можно создать массив записей:

type Vector is array(1..10_000) of Pupil;
mas : Vector;

[свернуть]
Предопределённые пакеты

  • Ada.Numerics.Elementary_Functions - Содержит подпрограммы для выполнения простейших математических операций (синус, косинус, тангенс, котангенс, логарифм, возведение в степень, корень, арксинус, арккосинус и т.д.). Работает только с типом Float.
  • Ada.Numerics.Generic_Elementary_Functions - Дженерик. На его основе генерируются пакеты, позволяющие использовать простейшие математические функции пакета Ada.Numerics.Elementary_Functions для любых типов данных:
    with Ada.Numerics.Generic_Elementary_Functions; --Подключаем пакет (дженерик)
    ...
    package LF_Math is new Ada.Numerics.Generic_Elementary_Functions (Long_Float); --Создаём на основе
                                             --дженерика новый пакет, который будет содержать описание
                                             --и реализацию команд для работы с типом Long_Float. Вместо
                                             --LF_Math можно использовать любое другое имя
    use LF_Math;                             --Сообщаем компилятору, что реализацию математических команд
                                             --для работы с типом Long_Float нужно смотреть в пакете
                                             --LF_Math. Если эту строку исключить, то далее в тексте
                                             --программы перед каждой математической командой, связанной
                                             --с типом Long_Float, нужно будет писать "LF_Math.", например,
                                             --LF_MATH.Sqrt(X);
  • Ada.Characters.Latin_1 - Содержит коды символов. Например,  BS - 8 (Backspase), DEL - 127, LF - 10 (Перевод строки), CR - 13 (Возврат каретки). необходимо помнить, что клавиша Backspace в Unix-системах имеет код 127, а в Dos/Windows - 8, (на код 127 в Windows обычно "вешают" кнопку "home") поэтому для обработки нажатия клавиши Backspace код для этих систем немного различается. Подробнее об этом можно прочитать в Википедии. Да и обработка Enter тоже отличается: 13 для Windows и 10 для Unix-like систем. Для написания кроссплатформенной программы необходимо учитывать этот факт.
  • Ada.Characters.Handling - содержит различные функции для работы с символами. Например, Is_Digit() проверяет, является ли функция числом, To_Upper() преобразует символ к верхнему регистру, To_Lower() преобразует символ к нижнему регистру и т.д.

[свернуть]
Переименование пакета

Этот приём позволяет значительно сократить код при использовании полной записи:

  • package ASU renames Ada.Strings.Unbounded;
    str : ASU.Unbounded_String;

[свернуть]
Ссылочные типы

Ссылки бывают на участки динамической памяти и на обычные переменные (обобщённые ссылки).

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

Для объявления ссылочного типа используется ключевое слово access. Переменная ссылочного типа объявляется стандартно. Память выделяется с помощью оператора new. Доступ к содержимому участка памяти, на который ссылается ссылочная переменная осуществляется с помощью ключевого слова all. Если переменная больше не нужна, то её нужно уничтожить  с помощью процедуры-дженерика Ada.Unchecked_Dealocation (пакет Ada.Unchecked_Dealocation):

with Ada.Unchecked_Deallocation;
...
--Создаём процедуру для очистки памяти с помощью дженерика:
procedure Free is new Ada.Unchecked_Deallocation(String, Ref_String);
type Ref_String is access String; --объявление ссылочного типа на строки
...
RStr : Ref_String; --Объявление переменной ссылочного типа
--Считывание строки текста с клавиатуры с одновременным выделением участка динамической
--памяти для его хранения:
RStr := new String'(Get_Line);
...
Put_Line(RStr.all); --Вывод строки, расположенной в динамической памяти, на экран
...
Free(RStr); --Очистка памяти

Если нужно создать ссылку на тип, который пользователь создаёт самостоятельно, то нужно использовать т.н. неполное описание типа:

type Person; --Неполное объявление типа
type Ref_Person is access Person; --Ссылочный тип
type Person is --Полное объявление типа
    Record
        Name : Unbounded_String;
        Next : Ref_Person;
    end Record;
...
procedure Free is new Ada.Unchecked_Deallocation(Person, Ref_Person);

Копирование ссылочных переменных происходит с использованием ключевого слова all:

ref_Pers_1.all := ref_Pers_2.all;

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

Сами статические переменные объявляются с использованием ключевого слова aliased:

Val_1 : aliased Integer; --Если обычная переменная
Val_2 : aliased constant Integer := 100; --Если константа.

2. Ссылочный тип объявляется с использованием слов all и constant. Причём, если ссылочный тип объявляется как const (на константу), то это означает, что переменные этого типа могут только читать значение константы (менять не могут):

type ref_Val_1 is access all Integer;
type ref_Val_2 is access constant Integer;

3. Привязка ссылки к переменной осуществляется с помощью атрибута Access

A : aliased Integer;
type Ref_Integer is access all Integer;
ref_Int : Ref_Integer;
...
ref_Int := A'Access; --Устанавливаем ссылку на статическую переменную
Put_Line("ref_Int = " & Integer'Image(ref_Int.all));

[свернуть]