Імперативна мова#
Ada це багатопарадигмальна мова з підтримкою об’єктно-орієнтованого програмування та деяких елементів функціонального програмування, але її ядром є проста, узгоджена процедурна/імперативна мова, схожа на C або Pascal.
В інших мовах
Одна важлива відмінність між Ada та такою мовою, як C, полягає в тому,
що оператори та вирази дуже чітко розрізняються. В Ada, якщо ви спробуєте
використати вираз, де потрібен оператор, ваша програма не зможе скомпілюватися.
Це правило підтримує корисний стилістичний принцип: вирази призначенні для
отримання значень а не побічних ефектів. Це також може запобігти деяким помилкам,
таким як помилкове використання оператора рівності =
замість операції
присвоювання :=
де потрібне саме присвоєння.
Hello world#
Ось дуже проста імперативна програма Ada:
with Ada.Text_IO; procedure Greet is begin -- Вивести "Hello, World!" на екран Ada.Text_IO.Put_Line ("Hello, World!"); end Greet;
яка може знаходитися в файлі greet.adb
.
Якщо ви скомпілюєте цей файл за допомогою компілятора GNAT і запустите на виконання, ви отримаєте очікуваний результат.
$ gprbuild greet.adb
using project file [...]_default.gpr
Compile
[Ada] greet.adb
Bind
[gprbind] greet.bexch
[Ada] greet.ali
Link
[link] greet.adb
$ ./greet
Hello, World!
$
У наведеній вище програмі є кілька цікавих речей:
Підпрограма в Ada може бути або процедурою, або функцією. Процедура, як показано вище, не повертає значення під час виклику.
with
використовується для посилання на зовнішні модулі, які потрібні процедурі. Це схоже наimport
у інших мовах або приблизно схоже на#include
у C та C++. Пізніше ми побачимо, як вони працюють у деталях. Тут нам потрібен модуль стандартної бібліотеки, пакетAda.Text_IO
, який містить процедуру друку тексту на екрані:Put_Line
.Greet
це процедура та основна точка входу для нашої першої програми. На відміну від C або C++, її можна назвати як завгодно. Точку входу визначить побудовник. У нашому простому прикладі gprbuild, побудовник GNAT, використовуватиме файл, який Ви передали як параметр.Put_Line
це процедура, як іGreet
, за винятком того, що вона оголошена в модуліAda.Text_IO
. Це еквівалент Сprintf
.Коментарі починаються з
--
і йдуть до кінця рядка. Синтаксису багаторядкового коментаря немає, тобто неможливо почати коментар в одному рядку з продовженням в наступному рядку. Єдиний спосіб створити кілька рядків коментарів в Ada, це використовувати--
для кожного рядка. Наприклад:
-- Ми починаємо коментар в цьому рядку
-- і продовжуємо в наступному
В інших мовах
Процедури подібні до функцій у C або C++, які повертають void
.
Пізніше ми побачимо, як оголошувати функції в Ada.
Ось мінімалістичний варіант прикладу "Hello, World":
with Ada.Text_IO; use Ada.Text_IO; procedure Greet is begin -- Вивести "Hello, World!" на екран Put_Line ("Hello, World!"); end Greet;
Ця версія використовує ключове слово use
, яке має
форму use
ім'я-пакету. Як видно з виклику
Put_Line
, ефект полягає в тому, що на сутності з
названого пакета можна посилатися безпосередньо, без
необхідності вказувати ім'я-пакету. попереду.
Імперативна мова - If/Then/Else#
У цьому розділі описується оператор if
і представлено кілька інших
фундаментальних можливостей мови, включаючи цілочисельний ввід/вивід,
оголошення змінних і режими доступу до параметрів підпрограм.
Оператор if
не дивує за формою та функціями:
with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Check_Positive is N : Integer; begin -- Виводимо запит на екран Put ("Enter an integer value: "); -- Зчитуємо цілочисленне значення Get (N); if N > 0 then -- Виводимо число Put (N); Put_Line (" is a positive number"); end if; end Check_Positive;
Оператор if
складається як мінімум із зарезервованого слова if
,
умови (яка має бути логічним значенням), зарезервованого слова then
і
непорожньої послідовності операторів (частина then
) яка виконується,
якщо умова оцінюється як Істина і завершальне end if
.
У цьому прикладі оголошується цілочисленна змінна N, запитується у користувача ціле число, перевіряється, чи значення є додатним, і, якщо так, відображається ціле значення, за яким слідує рядок "це додатне число". Якщо значення відємне, процедура не відображає жодних результатів.
Тип Integer є попередньо визначеним типом зі знаком, і його діапазон залежить від архітектури комп’ютера. На типових сучасних процесорах ціле число має 32-розрядний знак.
Приклад ілюструє деякі базові функції для цілочисельного введення-виведення.
Відповідні підпрограми знаходяться у пакеті Ada.Integer_Text_IO
і включають
процедуру Get
(яка читає число з клавіатури) і процедуру Put
(яка відображає ціле число).
Далі невеликі модифікації прикладу, які ілюструють оператор if
із частиною else
:
with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Check_Positive is N : Integer; begin -- Виводимо запит на екран Put ("Enter an integer value: "); -- Зчитуємо цілочисленне значення Get (N); -- Виводимо число Put (N); if N > 0 then Put_Line (" is a positive number"); else Put_Line (" is not a positive number"); end if; end Check_Positive;
У цьому прикладі, якщо вхідне значення є відємним, програма відображає значення, за яким слідує рядок "не є додатним числом".
Останній варіант ілюструє оператор if
з декількома elsif
:
with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Check_Direction is N : Integer; begin Put ("Enter an integer value: "); Get (N); Put (N); if N = 0 or N = 360 then Put_Line (" is due north"); elsif N in 1 .. 89 then Put_Line (" is in the northeast quadrant"); elsif N = 90 then Put_Line (" is due east"); elsif N in 91 .. 179 then Put_Line (" is in the southeast quadrant"); elsif N = 180 then Put_Line (" is due south"); elsif N in 181 .. 269 then Put_Line (" is in the southwest quadrant"); elsif N = 270 then Put_Line (" is due west"); elsif N in 271 .. 359 then Put_Line (" is in the northwest quadrant"); else Put_Line (" is not in the range 0..360"); end if; end Check_Direction;
У цьому прикладі очікується, що користувач введе ціле число від
0 до 360 включно, і відображається, якому квадранту чи осі
відповідає значення. Оператор in
перевіряє, чи знаходиться
скалярне значення в заданому діапазоні, і повертає логічний результат.
Ефект від програми має бути зрозумілим; пізніше ми побачимо
альтернативний і ефективніший стиль для досягнення того самого ефекту
за допомогою оператора case
.
Ключове слово elsif
відрізняється від C або C++, де замість нього
використовуються вкладені блоки else .. if
. І ще одна відмінність
полягає в наявності end if
, що дозволяє уникнути проблеми,
відомої як «висячий else».
Імперативна мова - Цикли#
Ada має три способи визначення циклів. Вони відрізняються від циклів C / Java / Javascript, проте більш простим синтаксисом і семантикою відповідно до філософії Ada.
Цикли For#
Першим типом циклу є цикл for
, який дозволяє виконувати ітерацію
в дискретному діапазоні.
with Ada.Text_IO; use Ada.Text_IO; procedure Greet_5a is begin for I in 1 .. 5 loop -- Виклик процедури Put_Line Put_Line ("Hello, World!" & Integer'Image (I)); -- ^ Procedure parameter end loop; end Greet_5a;
Виконання дає такий результат:
Hello, World! 1
Hello, World! 2
Hello, World! 3
Hello, World! 4
Hello, World! 5
Кілька речей, на які варто звернути увагу:
1 .. 5
це дискретний діапазон від1
до5
включно.Параметр циклу
I
(назва довільна) у тілі циклу має значення в цьому діапазоні.I
є локальним для циклу, тому ви не можете посилатися наI
поза циклом.Хоча значення
I
збільшується на кожній ітерації, з точки зору коду всередині циклу воно є постійним. Змінювати його неможна. Спроба змінити його значення призведе до помилки компіляції.
Integer'Image
це функція, яка приймає ціле число та перетворює його наString
. Це приклад мовної конструкції, відомої як атрибут, позначений синтаксисом'
, який буде розглянуто більш детально пізніше.Символ
&
є оператором конкатенації для строкових значеньend loop
позначає кінець циклу
«Крок» циклу обмежений 1 (напрямок вперед) і -1 (назад). Щоб виконати ітерацію
в діапазоні назад, використовуйте ключове слово reverse
:
with Ada.Text_IO; use Ada.Text_IO; procedure Greet_5a_Reverse is begin for I in reverse 1 .. 5 loop Put_Line ("Hello, World!" & Integer'Image (I)); end loop; end Greet_5a_Reverse;
Виконання дає такий результат:
Hello, World! 5
Hello, World! 4
Hello, World! 3
Hello, World! 2
Hello, World! 1
Межі циклу for
можуть бути обчислені під час виконання; вони
обчислюються один раз перед виконанням тіла циклу. Якщо значення
верхньої межі менше значення нижньої, то цикл не виконується взагалі.
Це також стосується циклів reverse
. Таким чином, у наступному
прикладі виводу на екран не буде:
with Ada.Text_IO; use Ada.Text_IO; procedure Greet_No_Op is begin for I in reverse 5 .. 1 loop Put_Line ("Hello, World!" & Integer'Image (I)); end loop; end Greet_No_Op;
Докладніше про цикл for
буде підніше.
Безумовний цикл#
Найпростішим циклом в Ada є безумовний цикл, який є основою для інших типів циклів Ada.
with Ada.Text_IO; use Ada.Text_IO; procedure Greet_5b is -- Оголошуємо змінну: I : Integer := 1; -- ^ Тип -- ^ Начальне значення begin loop Put_Line ("Hello, World!" & Integer'Image (I)); -- Вихід із циклу: exit when I = 5; -- ^ Умова -- Присвоєння: I := I + 1; -- Конструкції як в С 'I++' немає end loop; end Greet_5b;
Цей приклад дає той самий ефект, що й Greet_5a
, показаний раніше.
Він ілюструє кілька концепцій:
Ми оголосили змінну з назвою
I
міжis
іbegin
. Це являє собою декларативний блок. Ada чітко відокремлює декларативну область від суто коду підпрограми. Оголошення може відбуватися в декларативній області, але не допускається посеред коду.Цикл починається ключовим словом
loop
і, як і будь-який тип циклу, завершується комбінацією ключових слівend loop
. Сам по собі це нескінченний цикл. Ви можете вийти з цього за допомогою оператораexit
Синтаксис присвоєння:
:=
, а рівності —=
. Немає способу сплутати їх, оскільки, як зазначалося раніше, в Ada твердження та вирази є різними, а вирази не є дійсними твердженнями.
Цикл While#
Останній вид циклу в Ada — це цикл while
.
with Ada.Text_IO; use Ada.Text_IO; procedure Greet_5c is I : Integer := 1; begin -- Умова має бути логічним виразом -- (не численним). -- Оператор "<=" вертає результат -- порівняння while I <= 5 loop Put_Line ("Hello, World!" & Integer'Image (I)); I := I + 1; end loop; end Greet_5c;
Умова оцінюється перед кожною ітерацією. Якщо результат хибний, то цикл припиняється.
Ця програма робить то самє, що й попередні.
В інших мовах
Зауважте, що Ada має іншу семантику, ніж мови на основі C щодо умови в
циклі while. В Ada умова має бути логічним значенням, інакше компілятор
відхилить програму; умова не є цілим числом, яке розглядається як
True
або False
залежно від того, відмінне воно від нуля
чи ні.
Імперативна мова - Case#
Оператор Ada case
схожий на оператор C і C++ switch
, але з
деякими важливими відмінностями.
Ось приклад, варіація програми, яка була показана раніше з
оператором if
:
with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Check_Direction is N : Integer; begin loop Put ("Enter an integer value: "); Get (N); Put (N); case N is when 0 | 360 => Put_Line (" is due north"); when 1 .. 89 => Put_Line (" is in the northeast quadrant"); when 90 => Put_Line (" is due east"); when 91 .. 179 => Put_Line (" is in the southeast quadrant"); when 180 => Put_Line (" is due south"); when 181 .. 269 => Put_Line (" is in the southwest quadrant"); when 270 => Put_Line (" is due west"); when 271 .. 359 => Put_Line (" is in the northwest quadrant"); when others => Put_Line (" Au revoir"); exit; end case; end loop; end Check_Direction;
Ця програма постійно запитує ціле число, а потім, якщо значення знаходиться
в діапазоні 0 .. 360
, відображає відповідний квадрант або вісь. Якщо
значення виходить за межі цього діапазону, цикл (і програма) припиняється
після виведення прощального повідомлення.
Ефект оператора case подібний до оператора if у попередньому прикладі, але оператор case може бути ефективнішим, оскільки він не передбачає багаторазових перевірок діапазону.
Важливі моменти щодо конструкції case:
Вираз для case (тут змінна
N
) має бути дискретного типу, тобто або цілого типу, або типу перерахування. Дискретні типи будуть розглянуті більш детально пізніше дискретні типи.Кожне можливе значення виразу case має бути охоплено одною з гілок оператора case. Це буде перевірено під час компіляції.
Гілка може охоплювати одне значення, наприклад
0
; діапазон значень, наприклад1 .. 89
; або будь-яка комбінація значень (розділених символом |).Як особливий випадок, необов’язкова кінцева гілка може вказати
others
, яка охоплює всі інші значення, не включені в попередні гілки.Виконання складається з оцінки виразу case, а потім передачі керування коду в унікальній гілці, яка охоплює це значення.
Коли виконання коду у вибраній гілці завершено, керування передається коду після
end case
. На відміну від C, виконання не переходить до наступної гілки. Отже, Ada не потребує (і не має) оператораbreak
.
Імперативна мова - Декларативні блоки#
Як згадувалося раніше, Ada проводить чіткий синтаксичний розподіл між деклараціями, які вводять імена для сутностей, які використовуватимуться в програмі, та операторами, які виконують обробку. Області в програмі, де можуть з’являтися декларації, називаються декларативними блоками.
У будь-якій підпрограмі розділ між is
і begin
є декларативним блоком.
Ви можете оголосити там змінні, константи, типи, внутрішні підпрограми та інші сутності.
Ми коротко згадували про оголошення змінних у попередньому підрозділі. Давайте
розглянемо простий приклад, де ми оголошуємо цілочисельну змінну X
у декларативному
блоці та виконуємо її ініціалізацію та модифікацію:
with Ada.Text_IO; use Ada.Text_IO; procedure Main is X : Integer; begin X := 0; Put_Line ("The initial value of X is " & Integer'Image (X)); Put_Line ("Performing operation on X..."); X := X + 1; Put_Line ("The value of X now is " & Integer'Image (X)); end Main;
Давайте розглянемо ще один приклад:
with Ada.Text_IO; use Ada.Text_IO; procedure Main is procedure Nested is begin Put_Line ("Hello World"); end Nested; begin Nested; -- Викликали процедуру Nested end Main;
Оголошення неможливі посеред операторів. Якщо вам потрібно оголосити локальну змінну серед
операторів, ви можете оголосити новий декларативний блок за допомогою оператора declare
:
with Ada.Text_IO; use Ada.Text_IO; procedure Greet is begin loop Put_Line ("Please enter your name: "); declare Name : String := Get_Line; -- ^ Виклик функції -- Get_Line begin exit when Name = ""; Put_Line ("Hi " & Name & "!"); end; -- Змінної Name більше не існує end loop; Put_Line ("Bye!"); end Greet;
Увага
Функція Get_Line
дозволяє вам отримувати дані від користувача та отримати
строку як результат. Це більш-менш еквівалентно функції C:c:scanf.
Вона повертає String
, який, як ми побачимо пізніше, є
Необмеженим масивом. Наразі ми просто
зауважимо, що якщо ви бажаєте оголосити змінну String
і не знаєте її розмір
заздалегідь, вам потрібно ініціалізувати змінну під час її оголошення.
Імперативна мова - умовні вирази#
Ada 2012 додала аналог виразу для умовних операторів
(if
і case
).
If вираз#
Ось альтернативна версія прикладу, який ми бачили раніше;
оператор if
було замінено виразом if
:
with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; procedure Check_Positive is N : Integer; begin Put ("Enter an integer value: "); Get (N); Put (N); declare S : constant String := (if N > 0 then " is a positive number" else " is not a positive number"); begin Put_Line (S); end; end Check_Positive;
Вираз if
використовує один із двох строк залежно від N і
присвоює це значення локальній змінній S.
Вирази Ada if
подібні до операторів if
. Однак є кілька
відмінностей, які пов’язані з тим, що це вираз:
Обидва варіанти мають бути одного типу
Він має бути в дужках, якщо навколишній вираз їх ще не містить
Гілка
else
є обов’язковою, якщо вираз післяthen
не є логічним типом. У цьому випадку гілкаelse
є необов’язковою і, якщо її немає, за замовчуванням використовуєтьсяelse True
.
Ось інший приклад:
with Ada.Text_IO; use Ada.Text_IO; procedure Main is begin for I in 1 .. 10 loop Put_Line (if I mod 2 = 0 then "Even" else "Odd"); end loop; end Main;
Ця програма виводить 10 рядків, чергуючи «Непарні» та «Парні».
Case вираз#
Подібно до виразів if
, Ada також має вирази case
.
Вони працюють так, як Ви очікуєте.
with Ada.Text_IO; use Ada.Text_IO; procedure Main is begin for I in 1 .. 10 loop Put_Line (case I is when 1 | 3 | 5 | 7 | 9 => "Odd", when 2 | 4 | 6 | 8 | 10 => "Even"); end loop; end Main;
Ця програма робить то самє, що й попередній приклад.
Синтаксис відрізняється від оператора case
, в даному
випадку варіанти розділені комами.