The following article was printed in issue 9 1986 of the magazine „CT".
TURBO Pascal does not support procedures and functions as parameter. Read here how to solve this problem.

Noch ein Turbo-Tip

Prozeduren und Funktionen als Parameter in Turbo-Pascal

Bernd Rüffer
Allgemein wird davon ausgegangen, daß das vielgerühmte Turbo-Pascal in jeder Beziehung weit über den ursprünglichen Sprach-Standard hinausgeht. Aber es gibt ein recht nützliches Feature, das zwar Standard-Pascal vorsieht, aber nicht der ach so moderne Turbo-Compiler, nämlich prozedurale Parameter. Natürlich gelang es auch diesmal, dem Turbo-Compiler auf die Sprünge zu helfen und das fehlende Feature durch die Hintertür doch noch einzubauen.

Als Professor Wirth vor vielen Jahren die Sprache Pascal beschrieb, sah er auch Prozeduren und Funktionen als Parameter vor. In Standard-Pascal ist es also möglich, etwa eine Funktion als Parameter an eine Prozedur oder Funktion zu übergeben. Wozu das gut sein kann, zeigt das Beispiel einer universellen Funktion, die die Nullstelle einer beliebigen Funktion nach der Regula Falsi bestimmt. Die zu untersuchende Funktion wird erst beim Aufruf dieser Funktion als einer von vier Parametern übergeben. In Turbo-Pascal (auch bei Version 3.0) ist die Übergabe von Funktionen und Prozeduren nicht vorgesehen. Mit einer kleinen Assembler-Routine läßt sich dieses Manko allerdings beheben.

Doch vorher ein kleiner Exkurs in die Tiefen des Turbo-Compilers. Bei Aufrufen von Funktionen und Prozeduren werden die Parameter von links nach rechts der Reihe nach auf den Stack geschoben, von wo sie sich das Unterprogramm abholen kann. Ein universeller 'Unterprogrammaufrufer' läßt sich leicht als kurzes Maschinenprogramm schreiben, wenn ihm die Adresse des aufzurufenden Unterprogramms als letzter, ganz links stehender Parameter übergeben wird.

Diese Routinen entfernen den letzten Integer-Parameter, die Adresse des aufzurufenden Unterprogramms, vom Stack, pushen die Return-Adresse des aufrufenden Programms wieder auf die Spitze des Stacks und verzweigen zum Unterprogramm. Dieses muß natürlich alle nötigen Parameter in gewohnter Form auf dem Stack vorfinden. Zur Funktion

function f(x:real):real;

gehört deshalb die Dummy-Deklaration

function DUMMY(x:real; adresse:integer):real; external (Adr. des Dummy-Code);

Dummy entfernt die Adresse vom Stack, und die Funktion kann ihr Argument unterhalb der Return-Adresse vom Stack lesen.

Glücklicherweise haben die Turbo-Konstrukteure es sehr einfach gemacht, an die Adresse von Unterprogrammen, wie auch an die unserer prozeduralen Parameter, heranzukommen. Unter CP/M 80 geschieht dies durch addr(f), unter MS-DOS mit ofs(f). Im Beispiel muß nämlich die Adresse der zu untersuchenden Funktion übergeben werden:

regula(addr(f),xa,xe,eps);(CP/M)
regula(ofs(f),xa,xe,eps);(MS-DOS)

Eine Bemerkung am Rande: Der Aufruf von

fn := dummy(x,addr(f));

hat die gleiche Wirkung wie

fn := f(x).

Die Dummy-Routine kann von CP/Mlern im Copyright von Borland untergebracht werden. Die MS-DOS-Leute haben es da etwas einfacher. Sie können die Routine in einer COM-Datei unterbringen, die der Compiler bei Bedarf in das Programm einbindet. Da diese Routine für jede mögliche Funktion/Prozedur verwendet werden kann, muß sie nur einmal im Programm vorhanden sein.

Return-Adresse
letzter Parameter
...
...
erster Parameter
<---- Spitze des Stack Dummy entfernt den letzten Parameter vom Stack.
DUMMY:	POP HL      ;Return-Adresse vom Stack
	EX  (SP),HL ;Austausch von Return-Adresse und letz-
                    ;tem Integer-Parameter (Adr. d. Routine)
	JP  (HL)    ;Sprung zur Routine
oder für 8088/86-Freaks:
DUMMY:	POP  CX   ;Return-Adresse vom Stack
	POP  BX   ;letzter Ineteger-Parameter
                  ;(Offset der Routine)
	PUSH CX   ;Return-Adresse zurück
	JMP  BX   ;Sprung zur Routine
Professor Wirth sah in seiner Sprachdefinition auch Prozeduren und Funktionen als Parameter vor.
Die kurze Maschinen-Routine 'DUMMY' ermöglicht prozedurale Parameter auch in Turbo-Pascal. In der Parameterliste des Turbo-Unterprogramms muß die Adresse der zu Übergebenden Funktion aufgeführt sein.

Scanned by Werner Cirsovius
December 2004
© Heise Verlag