Cluster Kurzeinführung: ======================= Compiler Tastaturkürzel: ------------------------ F6 Laden F8 Compilieren ALT + F8 Prg starten Shift + F6 Text speichern Ctrl + F9 OldState speichern ALT + F9 OldState laden Shift + -> ans Zeilenende Shift + <- zum Zeilenanfang ALT + Pfeil nach oben/unten Seitenweise blättern Ctrl + Pfeile hoch/runter Fenster wechseln ALT + F1 Zeile löschen F1 Zeile einfügen F3 suchen Ctrl + F3 suchen und ersetzen F4 Paste Shift + F4 Copy ALT + F4 Block ausschneiden A + F4 schneidet aus und fügt bei Cursor ein A + F6 entfernt Fenster - Cluster unterscheidet strikt zwischen der Groß- Kleinschreibung. - Ein Semikolon trennt Anweisungen voneinander. - Ein ASCII-Code wird mit einem & davor definiert (&27 = ESC) 1 Variablen: (Speicherstellen im Rechner) ---------- CARDINAL 0 - 65535 2 Byte LONGCARD 0 - 4294967295 4 Byte SHORTCARD 0 - 255 1 Byte INTEGER -32768 - 32767 2 Byte LONGINT -2147483648 - 2147483647 4 Byte SHORTINT -128 - 127 1 Byte Operatoren: + - * DIV MOD < > <= >= = # (ungleich) mit -DIV wird eine ganzzahlige Division (nur Vorkommastelle) -MOD wird der ganzzahlige Rest einer Operation ausgegeben. REAL jede rationale Zahl (bis Mantisse 8 Stellen) 4 Byte LONGREAL jede rationale Zahl (Mantisse 15 Stellen) 8 Byte Operatoren: + - * / ^ < > <= >= = # (ungleich) Zahl = Mantisse * 10 ^ Exponent -------------------------------------------------------------------------------- 1737524.0000 = 1.737524 * 10 ^ 6 -101.3537 = -1.013537 * 10 ^ 2 5.13 = 5.13 * 10 ^ 0 0.05243 = 5.243 * 10 ^ -2 -0.00004254 = -4.254 * 10 ^ -5 Achtung, bei Kick 1.3 TYPE REAL = FFP BOOLEAN TRUE und FALSE 1 Byte Operatoren: AND OR NOT Überprüfung mit = und # (ungleich) 2 CHAR Alle ASCII-Zeichen 1 Byte Operatoren: < > <= >= = # (ungleich) Diese Variable kann immer nur ein Zeichen aufnehmen. Typenkonvertierung: In einem Ausdruck darf bei Cluster nur immer ein Variablentyp vorkommen. Bei einer Multiplikation von einer INTEGER und einer REAL Zahl wird folgendermaßen verfahren: VAR a : INTEGER; b,c : REAL; .......... c:=REAL(a)*b; | INTEGER a wird nach REAL konvertiert Anmerkung: Bei REAL nach INTEGER wird die Nachkommastelle abgeschnitten. Variablendeklaration: --------------------- Die Deklaration beginnt mit VAR es folgen die globalen Variablen mit dem Typ. x : INTEGER; y,y0,y1 : REAL; zeichen : CHAR; wohnort : STRING(30); jaOderNein : BOOLEAN; WebiString : String1; | selbstdefinierter Typ Variable und Typ werden durch : (Deklarationsoperator) getrennt. Variablen können durch Komma getrennt werden, einzelne Deklarationen werden durch Semikolen getrennt. Ferner kann auch ein Wert direkt mit angegeben werden. VAR heute : INTEGER := 10; morgen : REAL := 123.56; 3 Programmstruktur: ----------------- MODULE PRG_Name; FROM InOut IMPORT WriteInt; VAR a,b,c : INTEGER; BEGIN a:=10; b:=23; c:=a+b; WriteInt(c); | für Bildschirmausgabe END PRG_Name. Konstantendeklaration: ---------------------- Die Konstanten CONST stehen vor einer Prozedur, der Varibledeklaration oder dem Hauptprogramm. CONST Pi = 3.14; MwsT = 15; VAR ............ Typendeklaration: ----------------- TYPE String32 = STRING(32); NewInt = INTEGER; Tester = BOOLEAN; VAR ............ 4 Selbstdefinierte Typen: ----------------------- Diese werden mittels TYPE deklariert oder mit einem Doppelpunkt in der Variblendeklaration. TYPE INDEX = CARDINAL; SALDO = REAL; ZAEHLER = INDEX; | ZAEHLER ist vom Typ INDEX, also CARDINAL VAR i: INDEX; j: INDEX; k: INDEX; Überfällig, Angemahnt: SALDO; zaehl: ZAEHLER; Falls noch 23 Variablen vom Typ INDEX deklariert werden und auf einmal für diese Variablen negative Werte benötigt werden, so brauch man nur die Definition INDEX auf INTEGER ändern. Unterbereichstyp: (selbstdefinierter Typ) ----------------- Bevorzugt für CHAR und INTEGER, nicht zu verwenden für REAL (=unzählbar). Es werden Bereiche (von-bis) definiert oder auch eingeschränkt. TYPE GrossBuchstaben = ["A".."Z"]; Monate = [1..12]; oder [10] für 0 bis 10. Aufzählungstyp: (selbstdefinierter Typ) --------------- Beim Aufzählungstyp sind sogenannte Bezeichner die Werteträger. TYPE Monate = (Januar, Februar, Maerz, April, Mai, Juni, Juli, August, September, Oktober, November, Dezember); Januar, Februar, Maerz etc. sind keine Textstrings, sondern Werte, die diesen Namen tragen. Diese sind vergleichbar, vor und zurück gehbar, sowie in einer Schleife verwendbar. Es lassen sich auch Unterbereiche bilden: TYPE Monate = (Januar, Februar, Maerz, April, Mai, Juni, Juli, August, September, Oktober, November, Dezember); Sommer = [Juli..September]; Winter = [Januar..Maerz]; VAR m : Monate; s : Sommer; w : Winter; ........ Programmaufbau: --------------- MODULE FROM ... IMPORT ... VAR CONST TYPE PROCEDURE VAR BEGIN END BEGIN CLOSE END IMPORT-Teil: ------------ Möglichkeiten: IMPORT Graph Graph; hier werden alle definitionen aus einem Modul importiert, dies kann zu Namens- konflikten führen (unqualifizierter Import). Hier kann nicht direkt auf die importierten Module zugegriffen werden, sondern nur in Verbindung über ihren Modulnamen: Hier muß auf das Modul DrawPixel mit Graph.DrawPixel zugegriffen werden. Namensänderung beim Import: FROM Bibliothek AS BB IMPORT Graph AS Gr; Es werden zwei Objekte qualifiziert inportiert und der Rest unqualifiziert: FROM InOut AS io IMPORT WriteString, WriteLn; ....... Zugriff auf qualifizierten import mit WriteString WriteLn auf die unqualifiziert importierten io.ReadInt io.WriteInt Im Verzeichnis Modul-Texte kann man sich z.B. die Proceduren des Modules InOut anschauen und deren Funktionen für den eigenen Gebrauch ableiten. 7 Schleifenstrukturen: -------------------- REPEAT ... UNTIL Schleifenabarbeitung bis boolesche Ausdruck wahr (TRUE) wird. Abbruch- bedingung am Ende der Schleife. REPEAT a:=a+1 UNTIL a>10; WHILE ... DO ... END Die Abbruchbedingung steht am Anfang der Schleife. Falls die Bedingung schon vorher erfüllt war, wird die Schleife erst gar nicht ausgeführt. Die Schleife wird so lange ausgeführt, wie die Bedingung erfüllt ist. Sie wird erst abge- brochen wenn die Bedingung FALSE ist | Eingabe von von "Anzahl" WHILE Anzahl # 0 DO c:=a*b+2; s:=s+c; DEC(Anzahl) END; FOR ... DO ... END Hier steht fest, wie oft die Schleife wiederholt werden soll. ReadInt(n); summe:=0; FOR i:=1 TO n DO summe:=summe+i END; BY gibt die Schrittweite für die Steuerungsvarriable an, ohne diese wächst der Wert um 1 ReadInt(n); summe:=0; FOR i:=1 TO n BY 2 (* Schrittweite+2 *) DO summe:=summe+i END; IF ... THEN ... ELSE Über den ersten booleschen Ausdruck wird entschieden, welcher Programmteil weiter bearbeitet werden soll. IF Gehalt<3000 THEN Gehalt:=Gehalt+100 ELSE Gehalt:=Gehalt+50 END; Sollen viele verschiedene Fälle geprüft werden so gibt es folgende varianten: IF Alter=24 THEN Gehalt:=Gehalt+100 OR_IF Alter=25 THEN Gehalt:=Gehalt+200 OR_IF Alter>24 THEN Gehalt:=Gehalt+300 ELSE Gehalt:=Gehalt+50 END; (ein AND_IF wird vom Compiler schneller bearbeitet und es gibt einen besseren Code.) IF Alter=24 THEN Gehalt:=Gehalt+100 AND_IF Alter=25 THEN Gehalt:=Gehalt+200 ELSE Gehalt:=Gehalt+50 END; Wertevergleich ist auch so sehr schnell möglich: IF c OF "a","b","c" THEN ..... IF i OF 1,2,3,4,5,6 THEN ..... oder IF c NOT OF "a","b","c" THEN ..... Es können hier auch Variablen eingesetzt werden, die mit Werten verglichen werden. Fälle, die mit einem Schlüssel geprüft werden, sehen so aus: IF KEY a OF 1,-10,-5 THEN ..... END OF 2..10 THEN ..... END OF 11..20 THEN ..... END ELSE ..... END; Folgendes Programm prüft, ob ein Zeichen in c ein großer bzw. kleiner Buch- stabe oder eine Zahl ist: IF KEY c OF "a".."z","ä","ö","ü","ß" THEN WriteString("Kleiner Buchstabe"); WriteLn END OF "A".."Z","Ä","Ö","Ü" THEN WriteString("Großer Buchstabe"); WriteLn END OF "0".."9" THEN WriteString("Dat is ne Zahl"); WriteLn END ELSE WriteString("Unklares Zeichen"); WriteLn END; 10 Weitere Schleifenarten: ----------------------- WHILE-Struktur: WHILE KEY xxx OF xxx1 AND_WHILE Bool-yyy DO Anweisung1 END OF xxx2 DO Anweisung2 END ELSE Anweisung3 END LOOP: LOOP ...Anweisungsfolge END; WITH-Struktur: Mit dieser Schleife lassen sich auch gleichzeitig Variablen umbennen und bei Angabe eines Typs wird eine neue Variable erzeugt. WITH Voll_der_lange_Name AS vN1, Noch_ein_langer_Name AS VN2, rec.array[6] AS i, | neue Variable Ptr^.field[i]^.elem^ AS c DO ...... END; 11 Standardfunktionen: ------------------- z.B.: SUCC(3) = 4 PRED("B") = A SIN(x), COS(x), TAN(x), ASIN(x), ACOS(x), ATAN(x), SINH(x), COSH(x), TANH(x), SQRT(x), EXP(x), LN(x), LOG(x), ABS(x), ODD(x), PRED(x), SUCC(x), CEIL(x), FLOOR(x), INC(x), INC(x,y), DEC(x), DEC(x,y), EVEN(x) 12 Prozeduren: ----------- Eine Prozedur ist im Prinzip ein kleines Programm, welches von anderen Programmen aufgerufen werden kann. Der Prozedurname wird zu einer selbstdefinierten Anweisung. PROCEDURE GutenTagSagen; BEGIN WriteString("Guten Tag, Loser !") END GutenTagSagen; ......... BEGIN | Hauptprogramm ......... IF a=1 THEN GutenTagSagen END; ......... Variablen, die innerhalb einer Prozedure definiert wurden, gelten auch nur innerhalb dieser. Man nennt diese lokale Variablen. Variablen, die im Hauptprogramm deklariert wurden nennt man globale Variablen. Diese Variablen sind in Prozeduren, sowie außerhalb dieser immer verfügbar. Namensgleichheit von lokalen und globalen Variablen sind möglich, da nach Bereichen abgearbeitet wird. Innerhalb des Prozedur-Bereiches gilt nur die dort definierte Variable. Innerhalb von Prozeduren können weitere Prozeduren definiert weden, die lokale Prozeduren genannt werden. Sie können nur innerhalb der Prozedur aufgerufen werden, in der sie definiert wurden. Man kann auch innerhalb von Prozeduren Module importieren. Man kann auch einer Prozedur Werte auf den Weg geben = Prozedur mit Über- gabewerten. Diese können Werteparameter (call by value) sein oder Variable- parameter (call by reference). Bei den Variableparametern steht ein VAR davor. Werteparameter werden in den Prozeduren nicht mehr verändert. Es wird zwar mit ihnen innerhalb der Prozedure gearbeitet und gerechnet, aber nach Abarbeitung der Prozedure nehmen diese Parameter wieder ihren ursprünglichen Wert an (es wird mit Kopien gearbeitet). Variableparameter werden verändert und es wird der neue Wert ausgegeben. Variableparameter die verändert werden, sind auch über die Prozedur hinaus gültig (oder behalten ihren Wert) 13 Gibt man REF vor den Parametern an, wird nichts verändert, und es wird auch nicht mit Kopien gearbeitet. Variablen eines gleichen Typs werden mit Komma getrennt angegeben: PROCEDURE Name(a,b,c,d:INTEGER); Variablen verschiedener Typen werden durch Semikolen getrennt: PROCEDURE Name(i,j:INTEGER;oo,pp:REAL); PROCEDURE NeuerName(VAR help:CHAR;zaehler:CARDINAL); PROCEDURE Pro3(REF k:BOOLEAN;VAR kaelte:REAL); Es besteht die Möglichkeit Default-Werte zu definieren, sie werden automatisch übernommen, wenn keine Übergabeparameter gesetzt wurden. PROCEDURE Defwerte(val : LONGINT;breite : INTEGER:=0); Diese Prozedur wird aufgerufen mit: Defwerte(10,4) oder Defwerte(41) Bei vielen Parametern muß die Zuweisung durch Schlüsselwörter vorgenommen werden: PROCEDURE DefNeu(wert : INTEGER, flag1,flag2 : BOOLEAN:=FALSE, breite : INTEGER:=640; hoehe : CARDINAL:=512); DefNeu(10,TRUE,FALSE,320,256); DefNeu(5,breite:=320); DefNeu(8,breite:=320,hoehe:=250); STATIC-Variablen: STATIC Variablen können nur innerhalb einer Prozedur verwendet werden, sie überleben die Prozedur und haben beim nächsten Aufruf noch den selben Wert. Sie können einmal am Programmanfang vorinitialisiert werden. 14 PROCEDURE statictest(); VAR test1 STATIC : INTEGER; test2 STATIC := 10; BEGIN .......... END statictest; Funktionsprozeduren: -------------------- Das Ergebnis einer Prozedur kann nicht direkt an eine andere übergeben werden, sondern nur mittels einer Variable. Funktionsprozeduren sind Prozeduren, die direkt ein Ergebnis zurückgeben können. Standardfunktionen sind Funktions- prozeduren. Die Art des Typs, den eine Funktion zurückgeben soll, wird mittels eines Doppel- punktes hinter der Parameterliste, anstatt eines Semikolon, gefolgt von dem gewünschten Typ, und abschließendem Semikolon festgelegt. Der Wert der innerhalb einer Prozedur als Ergebnis zurückgegeben werden soll, wird mittels RETURN zurückgegeben. Ein RETURN innerhalb von normalen Prozeduren führt zum sofortigen Verlassen derselben. Werte, die nicht mehr gebraucht werden, können mit FORGET Test() | Boolvariable entfernt werden. MODULE Quadratwurzel_berechnen; FROM InOut IMPORT ReadReal, WriteLn, WriteString, WriteReal; VAR i : REAL; PROCEDURE Quadratwurzel(a:REAL):REAL; BEGIN RETURN SQRT(a) END Quadratwurzel; BEGIN WriteString("Positive Zahl eingeben: "); ReadReal(i); WriteLn; WriteReal(Quadratwurzel(i),10,3); END Quadratwurzel_berechnen. Felder & Mengen: ---------------- Die Menge: ---------- Eine Menge kann beliebige Elemente aus einer Grundmenge enthalten oder leer sein. Jedes Element darf höchstens einmal vorkommen. Enthält eine Menge nicht alle Elemente der Grundmenge, so nennt man diese Teilmenge der Grundmenge. In Cluster ist der Typ eine Menge die Grundmenge. Diese muß ein zählbarer Typ mit maximal 32 Elementen, also ein Unterbereichs- oder Aufzählungstyp sein. TYPE Monate = (Januar, Februar, Maerz, April, Mai, Juni, Juli, August, September, Oktober, November, Dezember); MonSet = SET OF Monate; Eine Konstante dieses Typs wird durch Aufzählen der enthaltenen Elemente gebildet: CONST SomerMonate = MonSet:{Juli, August, September}; Ob ein Element in der Menge vorhanden ist, prüft man mit IN: VAR Mons : MonSet; ... IF Juni IN Mons THEN ... END; INCL(Mons,Juni); fügt in die Menge "Mons" den Juni ein. EXCL(Mons,Januar); entfernt den Januar aus der Menge "Mons" UNI(Mons,{Juni,August}); fügt in die Menge "Mons" die Menge {Juni,August} ein. SEC(Mons,{Juni,August}); entfernt aus der Menge "Mons" die Menge {Juni,August}. Das ARRAY: ---------- Variablen gleichen Typs werden in einer Variable zusammengefasst. Mittels eines Index können die einzelnen Elemente angesprochen werden. TYPE IntArray = ARRAY [1..10] OF INTEGER; |Definition einer eindeminsionalen Tabelle. VAR Int : IntArray; int[1] := 100; |weist Feld 1 den Wert 100 zu. oder auch int[1]:=int[2]; int[3]:=int[1]+int[7]; Man kann auch Arrays von Array bilden: TYPE Matrix = ARRAY [1..10] OF ARRAY [1..10] OF INTEGER; |100 indizierbare Felder. VAR mat : Matrix; oder auch TYPE Matrix = ARRAY [1..10],[1..10] OF INTEGER; VAR mat : Matrix; oder auch TYPE Matrix = ARRAY [1..10],[1..10],[1..5],[5..7] OF INTEGER; VAR mat : Matrix; z.B. füllen aller Felder mit Nullen: VAR feld : ARRAY [0..9] OF INTEGER; i : INTEGER; ... FOR i:=0 TO 9 DO feld[i]:=0 END; oder auch FOR i:=feld'MIN TO feld'MAX DO feld[i]:=0 END; Der Record: ----------- Hier werden mehrere verschiedene Datentypen zu einem neuen zusammengefasst: TYPE Adresse = RECORD Name, Vorname : STRING(32); Telefon : STRING(10); Alter : INTEGER; PLZ : STRING(5); END; VAR adr : Adresse; ... auf die Elemente zuzugreifen muß man diese mit einem Punkt qualifizieren: adr.Name:="Weber" adr.Vorname:="Volker" usw. Für eine Adresskartei läßt sich am besten ein Array von Records verwenden: VAR AdressKartei : ARRAY [1..100] OF Adresse; |Platz für 100 Adressen. oder besser VAR AdressKartei : RECORD NumEintrag : INTEGER; Daten : ARRAY [1..100] OF Adresse; END; weiterhin könnte für eine Adresskartei noch interessant sein: INC(AdressKartei.NumEintrag); |Zähler um eins erhöhen. AdressKartei.Daten[AdressKartei.NumEintrag]:=NeuePerson; oder i:=1; WHILE (i<=AdressKartei.NumEintrag) AND_WHILE NOT Equal(AdressKartei.Daten[i].Name,SuchName) DO INC(i); ELSE WriteString("Gefunden"); WriteLn; END; ELSE WriteString("Ende des Feldes erreicht"); WriteLn; END;