home *** CD-ROM | disk | FTP | other *** search
- (*************************************************************************)
- (* >>>>>>>>>> MODUL: SORT.INC (v1.0) <<<<<<<<<< *)
- (* AUFGABE: Sortieren von beliebigen Arrays *)
- (* (c) 1988 Karsten Gieselmann & PASCAL International *)
- (*************************************************************************)
- (* Sortierreihenfolge *)
- TYPE SortOrder = (Ascending, Descending); (* aufsteigend, absteigend *)
-
- PROCEDURE Sort (VAR Data; (* Datenfeld *)
- n, (* Anzahl Feldelemente *)
- Size, (* Größe eines Elements in Bytes *)
- Comparison : INTEGER; (* Adr. d. Vergleichsfunk. *)
- Order : SortOrder); (* Sortierreihenfolge *)
-
- (*
- SORT implementiert einen Shellsort-Algorithmus für die Sortierung
- feldorientierter Datenstrukturen. Die Routine sortiert die ersten
- "n" Komponenten der ARRAY-Variablen "Data" in der Reihenfolge "Order".
- Eine Komponente des Feldes ist "Size" Bytes groß, das Sortierkriterium
- (der Vergleich zweier Feldelemente) wird durch die an der Adresse
- "Comparison" befindliche boolesche Funktion
- FUNCTION Lower (VAR a,b :SortType) : BOOLEAN;
- bestimmt (ist a < b ?). Die Adresse dieser Funktion im Code können DOS-User
- sich über "Comparison:=Ofs(Lower)" besorgen, CP/M-ler erhalten sie übeS
- die Anweisung Comparison:=Addr(Lower).
- *)
-
- TYPE Pointer = ^Byte; (* allgemeiner Zeigertyp *)
-
- VAR i, j, k : INTEGER;
-
- FUNCTION Compare (VAR a,b) :BOOLEAN; EXTERNAL 'CALL.BIN';
- (*
- erledigt den Aufruf des "Pseudo"-Prozeduralparameters "Comparison"E
- Der EXTERNAL-Anhang ist implementationsspezifisch und ist für Turbod
- DOS: EXTERNAL 'CALL.BIN';
- CP/M: EXTERNAL $0110;
- Benutzer von DOS-Turbo, die Binärdatei 'CALL.BIN' noch nicht habenb
- können diese mit dem DOS-Debugger wie folgt erzeugenk
- A>debug
- -e100
- b8 00 00 ff e0
- -r cx
- 5
- -ncall.bin
- -w
- -q
- *)
-
- PROCEDURE InitializeCall;
- (*
- Diese Prozedur initialisiert den Aufruf des Prozeduralparameters; wie
- der Aufruf ist auch sie abhängig von der verwendeten Version des Turbo
- Pascal Compilers (8 oder 16 Bit):
- DOS: MemW [CSeg:succ(Ofs(Compare))] := Comparison;
- CP/M: Mem [$0110] := $21;
- Mem [$0111] := Lo (Comparison);
- Mem [$0112] := Hi (Comparison);
- Mem [$0113] := $E9
- *)
- BEGIN
- MemW [CSeg:Succ(Ofs(Compare))] := Comparison; (* hier für DOS-Turbo *)
- END;
-
- FUNCTION Lower (a,b :Pointer) :BOOLEAN;
- (* Vergleich in Abhängigkeit der Sortierreihenfolge *)
- BEGIN
- IF Order = Ascending THEN Lower := Compare (a^,b^)
- ELSE Lower := Compare (b^,a^)
- END;
-
- FUNCTION p (i :INTEGER) : Pointer;
- (*
- liefert einen Zeiger auf das i-te Feldelement; die saubere Lösung
- dieses Zugriffs auf eine Komponente des Datenfeldes wäre für Turbo-
- DOS: p := Ptr (Seg(Data), Ofs(Data)+pred(i)*Size);
- CP/M: p := Ptr (Addr(Data)+pred(i)*Size);
- Die folgende Inline-Anweisung erledigt diese Aufgabe in wesentlich
- kürzerer Zeit, sie gilt jedoch nur für die DOS-Version von Turbo!
- *)
- BEGIN
- INLINE ($8b/$7E/$00/ (* MOV DI,[BP+00] *)
- $36/$C4/$9d/Data/ (* LES BX,SS:[DI+Data] *)
- $8b/$86/i/ (* MOV AX,[BP+i] *)
- $48/ (* DEC AX *)
- $36/$F7/$A5/Size/ (* MUL WORD PTR SS:[DI+Size] *)
- $01/$D8/ (* ADD AX,BX *)
- $8C/$C2/ (* MOV DX,ES *)
- $89/$46/$06/ (* MOV [BP+06],AX *)
- $89/$56/$08) (* MOV [BP+08],DX *)
- END;
-
-
- PROCEDURE Swap (a,b :Pointer; Size :INTEGER);
- (*
- vertauscht die Feldelemente, auf die "a" und "b" zeigen durch Tausch der
- ersten "Size" Bytes; auch hier gibt es eine saubere, aber langsame
- Lösung, diese ist für DOS- und CP/M-Turbo Pascal identisch:
-
- Var temp :Array [1..???] of Byte;
-
- Begin
- Move (a^, temp, Size); Move (b^, a^, Size); Move (temp, b^, Size);
- End;
-
- ACHTUNG: der Zwischenspeichers "temp" muß so groß deklariert sein, um
- eine Feldkomponente vollständig aufnehmen zu können! Die schnelle In-
- line-Anweisung darf wiederum nur auf DOS-Rechnern benutzt werden; er-
- setzt man die Parameterliste durch "Var a,b; Size :Integer", so kann
- man diese Prozedur auch als allgemeine Vertauschroutine verwenden!
- *)
- BEGIN
- INLINE ($1E/ (* PUSH DS *)
- $C5/$B6/a/ (* LDS SI,[BP+a] *)
- $C4/$BE/b/ (* LES DI,[BP+b] *)
- $8b/$8E/Size/ (* MOV CX,[BP+Size] *)
- $D1/$E9/ (* SHR CX,1 *)
- $73/$09/ (* JNB 013A *)
- $8a/$04/ (* MOV AL,[SI] *)
- $26/$86/$05/ (* XCHG AL,ES:[DI] *)
- $88/$04/ (* MOV [SI],AL *)
- $46/ (* INC SI *)
- $47/ (* INC DI *)
- $83/$F9/$00/ (* CMP CX,00 *)
- $74/$0d/ (* JZ 014C *)
- $8b/$04/ (* Swap: MOV AX,[SI] *)
- $26/$87/$05/ (* XCHG AX,ES:[DI] *)
- $89/$04/ (* MOV [SI],AX *)
- $46/ (* INC SI *)
- $46/ (* INC SI *)
- $47/ (* INC DI *)
- $47/ (* INC DI *)
- $E2/$F3/ (* LOOP Swap *)
- $1f) (* POP DS *)
- END;
-
- BEGIN
- InitializeCall;
- k := n;
- WHILE k > 1 DO BEGIN (* der verfeinerte Shellsort-Algorithmus *)
- k := k SHR 1;
- FOR i:=1 TO n-k DO
- IF Lower(p(i+k),p(i)) THEN BEGIN
- Swap (p(i),p(i+k),Size);
- j := i;
- WHILE (j >= k+1) AND Lower(p(j),p(j-k)) DO BEGIN
- Swap (p(j),p(j-k),Size);
- j := j - k
- END
- END
- END
- END;
- (*************** ENDE SORT.INC *******************************************)
-