Hlavní navigace

Programovací jazyk Ada: silná typová kontrola a hlášení překladače

20. 5. 2015
Doba čtení: 5 minut

Sdílet

V dnešním dílu se zaměříme hlavně na různé stránky typové kontroly jazyka Ada a ukážeme si spoustu chybových hlášení, které překladač generuje. Kromě toho se ještě v některých speciálních případech vrátíme k definicím typů a novým atributům, které by mohly být pro další postupy zajímavé.

Do dnešního dílu si pro lepší přehled znovu přeneseme přílohu z dílu minulého – ada9.

Je samozřejmě jasné, že si překladač definovaný rozsah hlídá a nedovolí z něj vybočit ani o krůček. On dokonce hlídá i něco jiného! Využijeme tedy kód z minulého dílu a definujeme dvě nové proměnné:

a : Integer range 1..25;
b : Integer range 1..25;

a do těla přidáme dva příkazy:

a := 5;
b := a+1;

Výsledkem je úspěšný překlad a spuštění:

./ada9
A =  5
B =  6

Pokud bychom ale použili příkaz b := a+100; , dostaneme samozřejmě chybové hlášení o překročení definovaného rozsahu. Nyní přidáme do těla procedury ještě další příkaz: a := b; Výsledek je opět očekávaný:

./ada9
A =  6
B =  6

Opět trochu změníme přístup a definujeme si ne proměnná, ale typy následovně:

type c is range 1..25;
type d is range 1..25;

a do těla přidáme příkaz c := d; Mohlo by se zdát, že to není žádný problematický příkaz, ale opak je pravdou:

gnatmake ada9.adb
gcc -c ada9.adb
ada9.adb:32:17: invalid use of subtype mark in expression or call
gnatmake: "ada9.adb" compilation error

Definované typy, i když jsou zdánlivě stejné, nejsou pro překladač vůbec stejné… Zkusíme to tedy nějak obejít a do definice přidáme dvě proměnné:

c1 : c;
d1 : d;

a do těla pak příkaz c1 := d1; Výsledek je sice jiný, ale pořád ne úspěšný:

gnatmake ada9.adb
gcc -c ada9.adb
ada9.adb:35:23: expected type "c" defined at line 22
ada9.adb:35:23: found type "d" defined at line 23
gnatmake: "ada9.adb" compilation error

Podobný výsledek dostaneme i tehdy, když do těla přidáme podobné příkazy jako v předchozím pokusu:

c1 := 5;
d1 := c1+1;
c1 := d1;

Pokud ale zadáme příkazy

c1 := 5;
d1 := 25;

bude výstup jasný a očekávaný:

./ada9
C1 =  5
D1 =  25

U typů a rozsahů ještě zůstaneme a ukážeme si další zajímavý příklad. Definujeme 3 další proměnné, resp. jeden typ a dva jeho podtypy:

type e1 is range 1..10;
subtype e2 is e1 range 1..10;
subtype e3 is e1'Base range 1..10;

Definice druhého podtypu se jednak zdá zbytečná a také je v ní použit nový atribut. Překlad proběhne bez problémů, a tak uděláme drobnou změnu:

type e1 is range 1..10;
subtype e2 is e1 range 5..15;
subtype e3 is e1'Base range 1..10;

a výsledek se dostaví neprodleně:

gnatmake ada9.adb
gcc -c ada9.adb
ada9.adb:29:35: warning: static value out of range of type "e1" defined at line 28
ada9.adb:29:35: warning: "Constraint_Error" will be raised at run time
gnatbind -x ada9.ali
gnatlink ada9.ali

Pokud ale změníme kód takto:

type e1 is range 1..10;
--  subtype e2 is e1 range 5..15;
subtype e3 is e1'Base range 5..15;

proběhne překlad bez problémů. Více o atributu Base je možné se dočíst v přehledu atributů v minulých dílech. Vytvoříme si další typ, který bude typem odvozeným a s rozsahem, který je v definičním oboru svého „předka“:

type e4 is new e1 range 2..8;

Překlad je bez problémů, takže přidáme do těla procedury příkaz e1 := e4; Podle rozsahu by vše mělo být v pořádku, ale není. Odvozené typy jsou opět přímo nekompatibilní s typem původním, jak jasně ukazuje pokus o překlad:

gnatmake ada9.adb
gcc -c ada9.adb
ada9.adb:46:17: invalid use of subtype mark in expression or call
gnatmake: "ada9.adb" compilation error

Pro začátek si vytvoříme novou proceduru a použijeme v ní definici dnů v týdnu, jako to bylo provedeno v proceduře číslo 6 našich příkladů, a přidáme k tomu další dvě deklarace, které si vysvětlíme později – viz obrázek. V předchozí proceduře jsme si ukázali, jak použít definici pro vytvoření smyčky. Je asi jasné, že by bylo vhodné a přínosné umět tuto definici využít i jinak, přímo. Ukážeme si také nové atributy, které je možné použít pro manipulaci s položkami výčtového typu. Proto si do těla nové procedury přidáme následující příkaz:

Put_Line(dny'Image(Ct));

Překlad proběhne bez problémů a výsledek je také očekávaný (jenom vypsaný velkým písmem) – vypsal se obsah položky definované jejím názvem:

./ada10
CT

Zkusíme si tedy zobrazit pozici zadaného prvku v množině příkazem

Put_Line(dny'Pos(Ct));

Překladač ovšem vyhodí docela rozsáhlou sbírku problémů:

gnatmake ada10.adb
gcc -c ada10.adb
ada10.adb:16:17: no candidate interpretations match the actuals:
ada10.adb:16:17: missing argument for parameter "Item" in call to "Put_Line" declared at a-textio.ads:259
ada10.adb:16:29: expected type "Standard.String"
ada10.adb:16:29: found type universal integer
ada10.adb:16:29:   ==> in call to "Put_Line" at a-textio.ads:263
gnatmake: "ada10.adb" compilation error

Důležité v ní je to, že byl v příkazu pro zobrazení očekáván typ String, ale nalezen typ Integer. Je možné použít dvě varianty řešení. My si nyní ukážeme tu jednodušší a převedeme si Integer na String. Příkazy pak budou vypadat následovně:

p := dny'Pos(Ct);               --1
Put_Line(Integer'Image(p));     --2

V prvním řádku si uložíme výsledek atributu typu Integer do deklarované proměnné stejného typu. Na druhém řádku pak převedeme Integer na String pomocí bazického atributu Integer'Image. Výsledek je už mnohem lepší při překladu i spuštění:

./ada10
CT
3

Nakonec si ukážeme ještě dva příkazy, které vrátí obsah položky na dané pozici v množině a zadané pomocí řetězce. Zde můžeme narazit na dva problémy: s deklarací typu a zobrazení výsledku. Nebudeme to zde příliš rozebírat a vložíme do těla procedury tyto příkazy:

den1 := dny'Val(0);
den2 := dny'Value("Ct");
Put_Line(den1'Img);
Put_Line(den2'Img);

Překlad proběhne v pořádku a zde je konečný výsledek:

CS24_early

./ada10
CT
 3
PO
CT

Hlavně zde stojí za to všimnout si skutečnosti, že výčtové typy se indexují od nuly! Výsledný a konečný kód je v příloze ada10.

Dalo by se pokračovat a demonstrovat možnosti jazyka Ada v oblasti statické typové kontroly mnohem déle a radostněji, ale pro základní přehled to stačí. V příštím dílu se zaměříme na další atributy, doplníme popis těch již známých a podíváme se také na zobrazení číselných hodnot na výstupu v terminálu. Také načneme kapitolu o procedurách a funkcích.

Byl pro vás článek přínosný?

Autor článku