Mit Pure Pascal kommt der erste Pascal-Compiler für den Atari auf den Markt, der auch objektorientierte Programmierung erlaubt. Unser Kurs führt Sie in fünf Etappen durch die Welt der Typen, Funktionen und Prozeduren. Mit der Demo-version von Pure Pascal [1] sind Sie von Anfang an hautnah dabei.
Der gesamten Atari-Gemeinde lief ein eiskalter Schauer über den Rücken, als bekannt wurde, daß Borland den Klassiker Turbo C für den Atari ST/TT aus seinem Programm streichen würde. So kam Erleichterung auf, als Application Systems verkündete, den Support für dieses erfolgreiche Entwicklungspaket zu übernehmen, das fortan auf den Namen »Pure C« hörte. Doch damit hatte man nicht genug: Die Programmiersprache »Pure Pascal« wurde vorgestellt.
Analog zu Pure C ist Pure Pascal weitgehend zum MS-DOS-Kollegen Turbo Pascal 6.0« kompatibel, enthält also erstmals auf dem Atari-Sektor die Elemente der objektorientierten Programmierung. In der Juni-Ausgabe der TOS hatten Sie bereits die Gelegenheit, erste Gehversuche unter Pure Pascal anhand der auf der TOS-Disk enthaltenen Demoversion zu unternehmen. Dieser fünfteilige Kurs hilft Ihnen zum richtigen Einstieg.
Zunächst wollen wir uns mit den Grundlagen der Sprache Pascal befassen, wobei wir auch auf die .spezielle Entwicklungsumgebung von Pure-Pascal eingehen. Starten Sie bitte die Entwicklungsumgebung von Pure Pascal. Auf dem Pure-Pascal-Desktop klicken Sie nun doppelt auf das Laufwerk, auf dem Sie Ihren Quelltext ablegen wollen. Wie auf dem GEM-Desktop erscheint nun ein Fenster mit den vorhandenen Dateien und Verzeichnissen. Durch Doppelklicken auf die Verzeichnisnamen schwingen Sie sich in Tarzan-Manier durch den Ordner-Dschungel. Wählen Sie nun aus dem Menü »File« den Eintrag »New File ... « zum Anlegen einer neuen Datei und geben Sie als Dateinamen »HELLO.PAS« ein. Schon erscheint ein Fenster, in dem Sie nun bitte folgende Zeilen eingeben:
(* Demoprogramm »Hello World! *)
PROGRAM Hello;
BEGIN
WRITELN ('Hello world!');
END.
{ Ende der Demo }
Diese Datei speichern wir nun durch »Save« aus dem »File«-Menü oder die Tasten CTRL + S und starten das Programm mit »Run« aus dem gleichnamigen Menü oder drücken ALTERNATE + R Das Programm ist mit seiner Arbeit jedoch so schnell fertig, daß wir kein Resultat sehen können, sondern sofort in die Entwicklungsumgebung zurückkehren. Betätigen Sie einfach die ESCAPE-Taste, um das Resultat der Ausgabe zu sehen:
»Hello world!«.
In Bild 1 sehen Sie den grundlegenden, eigentlich sehr simplen Aufbau eines Pascal-Programms. Nach dem Programmkopf, der zweiten Zeile des obigen Programmes, folgt der sogenannte »Block«. Der Dezimalpunkt ».« dient als Endemarke eines Programms. Kommentare dürfen beliebig lang sein und sind durch »(* ... *)« bzw. »{ ... }« einzugrenzen.
In den Syntaxdiagrammen sind druckbare Zeichen übrigens rund umrandet. Die anderen Symbole können wir weiter verfeinern: Der Deklarationsteil enthält Deklarationen von Variablen, Konstanten, Typen oder Prozeduren und Funktionen. Der Block besteht aus einem »Deklarationsteil« und einer »zusammengesetzten Anweisung«, welche die eigentlichen Befehle enthält, eingegrenzt durch die Schlüsselworte »BEGIN« und »END«. Nach jedem Befehl folgt ein Semikolon, das beim letzten Befehl nicht unbedingt erforderlich ist.
In Pascal realisieren Sie Dinge, die in Sprachen wie Basic oder C nicht auf gleiche Weise machbar sind. Ein Beispiel sind lokale Prozeduren, auf die wir in der nächsten Folge eingeben. Doch verwenden wir nun dieses Gerüst, um ein zweites, nicht ganz so triviales Programm zu erstellen. Nehmen wir an, wir wollen den Umfang eines Kreises nach der Eingabe des Radius berechnen. Zur Berechnung benötigen wir die die Zahl Pi, die wir uns deshalb als Konstante deklarieren, also beim Compiler anmelden. Dies geschieht im Deklarationsteil des Blocks, der mit dem Schlüsselwort »CONST« eingeleitet wird. Hierbei geben wir zunächst den Konstantennamen, ein Gleichheitszeichen und darauf den Dezimalwert in der üblichen Notation an.
Exponentialschreibweise ist übrigens auch erlaubt: 314.1592654E-2. Namen müssen unter Pure Pascal mit Buchstaben oder dem Unterstrich beginnen und können zusätzlich Dezimalziffern enthalten. Zwischen Groß- und Kleinschreibung wird nicht unterschieden! Neben der dezimalen Konstanten deklarieren wir auch eine Zeichenketten-Konstante, wobei wir den Text in einfache Anführungszeichen setzen:
PROGRAM Umfangberechnung;
CONST PI = 3.141592654;
Anfrage ='Radius: ';
Nun wollen wir den Umfang nach Eingabe des Radius berechnen. Deshalb benötigen wir noch Objekte, in denen wir den Radius und den Umfang speichern können: sogenannte »Variablen«. Im durch das Schlüsselwort »VAR« eingeleiteten Variablendeklarationsteil verwenden wir zwei Variablen für Fließkommazahlen, die auf den Typennamen »REAL« hören. In der Deklaration geben wir einfach die Variablennamen - getrennt durch Kommata - an. Nach einem Doppelpunkt bestimmen wir durch das entsprechende Schlüsselwort den Variablentyp:
VAR radius, umfang: REAL;
Somit hätten wir den Deklarationsteil abgeschlossen und kommen zur zusammengesetzten Anweisung, die wir mit »BEGIN« einleiten und in der wir zunächst eine Aufforderung zur Eingabe ausgeben. Dazu bietet sich die WRITE-Anweisung an, mit der wir Zahlenwerte oder Texte ausgeben, in unserem Fall die deklarierte Textkonstante. Das auszugebende Objekt setzen wir in Klammern.
BEGIN
WRITE(Anfrage);
Wie die anderen, nachfolgend vorgestellten »Standardprozeduren« stellt Pascal die Prozedur »WRITE« von Haus aus - also ohne das Verwenden externer Bibliotheken - zur Verfügung. Ähnlich wie Basic bietet Pascal eine Reihe von Prozeduren und Funktionen für Ein-/Ausgabe, mathematische Operationen und andere Bereiche. Das Einlesen des Radius erledigt die Prozedur »READLN«, welche die Eingabe eines Wertes über die Tastatur erwartet. Als Parameter übergeben wir den Namen der Variable, in der wir den eingegebenen Wert ablegen möchten.
READLN(radius);
Nun berechnen wir den Radius innerhalb einer Zuweisung. In Pascal stehen die üblichen Standard-Rechenoperationen für REAL-Fließkommawerte zur Verfügung Das Zuweisungssymbol unterscheidet sich jedoch von Basic oder C: Es ist der Doppelpunkt in Verbindung mit einem Gleichheitszeichen:
umfang := 2 * PI * radius;
Zuletzt geben wir den berechneten Umfang aus, voran setzen wir eine Textausgabe. Wir verwenden die »WRITELN«-Prozedur, die einen Zeilenvorschub nach der Ausgabe durchführt. Zwischen die Prozedurparameter setzen wir ein Komma. Die Anweisung »END.« beendet das Programm.
WRITELN ('Umfang: ', umfang)
END.
Für REAL-Zahlenwerte stellt uns Pascal eine Reihe vordefinierter Standardfunktionen zur Verfügung: Sinus SIN(x), Cosinus COS(x), Arcustangens ARCTAN(x), natürlicher Logarithmus LN(x), e-Funktion EXP(x) und die Quadratwurzel SQRT(x):
wurzelvonzwei := SQRT(2);
Pascal bietet jedoch eine Vielzahl weiterer Datentypen. So können wir auch die aus GFA-Basic und C bekannten Ganzzahlvariablen verwenden. Diese heißen »INTEGER« und besitzen den Wertebereich von -32768 bis 32767. Neben der Dezimalnotation können wir Zahlenwerte auch hexadezimal angeben, indem wir das Dollarzeichen vor die Konstante setzen:
wert := $abc;
Als Divisionsoperator verwenden wir das Schlüsselwort »DIV« anstatt des Schrägstrichs »/«, eine Divisionsrestbestimmung erledigt der Operator »MOD«:
VAR quotient, rest, dividend, divisor: INTEGER;
dividend := 9; divisor :=4;
quotient := dividend DIV divisor;
rest := dividend MOD divisor;
In diesem Beispiel erhalten wir einen Quotienten von 2 und einen Rest von 1. Mit der »INC(x)«-Operation erhöhen wir x um eins, mit »DEC(x)« erniedrigen wir die Variable. Die »ABS(x)«-Funktion sorgt für den absoluten Wert einer Zahl (ABS (-10) = 10), SQR(x) liefert das Quadrat des Operanden. Mit dem »SHL«-Operator lassen wir die Bits einer Zahl um die nachfolgend angegebene nach links rotieren, mit »SHR« nach rechts. Die Anweisungen »AND«, »OR«, »XOR« und »NOT« dienen der logischen Bit-Verknüpfung.
wert1 := ABS (-7); (* Ergibt 7 *)
wert2 := SQR (8); (* Ergibt 64 *)
INC (wert2); (* Ergibt 65 *)
wert1 := 1 SHL 4; (* Ergibt %10000 = 16 *)
wert2 := wert1 SHR 2; (* Ergibt %100 = 4 *)
wert1 := 1 OR 2; (* Ergibt %11 = 3 *)
wert2 := wert1 XOR 1; (* Ergibt %10 = 2 *)
wert1 := 7 AND 9; (* Ergibt 1 *)
wert1 := NOT 2; (* Ergibt %1111111111111101 *)
Pure Pascal bietet weitere Ganzzahltypen an, die andere Zahlenbereiche abdecken und die Operationen des INTEGER-Typs erlauben: »SHORTINT« (- 128 bis 127), »LONGINT« (-2147483648 bis 2147483647), »BYTE« (0 bis 255) und »VVORD«(0 bis 65535). Der Datentyp »BOOLEAN« dient zum Ablegen eines Wahrheitswertes und kann somit nur die Zustände »TRUE«und »FALSE« annehmen, weshalb er nicht über die Standardfunktionen ausgegeben werden kann. Wir können BOOLEAN-Variablen aber beispielsweise das Resultat eines Vergleichs zuweisen:
VAR istwahr: BOOLEAN;
istwahr := (wert1 > wert2);
Numerische Vergleiche sind in Pascal übrigens ähnlich wie in Basic mit den Operationen größer/kleiner (>/<), größer-/kleinergleich (>=/<=)oder gleich/ungleich (=/<>) möglich, wobei beide Operanden vom gleichen Datentyp sein müssen. Mit der logischen AND-Verknüpfung (logisches UND) erhalten wir nur dann ein wahres Resultat, wenn beide verknüpften Teile wahr sind. Bei der OR-Verknüpfung (logisches ODER) ist das Resultat wahr, wenn mindestens eines der Argumente wahr ist. Das Resultat können wir mit dem NOT-Operator (logisches NICHT) umkehren. In der üblichen Weise können wir durch Klammerung Prioritäten setzen:
istwahr := (test = minwert) AND (test = maxwert)
istwahr2 := NOT ((test = minwert) OR (test = maxwert));
Eine Sonderstellung nimmt die Funktion ODD(x) ein, mit der Sie den Ausdruck x auf Ungeradheit testen:
istwahr := ODD (1); (* Ergibt TRUE *)
Zum Ablegen von Zeichen verwenden wir den Variablentyp »CHAR«. Das zuzuweisende Zeichen setzen wir in einfache Anführungszeichen.
VAR kuerzel : CHAR;
...
kuerzel := 'F';
... WRITELN( 'Kürzel: ', kuerzel);
Zeichenketten legen wir in »STRING«-Variablen ab, deren maximale Länge wir bei der Deklaration in eckigen Klammern angeben:
VAR text := STRING[80]
READLN (text);
Interessant ist der Aufzählungstyp: Nehmen wir an, wir wollten für eine Auto-Datenbank die Automarke speichern. Da diese zu einer endlichen Zahl von Marken gehört, erlauben wir für diese Variable eine Reihe von möglichen Marken, die wir einfach in runde Klammern einschließen und durch Kommata trennen:
VAR marke: (Fiat, Audi, VW, Mercedes, BMW)
marke := Fiat;
Mit Aufzählungsvariablen können wir weder rechnen, noch sie direkt mit einer Standardfunktion auf dem Bildschirm ausgeben. Sie erlauben lediglich logische Operationen wie Vergleiche und erhöhen die Lesbarkeit Ihrer Programme. Nützlich ist auch der Unterbereichs-Datentyp, mit dem wir eine Teilmenge eines bereits bestehenden Datentyps verwenden. Variablen dieses Datentyps deklarieren wir unter Angabe der oberen und unteren Bereichsgrenzen, getrennt durch zwei Dezimalpunkte:
VAR Alphabet: 'A'..'Z'
EinsBisHundert: 1..100;
Die vielen Datentypen bringen jedoch Probleme bei der Konvertierung: Wir können nicht einfach REAL-Variablen den INTEGER-Variablen (der umgekehrte Weg ist kein Problem) zuweisen, sondern müssen diese vorher mit »ROUND(x)« runden. Als Alternative steht der »TRUNC«-Operator zur Verfügung, der einfach die Nachkommastellen streicht:
intwert := ROUND (28.66); (* Ergebnis: 29 *)
intwert := TRUNC (28.66); (* Ergebnis: 28 *)
Möchten wir eine INTEGER-Variable, die im Bereich von 0 bis 255 liegen muß, in Typ CHAR wandeln, verwenden wir »CHR(x)«. »x«enthält dabei den ASCII-Wert des gewünschten Zeichens.
zeichen := CHR (70); (* ASCII-Wert für 'F' *)
Den umgekehrten Weg gehen wir mit Hilfe von »ORD(x)«, das die Position des Operators in der Menge der möglichen Elemente als numerischen Wert zurückgibt. wert := ORD ('F'); liefert den Wert 70. Dies können wir auch auf alle anderen Datentypen - ausgenommen REAL - anwenden. ORD (Fiat) würde so beispielsweise den Wert 0 zurückliefern. ORD (TRUE) ist stets 1, ORD(FALSE) immer 0.Eine sehr flexible, aber deshalb auch gefährliche Möglichkeit zur Typkonvertierung ist das auf alle Typen anwendbare »Typecasting«: Die Typumwandlung erreichen wir durch Voranstellen des gewünschten Typennamens vor das zu klammernde, konvertierende Objekt:
zeichen := CHAR (wert);
Nützlich ist auch die Funktion »PRED(x)«, mit der wir stets den Vorgänger von x zurückerhalten, SUCC(x) liefert analog den Nachfolger, weshalb marke := SUCC (Fiat); zur Marke Audi führt.
Nachdem wir nun endlich die beeindruckende Vielfalt der einfachen Datentypen unter Pascal kennen, werfen wir einen Blick auf die Kontrollstrukturen, die sogenannten »strukturierten Anweisungen« (siehe Bild 2). Der wichtigste Vertreter ist die zusammengesetzte Anweisung, die wir bereits in Bild 1 kennengelernt haben: Statt einer einzelnen Anweisung fassen wir eine Folge von Anweisungen mit BEGIN und END zusammen.
Von nicht geringerer Bedeutung ist die »IF«-Anweisung: Auf das Schlüsselwort IF folgt ein Ausdruck vom Typ BOOLEAN, also ein Vergleich oder eine BOOLEAN-Variable, darauf das Schlüsselwort THEN und eine Anweisung, die bei erfüllter Bedingung bearbeitet wird:
IF eingabewert > 5 THEN WRITELN ('Wert > 5');
Möchten wir eine Anweisung anfügen, die bei nicht erfüllter Bedingung ausgeführt wird, so fügen wir sie mit dem Schlüsselwort »ELSE« an. Hierbei ist unbedingt darauf zu achten, daß der Befehl vor dem ELSE nicht mit einem Semikolon abgeschlossen ist:
IF marke = Fiat THEN BEGIN
WRITELN ('Es ist ein Fiat');
WRITELN ('Ein waschechter Italiener');
END
ELSE WRITELN ('Es ist ein Deutscher');
Auch die »FOR«-Anweisung ist in den gängigen Konkurrenzsprachen vorhanden: Für eine Variable wird ein angegebener Wertebereich in Schritten von eins durchlaufen, wobei jeweils der folgende Schleifenblock ausgeführt wird. In Pascal folgt auf das Schlüsselwort FOR der Name der Zählvariablen, ein Gleichheitszeichen und der Startwert. Nach dem Schlüsselwort »TO« beim Hochzählen bzw. »DOWNTO« beim Herunterzählen folgt der Endwert und das Schlüsselwort »DO«. Jetzt folgt der auszuführende Block:
FOR buchstabe := 'Z' DOWNTO 'A' DO BEGIN
WRITE(buchstabe);
WRITE(':');
END;
Diese Zeile gibt das Alphabet in umgekehrter Reihenfolge aus, getrennt durch Doppelpunkte. Die »REPEAT«-Anweisung wiederholt die eingeschlossene Befehlsfolge solange, bis eine Bedingung erfüllt ist. Diese Bedingung steht hinter dem mit »UNTIL« abgeschlossenen Befehlsblock, der stets mindestens einmal durchlaufen wird, weshalb wir von einer nicht abweisenden Schleife sprechen:
REPEAT
WRITE ('Wert eingeben (1-100): ');
READLN (wert);
UNTIL (wert >= 1) AND (wert <= 100);
Die »WHILE«-Schleife ist hingegen eine abweisende Schleife, die das Programm nur bei Erfüllung einer Bedingung bearbeitet. Ist die Bedingung nicht mehr erfüllt, wird die Schleife kein weiteres Mal durchlaufen. Hinter der Anweisung WHILE, dem BOOLEAN-Ausdruck und dem Schlüsselwort DO folgt der auszuführende Befehl:
pausenwert := 10000;
WHILE pausenwert > O DO DEC (pausenwert);
(* Warteschleife *)
Pascal unterstützt auch direkte GOTO-Sprünge, wenngleich der Programmierer sehr sparsam damit umgehen sollte, um den gefürchteten »Spaghetti-Code« zu verhindern. Sprünge sind immer nur innerhalb eines Blocks möglich, wobei das Sprungziel mit einer Marke zu kennzeichnen ist, dem sogenannten »Label«. Er ist im Deklarationsteil anzumelden. Am Sprungziel im Quelltext setzen wir den Labelnamen, gefolgt von einem Doppelpunkt.
LABEL endmarke;
...
IF wert < 0 THEN GOTO endmarke;
...
endmarke: END.
Der Befehl »CASE« unterscheidet verschiedene Fälle. Hinter dem Schlüsselwort CASE setzen wir den zu untersuchenden Ausdruck und das Schlüsselwort OF. Nun geben wir eine Folge von Werten an, die gegebenenfalls durch Kommata getrennt sind. CASE gestattet auch Unterbereichstypen. Nach einem Doppelpunkt folgt der mit einem Semikolon abgeschlossene Befehl, der ausgeführt wird, wenn die Variable den angegebenen Wert enthält oder dieser im angegebenen Bereich liegt. END schließt das gesamte Konstrukt ab:
READLN(wert);
CASE wert OF 1..10: WRITELN ('1-10');
0, 11: WRITELN ('O oder 11');
END;
Auf der TOS-Diskette finden Sie einfache Beispiele zu den besprochenen Themen. Im nächsten Kursteil wagen wir uns an Prozeduren, Funktionen und komplexe Datentypen und werfen einen genaueren Blick auf die Standardprozeduren und -funktionen von Pure Pascal. (ah)
[1] Die Demoversion von Pure Pascal finden Sie auf der TOS-Diskette zur Ausgabe 6/92