main
Hier für den Anfang ein Hello World Programm, das auf der Kommandozeile ein „Hello proggen.org!“ ausgibt:
with Ada.Text_IO; use Ada.Text_IO; procedure Hello is Greeting : String := "Hello proggen.org!"; begin Put_Line(Greeting); -- Alternativ: Ada.Text_IO.Put_Line(Greeting); end Hello;
Bei Ada wird der Quellcode in sogenannte „Compilation Units“ („Kompilationseinheiten“) unterteilt. Es gibt Compiler, die mehrere solche Einheiten in einer Datei zulassen, GNAT erwartet jedoch jede Einheit in einer eigenen Datei. Falls man doch alles in eine Datei schreiben möchte, kann man das Tool gnatchop verwenden, um die Einheiten für den Compiler aufzuspalten.
Zu Beginn einer Compilation Unit steht die „Context Clause“, die entweder leer ist oder with
- und use
-Statements enthält. Ein with
gibt an, dass der Quellcode von anderen Bibliotheken abhängig ist. Im obigen Fall benötigen wir with Ada.Text_IO;
, um die Text-Input-/Output-Methoden zu benutzen. Das use Ada.Text_IO;
importiert die öffentlichen Methoden und Variablen aus Ada.Text_IO in den lokalen Namensraum. Dies dient nur als Beispiel, das Importieren auf oberster Ebene sollte ähnlich dem using namespace std;
bei C++ gut überdacht werden.
Nach der Context Clause folgt das eigentliche „Library Item“, in diesem Fall eine Prozedur. Bei Ada wird zwischen Prozeduren und Funktionen unterschieden. Letztere geben einen Wert zurück und können nur an Stellen benutzt werden, an denen ein Wert des Typs erwartet wird, zum Beispiel auf der rechten Seite einer Zuweisung.
Weitere Arten von Library Items wären Packages, Generics oder Renamings.
Das Schlüsselwort is
nach dem Prozedur-Namen leitet die Implementation der Prozedur ein. Eine reine Deklaration würde nach dem Namen (sowie eventueller Parameter) enden. Danach folgt der Deklarations-Teil, das Schlüsselwort begin
, eine Folge von Anweisungen, sowie das Schlüsselwort end
. Der Name der Prozedur am Ende ist optional, hilft aber dabei Flüchtigkeitsfehler zu erkennen, da ein falscher Name nicht akzeptiert wird.
Im Deklarations-Teil wird die Variable Greeting
deklariert. Solch eine Deklaration läuft nach dem Schema Name : Typ;
ab. Es kann auch wie im Beispiel eine Initialisierung mitgegeben werden: Name : Typ := Wert;
. Das :=
steht in Ada für den Zuweisungs-Operator.
Nach dem begin
folgen die Anweisungen. Im oberen Beispiel ist dies lediglich eine. Es wird die Prozedur Put_Line
aufgerufen, die in der Bibliothek Ada.Text_IO
definiert ist. Durch das use
in der Context Clause kann sie direkt verwendet werden. Andernfalls müsste der komplette Name benutzt werden: Ada.Text_IO.Put_Line
.
Wenn eine Prozedur oder Funktion Parameter erwartet, kommen nach dem Namen die Parameter, durch Kommata getrennt und in runden Klammern. Falls keine Parameter erwartet werden, oder die Parameter einen Default-Wert besitzen und diese benutzt werden sollen, müssen auch die runden Klammern weggelassen werden. Eine solcher Prozedur-Aufruf wäre z.B.: New_Line;
Da bei Ada nicht zwischen Groß- und Kleinschreibung unterschieden wird, könnte die Zeile auch so aussehen:
put_LINE(GREEting);
Allerdings wird zur besseren Lesbarkeit meistens Camel_Case für Packages, Variablen, Prozeduren und Funktionen, sowie Kleinschreibung für Schlüsselwörter benutzt.
Bei Ada gibt es nur Zeilen-Kommentare. Diese beginnen mit einem doppelten Minus –
und gehen bis zum Ende der Zeile.
Das Hauptprogramm (bei C main()
) besitzt keinen fest definierten Namen, es muss lediglich eine Prozedur auf oberster Ebene (also nicht innerhalb eines Packages) sein.
GNAT erwartet üblicherweise den Namen des Library Items als Dateiname in Kleinschreibung (bei Betriebssystemen ohne Unterscheidung von Groß- und Kleinschreibung bei Dateinamen ist es prinzipiell egal, kann dann aber bei anderen Systemen zu Problemen führen). Für die Deklarationen (auch „Specification“ genannt, vergleichbar mit Header bei C) erwartet GNAT die Erweiterung .ads
, und für die Implementierung („Body“) die Erweiterung .adb
. Für unser Beispiel wäre der Dateiname also hello.adb
.
Da dies ein einfaches Beispiel ist, können wir das Beispiel folgendermaßen kompilieren, wenn wir uns im selben Verzeichnis wie die Quelldatei(en) befinden:
gnatmake hello
Unter Linux wird dann ein Executable hello
erzeugt, unter Windows eine hello.exe
. Von der Kommandozeile aufgerufen wird dann der Text „Hello proggen.org!“ ausgegeben. Wenn man es unter Windows per Doppelklick öffnet, schließt sich das Konsolenfenster sofort wieder, da wir vor dem Beenden nicht warten.
gnatmake ist das Ada-Äquivalent von make und führt in diesem Fall folgende Schritte aus:
gcc -c hello.adb gnatbind -x hello.ali gnatlink hello.ali
Das erste ist der Compiler. Als Ergebnis werden die Object-Datei hello.o
und eine sogenannte „Ada Library Information“-Datei hello.ali
erzeugt. Letztere beinhaltet Informationen zu den verwendeten Bibliotheken und deren Versionen, um eine konsistentes Programm zu gewährleisten. Sollte sich zwischen dem gcc
-Aufruf und gnatbind
oder gnatlink
etwas an den Bibliotheken ändern, wird der Compiler mit einer Fehlermeldung abbrechen.
gnatbind
führt das Binding des Programms durch. Als Zwischenprodukte werden in unserem Beispiel zwei Dateien erzeugt mit den Namen b~hello.ads
und b~hello.adb
, die beim anschließenden Linken durch gnatlink
kompiliert und wieder automatisch gelöscht werden (außer man benutzt den Debug-Switch -g
, dann bleiben die Zwischenprodukte erhalten). Außerdem wird im letzten Schritt das Executable hello
bzw. hello.exe
erzeugt.