One of the remaining limitations of the ListsWithCursors
module is that there is a preferred direction of movement through the list;
it's much easier to start at the beginning of the list and advance to the
end than to start at the end and move backwards to the beginning. There
are a fair number of cases (including the implementation of bignums -- natural numbers of unbounded size) in
which the possibility of traversing the list in either direction is
essential. To accommodate this need, I propose the bidirectional
list data type (with cursor).
The values of this type are the same as those of lists with cursors, but in addition to the repertoire of operations described in the handout on lists with cursors, the following operations, all involving the cursor:
cursor-to-end
Input: operand, a bidirectional list.
Outputs: none.
Preconditions: none.
Postconditions: If the length of operand is 0, its cursor is the
null cursor; otherwise, its cursor is marking its last position.
retreat-cursor
Input: operand, a bidirectional list.
Outputs: none.
Precondition: The cursor of operand is not null.
Postconditions: If the cursor of operand at input marks the
first position in operand, then it is a null cursor at output.
Otherwise, the cursor of operand at output marks the position
preceding the position that it marked at input.
find-previous
Inputs: sought and operand, where
operand is a bidirectional list and sought is a
value of its element type.
Outputs: none.
Preconditions: none.
Postconditions: Let p be 0 if the cursor of operand was
null at input; otherwise, let p be the position it marked. Either
the cursor of operand at output is null and
sought is not in any position less than p, or
sought is the element at the position q marked by the
cursor of operand at output, q is less than
p, and sought is not in any position less than
p and greater than q.
find-previous-by-test
Inputs: operand, a list, and test, an operation
that takes one input, a value of the element type of operand,
and yields one output, a Boolean.
Outputs: none.
Preconditions: none.
Postconditions: Let p be 0 if the cursor of operand was
null at input; otherwise, let p be the position it marked. Either
(1) the cursor of operand at output is null and applying
test to the element in any position less than p
yields false, or (2) applying test to the element at
the position q marked by the cursor of operand at
output yields true, q is less than p, and applying
test to the element in any of the positions less than
p and greater than q yields false.
nil.
As in the ListsWithCursors module, it is convenient to provide
a header node for each bidirectional list, containing pointers to the first
and last elements of the list, an indication of its size, and the list's
cursor.
One nice feature of doubly-linked lists is that it eliminates the annoying special case from the implementation of the insert-at-cursor and delete-at-cursor operations; the addition of the fore pointer gives us a way of finding the previous component in constant time.
{ This module defines an interface for a bidirectional list data type that
includes a cursor in each list and implements it for HP 9000 Series 700
workstations under HP-UX 9.x, using HP Pascal.
Programmer: John Stone, Grinnell College.
Original version: November 1-5, 1996
}
$heap_dispose on$
module BidirectionalLists;
$search 'elements.o'$
import Elements;
export
type
BidirectionalList = ^BidirectionalListRecord; { an opaque type }
{ The MakeEmptyBidirectionalList function creates and returns a newly
allocated, empty, bidirectional list. }
function MakeEmptyBidirectionalList: BidirectionalList;
{ The PrependToBidirectionalList procedure takes a bidirectional list and
prepends an element to it. }
procedure PrependToBidirectionalList (Prefix: Element;
var Base: BidirectionalList);
{ The FirstOfBidirectionalList function returns the first element of a
non-empty bidirectional list. }
function FirstOfBidirectionalList (Operand: BidirectionalList): Element;
{ The DeleteFirstOfBidirectionalList function takes a non-empty
bidirectional list and removes its first element. }
procedure DeleteFirstOfBidirectionalList (var Operand: BidirectionalList);
{ The EmptyBidirectionalList function determines whether a given
bidirectional list is empty. }
function EmptyBidirectionalList (Operand: BidirectionalList): Boolean;
{ The LengthOfBidirectionalList function returns the length of a given
bidirectional list. }
function LengthOfBidirectionalList (Operand: BidirectionalList): Integer;
{ The AppendToBidirectionalList procedure takes a bidirectional list and
appends an element to it. }
procedure AppendToBidirectionalList (var Base: BidirectionalList;
Postfix: Element);
{ The LastOfBidirectionalList function returns the last element of a
non-empty bidirectional list. }
function LastOfBidirectionalList (Operand: BidirectionalList): Element;
{ The DeleteLastOfBidirectionalList procedure takes a non-empty
bidirectional list and removes its last element. }
procedure DeleteLastOfBidirectionalList (var Operand: BidirectionalList);
{ The CopyBidirectionalList function constructs and returns a copy of a
given bidirectional list, in newly allocated storage. }
function CopyBidirectionalList (Operand: BidirectionalList):
BidirectionalList;
{ The CursorToStartOfBidirectionalList procedure adjusts a bidirectional
list's cursor so that it marks the first position (or is null, if the
list is empty). }
procedure CursorToStartOfBidirectionalList (var Operand: BidirectionalList);
{ The CursorToEndOfBidirectionalList procedure adjusts a bidirectional
list's cursor so that it marks the last position (or is null, if the
list is empty). }
procedure CursorToEndOfBidirectionalList (var Operand: BidirectionalList);
{ The AdvanceCursorAlongBidirectionalList procedure moves a bidirectional
list's cursor, assumed not to be null, to the next position on the list
(or makes it null, if there are no more positions. }
procedure AdvanceCursorAlongBidirectionalList (var Operand:
BidirectionalList);
{ The RetreatCursorAlongBidirectionalList procedure moves a bidirectional
list's cursor, assumed not to be null, to the previous position on the
list (or makes it null, if there are no previous positions. }
procedure RetreatCursorAlongBidirectionalList (var Operand:
BidirectionalList);
{ The NullCursorInBidirectionalList function determines whether a given
bidirectional list's cursor is null. }
function NullCursorInBidirectionalList (Operand: BidirectionalList):
Boolean;
{ The ConcatenateBidirectionalList procedure takes two bidirectional
lists and adds the elements of the second operand at the end of the
first operand. }
procedure ConcatenateBidirectionalList (var LeftOperand:
BidirectionalList; RightOperand: BidirectionalList);
{ The RecoverByPositionFromBidirectionalList function returns the value
occupying a specified position in a bidirectional list. }
function RecoverByPositionFromBidirectionalList (Position: Integer;
Ls: BidirectionalList): Element;
{ The ElementAtCursorInBidirectionalList function returns the element
occupying the position marked by the cursor in a given bidirectional
list. }
function ElementAtCursorInBidirectionalList (Operand: BidirectionalList):
Element;
{ The AssignAtPositionInBidirectionalList procedure replaces the value
occupying a specified position in a bidirectional list with a new
value. }
procedure AssignAtPositionInBidirectionalList (Position: Integer;
var Ls: BidirectionalList; NewValue: Element);
{ The AssignAtCursorInBidirectionalList procedure replaces the element
occupying the position marked by the cursor in a given bidirectional
list with a new value. }
procedure AssignAtCursorInBidirectionalList (var Ls: BidirectionalList;
NewValue: Element);
{ The ElementOfBidirectionalList function determines whether a given
value is an element of a given bidirectional list. }
function ElementOfBidirectionalList (Candidate: Element;
Ls: BidirectionalList): Boolean;
{ The LocateInBidirectionalList procedure determines whether a given
value is an element of a given bidirectional list and, if so, returns
the least position at which it occurs. }
procedure LocateInBidirectionalList (Sought: Element;
Ls:BidirectionalList; var Found: Boolean; var Position: Integer);
{ The FindNextInBidirectionalList procedure advances a given
bidirectional list's cursor to the next position occupied by a
specified value, leaving it null if there is no such position. }
procedure FindNextInBidirectionalList (Sought: Element;
var Ls: BidirectionalList);
{ The FindPreviousInBidirectionalList procedure moves a given
bidirectional list's cursor to the nearest lower-numbered position
occupied by a specified value, leaving it null if there is no such
position. }
procedure FindPreviousInBidirectionalList (Sought: Element;
var Ls: BidirectionalList);
{ The SublistOfBidirectionalList function takes a bidirectional list and
prunes off all of it but a section bounded by the positions indicated
by Start and Finish. }
procedure SublistOfBidirectionalList (var Ls: BidirectionalList;
Start, Finish: Integer);
{ The ReverseBidirectionalList procedure reverses the order of the
elements in a given bidirectional list. }
procedure ReverseBidirectionalList (var Operand: BidirectionalList);
{ The InsertAtPositionInBidirectionalList procedure inserts an element at
a specified position in a bidirectional list. }
procedure InsertAtPositionInBidirectionalList (var Ls: BidirectionalList;
Position: Integer; Elm: Element);
{ The InsertAtCursorInBidirectionalList procedure inserts a new element
into a bidirectional.list at the position marked by the list's cursor,
or at the end if the list's cursor is null. }
procedure InsertAtCursorInBidirectionalList (var Ls: BidirectionalList;
Elm: Element);
{ The DeleteAtPositionInBidirectionalList procedure removes the element
at a specified position in a bidirectional list. }
procedure DeleteAtPositionInBidirectionalList (var Ls: BidirectionalList;
Position: Integer);
{ The DeleteAtCursorInBidirectionalList procedure deletes and discards
the element at the position in a given bidirectional list that is
marked by the list's cursor. }
procedure DeleteAtCursorInBidirectionalList (var Ls: BidirectionalList);
{ The DeleteValueFromBidirectionalList procedure strips all occurrences
of a specified value out of a bidirectional list. }
procedure DeleteValueFromBidirectionalList (var Ls: BidirectionalList;
Delend: Element);
{ The ReplaceInBidirectionalList procedure replaces every occurrence of a
specified value in a bidirectional list with a new value. }
procedure ReplaceInBidirectionalList (var Ls: BidirectionalList;
Displacer, Displaced: Element);
{ The FillBidirectionalList function constructs and returns a
bidirectional list consisting of a specified number of copies of a
given element. }
function FillBidirectionalList (Length: Integer; Filler: Element):
BidirectionalList;
{ The GenerateBidirectionalList function constructs a bidirectional list
of a specified length by applying a given function to the positive
integers in ascending order until that length is reached. }
function GenerateBidirectionalList (function Generator (N: Integer): Element;
Length: Integer): BidirectionalList;
{ The TransformBidirectionalList procedure applies a transformation to
every element of a bidirectional list. }
procedure TransformBidirectionalList (var Ls: BidirectionalList;
function Transformer (E: Element): Element);
{ The ApplyAlongBidirectionalList procedure applies a given procedure to
each successive element of a given bidirectional list. }
procedure ApplyAlongBidirectionalList (Ls: BidirectionalList;
procedure Applicand (E: Element));
{ The EveryElementOfBidirectionalList function determines whether every
element of a given bidirectional list satisfies a given predicate. }
function EveryElementOfBidirectionalList (Ls: BidirectionalList;
function Test (E: Element): Boolean): Boolean;
{ The SomeElementOfBidirectionalList function determines whether at least
one element of a given bidirectional list satisfies a given predicate. }
function SomeElementOfBidirectionalList (Ls: BidirectionalList;
function Test (E: Element): Boolean): Boolean;
{ The RecoverByTestFromBidirectionalList procedure determines whether any
of the elements of a given bidirectional list satisfies a given
predicate and, if so, returns the one whose position is the least. }
procedure RecoverByTestFromBidirectionalList (Ls: BidirectionalList;
function Test (E: Element): Boolean; var Found: Boolean;
var Sought: Element);
{ The LocateByTestInBidirectionalList procedure determines whether any of
the elements of a given bidirectional list satisfies a given predicate
and, if so, returns the least position occupied by such an element. }
procedure LocateByTestInBidirectionalList (Ls: BidirectionalList;
function Test (E: Element): Boolean; var Found: Boolean;
var Position: Integer);
{ The FindNextByTestInBidirectionalList procedure advances a given
bidirectional list's cursor to the next position occupied by an element
that satisfies a given predicate, leaving it null if there is no such
position. }
procedure FindNextByTestInBidirectionalList (var Operand: BidirectionalList;
function Test (E: Element): Boolean);
{ The FindPreviousByTestInBidirectionalList procedure moves a given
bidirectional list's cursor to the nearest lower-numbered position
occupied by an element that satisfies a given predicate, leaving it
null if there is no such position. }
procedure FindPreviousByTestInBidirectionalList (var Operand:
BidirectionalList; function Test (E: Element): Boolean);
{ The FilterBidirectionalList procedure strips out of a given
bidirectional list any elements that do not satisfy a given
predicate. }
procedure FilterBidirectionalList (var Ls: BidirectionalList;
function Test (E: Element): Boolean);
{ The DeallocateBidirectionalList procedure recycles the storage
associated with a given bidirectional list. }
procedure DeallocateBidirectionalList (var Operand: BidirectionalList);
implement
import StdErr;
const
FirstExceptionCode = 1;
IncorrectlyConstructedBidirectionalListException = 1;
UninitializedBidirectionalListException = 2;
FirstOfBidirectionalListException = 3;
DeleteFirstOfBidirectionalListException = 4;
LastOfBidirectionalListException = 5;
DeleteLastOfBidirectionalListException = 6;
NullCursorException = 7;
RecoverByPositionFromBidirectionalListException = 8;
AssignAtPositionInBidirectionalListException = 9;
SublistOfBidirectionalListException = 10;
InsertAtPositionInBidirectionalListException = 11;
DeleteAtPositionInBidirectionalListException = 12;
FillBidirectionalListException = 13;
GenerateBidirectionalListException = 14;
ExceptionException = 15;
LastExceptionCode = 15;
Debug = True;
{ True during debugging, False (for greater speed) when the
module is released }
type
Link = ^BidirectionalListComponent;
BidirectionalListComponent = record
Datum: Element;
Fore, Aft: Link
end;
BidirectionalListRecord = record
Size: Integer;
Head, Tail: Link;
Cursor: Link
end;
procedure BidirectionalListExceptionHandler (ExceptionCode: Integer);
begin
if (ExceptionCode < FirstExceptionCode) or
(LastExceptionCode < ExceptionCode) then
ExceptionCode := ExceptionException;
WriteLn (StdErr, 'Exception #', ExceptionCode : 1,
' in module BidirectionalLists:');
case ExceptionCode of
IncorrectlyConstructedBidirectionalListException:
WriteLn (StdErr, 'An operation attempted to return an incorrectly ',
'constructed bidirectional list.');
UninitializedBidirectionalListException:
WriteLn (Stderr, 'An operation was applied to an uninitialized ',
'list. ');
FirstOfBidirectionalListException:
WriteLn (StdErr, 'The empty list was passed to the ',
'FirstOfBidirectionalList function.');
DeleteFirstOfBidirectionalListException:
WriteLn (StdErr, 'The empty list was passed to the ',
'DeleteFirstOfBidirectionalList function.');
LastOfBidirectionalListException:
WriteLn (StdErr, 'The empty list was passed to the ',
'LastOfBidirectionalList function.');
DeleteLastOfBidirectionalListException:
WriteLn (StdErr, 'The empty list was passed to the ',
'DeleteLastOfBidirectionalList function.');
NullCursorException:
WriteLn (StdErr, 'A list with a null cursor was passed to a ',
'procedure or function that required a non-null cursor.');
RecoverByPositionFromBidirectionalListException:
WriteLn (StdErr, 'An invalid index was passed to the ',
'RecoverByPositionFromBidirectionalList function.');
AssignAtPositionInBidirectionalListException:
WriteLn (StdErr, 'An invalid index was passed to the ',
'AssignAtPositionFromBidirectionalList function.');
SublistOfBidirectionalListException:
WriteLn (StdErr, 'An invalid index was passed to the ',
'SublistOfBidirectionalListfunction.');
InsertAtPositionInBidirectionalListException:
WriteLn (StdErr, 'An invalid index was passed to the ',
'InsertAtPositionInBidirectionalList function.');
DeleteAtPositionInBidirectionalListException:
WriteLn (StdErr, 'An invalid index was passed to the ',
'DeleteAtPositionInBidirectionalList function.');
FillBidirectionalListException:
WriteLn (StdErr, 'A negative Length argument was passed to the ',
'FillBidirectionalList function.');
GenerateBidirectionalListException:
WriteLn (StdErr, 'A negative Length argument was passed to the ',
'GenerateBidirectionalList function.');
ExceptionException:
WriteLn (StdErr, 'The BidirectionalListExceptionHandler procedure ',
'received an unknown exception code.')
end
end;
function ValidBidirectionalList (Ls: BidirectionalList): Boolean;
var
Tally: Integer;
{ counts the number of components actually in the doubly-linked
list }
Traverser: Link;
{ points to successive components of the doubly-linked list }
CursorFound: Boolean;
{ indicates whether the cursor has a suitable value (either nil, or
a pointer to one of the components of the doubly-linked list }
OKSoFar: Boolean;
{ indicates whether the internal links of the doubly-linked list are
all reciprocal (i.e., whether A's aft pointer points to B if and
only if B's fore pointer points to A) }
begin
if Ls = nil then
ValidBidirectionalList := False
else if Ls^.Size = 0 then
ValidBidirectionalList := (Ls^.Head = nil) and (Ls^.Tail = nil)
and (Ls^.Cursor = nil)
else if (Ls^.Head = nil) or (Ls^.Tail = nil) then
ValidBidirectionalList := False
else if (Ls^.Head^.Fore <> nil) or (Ls^.Tail^.Aft <> nil) then
ValidBidirectionalList := False
else begin
Tally := 1;
Traverser := Ls^.Head;
CursorFound := (Ls^.Cursor = nil) or (Ls^.Cursor = Ls^.Tail);
OKSoFar := True;
while OKSoFar and (Traverser^.Aft <> nil) do begin
if Traverser^.Aft^.Fore <> Traverser then
OKSoFar := False;
Tally := Tally + 1;
if Traverser = Ls^.Cursor then
CursorFound := True;
Traverser := Traverser^.Aft
end;
ValidBidirectionalList := OKSoFar and (Traverser = Ls^.Tail) and
(Tally = Ls^.Size) and CursorFound
end
end;
function MakeEmptyBidirectionalList: BidirectionalList;
var
Result: BidirectionalList;
{ the empty bidirectional list, as it is being constructed }
begin
New (Result);
Result^.Size := 0;
Result^.Head := nil;
Result^.Tail := nil;
Result^.Cursor := nil;
if Debug then
Assert (ValidBidirectionalList (Result),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler);
MakeEmptyBidirectionalList := Result
end;
procedure PrependToBidirectionalList (Prefix: Element;
var Base: BidirectionalList);
var
OneMore: Link;
{ a pointer to a component to be inserted into a doubly-linked list }
begin
Assert (Base <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
New (OneMore);
OneMore^.Datum := Prefix;
OneMore^.Fore := nil;
OneMore^.Aft := Base^.Head;
if Base^.Head = nil then
Base^.Tail := OneMore
else
Base^.Head^.Fore := OneMore;
Base^.Head := OneMore;
Base^.Cursor := nil;
Base^.Size := Base^.Size + 1;
if Debug then
Assert (ValidBidirectionalList (Base),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler)
end;
function FirstOfBidirectionalList (Operand: BidirectionalList): Element;
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert (Operand^.Head <> nil, FirstOfBidirectionalListException,
BidirectionalListExceptionHandler);
FirstOfBidirectionalList := Operand^.Head^.Datum
end;
procedure DeleteFirstOfBidirectionalList (var Operand: BidirectionalList);
var
OneLess: Link;
{ a pointer to a component to be removed from a doubly-linked list }
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert (Operand^.Head <> nil, DeleteFirstOfBidirectionalListException,
BidirectionalListExceptionHandler);
OneLess := Operand^.Head;
Operand^.Head := OneLess^.Aft;
if OneLess^.Aft = nil then
Operand^.Tail := nil
else
OneLess^.Aft^.Fore := nil;
Operand^.Cursor := nil;
Operand^.Size := Operand^.Size - 1;
Dispose (OneLess);
if Debug then
Assert (ValidBidirectionalList (Operand),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler);
end;
function EmptyBidirectionalList (Operand: BidirectionalList): Boolean;
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
EmptyBidirectionalList := (Operand^.Size = 0)
end;
function LengthOfBidirectionalList (Operand: BidirectionalList): Integer;
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
LengthOfBidirectionalList := Operand^.Size
end;
procedure AppendToBidirectionalList (var Base: BidirectionalList;
Postfix: Element);
var
OneMore: Link;
{ a pointer to a component to be inserted into a doubly-linked list }
begin
Assert (Base <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
New (OneMore);
OneMore^.Datum := Postfix;
OneMore^.Fore := Base^.Tail;
OneMore^.Aft := nil;
if Base^.Tail = nil then
Base^.Head := OneMore
else
Base^.Tail^.Aft := OneMore;
Base^.Tail := OneMore;
Base^.Cursor := nil;
Base^.Size := Base^.Size + 1;
if Debug then
Assert (ValidBidirectionalList (Base),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler);
end;
function LastOfBidirectionalList (Operand: BidirectionalList): Element;
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert (Operand^.Tail <> nil, LastOfBidirectionalListException,
BidirectionalListExceptionHandler);
LastOfBidirectionalList := Operand^.Tail^.Datum
end;
procedure DeleteLastOfBidirectionalList (var Operand: BidirectionalList);
var
OneLess: Link;
{ a pointer to a component to be removed from a doubly-linked list }
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert (Operand^.Tail <> nil, DeleteLastOfBidirectionalListException,
BidirectionalListExceptionHandler);
OneLess := Operand^.Tail;
if OneLess^.Fore = nil then
Operand^.Head := nil
else
OneLess^.Fore^.Aft := nil;
Operand^.Tail := OneLess^.Fore;
Operand^.Cursor := nil;
Operand^.Size := Operand^.Size - 1;
Dispose (OneLess);
if Debug then
Assert (ValidBidirectionalList (Operand),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler);
end;
function CopyBidirectionalList (Operand: BidirectionalList):
BidirectionalList;
var
Result: BidirectionalList;
{ the duplicate bidirectional list, as it is being constructed }
ResultTraverser, OperandTraverser: Link;
{ pointers to successive components of the duplicate and original
doubly-linked lists, respectively }
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
New (Result);
if Operand^.Size = 0 then begin
Result^.Head := nil;
Result^.Tail := nil
end
else begin
New (ResultTraverser);
Result^.Head := ResultTraverser;
ResultTraverser^.Fore := nil;
OperandTraverser := Operand^.Head;
ResultTraverser^.Datum := OperandTraverser^.Datum;
while OperandTraverser^.Aft <> nil do begin
New (ResultTraverser^.Aft);
ResultTraverser^.Aft^.Fore := ResultTraverser;
ResultTraverser := ResultTraverser^.Aft;
OperandTraverser := OperandTraverser^.Aft;
ResultTraverser^.Datum := OperandTraverser^.Datum
end;
ResultTraverser^.Aft := nil;
Result^.Tail := ResultTraverser
end;
Result^.Size := Operand^.Size;
Result^.Cursor := nil;
if Debug then
Assert (ValidBidirectionalList (Result),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler);
CopyBidirectionalList := Result
end;
procedure CursorToStartOfBidirectionalList (var Operand: BidirectionalList);
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Operand^.Cursor := Operand^.Head
end;
procedure CursorToEndOfBidirectionalList (var Operand: BidirectionalList);
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Operand^.Cursor := Operand^.Tail
end;
procedure AdvanceCursorAlongBidirectionalList (var Operand:
BidirectionalList);
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert (Operand^.Cursor <> nil, NullCursorException,
BidirectionalListExceptionHandler);
Operand^.Cursor := Operand^.Cursor^.Aft
end;
procedure RetreatCursorAlongBidirectionalList (var Operand:
BidirectionalList);
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert (Operand^.Cursor <> nil, NullCursorException,
BidirectionalListExceptionHandler);
Operand^.Cursor := Operand^.Cursor^.Fore
end;
function NullCursorInBidirectionalList (Operand: BidirectionalList):
Boolean;
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
NullCursorInBidirectionalList := (Operand^.Cursor = nil)
end;
procedure ConcatenateBidirectionalList (var LeftOperand:
BidirectionalList; RightOperand: BidirectionalList);
var
ResultTraverser, OperandTraverser: Link;
{ pointers to successive components of the doubly-linked lists in the
right operand and in the extended left operand, respectively }
begin
Assert ((LeftOperand <> nil) and (RightOperand <> nil),
UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
if LeftOperand^.Size = 0 then begin
DeallocateBidirectionalList (LeftOperand);
LeftOperand := CopyBidirectionalList (RightOperand)
end
else if RightOperand^.Size = 0 then
LeftOperand^.Cursor := nil
else begin
New (ResultTraverser);
LeftOperand^.Tail^.Aft := ResultTraverser;
ResultTraverser^.Fore := LeftOperand^.Tail;
OperandTraverser := RightOperand^.Head;
ResultTraverser^.Datum := OperandTraverser^.Datum;
while OperandTraverser^.Aft <> nil do begin
New (ResultTraverser^.Aft);
ResultTraverser^.Aft^.Fore := ResultTraverser;
ResultTraverser := ResultTraverser^.Aft;
OperandTraverser := OperandTraverser^.Aft;
ResultTraverser^.Datum := OperandTraverser^.Datum
end;
ResultTraverser^.Aft := nil;
LeftOperand^.Tail := ResultTraverser;
LeftOperand^.Size := LeftOperand^.Size + RightOperand^.Size;
LeftOperand^.Cursor := nil
end;
if Debug then
Assert (ValidBidirectionalList (LeftOperand),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler);
end;
function RecoverByPositionFromBidirectionalList (Position: Integer;
Ls: BidirectionalList): Element;
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert ((1 <= Position) and (Position <= Ls^.Size),
RecoverByPositionFromBidirectionalListException,
BidirectionalListExceptionHandler);
Traverser := Ls^.Head;
while 1 < Position do begin
Traverser := Traverser^.Aft;
Position := Position - 1
end;
RecoverByPositionFromBidirectionalList := Traverser^.Datum
end;
function ElementAtCursorInBidirectionalList (Operand: BidirectionalList):
Element;
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert (Operand^.Cursor <> nil, NullCursorException,
BidirectionalListExceptionHandler);
ElementAtCursorInBidirectionalList := Operand^.Cursor^.Datum
end;
procedure AssignAtPositionInBidirectionalList (Position: Integer;
var Ls: BidirectionalList; NewValue: Element);
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert ((1 <= Position) and (Position <= Ls^.Size),
RecoverByPositionFromBidirectionalListException,
BidirectionalListExceptionHandler);
Traverser := Ls^.Head;
while 1 < Position do begin
Traverser := Traverser^.Aft;
Position := Position - 1
end;
Traverser^.Datum := NewValue
end;
procedure AssignAtCursorInBidirectionalList (var Ls: BidirectionalList;
NewValue: Element);
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert (Ls^.Cursor <> nil, NullCursorException,
BidirectionalListExceptionHandler);
Ls^.Cursor^.Datum := NewValue
end;
function ElementOfBidirectionalList (Candidate: Element;
Ls: BidirectionalList): Boolean;
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
Found: Boolean;
{ indicates whether the element sought has yet been encountered }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Found := False;
Traverser := Ls^.Head;
while not Found and (Traverser <> nil) do
if Traverser^.Datum = Candidate then
Found := True
else
Traverser := Traverser^.Aft;
ElementOfBidirectionalList := Found
end;
procedure LocateInBidirectionalList (Sought: Element;
Ls: BidirectionalList; var Found: Boolean; var Position: Integer);
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Position := 0;
Found := False;
Traverser := Ls^.Head;
while not Found and (Traverser <> nil) do begin
Position := Position + 1;
if Traverser^.Datum = Sought then
Found := True
else
Traverser := Traverser^.Aft
end
end;
procedure FindNextInBidirectionalList (Sought: Element;
var Ls: BidirectionalList);
label
99; { Exit when the element is found or the end of the list
is reached. }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
if Ls^.Cursor = nil then
Ls^.Cursor := Ls^.Head
else
Ls^.Cursor := Ls^.Cursor^.Aft;
while True do
if Ls^.Cursor = nil then
goto 99
else if EqualElement (Ls^.Cursor^.Datum, Sought) then
goto 99
else
Ls^.Cursor := Ls^.Cursor^.Aft;
99:
end;
procedure FindPreviousInBidirectionalList (Sought: Element;
var Ls: BidirectionalList);
label
99; { Exit when the element is found or the start of the list
is reached. }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
if Ls^.Cursor = nil then
Ls^.Cursor := Ls^.Tail
else
Ls^.Cursor := Ls^.Cursor^.Fore;
while True do
if Ls^.Cursor = nil then
goto 99
else if EqualElement (Ls^.Cursor^.Datum, Sought) then
goto 99
else
Ls^.Cursor := Ls^.Cursor^.Fore;
99:
end;
procedure SublistOfBidirectionalList (var Ls: BidirectionalList;
Start, Finish: Integer);
var
Traverser, Trailer: Link;
{ pointers to successive components of the doubly-linked list;
Trailer is consistently one component behind Traverser }
Position: Integer;
{ counts off positions in the doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert ((1 <= Start) and (Start <= Ls^.Size) and
(1 <= Finish) and (Finish <= Ls^.Size),
SublistofBidirectionalListException,
BidirectionalListExceptionHandler);
if Finish < Start then begin
Traverser := Ls^.Head;
while Traverser <> nil do begin
Trailer := Traverser;
Traverser := Traverser^.Aft;
Dispose (Trailer)
end;
Ls^.Head := nil;
Ls^.Tail := nil;
Ls^.Cursor := nil;
Ls^.Size := 0
end
else begin
Traverser := Ls^.Head;
for Position := 1 to Start - 1 do begin
Trailer := Traverser;
Traverser := Traverser^.Aft;
Dispose (Trailer)
end;
Ls^.Head := Traverser;
Traverser^.Fore := nil;
Traverser := Ls^.Tail;
for Position := Ls^.Size downto Finish + 1 do begin
Trailer := Traverser;
Traverser := Traverser^.Fore;
Dispose (Trailer)
end;
Ls^.Tail := Traverser;
Traverser^.Aft := nil;
Ls^.Cursor := nil;
Ls^.Size := Finish - Start + 1
end;
if Debug then
Assert (ValidBidirectionalList (Ls),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler)
end;
procedure ReverseBidirectionalList (var Operand: BidirectionalList);
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
Temp: Link;
{ temporary storage for a pointer as its direction is reversed }
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
if 1 < Operand^.Size then begin
Traverser := Operand^.Head;
while Traverser <> nil do begin
Temp := Traverser^.Aft;
Traverser^.Aft := Traverser^.Fore;
Traverser^.Fore := Temp;
Traverser := Traverser^.Fore
end;
Temp := Operand^.Head;
Operand^.Head := Operand^.Tail;
Operand^.Tail := Temp;
end;
Operand^.Cursor := nil;
if Debug then
Assert (ValidBidirectionalList (Operand),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler)
end;
procedure InsertAtPositionInBidirectionalList (var Ls: BidirectionalList;
Position: Integer; Elm: Element);
var
OneMore: Link;
{ a pointer to a component to be inserted into a doubly-linked list }
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert ((1 <= Position) and (Position <= Ls^.Size + 1),
InsertAtPositionInBidirectionalListException,
BidirectionalListExceptionHandler);
Traverser := Ls^.Head;
while 1 < Position do begin
Traverser := Traverser^.Aft;
Position := Position - 1
end;
New (OneMore);
OneMore^.Datum := Elm;
if Traverser = nil then
OneMore^.Fore := Ls^.Tail
else
OneMore^.Fore := Traverser^.Fore;
OneMore^.Aft := Traverser;
if Traverser = Ls^.Head then
Ls^.Head := OneMore
else if Traverser = nil then
Ls^.Tail^.Aft := OneMore
else
Traverser^.Fore^.Aft := OneMore;
if Traverser = nil then
Ls^.Tail := OneMore
else
Traverser^.Fore := OneMore;
Ls^.Cursor := nil;
Ls^.Size := Ls^.Size + 1;
if Debug then
Assert (ValidBidirectionalList (Ls),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler)
end;
procedure InsertAtCursorInBidirectionalList (var Ls: BidirectionalList;
Elm: Element);
var
OneMore: Link;
{ a pointer to a component to be inserted into a doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
New (OneMore);
OneMore^.Datum := Elm;
if Ls^.Cursor = nil then
OneMore^.Fore := Ls^.Tail
else
OneMore^.Fore := Ls^.Cursor^.Fore;
OneMore^.Aft := Ls^.Cursor;
if Ls^.Cursor = Ls^.Head then
Ls^.Head := OneMore
else if Ls^.Cursor = nil then
Ls^.Tail^.Aft := OneMore
else
Ls^.Cursor^.Fore^.Aft := OneMore;
if Ls^.Cursor = nil then
Ls^.Tail := OneMore
else
Ls^.Cursor^.Fore := OneMore;
Ls^.Size := Ls^.Size + 1;
if Debug then
Assert (ValidBidirectionalList (Ls),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler)
end;
procedure DeleteAtPositionInBidirectionalList (var Ls: BidirectionalList;
Position: Integer);
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert ((1 <= Position) and (Position <= Ls^.Size),
DeleteAtPositionInBidirectionalListException,
BidirectionalListExceptionHandler);
Traverser := Ls^.Head;
while 1 < Position do begin
Traverser := Traverser^.Aft;
Position := Position - 1
end;
if Traverser^.Fore = nil then
Ls^.Head := Traverser^.Aft
else
Traverser^.Fore^.Aft := Traverser^.Aft;
if Traverser^.Aft = nil then
Ls^.Tail := Traverser^.Fore
else
Traverser^.Aft^.Fore := Traverser^.Fore;
Dispose (Traverser);
Ls^.Cursor := nil;
Ls^.Size := Ls^.Size - 1;
if Debug then
Assert (ValidBidirectionalList (Ls),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler)
end;
procedure DeleteAtCursorInBidirectionalList (var Ls: BidirectionalList);
var
OneLess: Link;
{ a pointer to a component to be removed from a doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Assert (Ls^.Cursor <> nil, NullCursorException,
BidirectionalListExceptionHandler);
OneLess := Ls^.Cursor;
Ls^.Cursor := OneLess^.Aft;
if OneLess^.Fore = nil then
Ls^.Head := OneLess^.Aft
else
OneLess^.Fore^.Aft := OneLess^.Aft;
if OneLess^.Aft = nil then
Ls^.Tail := OneLess^.Fore
else
OneLess^.Aft^.Fore := OneLess^.Fore;
Dispose (OneLess);
Ls^.Size := Ls^.Size - 1;
if Debug then
Assert (ValidBidirectionalList (Ls),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler)
end;
procedure DeleteValueFromBidirectionalList (var Ls: BidirectionalList;
Delend: Element);
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
OneLess: Link;
{ a pointer to a component to be removed from a doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Traverser := Ls^.Head;
while Traverser <> nil do
if Traverser^.Datum = Delend then begin
OneLess := Traverser;
Traverser := Traverser^.Aft;
if OneLess^.Fore = nil then
Ls^.Head := OneLess^.Aft
else
OneLess^.Fore^.Aft := OneLess^.Aft;
if OneLess^.Aft = nil then
Ls^.Tail := OneLess^.Fore
else
OneLess^.Aft^.Fore := OneLess^.Fore;
Dispose (OneLess);
Ls^.Size := Ls^.Size - 1
end
else
Traverser := Traverser^.Aft;
Ls^.Cursor := nil;
if Debug then
Assert (ValidBidirectionalList (Ls),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler)
end;
procedure ReplaceInBidirectionalList (var Ls: BidirectionalList;
Displacer, Displaced: Element);
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Traverser := Ls^.Head;
while Traverser <> nil do begin
if Traverser^.Datum = Displaced then
Traverser^.Datum := Displacer;
Traverser := Traverser^.Aft
end
end;
function FillBidirectionalList (Length: Integer; Filler: Element):
BidirectionalList;
var
Filled: BidirectionalList;
{ the new bidirectional list, as it is constructed }
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
Position: Integer;
{ the number of components so far constructed }
begin
Assert (0 <= Length, FillBidirectionalListException,
BidirectionalListExceptionHandler);
New (Filled);
if Length = 0 then begin
Filled^.Head := nil;
Filled^.Tail := nil
end
else begin
New (Filled^.Head);
Traverser := Filled^.Head;
Traverser^.Fore := nil;
Traverser^.Datum := Filler;
Position := 1;
while Position < Length do begin
New (Traverser^.Aft);
Traverser^.Aft^.Fore := Traverser;
Traverser := Traverser^.Aft;
Traverser^.Datum := Filler;
Position := Position + 1
end;
Traverser^.Aft := nil;
Filled^.Tail := Traverser
end;
Filled^.Cursor := nil;
Filled^.Size := Length;
if Debug then
Assert (ValidBidirectionalList (Filled),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler);
FillBidirectionalList := Filled
end;
function GenerateBidirectionalList (function Generator (N: Integer):
Element; Length: Integer): BidirectionalList;
var
Generated: BidirectionalList;
{ the new bidirectional list, as it is constructed }
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
Position: Integer;
{ the number of components so far constructed }
begin
Assert (0 <= Length, GenerateBidirectionalListException,
BidirectionalListExceptionHandler);
New (Generated);
if Length = 0 then begin
Generated^.Head := nil;
Generated^.Tail := nil
end
else begin
New (Generated^.Head);
Traverser := Generated^.Head;
Traverser^.Fore := nil;
Position := 1;
Traverser^.Datum := Generator (Position);
while Position < Length do begin
New (Traverser^.Aft);
Traverser^.Aft^.Fore := Traverser;
Traverser := Traverser^.Aft;
Position := Position + 1;
Traverser^.Datum := Generator (Position)
end;
Traverser^.Aft := nil;
Generated^.Tail := Traverser
end;
Generated^.Cursor := nil;
Generated^.Size := Length;
if Debug then
Assert (ValidBidirectionalList (Generated),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler);
GenerateBidirectionalList := Generated
end;
procedure TransformBidirectionalList (var Ls: BidirectionalList;
function Transformer (E: Element): Element);
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Traverser := Ls^.Head;
while Traverser <> nil do begin
Traverser^.Datum := Transformer (Traverser^.Datum);
Traverser := Traverser^.Aft
end
end;
procedure ApplyAlongBidirectionalList (Ls: BidirectionalList;
procedure Applicand (E: Element));
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Traverser := Ls^.Head;
while Traverser <> nil do begin
Applicand (Traverser^.Datum);
Traverser := Traverser^.Aft
end
end;
function EveryElementOfBidirectionalList (Ls: BidirectionalList;
function Test (E: Element): Boolean): Boolean;
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
TrueSoFar: Boolean;
{ indicates whether all of the elements so far encountered have
passed the test }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
TrueSoFar := True;
Traverser := Ls^.Head;
while TrueSoFar and (Traverser <> nil) do
if Test (Traverser^.Datum) then
Traverser := Traverser^.Aft
else
TrueSoFar := False;
EveryElementOfBidirectionalList := TrueSoFar
end;
function SomeElementOfBidirectionalList (Ls: BidirectionalList;
function Test (E: Element): Boolean): Boolean;
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
FalseSoFar: Boolean;
{ indicates whether all of the elements so far encountered have
failed the test }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
FalseSoFar := True;
Traverser := Ls^.Head;
while FalseSoFar and (Traverser <> nil) do
if Test (Traverser^.Datum) then
FalseSoFar := False
else
Traverser := Traverser^.Aft;
SomeElementOfBidirectionalList := not FalseSoFar
end;
procedure RecoverByTestFromBidirectionalList (Ls: BidirectionalList;
function Test (E: Element): Boolean; var Found: Boolean;
var Sought: Element);
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Found := False;
Traverser := Ls^.Head;
while not Found and (Traverser <> nil) do
if Test (Traverser^.Datum) then begin
Found := True;
Sought := Traverser^.Datum
end
else
Traverser := Traverser^.Aft
end;
procedure LocateByTestInBidirectionalList (Ls: BidirectionalList;
function Test (E: Element): Boolean; var Found: Boolean;
var Position: Integer);
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Found := False;
Position := 1;
Traverser := Ls^.Head;
while not Found and (Traverser <> nil) do
if Test (Traverser^.Datum) then
Found := True
else begin
Traverser := Traverser^.Aft;
Position := Position + 1
end
end;
procedure FindNextByTestInBidirectionalList (var Operand: BidirectionalList;
function Test (E: Element): Boolean);
label
99; { Exit when the test succeeds or the end of the list is reached. }
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
if Operand^.Cursor = nil then
Operand^.Cursor := Operand^.Head
else
Operand^.Cursor := Operand^.Cursor^.Aft;
while True do
if Operand^.Cursor = nil then
goto 99
else if Test (Operand^.Cursor^.Datum) then
goto 99
else
Operand^.Cursor := Operand^.Cursor^.Aft;
99:
end;
procedure FindPreviousByTestInBidirectionalList (var Operand:
BidirectionalList; function Test (E: Element): Boolean);
label
99; { Exit when the test succeeds or the end of the list is reached. }
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
if Operand^.Cursor = nil then
Operand^.Cursor := Operand^.Tail
else
Operand^.Cursor := Operand^.Cursor^.Fore;
while True do
if Operand^.Cursor = nil then
goto 99
else if Test (Operand^.Cursor^.Datum) then
goto 99
else
Operand^.Cursor := Operand^.Cursor^.Fore;
99:
end;
procedure FilterBidirectionalList (var Ls: BidirectionalList;
function Test (E: Element): Boolean);
var
Traverser: Link;
{ a pointer to successive components of the doubly-linked list }
OneLess: Link;
{ a pointer to a component to be removed from a doubly-linked list }
begin
Assert (Ls <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Traverser := Ls^.Head;
while Traverser <> nil do
if Test (Traverser^.Datum) then
Traverser := Traverser^.Aft
else begin
OneLess := Traverser;
Traverser := Traverser^.Aft;
if OneLess^.Fore = nil then
Ls^.Head := OneLess^.Aft
else
OneLess^.Fore^.Aft := OneLess^.Aft;
if OneLess^.Aft = nil then
Ls^.Tail := OneLess^.Fore
else
OneLess^.Aft^.Fore := OneLess^.Fore;
Dispose (OneLess);
Ls^.Size := Ls^.Size - 1
end;
Ls^.Cursor := nil;
if Debug then
Assert (ValidBidirectionalList (Ls),
IncorrectlyConstructedBidirectionalListException,
BidirectionalListExceptionHandler)
end;
procedure DeallocateBidirectionalList (var Operand: BidirectionalList);
var
Traverser, Trailer: Link;
{ pointers to successive components of the doubly-linked list;
Trailer is consistently one component behind Traverser }
begin
Assert (Operand <> nil, UninitializedBidirectionalListException,
BidirectionalListExceptionHandler);
Traverser := Operand^.Head;
while Traverser <> nil do begin
Trailer := Traverser;
Traverser := Traverser^.Aft;
Dispose (Trailer)
end;
Dispose (Operand)
end;
end.