The following article was printed in the magazine „CHIP" (Date unknown).
A compilation of useful hints for TURBO Pascal.
For the sake of completeness also MS-DOS related hints are listed.

20 tolle Turbo-Tips und Tricks

Turbo-Pascal ist auf dem besten Wege, BASIC den Rang als verbreitetste und beliebteste Programmiersprache abzulaufen. Ein paar Kniffe helfen bei der Erstellung leistungsfähiger Programme.

Innerhalb von nur zwei Jahren ist Turbo-Pascal zur weltweit beliebtesten Compilersprache geworden. Im professionellen Bereich ist es der extrem kurze Editieren-Übersetzen-Testen-Zyklus, der positiv auf die Programmentwicklungszeit und -kosten einwirkt. In Amateurkreisen wird besonders die einfache, Interpreterähnliche Handhabung geschätzt.
Doch bis zum großen Programmiererfolg ist es oft ein langer und schwieriger Weg. Trotz seiner Kompaktheit stellt Turbo-Pascal eine sehr komplexe Programmiersprache zur Verfügung, in der bereits viele Möglichkeiten von C und Modula 2 integriert sind.
Damit Sie nun nicht auch noch die große Entdeckungsreise durch Erfahrung und Handbuch in allen Einzelheiten bestehen müssen, haben wir die 20 wichtigsten Tips für Sie zusammengestellt.
Tricks nur bei echtem Bedarf Umleitung der Druckerausgabe Open-Arrays unter Turbo-Pascal Editor läuft über
Command-Nachladen bei MS-DOS Zuviel Code Runtime- und I/O- Fehler Inverse Schrift auf IBM-Rechnern
Turbo-Pascal und Maschinensprache Halbdynamische Strings Bereichsüberwachung Dateien löschen
Rekursion unter CP/M-80 EXIT mit Turbo-Pascal vor 3.0 Freier Diskettenplatz unter CP/M 3.0 Speicherplatz für Daten teilen
Sonder- und, Grafikzeichen unter CP/M-80 Eingabe von Zahlenkolonnen Turbo High-Speed Programmunterbrechung

1. Tricks nur bei echtem Bedarf

Je mehr „geniale" Tricks in einem Programm vorhanden sind, desto weniger werden es andere verstehen. Auch Sie sind schon nach kurzer Zeit ein anderer Mensch, zumindest was die Erstellung Ihrer Programme betrifft. Wenn Sie Ihr Programm nach einer Woche selbst nicht mehr verstehen, haben Sie mit Sicherheit etwas falsch gemacht.

2. Umleitung der Druckerausgabe

Wenn sich Berge von Papier um Ihren Drucker türmen, sollten Sie vielleicht einmal darüber nachdenken, die Druckerausgabe während der Ausgabe auf den Bildschirm umzuleiten. Der erste Gedanke, „LST" überall durch „CON" zu ersetzen, ist wahrscheinlich dann nicht mehr so gut, wenn Ausgabeanweisungen über mehrere Include-Dateien verteilt sind. Aber es geht ja auch viel einfacher:
VAR LST: text;
Das Hauptprogramm beginnt dann mit
assign (LST,'CON:'); rewrite (LST);
und endet mit
close(LST);
Um die Druckerausgabe wieder auf den Drucker zu bringen, genügt eine Veränderung der assign-Anweisung zu assign(LST,'LST:').

3. Open-Arrays unter Turbo-Pascal

Ein großes Hindernis bei der Erstellung von Programmbibliotheken unter Pascal war die Tatsache, daß Feld-Parameter nur mit festgelegter Dimensionierung zugelassen waren. Aus diesem Grund hat Wirth in Modula 2 die „open arrays" bereitgestellt. Turbo-Pascal bietet folgenden Ausweg:
   TYPE FeldElement = IrgendEinTyp;
   VAR F1 : array[1..100] OF FeldElement;
       F2 : array[-10..10] OF FeldElement;
   PROCEDURE FeldBearbeiten(VAR F; Low, High : integer);
   VAR Feld : array[1..maxint] of FeldElement absolute F;
Der Aufruf dieser Prozedur lautet dann beispielsweise
   FeldBearbeiten(F1,1,100) oder
   FeldBearbeiten(F2,-10,10).
Im Gegensatz zu Modula 2, wo nur eindimensionale Felder zugelassen sind, gibt es bei dieser Methode keine Einschränkung.

4. Editor läuft über

Gott sei Dank - sagen viele Pascal-Pädagogen. Denn die Begrenzung des Editier-Speichers zwingt den Programmierer dazu, große Programme in überschaubare Happen aufzuteilen.
Die Compiler-Anweisung
(*$I FileName)
sorgt dafür, daß der Quelltext wieder richtig zusammengesetzt wird.

5. Command-Nachladen bei MS-DOS

Wenn Sie unter MS-DOS ein COM-File erzeugen, reserviert Turbo-Pascal automatisch den gesamten vorhandenen Speicher für Ihr Programm. Das hat zur Folge, daß beim Programmende der Kommando-Prozessor COMMAND.COM neu geladen werden muß. Wenn Sie jedoch mit der Compiler-Option „A" die maximale Heap/Stack-Größe um 1000H bis 2000H Paragraphen verringern, verabschieden sich von Turbo-Pascal erzeugte COM-Dateien ohne weiteres Nachladen.

6. Zuviel Code

Turbo-Pascal begrenzt den Code auf maximal 64 KByte. Das ist zwar eine ganze Menge, reicht jedoch für manche Anwendung nicht aus. Seit der Version 2.0 bietet Turbo-Pascal einen einfach zu handhabenden Overlay-Mechanismus, mit dem dieses Problem leicht zu lösen ist. Dabei gehen Sie so vor, daß Sie mehreren aufeinanderfolgenden Prozeduren das Wort „overlay" dem jeweiligen Prozedurkopf voranstellen. Einzige Einschränkung: Die Prozeduren dürfen sich nicht gegenseitig aufrufen oder rekursiv sein. Bei Verwendung von typisierten Konstanten ist darauf zu achten, daß deren Veränderung beim Nachladen wieder rückgängig gemacht wird.

7. Runtime- und I/O- Fehler

Vielen Turbo-Anwendern fehlt die Möglichkeit, auf Fehler zu reagieren, die erst zur Laufzeit auftreten. Das Programm wird unter Ausgabe zweier Hexzahlen abgebrochen. Besonders bei kommerziellen Programmen ist das natürlich kein Zustand.
Entgegen dem Anschein gibt es aber in Turbo-Pascal (ab Version 3.0) sehr wohl die Möglichkeit, solche Fehler abzufangen und das Programm mit entsprechenden Angaben zu beenden. Der Hinweis ist zwar nicht im Handbuch zu finden aber auf der Originaldiskette in dem File READ-ME.
Schreiben Sie eine Prozedur
FehlerBehandlung(Code,PC:integer).
In der Variablen Code sind Fehlerart und -nummer verschlüsselt. Hi(Code) läßt auf die Art schließen:
0:Das Programm wurde durch Ctrl-C abgebrochen
1:I/O Fehler (Diskette voll...)
2:Runtime-Fehler (wie Division durch 0 etc.)
Lo(Code) ergibt die Fehlernummer, deren Bedeutung dem Handbuch zu entnehmen ist. Schließen Sie diese Prozedur unbedingt mit „halt" ab, da ansonsten wieder der spartanische Turbo-Fehlermelder zuschlägt. Damit nun im Bedarfsfalle Ihre Prozedur auch angesprungen wird, genügt im Hauptprogramm folgende Anweisung:
ErrorPtr:=Addr(FehlerBehandlung) (* CP/M-80 *)
ErrorPtr:=Ofs(FehlerBehandlung) (* andere Versionen *)

8. Inverse Schrift auf IBM-Rechnern

Helle und dunkle Schrift ist zwar recht fein, doch manchmal soll es auch invers sein:
[Die beiden Prozeduren lassen sich auch mit dem JOYCE ausführen]
  procedure InverseOn;
   begin
    TextColor(0);
    TextBackground(15)
   end;
  procedure InverseOff;
   begin
    TextColor(15);
    TextBackground(0)
   end;
  procedure InverseOn;
   begin
    write(#27'b'#63);
    write(#27'c'#00)
   end;
  procedure InverseOff;
   begin
    write(#27'b'#00);
    write(#27'c'#63);
   end;
OriginalBeim JOYCE

9. Turbo-Pascal und Maschinensprache

Obwohl Turbo-Pascal kein linkbares System ist, gibt es einen einfachen Weg, Routinen in Maschinensprache in Pascal-Programme einzubinden. Notwendiges Werkzeug hierfür ist der Assembler INLASS von CHIP-SOFT. Er kann die Assemblersprachen von vier Prozessoren übersetzen: 8080, Z80, 6502 und 8088/86. Zudem bietet er so feine Features wie rekursive Makros oder bedingte Assemblierung. Der Output von INLASS1 ist eine vollkommen frei verschiebbare INLINE-Anweisung. Damit dürfte dieser Problemkreis endgültig gelöst sein.

10. Halbdynamische Strings

Bei Textverarbeitungsprogrammen ist die statische Speicherverwaltung von Pascal eher hinderlich. Die Variable
      Dokument: ARRAY[1..500] OF STRING[100]
belegt immer knapp 50 KByte, auch wenn mehr als die Hälfte davon Leerzeilen sind.
Ausweg bietet die Verwendung eines Feldes von Zeigern auf Strings einschließlich einer Puffervariablen:
      TYPE Zeile = STRING[100];
      VAR Dokument : ARRAY[1..500] OF ^Zeile;
          PufferZeile : Zeile;
Anstelle von read(Dokument[i]) muß es dann heißen:
      read(PufferZeile);
      getmem(Dokument[i], succ(length(PufferZeile)));
      Dokument[i]^:= PufferZeile;
Der gewonnene Speicherplatz macht die etwas umständliche Programmierung schnell wieder wett.

11. Bereichsüberwachung

Schalten Sie während der Programmentwicklungsphase grundsätzlich die Bereichsüberwachung ein. Die Compiler-Anweisung hierfür lautet (*$R+*). Schnell ist aufgrund eines Programmierfehlers auf ein illegales Feld zugegriffen und der Rechner zum Abstürzen gebracht.
Blutige Anfänger seien darauf hingewiesen, daß diese Compiler-Anweisungen, die genauso wie Kommentare aussehen, beim Abtippen von Listings keinesfalls weggelassen werden dürfen.

12. Dateien löschen

Ein wenig ärgerlich ist die Tatsache, daß man vom Turbo-System keine Dateien auf Diskette oder Festplatte löschen kann. In schwierigen Fällen, wenn der Platz zum Abspeichern des Workfiles zu knapp ist und keine andere Diskette zur Verfügung steht, hilft folgender Trick:
Diese Datei wird mit dem Block überschrieben, der gewonnene Diskettenplatz steht zu Ihrer Verfügung.

13. Rekursion unter CP/M-80

Programmierer, die unter CP/M-80 ihre Programme erstellen, finden im Turbo-Pascal-Handbuch2 den verunsichernden Satz: Lokale Variable dürfen in rekursiven Prozeduren nicht als Referenzparameter übergeben werden. Lokal wozu? Nur zu der rekursiven Prozedur der sie wiederum übergeben werden sollen. Allein in diesem Fall kommt der Mechanismus zum Tragen, daß in jeder Rekursionstiefe auf dieselbe Variable gezeigt wird. In allen anderen Fällen kann die Rekursion uneingeschränkt genutzt werden.

14. EXIT mit Turbo-Pascal vor 3.0

Wenn Sie mit Turbo-Pascal 1.0 oder 2.0 arbeiten, können Sie die Anweisung EXIT leicht simulieren:

15. Freier Diskettenplatz unter CP/M 3.0

Einem Programmabsturz bei mangelndem Diskettenplatz beugt folgende kleine Funktion vor, die die verbleibende Kapazität in KBYTE zurückgibt:
FUNCTION Freier_Diskettenplatz(Laufwerk:byte):integer;
(* Laufwerk 0 = Bezugslaufwerk, 1 = A:... *)
TYPE DMA_Puffer=RECORD
       Anzahl_der_Records_low: integer;
       Anzahl_der_Records_high: byte;
       Fueller: ARRAY[0..124] OF byte
      END;
VAR p: ^DMA_Puffer;
BEGIN
 new(p); bdos(26,ord(p));
 IF Laufwerk=0 THEN Laufwerk:=bdos(25)+1;
 bdos(46,Laufwerk-1);
 Freier_Diskettenplatz:= p^.Anzahl_der_Records_low SHR 3 +
             p^.Anzahl_der_Records_high SHL 13;
 dispose(p)
END;

16. Speicherplatz für Daten teilen

Gerade unter CP/M-80 wird der Speicher für Programme und Daten doch manchmal knapp. Brauchen verschiedene Prozeduren für speicherintensive Variable wie Felder oder große Records viel Platz und rufen sie sich nicht gegenseitig auf, so kann mit folgendem Verfahren der Speicherbedarf merklich reduziert werden:

17. Sonder- und, Grafikzeichen unter CP/M-80

Unter CP/M-80 sind Turbo-Programmtexte reine 7-bit-ASCII-Dateien. Viele Computer stellen Sonder- und Grafikzeichen in einem 8-bit-Code dar. Wenn Sie Zeichen, deren ASCII-Code über 127 liegt, in Kommentaren oder Strings verwenden, erscheinen diese zunächst ganz normal auf dem Bildschirm. Wenn Sie jedoch den Text abspeichern und dann wieder laden, sind die Zeichen verschwunden! Abhilfe: Verzichten Sie in Kommentaren auf irgendwelche Sonderzeichen. In Strings können Sie sie ohne weiteres durch Angabe ihres Codes verwenden: write(#134#230#198).

18. Eingabe von Zahlenkolonnen

Angenommen, Sie wollen in einer Schleife ein Zahlenfeld einlesen, ohne nach jeder Eingabe die RETURN-Taste zu drücken. Der Weg
     FOR i:= 1 TO n DO read(Feld[i])
führt leider nicht zum Erfolg. Es wird immer nur die erste Zahl jeder Eingabezeile gelesen. Den Ausweg liefert folgende Anweisung:
     FOR i:= 1 TO n DO read(TRM,Feld[i])
Die einzelnen Zahlen müssen durch mindestens ein Leerzeichen voneinander getrennt sein.

19. Turbo High-Speed

Die schnellste Schleife ist die FOR-TO-Anweisung.
Succ(i) und pred(i) sind schneller als i+1 oder i-1.
IF a THEN IF b THEN IF c ist schneller als IF a AND b AND c.
SHL, SHR und AND sind schneller als *, DIV und MOD, allerdings nur dann einsetzbar, wenn es sich bei einem der beiden Operanden um Potenzen von 2 handelt.

20. Programmunterbrechung

Die Funktion KEYPRESSED und die Compiler-Anweisung (*$U+*) vertragen sich nicht besonders gut. Um eigenartige Zustände während der Programmausführung zu vermeiden, sollte die Abfrage des Konsolenstatus tunlichst nur einer Seite aufgetragen werden. Der Einsatz von KEYPRESSED ist eigentlich nur dann sinnvoll, wenn das Programm nach einem Tastendruck anders reagieren soll, als wenn ein solcher unterbleibt. Da man in der Entwicklungsphase immer die Möglichkeit haben sollte, das Programm zu unterbrechen, sollte die Compiler-Anweisung (*$U+*) nur an solchen Stellen aufgehoben werden. Aber auch hier sollten Sie den Wunsch einer Unterbrechung respektieren. Beispiel:
   (*$U-*)
   IF KEYPRESSED THEN
   BEGIN
    read(KBD,c);
    IF c=^C THEN HALT
    ELSE
   (*$U+*)

Ulrich Kern

1. Hinweis zu INLINE Codes: Das besagte Programm INLASS findet sich auf der Seite der ZNODE 51 (unter GERMANY/ Beiträge dt. Programmierer zur Z80-Programmierung - gut versteckt in dem .LBR-File mtxclub/mtxlbrs/club005.lbr. Unter diesem Link findet sich auch eine Beschreibung (INLASS.DOC), in der sich wiederum ein Hinweis auf das Programm INLOAD findet (in mtxclub/mtxlbrs/club007.lbr). Wer möchte, kann sich das Paket hier als ZIP-File herunterladen oder vorab einen Blick in die Beschreibung werfen.
Eine Nachfrage im Internet half: hier der Quelltext von INLASS.
Andere Möglichkeiten zum Erstellen von INLINE Codes sind hier beschrieben.
2. Aus Compiler Handbuch, Heimsoeth Software, TURBO PASCAL 3.0, 5. Auflage, März 1986:

D.2 Rekursion

Nur CP/M-80: Wegen der Art, wie lokale Variablen während der Rekursion behandelt werden, darf eine zu einem Unterprogramm lokale Variable nicht als var Parameter in rekursive Aufrufe übergeben werden.

Scanned by Werner Cirsovius
September 2004
May 2005 [INLASS Quellen]
© CHIP Verlag