Reference

1. Die ersten Schritte

Machen Sie sich als erstes mit den Grundbefehlen in AdaLogo vertraut. Gehen Sie dazu auf Examples/befehle.adl und führen Sie die Befehle im Editor-Fenster durch "step by step" aus. Lesen Sie dazu die Kommentaren und beobachten Sie was die Schildkröte macht.

Alle Grundbefehle, die direkt Auswirkungen auf die Schildkröte haben, sind:

forward(100);
move_to(200,200);
new_line;
pen_up;
pen_down;
put_line("hallo");
put(100);
turtle_reset;
turn(90);
turn_to(225);

Natürlich kann innerhalb der Klammer eine beliebige ganze Zahl stehen, ja sogar noch mehr. AdaLogo kann auch rechnen, dazu kommen wir jedoch im Punkt 3.
put und put_line akzeptieren außer Zahlenausdrücke (siehe 3.) und logische Operationen (siehe 4.) auch Zeichenketten. In einer Zeichenkette dürfen beliebige Buchstaben auftauchen außer Anführungszeichen ("). put und put_line werten diese Ausdrücke aus und geben die Auswertung in der Konsole aus. new_line; schreibt eine neue leere Zeile in die Konsole.
Mit diesen Befehlen können Sie bereits den ersten Buchstaben Ihres Namen zeichnen. Versuchen Sie es doch einmal!

2. Der "Rahmen"

Wählen Sie bitte Examples/template.adl aus. Bevor Sie beginnen, sollten Sie doch mit folgenden Sprachkonstrukten vertraut sein:

  • Kommentare können geschrieben werden und eine Zeile mit einem Kommentar fängt mit -- an. Alles, was danach geschrieben wird, wird vom Interpreter ignoriert.
  • Es gehört zum guten Programmierstil, dass Sie die Zeilen Autor, Datum und Idee ausfüllen.
  • Prozeduren- und Variabel-Deklarationen werden innerhalb von is und begin geschrieben, dazu siehe Punkt 7.
  • Das eigentliche Programm liegt zwischen begin und end; Hier können bereits die Befehle aus Punkt 1 eingetragen werden.
  • Wie im Sinne Ada mit "package", so muss auch in AdaLogo das package adalogo eingebunden werden mit
    with adalogo;
    use adalogo;
    
    Diese zwei Anweisungen müssen vor procedure stehen.
  • Gewöhnen Sie sich an, bitte eine sinnvollen Namen für das Programm zu geben und NONAME zu ersetzen. Falls Sie die Datei abspeichern, so soll der Dateiname mit der Endung *.adl wie die Prozedur gewählt sein, z.B.:
    procedure mein_erstes_adalogo_programm is
    begin
      null;
    end;
    	
    Der Name für die Datei lautet dann mein_erstes_adalogo_programm.adl

3. Der "Taschenrechner"

Sie können nicht nur forward(100); mit einer einfachen ganzen Zahl schreiben, sondern Sie können mit AdaLogo auch Berechnungen anstellen. Anstelle von 100 können Sie auch Folgendes schreiben, wobei x und y Element der ganzen Zahlen sein darf.

  • -x bildet das Inverse zu x.
  • x + y Addition
  • x - y Subtraktion
  • x * y Multiplikation
  • x / y (Vorsicht, y ungleich 0) Division
  • x mod y (Vorsicht, y ungleich 0) Modulo
  • x rem y (Vorsicht, y ungleich 0) Remainder
  • turtle_x liefert den x-Wert von Stelle, an der sich die Schildkröte befindet.
  • turtle_y liefert den y-Wert von Stelle, an der sich die Schildkröte befindet.
  • turtle_dir liefert die Richtung, in der die Schildkröte gerade zeigt.
  • min(x,y) liefert die kleinere Zahl von x und y.
  • max(x,y) liefert die größere Zahl von x und y.
  • random(x,y) liefert eine zufällige Zahl zwischen x und y, wobei nicht zwingend y > x gelten muss. Die untere Grenze gehört dazu, die obere jedoch nicht. Z.B. liefert random(2,6) zufällige Zahlen von der Menge {2,3,4,5}.

AdaLogo rechnet dabei "Punkt vor Strich". * / mod und rem binden "stärker" und werden zuerst ausgerechnet, danach kommen + und - . Inversebildung bindet am "stärksten". Wollen Sie bei einem Ausdruck a + b * c, dass a + b zuerst ausgerechnet wird, so müssen Sie für die richtige Klammerung sorgen:

(a + b) * c

Natürlich ist es möglich diese Operationen auf der Menge der ganzen Zahlen beliebig zu kombinieren.

Anstelle von x und y ist es auch möglich Variabel-Namen aufzurufen, falls diese vorher im Deklarationsbereich definiert wurden. Dazu siehe Punkt 7.

4. Logik

AdaLogo unterstützt die zweiwertige Logik mit true und false. Logische Werte a und b können mit folgenden Operationen verknüpft werden:

  • a or b gibt true zurück, falls a oder b true ist, andernfalls false. (siehe Wikipedia)
  • a and b gibt true zurück, falls a und b true ist, andernfalls false. (siehe Wikipedia)
  • not a bildet das Inverse zu a.

Zu beachten ist, dass not am "stärksten" bindet, danach and und dann or. Möchten Sie diese Bindung anders, so muss entsprechend Klammer gesetzt werden. Hier Beispiele:

not(a or b) and c 
-- Zuerst a or b, dann not und danach and.
(a or not b) and (c or d) 
-- Zuerst not, danach beide Klammer und dann and.

Anstelle von a und b ist es auch möglich Variabel-Namen aufzurufen, falls diese vorher im Deklarationsbereich definiert wurden. Dazu siehe Punkt 7.

5. Vergleichsoperationen

In AdaLogo gibt es folgende Vergleichsoperationen. Verglichen werden x und y, wobei diese die Bedingung aus 3. erfüllen müssen. Das Ergebnis ist true oder false und entspricht die Definition von 4.

  • a = b ergibt true falls a den gleichen Wert hat wie b, andernfalls false.
  • a /= b ergibt true falls a nicht den gleichen Wert hat wie b, andernfalls false.
  • a > b ergibt true falls a größer ist als b, andernfalls false.
  • a >= b ergibt true falls a ist größer oder gleich b, andernfalls false.
  • a < b ergibt true falls a kleiner ist als b, andernfalls false.
  • a <= b ergibt true falls a ist kleiner oder gleich b, andernfalls false.

Ergebnisse von Vergleichsoperationen können in 4. als ein Logikausdruck verwendet werden. Z.B. ist a < b or c >= d zulässig.

6. Sprachkonstrukte

Für "null", bedingte, wiederholte und Sprung-Anweisungen existieren folgende Sprachelemente:

6.1 null;

null; - diese Anweisung macht und schlicht und einfach gar nichts. Sie ist nur wichtig, um leere Prozeduren oder Konstrukte zu schreiben. In Ada(Logo) wird oft nach mindestens einer Anweisung verlangt, falls Sie keine Anweisung ausführen möchten, so benutzen Sie

null;

6.2 if

So sieht z.B. eine bedingte Anweisung mit if aus:

if a then
  -- hier anweisungen1
elsif b then
  -- hier anweisungen2
elsif c then
  -- hier anweisungen3
else
  -- hier anweisungen4
end if;  

Der if-Teil mit Anweisungen sowie end if; muss genau 1 Mal da sein. Der elsif-Teil mit Anweisungen kann 0 Mal, 1 Mal oder beliebig oft benutzt werden. Der else-Teil mit Anweisungen kann 0 Mal oder 1 Mal verwendet werden.

Anstelle von a, b, oder c kann alles, was in 4. und 5. genannt wurde, verwendet werden. Bei den Anweisungen muss mindestens ein Element aus 1., 6. oder 8. verwendet werden.

Logisch betrachtet wird Folgendes gemacht:

  • Wenn a wahr ist, dann werden anweisungen1 ausgeführt. Der Rest wird ignoriert.
  • Wenn a falsch ist und b ist richtig, dann werden anweisungen2 ausgeführt. Der Rest wird ignoriert.
  • Wenn a und b falsch sind und c ist richtig, dann werden anweisungen3 ausgeführt. Der Rest wird ignoriert.
  • ...
  • Wenn alles davor falsch war, dann führe anweisungen4 durch.

6.3 for

So sieht eine for-Schleife aus:

for i in a .. b loop
  -- hier anweisungenX
end loop;

Die Werte a und b können alles aus 3. sein. Bei den Anweisungen muss mindestens ein Element aus 1., 6. oder 8. verwendet werden.

Für den Namen der Variabel i gilt 7. Mit der for-Schleife wird ein neuer "Block" aufgemacht. Existiert schon vorher eine Variabel mit dem gleichen Namen, so wird diese von der neuen Variabel "überdeckt" und ist nicht mehr "sichtbar".

Semantisch gesehen werden die anweisungenX (b - a + 1) Mal gemacht. Ist die Differenz von b - a kleiner als 0, so werden die anweisungenX gar nicht ausgeführt.

Die Variabel i erhält am Anfang den Wert von a und wird nach jedem Schleifendurchlauf um 1 erhöht.
Verwenden Sie:

for i in reverse a .. b loop
  -- hier anweisungenX
end loop;

so erhält die Variabel i am Anfang den Wert b und nach jeder Schleifendurchlauf wird sie um 1 erniedrigt.

6.4 loop

So sieht eine loop-Schleife aus:

loop
  --hier anweisungenY
end loop;

Bei den Anweisungen muss mindestens ein Element aus 1., 6. oder 8. verwendet werden. Semantisch gesehen werden die anweisungenY unendlich oft ausgeführt. Seien Sie bitte vorsichtig, Sie können das Programm zum abstürzen bringen. Wie Sie trotzdem bedingt/unbedingt abbrechen können, lesen Sie bitte 6.5. und 6.6.

6.5 while

So sieht eine while-Schleife aus:

while a loop
  -- hier anweisungenZ
end loop;

Anstelle von a muss ein Element aus 4. oder 5. stehen. Falls a wahr ist, so werden anweisungenZ ausgeführt. Danach wird auf dem Wahrheitswert von a wieder überprüft und falls wahr, anweisungenZ wieder ausgeführt etc. Falls der Wahrheitswert von a sich nicht nie ändert, so erreichen Sie den gleichen Effekt mit der loop-Schleife. Falls a nicht mehr zutrifft, so wird abgebrochen.

6.6 exit

exit; - Mit exit; springen Sie unbedingt oder falls Sie eine if-Anweisung um Ihr exit; bauen bedingt aus einer for-, while- oder loop-Schleife heraus.

Versuchen Sie bitte exit; so gut wie möglich zu vermeiden. Das Verwenden von exit; gehört zum schlechten Programmierstil und wird normalerweise im Programmierkurs I und II verboten.
exit; nicht innerhalb einer Schleife zu verwenden ist in Ada(Logo) falsch.

Wenn Sie z.B. eine doppelte Schleife benutzen und innerhalb der inneren Schleife exit; benutzen, so wird nur die innere Schleife abgebrochen, die äußere wird jedoch weiter ausgeführt. exit; springt immer bis zur nächsten Schleife, die ihm umgibt.

7. Prozedur- und Variabel-Deklarationen

7.1. Variabel-Deklarationen

In AdaLogo gibt es (im Vergleich zu Ada nur) 2 Datentypen integer und boolean. Variablen von Typ integer oder boolean werden im Deklarationsblock definiert und können später verwendet werden. Hier Beispiele für Variabel-Deklarationen:

  • a : integer := -10; -- bsp1
  • b : integer; -- bsp2
  • c : boolean := true; -- bsp3
  • d : boolean; -- bsp4

In Beispiel 1 und 2 werden integer (ganze Zahlen) definiert. a bekommt in Beispiel 1 sofort den Wert -10 zugewiesen, während b keinen Wert bekommt. In Beispiel 3 und 4 werden die Variablen c und d als boolean definiert. c hat sofort den Wert true, d jedoch bleibt unbestimmt.

Vorsicht: falls später auf die Variabel b und d zugegriffen werden, ohne dass b und d jemals einen konkreten Wert zugewiesen bekommen, so haben die Variablen b und d wie in Ada einen zufälligen Wert - das kann zu schweren Nebeneffekten führen!

7.2. Prozedur-Deklarationen

Hier Beispiele, wie Prozeduren definiert werden:

-- bsp1:
procedure line is
  -- Deklarationen hier
begin 
  pen_down;
  forward(100);
  turn(180);
  forward(100);
  turn(180);
end;

-- bsp2:
procedure quadrat (seitenlaenge : integer) is
  -- Deklarationen hier
begin 
  pen_down;
  for i in 1..4 loop
    forward(seitenlaenge);
    turn(90);
  end loop;
end;

-- bsp3:
procedure schwarzeflaeche 
    (laenge : integer; breite : integer; do_it : boolean) is
  -- Deklarationen hier
begin
  if do_it then
    for l in 1..breite/2 loop
      forward(laenge);
      turn(90);
      forward(1);
      turn(90);
  
      forward(laenge);
      turn(-90);
      forward(1);
      turn(-90);
    end loop;
  end if;
end;

In Beispiel 1 wird eine einfache Linie gezeichnet. Die Prozedur line erhält keine Eingabe-Parameter. Die Prozedur Quadrat erhält als "in"-Parameter die Seitenlänge und zeichnet ein Quadrat mit dieser Seitenlänge. Innerhalb dieser Prozedur ist die Variabel seitenlaenge bekannt und sie wird dazu verwendet, um die Seitenlänge des Quadrates zu zeichnen. An Beispiel 3 können Sie erkennen, dass es auch mehrere Eingabe-Parameter sein können. Eingabe-Parameter können sowohl integer als auch boolean sein.

Zwischen is und begin können weitere Deklarationen folgen. Unter anderem bedeutet das, dass Sie weitere Unter- und Unterprozeduren beliebig verschachtelt definieren können.

Variabel-Namen sind (wie in Ada) definiert:

  • Der erste Buchstabe muss ein Buchstabe (a-z) oder ein _ sein.
  • Die weiteren Buchstaben können Buchstaben (a-z), Zahlen (0-9) oder _ sein.
  • Groß- und Kleinschreibung spielen keine Rolle.
  • Vorsicht: dabei sind Sonderzeichen, Umlaute oder ß nicht erlaubt. Sie schreiben daher lieber oe, ae, ue und ss.
  • Reservierte Wörter dürfen nicht benutzt werden.

Die Sichtbarkeit der Variablen und Prozeduren ist wichtig.
Folgende Zeilen sind gültig:

a : integer := 10;
b : integer := a * a;
da b a bereits sehen kann.
Folgende Zeilen sind nicht gültig:
a : integer := b * b
b : integer := 10;
da b für a noch nicht sichtbar ist.

Die Sichtbarkeit von Prozeduren ist in AdaLogo anders als in Ada!
Folgende Zeilen ist in AdaLogo möglich, in Ada jedoch nicht!

procedure bla is begin
  blubb;
end;
procedure blubb is begin
  forward(100);
end;

8. Wertzuweisungen und Prozedurenaufrufe

8.1 Wertzuweisungen

Hier einpaar Beispiele:

a := 10; -- bsp1
b := random(10,25); -- bsp2
a := turtle_x; -- bsp3

c := true; -- bsp4
d := turtle_y < a; -- bsp5

Beispiele 1, 2 und 3 sind Wertzuweisungen von integer Variablen, vorausgesetzt ist, dass diese Variablen a, b schon vorher im Deklarationsblock definiert worden sind.

Beispiele 4 und 5 sind Wertzuweisungen von boolean, auch hier ist die Voraussetzung, dass diese schon vorher als boolean deklariert worden sind.

8.2 Prozedur-Aufrufe

Hier einpaar Beispiele:

line; -- bsp1
quadrat(4); -- bsp2
schwarzeflaeche(a,10,true); -- bsp3

Diese 3 Beispiele beziehen sich auf 7.2.
line; ist eine Prozedur ohne Eingabe-Parameter, quadrat hat einen Eingabeparameter als integer, während schwarzeflaeche 3 Eingabe-Parameter hat, wobei die ersten 2 Parameter integer sind, der 3. Parameter ist von Typ boolean.

Wurden die Prozeduren im Deklarationsbereich mit n Parametern (n ≥ 0) definiert, so müssen sie beim Aufruf ebenfalls n Eingabe-Parameter bekommen, diese müssen vom Typ mit der Definition übereinstimmen.

9. Rekursion

Folgende Zeilen sind ein Beispiel für Rekursion:

with adalogo;
use adalogo;

procedure foobar is
  procedure viele_quadrate(kante : integer) is
  begin
    for i in 1..4 loop
      forward(kante);
      turn(90);
    end loop;

    if kante > 42 then
      viele_quadrate(kante-5);      
    elsif kante < -84 then
      null;
    else 
      viele_quadrate(kante-5);      
    end if; 
  end;
begin
  viele_quadrate(84);
  viele_quadrate(42);
  turn(90);
  viele_quadrate(84);
  viele_quadrate(42);
end;
Innerhalb der Prozedur viele_quadrate ruft die Prozedur sich selbst auf. Zu beachten ist, dass Sie für eine Abbruch-Bedingung sorgen müssen, da ansonsten eine endlose Rekursion entsteht. Ein anderes Beispiel für rekursives Aufrufen, finden Sie im Beispiel hilbert. Es ist auch möglich zwei oder mehr Prozeduren zu definieren, die sich gegenseitig aufrufen. Entnehmen Sie aus der Informatik-Vorlesung, wann eine Prozedur A eine Prozedur B aufrufen kann und wann nicht. Hierbei spielt die Sichtbarkeit eine Rolle, die bei Unterprozeduren nicht immer gegeben sind. Die Sichtbarkeit zu erklären würde den Rahmen dieser Seite sprengen.