The following article was printed in October 1987 of the magazine „MC".
Tips and hints for Turbo Pascal
|
|
Turbo-Tricks
Im Lauf der Zeit sammeln sich bei manchem Turbo-Pascal-Programmierer nützliche Prozeduren und Tricks an, die viel zu schade sind, um einfach in der Schublade zu landen.
Auch die folgenden Routinen sind Nebenprodukte praktischer Arbeit - entwickelt und getestet auf einem Apple-II unter CP/M-80.
In der Turbo-Version 3.0 werden die logischen Gerätenamen CON:
und TRM:
nicht mehr unterschieden.
Die B
-Compiler-Directive ist daher unwirksam.
Ein Blick in den Compiler zeigt, daß es sich vermutlich nicht um einen Bug handelt, sondern diese Unterscheidung aus Platzgründen nicht mehr vorgenommen wird.
Ein Patch ist mir nicht bekannt.
Abhilfe schafft die Prozedur von Bild 1.
Außerdem funktionieren die Editierhilfen ^R
und ^D
entgegen den Angaben im Handbuch nicht.
PROCEDURE READTRM (VAR KEY : CHAR);
BEGIN
READ(KBD,KEY);
IF KEY >= ' ' THEN WRITE(KEY)
END;
|
Bild 1. Einen Lesevorgang vom logischen Gerät TRM: simuliert diese Prozedur
|
|
Assign mit Joker
Obwohl es im Handbuch nirgends erwähnt wird, akzeptiert die ASSIGN
-Prozedur der Turbo-Version 2.0 das Fragezeichen als Joker (den Stern allerdings nicht).
Dadurch können Prozeduren zum Löschen von Dateien sehr einfach und komfortabel geschrieben werden.
Turbo 3.0 weigert sich hier und bricht den String beim ersten Auftreten des Fragezeichens ab:
alle folgenden Zeichen werden ignoriert.
Schaut man sich die Runtime-Library genauer an, so erkennt man, daß hier eine Routine implementiert wurde, die neben „?" sogar „*" richtig behandelt.
Allerdings wird diese Routine nie angesprungen.
Ursache ist das Byte in $3F3
, das die Aufgabe eines Flags übernimmt:
Ist der Wert ungleich null, werden die Jokerzeichen richtig behandelt.
Da die Speicherstelle in der Library liegt, kann der Patch vom Pascal-Programm selbst vorgenommen werden.
Man vereinbart im Deklarationsteil:
Var Wildcard: Boolean absolute $3F3:
Im Programm ordnet man dann der Variablen Wildcard
den Wert TRUE
zu, wenn man Jokerzeichen verwenden will.
Error-Handler
Der in mc 6/86 auf Seite 89 abgedruckte
Error-Handler arbeitet auch in Turbo 3.0 ohne weitere Änderung, wenn man die absolute Adresse des Jump-Vektors von
$1F75
auf
$207A
ändert und Zeile 51 zu
51: Inline ($32/ERROR_CODE/$DD/$E5)
ergänzt.
Durch den Error-Handler werden Runtime-Fehler abgefangen:
(*$I-*)
schützt vor I/O-Fehlern.
Kritisch sind dann nur noch BDOS-Fehler bzw. das Betätigen der Reset-Taste.
Aber auch hier kann man sich schützen (
Bild 2).
VAR STACK : INTEGER;
WBOOTLO : BYTE;
WBOOTHI : BYTE;
BIOSADDR : INTEGER ABSOLUTE $0001;
PROCEDURE CLR_ERROR;
BEGIN
MEM[BIOSADDR+1] := WBOOTLO;
MEM[BIOSADDR+2] := WBOOTHI
END;
PROCEDURE RESETHANDLER;
BEGIN
STACKPTR := STACK;
INLINE ($C3/$100)
END;
PROCEDURE INIT_ERROR;
BEGIN
STACK := STACKPTR;
WBOOTLO := MEM[BIOSADDR+1];
WBOOTHI := MEM[BIOSADDR+2];
MEM[BIOSADDR+1] := LO(ADDR(RESETHANDLER));
MEM[BIOSADDR+2] := HI(ADDR(RESETHANDLER));
END;
|
Bild 2. Schutz vor dem unbeabsichtigten Betätigen der Reset-Taste bieten diese Prozeduren
|
|
Man ruft zu Beginn des Programms die Prozedur INIT_ERROR
auf, die den entsprechenden Vektor im BIOS-Teil auf den Reset-Handler umlenkt.
Am Ende des Programms wird dann die Prozedur CLR_ERROR
aufgerufen, die den Vektor wieder geradebiegt.
Diese Prozeduren sollte man aber erst implementieren, wenn das eigene Programm vollständig ausgetestet ist.
Sonst gerät man leicht in eine Endlosschleife - dann hilft nur noch der Netzschalter!
Zusätzliche Variablen
Turbo 3.0 verfügt über (mindestens) zwei zusätzliche Variablen, die im Handbuch nicht erwähnt werden:
ERRORPTR
ist vom Typ Integer und ermöglicht eine eigene Fehlerbehandlung;
CBREAK
ist vom Typ Boolean.
Diese Variable steuert die C
-Compiler-Option, so daß man diese Option nun auch vom Programm aus steuern kann, also zur Laufzeit.
CBREAK := TRUE
entspricht
(*$C+*)
oder
{$C+}
CBREAK := FALSE
entspricht
(*$C-*)
Die Variable ERRORPTR bedarf noch einiger Erläuterungen.
Man ordnet ihr zu Beginn des Programms die Adresse der eigenen Fehlerbehandlungsroutine zu, also etwa
ERRORPTR := ADDR(ERRORHANDLER)
Der Prozedur
ERRORHANDLER
werden dann im Fehlerfall zwei Integer-Variablen übergeben, die Auskunft über die Art des aufgetretenen Fehlers geben.
Das Programmierbeispiel von
Bild 3 soll das verdeutlichen.
PROCEDURE ERRORHANDLER(ERRNR, ERRADDR : INTEGER);
VAR NR : BYTE;
BEGIN
CLRSCR;
GOTOXY(28,10);
LOWVIDEO; WRITE(^G);
CASE HI(ERRNR) OF
0 : WRITE(' User - Break ');
1 : WRITE(' I/O - Error ');
2 : WRITE(' Runtime - Error ');
END;
NORMVIDEO;
WRITELN;
GOTOXY(20,12);
LOWVIDEO;
WRITE(' Error # $');
NR := LO(ERRNR);
INLINE ($3A/NR/$CD/$4B4);
WRITE(' occurs at PC : $');
INLINE ($2A/ERRADDR/$CD/$4AF);
WRITE(' ');
NORMVIDEO;
DELAY(2000);
INLINE ($C3/$100)
END;
PROCEDURE INIT_ERROR;
BEGIN
ERRORPTR := ADDR(ERRORHANDLER)
END;
|
Bild 3. Der Prozedur ERRORHANDLER werden im Fehlerfall zwei Integer-Variablen übergeben
|
|
Die angeführten Inline-Statements sind ebenfalls Tricks, die im Handbuch nicht erwähnt werden, aber dennoch bekannt sein dürften:
Das erste Statement gibt das Byte
NR
in hexadezimaler Schreibweise auf dem Bildschirm aus;
das zweite die Integer-Variable
ERRADDR
.
Die absoluten Adressen
$4B4
und
$4AF
gelten für Turbo 3.0.
In Turbo 2.0 sind die Adressen auf $492 und $48D zu ändern.
Das letzte Inline-Statement veranlaßt einen Sprung zur Adresse
$100
, wodurch das Programm neu gestartet wird.
Die Frage, ob der Turbo-eigene Error-Handler über die Möglichkeit eines
RESUME
verfügt, konnte ich bislang noch nicht klären.
Ich vermute aber, daß das unmöglich ist.
Man muß bei der Verwendung des
ERRORPTR
lediglich beachten, daß nach Auftreten eines Fehlers diese Variable neu initialisiert werden muß, gleiches gilt für eine eventuelle
OVRDRIVE
-Anweisung.
Chain-Files
Abschließend noch ein Tip zur Verwendung von
CHN
-Files.
Will man auf einem Apple-II hochauflösende Grafik benutzen, so muß das Programm als
COM
-File mit einer Startadresse über
$5000
compiliert werden.
Dadurch werden auf der Diskette etwa 10 KByte Speicherplatz verschenkt, außerdem dauert das Laden des Programms unnötig lang.
Es ist schon vorgeschlagen worden, statt dessen das Grafikprogramm als
CHN
-File zu compilieren und es von einem als
COM
-File compilierten Menü-Programm zu starten.
Dieses Verfahren ist aber erst dann effektiv, wenn man mehrere Grafikprogramme von diesem Menü-Programm aus starten will, was mir wenig sinnvoll erscheint.
Mit einem Trick kann man aber diesen Speicherplatz völlig einsparen:
Nehmen wir an, das Hauptprogramm hieße
GRAFIK.PAS
und wäre als
CHN
-File mit einer Startadresse von
$5000
auf Diskette compiliert.
Das Programm von
Bild 4 startet dann dieses
CHN
-File, obwohl es als
COM
-File mit der kleinstmöglichen Startadresse compiliert wurde.
PROGRAM STARTUP;
VAR DATEI : FILE;
STARTADDR : INTEGER ABSOLUTE $101;
BEGIN
STARTADDR := $5000; { Startadresse des Chain-Files }
{$I-}
ASSIGN(DATEI,'GRAFIK.CHN');
RESET(DATEI);
IF IORESULT <>
0 THEN WRITELN(^G ,'Datei GRAFIK.CHN nicht gefunden. ',
'Programm abgebrochen.')
ELSE CHAIN(DATEI)
{$I+}
END.
|
Bild 4. Dieses Programm startet ein Programm mit dem Namen GRAFIK.CHN, das als Chain-File compiliert wurde
|
|
Scanned by
Werner Cirsovius
February 2005
© Franzis' Verlag