veb mikroelektronik "wilhelm pieck" mühlhausen Ohne Genehmigung des Herausgebers ist es nicht gestattet, das Buch oder Teile daraus nachzudrucken oder auf fotomechanischem Wege zu vervielfältigen. Redaktionsschluß der vorliegenden Ausgabe: August 1989 KC PASCAL # Inhaltsverzeichnis I n h a l t s v e r z e i c h n i s 1. Einleitung...........................................3 2. Systemkern...........................................5 2.1. Editor...............................................6 2.2. Der Compiler und Start des übersetzten Programms.....8 3. Systemservice.......................................10 4. Sprachbeschreibung..................................14 4.1. Einleitung..........................................14 4.2. Grundelemente.......................................16 4.2.1. Bezeichner..........................................16 4.2.2. Zahlen..............................................17 4.3. Deklarationen und Definitionen......................18 4.3.1. Marken..............................................18 4.3.2. Konstanten..........................................18 4.3.3. Variablen...........................................19 4.3.4. Datentypen..........................................21 4.3.4.1. Einfacher Datentyp..................................23 4.3.4.2. Strukturierter Datentyp.............................24 4.3.4.3. Zeigertyp...........................................26 4.4. Faktoren, Operatoren, Ausdrücke.....................26 4.5. Anweisungen.........................................28 4.6. Standardprozeduren und -funktionen..................32 4.6.1. Prozeduren und Funktionen zur Ein- und Ausgabe......32 4.6.2. Arithmetische Funktionen............................37 4.6.3. Skalarfunktionen....................................38 4.6.4. Konvertierungsfunktionen............................38 4.6.5. Weitere Funktionen und Prozeduren...................39 4.7. Compiler-Direktiven.................................48 5. Interne Datendarstellung............................50 A. Anhang..............................................53 A1. Fehlermeldungen des Compilers.......................53 A2. Laufzeit-Fehlermeldungen............................54 A3. Wortsymbole.........................................54 A4. Standardbezeichner..................................55 A5. Listing des Demonstrationsbeispiels.................56 Redaktionsschluß der vorliegenden Ausgabe: Juli 1989 KC PASCAL # Einleitung 1. E i n l e i t u n g Die Kassette CC1002 KC PASCAL enthält eine schnelle, leicht bedienbare PASCAL-Version (Compiler) für den KC compact, sowie die Quelldatei eines Demonstrationsprogramms. Die Programme sind auf der Kassette wie folgt angeordnet: Programm ! Zählerstand ! Geracord LCR-C ------------------------------------------------- KCPASCAL ! 010 017 DEMO ! 090 125 Auf der A-Seite der Kassette sind die Programme mit 1000 Baud und auf der B-Seite mit 2000 Baud Übertragungsrate abgespeichert, wobei die B-Seite nur bei optimal eingestellten Kassettenrecorder eingelesen werden kann. Als Grundlage von KC PASCAL diente die von Jensen/Wirth Second Edition herausgegebene PASCAL-Version "PASCAL User Manual and Report". Abweichend von dieser Version existieren folgende Ein- schränkungen: - Es sind keine File-Typen implementiert, jedoch können Variablen beliebigen Typs auf Magnetband oder Diskette abgespeichert werden. - Ein Record-Typ darf keinen Variant-Teil enthalten. - PROCEDUREs und FUNCTIONs sind nicht als Parameter zugelassen. Neben diesen Einschränkungen, die sich jedoch nur geringfügig in der Arbeit bemerkbar machen, beinhaltet der Compiler viele zusätzliche Funktionen und Prozeduren, die die Vorzüge und Besonderheiten des KC compact im Verkehr mit den verschiedenen Umgebungen unterstützen, sowie Elemente, die sich in anderen Programmiersprachen bewährt haben (z.B. PEEK, POKE, TIN, TOUT,...). Eines der wichtigsten Neuheiten von KC PASCAL ist die Fähigkeit, Ereignis-Bearbeitungen (AFTER, EVERY,...) durchführen zu können, die durch die Multitasking-Funktionen des Betriebs- systems mit seinen 3 Zeitgebern ermöglicht wird. Die Gesamtheit der zusätzlichen Funktionen und Prozeduren wird schließlich noch von umfangreichen SOUND-Befehlen und über den Aufruf der USER-Prozedur zu erreichende Grafikbefehle abgeschlossen. Somit sind alle Befehle unter BASIC auch in PASCAL erreichbar. Der Compiler benötigt einschließlich Editor und Runtimes ca. 20 KByte Speicherplatz. Für den Anwender stehen damit noch mehr als 20 KByte freier Speicherplatz zur Verfügung. Zum Laden des Compilers ist folgendes zu beachten: Nachdem ein kurzes Vorprogramm in BASIC mit RUN"KCPASCAL.BAS" geladen und selbständig gestartet wurde, erscheint die Bildschirmausschrift "memory end(^RETURN_=45312) ?" Wird diese Frage mit ^RETURN_ beantwortet, so wird der größt- mögliche Speicherbereich für das zu erstellende PASCAL-Programm bereitgestellt. Durch Eingabe geringerer dezimaler Werte (als 45312) kann oberhalb des PASCAL-Programms, d.h. der höchsten von PASCAL verwendeten Speicherplatzadresse noch Freiraum für Maschinenprogramme geschaffen werden, die dann vom PASCAL- Programm aufrufbar sind. Nach Eingabe von ^RETURN_ oder einer Dezimalzahl wird KC PASCAL geladen und meldet sich mit dem Servicemenü in der Kommandoebene. Ebenfalls mit auf der Kassette befindet sich eine PASCAL- Quelldatei unter dem Dateinamen DEMO, die eindrucksvoll die vielfältigen Möglichkeiten von KC PASCAL demonstriert: - Schnelligkeit der Grafikausgabe - Tonausgabe - Ereignisbearbeitung (Uhrzeit) Das Listing dieser Quelldatei ist Anhang A5 zu entnehmen. Von der Kommandoebene kann diese Datei mit dem Kommando g,,demo geladen und mittels dem Kommando c übersetzt (compiliert) werden. Daraufhin erscheint die Bild- schirmausschrift "RUN?", die mit ^y_ oder ^Y_ zu quittieren ist. Das Programm zeigt 50 verschiedene, zufällig entstehende Grafiken. Hinweis: Dieses Handbuch ist ein Nachschlagewerk für KC PASCAL und nicht geeignet, die Programmiersprache PASCAL zu erlernen. KC PASCAL # Systemkern 2. S y s t e m k e r n Zum Systemkern zählen der relativ einfache, zeilenorientierte Editor, der ein einfaches und schnelles Editieren der Programme erlaubt, sowie der Compiler zur Umwandlung des Quelltextes in ein abarbeitungsfähiges Programm. Nach dem Laden von KC PASCAL befindet man sich in der Kommandoebene und es erscheint folgende Bildschirmausschrift *** KC PASCAL *** v 1.0 veb mikroelektronik "w. pieck" muehlhausen Im weiteren erscheint eine kurze erklärende Übersicht über die von der Kommandoebene ausführbaren Kommandos. Die Kommandoebene wird durch das Promptzeichen ">" angezeigt. Im folgenden ist die Eingabe einer Kommandozeile des Formates: C N1,N2,S1,S2 gefolgt von ^RETURN_ möglich, wobei C das auszuführende Kommando, N1 und N2 Zahlen im Bereich 1 bis 32767 und S1 und S2 Zeichenketten mit einer maximalen Länge von 20 Zeichen darstellen. Das Komma wird benutzt, um die einzelnen Argumente zu trennen (kann durch das Q-Kommando verändert werden). Außerhalb der Strings werden Leerzeichen ignoriert. Keines der Argumente ist obligatorisch, aber einige Kommandos (z.B. das 'D'elete-Kommando) werden nicht ausgeführt, ohne daß N1 und N2 spezifiziert werden. Parameter, die von bestimmten Kommandos schon mit standardmäßig vorgegebenen Werten belegt sind, werden in der nachfolgenden Beschreibung in eckige Klammern gesetzt. Achtung: Parameterangaben aus früheren Kommandoeingaben bleiben erhalten und können bei Kommandos ohne standard- mäßiger Vorgabe wiederholt benutzt werden. Die Werte von N1 und N2 werden anfangs auf 10 gesetzt, die Strings sind leer. Wird eine unzulässige Zeile, wie F-10,10,PASCAL eingeben, wird die Zeile ignoriert und "Pardon?" ausgegeben. Diese Fehlermeldung wird auch ausgegeben, wenn die Länge von S2 20 Zeichen übersteigt. Wenn S1 länger als 20 Zeichen ist, werden die überzähligen Zeichen ignoriert. Die Kommandos können als Groß- oder Kleinbuchstaben eingegeben werden. 2.1. Der Editor Aus der Kommandoebene heraus können neben der Eingabe von Kommandos auch Programmzeilen eingegeben werden - zu beachten ist aber, daß vor der Programmzeile die Zeilennummer und mindestens ein Leerzeichen stehen müssen. Eine Eingabezeile kann maximal 80 Zeichen umfassen, weitere Zeichen werden ignoriert. Mit ^RETURN_ wird der editierte Text in einer kompakten Form im Quelltextspeicher abgelegt. Die Zahl der führenden Leerzeichen einer Zeile wird in einem Byte am Anfang dieser Zeile abgespeichert. Wenn eine Zeilennummer gefolgt von ^RETURN_, d.h. ohne nach- folgenden Text eingegeben wird, wird eine eventuell schon existierende Zeile unter dieser Zeilennummer aus dem Quelltext- speicher gelöscht. Beim Eingeben von Text oder Kommandos können folgende Steuertasten verwendet werden: ^CTRL_-^X_ Löscht die Zeile bis zum Zeilenanfang. ^ESC_ Kehrt in die Kommando-Schleife zurück. ^CTRL_-^P_ Schaltet die Ausgabe wechselweise auf Drucker/ Bildschirm um. ^DEL_ Löscht das Zeichen links vom Cursor innerhalb einer Zeile. ^TAB_ Springt zur nächsten Tabulatorposition. Hinweis: ^ _-^ _ bedeutet gleichzeitige Tastenbetätigung der in den Klammern aufgeführten Tasten! Der Text wird immer erst in einen Eingabepuffer eingelesen. Ist dieser voll, wird das Eingeben weiterer Zeichen verhindert. Mit ^DEL_ oder ^CTRL_-^X_ können Zeichen gelöscht und damit neuer Speicherplatz bereitgestellt werden. Mit ^RETURN_ wird die betreffende Zeile in den Quelltextspeicher übernommen. Der zeilenorientierte Editor wird mit dem Kommando: E n auf die entsprechende Zeilennummer n gesetzt. Fehlendes n bewirkt die Zurückweisung des Kommandos. Die angegebene Zeile n wird auf dem Bildschirm dargestellt und ebenfalls in den Eingabepuffer geladen, in dem die Änderungen eingetragen werden können. Dadurch kann der ursprüngliche Zeileninhalt jederzeit wiederhergestellt werden. Die aktuell bearbeitete Position im Puffer wird durch einen Textzeiger angezeigt, der durch folgende Unterkommandos manipuliert werden kann: ^SPACE_ - Bewegt den Textzeiger um ein Zeichen weiter. ^DEL_ - Bewegt den Textzeiger um eine Position zurück. ^RETURN_ - Unabhängig von der aktuellen Textzeiger-Position wird die gesamte editierte Zeile vom Puffer in den Quelltextspeicher zurückkopiert und die Zeilenedi- tierung beendet. ^C_ - ("CHANGE") Das Zeichen an der aktuellen Zeigerpo- sition (dargestelt durch "+") wird durch das einge- gebene Zeichen überschrieben und der Zeiger eine Stelle weitergerückt. Mittels ^DEL_ kann der Textzeiger um eine Position wieder nach links verschoben und mittels ^RETURN_ dieser Modus verlassen werden. ^F_ - ("FIND") sucht das nächste Auftreten des vorher mit dem F-Kommando definierten Suchstrings. Dieses Unterkommando schließt gleichzeitig das Editieren der gerade aufgerufenen Zeile ab (unter Beibehaltung aller Änderungen), falls der Suchstring in dieser Zeile nicht noch einmal auftritt. Nach wiederholter Betätigung von ^F_ werden die nächsten Zeilen nach dem Suchstring durchsucht und bei Auffinden der Editor auf die betreffende Zeile gesetzt. Der Textzeiger befindet sich immer am Anfang der gefundenen Zeichenkette. ^I_ - ("INSERT") fügt Zeichen an der gegenwärtigen Zeiger- position (dargestellt durch "*") ein. Der I-Modus wird ebenfalls solange beibehalten, bis die ^RETURN_-Taste einmal gedrückt wird. In diesem Unterkommando löscht ^DEL_ das Zeichen vor dem Zeiger aus dem Textpuffer. Nach dem Verlassen von "INSERT" steht der Textzeiger hinter dem zuletzt eingefügten Zeichen. ^K_ - ("KILL") löscht das Zeichen an der aktuellen Zeigerposition. ^L_ - ("LIST") listet den Rest der editierten Zeile. Der Textzeiger steht anschließend am Anfang der zu editierenden Zeile. ^Q_ - ("QUIT") bricht das Editieren ab, ohne die Änderungen zu berücksichtigen, d.h. beläßt die Zeilen in ihrem alten Zustand. ^R_ - ("RELOAD") lädt den Textpuffer noch einmal mit der alten Version der Zeile und bewirkt somit ein Überschreiben aller gemachten Änderungen. ^S_ - ("SUBSTITUTE") wird im Zusammenhang mit dem F- Kommando benutzt und ersetzt den eben gefundenen Suchstring f durch den im F-Kommando definierten Austauschstring s und führt dann automatisch das Unterkommando F aus, d.h. es wird nach dem nächsten Auftreten von f gesucht. Damit kann man sich durch einen Quelltextfile hindurcharbeiten und jeden String f nach Belieben gegen String s austauschen (weiter mit ^S_) oder auch nicht (weiter mit ^F_). ^X_ - Setzt den Textzeiger auf das Zeilenende und ruft automatisch den Einfüge(^I_)-Modus auf. ^Z_ - Löscht alle Zeichen ab (und einschließlich) der aktuellen Zeigerposition bis zum Ende der Zeile. 2.2. Der Compiler und Start des übersetzten Programms Der Compiler übersetzt den PASCAL-Quelltext in ein abarbeitungs- fähiges Maschinenprogramm und wird mit dem Kommando: C ^n_ aufgerufen. n spezifiziert dabei die Zeilennummer, ab der übersetzt werden soll. Bei fehlendem Wert n wird der gesamte Quelltext übersetzt. Nach dem Aufruf des Compilers wird ein Listing mit folgenden Angaben erzeugt: xxxx nnnn Zeileninhalt wobei xxxx die Anfangsadresse des von der Zeile nnnn erzeugten Maschinencodes darstellt. Mittels der Compilerdirektive (*$P*) kann dieses Listing vom Bildschirm auf den Drucker umgelenkt werden. Wird während der Übersetzung ein syntaktischer Fehler erkannt, tritt die Fehlerausschrift "*ERROR*" und eine Fehlernummer (siehe Anhang A1) auf. Das den Fehler verursachende Zeichen wird im Listing durch einen nachgestellten Aufwärtspfeil kenntlich gemacht. Nun besteht die Möglichkeit, entweder mittels ^E_ den Editor für diese Zeile aufzurufen, mittels ^P_ den Editor auf die vorhergehende Zeile zu setzen oder in der Übersetzung fortzufahren (jede andere Taste), wobei am Ende der Übersetzung dann die Anzahl der Fehler ausgegeben und der Objektcode gelöscht wird. Die Fehlerausschrift "No more text" weist auf ein nicht korrektes Ende des PASCAL-Quelltextes hin (z.B. fehlendes END.). "No table space" gibt an, daß der Tabellenbereich des Compilers übergelaufen ist. Einen größeren Tabellenbereich kann über das Kommando A (Alter) eingestellt werden. Bei einer erfolgreichen (fehlerlosen) Übersetzung folgt die Abfrage "RUN?", woraufhin das Programm mit der Taste ^y_ oder ^Y_ gestartet werden kann. Treten Laufzeitfehlermeldungen auf, so kann deren Bedeutung im Anhang A2 ermittelt werden. Die Ausgabe des Listings sowie die Abarbeitung des Programms kann durch Drücken einer beliebigen Taste ausgesetzt und durch nachfolgendes Betätigen der ^ESC_-Taste abgebrochen werden. Jede andere Taste setzt die Abarbeitung bzw. Ausgabe fort. Mit dem Kommando: R kann jederzeit der Objektcode des mit Kommando C übersetzten Programms abgearbeitet werden. Kommando: T ^n_ Der Quelltext wird wiederum beginnend mit Zeile n (bzw. bei Nichteingabe von n, ab der ersten existierenden Zeile) übersetzt. War die Übersetzung fehlerfrei, wird die Frage "OK ?" ausgegeben. Antwortet man mit ^y_ oder ^Y_, so wird der erzeugte Objektcode an das Ende der Runtimes verschoben (dabei wird jedoch der Compiler zerstört) und zusammen mit diesem in binärer Form auf externen Datenträger abgespeichert. Als Filename wird der zuletzt definierte Suchstring verwendet. Jede andere Antwort bewirkt einen Abbruch des Kommandos. Der erzeugte Objektcode enthält Befehle, die bei der Ausführung die Routine MC START PROGRAM aufrufen. Da diese Routine BASIC und alle in der Firmware existierenden RSX-en löscht, muß vor einem eventuellen RSX-Aufruf vom übersetzten PASCAL-Programm her über die PASCAL-Prozedur USER (#BCD1) die Firmware-Routine KL LOG EXT aufgerufen werden, die wiederrum die entsprechenden RSX-en initialisiert. Nach dem Kommando T muß der Compiler erneut geladen werden. Mittels Kommando: A können die Grundeinstellungen für Übersetzung und Start eines Programms geändert werden. Wird auf die Abfrage "Symbol Table Size?" nur ^RETURN_ eingegeben, bleibt die Standardgröße für die Symboltabelle von 1858 Byte bestehen; jede andere dezimale Zahl kann sie verändern, was aber bei den meisten Programmen nicht notwendig ist. Es folgt die Frage "Translate Stack?". Über die Eingabe einer Dezimalzahl und ^RETURN_ kann man nun festlegen, auf welcher Adresse der Stack liegen soll, der von jedem mittels des T-Kommandos übersetzten PASCAL-Maschinenprogramm benötigt wird. Standardmäßig ist der zu Beginn des Ladens von KC PASCAL eingegebene Wert für MEMORY END als Stack-Adresse festgelegt. Wie im der Einleitung bereits erwähnt, ist die Änderung der Adressen auch hier über das A-Kommando unbedingt notwendig, wenn man Speicherplatz für Routinen im oberen RAM-Bereich reservieren will, um sie aus dem mittels Kommando T übersetzten Programm anzusprechen. Durch die alleinige Eingabe von ^RETURN_ bleibt die Stack-Adresse unverändert. KC PASCAL # Systemservice 3. S y s t e m s e r v i c e Die nachfolgenden, umfangreichen Kommandos sichern dem Nutzer einen einfachen, schnell erlernbaren Umgang mit dem KC PASCAL- System. Zur Unterstützung der Kommando- und Programmzeileneingabe dienen ebenfalls die ^COPY_- und die ^SHIFT_- in Zusammenhang mit den Cursortasten, mit denen ein einfaches Kopieren von Zeichen auf dem Bildschirm möglich ist. Dazu wird der Cursor als Lese- und Schreibcursor programmiert. Während der Schreibcursor auf der gegenwärtigen Position verbleibt, kann man über die gleichzeitige Betätigung der ^SHIFT_ und einer der Cursortasten den Lesecursor frei über den Bildschirm bewegen und an die zu kopierende Stelle bringen. Anschließendes Betätigen der ^COPY_-Taste kopiert die Zeichen vom Lese- zum Schreibcursor. Ebenfalls können auch direkt Zeichen über die Tastatur eingegeben werden. Mit ^RETURN_ wird der Kopiermodus wieder verlassen. Kommando: D n,m Alle Zeilen von Zeilennummer n bis Zeilennummer m (einschließlich) werden aus dem Quelltextspeicher gelöscht. Ist m ! = sowie die Zeichenpaare := > = >= .. (* *) Im weiteren sind Standardbezeichner (z.B. Funktions- und Prozedurbezeichnungen; siehe Anhang A4) vordefiniert und Wortsymbole (Anhang A3) nur für bestimmte Zwecke einsetzbar. 4.2.1. Bezeichner ----------------- Unter Bezeichner (oder Name) ist eine Folge von Buchstabenzeichen und Ziffernzeichen zu verstehen, die mit einem Buchstabenzeichen beginnt und zur Bezeichnung von Marken, Konstanten, Typen, Variablen, Prozeduren und Funktionen dienen. Bild 3: Bezeichner (Name) Die Bezeichner charakterisieren die Objekte eines Programms. Die Standardbezeichner sind dem System bereits bekannte Bezeichner mit einer definierten Bedeutung (z.B. READ, SIN). Prinzipiell können diese Bezeichner vom Programmierer umdefiniert werden; jedoch ist davon abzuraten, da die vordefinierte Funktion der Bezeichner verlorengeht. Es werden nur die ersten 10 Zeichen eines Bezeichners ausgewertet. Dabei ist es gleich, ob die Bezeichner Groß- oder Kleinbuchstaben enthalten - alle Zeichen werden intern in Großbuchstaben umgewandelt. Wortsymbole werden bereits vom Editor automatisch in Großbuchstaben umgewandelt und erscheinen so auf dem Bildschirm. Ein Bezeichner gilt immer im Block des jeweiligen Deklarationsteils als definiert, d.h. im Hauptprogramm definierte Bezeichner sind global gültig. 4.2.2. Zahlen ------------- Zahlen sind Konstanten der Typen INTEGER (Bild 4) oder REAL (Bild 5). Bild 4: Vorzeichenlose ganze Zahl (INTEGER) INTEGER oder vorzeichenlose ganze Zahlen haben einen Wertebereich kleiner oder gleich 32767. Bild 5: Vorzeichenlose reelle Zahl (REAL) Der Bereich der REAL oder vorzeichenlosen reellen Zahlen beträgt 5.9E-39 .. 34E+38 mit einer maximalen Mantissenlänge von 23 Bits, d.h. die reelle Zahl ist auf 7 höchstwertige Stellen genau. Zu beachten ist jedoch, daß die Berechnung durch die binäre Darstellung dezimaler Brüche ungenau wird, wenn das Ergebnis sehr viel kleiner als die absoluten Werte der Argumente ist. Dieser Effekt tritt nicht auf, wenn größere ganze Zahlen als reelle Zahlen dargestellt werden. z.B. 1.000 001 - 1 = 0.000 000 954 1 000 001 - 1 000 000 = 1.000 000 Führende Nullen sind bei der Berechnung mit hoher Genauigkeit zu vermeiden, denn jede Null wird als eine Ziffer verarbeitet. Besser ist es, solche Zahlen gleich in Exponentialschreibweise einzugeben. Hexadezimale Zahlen haben einen Wertebereich von #0000...#FFFF und sind vorteilhaft für die Darstellung von Speicherplatzadres- sen einsetzbar. 4.3. Deklarationen und Definitionen 4.3.1. Marken ------------- Jede Anweisung im PASCAL-Programm kann mit einer Marke versehen werden. Die damit gekennzeichneten Anweisungen können mit der Sprunganweisung GOTO von jeder Stelle der jeweiligen Programm- ebene aus erreicht werden. Allerdings wird dadurch die sequentielle Programmabarbeitung unterbrochen und die logischen Zusammenhänge, die durch die struktruierte Programmierung erreicht werden, zerstört. Marken sind vorzeichenlose INTEGER-Zahlen und müssen im Deklarationsteil des Programms mit dem Wortsymbol LABEL vereinbart z.B. LABEL 1111,2222; und können im Anweisungsteil wie folgt verwendet werden: . . 1111: GOTO 2222; . . 2222: END; 4.3.2. Konstanten ----------------- Durch die Konstantendefinition können Bezeichner Werte zugeordnet werden. Eine Konstante kann folgende Gestalt haben: Bild 6: Konstante Zu beachten ist, daß Zeichenketten (Strings) nicht mehr als 255 Zeichen enthalten dürfen und vom Typ ARRAY ^1...N_ OF CHAR sind, wobei N eine ganze Zahl zwischen 1 und 255 ist. In Zeichenketten darf kein End-of-line-Zeichen (CHR(13)) enthalten sein; ansonsten kann der ganze erweiterte ASCII- Zeichensatz mit 256 Elementen benutzt werden. Ebenfalls können Steuerzeichen über CHR-Konstruktionen als Konstanten vereinbart werden ,z.B. CONST a=CHR(8); (*Backspace*) b=CHR(13); (*Carrige return*) c=CHR(16); (*Drucker an/aus*) KC PASCAL enthält bereits die vordefinierten Konstanten: MAXINT = größte INTEGER-Zahl 32767 FALSE,TRUE = Konstanten vom Typ BOOLEAN 4.3.3. Variablen ---------------- Alle Variablen, die während eines Programms benutzt werden, müssen vorher deklariert sein. Bei der Deklaration wird einer Variablen ein Bezeichner und ein Typ zugeordnet. Über die Wahl des Typs (INTEGER, REAL, CHAR, BOOLEAN) legt der Programmierer den Definitionsbereich der betreffenden Variablen fest. Weist dieser von den Standards ab, so kann über die Typendefinition ein eigener Definitionsbereich geschaffen werden. In KC PASCAL sind sowohl statische als auch dynamische Variablen verfügbar. Abhängig vom Typ wird einer statischen Variablen bereits vor dem Programmlauf ein fester Speicherbereich zugeordnet. Er steht dieser Variablen während der gesamten Abarbeitungszeit zur Verfügung. Unter den Variablen zählen die einfachen, die strukturierten und die Zeigervariablen. Bild 7: Variable Sie werden im Deklarationsteil z.B. mit der Anweisung VAR X:REAL; Y:ARRAY^1...100_ OF REAL; SATZ:RECORD R:REAL; I:INTEGER; M:ARRAY^1...10,1...100_ OF CHAR; B:BOOLEAN END; definiert und sind für den gesamten Block gültig, in dem sie definiert wurden. Der Wert der statischen Variablen ist durch ihren Bezeichner aufrufbar. Dynamische Variablen werden nicht explizit deklariert und können auch nicht über einen Bezeichner angesprochen werden. Auf sie wird mittels einer statischen Variablen vom Typ Zeiger, die die Adresse der dynamischen Variablen enthält, zugegriffen. Dynamische Variablen werden erst während des Programmlaufs mittels der Prozedur NEW auf der Halde erzeugt bzw. mittels MARK und RELEASE vernichtet und gestatten dadurch eine dynamische Speicherplatzverwaltung. Das kurze Programm zeigt, wie ein beliebig langer Satz (Text) dynamisch abgespeichert werden kann. NIL dient zum Initialisieren der Zeigervariablen und gibt das Ende des Datensatzes an. Dies ist so realisiert, daß der Zeigervariablen, der die Konstante NIL zugewiesen wurde, keine Adresse enthält. 10 PROGRAM dynamischeVariable; 20 TYPE satz=RECORD buchstabe:char; 40 next: satz 50 END; 60 zeiger= satz; 70 VAR wurzel,halde,eingabe:zeiger; 80 BEGIN 90 mark(halde); (*Merken der Halde*) 100 wurzel:=NIL; (*Anfang der dynam. Liste*) 110 readln; 120 REPEAT 130 new(eingabe); 140 read(eingabe .buchstabe); 150 eingabe .next:=wurzel; 160 wurzel:=eingabe 170 UNTIL false; (*^ESC_ fuer Abbruch*) 180 release(halde) (*Loeschen der Halde*) 190 END. KC PASCAL enthält folgende vordefinierte Variablen: - ERRFLG, ERRCHK ERRFLG und ERRCHK sind boolsche Variablen, die fehlerhafte Zahleneingaben erkennen. Der Wert von ERRFLG ist im Normalzustand FALSE. Wird ERRCHK auf TRUE gesetzt und tritt der Fehler "DIGIT EXPECTED" auf, so wird nicht das Programm gestoppt, sondern Null eingelesen und ERRFLG auf den Wert TRUE gesetzt. 10 PROGRAM ERRFLGundERRCHK; 20 VAR i:real; 30 BEGIN 40 errchk:=true; 50 write('Geben Sie eine REAL-Zahl ein !'); 60 read(i); 70 WHILE errflg DO 80 BEGIN 90 write('Bitte eine REAL-Zahl eingeben !'); 100 read(i) 110 END; 120 write('i= ',i) 130 END. - RA, RB, RC, RD, RE, RH, RL, RF Diese Variablen vom Typ CHAR werden beim Aufruf einer USER- Prozedur direkt in die Z80-Register geladen bzw. durch die Ergebnisse der Routine überschrieben, z.B. ra:=chr(c); user(#bb6f); (*setzt die horizontale Position des Cursors*) - RAF, RBC, RDE, RHL Für diese Variablen vom Typ INTEGER trifft das gleiche wie im vorigen Absatz zu, jedoch mit der Besonderheit, daß INTEGER- Parameter an die USER-Prozedur übergeben bzw. von ihr empfangen werden, z.B. user(#bbc6); (*uebergibt momentane Grafik-Cursor-Position*) x:=rde;y:=rhl; Achtung: Die Variablen RA, RB, RC,... und RAF, RBC,... beeinflussen sich gegenseitig. So überschreibt RHL die Variablen RH und RL. 4.3.4. Datentypen ----------------- Jede Variable und Konstante eines PASCAL-Programms besitzt einen Datentyp, welcher die entsprechende Darstellungsform im Speicher und den Wertevorrat spezifiziert. Grundsätzlich ist zwischen den bereits vordefinierten Standardtypen und den vom Programmierer definierbaren Typen zu unterscheiden. Folgende Übersicht zeigt eine Aufteilung der Datentypen: Typ ! ----------------------------!------------------------ ! ! ! ! ! ! einfacher Typ strukturierter Typ Zeigertyp ! ! ----!------------- ! ! ! ! - INTEGER REAL - array-Typ - BOOLEAN - record-Typ - CHAR - Mengentyp - Unterbereichstypen - Aufzählungstypen Die Definition von neuen Datentypen (Unterbereichs-, Aufzählungstypen) geschieht mit der Anweisung TYPE kleinbuchstaben='a'...'z'; wochentag=(mo,di,mi,do,fr,sa,so); Zu beachten ist, daß der Typ jeder Variablen vor der ersten Verwendung vereinbart werden muß und daß bei Operationen mit Daten verschiedenen Typs die Typ- und Zuweisungsverträglichkeit gewährleistet sein muß. Für array- und record-Typen benutzt KC PASCAL die Namensäquiva- lenz. Will man z.B. zwei Felder A und B einander zuweisen, so führt das bei der Variablenvereinbarung VAR A:ARRAY^'A'...'C'_ OF INTEGER; B:ARRAY^'A'...'C'_ OF INTEGER; zu der Fehlermeldung (*ERROR*10), da zwei verschiedene Datentypen erzeugt wurden. Der gleiche Datentyp und damit die Zuweisungsverträglichkeit wird mit der Anweisung VAR A,B:ARRAY^'A'...'C'_ OF INTEGER; geschaffen. Obwohl diese Namensäquivalenz etwas kompliziert erscheint, werden durch die geforderte größere Gewissenhaftigkeit beim Programmieren die Fehler eingeschränkt. Wie am Beispiel gerade gezeigt wurde, kann die Festlegung des Datentyps auch direkt im Variablendeklarationsteil mit der Anweisung VAR Kleinbuchstabe:'a'..'z'; erfolgen. "Kleinbuchstabe" ist hier jedoch bereits die Variablenbezeichnung, während bei der TYPE-Anweisung "Kleinbuchstabe" erst der Typbezeichner ist, der mittels der VAR- Anweisung einer Variablen noch zugeordnet werden muß. Trotz der etwas aufwendigen Schreibweise bringt die Definition von Datentypen mit TYPE folgende Vorteile: - Vereinfachung des Entwurfes eines PASCAL-Programms - Einsparung von Schreibaufwand bei Verwendung mehrerer Variablen des gleichen Typs - Hilfe beim Verhüten und Suchen von Fehlern - Herstellen von Typverträglichkeit für Felder - Schaffung von Voraussetzungen zum Parameteraustausch mit Unterprogrammen für strukturierte Variablen 4.3.4.1. Einfacher Datentyp --------------------------- Bild 8: Einfacher Datentyp Für Typ-Name können folgende vordefinierte Standardtypen eingesetzt werden: - CHAR vollständiger ASCII-Zeichensatz mit 256 Elementen - BOOLEAN (FALSE, TRUE) Datentyp für logische Operationen - INTEGER ganze Zahl zwischen -32768 ... 32767 - REAL reelle Zahl zwischen 3.4E38 ... 5.9E-39 (ebenfalls im negativen Bereich) mit siebenstelliger Mantisse Aufzählungstypen werden durch in Klammern gesetzte Aufzählung der Bezeichner (Namen) definiert. Sie dürfen nicht mehr als 256 Elemente enthalten, z.B. TYPE MATERIAL=(HOLZ,STEIN,METALL); Unterbereichstypen werden durch Angabe des kleinsten und des größten Wertes, als ein Teilbereich eines vordefinierten Standardtyps, definiert, z.B. TYPE ZIFFER=1..9; 4.3.4.2. Strukturierter Datentyp -------------------------------- Bild 9: Strukturierter Datentyp Ein strukturierter Typ wird durch die Typen seiner Komponenten und durch die Methode der Strukturierung gekennzeichnet. Das Wortsymbol PACKED wird akzeptiert aber ignoriert, da Packen bei ARRAYs OF CHAR usw. schon stattfindet. Der einzige Fall in dem Packen von Arrays vorteilhaft wäre, ist der bei ARRAYs OF BOOLEAN, aber in diesem Fall wird normalerweise ein SET-Typ verwendet. Ein ARRAY-Typ besteht aus einer festen Anzahl von Komponenten, die alle vom gleichen Typ sind. Die Komponenten des Feldes werden durch Indizes angesprochen, die zum einfachen Datentyp (außer REAL) gehören. Sie werden in eckigen Klammern geschrieben und an den Bezeichner des Feldes angehängt, z.B. TYPE Werte=ARRAY^Anfang..Ende,1..10_ OF REAL; Zugelassen sind auch ARRAYs OF ARRAYs und ARRAYs OF SETs. Achtung: Bei Zuweisungen verschiedener Arrays gilt die Namens- äquivalenz (siehe 4.3.4.). Unter einem SET-Typ versteht man die Zusammenfassung mehrerer Objekte des gleichen Typs. Zu einer Menge können maximal 256 Elemente gehören und somit liegen die Ordungswerte der Elemente im Bereich von 0...255. Jedes Element der Menge wird in einem Bit gespeichert. Ist das Element im Satz enthalten, so ist das Bit gesetzt. Ein Record-Typ ist eine Struktur, welche aus einer festen Anzahl Komponenten (Komponentenliste) gleicher oder unterschiedlicher Typen besteht. Für jede Komponente wird ein Bezeichner und ein Typ festgelegt. In zwei unterschiedlichen Records sollten nie gleiche Komponentenbezeichner verwendet werden. Ein Variantenteil in der Komponentenliste wird nicht unterstützt. Bild 10: Komponentenliste Zwei Recordvariablen können nur dann einander zugewiesen werden, wenn ihre Typen namensäquivalent sind (siehe Abschnitt 4.3.4.). Der Zugriff zu einer Recordkomponente wird erreicht, indem der Variablenbezeichner mit dem Recordkomponentenbezeichner, getrennt durch einen Punkt, angegeben wird. Mit der WITH-Anweisung kann der Zugriff zu den einzelnen Recordkomponenten in kompakterer Form ermöglicht werden, z.B. TYPE Person=RECORD Name,Vorname:ARRAY^1..20_ OF CHAR; Alter :0..100; Verheiratet :BOOLEAN END; VAR Mitarbeiter:Person; BEGIN . . WITH Mitarbeiter D0 BEGIN READ(Name); READ(Vorname); . . END; KC PASCAL unterstützt ebenfalls den Typ RECORD OF SET. Im obigen Beispiel könnte man in der TYPE-Anweisung noch den Recordkompo- nentenbezeichner Schulbildung:SET OF (POS,EOS,Fachschule,Hochschule); aufnehmen. 4.3.4.3. Zeigertyp ------------------ Im Bild 9 ist ebenfalls der Zeigertyp mit enthalten. Der Zeiger wird während der Erzeugung einer dynamischen Variablen bereitgestellt und enthält die Adresse der dynamischen Variablen. Auf diese wird mittels eines Pfeils hinter dem Zeiger (Zeigervariablen) zugegriffen. In KC PASCAL gibt es folgende Einschränkungen in der Benutzung von Zeigern: - Zeiger auf Typen, die nicht vereinbart wurden, sind nicht erlaubt. Verkettete Listen können jedoch aufgebaut werden da Typ- Definitionen auch Zeiger auf sich selbst enthalten dürfen. Ein Beispiel dazu ist im Abschnitt 4.3.3. enthalten. - Zeiger auf Zeiger sind nicht erlaubt. - Zwei Zeiger, die auf den gleichen Typ weisen sind äquivalent (es wird die Strukturäquivalenz benutzt) und können einander zugewiesen und verglichen werden. 4.4. Faktoren, Operatoren und Ausdrücke Ein Faktor kann folgende Form haben: Bild 11: Faktor Operatoren werden zum Verknüpfen bzw. Vergleichen von Ausdrücken verwendet. Ein Faktor selbst oder die Verknüpfung zweier Faktoren mit einem Multiplikationsoperator heißt Term. Bild 12: Term Nachfolgende Bilder zeigen die Darstellungen eines einfachen Ausdrucks sowie das eines Ausdrucks. Bild 13: Einfacher Ausdruck Bild 14: Ausdruck Die Vergleichsoperatoren können auf Strings gleicher Länge und auf alle einfachen Datentypen angewandt werden. Zeiger sind nur über die Operatoren = und > miteinander vergleichbar. Mengen können durch >=, =, >, = verglichen oder mittels IN auf Mitgliedschaft in einer weiteren Menge geprüft werden. Weitere Mengenoperatoren sind: * Mengendurchschnitt + Mengenvereinigung - Mengendifferenz Bei Anwendung der Mengenoperatoren ist darauf zu achten, daß die Elemente der einzelnen Mengen alle vom gleichen Basistyp sind. ^_ kennzeichnet eine leere Menge und ^a..b_ bezeichnet die Menge aller Werte aus dem Intervall a bis b. 4.5. Anweisungen Alle Anweisungen in PASCAL-Programmen stehen im Anweisungsteil zwischen dem BEGIN . . END. des Hauptprogramms und beschreiben auszuführende Operationen. .pa Bild 15: Anweisungen KC PASCAL # Sprachbeschreibung Folgende Anweisungen sind möglich: a) Wertzuweisung Mittels der Wertzuweisung wird einer Variablen der Wert eines Ausdrucks zugewiesen. Die Wertzuweisung wird nur ausgeführt, wenn der Typ der Variablen und des Ausdrucks identisch oder typverträglich ist. Variablentyp INTEGER REAL CHAR BOOLEAN INTEGER + - - - REAL + + - - CHAR - - + - BOOLEAN - - - + '+' bedeutet, daß die Zuweisung erlaubt ist. b) Prozeduranweisung Prozeduren sind entweder im Deklarationsteil definiert oder stehen als vordefinierte Standardbezeichner zur Verfügung (siehe 4.6.). Die Verwendung dieser Prozedurbezeichner mit der geforderten Parameterliste Bild 16: Parameterliste nennt man eine Prozeduranweisung. Prozeduren und Funktionen sind als Parameter nicht zugelassen. Prozeduren und Funktionen können in Anweisungen verwendet werden, bevor sie deklariert wurden. Das ist durch das Wortsymbol FORWARD möglich, z.B PROCEDURE Zeichne(z1,z2,z3,z4:REAL);FORWARD; PROCEDURE Auswertung(a,b:boolean); VAR x,y:integer; BEGIN . . READ(x,y); Zeichne(a,b,x,y); . . END; PROCEDURE Zeichne; BEGIN . . END; c) Verbundanweisung Eine Verbundanweisung besteht aus einer beliebigen Anzahl von Einzelanweisungen, die über die Wortsymbole BEGIN und END zu einem Block zusammengefaßt werden und syntaktisch als eine Anweisung fungieren. Das Semikolon dient als Trennzeichen zwischen den Einzelanweisungen; nach der letzten Anweisung braucht kein Semikolon mehr zu stehen. Verbundanweisungen werden in bedingten, in Zyklenanweisungen und in Prozedur- sowie Funktionendeklarationen benötigt. d) Bedingte Anweisung Es gibt zwei Formen der bedingten Anweisung, die IF- und die CASE-Anweisung. Die Anweisungen können wiederum Verbundanweisungen sein. Eine leere CASE-Anweisung ist nicht gestattet. Eine CASE-Anweisung kann entweder mit einem ELSE-Zweig (wird ausgeführt, wenn die Auswahlbedingung mit keiner CASE-Marke übereinstimmt) oder mit END abgeschlossen werden. e) Anfangsgeprüfte Schleifenanweisung (WHILE...DO...) Die Anweisung wird solange ausgeführt, wie die Berechnung des Ausdrucks den Wert TRUE liefert. Ist der Wert des Ausdrucks vor dem ersten Schleifendurchlauf bereits FALSE, wird die Anweisung kein einziges Mal ausgeführt. f) Endgeprüfte Schleifenanweisung (REPEAT...UNTIL...) Die Anweisung wird mindestens einmal durchlaufen. Am Ende der Schleife wird der Ausdruck geprüft und ergibt bei FALSE einen erneuten Schleifendurchlauf, bis der Ausdruck TRUE wird. g) Zählanweisung (FOR...TO/DOWNTO...DO...) Die Steueranweisung darf nur eine unstrukturierte Variable und kein Parameter sein. Sie wird um +1 bzw. -1 weitergezählt. Anfangs- und Endwert symbolisieren Ausdrücke, deren Werte mit dem Typ der Steuervariable verträglich sein müssen. Ist der Endwert von vornherein überschritten bzw. unterschritten, so wird die Anweisung nicht ausgeführt. h) WITH-Anweisung Innerhalb der WITH-Anweisung können die Recordkomponentenvariab- len, die durch die WITH-Variable spezifiziert sind, allein durch den Recordkomponentenbezeichner angegeben werden, d.h. ohne die Angabe der Recordvariablen voranzustellen.(siehe 4.3.4.2.) i) Sprunganweisung Über die GOTO-Anweisung ist der Sprung zu einer Marke möglich, die sich im selben Block und in der selben Ebene befindet. Die Marke ist eine INTEGER-Zahl und wird durch Doppelpunkt von der folgenden Anweisung getrennt. Marken müssen durch das Wortsymbol LABEL in dem Block, in dem sie verwendet werden sollen, deklariert sein. 4.6. Standardprozeduren und -funktionen 4.6.1. Prozeduren und Funktionen zur Ein- und Ausgabe ----------------------------------------------------- WRITE Die Prozedur WRITE wird verwendet, um Daten auf dem Bildschirm oder Drucker auszugeben. Wenn der auszugebende Ausdruck vom CHARACTER-Typ ist, dann gibt WRITE (e) den 8-bit-Wert, der durch den Wert des Ausdruckes e dargestellt wird, am Bildschirm oder Drucker aus. Beachte: CHR (n) ergibt das Steuerzeichen n; die möglichen Steuerzeichen sind im BASIC- Handbuch zu ersehen. Allgemein gilt: WRITE (P1, P2, ... Pn); entspricht: BEGIN WRITE(P1);WRITE(P2);......;WRITE(Pn) END; Die Parameter P1,P2,...Pn können eine der folgenden Formen haben: (e) oder (e:m) oder (e:m:n) oder (e:m:H) wobei für e, m, n Zahlen einzusetzen sind und H der unmittelbare Buchstabe ist. 5 Fälle sind zu betrachten: a) e ist von INTEGER-Typ und (e) oder (e:m) wird benutzt: Der Wert von e wird in einen Zeichenstring mit abschließendem Leerzeichen umgewandelt. Eine Verlängerung des Strings mittels führender Leerzeichen kann durch Angabe von m, welches die Gesamtlänge des Strings angibt, erreicht werden. Wenn m nicht ausreichend ist, um e auszugeben oder m nicht vorhanden ist, dann wird e vollständig mit abschließendem Leerzeichen ausgegeben und m wird ignoriert. Wenn die durch m festgelegte Länge der Länge von e ohne nachfolgenden Leerzeichen entspricht, wird kein ab- schließendes Leerzeichen ausgegeben. b) e ist vom INTEGER-Typ und (e:m:H) wird benutzt: In diesem Fall erfolgt die Ausgabe hexadezimal. Falls m=1 oder m=2 ist, wird der Wert (e MOD 16 ) ausgegeben, d.h. die m höchstwertigen Hex-Ziffern ausgegeben. Wenn m>4 ist, werden führende Leerzeichen hinzugeführt. Führende Nullen werden angefügt, wo es notwendig ist. Beispiel: WRITE (2049:m:H); m=1 ergibt: 1 m=2 ergibt: 01 m=3 ergibt: 0801 m=4 ergibt: 0801 m=5 ergibt: 0801 c) e ist vom REAL-Typ und (e), (e:m) oder (e:m:n) wird benutzt Der Wert von e wird in einen Zeichenstring, der eine reelle Zahl darstellt, umgewandelt. Das Format der Darstellung wird durch n festgelegt. Falls n nicht vorhanden ist, wird die Zahl in der Exponentialform (mit Mantisse und Exponent) ausgegeben. Wenn die Zahl negativ ist, wird ein Minuszeichen vor der Mantisse, anderenfalls ein Leerzeichen ausgegeben. Die Zahl wird immer mit mindestens einer Nachkommastelle und mit maximal 5 Nachkommastellen ausgegeben. Der Exponent wird immer mit Vorzeichen notiert. Daraus folgt, daß die minimale Länge der exponentiellen Dar- stellung 8 Zeichen beträgt. Wenn m 8 ist, wird die vollständige Darstellung von 12 Zeichen genommen. Wenn 8 = m = 12 ist, werden mehr oder weniger Dezimalstellen ausgegeben. Ist m > 12, werden führende Leerzeichen angefügt : Beispiel: WRITE(-4.75E+19:m); m=7 ergibt: -4.75000E+19 m=8 ergibt: -4.7E+19 m=10 ergibt: -4.750E+19 m=12 ergibt: -4.75000E+19 m=13 ergibt: -4.75000E+19 Wird die Form (e:m:n) benutzt,so wird die Zahl e in Festkomma- darstellung ausgegeben, wobei n die Zahl der Nachkommastellen angibt. Solange die Länge m nicht ausreichend groß ist, werden keine führenden Leerzeichen ausgegeben. Wenn n=0 ist, ist die Ausgabe eine ganze Zahl. Falls e zu groß ist, um in dem angegebenen Feld dargestellt zu werden, erfolgt die Ausgabe im exponentiellen Format (siehe oben). Beispiel: WRITE(2E2:6:2) ergibt: 200.00 WRITE(2E2:8:2) ergibt: 200.00 WRITE(77.888:6:1) ergibt: 77.9 WRITE(77.8888:2) ergibt: 7.78888E+01 WRITE(77.888:4:0) ergibt: 78 d) e ist vom CHARACTER- oder STRING-Typ: Sowohl (e) als auch (e:m) können verwendet werden. Das Zeichen oder der String werden mit einer minimalen Länge von 1 (bei Zeichen) oder der Länge der Strings (bei STRING-Typen) ausgege- ben. Führende Leerzeichen werden angefügt, wenn m ausreichend groß ist. z.B. 10 PROGRAM StringEinAusgabe; 20 VAR string:ARRAY^1..10_ OF char; 30 a:integer; 40 BEGIN 50 write(chr(12),'Geben Sie bitte einen String von max. 10 Zeichen ein! '); 60 readln; (*Uebergehen der eoln-Marke*) 70 read(string); 80 FOR a:=1 to 13 do writeln(string:a) end. e) e ist von BOOLEAN-Typ: (e) und (e:m) können verwendet werden. 'TRUE' oder 'FALSE' werden in Abhängigkeit vom boolschen Wert e ausgegeben, wobei eine minimale Länge von 4 bzw. 5 verwendet wird. WRITELN Ausgaben mittels WRITELN schließen mit Zeilenvorschub/Wagen- rücklauf ab, d.h. mit einem WRITE (CHR(10),CHR(13)). WRITELN(P1,P2......,P3); entspricht BEGIN WRITE(P1,P2,...,P3);WRITELN END; PAGE Die Prozedur PAGE entspricht einem WRITE (CHR(12)); und bewirkt ein Löschen des Bildschirmes. READ Die Prozedur READ liest Daten von der Tastatur. Dies erfolgt über einen Puffer, der sich in den Runtimes befindet. Dieser ist anfangs leer (bis auf eine Zeilenende-Markierung). Man kann sich den Zugriff auf diesen Puffer so vorstellen, daß ein Textfenster über den Puffer gelegt wird, durch welches jeweils ein Zeichen sichtbar ist. Wenn dieses Textfenster über einer Zeilenende- Markierung liegt, wird vor dem Abschluß der READ-Operation eine neue Textzeile von der Tastatur in den Puffer gelesen. READ (V1, ....,Vn); entspricht: BEGIN READ (V1); READ(V2);.....;READ(Vn) END; wobei V1, V2, usw. vom Typ CHARACTER, STRING, INTEGER oder REAL sein müssen. Während der Eingabe können die Steuertasten (siehe Abschnitt 2.1.) benutzt werden. 4 Fälle sind zu betrachten: a) V ist vom CHARACTER-Typ In diesem Fall liest READ (V) nur ein Zeichen aus dem Eingabe- puffer und weist es V zu. Wenn das Textfenster über einer Zeilen- markierung (CHR (13)) liegt, liefert die Funktion EOLN den Wert TRUE und eine neue Textzeile wird von der Tastatur gelesen. Achtung !: Nach dem Start des Programms ist EOLN=TRUE, d.h. falls zuerst ein READ eines CHARACTER-Typ erfolgt, wird ein CHR(13) übergeben und daraufhin eine neue Zeile von der Tastatur gelesen. Ein anschließendes READ eines CHARACTERs übergibt das erste Zeichen dieser Zeile, vorausgesetzt, sie ist nicht leer.(Siehe auch unter READLN) b) V ist vom STRING-Typ Wird ein String mittels READ gelesen, werden so viele Zeichen eingelesen, wie bei der Stringdefinition als Länge angegeben wurden, bzw. so viele bis EOLN=TRUE ist. Falls der String durch READ nicht gefüllt wird (d.h. falls das Zeilenende erreicht ist, bevor das Stringende erreicht ist), wird der Rest des Strings mit CHR(0) aufgefüllt. Das ermöglicht dem Programmierer die Länge des eingelesenen Strings zu ermitteln (siehe vorheriges Beispiel). Die unter a) gemachte "Achtung !"- Bemerkung gilt auch hier. c) V ist vom INTEGER-Typ In diesem Fall wird eine Reihe von Zeichen eingelesen, die eine INTEGER-Zahl darstellen. Alle vorausgehenden Leerzeichen und Zeilenende-Markierungen werden übergangen. (Das bedeutet das INTEGER-Zahlen direkt eingelesen werden können). Wenn die eingelesene Zahl größer als MAXINT (32767) ist, wird der Runtime-Fehler "Number too large" ausgegeben und das Programm gestoppt. Wenn das erste eingelesene Zeichen (nachdem Leerzeichen und Zeilenende-Markierung übersprungen wurden) keine Ziffer oder Vorzeichen ist, wird der Fehler "Number expected" angezeigt und das Programm abgebrochen. d) V ist vom REAL-Typ Hierbei wird eine Zeichenfolge eingelesen, die eine REAL-Zahl darstellt. Alle führenden Leerzeichen und Zeilenende-Markierungen werden übergangen, und wie bei c) muß das erste andere Zeichen eine Ziffer oder Vorzeichen sein. Wenn die Zahl zu groß oder zu klein ist, wird der Fehler "Overflow" angezeigt, wenn 'E' ohne nachfolgendes Vorzeichen oder Ziffer eingelesen wird, tritt Fehler "Exponent expected" auf und wenn ein Dezimalpunkt ohne nachfolgende Ziffer gelesen wird, kommt es zum Fehler "Number expected". Die Zahleneingabe kann mittels der boolschen Variablen ERRFLG und ERRCHK programmtechnisch überwacht werden (siehe Abschnitt 4.3.3.) READLN READLN(V1,V2,....,Vn); entspricht: BEGIN READ(V1,V2,....,Vn); READLN END; READLN liest einen neuen Pufferinhalt von der Tastatur. Nach der Ausführung von READLN wird EOLN = FALSE, es sei denn, die nächste Textzeile ist leer. READLN kann verwendet werden, um die zu Beginn der Programmaus- führung vorhandene leere Zeile zu überspringen, d.h. es wird ein neuer Puffer gelesen. Diese Maßnahme ist nützlich, wenn zu Beginn eines Programms ein CHARACTER eingelesen werden soll, aber nicht notwendig, wenn Zahlen (da Zeilenende-Markierungen übersprungen werden) oder Zeichen von späteren Zeilen eingelesen werden sollen. z.B. 10 PROGRAM readchar; 20 VAR ch:char; 30 BEGIN 40 REPEAT 50 WRITELN; WRITE('Geben Sie einige Zeichen ein! '); 60 READLN; 70 WHILE NOT EOLN DO 80 BEGIN 90 READ(ch); 100 WRITELN('Das "',ch,'"entsprechende ASCII-Zeichen ist ',ORD(ch)); 110 END 120 UNTIL ch='z' 130 END. EOLN Diese Standardfunktion hat den Wert TRUE, wenn als nächstes zu verarbeitendes Zeichen das eoln-Zeichen (CHR(13)) erkannt wurde, sonst hat die Funktion den Wert FALSE. INCH Die Funktion INCH fragt die Tastatur ab, ob eine Taste gedrückt wurde. Ist dies der Fall, liefert die Funktion das dieser Taste zugehörige Zeichen, ansonsten CHR(0). Diese Funktion ist günstig mit der Compiler-Direktive C- einsetzbar. z.B. 10 PROGRAM inch; 20 VAR c:char;a:integer; 30 BEGIN (*$c-*) 40 REPEAT 50 a:=random(0);c:=inch; 60 IF c='z' THEN BEGIN 70 writeln('Taste ^z_ wurde ausgelesen !');halt end 80 UNTIL a>32766; 90 write('zu spaet!!!') 100 end. 4.6.2. Arithmetische Funktionen ------------------------------- Arithmetische Funktionen sind nur für INTEGER oder REAL-Zahlen (im folgenden mit x bezeichnet) erlaubt. ABS(x) liefert den Absolutwert von x. Das Ergebnis ist vom gleichen Typ wie x. z.B. ABS(-6.93) = 6.93 SQR(x) liefert das Quadrat der Zahl x. Das Ergebnis ist vom gleichen Typ wie x. z.B. SQR(5.5) = 30.25 SQRT(x) liefert die Quadratwurzel von der Zahl x. Das Ergebnis ist immer vom Typ REAL. z.B. SQRT(100) = 1.00000E+01 FRAC(x) liefert die Differenz vom Wert x zur nächst gelegenen INTEGER-Zahl kleiner oder gleich x. Das Ergebnis ist vom Typ REAL. z.B. FRAC(2.9) = 0.9 FRAC(-2.6) = 0.4 FRAC(-2.4) = 0.6 ENTIER(x) liefert für den Wert x die größte INTEGER-Zahl kleiner oder gleich x. Das Ergebnis ist vom Typ INTEGER. z.B. ENTIER(2.9) = 2 ENTIER(-2.6) = -3 ENTIER(-2.4) = -3 FRAC und ENTIER dienen dem Erstellen schneller mathematischer Routinen. SIN(x) liefert den Sinus von x als REAL-Zahl. Die Variable x ist in Bogenmaß anzugeben. z.B. SIN(3.14/2) = 1.00000E+00 COS(x) liefert den Cosinus von x als REAL-Zahl. Die Variable x ist in Bogenmaß anzugeben. z.B. cos(3.14/3) = 5.00461E-01 TAN(x) liefert den Tangens von x als REAL-Zahl. Die Variable x ist in Bogenmaß anzugeben. z.B. TAN(3.14/4) = 9.99201E-01 ARCTAN(x) liefert den Winkel im Bogenmaß, dessen Tangens gleich x ist. Das Ergebnis ist vom Typ REAL. z.B. ARCTAN(9.99201E-01) = 7.84998E-01 EXP(x) liefert die Exponentialfunktion e hoch x als reelle Zahl. (e = 2.71828) z.B. EXP(2.5) = 1.21825E+01 LN(x) liefert den natürlichen Logarithmus (zur Basis e) von x als reelle Zahl;die Variable x muß größer Null sein. z.B. LN(1.21825E+01) = 2.50000E+00 4.6.3. Skalarfunktionen ----------------------- PRED(C) liefert den Vorgänger von C. C kann von jedem einfachen Typ (außer REAL) sein. z.B. PRED('b') = 'a' SUCC(C) liefert den Nachfolger von C. C kann von jedem einfachen Typ (außer REAL) sein. z.B. SUCC('a') = 'b' ODD(y) liefert den Wert TRUE für ungeradzahlige INTEGER- Zahlen; gerade Zahlen ergeben FALSE. z.B. ODD(23) = 'TRUE' 4.6.4. Konvertierungsfunktionen ------------------------------- ROUND(x) rundet auf die nächstgelegene INTEGER-Zahl entspre- chend den Rundungsregeln. z.B. ROUND(-6.5) = -6 TRUNC(x) liefert den ganzzahligen Teil (INTEGER) der reellen Zahl x. Es werden also die Stellen hinter dem Dezimalpunkt abgeschnitten. z.B. TRUNC(-7.9) = -7 CHR(y) liefert das dem Wert von y (INTEGER) entsprechende ASCII-Zeichen. z.B. CHR(78) = 'N' ORD(C) liefert die Ordnungsnummer (INTEGER) des Wertes von x, innerhalb der definierten Wertemenge, wobei x von jedem einfachen Typ (außer REAL) sein kann. z.B. ORD('n') = 110 ORD(-131) = -131 TYPE farbe=(rot,gruen,blau); ORD(gruen) = 1 4.6.5. Weitere Funktionen und Prozeduren ---------------------------------------- NEW(V) Mit der Prozedur NEW ist es möglich, Speicherplatz für dynamische Variablen zu reservieren. V ist eine Zeigervariable, und nachdem NEW(V) ausgeführt wurde, enthält V die Adresse der neu zugewie- senen dynamischen Variablen. Zur Erstellung verketteter Listen wird V selbst, meist als Bestandteil einer Recordvariablen, abgespeichert. Die Größe des zu reservierenden Speicherplatzes hängt vom Typ von V ab; der Typ selbst kann beliebig sein und ist identisch mit dem der dynamischen Variablen. Der Zugriff auf die dynamische Variable erfolgt über V . Der erneute Aufruf von NEW(V) führt zu neuer Speicherplatzreser- vierung. (siehe Abschnitt 4.3.3.) MARK(V1) In KC PASCAL ist die Freigabemethode nach Bowles implementiert. Dabei wird über MARK(V1) der aktuelle Stand der Halde, auf der die dynamischen Variablen abgelegt werden, auf die Zeigervariable V1 gespeichert. Der Typ der Variablen, auf die V1 zeigt, ist gleichgültig, da V1 nur mit MARK und RELEASE, niemals mit NEW verwendet werden darf. RELEASE(V1) RELEASE(V1) ist nur nach MARK(V1) zu verwenden, wobei die Zeigervariable V1 zwischendurch nicht manipuliert werden darf. Über den Aufruf von RELEASE(V1) wird sämtlicher Speicherplatz ab der Adresse, auf die V1 weist, bis zum Ende des Bereichs der dynamischen Variablen gelöscht und kann nun über NEW(V) neu verwendet werden. RELEASE(V1) stellt also wieder den Zustand her, der zum Zeitpunkt des vorhergehenden Prozeduraufrufs MARK(V1) existierte. Ein Beispiel dazu ist im Abschnitt 4.3.3. zu finden. INLINE(z1,z2,...) Mit dieser Prozedur kann Z80-Maschinencode direkt in das PASCAL- Programm eingebunden werden. Der Operationscode wird dezimal oder hexadezimal (#) als Parameter der INLINE-Anweisung übernommen. Die Anzahl der Parameter ist beliebig. Sie werden während des Übersetzens an der Stelle, an der sich der Compiler gerade befindet, in das Objekt-Programm eingefügt. Mit dem Einbau direkter Maschinenbefehle kann das Laufzeitverhal- ten von PASCAL-Programmen verbessert, sowie spezielle Abläufe programmiert werden. USER(V) Die Prozedur bewirkt den Aufruf eines Maschinenunterprogrammes an der durch V spezifizierten Adresse (INTEGER-Wert). Da INTEGER- Zahlen in Zweierkomplement-Form bearbeitet werden, müssen Adressen, die größer als #7FFF (32767) sind, als negative Zahlen eingegeben werden. Günstiger ist es, die Speicheradresse gleich als hexadezimale Zahl einzugeben. z.B. USER(#C000) = USER(-16384) Die aufgerufene Routine muß mit dem Z80-Befehl RET (#C9) enden und darf den Wert im IX-Register nicht überschreiben. Die dazu notwendigen Register A, B, C, D, E, H, L und F werden vor der Abarbeitung des Unterprogramms mit den vordefinierten Variablen RA, RB, RC, RD, RE, RH, RL und RF (oder auch RAF, RBC, RDE, RHL) belegt und nach RET in die vordefinierte Variablen zurückgeschrieben. Die vom Betriebssystem angebotenen Maschinenunterprogramme sind dem Systemhandbuch zu entnehmen. HALT Diese Prozedur stoppt die Programmausführung und gibt die Meldung "Halt at PC=xxxx", wobei xxxx die hexadezimale Speicheradresse ist, an der der Abbruch erfolgte. HALT kann zusammen mit dem Compiler-Listing zur Fehlersuche verwendet werden (z.B. beim Testen, welche Schleifen durchlaufen werden). PEEK(X.T) X ist ein INTEGER-Wert und stellt die Speicheradresse dar, von der Daten beliebigen Typs (T) gelesen werden können. Die Datenoperationen erfolgen bei PEEKs und POKEs in KC PASCAL typischer Datendarstellung (siehe Abschnitt 4). z.B. Im Speicher steht ab der Adresse #6000 die HEX-Bytes 4B 43 20 50 41 53 43 41 4C WRITE(PEEK(#6000,ARRAY^1...9_ OF CHAR)); ergibt 'KC PASCAL' WRITE(PEEK(#6000,CHAR)); ergibt 'K' WRITE(PEEK(#6000,INTEGER)); ergibt 17227 WRITE(PEEK(#6000,REAL)); ergibt 1.84758E+20 POKE(X,V) POKE schreibt den Ausdruck V ab Adresse X aufwärts in den Speicher. X ist vom INTEGER-Typ und V kann von jedem Typ (außer SET) sein. z.B. POKE(#6000,'KC PASCAL'); POKE(-16384,2.1E-1); ADDR(V) V ist ein Variablenname beliebigen Typs. Die Funktion liefert die Speicheradresse, ab der die Variable V im Speicher steht, als INTEGER-Zahl. SIZE(V) Über die Funktion SIZE(V) kann der Speicherplatzbedarf der Variablen V ermittelt werden. TOUT(NAME,START,SIZE) Mit TOUT werden Variablen auf einen externen Speicher abgelegt. Der Dateiname (NAME) ist vom Typ ARRAY^1...12_ OF CHAR. Fehlende Zeichen im Dateinamen sind mit Leerzeichen aufzufüllen. START symbolisiert die Startadresse, ab der die Variable abgespeichert wird und SIZE die Anzahl der auszugebenden Bytes. START und SIZE sind vom INTEGER-Typ. Soll eine Datei auf Diskette abgespeichert werden, so ist im Dateinamen an 9.Stelle der Punkt vorzusehen. Über die freie Wahl der Startadresse und der Größe des Speicher- bereiches, der auszulagern ist, hat der Programmierer die Möglichkeit, ganze Bildschirmbereiche, globale Variablen usw. in einer Datei zu sichern. TIN(NAME,START) Mit dieser Prozedur können durch TOUT gesicherte Variablen etc. wieder vom externen Speichergerät geladen werden. Der Parameter NAME ist wiederum vom Typ ARRAY^1...12_ OF CHAR. Das Speicher- gerät wird nach einer Datei mit diesem Namen durchsucht und, falls gefunden, in den Speicher ab Adresse START (INTEGER-Zahl) geladen. Die Anzahl der zu ladenden Bytes ist durch TOUT mit abgespeichert worden und wird von dort übernommen. Beispiel: Eine Datei mit 10 Zeichen soll erst auf Kassette/ Diskette ausgelagert und die Variable a mit einer anderen Datei überschrieben werden. 10 PROGRAM EinAusgabe; 20 VAR a:ARRAY^1..10_ OF char; 30 BEGIN 40 writeln('Geben Sie max. 10 Zeichen ein !'); 50 readln;read(a); writeln('a alt= ',a); 60 tout('zeichenk.alt',addr(a),size(a); 70 tin('zeichenk.neu',addr(a)); 80 writeln('a neu=',a) 90 end. INP(P) Über die Funktion INP kann man direkt auf den Z80-Input-Port zugreifen, ohne die Inline-Prozedur zu benutzen. Der INTEGER-Wert P wird in das BC-Registerpaar geladen und der Assembler-Befehl IN A,(C) ausgeführt. Das Ergebnis ist vom Typ CHAR. OUT(P,C) Über die Prozedur OUT kann man direkt auf den Z80-Output-Port zugreifen, ohne die Inline-Prozedur zu benutzen. Der INTEGER-Wert P wird in das BC-Registerpaar und der CHARACTER- Wert C in das A-Register geladen; dann wird der Assembler-Befehl OUT(C),A ausgeführt. z.B. OUT(1,'Z'); gibt das Zeichen 'Z' an den Z80-Port 1 aus. EXTERNAL(S1,V1,V2,...) Die Prozedur EXTERNAL ermöglicht den Aufruf von externen ROM- oder von nachladbaren RSX-Befehlen. Damit wird der Wortschatz von KC PASCAL erheblich, vornehmlich für die Arbeit mit Diskettensystem, erweitert. Die EXTERNAL-Prozedur ähnelt dem Kommando ' ' , das von der Kommandoebene zu erreichen ist, sowie dem BASIC-Befehl ' ' (die einzelnen Befehle können dem BASIC-Handbuch entnommen werden). S1 ist vom Typ STRING und bezeichnet den Namen des externen Befehls. Die weiteren Parameter können vom Typ STRING, CHAR oder INTEGER sein und sind, falls benötigt, anzugeben. Mit der Funktion ADDR(V) kann auch eine Variable an die externe Prozedur übergeben werden. z.B. EXTERNAL('DISC'); stellt als Ein-Ausgabemedium für die Befehle TIN, TOUT die Diskette ein. EXTERNAL('DIR','*.'); gibt das Dirctory aller PASCAL- Quelldateien aus. Sollte ein RSX-Befehl ausgeführt werden, ist es notwendig, vorher die Firmware-Routine KL LOG EXT aufzurufen, die die RSX-en initialisiert, da nach Abarbeitung eines Programms alle Ereignis- Warteschlangen und RSX-en gelöscht werden. RANDOM(X) Die Funktion RANDOM gibt eine positive Pseudozufallszahl zurück. Sie ist vom Typ INTEGER und liegt im Bereich 0...MAXINT. Ist der zu übergebende INTEGER-Parameter gleich Null, stellt RANDOM(0) die nächste Zufallszahl dieser Sequenz bereit. Ist der Parameter X >0, so wird eine neue Sequenz von Zufallszahlen gestartet, wobei X selbst die erste Zufallszahl ist. AFTER(ZEIT,ZEITGEBER,PROCEDURE) Die Prozedur AFTER ruft nach Ablauf der durch den Parameter ZEIT angegebenen Zeit (in Einheiten zu 0,02 Sekunden) die parameterlose Prozedur PROCEDURE auf. Der Parameter ZEITGEBER spezifiziert einen der 4 (0...3) Zeitgeber. Zeitgeber 3 hat die höchste , Zeitgeber 0 die niedrigste Priorität. Die ersten beiden Parameter sind als INTEGER-Werte anzugeben. z.B. AFTER(10,3,ZAEHLE); startet die Prozedur ZAEHLE durch Zeitgeber 3 nach 0,2 Sekunden. EVERY(ZEIT,ZEITGEBER,PROCEDURE) Die Prozedur EVERY bewirkt das Aufrufen der Prozedur PROCEDURE (ohne Parameter) in regelmäßigen, durch den Parameter ZEIT(in 0,02 Sekunden) angegebenen, Zeitabständen. Ansonsten gilt das unter AFTER Vermerkte. z.B. EVERY(10,1,ZAEHLE); ruft die Prozedur ZAEHLE durch Zeitgeber 1 alle 0,2 Sekunden auf. Achtung: EVERY- und AFTER-Befehle beeinflussen sich für einen bestimmten Zeitgeber gegenseitig ! REMAIN(ZEITGEBER) Diese Funktion gibt die verbleibende Restzeit des als INTEGER- Parameter anzugebenden Zeitgebers (0...3) an und setzt ihn außer Kraft. Das Ergebnis ist vom Typ INTEGER; Null wird zurückgegeben, wenn der entsprechende Zeitgeber ausgeschaltet war. ENV(N,P1,Q1,R1,P2,Q2,R2,...) Die Prozedur ENV definiert die Lautstärkehüllkurve für den SOUND- Befehl und ist identisch mit dem BASIC-Befehl gleichen Namens. Sie bewirkt das Anschwellen und Abklingen des Tones, ausgehend von der Lautstärke, die im SOUND-Befehl vorgegeben wird. Folgende INTEGER-Parameter sind anzugeben: N Hüllkurvennummer (1...15) P Schrittanzahl; Anzahl der Lautstärkeänderungen in einem Hüllkurvenabschnitt (0...127) Q Schrittweite; Differenz zwischen den jeweiligen Lautstärkeschritten. Die Differenz kann Werte zwischen 0 und 15 annehmen, da im SOUND-Befehl 16 verschiedene Lautstärkegrade möglich sind. Weil die Eingabe aller INTEGER-Werte möglich ist, kehrt die Lautstärke jedes Mal auf 0 zurück, wenn sie das Maximum überschritten hat. R Schrittzeit; Zeit zwischen den einzelnen Laustärkeschritten in 1/100 Sekunden (0...255) Zu beachten ist, daß die Dauer aller Lautstärkeschritte zusammen nicht länger als die Dauer des Tons, der im SOUND- Befehl definiert ist, sein sollte. Der Ton wird sonst vor- zeitig abgebrochen und die restlichen Hüllkurvenabschnitte werden nicht abgearbeitet. Ist dagegen die Dauer des Tons im SOUND-Befehl größer, verbleibt der Ton für die restliche Zeit auf der letzten Lautstärkestufe. P, Q, R bilden zusammen einen Hüllkurvenabschnitt, von denen fünf in einem ENV-Befehl definiert werden können. z.B. ENV(1,3,1,2,1,0,6,2,-2,2); Lautstärke /! ! 15 --- ! --- ! --- ! --- 7 = Anfangs-Lautstärke vom SOUND-Befehl ! --- ! --- !-----!-----------------! ! ! ! ! --- !-----! ! ! ! ! ! ! -------! ! !-----! ! ! ! ! 7 ----!--!--!--!--!--!--!--!--!--!--!--!--!--!--!--!--!--!--!--> ! ! ! ! --- ! ! !------ Zeit in ! ! ! 1/100 s --- ! ! ! ! ! --- ! ! ! 1. Abschnitt ! 2. Abschnitt ! 3.Abschnitt --- ! --- ! --- ! 0 --- Neben diesen Software-Hüllkurven gibt es noch Hardware- Hüllkurven, die durch folgende Parameter beschrieben werden: 1. Hüllkurven-Form (größer als 128) Dieser Parameter wird in das Lautstärkeregister des Tongenerators geschrieben. 2. Niederwertiges Byte der Hüllkurvenperiode (wird in das Hüllkurven-Register des Tongenerators geschrieben) 3. Höherwertiges Byte der Hüllkurvenperiode (wird in das Hüllkurven-Register des Tongenerators geschrieben) Die Nutzung dieser Hardware-Hüllkurven setzt umfangreiche Kenntnisse der Hardware voraus. ENT (N,P1,Q1,R1,P2,Q2,R2,...) Die Prozedur ENT definiert die Tonhüllkurve für den SOUND-Befehl und ist identisch mit dem BASIC-Befehl gleichen Namens. Sie bewirkt kleine Frequenzschwankungen betreffend des Tones, der im SOUND-Befehl definiert wird, d.h. man kann den Ton in seiner Tonhöhe noch etwas variieren, etwa wie beim Vibrato. Folgende INTEGER-Parameter sind anzugeben: N Hüllkurvennummer (1...15) Wird die Hüllkurvennummer mit einem Minuszeichen versehen, dann wird die Tonhüllkurve so oft wiederholt, wie der Dauer- Parameter im SOUND-Kommando angibt (wird aber im SOUND- Kommando nicht negativ aufgerufen). P Schrittanzahl (0...239) Anzahl der Tonhöhenschritte in einem Abschnitt Q Schrittweite (-128...127) Differenz zwischen den jeweiligen Tonhöhenschritten. Mit positiven Schritten nimmt die Tonhöhe ab, mit negativen Schritten nimmt sie zu. R Schrittzeit (0...255) Zeit zwischen den einzelnen Tonhöhenschritten in 1/100 Sekunden. Zu beachten ist, daß die Summe der Schrittzeiten wiederrum im richtigen Verhältnis zum Dauer-Parameter im SOUND-Befehl steht (siehe ENV). P, Q, R bilden zusammen einen Hüllkurvenabschnitt, von denen fünf in einem ENT-Befehl definiert werden können. Eine Variation von P, Q und R (auch beim ENV-Befehl) über die vorgegebenen Grenzen hinaus, können mitunter interessante Effekte hervorrufen. Neben dieser Form des schrittweisen Verändern der Tonhöhe, kann man sie auch absolut in der ENT-Prozedur setzen. Der absolute Hüllkurven-Abschnitt (siehe BASIC-Handbuch) mit den zwei Parametern, Tonperiode und Pausenzeit, entspricht unter KC PASCAL 240 + Tonperiode DIV 256, Tonperiode MOD 256, Pausenzeit. Tonperiode ist ein ganzzahliger Ausdruck zwischen 0...4095 und entspricht der Tonhöhe. Pausenzeit ist äquivalent der Schrittzeit - der Zeit, in der ein Ton ohne Veränderung klingt. Diese Form der Tonhüllkurvengenerierung sollte jedoch ebenfalls nur Hardware-Kennern vorbehalten sein. SOUND(K,LH,TH,T,G,L,D) Die SOUND-Prozedur dient der Ausgabe von Tönen über bis zu 3 Kanälen. Die Hüllkurven (Ton- und Lautstärke-) müssen vorher definiert sein. Die Parameter sind als INTEGER-Werte einzugeben. Ihre ausführliche Beschreibung ist im BASIC-Handbuch zu finden. Lediglich die Reihenfolge der Parameterangabe ist verschieden. K Kanalstatus (1...255), bitsignifikant BIT Dezimalwert ----------------------------------------------------------------- 0 0 Ton wird zum Kanal A geschickt 1 2 Ton wird zum Kanal B geschickt 2 4 Ton wird zum Kanal C geschickt 3 8 Rendezvous mit Kanal A 4 16 Rendezvous mit Kanal B 5 32 Rendezvous mit Kanal C 6 64 Halte den Tonkanal 7 128 Leere den Tonkanal LH Lautstärkehüllkurve (1...15) Der Parameter LH entspricht der Hüllkurvennummer in der ENV- Prozedur. Damit wird der SOUND-Ausgabe die entsprechende Lautstärkehüllkurve, die vorher definiert wurde, zur Verfügung gestellt. TH Tonhüllkurve (1...15) Der Parameter TH entspricht der positiven bzw. negativen Hüllkurvennummer in der ENT-Prozedur. Damit wird der SOUND- Ausgabe die entsprechende Tonhüllkurve, die vorher definiert wurde, zur Verfügung gestellt. Ist die Hüllkurvennummer im ENT-Befehl negativ, so wird der Verlauf der Tonhüllkurve bis zum Ende der SOUND-Ausgabe wiederholt; TH wird jedoch positiv angegeben. T Tonperiode bzw. Tonhöhe (16...3822) Dieser Bereich von T umspannt 8 Tonoktaven. z.B. T=239 Mittleres C T=142 Kammerton A Die über T angegebene Tonhöhe ist die Anfangstonhöhe, die in ihrem zeitlichen Verlauf mittels der Tonhüllkurve (ENT) variiert werden kann. G Geräuschperiode (0...31) Dieser Parameter erzeugt "Weißes Rauschen", womit die Tonausgabe begleitet werden kann. L Lautstärke (0...15) Dieser Parameter bestimmt die Lautstärke am Anfang des Tones. Der weitere zeitliche Verlauf wird über die Prozedur ENV festgelegt. D Tondauer in 1/100 Sekunden SQ(K) Diese Funktion gibt die Anzahl der freien Plätze in der Tonwarteschlange des Kanals K zurück, wobei K=1 Kanal A K=2 Kanal B und K=4 Kanal C ist. Das Ergebnis dieser Funktion ist vom Typ INTEGER und bitsignifikant, wobei die einzelnen Bits folgende Bedeutung haben: Bit 0, 1, 2 Anzahl der freien Plätze in der Warteschlange Bit 3, 4, 5 Rendezvous-Zustand am oberen Ende der Warteschlange Bit 6 das obere Ende der Warteschlange befindet sich im Haltezustand Bit 7 der Kanal ist gerade aktiv ONSQ(KANAL,PROCEDURE) Diese Prozedur ermöglicht den Aufruf einer weiteren Prozedur, falls bei der Tonausgabe ein Platz in der Tonwarteschlange des betreffenden Kanals frei geworden ist. KANAL ist ein ganzzahliger Ausdruck mit gleichen Werten wie unter SQ(K). INITEVENT(ZEITGEBER,PROCEDURE) Diese Funktion initialisiert einen Ereignis-Block für synchrone Ereignisse und übergibt als Ergebnis die Speicheradresse (INTEGER) auf der die PROCEDURE beginnt und bei Eintritt des Ereignisses aufgerufen werden soll. Der INTEGER-Parameter ZEITGEBER gibt die Ereignis-Klasse bzw. den Zeitgeber an. Mit dieser Funktion kann der Programmierer auf den Betriebssystemkern zugreifen. KC PASCAL # Sprachbeschreibung 4.7. Compiler-Direktiven Compiler-Direktiven, die in Form von Pseudokommentaren an beliebiger Stelle im Quelltext codiert werden, dienen dazu, Sonderabläufe während der Übersetzung und Abarbeitung des Programms vorzusehen. Der Liste der Compiler-Direktiven muß ein "$"-Zeichen vorangestellt werden. (*$C-,I-*) (*$A-*) Für alle Compiler-Direktiven sind Standardwerte vorgegeben, die falls gewünscht, geändert werden können. Folgende Direktiven stehen zur Verfügung: A Indexprüfung Standardwert: A+ Mit der Standardeinstellung A+ wird während der Laufzeit geprüft, ob Bereichsüberschreitungen bei ARRAY-Indizes vorliegen. Ein zu großer oder zu kleiner ARRAY-Index bewirkt einen Programm-Stop und die Fehlerausschrift "Index too high" oder "Index too low". A- schaltet die ARRAY-Überprüfung aus und ist damit in der Laufzeit schneller. C Tastaturabfrage Standardwert: C+ Durch C+ wird erreicht, daß von der Tastatur durch Betätigen einer beliebigen Taste das Programm unterbrochen und durch nachfolgendes ^ESC_ abgebrochen werden kann. Eine andere Taste außer ^ESC_ bewirkt die Fortsetzung des Programms. Die Tastaturabfrage wird zu Beginn jeder Schleife, Prozedur und Funktion durchgeführt und vergrößert dadurch die Abarbeitungszeit. C- schaltet die Tastaturabfrage aus (außer INCH-Funktion). F Include-Datei Im Gegensatz zu den anderen Compiler-Direktiven muß bei F ein Leerzeichen und ein 12 Zeichen langer Dateiname folgen. Ist der Dateiname kürzer, muß er mit Leerzeichen aufgefüllt werden. Die Quelltextdatei unter diesem Namen wird auf Kassette oder Diskette gesucht und falls gefunden, an die Stelle der F- Direktive geladen. Mit dieser Direktive steht dem Programmierer ein geeignetes Mittel zum Erstellen von Prozedur- und Funktionsbibliotheken, die dann in jedes Programm im Deklarationsteil einfügbar sind, zur Verfügung. Ebenfalls kann man dieses Mittel anwenden, wenn bei der Entwicklung sehr langer Programme der Speicherbereich nicht mehr ausreicht. Diese Programme sind dennoch übersetzbar, indem der große Teil des Programms auf Kassette oder Diskette ausgelagert und mit der Include-Anweisung (*$F LANGEQUELLE *) immer nur 128 Byte nacheinander im RAM übersetzt werden. Damit erhöht sich erheblich der Speicherbereich für das übersetzte Programm. Eine Verschachtelung dieser Direktive ist nicht gestattet (in einer Include-Datei darf sich keine weitere befinden). I Überlauftest Standardwert: I- Beim Vergleich zweier INTEGER-Zahlen, die sich um mehr als MAXINT voneinander unterscheiden, entsteht ein falsches Resultat, wenn die übliche 16-bit-Zweierkomplementarithmetik verwendet wird. Bei der Einstellung von I+ wird auch bei solchen Vergleichen ein richtiges Ergebnis gesichert. I- schaltet den Überlauftest aus. Bei arithmetischen Operationen reeller Zahlen kann ebenfalls ein Überlauf auftreten, wenn sich die Operanden um mehr als 3.4E38 unterscheiden. In diesem Fall ist ein Überlauftest nicht möglich. L Listen von Programmen beim Compilieren Standardwert: L+ Mit L+ wird während des Compilierens das Auflisten von Programmtext und Objektcodeadressen ausgeführt. L- erzeugt ein Listing der fehlerhaften Zeilen. O Bereichsüberschreitung Standardwert: O+ Test auf Bereichsüberschreitung bei ganzzahliger Addition und Subtraktion. Eine Abfrage auf Bereichsüberschreitung aller INTEGER-Multiplikationen und -Divisionen sowie aller arithmeti- schen Operationen mit reellen Zahlen wird generell (unabhängig von O+ oder O-) durchgeführt. O- schaltet den Test für ganzahlige Addition und Subtraktion aus. P Ausgabe Compilerlisting P schaltet wechselweise das Compilerlisting auf Drucker oder Bildschirm. Ein "+" oder "-" -Zeichen wird nicht gebraucht. Beim Start des Compilers ist immer der Bildschirm als Ausgabegerät aktiviert. S Stack-Abfrage Standardwert: S+ Zu Beginn jeder Prozedur- und Funktionsabarbeitung wird der Stack auf Überlauf geprüft. Tritt ein Überlauf ein, wird das Programm abgebrochen und es folgt die Fehlerausschrift "Out of RAM at PC=zzzz". Mit dieser Maßnahme können jedoch überflüssige Programmabbrüche hervorgerufen werden. S- schaltet die Stack-Abfrage aus. KC PASCAL # Interne Datendarstellung 5. I n t e r n e D a t e n d a r s t e l l u n g 1. INTEGER INTEGER-Zahlen belegen zwei Bytes im Zeierkomplement. z.B. 16 --> 0010 -2048 --> F800 2. REAL REAL-Zahlen belegen vier Bytes als binäre Werte. Sie liegen in normierter Darstellung im Speicher vor. Exponent: Bit 0...7 ;binäres Zweierkomplement normierte Mantisse: Bit 8...30 ;Bit 29 immer 1 ;bis auf die Zahl 0 Vorzeichen: Bit 31 ;1=negativ ;0=positiv z.B. 2=2*10 =0010 *2 =1.0 *2 =01.00 0000!0000 0000!0000 0000!0000 0001 ! ! ! -10=-10*10 =-1010 *2 ! ! ! =-1.010 *2 =11.01 0000!0000 0000!0000 0000!0000 0011 ! ! ! H ! L ! E ! D Die Register werden in der Reihenfolge E, D, L, H im Speicher abgelegt. 3. CHAR CHAR-Zeichen belegen ein Byte, in das der ASCII-Code des Zeichens abgespeichert wird. 4. BOOLEAN BOOLEAN-Werte belegen ebenfalls ein Byte. z.B. TRUE --> 01 FALSE --> 00 5. RECORDs und ARRAYs Diese Variablen belegen den gleichen Speicherplatz wie die Summe ihrer Komponenten. 6. SETs Mengen werden als Bitketten gespeichert (pro Element der Menge steht ein Bit zur Verfügung). Wenn der Basistyp der Menge n Elemente hat, werden (n-1) DIV 8+1 Bytes benötigt. 7. Zeiger Zeiger belegen zwei Byte. Abgespeichert wird die Adresse der zugeordneten Variablen. Zur Laufzeit des Programms werden die Variablen folgendermaßen eingeteilt und abgespeichert: 1. Globale Variablen sind im Haupt-Block des Programms verein- bart und werden in der Reihenfolge, in der sie deklariert wurden, vom Ende des Runtime-Stack beginnend, abwärts gespeichert. 2. Lokale Variablen sind in Unterblöcken wie PROCEDURE und FUNCTION vereinbart und werden mit Hilfe des IX-Registers lokalisiert. Beim Aufruf der PROCEDURE oder FUNCTION zeigt IX auf den Beginn des inneren Blocks, so daß IX-4 auf den Anfang der lokalen Variablen zeigt. 3. Parameter (Werteparameter) von PROCEDUREn werden wie lokale Variablen behandelt und wie bei diesen gilt: je früher ein Parameter deklariert wurde, desto höher ist seine Speicher- adresse. Die niedrigste Adresse ist jedoch im Gegensatz zu lokalen Variablen IX+2. Variable Parameter belegen immer zwei Byte, die die Adresse der entsprechenden Variablen enthalten. Rückgabewerte von FUNCTIONen werden oberhalb des ersten Parameters der Funktion im Speicher abgelegt. Nachfolgendes Beispiel soll die interne Datendarstellung verdeut- lichen: PROGRAM beispiel; VAR A: INTEGER; B: CHAR; C: REAL; PROCEDURE P(D: INTEGER; E: REAL; VAR F: REAL); VAR G: INTEGER; H: CHAR; I: REAL; BEGIN END; (* of P) FUNCTION K(J: REAL): REAL; VAR L: INTEGER; BEGIN K:=J END; (* of K :) BEGIN (* Hauptprogramm *) . . END. Der Runtime-Stack möge den Standardwert #B000 besitzen. Variable Adressbereich (hexadezimal) A AFFE AFFF B AFFD C AFF9 AFFA AFFB AFFC D IX+8 IX+9 E IX+4 IX+5 IX+6 IX+7 F IX+2 IX+3 G IX-6 IX-5 H IX-7 I IX-B IX-A IX-9 IX-8 J IX+2 Ix+3 IX+4 IX+5 K IX+6 IX+7 IX+8 IX+9 L IX-6 IX-5 KC PASCAL # Anhang A. A n h a n g A1. Fehlermeldungen des Compilers 1 Zahl zu groß 2 Semikolon erwartet 3 nicht vereinbarter Name 4 Name erwartet 5 = und nicht := 6 = erwartet 7 Anweisung darf nicht mit diesem Namen beginnen 8 := erwartet 9 ) erwartet 10 falscher Typ 11 . erwartet 12 Faktor erwartet 13 Konstante erwartet 14 dieser Name ist keine Konstante 15 THEN erwartet 16 DO erwartet 17 TO oder DOWNTO erwartet 18 ( erwartet 19 dieser Ausdrucktyp kann nicht geschrieben werden 20 OF wird erwartet 21 , erwartet 22 : erwartet 23 PROGRAM erwartet 24 Variable erwartet, da der Parameter ein variabler ist 25 BEGIN erwartet 26 READ erwartet eine Variable 27 Ausdrücke dieses Typs können nicht verglichen werden 28 INTEGER- oder REAL-Zahl erwartet 29 dieser Variablentyp kann nicht gelesen werden 30 dieser Name ist kein Typ 31 REAL-Zahl verlangt Exponent 32 skalarer, nicht numerischer Ausdruck erwartet 33 statt Null-String, CHR(0) verwenden 34 ^ erwartet 35 _ erwartet 36 ARRAY-Index muß skalarer Typ sein 37 ..erwartet 38 ARRAY-Deklaration verlangt ^ oder , 39 obere Grenze ist kleiner als untere 40 SET ist zu groß (mehr als 256 Elemente) 41 Funktionstyp muß vom Typ Name sein 42 in SET wird , oder _ erwartet 43 in SET wird .. oder , oder _ erwartet 44 Parameter muß vom Typ Name sein 45 leerer SET kann nicht erster Faktor in einer nicht zuweisenden Anweisung sein 46 einfacher Typ (einschließlich reeller Zahlen) erwartet 47 einfacher Typ (außer reellen Zahlen) erwartet 48 SETs sind nicht verträglich 49 SETs können nicht mit oder > verglichen werden 50 FORWARD, LABEL, CONST, VAR, TYPE oder BEGIN erwartet 51 Hexadezimalziffer wird erwartet 52 SETs können nicht mit POKE abgesetzt werden 53 ARRAY zu groß (mehr als 64K) 54 RECORD-Definition verlangt END oder ; 55 Feldname erwartet 56 Nach WITH wird eine Variable erwartet 57 Variable bei WITH muß vom RECORD-Typ sein 58 der Feldname wurde nicht mit WITH-Anweisung in Verbindung gebracht 59 nach LABEL wird eine vorzeichenlose INTEGER-Zahl erwartet 60 nach GOTO wird eine vorzeichenlose INTEGER-Zahl erwartet 61 Marke in einer falschen Programmebene 62 Marke ist nicht vereinbart 63 Parameter von SIZE muß Variable sein 64 auf Zeiger kann nur Gleichheitstest angewandt werden 67 einzig zulässiger Parameter für INTEGER-Zahlen mit zwei ":" ist e:m:H 68 Strings dürfen kein Zeilenendezeichen enthalten 69 NEW, MARK oder RELEASE verlangt Zeigervariable 70 ADDR verlangt Variable als Parameter 71 der Parameter muß eine Prozedur sein 72 der Parameter muß eine parameterlose Prozedur sein 73 maximal fünf Hüllkurvenabschnitte zulässig A2. Laufzeit-Fehlermeldungen Laufzeitfehler unterbrechen die Programmausführung. Auf dem Bildschirm erscheint eine der folgenden Fehlermeldungen und die Stelle, an der der Fehler auftrat ("at PC=xxxx"). Ist der Fehler nicht anhand der Fehlermeldung einsichtig, kann das Compilerlisting, indem ebenfalls die Adressen der übersetzten Anweisungen stehen, weiterhelfen. 1. Halt Halt 2. Overflow Überlauf 3. Out of Ram Speicher zu klein 4. Division by zero Division durch Null 5. Index too low Index kleiner als Bereichsgrenze 6. Index too high Index größer als Bereichsgrenze 7. Maths Call error Mathematischer Fehler 8. Number too large Zahl zu groß 9. Number expected Zahl erwartet 10. Line too long Zeile zu lang 11. Exponent expected Exponent erwartet A3. Wortsymbole AND DOWNTO IN PACKED TO ARRAY ELSE LABEL PROCEDURE TYPE BEGIN END MOD PROGRAM UNTIL CASE FORWARD NIL RECORD VAR CONST FUNCTION NOT REPEAT WHILE DIV GOTO OF SET WITH DO IF OR THEN A4. Standardbezeichner CONST MAXINT=32767; FALSE,TRUE TYPE BOOLEAN=(FALSE,TRUE); CHAR (*erweiterter ASCII-Zeichensatz*) INTEGER=-MAXINT...MAXINT; REAL VAR ERRFLG, ERRCHK: BOOLEAN; RA, RB, RC, RD, RE, RF, RH, RL: CHAR; RAF, RBC, RDE, RHL: INTEGER; PROCEDURE AFTER, ENT, ENV, EVERY, EXTERNAL, HALT, INLINE, MARK, NEW, ONSQ, OUT, PAGE, POKE, READ, READLN, RELEASE, SOUND, TIN, TOUT, USER, WRITE, WRITELN FUNCTION ABS, ADDR, ARCTAN, CHR, COS, ENTIER, EOLN, EXP, FRAC, INCH, INITEVENT, INP, LN, ODD, ORD, PEEK, PRED, RANDOM, REMAIN, ROUND, SIN, SIZE, SQR, SORT, SUCC, TAN, TRUNC A5. Listing des Demonstrationsbeispiels 10 PROGRAM demonstration; 20 (*$l-*) 30 VAR a,b,musikadr,zaehler:integer; 40 Xcor,Ycor,heading:real; 50 sec,min,stunden:integer; 60 anz:integer; 70 80 PROCEDURE musik; 90 LABEL 1111; 100 BEGIN 110 IF zaehler>24 THEN GOTO 1111; 120 sound(7,1,1,602-zaehler*20,0,0,75); 130 zaehler:=zaehler+1; 140 1111: END; 150 160 PROCEDURE setcursor(spalte,zeile:integer); 170 BEGIN 180 rh:=chr(spalte); rl:=chr(zeile); 190 user(#bb75) 200 END; 210 220 PROCEDURE getcursor(VAR spalte,zeile:integer); 230 BEGIN 240 user(#bb78); 250 spalte:=ord(rh); zeile:=ord(rl) 260 END; 270 280 PROCEDURE uhrzeit; 290 VAR spalte,zeile:integer; 300 BEGIN 310 sec:=sec+1; 320 IF sec=60 THEN 330 BEGIN 340 sec:=0; min:=min+1; 350 IF min=60 THEN 360 BEGIN 370 min:=0; stunden:=stunden+1 380 END 390 END; 400 getcursor(spalte,zeile); 410 setcursor(72,1); 420 write(stunden:2,':',min:2,':',sec:2); 430 setcursor(spalte,zeile) 440 END; 450 460 PROCEDURE mode(m:integer); 470 BEGIN 480 ra:=chr(m); 490 user(#bc0e) 500 END; 510 520 PROCEDURE pen(i:integer); 530 BEGIN 540 ra:=chr(i); 550 user(#bbde) 560 END; 570 580 PROCEDURE paper(i:integer); 590 BEGIN 600 ra:=chr(i); 610 user(#bbe4) 620 END; 630 640 PROCEDURE ink(i,c1,c2:integer); 650 BEGIN 660 ra:=chr(i); rb:=chr(c1); rc:=chr(c2); 670 user(#bc32) 680 END; 690 700 PROCEDURE plot(x,y:integer); 710 BEGIN 720 rde:=x; rhl:=y; 730 user(#bbea) 740 END; 750 760 PROCEDURE line(x,y:integer); 770 BEGIN 780 rde:=x; rhl:=y; 790 user(#bbf6) 800 END; 810 820 PROCEDURE setXY(x,y:real); 830 BEGIN 840 XCOR:=x; 850 Yc80 PROCEDURE paper(i:integer); 590 BEGIN 600 ra:=chr(i); 610 user(#bbe4) 620 END; 630 640 PROCEDURE ink(i,c1,c2:in80 PROCEDURE paper(i:integer); 590 BEGIN 600 ra:=chr(i); 610 user(#bbe4) 620 END; 630 640 PROCEDURE ink(i,c1,c2:integer); 650 BEGIN 660 ra:=chr(i); rb:=chr(c1); rc:=chr(c2); 670 user(#bc32) 680 END; 690 700 PROCEDURE plot(x,y:integer); 710 BEGIN 720 rde:=x; rhl:=y; 730 user(#bbea) 740 END; 750 760 PROCEDURE line(x,y:integer); 770 BEGIN 780 rde:=x; rhl:=y; 790 user(#bbf6) 800 END; 810 820 PROCEDURE setXY(x,y:real); 830 BEGIN 840 XCOR:=x; 850 Ycor:=y 860 END; 870 880 PROCEDURE fwd(len:real); 890 CONST PIby180=1.745329E-2; 900 VAR newX,newY:real; 910 BEGIN 920 plot(round(Xcor),round(Ycor)); 930 newX:=Xcor+len*COS(heading*PIby180); 940 newY:=Ycor+len*SIN(heading*PIby180); 950 line(round(newX),round(newY)); 960 Xcor:=newX; 970 Ycor:=newY 980 END; 990 1000 PROCEDURE right(angle:real); 1010 BEGIN 1020 heading:=heading-angle 1030 END; 1040 1050 PROCEDURE init; 1060 BEGIN 1070 ink(0,24,24); 1080 ink(1,2,2); 1090 paper(0); 1100 pen(1); 1110 mode(2); 1120 setXY(300,200); 1130 heading:=0 1140 END; 1150 1160 PROCEDURE spirals(l,a:real); 1170 BEGIN 1180 user(#bbc6);IF rde 480 THEN BEGIN (*Abfrage Grafik-Cursor*) 1190 ra:=chr(1); rhl:=musikadr; user(#bcb0); 1200 fwd(l); 1210 right(a); 1220 spirals(l+1,a) 1230 END 1240 END; 1250 1260 BEGIN 1270 env(1,1; user(#bcb0); 1200 fwd(l); 1210 right(a); 1220 spirals(l+1,a) 1230 END 1240 END; 1250 1260 BEGIN 1270 env(1,1,10,10); 1280 ent(-1,5,240,10); 1290 anz:=0; 1300 musikadr:=initevent(2,musik); 1310 sec:=0; min:=0; stunden:=0; 1320 every(50,3,uhrzeit); 1330 REPEAT 1340 anz:=anz+1; 1350 zaehler:=0; 1360 init; 1370 page; 1380 writeln('Demonstrationsprogramm'); 1390 writeln; writeln(' KC PASCAL'); 1400 writeln;writeln(' ',anz); 1410 b:=random(0); 1420 WHILE b>300 DO b:=round(b/10); 1430 a:=9; 1440 spirals(a,b); 1450 user(#bca7); 1460 UNTIL anz=50 1470 END.