This program illustrates the use of a hierarchical library to create an abstract data type and its associated operations. It is based on the type Rational of Exercise 12.2(3).
The root package Rational_Numbers declares the type Rational and the usual arithmetic operations. The private child package Rational_Numbers.Slave contains the functions Normal and GCD as in Exercise 13.4(1). Thus Normal cancels any common factors in the numerator and denominator and returns the normalized form. It is called by various operations in the parent package. It would be possible to restructure Normal so that it was a private child function.
Appropriate input–output subprograms are declared in the public child Rational_Numbers.IO.
In order to exercise the rational subsystem a simple interpretive calculator is added as the main subprogram. This enables the user to read in rational numbers, perform the usual arithmetic operations upon them and print out the result.
The numbers are held in a stack which is operated upon in the reverse Polish form (Polish after the logician Jan /Lucasiewicz). The root package Rat_Stack contains subprograms Clear, Push and Pop. The private child package Rat_Stack.Data contains the actual data, and the public child procedure Rat_Stack.Print_Top prints the top item. This structure is somewhat similar to that described in Section 13.4 and enables the stack size to be changed with minimal effect on the rest of the system.
The main subprogram is decomposed into subunits Process and Get_Rational in order to isolate the dependencies and clarify the structure.
package Rational_Numbers is
type Rational is private;
-- unary operators
function “+” (X: Rational) return Rational;
function “-” (X: Rational) return Rational;
-- binary operators
function “+” (X, Y: Rational) return Rational;
function “-” (X, Y: Rational) return Rational;
function “*” (X, Y: Rational) return Rational;
function “/” (X, Y: Rational) return Rational;
-- constructor and selector functions
function “/” (X: Integer; Y: Positive) return Rational;
function Numerator(R: Rational) return Integer;
function Denominator(R: Rational) return Positive;
private
type Rational is
record
Num: Integer := 0; -- numerator
Den: Positive := 1; -- denominator
end record;
end;
private package Rational_Numbers.Slave is function Normal(R: Rational) return Rational;
end;
package body Rational_Numbers.Slave is
function GCD(X, Y: Natural) return Natural is
begin
if Y = 0 then
return X;
else
return GCD(Y, X mod Y);
end if;
end GCD;
function Normal(R: Rational) return Rational is
G: Positive := GCD(abs R.Num, R.Den);
begin
return (R.Num/G, R.Den/G);