|
DataMuseum.dkPresents historical artifacts from the history of: Rational R1000/400 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Rational R1000/400 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 228267 (0x37bab) Types: TextFile Notes: R1k Text-file segment
└─⟦8527c1e9b⟧ Bits:30000544 8mm tape, Rational 1000, Arrival backup of disks in PAM's R1000 └─ ⟦5a81ac88f⟧ »Space Info Vol 1« └─⟦cb4012ff5⟧ └─⟦this⟧
package Bounded_String is subtype String_Length is Natural; type Variable_String (Maximum_Length : String_Length) is private; -- initialized to have a length of 0 procedure Copy (Target : in out Variable_String; Source : Variable_String); procedure Copy (Target : in out Variable_String; Source : String); procedure Copy (Target : in out Variable_String; Source : Character); procedure Move (Target : in out Variable_String; Source : in out Variable_String); function Image (V : Variable_String) return String; -- Value function with maximum length = current length function Value (S : String) return Variable_String; -- Value function with specified maximum length function Value (S : String; Max_Length : Natural) return Variable_String; pragma Inline (Image); procedure Free (V : in out Variable_String); procedure Append (Target : in out Variable_String; Source : Variable_String); procedure Append (Target : in out Variable_String; Source : String); procedure Append (Target : in out Variable_String; Source : Character); procedure Append (Target : in out Variable_String; Source : Character; Count : Natural); procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : Variable_String); procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : String); procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : Character); procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : Character; Count : Natural); procedure Delete (Target : in out Variable_String; At_Pos : Positive; Count : Natural := 1); procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : Character); procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : Character; Count : Natural); procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : String); procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : Variable_String); -- Truncate or extend with fill procedure Set_Length (Target : in out Variable_String; New_Length : Natural; Fill_With : Character := ' '); -- Get information about or contents of a string function Length (Source : Variable_String) return Natural; function Char_At (Source : Variable_String; At_Pos : Positive) return Character; function Extract (Source : Variable_String; Start_Pos : Positive; End_Pos : Natural) return String; -- get the allocated length of the string function Max_Length (Source : Variable_String) return Natural; pragma Inline (Length); pragma Inline (Char_At); pragma Inline (Max_Length); private type Variable_String (Maximum_Length : String_Length) is record Length : String_Length := 0; Contents : String (1 .. Maximum_Length); end record; end Bounded_String;package body Bounded_String is procedure Copy (Target : in out Variable_String; Source : Variable_String) is begin Target.Contents (1 .. Source.Length) := Source.Contents (1 .. Source.Length); Target.Length := Source.Length; end Copy; procedure Copy (Target : in out Variable_String; Source : String) is begin Target.Contents (1 .. Source'Length) := Source; Target.Length := Source'Length; end Copy; procedure Copy (Target : in out Variable_String; Source : Character) is begin Target.Contents (1) := Source; Target.Length := 1; end Copy; procedure Move (Target : in out Variable_String; Source : in out Variable_String) is begin Target.Contents (1 .. Source.Length) := Source.Contents (1 .. Source.Length); Target.Length := Source.Length; Source.Length := 0; end Move; function Image (V : Variable_String) return String is begin return V.Contents (1 .. V.Length); end Image; function Value (S : String; Max_Length : Natural) return Variable_String is String_Value : String (1 .. Max_Length); begin String_Value (1 .. S'Length) := S; return Variable_String'(Maximum_Length => Max_Length, Length => S'Length, Contents => String_Value); end Value; function Value (S : String) return Variable_String is begin return Variable_String'(Maximum_Length => S'Length, Length => S'Length, Contents => S); end Value; procedure Free (V : in out Variable_String) is begin V.Length := 0; end Free; procedure Append (Target : in out Variable_String; Source : String) is Len : Natural := Target.Length + Source'Length; begin Target.Contents (Target.Length + 1 .. Len) := Source; Target.Length := Len; end Append; procedure Append (Target : in out Variable_String; Source : Variable_String) is begin Append (Target, Image (Source)); end Append; procedure Append (Target : in out Variable_String; Source : Character) is Len : Natural := Target.Length + 1; begin Target.Contents (Len) := Source; Target.Length := Len; end Append; procedure Append (Target : in out Variable_String; Source : Character; Count : Natural) is Value_String : String (1 .. Count) := String'(1 .. Count => Source); begin Append (Target, Value_String); end Append; procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : String) is begin if At_Pos = Target.Length + 1 then Append (Target, Source); elsif At_Pos <= Target.Length then declare Len : Natural := Target.Length + Source'Length; begin Target.Contents (At_Pos .. Len) := Source & Target.Contents (At_Pos .. Target.Length); Target.Length := Len; end; else raise Constraint_Error; end if; end Insert; procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : Variable_String) is begin Insert (Target, At_Pos, Source.Contents (1 .. Source.Length)); end Insert; procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : Character) is New_Len : Natural := Target.Length + 1; begin if At_Pos = New_Len then Append (Target, Source); elsif At_Pos > New_Len then raise Constraint_Error; else Target.Contents (At_Pos + 1 .. New_Len) := Target.Contents (At_Pos .. Target.Length); Target.Contents (At_Pos) := Source; Target.Length := New_Len; end if; end Insert; procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : Character; Count : Natural) is Value_String : String (1 .. Count) := String'(1 .. Count => Source); begin Insert (Target, At_Pos, Value_String); end Insert; procedure Delete (Target : in out Variable_String; At_Pos : Positive; Count : Natural := 1) is Len : Natural := Target.Length - Count; begin if At_Pos - 1 > Len then raise Constraint_Error; end if; if At_Pos <= Len then Target.Contents (At_Pos .. Len) := Target.Contents (At_Pos + Count .. Target.Length); end if; Target.Length := Len; end Delete; procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : Character) is begin if At_Pos > Target.Length then raise Constraint_Error; else Target.Contents (At_Pos) := Source; end if; end Replace; procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : String) is End_Pos : constant Positive := At_Pos + Source'Length - 1; begin if End_Pos > Target.Length then raise Constraint_Error; else Target.Contents (At_Pos .. End_Pos) := Source; end if; end Replace; procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : Character; Count : Natural) is Value_String : String (1 .. Count) := String'(1 .. Count => Source); begin Replace (Target, At_Pos, Value_String); end Replace; procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : Variable_String) is begin Replace (Target, At_Pos, Image (Source)); end Replace; procedure Set_Length (Target : in out Variable_String; New_Length : Natural; Fill_With : Character := ' ') is Current_Length : Natural := Target.Length; begin for I in Current_Length + 1 .. New_Length loop Target.Contents (I) := Fill_With; end loop; Target.Length := New_Length; end Set_Length; function Length (Source : Variable_String) return Natural is begin return Source.Length; end Length; function Max_Length (Source : Variable_String) return Natural is begin return Source.Maximum_Length; end Max_Length; function Char_At (Source : Variable_String; At_Pos : Positive) return Character is begin if At_Pos > Source.Length then raise Constraint_Error; else return Source.Contents (At_Pos); end if; end Char_At; function Extract (Source : Variable_String; Start_Pos : Positive; End_Pos : Natural) return String is begin if End_Pos > Source.Length then raise Constraint_Error; else return Source.Contents (Start_Pos .. End_Pos); end if; end Extract; end Bounded_String;generic Size : Integer; -- number of buckets type Domain_Type is private; type Range_Type is private; -- both types are pure values -- no initialization or finalization is necessary -- = and := can be used for equality and copy with function Hash (Key : Domain_Type) return Integer is <>; -- for efficiency, spread hash over an interval at least as great as size pragma Must_Be_Constrained (Yes => Domain_Type, Range_Type); package Concurrent_Map_Generic is type Map is private; type Pair is record D : Domain_Type; R : Range_Type; end record; function Eval (The_Map : Map; D : Domain_Type) return Range_Type; procedure Find (The_Map : Map; D : Domain_Type; R : in out Range_Type; Success : out Boolean); procedure Find (The_Map : Map; D : Domain_Type; P : in out Pair; Success : out Boolean); procedure Define (The_Map : in out Map; D : Domain_Type; R : Range_Type; Trap_Multiples : Boolean := False); procedure Undefine (The_Map : in out Map; D : Domain_Type); procedure Initialize (The_Map : out Map); function Is_Empty (The_Map : Map) return Boolean; procedure Make_Empty (The_Map : in out Map); procedure Copy (Target : in out Map; Source : Map); type Iterator is private; procedure Init (Iter : out Iterator; The_Map : Map); procedure Next (Iter : in out Iterator); function Value (Iter : Iterator) return Domain_Type; function Done (Iter : Iterator) return Boolean; Undefined : exception; -- raised by eval if the domain value in not in the map Multiply_Defined : exception; -- raised by define if the domain value is already defined and -- the trap_multiples flag has been specified (ie. is true) function Nil return Map; function Is_Nil (The_Map : Map) return Boolean; function Cardinality (The_Map : Map) return Natural; ------------------------------------------------------ -- Implementation Notes and Non-Standard Operations -- ------------------------------------------------------ -- := and = operate on references -- := implies sharing (introduces an alias) -- = means is the same map, not the same value of type map -- Initializing a map also makes it empty -- Maps must be initialized before use. -- garbage may be generated -- Concurrent Properties -- any number of find/eval/is_empty/copy may be safely done while one -- define/undefine/make_empty is taking place. -- Define/undefine/make_empty operations are serialized. -- Iterators may be used asynchronously, however the sequence of values -- yielded may never have been in the map at any one time. private type Node; type Set is access Node; type Node is record Value : Pair; Link : Set; end record; type Map_Data; type Map is access Map_Data; type Iterator is record The_Map : Map; Index_Value : Natural; Set_Iter : Set; Done : Boolean; end record; subtype Index is Integer range 0 .. Size - 1; type Table is array (Index) of Set; type Map_Data is record Cache : Set; -- of at most one node Bucket : Table; Size : Natural := 0; end record; end Concurrent_Map_Generic;package body Concurrent_Map_Generic is task Serialize is entry Define (The_Map : in out Map; D : Domain_Type; R : Range_Type; Trap_Multiples : Boolean := False); entry Undefine (The_Map : in out Map; D : Domain_Type); entry Make_Empty (The_Map : in out Map); end Serialize; function Myhash (D : Domain_Type) return Index is begin return Index (Hash (D) mod Size); end Myhash; pragma Inline (Myhash); function Find (The_Map : Map; D : Domain_Type) return Set is -- result = null ==> D not in S Rest : Set := The_Map.Bucket (Myhash (D)); begin while Rest /= null and then Rest.Value.D /= D loop Rest := Rest.Link; end loop; if Rest /= null then The_Map.Cache := Rest; end if; return Rest; end Find; procedure Find (S : Set; D : Domain_Type; Ptr : in out Set; Prev : in out Set) is -- ptr = null ==> D not in S -- ptr /= null and prev = null ==> D = first element of S begin Ptr := S; Prev := null; while (Ptr /= null) and then (Ptr.Value.D /= D) loop Prev := Ptr; Ptr := Ptr.Link; end loop; end Find; function Eval (The_Map : Map; D : Domain_Type) return Range_Type is Cache : Set := The_Map.Cache; -- cached pointer value must be fetched only once -- since cache may be concurrently updated begin if Cache /= null then declare Value : Pair renames Cache.Value; begin if Value.D = D then return Value.R; end if; end; end if; declare Ptr : Set := Find (The_Map, D); begin if Ptr /= null then return Ptr.Value.R; else raise Undefined; end if; end; end Eval; procedure Find (The_Map : Map; D : Domain_Type; R : in out Range_Type; Success : out Boolean) is Cache : Set := The_Map.Cache; -- cached pointer value must be fetched only once -- since cache may be concurrently updated begin if Cache /= null then declare Value : Pair renames Cache.Value; begin if Value.D = D then R := Value.R; Success := True; return; end if; end; end if; declare Ptr : Set := Find (The_Map, D); begin if Ptr /= null then R := Ptr.Value.R; Success := True; else Success := False; end if; end; end Find; procedure Find (The_Map : Map; D : Domain_Type; P : in out Pair; Success : out Boolean) is Cache : Set := The_Map.Cache; -- cached pointer value must be fetched only once -- since cache may be concurrently updated begin if Cache /= null then declare Value : Pair renames Cache.Value; begin if Value.D = D then P := Value; Success := True; return; end if; end; end if; declare Ptr : Set := Find (The_Map, D); begin if Ptr /= null then P := Ptr.Value; Success := True; else Success := False; end if; end; end Find; procedure Define (The_Map : in out Map; D : Domain_Type; R : Range_Type; Trap_Multiples : Boolean := False) is begin Serialize.Define (The_Map, D, R, Trap_Multiples); end Define; procedure Real_Define (The_Map : in out Map; D : Domain_Type; R : Range_Type; Trap_Multiples : Boolean := False) is Cache : Set renames The_Map.Cache; -- cache can be written but not fetched -- since cache may be concurrently updated The_Set : Set renames The_Map.Bucket (Myhash (D)); Ptr : Set; Prev : Set; begin Find (The_Set, D, Ptr, Prev); if Ptr = null then The_Set := new Node'(Pair'(D => D, R => R), The_Set); Cache := The_Set; The_Map.Size := The_Map.Size + 1; elsif Trap_Multiples then raise Multiply_Defined; elsif Prev = null then The_Set := new Node'(Pair'(D => D, R => R), Ptr.Link); Cache := The_Set; else Prev.Link := new Node'(Pair'(D => D, R => R), Ptr.Link); Cache := Prev.Link; end if; end Real_Define; procedure Undefine (The_Map : in out Map; D : Domain_Type) is begin Serialize.Undefine (The_Map, D); end Undefine; procedure Real_Undefine (The_Map : in out Map; D : Domain_Type) is Cache : Set renames The_Map.Cache; -- cache must be written but not fetched -- since cache may be concurrently updated Start : Set renames The_Map.Bucket (Myhash (D)); Current : Set; Previous : Set; begin Find (Start, D, Current, Previous); if Current = null then raise Undefined; elsif Previous = null then -- old node cannot be reused due to concurrent readers Start := Current.Link; else -- old node cannot be reused due to concurrent readers Previous.Link := Current.Link; end if; The_Map.Size := The_Map.Size - 1; Cache := null; end Real_Undefine; procedure Copy (Target : in out Map; Source : Map) is procedure Copy_Set (Target_Set : in out Set; Source_Set : Set) is Rest : Set := Source_Set; begin Target_Set := null; while Rest /= null loop Target_Set := new Node'(Rest.Value, Target_Set); Target.Size := Target.Size + 1; Rest := Rest.Link; end loop; end Copy_Set; begin Target.Size := 0; for I in Index loop Copy_Set (Target_Set => Target.Bucket (I), Source_Set => Source.Bucket (I)); end loop; Target.Cache := null; end Copy; procedure Initialize (The_Map : out Map) is begin The_Map := new Map_Data; end Initialize; function Is_Empty (The_Map : Map) return Boolean is begin for I in Index loop if The_Map.Bucket (I) /= null then return False; end if; end loop; return True; end Is_Empty; procedure Make_Empty (The_Map : in out Map) is begin Serialize.Make_Empty (The_Map); end Make_Empty; procedure Real_Make_Empty (The_Map : in out Map) is begin The_Map.Cache := null; for I in Index loop The_Map.Bucket (I) := null; end loop; end Real_Make_Empty; procedure Init (Iter : out Iterator; The_Map : Map) is The_Iter : Iterator; begin if The_Map = null then Iter.Done := True; return; end if; for I in Index loop The_Iter.Set_Iter := The_Map.Bucket (I); if The_Iter.Set_Iter /= null then The_Iter.Done := False; The_Iter.Index_Value := I; The_Iter.The_Map := The_Map; Iter := The_Iter; return; end if; end loop; The_Iter.Done := True; Iter := The_Iter; end Init; procedure Next (Iter : in out Iterator) is begin Iter.Set_Iter := Iter.Set_Iter.Link; while Iter.Set_Iter = null loop if Iter.Index_Value = Index'Last then Iter.Done := True; return; end if; Iter.Index_Value := Iter.Index_Value + 1; Iter.Set_Iter := Iter.The_Map.Bucket (Iter.Index_Value); end loop; end Next; function Value (Iter : Iterator) return Domain_Type is begin return Iter.Set_Iter.Value.D; end Value; function Done (Iter : Iterator) return Boolean is begin return Iter.Done; end Done; task body Serialize is begin loop begin select accept Define (The_Map : in out Map; D : Domain_Type; R : Range_Type; Trap_Multiples : Boolean := False) do Real_Define (The_Map, D, R, Trap_Multiples); end Define; or accept Undefine (The_Map : in out Map; D : Domain_Type) do Real_Undefine (The_Map, D); end Undefine; or accept Make_Empty (The_Map : in out Map) do Real_Make_Empty (The_Map); end Make_Empty; or terminate; end select; exception when others => null; end; end loop; end Serialize; function Nil return Map is begin return null; end Nil; function Is_Nil (The_Map : Map) return Boolean is begin return The_Map = null; end Is_Nil; function Cardinality (The_Map : Map) return Natural is begin return The_Map.Size; end Cardinality; end Concurrent_Map_Generic;with Floating_Characteristics; use Floating_Characteristics; package Core_Functions is Exp_Large : Float; Exp_Small : Float; function Sqrt (X : Float) return Float; function Cbrt (X : Float) return Float; function Log (X : Float) return Float; function Log10 (X : Float) return Float; function Exp (X : Float) return Float; function "**" (X, Y : Float) return Float; end Core_Functions;with Text_Io; use Text_Io; with Floating_Characteristics; use Floating_Characteristics; with Numeric_Io; use Numeric_Io; with Numeric_Primitives; use Numeric_Primitives; package body Core_Functions is -- The following routines are coded directly from the algorithms and -- coeficients given in "Software Manual for the Elementry Functions" -- by William J. Cody, Jr. and William Waite, Prentice_Hall, 1980 -- CBRT by analogy -- A more general formulation uses MANTISSA_TYPE, etc. -- The coeficients are appropriate for 25 to 32 bits floating significance -- They will work for less but slightly shorter versions are possible -- The routines are coded to stand alone so they need not be compiled together -- These routines have been coded to accept a general MANTISSA_TYPE -- That is, they are designed to work with a manitssa either fixed of float -- There are some explicit conversions which are required but these will -- not cause any extra code to be generated -- 16 JULY 1982 W A WHITAKER AFATL EGLIN AFB FL 32542 -- T C EICHOLTZ USAFA function Sqrt (X : Float) return Float is M, N : Exponent_Type; F, Y : Mantissa_Type; Result : Float; subtype Index is Integer range 0 .. 100; -- ######################### Sqrt_L1 : Index := 3; -- Could get away with SQRT_L1 := 2 for 28 bits -- Using the better Cody-Waite coeficients overflows MANTISSA_TYPE Sqrt_C1 : Mantissa_Type := 8#0.3317777777#; Sqrt_C2 : Mantissa_Type := 8#0.4460000000#; Sqrt_C3 : Mantissa_Type := 8#0.55202_36314_77747_36311_0#; begin if X = Zero then Result := Zero; return Result; elsif X = One then -- To get exact SQRT(1.0) Result := One; return Result; elsif X < Zero then New_Line; Put ("CALLED SQRT FOR NEGATIVE ARGUMENT "); raise Program_Error; --Put (X); Put (" USED ABSOLUTE VALUE"); New_Line; Result := Sqrt (abs (X)); return Result; else Defloat (X, N, F); Y := Sqrt_C1 + Mantissa_Type (Sqrt_C2 * F); for J in 1 .. Sqrt_L1 loop Y := Y / Mantissa_Divisor_2 + Mantissa_Type ((F / Mantissa_Divisor_2) / Y); end loop; if (N mod 2) /= 0 then Y := Mantissa_Type (Sqrt_C3 * Y); N := N + 1; end if; M := N / 2; Refloat (M, Y, Result); return Result; end if; exception when others => New_Line; Put (" EXCEPTION IN SQRT, X = "); raise Program_Error; --Put (X); Put (" RETURNED 1.0"); New_Line; return One; end Sqrt; function Cbrt (X : Float) return Float is M, N : Exponent_Type; F, Y : Mantissa_Type; Result : Float; subtype Index is Integer range 0 .. 100; -- ######################### Cbrt_L1 : Index := 3; Cbrt_C1 : Mantissa_Type := 0.5874009; Cbrt_C2 : Mantissa_Type := 0.4125990; Cbrt_C3 : Mantissa_Type := 0.62996_05249; Cbrt_C4 : Mantissa_Type := 0.79370_05260; begin if X = Zero then Result := Zero; return Result; else Defloat (X, N, F); F := abs (F); Y := Cbrt_C1 + Mantissa_Type (Cbrt_C2 * F); for J in 1 .. Cbrt_L1 loop Y := Y - (Y / Mantissa_Divisor_3 - Mantissa_Type ((F / Mantissa_Divisor_3) / Mantissa_Type (Y * Y))); end loop; case (N mod 3) is when 0 => null; when 1 => Y := Mantissa_Type (Cbrt_C3 * Y); N := N + 2; when 2 => Y := Mantissa_Type (Cbrt_C4 * Y); N := N + 1; when others => null; end case; M := N / 3; if X < Zero then Y := -Y; end if; Refloat (M, Y, Result); return Result; end if; exception when others => Result := One; if X < Zero then Result := -One; end if; New_Line; Put ("EXCEPTION IN CBRT, X = "); raise Program_Error; --Put (X); Put (" RETURNED "); raise Program_Error; --Put (Result); New_Line; return Result; end Cbrt; function Log (X : Float) return Float is -- Uses fixed formulation for generality Result : Float; N : Exponent_Type; Xn : Float; Y : Float; F : Mantissa_Type; Z, Zden, Znum : Mantissa_Type; C0 : constant Mantissa_Type := 0.20710_67811_86547_52440; -- SQRT(0.5) - 0.5 C1 : constant Float := 8#0.543#; C2 : constant Float := -2.12194_44005_46905_82767_9E-4; function R (Z : Mantissa_Type) return Mantissa_Type is -- Use fixed formulation here because the float coeficents are > 1.0 -- and would exceed the limits on a MANTISSA_TYPE A0 : constant Mantissa_Type := 0.04862_85276_587; B0 : constant Mantissa_Type := 0.69735_92187_803; B1 : constant Mantissa_Type := -0.125; C : constant Mantissa_Type := 0.01360_09546_862; begin return Z + Mantissa_Type (Z * Mantissa_Type (Mantissa_Type (Z * Z) * (C + Mantissa_Type (A0 / (B0 + Mantissa_Type (B1 * Mantissa_Type (Z * Z))))))); end R; begin if X < Zero then New_Line; Put ("CALLED LOG FOR NEGATIVE "); raise Program_Error; --put (X);; Put (" USE ABS => "); Result := Log (abs (X)); raise Program_Error; --Put (Result); New_Line; elsif X = Zero then New_Line; Put ("CALLED LOG FOR ZERO ARGUMENT, RETURNED "); Result := -Xmax; -- SUPPOSED TO BE -LARGE raise Program_Error;--Put (Result); New_Line; else Defloat (X, N, F); Znum := F - Mantissa_Half; Y := Convert_To_Float (Znum); Zden := Znum / Mantissa_Divisor_2 + Mantissa_Half; if Znum > C0 then Y := Y - Mantissa_Half; Znum := Znum - Mantissa_Half; Zden := Zden + Mantissa_Half / Mantissa_Divisor_2; else N := N - 1; end if; Z := Mantissa_Type (Znum / Zden); Result := Convert_To_Float (R (Z)); if N /= 0 then Xn := Convert_To_Float (N); Result := (Xn * C2 + Result) + Xn * C1; end if; end if; return Result; exception when others => New_Line; Put (" EXCEPTION IN LOG, X = "); raise Program_Error; --put (X);; Put (" RETURNED 0.0"); New_Line; return Zero; end Log; function Log10 (X : Float) return Float is Log_10_Of_2 : constant Float := Convert_To_Float (Mantissa_Type ( 8#0.33626_75425_11562_41615#)); begin return Log (X) * Log_10_Of_2; end Log10; function Exp (X : Float) return Float is Result : Float; N : Exponent_Type; Xg, Xn, X1, X2 : Float; F, G : Mantissa_Type; Bigx : Float := Exp_Large; Smallx : Float := Exp_Small; One_Over_Log_2 : constant Float := 1.4426_95040_88896_34074; C1 : constant Float := 0.69335_9375; C2 : constant Float := -2.1219_44400_54690_58277E-4; function R (G : Mantissa_Type) return Mantissa_Type is Z, Gp, Q : Mantissa_Type; P0 : constant Mantissa_Type := 0.24999_99999_9992; P1 : constant Mantissa_Type := 0.00595_04254_9776; Q0 : constant Mantissa_Type := 0.5; Q1 : constant Mantissa_Type := 0.05356_75176_4522; Q2 : constant Mantissa_Type := 0.00029_72936_3682; begin Z := Mantissa_Type (G * G); Gp := Mantissa_Type ((Mantissa_Type (P1 * Z) + P0) * G); Q := Mantissa_Type ((Mantissa_Type (Q2 * Z) + Q1) * Z) + Q0; return Mantissa_Half + Mantissa_Type (Gp / (Q - Gp)); end R; begin if X > Bigx then New_Line; Put (" EXP CALLED WITH TOO BIG A POSITIVE ARGUMENT, "); raise Program_Error; --put (X);; Put (" RETURNED XMAX"); New_Line; Result := Xmax; elsif X < Smallx then New_Line; Put (" EXP CALLED WITH TOO BIG A NEGATIVE ARGUMENT, "); raise Program_Error; --put (X);; Put (" RETURNED ZERO"); New_Line; Result := Zero; elsif abs (X) < Eps then Result := One; else N := Exponent_Type (X * One_Over_Log_2); Xn := Convert_To_Float (N); X1 := Round (X); X2 := X - X1; Xg := ((X1 - Xn * C1) + X2) - Xn * C2; G := Mantissa_Type (Xg); N := N + 1; F := R (G); Refloat (N, F, Result); end if; return Result; exception when others => New_Line; Put (" EXCEPTION IN EXP, X = "); raise Program_Error; --put (X);; Put (" RETURNED 1.0"); New_Line; return One; end Exp; function "**" (X, Y : Float) return Float is -- This is the last function to be coded since it appeared that it really -- was un-Ada-like and ought not be in the regular package -- Nevertheless it was included in this version -- It is specific for FLOAT and does not have the MANTISSA_TYPE generality M, N : Exponent_Type; G : Mantissa_Type; P, Temp, Iw1, I : Integer; Result, Z, V, R, U1, U2, W, W1, W2, W3, Y1, Y2 : Float; K : constant Float := 0.44269_50408_88963_40736; Ibigx : constant Integer := Integer (Truncate (16.0 * Log (Xmax) - 1.0)); Ismallx : constant Integer := Integer (Truncate (16.0 * Log (Xmin) + 1.0)); P1 : constant Float := 0.83333_32862_45E-1; P2 : constant Float := 0.12506_48500_52E-1; Q1 : constant Float := 0.69314_71805_56341; Q2 : constant Float := 0.24022_65061_44710; Q3 : constant Float := 0.55504_04881_30765E-1; Q4 : constant Float := 0.96162_06595_83789E-2; Q5 : constant Float := 0.13052_55159_42810E-2; A1 : array (1 .. 17) of Float := (8#1.00000_0000#, 8#0.75222_5750#, 8#0.72540_3067#, 8#0.70146_3367#, 8#0.65642_3746#, 8#0.63422_2140#, 8#0.61263_4520#, 8#0.57204_2434#, 8#0.55202_3631#, 8#0.53254_0767#, 8#0.51377_3265#, 8#0.47572_4623#, 8#0.46033_7602#, 8#0.44341_7233#, 8#0.42712_7017#, 8#0.41325_3033#, 8#0.40000_0000#); A2 : array (1 .. 8) of Float := (8#0.00000_00005_22220_66302_61734_72062#, 8#0.00000_00003_02522_47021_04062_61124#, 8#0.00000_00005_21760_44016_17421_53016#, 8#0.00000_00007_65401_41553_72504_02177#, 8#0.00000_00002_44124_12254_31114_01243#, 8#0.00000_00000_11064_10432_66404_42174#, 8#0.00000_00004_72542_16063_30176_55544#, 8#0.00000_00001_74611_03661_23056_22556#); function Reduce (V : Float) return Float is begin return Float (Integer (16.0 * V)) * 0.0625; end Reduce; begin if X <= Zero then if X < Zero then Result := (abs (X)) ** Y; New_Line; Put ("X**Y CALLED WITH X = "); raise Program_Error; --put (X); New_Line; Put ("USED ABS, RETURNED "); raise Program_Error;--Put (Result); New_Line; else if Y <= Zero then if Y = Zero then Result := Zero; else Result := Xmax; end if; New_Line; Put ("X**Y CALLED WITH X = 0, Y = "); raise Program_Error; --put (Y); New_Line; Put ("RETURNED "); raise Program_Error;--Put (Result); New_Line; else Result := Zero; end if; end if; else Defloat (X, M, G); P := 1; if G <= A1 (9) then P := 9; end if; if G <= A1 (P + 4) then P := P + 4; end if; if G <= A1 (P + 2) then P := P + 2; end if; Z := ((G - A1 (P + 1)) - A2 ((P + 1) / 2)) / (G + A1 (P + 1)); Z := Z + Z; V := Z * Z; R := (P2 * V + P1) * V * Z; R := R + K * R; U2 := (R + Z * K) + Z; U1 := Float (Integer (M) * 16 - P) * 0.0625; Y1 := Reduce (Y); Y2 := Y - Y1; W := U2 * Y + U1 * Y2; W1 := Reduce (W); W2 := W - W1; W := W1 + U1 * Y1; W1 := Reduce (W); W2 := W2 + (W - W1); W3 := Reduce (W2); Iw1 := Integer (Truncate (16.0 * (W1 + W3))); W2 := W2 - W3; if W > Float (Ibigx) then Result := Xmax; Put ("X**Y CALLED X ="); raise Program_Error; --put (X); Put (" Y ="); raise Program_Error; --put (Y); Put (" TOO LARGE RETURNED "); raise Program_Error;--Put (Result); New_Line; elsif W < Float (Ismallx) then Result := Zero; Put ("X**Y CALLED X ="); raise Program_Error; --put(X); Put (" Y ="); raise Program_Error; Put (" TOO SMALL RETURNED "); raise Program_Error;--Put (Result); New_Line; else if W2 > Zero then W2 := W2 - 0.0625; Iw1 := Iw1 + 1; end if; if Iw1 < Integer (Zero) then I := 0; else I := 1; end if; M := Exponent_Type (I + Iw1 / 16); P := 16 * Integer (M) - Iw1; Z := ((((Q5 * W2 + Q4) * W2 + Q3) * W2 + Q2) * W2 + Q1) * W2; Z := A1 (P + 1) + (A1 (P + 1) * Z); Refloat (M, Z, Result); end if; end if; return Result; end "**"; begin Exp_Large := Log (Xmax) * (One - Eps); Exp_Small := Log (Xmin) * (One - Eps); end Core_Functions; generic type Enumeration is (<>); procedure Enumeration_Value (S : String; Result : out Enumeration; Prefix : out Boolean; Unique : out Boolean);with String_Utilities; procedure Enumeration_Value (S : String; Result : out Enumeration; Prefix : out Boolean; Unique : out Boolean) is Already_Matched : Boolean := False; Exact : Boolean; Match : Boolean; Up_S : constant String := String_Utilities.Upper_Case (S); begin Prefix := False; Unique := False; Result := Enumeration'Last; for Enum in Enumeration loop declare Enum_Image : constant String := Enumeration'Image (Enum); begin Match := Up_S'Length <= Enum_Image'Length and then Up_S = Enum_Image (1 .. Up_S'Length); Exact := Match and then (Up_S'Length = Enum_Image'Length); end; if Exact then Result := Enum; Unique := True; Prefix := False; return; elsif Match then Unique := not Already_Matched; Already_Matched := True; Prefix := True; Result := Enum; end if; end loop; end Enumeration_Value;package Floating_Characteristics is -- This package is a floating mantissa definition of a binary FLOAT -- It was first used on the DEC-10 and the VAX but should work for any -- since the parameters are obtained by initializing on the actual hardware -- Otherwise the parameters could be set in the spec if known -- This is a preliminary package that defines the properties -- of the particular floating point type for which we are going to -- generate the math routines -- The constants are those required by the routines described in -- "Software Manual for the Elementary Functions" W. Cody & W. Waite -- Prentice-Hall 1980 -- Actually most are needed only for the test programs -- rather than the functions themselves, but might as well be here -- Most of these could be in the form of attributes if -- all the floating types to be considered were those built into the -- compiler, but we also want to be able to support user defined types -- such as software floating types of greater precision than -- the hardware affords, or types defined on one machine to -- simulate another -- So we use the Cody-Waite names and derive them from an adaptation of the -- MACHAR routine as given by Cody-Waite in Appendix B -- Ibeta : Integer; -- The radix of the floating-point representation -- It : Integer; -- The number of base IBETA digits in the DIS_FLOAT significand -- Irnd : Integer; -- TRUE (1) if floating addition rounds, FALSE (0) if truncates -- Ngrd : Integer; -- Number of guard digits for multiplication -- Machep : Integer; -- The largest negative integer such that -- 1.0 + FLOAT(IBETA) ** MACHEP /= 1.0 -- except that MACHEP is bounded below by -(IT + 3) -- Negep : Integer; -- The largest negative integer such that -- 1.0 -0 FLOAT(IBETA) ** NEGEP /= 1.0 -- except that NEGEP is bounded below by -(IT + 3) -- Iexp : Integer; -- The number of bits (decimal places if IBETA = 10) -- reserved for the representation of the exponent (including -- the bias or sign) of a floating-point number -- Minexp : Integer; -- The largest in magnitude negative integer such that -- FLOAT(IBETA) ** MINEXP is a positive floating-point number -- Maxexp : Integer; -- The largest positive exponent for a finite floating-point number -- Eps : Float; -- The smallest positive floating-point number such that -- 1.0 + EPS /= 1.0 -- In particular, if IBETA = 2 or IRND = 0, -- EPS = FLOAT(IBETA) ** MACHEP -- Otherwise, EPS = (FLOAT(IBETA) ** MACHEP) / 2 -- Epsneg : Float; -- A small positive floating-point number such that 1.0-EPSNEG /= 1.0 -- Xmin : Float; -- The smallest non-vanishing floating-point power of the radix -- In particular, XMIN = FLOAT(IBETA) ** MINEXP -- Xmax : Float; -- The largest finite floating-point number -- Here the structure of the floating type is defined -- I have assumed that the exponent is always some integer form -- The mantissa can vary -- Most often it will be a fixed type or the same floating type -- depending on the most efficient machine implementation -- Most efficient implementation may require details of the machine hardware -- In this version the simplest representation is used -- The mantissa is extracted into a FLOAT and uses the predefined operations -- subtype Exponent_Type is Integer; -- should be derived ########## subtype Mantissa_Type is Float; -- range -1.0..1.0; -- -- A consequence of the rigorous constraints on MANTISSA_TYPE is that -- operations must be very carefully examined to make sure that no number -- greater than one results -- Actually this limitation is important in constructing algorithms -- which will also run when MANTISSA_TYPE is a fixed point type -- If we are not using the STANDARD type, we have to define all the -- operations at this point -- We also need PUT for the type if it is not otherwise available -- Now we do something strange -- Since we do not know in the following routines whether the mantissa -- will be carried as a fixed or floating type, we have to make some -- provision for dividing by two -- We cannot use the literals, since FIXED/2.0 and FLOAT/2 will fail -- We define a type-dependent factor that will work -- Mantissa_Divisor_2 : constant Float := 2.0; Mantissa_Divisor_3 : constant Float := 3.0; -- -- This will work for the MANTISSA_TYPE defined above -- The alternative of defining an operation "/" to take care of it -- is too sweeping and would allow unAda-like errors -- Mantissa_Half : constant Mantissa_Type := 0.5; procedure Defloat (X : in Float; N : in out Exponent_Type; F : in out Mantissa_Type); procedure Refloat (N : in Exponent_Type; F : in Mantissa_Type; X : in out Float); -- Since the user may wish to define a floating type by some other name -- CONVERT_TO_FLOAT is used rather than just FLOAT for explicit coersion function Convert_To_Float (K : Integer) return Float; -- function CONVERT_TO_FLOAT(N : EXPONENT_TYPE) return FLOAT; function Convert_To_Float (F : Mantissa_Type) return Float; end Floating_Characteristics;with Text_Io; use Text_Io; package body Floating_Characteristics is -- This package is a floating mantissa definition of a binary FLOAT A, B, Y, Z : Float; I, K, Mx, Iz : Integer; Beta, Betam1, Betain : Float; One : Float := 1.0; Zero : Float := 0.0; procedure Defloat (X : in Float; N : in out Exponent_Type; F : in out Mantissa_Type) is -- This is admittedly a slow method - but portable - for breaking down -- a floating point number into its exponent and mantissa -- Obviously with knowledge of the machine representation -- it could be replaced with a couple of simple extractions Exponent_Length : Integer := Iexp; M : Exponent_Type; W, Y, Z : Float; begin N := 0; F := 0.0; Y := abs (X); if Y = 0.0 then return; elsif Y < 0.5 then for J in reverse 0 .. (Exponent_Length - 2) loop -- Dont want to go all the way to 2.0**(EXPONENT_LENGTH - 1) -- Since that (or its reciprocal) will overflow if exponent biased -- Ought to use talbular values rather than compute each time M := Exponent_Type (2 ** J); Z := 1.0 / (2.0 ** M); W := Y / Z; if W < 1.0 then Y := W; N := N - M; end if; end loop; else for J in reverse 0 .. (Exponent_Length - 2) loop M := Exponent_Type (2 ** J); Z := 2.0 ** M; W := Y / Z; if W >= 0.5 then Y := W; N := N + M; end if; end loop; -- And just to clear up any loose ends from biased exponents end if; while Y < 0.5 loop Y := Y * 2.0; N := N - 1; end loop; while Y >= 1.0 loop Y := Y / 2.0; N := N + 1; end loop; F := Mantissa_Type (Y); if X < 0.0 then F := -F; end if; return; exception when others => N := 0; F := 0.0; return; end Defloat; procedure Refloat (N : in Exponent_Type; F : in Mantissa_Type; X : in out Float) is -- Again a brute force method - but portable -- Watch out near MAXEXP M : Integer; Y : Float; begin if F = 0.0 then X := Zero; return; end if; M := Integer (N); Y := abs (Float (F)); while Y < 0.5 loop M := M - 1; if M < Minexp then X := Zero; end if; Y := Y + Y; exit when M <= Minexp; end loop; if M = Maxexp then M := M - 1; X := Y * 2.0 ** M; X := X * 2.0; elsif M <= Minexp + 2 then M := M + 3; X := Y * 2.0 ** M; X := ((X / 2.0) / 2.0) / 2.0; else X := Y * 2.0 ** M; end if; if F < 0.0 then X := -X; end if; return; end Refloat; function Convert_To_Float (K : Integer) return Float is begin return Float (K); end Convert_To_Float; -- function CONVERT_TO_FLOAT(N : EXPONENT_TYPE) RETURN FLOAT is -- begin -- RETURN FLOAT(N); -- end CONVERT_TO_FLOAT; function Convert_To_Float (F : Mantissa_Type) return Float is begin return Float (F); end Convert_To_Float; -- begin -- Initialization for the VAX with values derived by MACHAR -- In place of running MACHAR as the actual initialization Ibeta := 2; It := 24; Irnd := 1; Negep := -24; Epsneg := 5.9604644E-008; Machep := -24; Eps := 5.9604644E-008; Ngrd := 0; Xmin := 5.9E-39; Minexp := -126; Iexp := 8; Maxexp := 127; Xmax := 8.5E37 * 2.0; ---- This initialization is the MACHAR routine of Cody and Waite Appendix B. --PUT("INITIALIZATING WITH MACHAR - "); -- A := ONE; -- while (((A + ONE) - A) - ONE) = ZERO loop -- A := A + A; -- end loop; -- B := ONE; -- while ((A + B) - A) = ZERO loop -- B := B + B; -- end loop; -- IBETA := INTEGER((A + B) - A); -- BETA := CONVERT_TO_FLOAT(IBETA); -- -- -- IT := 0; -- B := ONE; -- while (((B + ONE) - B) - ONE) = ZERO loop -- IT := IT + 1; -- B := B * BETA; -- end loop; -- -- -- IRND := 0; -- BETAM1 := BETA - ONE; -- if ((A + BETAM1) - A) /= ZERO then -- IRND := 1; -- end if; -- -- -- NEGEP := IT + 3; -- BETAIN := ONE / BETA; -- A := ONE; -- -- for I in 1..NEGEP loop -- for I in 1..50 loop -- exit when I > NEGEP; -- A := A * BETAIN; -- end loop; -- B := A; -- while ((ONE - A) - ONE) = ZERO loop -- A := A * BETA; -- NEGEP := NEGEP - 1; -- end loop; -- NEGEP := -NEGEP; -- -- -- EPSNEG := A; -- if (IBETA /= 2) and (IRND /= 0) then -- A := (A * (ONE + A)) / (ONE + ONE); -- if ((ONE - A) - ONE) /= ZERO then -- EPSNEG := A; -- end if; -- end if; -- -- -- MACHEP := -IT - 3; -- A := B; -- while ((ONE + A) - ONE) = ZERO loop -- A := A * BETA; -- MACHEP := MACHEP + 1; -- end loop; -- -- -- EPS := A; -- if (IBETA /= 2) and (IRND /= 0) then -- A := (A * (ONE + A)) / (ONE + ONE); -- if ((ONE + A) - ONE) /= ZERO then -- EPS := A; -- end if; -- end if; -- -- -- NGRD := 0; -- if ((IRND = 0) and ((ONE + EPS) * ONE - ONE) /= ZERO) then -- NGRD := 1; -- end if; -- -- -- I := 0; -- K := 1; -- Z := BETAIN; -- loop -- Y := Z; -- Z := Y * Y; -- A := Z * ONE; -- exit when ((A + A) = ZERO) or (ABS(Z) >= Y); -- I := I + 1; -- K := K + K; -- end loop; -- if (IBETA /= 10) then -- IEXP := I + 1; -- MX := K + K; -- else -- IEXP := 2; -- IZ := IBETA; -- while (K >= IZ) loop -- IZ := IZ * IBETA; -- IEXP := IEXP + 1; -- end loop; -- MX := IZ + IZ - 1; -- end if; -- -- loop -- XMIN := Y; -- Y := Y * BETAIN; -- A := Y * ONE; -- exit when ((A + A) = ZERO) or (ABS(Y) >= XMIN); -- K := K + 1; -- end loop; -- -- -- MINEXP := -K; -- -- -- if ((MX <= (K + K - 3)) and (IBETA /= 10)) then -- MX := MX + MX; -- IEXP := IEXP + 1; -- end if; -- -- -- MAXEXP := MX + MINEXP; -- I := MAXEXP + MINEXP; -- if ((IBETA = 2) and (I = 0)) then -- MAXEXP := MAXEXP - 1; -- end if; -- if (I > 20) then -- MAXEXP := MAXEXP - 1; -- end if; -- if (A /= Y) then -- MAXEXP := MAXEXP - 2; -- end if; -- -- -- XMAX := ONE - EPSNEG; -- if ((XMAX * ONE) /= XMAX) then -- XMAX := ONE - BETA * EPSNEG; -- end if; -- XMAX := XMAX / (BETA * BETA * BETA * XMIN); -- I := MAXEXP + MINEXP + 3; -- if I > 0 then -- for J in 1..50 loop -- exit when J > I; -- if IBETA = 2 then -- XMAX := XMAX + XMAX; -- else -- XMAX := XMAX * BETA; -- end if; -- end loop; -- end if; -- --PUT("INITIALIZED"); NEW_LINE; end Floating_Characteristics; generic type Element is private; -- must be a pure value -- ie. no initialization or finalization is necessary -- = and := are equality and copy pragma Must_Be_Constrained (Yes => Element); package List_Generic is type List is private; -- may generate garbage -- = and := operate on references -- "make" constructs lists with structural sharing -- constraint error is raised when nil i provided to any of -- first, rest, set_first, or set_rest function Make (X : Element; L : List) return List; function Nil return List; function Is_Empty (L : List) return Boolean; procedure Free (L : in out List); -- make L empty function First (L : List) return Element; function Rest (L : List) return List; procedure Set_Rest (L : List; To_Be : List); procedure Set_First (L : List; To_Be : Element); function Length (L : List) return Natural; type Iterator is limited private; procedure Init (Iter : out Iterator; L : List); procedure Next (Iter : in out Iterator); function Value (Iter : Iterator) return Element; function Done (Iter : Iterator) return Boolean; private type Listdata; type List is access Listdata; -- variables of type list are initialized to null type Listdata is record First : Element; Rest : List; end record; type Iterator is new List; end List_Generic;package body List_Generic is function Nil return List is begin return null; end Nil; function Is_Empty (L : List) return Boolean is begin return L = Nil; end Is_Empty; function First (L : List) return Element is begin return L.First; end First; function Rest (L : List) return List is begin return L.Rest; end Rest; function Make (X : Element; L : List) return List is begin return new Listdata'(X, L); end Make; procedure Set_Rest (L : List; To_Be : List) is begin L.Rest := To_Be; end Set_Rest; procedure Set_First (L : List; To_Be : Element) is begin L.First := To_Be; end Set_First; procedure Free (L : in out List) is begin L := null; end Free; function Length (L : List) return Natural is Count : Natural := 0; Iter : Iterator; begin Init (Iter, L); while not Done (Iter) loop Count := Count + 1; Next (Iter); end loop; return Count; end Length; procedure Init (Iter : out Iterator; L : List) is begin Iter := Iterator (L); end Init; procedure Next (Iter : in out Iterator) is begin Iter := Iterator (Iter.Rest); end Next; function Value (Iter : Iterator) return Element is begin return Iter.First; end Value; function Done (Iter : Iterator) return Boolean is begin return Iter = null; end Done; end List_Generic;package Machine_Independent_Integer32 is -- -- This package provides integer operations for signed integers that fit -- comfortable into 32 bits. -- This spec is "kludged" in that it assumes there is an existing -- integer or fixed type that will support 32 bit integer operations. -- -- Current minimal implementation is provided to support the functionality -- required by the Time_Utilities package. -- type Integer32 is range Integer'First .. Integer'Last; function "*" (L : Integer32; R : Integer) return Integer32; function "/" (L : Integer32; R : Integer) return Integer32; procedure Div_Rem (L : Integer32; R : Integer; Quotient, Remainder : out Integer32); end Machine_Independent_Integer32;package body Machine_Independent_Integer32 is function "*" (L : Integer32; R : Integer) return Integer32 is begin return L * Integer32 (R); end "*"; function "/" (L : Integer32; R : Integer) return Integer32 is begin return L / Integer32 (R); end "/"; procedure Div_Rem (L : Integer32; R : Integer; Quotient, Remainder : out Integer32) is Local_Quotient : Integer32 := L / R; begin Quotient := Local_Quotient; Remainder := L - Local_Quotient * R; end Div_Rem; end Machine_Independent_Integer32;generic Size : Integer; -- number of buckets type Domain_Type is private; type Range_Type is private; -- both types are pure values -- no initialization or finalization of values of either -- domain_type or range_type is necessary -- = and := can be used for equality and copy with function Hash (Key : Domain_Type) return Integer is <>; -- efficiency => spread hash over an interval at least as great as size pragma Must_Be_Constrained (Yes => Domain_Type, Range_Type); package Map_Generic is type Map is private; type Pair is record D : Domain_Type; R : Range_Type; end record; function Eval (The_Map : Map; D : Domain_Type) return Range_Type; procedure Find (The_Map : Map; D : Domain_Type; R : in out Range_Type; Success : out Boolean); procedure Find (The_Map : Map; D : Domain_Type; P : in out Pair; Success : out Boolean); procedure Define (The_Map : in out Map; D : Domain_Type; R : Range_Type; Trap_Multiples : Boolean := False); procedure Undefine (The_Map : in out Map; D : Domain_Type); procedure Initialize (The_Map : out Map); function Is_Empty (The_Map : Map) return Boolean; procedure Make_Empty (The_Map : in out Map); procedure Copy (Target : in out Map; Source : Map); type Iterator is limited private; procedure Init (Iter : out Iterator; The_Map : Map); procedure Next (Iter : in out Iterator); function Value (Iter : Iterator) return Domain_Type; function Done (Iter : Iterator) return Boolean; Undefined : exception; -- raised by eval if the domain value in not in the map Multiply_Defined : exception; -- raised by define if the domain value is already defined and -- the trap_multiples flag has been specified (ie. is true) function Cardinality (The_Map : Map) return Natural; function Nil return Map; function Is_Nil (The_Map : Map) return Boolean; ------------------------------------------------------ -- Implementation Notes and Non-Standard Operations -- ------------------------------------------------------ -- := and = operate on references -- := implies sharing (introduces an alias) -- = means is the same set, not the same value of type set -- Initializing a map also makes it empty -- Accessing an uninitialized map will raise CONSTRAINT_ERROR. -- garbage may be generated -- Concurrent Properties -- any number of find/eval/is_empty may be safely done while one -- define/undefine is taking place. If the define is redefining -- an -- existing element in the domain of the map, concurrrent -- reading is -- safe if and only if := on range_type is atomic. private type Node; type Set is access Node; type Node is record Value : Pair; Link : Set; end record; subtype Index is Integer range 0 .. Size - 1; type Table is array (Index) of Set; type Map_Data is record Bucket : Table; Size : Integer := 0; end record; type Map is access Map_Data; type Iterator is record The_Map : Map; Index_Value : Index; Set_Iter : Set; Done : Boolean; end record; end Map_Generic;package body Map_Generic is function Find (S : Set; D : Domain_Type) return Set is Rest : Set := S; begin while Rest /= null loop if Rest.Value.D = D then return Rest; end if; Rest := Rest.Link; end loop; return null; end Find; function Myhash (D : Domain_Type) return Index is begin return Index (Hash (D) mod Size); end Myhash; function Eval (The_Map : Map; D : Domain_Type) return Range_Type is Ptr : Set := Find (The_Map.Bucket (Myhash (D)), D); begin if Ptr /= null then return Ptr.Value.R; else raise Undefined; end if; end Eval; procedure Find (The_Map : Map; D : Domain_Type; R : in out Range_Type; Success : out Boolean) is Ptr : Set := Find (The_Map.Bucket (Myhash (D)), D); begin if Ptr /= null then R := Ptr.Value.R; Success := True; else Success := False; end if; end Find; procedure Find (The_Map : Map; D : Domain_Type; P : in out Pair; Success : out Boolean) is Ptr : Set := Find (The_Map.Bucket (Myhash (D)), D); begin if Ptr /= null then P := Ptr.Value; Success := True; else Success := False; end if; end Find; procedure Define (The_Map : in out Map; D : Domain_Type; R : Range_Type; Trap_Multiples : Boolean := False) is The_Set : Set renames The_Map.Bucket (Myhash (D)); Ptr : Set := Find (The_Set, D); Success : Boolean; begin if Ptr = null then The_Set := new Node'(Pair'(D => D, R => R), The_Set); The_Map.Size := The_Map.Size + 1; elsif Trap_Multiples then raise Multiply_Defined; else Ptr.Value.R := R; end if; end Define; procedure Undefine (The_Map : in out Map; D : Domain_Type) is Start : Set renames The_Map.Bucket (Myhash (D)); Current : Set := Start; Previous : Set := null; begin while Current /= null loop if Current.Value.D = D then if Previous /= null then Previous.Link := Current.Link; else Start := Current.Link; end if; The_Map.Size := The_Map.Size - 1; return; else Previous := Current; Current := Current.Link; end if; end loop; raise Undefined; end Undefine; procedure Copy (Target : in out Map; Source : Map) is procedure Copy_Set (Target : in out Set; Source : Set) is Rest : Set := Source; begin Target := null; while Rest /= null loop Target := new Node'(Rest.Value, Target); Rest := Rest.Link; end loop; end Copy_Set; begin for I in Index loop Copy_Set (Target => Target.Bucket (I), Source => Source.Bucket (I)); end loop; Target.Size := Source.Size; end Copy; procedure Initialize (The_Map : out Map) is begin The_Map := new Map_Data; end Initialize; function Is_Empty (The_Map : Map) return Boolean is Iter : Iterator; begin for I in Index loop if The_Map.Bucket (I) /= null then return False; end if; end loop; return True; end Is_Empty; procedure Make_Empty (The_Map : in out Map) is begin for I in Index loop The_Map.Bucket (I) := null; end loop; end Make_Empty; procedure Init (Iter : out Iterator; The_Map : Map) is The_Iter : Iterator; begin for I in Index loop The_Iter.Set_Iter := The_Map.Bucket (I); if The_Iter.Set_Iter /= null then The_Iter.Done := False; The_Iter.Index_Value := I; The_Iter.The_Map := The_Map; Iter := The_Iter; return; end if; end loop; The_Iter.Done := True; Iter := The_Iter; end Init; procedure Next (Iter : in out Iterator) is begin Iter.Set_Iter := Iter.Set_Iter.Link; while Iter.Set_Iter = null loop if Iter.Index_Value = Index'Last then Iter.Done := True; return; end if; Iter.Index_Value := Iter.Index_Value + 1; Iter.Set_Iter := Iter.The_Map.Bucket (Iter.Index_Value); end loop; end Next; function Value (Iter : Iterator) return Domain_Type is begin return Iter.Set_Iter.Value.D; end Value; function Done (Iter : Iterator) return Boolean is begin return Iter.Done; end Done; function Cardinality (The_Map : Map) return Natural is begin return The_Map.Size; end Cardinality; function Nil return Map is begin return null; end Nil; function Is_Nil (The_Map : Map) return Boolean is begin return The_Map = null; end Is_Nil; end Map_Generic;with Floating_Characteristics; use Floating_Characteristics; package Numeric_Io is Exp_Large : Float; Exp_Small : Float; function Sqrt (X : Float) return Float; function Cbrt (X : Float) return Float; function Log (X : Float) return Float; function Log10 (X : Float) return Float; function Exp (X : Float) return Float; function "**" (X, Y : Float) return Float; end Numeric_Io;with Text_Io; use Text_Io; with Floating_Characteristics; use Floating_Characteristics; --with Numeric_Io; --use Numeric_Io; with Numeric_Primitives; use Numeric_Primitives; package body Numeric_Io is -- The following routines are coded directly from the algorithms and -- coeficients given in "Software Manual for the Elementry Functions" -- by William J. Cody, Jr. and William Waite, Prentice_Hall, 1980 -- CBRT by analogy -- A more general formulation uses MANTISSA_TYPE, etc. -- The coeficients are appropriate for 25 to 32 bits floating significance -- They will work for less but slightly shorter versions are possible -- The routines are coded to stand alone so they need not be compiled together -- These routines have been coded to accept a general MANTISSA_TYPE -- That is, they are designed to work with a manitssa either fixed of float -- There are some explicit conversions which are required but these will -- not cause any extra code to be generated -- 16 JULY 1982 W A WHITAKER AFATL EGLIN AFB FL 32542 -- T C EICHOLTZ USAFA function Sqrt (X : Float) return Float is M, N : Exponent_Type; F, Y : Mantissa_Type; Result : Float; subtype Index is Integer range 0 .. 100; -- ######################### Sqrt_L1 : Index := 3; -- Could get away with SQRT_L1 := 2 for 28 bits -- Using the better Cody-Waite coeficients overflows MANTISSA_TYPE Sqrt_C1 : Mantissa_Type := 8#0.3317777777#; Sqrt_C2 : Mantissa_Type := 8#0.4460000000#; Sqrt_C3 : Mantissa_Type := 8#0.55202_36314_77747_36311_0#; begin if X = Zero then Result := Zero; return Result; elsif X = One then -- To get exact SQRT(1.0) Result := One; return Result; elsif X < Zero then New_Line; Put ("CALLED SQRT FOR NEGATIVE ARGUMENT "); raise Program_Error; --Put (X); Put (" USED ABSOLUTE VALUE"); New_Line; Result := Sqrt (abs (X)); return Result; else Defloat (X, N, F); Y := Sqrt_C1 + Mantissa_Type (Sqrt_C2 * F); for J in 1 .. Sqrt_L1 loop Y := Y / Mantissa_Divisor_2 + Mantissa_Type ((F / Mantissa_Divisor_2) / Y); end loop; if (N mod 2) /= 0 then Y := Mantissa_Type (Sqrt_C3 * Y); N := N + 1; end if; M := N / 2; Refloat (M, Y, Result); return Result; end if; exception when others => New_Line; Put (" EXCEPTION IN SQRT, X = "); raise Program_Error --Put (X); ; Put (" RETURNED 1.0"); New_Line; return One; end Sqrt; function Cbrt (X : Float) return Float is M, N : Exponent_Type; F, Y : Mantissa_Type; Result : Float; subtype Index is Integer range 0 .. 100; -- ######################### Cbrt_L1 : Index := 3; Cbrt_C1 : Mantissa_Type := 0.5874009; Cbrt_C2 : Mantissa_Type := 0.4125990; Cbrt_C3 : Mantissa_Type := 0.62996_05249; Cbrt_C4 : Mantissa_Type := 0.79370_05260; begin if X = Zero then Result := Zero; return Result; else Defloat (X, N, F); F := abs (F); Y := Cbrt_C1 + Mantissa_Type (Cbrt_C2 * F); for J in 1 .. Cbrt_L1 loop Y := Y - (Y / Mantissa_Divisor_3 - Mantissa_Type ((F / Mantissa_Divisor_3) / Mantissa_Type (Y * Y))); end loop; case (N mod 3) is when 0 => null; when 1 => Y := Mantissa_Type (Cbrt_C3 * Y); N := N + 2; when 2 => Y := Mantissa_Type (Cbrt_C4 * Y); N := N + 1; when others => null; end case; M := N / 3; if X < Zero then Y := -Y; end if; Refloat (M, Y, Result); return Result; end if; exception when others => Result := One; if X < Zero then Result := -One; end if; New_Line; Put ("EXCEPTION IN CBRT, X = "); raise Program_Error --Put (X); ; Put (" RETURNED "); raise Program_Error --Put (Result); ; New_Line; return Result; end Cbrt; function Log (X : Float) return Float is -- Uses fixed formulation for generality Result : Float; N : Exponent_Type; Xn : Float; Y : Float; F : Mantissa_Type; Z, Zden, Znum : Mantissa_Type; C0 : constant Mantissa_Type := 0.20710_67811_86547_52440; -- SQRT(0.5) - 0.5 C1 : constant Float := 8#0.543#; C2 : constant Float := -2.12194_44005_46905_82767_9E-4; function R (Z : Mantissa_Type) return Mantissa_Type is -- Use fixed formulation here because the float coeficents are > 1.0 -- and would exceed the limits on a MANTISSA_TYPE A0 : constant Mantissa_Type := 0.04862_85276_587; B0 : constant Mantissa_Type := 0.69735_92187_803; B1 : constant Mantissa_Type := -0.125; C : constant Mantissa_Type := 0.01360_09546_862; begin return Z + Mantissa_Type (Z * Mantissa_Type (Mantissa_Type (Z * Z) * (C + Mantissa_Type (A0 / (B0 + Mantissa_Type (B1 * Mantissa_Type (Z * Z))))))); end R; begin if X < Zero then New_Line; Put ("CALLED LOG FOR NEGATIVE "); raise Program_Error --Put (X); ; Put (" USE ABS => "); Result := Log (abs (X)); raise Program_Error --Put (Result); ; New_Line; elsif X = Zero then New_Line; Put ("CALLED LOG FOR ZERO ARGUMENT, RETURNED "); Result := -Xmax; -- SUPPOSED TO BE -LARGE raise Program_Error --Put (Result); ; New_Line; else Defloat (X, N, F); Znum := F - Mantissa_Half; Y := Convert_To_Float (Znum); Zden := Znum / Mantissa_Divisor_2 + Mantissa_Half; if Znum > C0 then Y := Y - Mantissa_Half; Znum := Znum - Mantissa_Half; Zden := Zden + Mantissa_Half / Mantissa_Divisor_2; else N := N - 1; end if; Z := Mantissa_Type (Znum / Zden); Result := Convert_To_Float (R (Z)); if N /= 0 then Xn := Convert_To_Float (N); Result := (Xn * C2 + Result) + Xn * C1; end if; end if; return Result; exception when others => New_Line; Put (" EXCEPTION IN LOG, X = "); raise Program_Error; --Put (X); Put (" RETURNED 0.0"); New_Line; return Zero; end Log; function Log10 (X : Float) return Float is Log_10_Of_2 : constant Float := Convert_To_Float (Mantissa_Type ( 8#0.33626_75425_11562_41615#)); begin return Log (X) * Log_10_Of_2; end Log10; function Exp (X : Float) return Float is Result : Float; N : Exponent_Type; Xg, Xn, X1, X2 : Float; F, G : Mantissa_Type; Bigx : Float := Exp_Large; Smallx : Float := Exp_Small; One_Over_Log_2 : constant Float := 1.4426_95040_88896_34074; C1 : constant Float := 0.69335_9375; C2 : constant Float := -2.1219_44400_54690_58277E-4; function R (G : Mantissa_Type) return Mantissa_Type is Z, Gp, Q : Mantissa_Type; P0 : constant Mantissa_Type := 0.24999_99999_9992; P1 : constant Mantissa_Type := 0.00595_04254_9776; Q0 : constant Mantissa_Type := 0.5; Q1 : constant Mantissa_Type := 0.05356_75176_4522; Q2 : constant Mantissa_Type := 0.00029_72936_3682; begin Z := Mantissa_Type (G * G); Gp := Mantissa_Type ((Mantissa_Type (P1 * Z) + P0) * G); Q := Mantissa_Type ((Mantissa_Type (Q2 * Z) + Q1) * Z) + Q0; return Mantissa_Half + Mantissa_Type (Gp / (Q - Gp)); end R; begin if X > Bigx then New_Line; Put (" EXP CALLED WITH TOO BIG A POSITIVE ARGUMENT, "); raise Program_Error --Put (X); ; Put (" RETURNED XMAX"); New_Line; Result := Xmax; elsif X < Smallx then New_Line; Put (" EXP CALLED WITH TOO BIG A NEGATIVE ARGUMENT, "); raise Program_Error; --Put (X); Put (" RETURNED ZERO"); New_Line; Result := Zero; elsif abs (X) < Eps then Result := One; else N := Exponent_Type (X * One_Over_Log_2); Xn := Convert_To_Float (N); X1 := Round (X); X2 := X - X1; Xg := ((X1 - Xn * C1) + X2) - Xn * C2; G := Mantissa_Type (Xg); N := N + 1; F := R (G); Refloat (N, F, Result); end if; return Result; exception when others => New_Line; Put (" EXCEPTION IN EXP, X = "); raise Program_Error; --Put (X); Put (" RETURNED 1.0"); New_Line; return One; end Exp; function "**" (X, Y : Float) return Float is -- This is the last function to be coded since it appeared that it really -- was un-Ada-like and ought not be in the regular package -- Nevertheless it was included in this version -- It is specific for FLOAT and does not have the MANTISSA_TYPE generality M, N : Exponent_Type; G : Mantissa_Type; P, Temp, Iw1, I : Integer; Result, Z, V, R, U1, U2, W, W1, W2, W3, Y1, Y2 : Float; K : constant Float := 0.44269_50408_88963_40736; Ibigx : constant Integer := Integer (Truncate (16.0 * Log (Xmax) - 1.0)); Ismallx : constant Integer := Integer (Truncate (16.0 * Log (Xmin) + 1.0)); P1 : constant Float := 0.83333_32862_45E-1; P2 : constant Float := 0.12506_48500_52E-1; Q1 : constant Float := 0.69314_71805_56341; Q2 : constant Float := 0.24022_65061_44710; Q3 : constant Float := 0.55504_04881_30765E-1; Q4 : constant Float := 0.96162_06595_83789E-2; Q5 : constant Float := 0.13052_55159_42810E-2; A1 : array (1 .. 17) of Float := (8#1.00000_0000#, 8#0.75222_5750#, 8#0.72540_3067#, 8#0.70146_3367#, 8#0.65642_3746#, 8#0.63422_2140#, 8#0.61263_4520#, 8#0.57204_2434#, 8#0.55202_3631#, 8#0.53254_0767#, 8#0.51377_3265#, 8#0.47572_4623#, 8#0.46033_7602#, 8#0.44341_7233#, 8#0.42712_7017#, 8#0.41325_3033#, 8#0.40000_0000#); A2 : array (1 .. 8) of Float := (8#0.00000_00005_22220_66302_61734_72062#, 8#0.00000_00003_02522_47021_04062_61124#, 8#0.00000_00005_21760_44016_17421_53016#, 8#0.00000_00007_65401_41553_72504_02177#, 8#0.00000_00002_44124_12254_31114_01243#, 8#0.00000_00000_11064_10432_66404_42174#, 8#0.00000_00004_72542_16063_30176_55544#, 8#0.00000_00001_74611_03661_23056_22556#); function Reduce (V : Float) return Float is begin return Float (Integer (16.0 * V)) * 0.0625; end Reduce; begin if X <= Zero then if X < Zero then Result := (abs (X)) ** Y; New_Line; Put ("X**Y CALLED WITH X = "); raise Program_Error; --Put (X); New_Line; Put ("USED ABS, RETURNED "); raise Program_Error --Put (Result); ; New_Line; else if Y <= Zero then if Y = Zero then Result := Zero; else Result := Xmax; end if; New_Line; Put ("X**Y CALLED WITH X = 0, Y = "); raise Program_Error; --Put (Y); New_Line; Put ("RETURNED "); raise Program_Error --Put (Result); ; New_Line; else Result := Zero; end if; end if; else Defloat (X, M, G); P := 1; if G <= A1 (9) then P := 9; end if; if G <= A1 (P + 4) then P := P + 4; end if; if G <= A1 (P + 2) then P := P + 2; end if; Z := ((G - A1 (P + 1)) - A2 ((P + 1) / 2)) / (G + A1 (P + 1)); Z := Z + Z; V := Z * Z; R := (P2 * V + P1) * V * Z; R := R + K * R; U2 := (R + Z * K) + Z; U1 := Float (Integer (M) * 16 - P) * 0.0625; Y1 := Reduce (Y); Y2 := Y - Y1; W := U2 * Y + U1 * Y2; W1 := Reduce (W); W2 := W - W1; W := W1 + U1 * Y1; W1 := Reduce (W); W2 := W2 + (W - W1); W3 := Reduce (W2); Iw1 := Integer (Truncate (16.0 * (W1 + W3))); W2 := W2 - W3; if W > Float (Ibigx) then Result := Xmax; Put ("X**Y CALLED X ="); raise Program_Error; --Put (X); Put (" Y ="); raise Program_Error --Put (Y); ; Put (" TOO LARGE RETURNED "); raise Program_Error; --Put (Result); New_Line; elsif W < Float (Ismallx) then Result := Zero; Put ("X**Y CALLED X ="); raise Program_Error; --Put (X); Put (" Y ="); raise Program_Error --Put (Y); ; Put (" TOO SMALL RETURNED "); raise Program_Error --Put (Result); ; New_Line; else if W2 > Zero then W2 := W2 - 0.0625; Iw1 := Iw1 + 1; end if; if Iw1 < Integer (Zero) then I := 0; else I := 1; end if; M := Exponent_Type (I + Iw1 / 16); P := 16 * Integer (M) - Iw1; Z := ((((Q5 * W2 + Q4) * W2 + Q3) * W2 + Q2) * W2 + Q1) * W2; Z := A1 (P + 1) + (A1 (P + 1) * Z); Refloat (M, Z, Result); end if; end if; return Result; end "**"; begin Exp_Large := Log (Xmax) * (One - Eps); Exp_Small := Log (Xmin) * (One - Eps); end Numeric_Io; with Floating_Characteristics; use Floating_Characteristics; package Numeric_Primitives is -- This may seem a little much but is put in this form to allow the -- same form to be used for a generic package -- If that is not needed, simple litterals could be substituted Zero : Float := Convert_To_Float (Integer (0)); One : Float := Convert_To_Float (Integer (1)); Two : Float := One + One; Three : Float := One + One + One; Half : Float := One / Two; -- The following "constants" are effectively deferred to -- the initialization part of the package body -- This is in order to make it possible to generalize the floating type -- If that capability is not desired, constants may be included here Pi : Float; One_Over_Pi : Float; Two_Over_Pi : Float; Pi_Over_Two : Float; Pi_Over_Three : Float; Pi_Over_Four : Float; Pi_Over_Six : Float; function Sign (X, Y : Float) return Float; -- Returns the value of X with the sign of Y function Max (X, Y : Float) return Float; -- Returns the algebraicly larger of X and Y function Min (X, Y : Float) return Float; -- Returns the algebraicly smaller of X and Y function Truncate (X : Float) return Float; -- Returns the floating value of the integer no larger than X -- AINT(X) function Round (X : Float) return Float; -- Returns the floating value nearest X -- AINTRND(X) function Ran return Float; -- This uses a portable algorithm and is included at this point -- Algorithms that presume unique machine hardware information -- should be initiated in FLOATING_CHARACTERISTICS end Numeric_Primitives;with Floating_Characteristics; use Floating_Characteristics; package body Numeric_Primitives is function Sign (X, Y : Float) return Float is -- Returns the value of X with the sign of Y begin if Y >= 0.0 then return X; else return -X; end if; end Sign; function Max (X, Y : Float) return Float is begin if X >= Y then return X; else return Y; end if; end Max; function Min (X, Y : Float) return Float is begin if X <= Y then return X; else return Y; end if; end Min; function Truncate (X : Float) return Float is -- Optimum code depends on how the system rounds at exact halves begin if Float (Integer (X)) = X then return X; end if; if X > Zero then return Float (Integer (X - Half)); elsif X = Zero then return Zero; else return Float (Integer (X + Half)); end if; end Truncate; function Round (X : Float) return Float is begin return Float (Integer (X)); end Round; package Key is X : Integer := 10_001; Y : Integer := 20_001; Z : Integer := 30_001; end Key; function Ran return Float is -- This rectangular random number routine is adapted from a report -- "A Pseudo-Random Number Generator" by B. A. Wichmann and I. D. Hill -- NPL Report DNACS XX (to be published) -- In this stripped version, it is suitable for machines supporting -- INTEGER at only 16 bits and is portable in Ada W : Float; begin Key.X := 171 * (Key.X mod 177 - 177) - 2 * (Key.X / 177); if Key.X < 0 then Key.X := Key.X + 30269; end if; Key.Y := 172 * (Key.Y mod 176 - 176) - 35 * (Key.Y / 176); if Key.Y < 0 then Key.Y := Key.Y + 30307; end if; Key.Z := 170 * (Key.Z mod 178 - 178) - 63 * (Key.Z / 178); if Key.Z < 0 then Key.Z := Key.Z + 30323; end if; -- CONVERT_TO_FLOAT is used instead of FLOAT since the floating -- type may be software defined W := Convert_To_Float (Key.X) / 30269.0 + Convert_To_Float (Key.Y) / 30307.0 + Convert_To_Float (Key.Z) / 30323.0; return W - Convert_To_Float (Integer (W - 0.5)); end Ran; begin Pi := Convert_To_Float (Integer (3)) + Convert_To_Float (Mantissa_Type (0.14159_26535_89793_23846)); One_Over_Pi := Convert_To_Float (Mantissa_Type (0.31830_98861_83790_67154)); Two_Over_Pi := Convert_To_Float (Mantissa_Type (0.63661_97723_67581_34308)); Pi_Over_Two := Convert_To_Float (Integer (1)) + Convert_To_Float (Mantissa_Type ( 0.57079_63267_94896_61923)); Pi_Over_Three := Convert_To_Float (Integer (1)) + Convert_To_Float (Mantissa_Type (0.04719_75511_96597_74615)); Pi_Over_Four := Convert_To_Float (Mantissa_Type (0.78539_81633_97448_30962)); Pi_Over_Six := Convert_To_Float (Mantissa_Type (0.52359_87755_98298_87308)); end Numeric_Primitives; generic type Element is private; pragma Must_Be_Constrained (Yes => Element); package Queue_Generic is type Queue is private; procedure Initialize (Q : out Queue); function Is_Empty (Q : Queue) return Boolean; procedure Make_Empty (Q : in out Queue); procedure Copy (Target : in out Queue; Source : Queue); procedure Add (Q : in out Queue; X : Element); procedure Delete (Q : in out Queue); function First (Q : Queue) return Element; -- on calls to delete and first, not is_empty(q) is assumed -- constraint error will be raises is is_empty(q) type Iterator is limited private; procedure Init (Iter : out Iterator; Q : Queue); procedure Next (Iter : in out Iterator); function Value (Iter : Iterator) return Element; function Done (Iter : Iterator) return Boolean; ------------------------------------------------------ -- Implementation Notes and Non-Standard Operations -- ------------------------------------------------------ -- variables of type queue are initially empty -- therefore, the call to initialize is optional -- := and = are meaningless -- := implies sharing (introduces an alias) for sub-structures -- garbage may be generated private type Node; type Pointer is access Node; type Node is record Value : Element; Link : Pointer; end record; type Queue is record Head : Pointer; Tail : Pointer; end record; type Iterator is new Queue; end Queue_Generic;package body Queue_Generic is procedure Initialize (Q : out Queue) is begin null; end Initialize; function Is_Empty (Q : Queue) return Boolean is begin return Q.Head = null; end Is_Empty; procedure Make_Empty (Q : in out Queue) is begin Q.Head := null; Q.Tail := null; end Make_Empty; procedure Init (Iter : out Iterator; Q : Queue) is begin Iter := Iterator (Q); end Init; procedure Next (Iter : in out Iterator) is begin Iter.Head := Iter.Head.Link; end Next; function Value (Iter : Iterator) return Element is begin return Iter.Head.Value; end Value; function Done (Iter : Iterator) return Boolean is begin return Iter.Head = null; end Done; procedure Copy (Target : in out Queue; Source : Queue) is Iter : Iterator; begin Make_Empty (Target); Init (Iter, Source); while not Done (Iter) loop Add (Target, Value (Iter)); Next (Iter); end loop; end Copy; procedure Add (Q : in out Queue; X : Element) is New_Node : constant Pointer := new Node'(X, null); begin if Q.Head = null then Q.Head := New_Node; else Q.Tail.Link := New_Node; end if; Q.Tail := New_Node; end Add; procedure Delete (Q : in out Queue) is First : constant Pointer := Q.Head; begin Q.Head := First.Link; First.Link := null; if Q.Head = null then Q.Tail := null; end if; end Delete; function First (Q : Queue) return Element is begin return Q.Head.Value; end First; end Queue_Generic;generic type Element is private; -- must be a pure value -- ie. no initialization or finalization is necessary -- = and := are equality and copy pragma Must_Be_Constrained (Yes => Element); package Set_Generic is type Set is private; procedure Initialize (S : out Set); function Is_Empty (S : Set) return Boolean; procedure Make_Empty (S : in out Set); procedure Copy (Target : in out Set; Source : Set); function Is_Member (S : Set; X : Element) return Boolean; procedure Add (S : in out Set; X : Element); procedure Delete (S : in out Set; X : Element); -- X is (is not) in S then the operation add (delete) is a no op. type Iterator is limited private; procedure Init (Iter : out Iterator; S : Set); procedure Next (Iter : in out Iterator); function Value (Iter : Iterator) return Element; function Done (Iter : Iterator) return Boolean; ------------------------------------------------------ -- Implementation Notes and Non-Standard Operations -- ------------------------------------------------------ -- variables of type set are initially empty -- therefore, the call to initialize is optional -- initialize does make the set empty -- := and = operate on references -- := implies sharing (introduces an alias) -- = means is the same set, not the same value of type set -- garbage may be generated -- Concurrency Properties -- any number of read operations (is_empty,is_member) can procede -- concurrently with one write operations (add/delete/make_empty) private type Node is record Value : Element; Link : Set; end record; type Set is access Node; type Iterator is new Set; end Set_Generic;package body Set_Generic is procedure Initialize (S : out Set) is begin S := null; end Initialize; function Is_Empty (S : Set) return Boolean is begin return S = null; end Is_Empty; procedure Make_Empty (S : in out Set) is begin S := null; end Make_Empty; procedure Init (Iter : out Iterator; S : Set) is begin Iter := Iterator (S); end Init; procedure Next (Iter : in out Iterator) is begin Iter := Iterator (Iter.Link); end Next; function Value (Iter : Iterator) return Element is begin return Iter.Value; end Value; function Done (Iter : Iterator) return Boolean is begin return Iter = null; end Done; procedure Copy (Target : in out Set; Source : Set) is Rest : Set := Source; begin Target := null; while Rest /= null loop Target := new Node'(Rest.Value, Target); Rest := Rest.Link; end loop; end Copy; function Is_Member (S : Set; X : Element) return Boolean is Rest : Set := S; begin while Rest /= null loop if Rest.Value = X then return True; end if; Rest := Rest.Link; end loop; return False; end Is_Member; procedure Add (S : in out Set; X : Element) is begin if not Is_Member (S, X) then S := new Node'(X, S); end if; end Add; procedure Delete (S : in out Set; X : Element) is Current : Set := S; Previous : Set := null; begin while Current /= null loop if Current.Value = X then if Previous /= null then Previous.Link := Current.Link; else S := Current.Link; end if; return; end if; Previous := Current; Current := Current.Link; end loop; end Delete; end Set_Generic;generic type Element is private; pragma Must_Be_Constrained (Yes => Element); package Stack_Generic is type Stack is private; Empty_Stack : constant Stack; -- It is expected that a declared stack is initialized to Empty_Stack procedure Make_Empty (S : in out Stack); procedure Pop (S : in out Stack); procedure Push (X : Element; S : in out Stack); function Empty (S : Stack) return Boolean; function Top (S : Stack) return Element; procedure Copy (Target : in out Stack; Source : Stack); Underflow : exception; type Iterator is private; procedure Init (Iter : out Iterator; S : Stack); procedure Next (Iter : in out Iterator); function Value (Iter : Iterator) return Element; function Done (Iter : Iterator) return Boolean; private type Stack_Node; type Stack is access Stack_Node; Empty_Stack : constant Stack := null; type Iterator is new Stack; end Stack_Generic;package body Stack_Generic is type Stack_Node is record Elt : Element; Link : Stack; end record; procedure Make_Empty (S : in out Stack) is begin S := null; end Make_Empty; procedure Pop (S : in out Stack) is begin if S = null then raise Underflow; else S := S.Link; end if; end Pop; procedure Push (X : Element; S : in out Stack) is New_Node : Stack; begin New_Node := new Stack_Node'(Elt => X, Link => S); S := New_Node; end Push; function Empty (S : Stack) return Boolean is begin return S = null; end Empty; function Top (S : Stack) return Element is begin if S = null then raise Underflow; else return S.Elt; end if; end Top; procedure Copy (Target : in out Stack; Source : Stack) is Rest_Of_Source : Stack; Last_Of_Target : Stack; begin if Source /= null then Target := new Stack_Node'(Elt => Source.Elt, Link => null); Last_Of_Target := Target; Rest_Of_Source := Source.Link; while Rest_Of_Source /= null loop Last_Of_Target.Link := new Stack_Node'(Elt => Rest_Of_Source.Elt, Link => null); Last_Of_Target := Last_Of_Target.Link; Rest_Of_Source := Rest_Of_Source.Link; end loop; else Target := null; end if; end Copy; procedure Init (Iter : out Iterator; S : Stack) is begin Iter := Iterator (S); end Init; procedure Next (Iter : in out Iterator) is begin Iter := Iterator (Iter.Link); end Next; function Value (Iter : Iterator) return Element is begin return Iter.Elt; end Value; function Done (Iter : Iterator) return Boolean is begin return Iter = null; end Done; end Stack_Generic;generic Size : Integer; type Range_Type is private; -- Range_Type is a pure value -- no initialization or finalization of values of range_type is -- necessary -- = and := can be used for equality and copy Ignore_Case : Boolean := True; pragma Must_Be_Constrained (Yes => Range_Type); package String_Map_Generic is type Map is private; function Eval (The_Map : Map; D : String) return Range_Type; procedure Find (The_Map : Map; D : String; R : in out Range_Type; Success : out Boolean); procedure Define (The_Map : in out Map; D : String; R : Range_Type; Trap_Multiples : Boolean := False); procedure Undefine (The_Map : in out Map; D : String); procedure Initialize (The_Map : out Map); function Is_Empty (The_Map : Map) return Boolean; procedure Make_Empty (The_Map : in out Map); procedure Copy (Target : in out Map; Source : Map); type Iterator is private; procedure Init (Iter : out Iterator; The_Map : Map); procedure Next (Iter : in out Iterator); function Value (Iter : Iterator) return String; function Done (Iter : Iterator) return Boolean; Undefined : exception; -- raised by eval if the domain value in not in the map Multiply_Defined : exception; -- raised by define if the domain value is already defined and -- the trap_multiples flag has been specified (ie. is true) function Nil return Map; function Is_Nil (The_Map : Map) return Boolean; function Cardinality (The_Map : Map) return Natural; ------------------------------------------------------ -- Implementation Notes and Non-Standard Operations -- ------------------------------------------------------ -- := and = operate on references -- := implies sharing (introduces an alias) -- = means is the same set, not the same value of type set -- Initializing a map also makes it empty -- Accessing an uninitialized map will raise CONSTRAINT_ERROR. -- garbage may be generated private subtype Index is Natural range 0 .. Size - 1; type Node (Size : Natural); type Set is access Node; type Table is array (Index) of Set; type Map_Data is record Bucket : Table; Size : Integer := 0; end record; type Map is access Map_Data; type Iterator is record The_Map : Map; Index_Value : Index; Set_Iter : Set; Done : Boolean; end record; type Node (Size : Natural) is record Link : Set; Value : Range_Type; Name : String (1 .. Size); end record; end String_Map_Generic;with String_Utilities; package body String_Map_Generic is function Find (S : Set; Name : String) return Set is Rest : Set := S; begin if Ignore_Case then declare Upper_Name : constant String := String_Utilities.Upper_Case (Name); begin while Rest /= null loop if Rest.Name'Length = Upper_Name'Length and then String_Utilities.Upper_Case (Rest.Name) = Upper_Name then return Rest; end if; Rest := Rest.Link; end loop; end; else while Rest /= null loop if Rest.Name = Name then return Rest; end if; Rest := Rest.Link; end loop; end if; return null; end Find; function Hash (Name : String) return Index is begin return Index'(String_Utilities.Hash_String (Name) mod Size); end Hash; pragma Inline (Hash); function Eval (The_Map : Map; D : String) return Range_Type is Ptr : Set := Find (The_Map.Bucket (Hash (D)), D); begin if Ptr /= null then return Ptr.Value; else raise Undefined; end if; end Eval; procedure Find (The_Map : Map; D : String; R : in out Range_Type; Success : out Boolean) is Ptr : Set := Find (The_Map.Bucket (Hash (D)), D); begin if Ptr /= null then R := Ptr.Value; Success := True; else Success := False; end if; end Find; procedure Define (The_Map : in out Map; D : String; R : Range_Type; Trap_Multiples : Boolean := False) is This_Node : Set renames The_Map.Bucket (Hash (D)); The_Set : Set := This_Node; Ptr : Set := Find (The_Set, D); begin if Ptr = null then This_Node := new Node (D'Length); declare N : Node renames This_Node.all; begin N.Link := The_Set; N.Value := R; N.Name := D; end; The_Map.Size := The_Map.Size + 1; elsif Trap_Multiples then raise Multiply_Defined; else Ptr.Value := R; end if; end Define; procedure Undefine (The_Map : in out Map; D : String) is The_Bucket : Index := Hash (D); Current : Set := The_Map.Bucket (The_Bucket); Previous : Set := null; begin while Current /= null loop if Current.Name = D then if Previous /= null then Previous.Link := Current.Link; else The_Map.Bucket (The_Bucket) := Current.Link; end if; The_Map.Size := The_Map.Size - 1; return; else Previous := Current; Current := Current.Link; end if; end loop; raise Undefined; end Undefine; procedure Copy (Target : in out Map; Source : Map) is Rest : Set; begin for I in Index loop Rest := Source.Bucket (I); Target.Bucket (I) := null; while Rest /= null loop Target.Bucket (I) := new Node'(Size => Rest.Name'Length, Name => Rest.Name, Value => Rest.Value, Link => Target.Bucket (I)); Rest := Rest.Link; end loop; end loop; Target.Size := Source.Size; end Copy; procedure Initialize (The_Map : out Map) is begin The_Map := new Map_Data; end Initialize; function Is_Empty (The_Map : Map) return Boolean is Iter : Iterator; begin for I in Index loop if The_Map.Bucket (I) /= null then return False; end if; end loop; return True; end Is_Empty; procedure Make_Empty (The_Map : in out Map) is begin for I in Index loop The_Map.Bucket (I) := null; end loop; end Make_Empty; procedure Init (Iter : out Iterator; The_Map : Map) is The_Iter : Iterator; begin for I in Index loop The_Iter.Set_Iter := The_Map.Bucket (I); if The_Iter.Set_Iter /= null then The_Iter.Done := False; The_Iter.Index_Value := I; The_Iter.The_Map := The_Map; Iter := The_Iter; return; end if; end loop; The_Iter.Done := True; Iter := The_Iter; end Init; procedure Next (Iter : in out Iterator) is begin Iter.Set_Iter := Iter.Set_Iter.Link; while Iter.Set_Iter = null loop if Iter.Index_Value = Index'Last then Iter.Done := True; return; end if; Iter.Index_Value := Iter.Index_Value + 1; Iter.Set_Iter := Iter.The_Map.Bucket (Iter.Index_Value); end loop; end Next; function Value (Iter : Iterator) return String is begin return Iter.Set_Iter.Name; end Value; function Done (Iter : Iterator) return Boolean is begin return Iter.Done; end Done; function Nil return Map is begin return null; end Nil; function Is_Nil (The_Map : Map) return Boolean is begin return The_Map = null; end Is_Nil; function Cardinality (The_Map : Map) return Natural is begin return The_Map.Size; end Cardinality; end String_Map_Generic;package String_Table is type Item is private; type Table is private; Table_Full : exception; -- create a table for unique strings function New_Table (Minimum_Table_Size : Natural := 127) return Table; function Nil return Item; -- return unique item in table, ignore_case => upper_case storage function Unique (Source : String; In_Table : Table; Ignore_Case : Boolean := True) return Item; -- return item if present, otherwise Nil function Find (Source : String; In_Table : Table; Ignore_Case : Boolean := True) return Item; -- return an item without entering in table function Allocate (Source : String; In_Table : Table) return Item; -- compare strings for identity, then same contents function Equal (L, R : Item) return Boolean; -- representation of string, suitable for hashing function Unique_Index (U : Item) return Integer; -- value of character or entire string function Char_At (Source : Item; At_Pos : Natural) return Character; function Image (Source : Item) return String; function Length (Source : Item) return Natural; function Is_Nil (Source : Item) return Boolean; type Iterator is private; procedure Init (Iter : out Iterator; The_Table : Table); procedure Next (Iter : in out Iterator); function Value (Iter : Iterator) return Item; function Done (Iter : Iterator) return Boolean; private type Table_Storage; type Table is access Table_Storage; type Item is access String; type Sym_Rec; type Long_Sym_Pointer is access Sym_Rec; type Sym_Pointer is new Long_Sym_Pointer; subtype Element_Index is Integer; type Iterator is record The_Table : Table; Bucket : Element_Index; Member : Long_Sym_Pointer; end record; end String_Table;with String_Utilities; with Unchecked_Conversion; package body String_Table is function Item_To_Integer is new Unchecked_Conversion (Item, Integer); package Util renames String_Utilities; type Sym_Rec is record Value : Item; Next : Sym_Pointer; end record; type Table_Storage is array (Element_Index range <>) of Sym_Pointer; function Nil return Item is begin return null; end Nil; function Hash_Code (S : String; Hash_Size : Positive) return Element_Index is begin return Element_Index (abs (Util.Hash_String (S) mod Hash_Size)); end Hash_Code; pragma Inline (Hash_Code); function New_Table (Minimum_Table_Size : Natural := 127) return Table is begin return new Table_Storage (0 .. Minimum_Table_Size); end New_Table; function Unique (Source : String; In_Table : Table; Ignore_Case : Boolean := True) return Item is Bucket : Sym_Pointer renames In_Table (Hash_Code (Source, In_Table'Length)); Chain : Sym_Pointer := Bucket; begin if Source'Length = 0 then return null; end if; if Ignore_Case then declare S : constant String := Util.Upper_Case (Source); begin while Chain /= null loop if Util.Upper_Case (Chain.Value.all) = S then return Chain.Value; end if; Chain := Chain.Next; end loop; end; else while Chain /= null loop if Chain.Value.all = Source then return Chain.Value; end if; Chain := Chain.Next; end loop; end if; Chain := new Sym_Rec; Chain.Value := new String'(Source); Chain.Next := Bucket; Bucket := Chain; return Chain.Value; end Unique; function Find (Source : String; In_Table : Table; Ignore_Case : Boolean := True) return Item is Chain : Sym_Pointer := In_Table (Hash_Code (Source, In_Table'Length)); begin if Source'Length = 0 then return null; end if; if Ignore_Case then declare S : constant String := Util.Upper_Case (Source); begin while Chain /= null loop if Util.Upper_Case (Chain.Value.all) = S then return Chain.Value; end if; Chain := Chain.Next; end loop; end; else while Chain /= null loop if Chain.Value.all = Source then return Chain.Value; end if; Chain := Chain.Next; end loop; end if; return null; end Find; function Allocate (Source : String; In_Table : Table) return Item is begin if Source'Length > 0 then return new String'(Source); else return Nil; end if; end Allocate; function Equal (L, R : Item) return Boolean is begin return L = R or else ((L /= Nil and then R /= Nil) and then L.all = R.all); end Equal; function Unique_Index (U : Item) return Integer is begin return Item_To_Integer (U); end Unique_Index; function Char_At (Source : Item; At_Pos : Natural) return Character is begin return Source (At_Pos - 1 + Source'First); end Char_At; function Image (Source : Item) return String is begin if Source = Nil then return ""; else return Source.all; end if; end Image; function Length (Source : Item) return Natural is begin if Source = Nil then return 0; else return Source.all'Length; end if; end Length; function Is_Nil (Source : Item) return Boolean is begin return Source = Nil; end Is_Nil; procedure Incr (Iter : in out Iterator) is begin loop Iter.Member := Long_Sym_Pointer (Iter.The_Table (Iter.Bucket)); exit when Iter.Member /= null or else Iter.Bucket = Iter.The_Table'Last; Iter.Bucket := Iter.Bucket + 1; end loop; end Incr; procedure Init (Iter : out Iterator; The_Table : Table) is The_Iter : Iterator; begin The_Iter.The_Table := The_Table; The_Iter.Bucket := 0; Incr (The_Iter); Iter := The_Iter; end Init; procedure Next (Iter : in out Iterator) is begin Iter.Member := Long_Sym_Pointer (Iter.Member.Next); if Iter.Member = null and then Iter.Bucket /= Iter.The_Table'Last then Iter.Bucket := Iter.Bucket + 1; Incr (Iter); end if; end Next; function Value (Iter : Iterator) return Item is begin return Iter.Member.Value; end Value; function Done (Iter : Iterator) return Boolean is begin return Iter.Member = null; end Done; end String_Table;package String_Utilities is function Hash_String (S : String) return Integer; procedure Upper_Case (C : in out Character); procedure Lower_Case (C : in out Character); function Upper_Case (C : Character) return Character; function Lower_Case (C : Character) return Character; procedure Upper_Case (S : in out String); procedure Lower_Case (S : in out String); -- string returned has same 'First and 'Last as S function Upper_Case (S : String) return String; function Lower_Case (S : String) return String; function Number_To_String (Value : Integer; Base : Natural := 10; Width : Natural := 0; Leading : Character := ' ') return String; -- function Number_To_String (Value : Long_Integer; -- Base : Natural := 10; -- Width : Natural := 0; -- Leading : Character := ' ') return String; procedure String_To_Number (Source : String; Target : out Integer; Worked : out Boolean; Base : Natural := 10); -- procedure String_To_Number (Source : String; -- Target : out Long_Integer; -- Worked : out Boolean; -- Base : Natural := 10); function Strip_Leading (From : String; Filler : Character := ' ') return String; function Strip_Trailing (From : String; Filler : Character := ' ') return String; function Strip (From : String; Filler : Character := ' ') return String; -- Searches and compares -- Locate returns the index value in Within if found, 0 otherwise function Locate (Fragment : String; Within : String; Ignore_Case : Boolean := False) return Natural; function Locate (Fragment : Character; Within : String; Ignore_Case : Boolean := False) return Natural; function Reverse_Locate (Fragment : String; Within : String; Ignore_Case : Boolean := False) return Natural; function Reverse_Locate (Fragment : Character; Within : String; Ignore_Case : Boolean := False) return Natural; function Equal (Str1 : String; Str2 : String; Ignore_Case : Boolean := False) return Boolean; function Less_Than (Str1 : String; Str2 : String; Ignore_Case : Boolean := False) return Boolean; function Greater_Than (Str1 : String; Str2 : String; Ignore_Case : Boolean := False) return Boolean; procedure Capitalize (S : in out String); function Capitalize (S : String) return String; end String_Utilities;with Bounded_String; package body String_Utilities is type Translate_Table is array (Character) of Character; type Equality_Table is array (Character, Character) of Boolean; pragma Pack (Equality_Table); Upper_Ascii : Translate_Table; Lower_Ascii : Translate_Table; Equal_Mod_Case : Equality_Table := (others => (others => False)); subtype Translation is Integer range 0 .. 2 ** 8 - 1; -- Next_Cap is 0..1 * 2**7 -- Lower_Char is 0..127 type Caps_Array is array (Translation) of Translation; Caps : Caps_Array; Char : constant Translation := 2 ** 7; Base_Characters : array (0 .. 15) of Character := ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); procedure Capitalize (S : in out String) is Upper : Translation := 0; begin for I in S'Range loop declare C : Character renames S (I); T : Translation renames Caps (Character'Pos (C) + Upper); begin C := Character'Val (T mod Char); Upper := T - Character'Pos (C); end; end loop; end Capitalize; function Capitalize (S : String) return String is Upper : Translation := 0; New_S : String (S'Range) := S; begin for I in New_S'Range loop declare C : Character renames New_S (I); T : Translation renames Caps (Character'Pos (C) + Upper); begin C := Character'Val (T mod Char); Upper := T - Character'Pos (C); end; end loop; return New_S; end Capitalize; function Upper_Case (C : Character) return Character is begin return Upper_Ascii (C); end Upper_Case; function Lower_Case (C : Character) return Character is begin return Lower_Ascii (C); end Lower_Case; procedure Upper_Case (C : in out Character) is begin C := Upper_Ascii (C); end Upper_Case; procedure Lower_Case (C : in out Character) is begin C := Lower_Ascii (C); end Lower_Case; procedure Upper_Case (S : in out String) is begin for I in S'Range loop S (I) := Upper_Ascii (S (I)); end loop; end Upper_Case; procedure Lower_Case (S : in out String) is begin for I in S'Range loop S (I) := Lower_Ascii (S (I)); end loop; end Lower_Case; function Upper_Case (S : String) return String is New_S : String (S'First .. S'Last); begin for I in S'Range loop New_S (I) := Upper_Ascii (S (I)); end loop; return New_S; end Upper_Case; function Lower_Case (S : String) return String is New_S : String (S'First .. S'Last); begin for I in S'Range loop New_S (I) := Lower_Ascii (S (I)); end loop; return New_S; end Lower_Case; -- It is expected that specific targets will be able to get better hashes -- using code insertions. function Hash_String (S : String) return Integer is L : constant Integer := S'Length; Result : Integer := L; begin if L > 0 then Result := Result + 2 ** 5 * Character'Pos (Upper_Ascii (S (S'First))) + Character'Pos (Upper_Ascii (S (S'First + (1 + S'Last - S'First) / 2))) + 2 ** 3 * Character'Pos (Upper_Ascii (S (S'Last))); end if; return Result; end Hash_String; function Number_To_String (Value : Integer; Base : Natural := 10; Width : Natural := 0; Leading : Character := ' ') return String is Sign : Boolean := False; Result : Bounded_String.Variable_String (80); Ch : Integer; procedure N2s (Num : Integer; Width : Integer) is begin if Num = 0 then -- Handle leading stuff for I in 1 .. Width loop Bounded_String.Append (Result, Leading); end loop; if Sign then Bounded_String.Append (Result, '-'); end if; if Value = 0 then if Width > 0 then Bounded_String.Replace (Result, Bounded_String.Length (Result), '0'); else Bounded_String.Append (Result, '0'); end if; end if; else N2s (Num / Base, Width - 1); if not Sign then Ch := Num mod Base; else Ch := Base - Num mod Base; if Ch = Base then Ch := 0; end if; end if; Bounded_String.Append (Result, Base_Characters (Ch)); end if; end N2s; begin Bounded_String.Set_Length (Result, 0); if Value < 0 then Sign := True; N2s (Value, Width - 1); else N2s (Value, Width); end if; return Bounded_String.Image (Result); end Number_To_String; -- the above used to be the long_integer version -- function Number_To_String (Value : Integer; -- Base : Natural := 10; -- Width : Natural := 0; -- Leading : Character := ' ') return String is -- begin -- return Number_To_String (Long_Integer (Value), Base, Width, Leading); -- end Number_To_String; -- the following used to be the long_integer version procedure String_To_Number (Source : String; Target : out Integer; Worked : out Boolean; Base : Natural := 10) is Sign : Integer; Result : Integer; Ch : Character; Char_Val : Integer; Prefix : Boolean := True; begin Worked := False; Target := 0; Result := 0; Sign := +1; for I in Source'Range loop Ch := Source (I); if Ch = ' ' then if not Prefix then return; end if; else if Prefix and Ch = '-' then Sign := -1; else if Ch in '0' .. '9' then Char_Val := (Character'Pos (Ch) - 48); else Upper_Case (Ch); if Ch in 'A' .. 'F' then Char_Val := Character'Pos (Ch) - Character'Pos ('A') + 10; else -- set Char_Val > any legal base Char_Val := 500; end if; end if; if Char_Val >= Base then return; end if; Result := Result * Base + Char_Val; end if; Prefix := False; end if; end loop; if Source'Length /= 0 and then (Source'Length > 1 or else Sign = +1) then Target := Result * Sign; Worked := True; end if; exception when others => Worked := False; end String_To_Number; -- procedure String_To_Number (Source : String; -- Target : out Integer; -- Worked : out Boolean; -- Base : Natural := 10) is -- Result : Long_Integer; -- begin -- String_To_Number (Source, Result, Worked, Base); -- Target := Integer (Result); -- end String_To_Number; function Locate (Fragment : Character; Within : String; Ignore_Case : Boolean := False) return Natural is begin if Ignore_Case then for I in Within'Range loop if Equal_Mod_Case (Fragment, Within (I)) then return I; end if; end loop; else for I in Within'Range loop if Fragment = Within (I) then return I; end if; end loop; end if; return 0; end Locate; function Locate (Fragment : String; Within : String; Ignore_Case : Boolean := False) return Natural is Dec_Length : Integer := Fragment'Length - 1; First : Positive := Fragment'First; First_Char : Character; begin if Dec_Length >= 1 then First_Char := Fragment (First); if Ignore_Case then for I in Within'First .. Within'Last - Dec_Length loop if Equal_Mod_Case (Within (I), First_Char) then for J in reverse 1 .. Dec_Length loop if not Equal_Mod_Case (Fragment (First + J), Within (I + J)) then exit; elsif J = 1 then return I; end if; end loop; end if; end loop; else for I in Within'First .. Within'Last - Dec_Length loop if Within (I) = First_Char then for J in reverse 1 .. Dec_Length loop if Fragment (First + J) /= Within (I + J) then exit; elsif J = 1 then return I; end if; end loop; end if; end loop; end if; return 0; elsif Dec_Length = 0 then return Locate (Fragment (First), Within, Ignore_Case); else return Within'First; end if; end Locate; function Reverse_Locate (Fragment : Character; Within : String; Ignore_Case : Boolean := False) return Natural is begin if Ignore_Case then for I in reverse Within'Range loop if Equal_Mod_Case (Fragment, Within (I)) then return I; end if; end loop; else for I in reverse Within'Range loop if Fragment = Within (I) then return I; end if; end loop; end if; return 0; end Reverse_Locate; function Reverse_Locate (Fragment : String; Within : String; Ignore_Case : Boolean := False) return Natural is Dec_Length : Integer := Fragment'Length - 1; First : Positive := Fragment'First; First_Char : Character; begin if Dec_Length >= 1 then First_Char := Fragment (First); if Ignore_Case then for I in reverse Within'First .. Within'Last - Dec_Length loop if Equal_Mod_Case (Within (I), First_Char) then for J in reverse 1 .. Dec_Length loop if not Equal_Mod_Case (Fragment (First + J), Within (I + J)) then exit; elsif J = 1 then return I + Dec_Length; end if; end loop; end if; end loop; else for I in reverse Within'First .. Within'Last - Dec_Length loop if Within (I) = First_Char then for J in reverse 1 .. Dec_Length loop if Fragment (First + J) /= Within (I + J) then exit; elsif J = 1 then return I + Dec_Length; end if; end loop; end if; end loop; end if; return 0; elsif Dec_Length = 0 then return Reverse_Locate (Fragment (First), Within, Ignore_Case); else return Within'Last; end if; end Reverse_Locate; function Equal (Str1 : String; Str2 : String; Ignore_Case : Boolean := False) return Boolean is Length : Integer := Str1'Length; First1 : Positive := Str1'First; First2 : Positive := Str2'First; begin if Length = Str2'Length then if Ignore_Case then for I in 0 .. Length - 1 loop if not Equal_Mod_Case (Str1 (First1 + I), Str2 (First2 + I)) then return False; end if; end loop; return True; else return Str1 = Str2; end if; else return False; end if; end Equal; function Less_Than (Str1 : String; Str2 : String; Ignore_Case : Boolean := False) return Boolean is begin if Ignore_Case then return Lower_Case (Str1) < Lower_Case (Str2); else return Str1 < Str2; end if; end Less_Than; function Greater_Than (Str1 : String; Str2 : String; Ignore_Case : Boolean := False) return Boolean is begin if Ignore_Case then return Lower_Case (Str1) > Lower_Case (Str2); else return Str1 > Str2; end if; end Greater_Than; function Strip_Leading (From : String; Filler : Character := ' ') return String is begin for I in From'First .. From'Last loop if From (I) /= Filler then return From (I .. From'Last); end if; end loop; return ""; end Strip_Leading; function Strip_Trailing (From : String; Filler : Character := ' ') return String is begin for I in reverse From'First .. From'Last loop if From (I) /= Filler then return From (From'First .. I); end if; end loop; return ""; end Strip_Trailing; function Strip (From : String; Filler : Character := ' ') return String is begin return Strip_Leading (Strip_Trailing (From, Filler), Filler); end Strip; begin for C in Character loop Upper_Ascii (C) := C; Equal_Mod_Case (C, C) := True; end loop; Lower_Ascii := Upper_Ascii; for C in 'A' .. 'Z' loop Lower_Ascii (C) := Character'Val (Character'Pos (C) + 32); Equal_Mod_Case (C, Lower_Ascii (C)) := True; end loop; for C in 'a' .. 'z' loop Upper_Ascii (C) := Character'Val (Character'Pos (C) - 32); Equal_Mod_Case (C, Upper_Ascii (C)) := True; end loop; declare Alphanumeric : Integer; Upper : Character; Lower : Character; begin for C in Character loop Upper := Upper_Ascii (C); Lower := Lower_Ascii (C); Alphanumeric := Boolean'Pos (Upper /= Lower or else C in '0' .. '9') * Char; Caps (Character'Pos (C)) := Alphanumeric + Character'Pos (Upper); Caps (Character'Pos (C) + Char) := Alphanumeric + Character'Pos (Lower); end loop; end; end String_Utilities;with Text_Io; -- This package is used to produce neatly formatted tables with centered -- headers and even amounts of white space between the columns. The first -- N calls should be to header, which defines a header and a type of -- justification for the items that will go into each column. Then the M*N -- items of an M line table are sent into the package a row at a time. An -- item is defined by either a single call to Item, or a series of zero or -- more calls to Subitem terminated by a call to Last_Subitem. Multiple -- parts of an item are separated by the subitem separator. After all the -- items have been defined, the table is output with a call to Display. -- The package internally allocates enough memory to save a copy of the -- entire table. It is therefore a good idea to instantiate this -- procedure in a local frame so that all the memory it allocates will go -- away when the frame does. generic Number_Of_Columns : Positive; Subitem_Separator : String := " "; package Table_Formatter is type Adjust is (Left, Right, Centered); procedure Header (S : String; Format : Adjust := Left); procedure Item (S : String); procedure Subitem (S : String); procedure Last_Subitem; procedure Display (On_File : Text_Io.File_Type); type Field_List is array (Integer range <>) of Positive; procedure Sort (On_Field : Positive := 1); procedure Sort (On_Fields : Field_List); end Table_Formatter;with Table_Sort_Generic; package body Table_Formatter is Intercolumn_Spacing : constant := 2; subtype Column_Index is Natural range 1 .. Number_Of_Columns; type Width_List is array (Column_Index) of Natural; type A_String is access String; type An_Item (Subitem_Length : Natural); type Access_Item is access An_Item; type An_Item (Subitem_Length : Natural) is record Subitem : String (1 .. Subitem_Length); Next : Access_Item; end record; type Item_List is array (Column_Index) of Access_Item; type Line; type Access_Line is access Line; type Access_Line_Array is array (Integer range <>) of Access_Line; Current_Line : Access_Line; type Line is record Values : Item_List; Width : Width_List := (others => 0); Next : Access_Line := Current_Line; end record; Current_Column : Column_Index := Column_Index'Last; In_Subitem : Boolean := False; Max_Width : Width_List := (others => 0); Headers : array (Column_Index) of A_String; Header_Column : Natural := 0; Column_Format : array (Column_Index) of Adjust; function Max (Left, Right : Integer) return Integer is begin if Left >= Right then return Left; else return Right; end if; end Max; procedure Insert (S : String) is -- Put the String into the current row/column, appending it if -- there is already something there. Cell : Access_Item renames Current_Line.Values (Current_Column); Width : Natural renames Current_Line.Width (Current_Column); Max : Natural renames Max_Width (Current_Column); begin if Cell = null then Width := S'Length; else Width := Width + Subitem_Separator'Length + S'Length; end if; if Width > Max then Max := Width; end if; Cell := new An_Item'(S'Length, S, Cell); end Insert; procedure Item (S : String) is -- Begin a new cell, put S there, and mark the cell closed by -- setting In_Subitem to be false. begin if Current_Column = Column_Index'Last then Current_Line := new Line; Current_Column := Column_Index'First; else Current_Column := Current_Column + 1; end if; Insert (S); In_Subitem := False; end Item; procedure Header (S : String; Format : Adjust := Left) is -- Set Header and Column Format begin Header_Column := Header_Column + 1; Column_Format (Header_Column) := Format; Headers (Header_Column) := new String'(S); end Header; procedure Subitem (S : String) is -- If the current cell is open, add S to it. Otherwise start a new -- cell, but leave it open. begin if In_Subitem then Insert (S); else Item (S); end if; In_Subitem := True; end Subitem; procedure Last_Subitem is -- If the current cell is open, close it. If the current cell is -- closed, we have an item that consists of zero subitems. Give it -- a visible representation. begin if In_Subitem then In_Subitem := False; else Item ("(none)"); end if; end Last_Subitem; function Image (P : Access_Item) return String is -- P must be non-null begin if P.Next = null then return P.Subitem; end if; return Image (P.Next) & Subitem_Separator & P.Subitem; -- Recall that subitem lists are stored in reverse order end Image; procedure Display (On_File : Text_Io.File_Type) is -- Dump the data structure we have been building by traversing it -- recursively. Note that all of the lists are stored in reverse -- order so that they were easy to build. procedure Replicate (C : Character; N : Natural) is -- Output N copies of C S : constant String (1 .. N) := (others => C); begin Text_Io.Put (On_File, S); end Replicate; procedure Display (P : Access_Item) is begin if P /= null then Text_Io.Put (On_File, Image (P)); end if; end Display; procedure Display_Headers is Excess : Width_List; begin for J in Column_Index loop Excess (J) := Max (Headers (J).all'Length, Max_Width (J)) - Headers (J).all'Length; end loop; Replicate (' ', Excess (1) / 2); for J in Column_Index loop Text_Io.Put (On_File, Headers (J).all); if J /= Column_Index'Last then Replicate (' ', (Excess (J) + 1) / 2 + Excess (J + 1) / 2 + Intercolumn_Spacing); end if; end loop; Text_Io.New_Line (On_File); end Display_Headers; procedure Display_Adjusted (L : Line) is Inner_Excess, Outer_Excess : Natural; begin for J in Column_Index loop Inner_Excess := Max_Width (J) - L.Width (J); Outer_Excess := Max (Headers (J).all'Length, Max_Width (J)) - Max_Width (J); case Column_Format (J) is when Left => Replicate (' ', Outer_Excess / 2); Display (L.Values (J)); if J /= Column_Index'Last then Replicate (' ', (Outer_Excess + 1) / 2 + Inner_Excess + Intercolumn_Spacing); end if; when Right => Replicate (' ', Outer_Excess / 2 + Inner_Excess); Display (L.Values (J)); if J /= Column_Index'Last then Replicate (' ', (Outer_Excess + 1) / 2 + Intercolumn_Spacing); end if; when Centered => Replicate (' ', (Inner_Excess + Outer_Excess) / 2); Display (L.Values (J)); if J /= Column_Index'Last then Replicate (' ', (Inner_Excess + Outer_Excess + 1) / 2 + Intercolumn_Spacing); end if; end case; end loop; Text_Io.New_Line (On_File); end Display_Adjusted; procedure Display (L : Access_Line) is begin if L = null then -- Center the header Display_Headers; -- A separator line for J in Column_Index loop Replicate ('=', Max (Headers (J).all'Length, Max_Width (J))); if J /= Column_Index'Last then Replicate (' ', Intercolumn_Spacing); end if; end loop; Text_Io.New_Line (On_File); else -- Display the head of the table Display (L.Next); -- Display the final line Display_Adjusted (L.all); end if; end Display; begin Display (Current_Line); end Display; function Normalize return Natural is -- Traverse the current structure looking for cells that consist -- of more than one subitem, and concatentate the subitems into -- a single item. -- Return the number of rows in the table. Result : Natural := 0; Line : Access_Line := Current_Line; P : Access_Item; begin while Line /= null loop for J in Line.Values'Range loop P := Line.Values (J); if P = null then Line.Values (J) := new An_Item'(0, "", null); elsif P.Next /= null then Line.Values (J) := new An_Item'(Line.Width (J), Image (P), null); end if; end loop; Line := Line.Next; Result := Result + 1; end loop; return Result; end Normalize; procedure Fill (Table : out Access_Line_Array) is -- Transfers the linked list pointed to by Current_Line into -- the sequential table. P : Access_Line; begin P := Current_Line; for J in reverse Table'Range loop Table (J) := P; P := P.Next; end loop; end Fill; procedure Empty (Table : Access_Line_Array) is -- rebuilds the Current_Line link list from the sequential table, -- preserving the convention that lists are stored backwards. begin if Table'Length = 0 then Current_Line := null; return; end if; Table (Table'First).Next := null; for J in Table'First + 1 .. Table'Last loop Table (J).Next := Table (J - 1); end loop; Current_Line := Table (Table'Last); end Empty; procedure Sort (On_Field : Positive := 1) is Table : Access_Line_Array (1 .. Normalize); function "<" (Left, Right : Access_Line) return Boolean is begin return Left.Values (On_Field).Subitem < Right.Values (On_Field).Subitem; end "<"; procedure Table_Sort is new Table_Sort_Generic (Element => Access_Line, Index => Integer, Element_Array => Access_Line_Array); begin Fill (Table); Table_Sort (Table); Empty (Table); end Sort; procedure Sort (On_Fields : Field_List) is Table : Access_Line_Array (1 .. Normalize); function "<" (Left, Right : Access_Line) return Boolean is begin for J in On_Fields'Range loop if Left.Values (On_Fields (J)).Subitem < Right.Values (On_Fields (J)).Subitem then return True; end if; if Left.Values (On_Fields (J)).Subitem > Right.Values (On_Fields (J)).Subitem then return False; end if; end loop; return False; end "<"; procedure Table_Sort is new Table_Sort_Generic (Element => Access_Line, Index => Integer, Element_Array => Access_Line_Array); begin Fill (Table); Table_Sort (Table); Empty (Table); end Sort; begin -- Default to empty left justified headers. for J in Column_Index loop Column_Format (J) := Left; Headers (J) := new String'(""); end loop; end Table_Formatter;generic type Element is private; pragma Must_Be_Constrained (Yes => Element); type Index is (<>); type Element_Array is array (Index range <>) of Element; with function "<" (Left, Right : Element) return Boolean is <>; procedure Table_Sort_Generic (Table : in out Element_Array);procedure Table_Sort_Generic (Table : in out Element_Array) is First_Index : Integer := Index'Pos (Table'First); Last_Index : Integer := Index'Pos (Table'Last); J : Integer; Jg : Integer; Gap : Integer; Temp : Element; begin Gap := Last_Index - First_Index; while Gap > 0 loop for I in Index'Val (Gap + First_Index) .. Table'Last loop J := Index'Pos (I) - Gap; while J >= First_Index loop Jg := J + Gap; declare Op1 : Element renames Table (Index'Val (J)); Op2 : Element renames Table (Index'Val (Jg)); begin if Op2 < Op1 then Temp := Op1; Op1 := Op2; Op2 := Temp; else exit; end if; end; J := J - Gap; end loop; end loop; Gap := Gap / 2; end loop; end Table_Sort_Generic;with Calendar; package Time_Utilities is Minute : constant Duration := 60.0; Hour : constant Duration := 3600.0; Day : constant Duration := 86_400.0; -------------------------------------------------------------------- -- Time_Utilities.Time is a segmented version of Calendar.Time -- with image and value functions -------------------------------------------------------------------- type Years is new Calendar.Year_Number; type Months is (January, February, March, April, May, June, July, August, September, October, November, December); type Days is new Calendar.Day_Number; type Hours is new Integer range 1 .. 12; type Minutes is new Integer range 0 .. 59; type Seconds is new Integer range 0 .. 59; type Sun_Positions is (Am, Pm); type Time is record Year : Years; Month : Months; Day : Days; Hour : Hours; Minute : Minutes; Second : Seconds; Sun_Position : Sun_Positions; end record; function Get_Time return Time; function Convert_Time (Date : Calendar.Time) return Time; function Convert_Time (Date : Time) return Calendar.Time; function Nil return Time; function Is_Nil (Date : Time) return Boolean; function Nil return Calendar.Time; function Is_Nil (Date : Calendar.Time) return Boolean; type Time_Format is (Expanded, -- 11:00:00 PM Military, -- 23:00:00 Short, -- 23:00 Ada -- 23_00_00 ); type Date_Format is (Expanded, -- September 29, 1983 Month_Day_Year, -- 09/29/83 Day_Month_Year, -- 29-SEP-83 Year_Month_Day, -- 83/09/29 Ada -- 83_09_29 ); type Image_Contents is (Both, Time_Only, Date_Only); function Image (Date : Time; Date_Style : Date_Format := Time_Utilities.Expanded; Time_Style : Time_Format := Time_Utilities.Expanded; Contents : Image_Contents := Time_Utilities.Both) return String; function Value (S : String) return Time; -- Gives incorrect results for dates earlier than 1924. -------------------------------------------------------------------- -- Time_Utilities.Interval is a segmented version of Duration -- with image and value functions -------------------------------------------------------------------- type Day_Count is new Integer range 0 .. Integer'Last; type Military_Hours is new Integer range 0 .. 23; type Milliseconds is new Integer range 0 .. 999; type Interval is record Elapsed_Days : Day_Count; Elapsed_Hours : Military_Hours; Elapsed_Minutes : Minutes; Elapsed_Seconds : Seconds; Elapsed_Milliseconds : Milliseconds; end record; function Convert (I : Interval) return Duration; function Convert (D : Duration) return Interval; function Image (I : Interval) return String; function Value (S : String) return Interval; function Image (D : Duration) return String; function Duration_Until (T : Time) return Duration; function Duration_Until (T : Calendar.Time) return Duration; function Duration_Until_Next (H : Military_Hours; M : Minutes := 0; S : Seconds := 0) return Duration; -- Day of week support; Monday is 1. type Weekday is new Positive range 1 .. 7; function Day_Of_Week (T : Calendar.Time) return Weekday; function Day_Of_Week (T : Time := Get_Time) return Weekday; function Image (D : Weekday) return String; function "+" (D : Weekday; I : Integer) return Weekday; function "-" (D : Weekday; I : Integer) return Weekday; end Time_Utilities;with Enumeration_Value; with Machine_Independent_Integer32; with String_Utilities; package body Time_Utilities is package Mii renames Machine_Independent_Integer32; subtype Integer32 is Mii.Integer32; function "+" (L, R : Integer32) return Integer32 renames Mii."+"; function "-" (L, R : Integer32) return Integer32 renames Mii."-"; function "*" (L : Integer32; R : Integer) return Integer32 renames Mii."*"; function "/" (L : Integer32; R : Integer) return Integer32 renames Mii."/"; function "=" (L, R : Integer32) return Boolean renames Mii."="; function "<" (L, R : Integer32) return Boolean renames Mii."<"; Zero : constant Integer32 := Integer32 (0); Seconds_Per_Minute : constant := 60; Seconds_Per_Hour : constant := 60 * Seconds_Per_Minute; Seconds_Per_Half_Day : constant := 12 * Seconds_Per_Hour; Null_Calendar_Time : Calendar.Time; type Number_Array is array (Positive range <>) of Natural; type Character_Map is array (Character) of Boolean; Is_Numeric : constant Character_Map := Character_Map'('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => True, others => False); Is_Alphabetic : constant Character_Map := Character_Map'('a' .. 'z' | 'A' .. 'Z' => True, others => False); Null_Time : constant Time := Time'(Year => Years'First, Month => Months'First, Day => Days'First, Hour => Hours'First, Minute => Minutes'First, Second => Seconds'First, Sun_Position => Sun_Positions'First); Null_Interval : constant Interval := Interval'(Elapsed_Days => Day_Count'First, Elapsed_Hours => Military_Hours'First, Elapsed_Minutes => Minutes'First, Elapsed_Seconds => Seconds'First, Elapsed_Milliseconds => Milliseconds'First); Military_Hour : constant array (Sun_Positions, Hours) of Military_Hours := (Am => (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0), Pm => (13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12)); -- used in day of week calculation Days_In_Month : constant array (Months) of Integer := (January | March | May | July | August | October | December => 31, April | June | September | November => 30, February => 28); function Image (Value : Integer; Base : Natural := 10; Width : Natural := 2; Leading : Character := '0') return String renames String_Utilities.Number_To_String; package Interval_Value is -- Hack to get around RCG bug function Value (S : String) return Interval; end Interval_Value; procedure Unique_Prefix is new Enumeration_Value (Months); function Convert_Time (Date : Calendar.Time) return Time is Result : Time; C_Year : Calendar.Year_Number; C_Month : Calendar.Month_Number; C_Day : Calendar.Day_Number; C_Second : Calendar.Day_Duration; Total_Seconds : Integer32; Hour_Offset : Integer32; Junk, Min, Sec : Integer32; begin Calendar.Split (Date, C_Year, C_Month, C_Day, C_Second); Result.Year := Years (C_Year); Result.Month := Months'Val (C_Month - 1); Result.Day := Days (C_Day); Total_Seconds := Integer32 (C_Second); if Total_Seconds < Integer32 (Seconds_Per_Half_Day) then Result.Sun_Position := Am; else Result.Sun_Position := Pm; Total_Seconds := Total_Seconds - Integer32 (Seconds_Per_Half_Day); end if; Hour_Offset := Total_Seconds / Seconds_Per_Hour; if Hour_Offset = Zero then Result.Hour := 12; Result.Sun_Position := Pm; else Result.Hour := Hours (Hour_Offset); end if; --- Total_Seconds := Total_Seconds rem Seconds_Per_Hour; --tjl was MOD Mii.Div_Rem (Total_Seconds, Seconds_Per_Hour, Junk, Total_Seconds); Mii.Div_Rem (Total_Seconds, Seconds_Per_Minute, Min, Sec); Result.Minute := Minutes (Min); Result.Second := Seconds (Sec); --- Result.Minute := Minutes (Total_Seconds / Seconds_Per_Minute); --- Result.Second := Seconds (Total_Seconds rem Seconds_Per_Minute);--tjl return Result; end Convert_Time; function Convert_Time (Date : Time) return Calendar.Time is C_Year : Calendar.Year_Number; C_Month : Calendar.Month_Number; C_Day : Calendar.Day_Number; Total_Seconds : Integer32; begin C_Year := Calendar.Year_Number (Date.Year); C_Month := Calendar.Month_Number (Months'Pos (Date.Month) + 1); C_Day := Calendar.Day_Number (Date.Day); Total_Seconds := Integer32 (Date.Second) + Integer32 (Date.Minute) * Seconds_Per_Minute; if Date.Hour /= 12 then Total_Seconds := Total_Seconds + Integer32 (Date.Hour) * Seconds_Per_Hour; end if; if Date.Sun_Position = Pm then Total_Seconds := Total_Seconds + Integer32 (Seconds_Per_Half_Day); end if; return Calendar.Time_Of (C_Year, C_Month, C_Day, Duration (Total_Seconds)); exception when Calendar.Time_Error => return Calendar.Clock; end Convert_Time; function Get_Time return Time is begin return Convert_Time (Calendar.Clock); end Get_Time; function Image (Month : Months; Full_Width : Boolean := True) return String is Name : constant String := Months'Image (Month); begin if Full_Width then return String_Utilities.Capitalize (Name); else return Name (Name'First .. Name'First + 2); end if; end Image; function Time_Image (Date : Time; Time_Style : Time_Format) return String is Sep : Character := ':'; Hour : Integer := Integer (Military_Hour (Date.Sun_Position, Date.Hour)); begin case Time_Style is when Expanded => return Image (Integer (Date.Hour), Width => 0) & Sep & Image (Integer (Date.Minute)) & Sep & Image (Integer (Date.Second)) & ' ' & Sun_Positions'Image (Date.Sun_Position); when Military | Ada => if Time_Style = Ada then Sep := '_'; end if; return Image (Hour) & Sep & Image (Integer (Date.Minute)) & Sep & Image (Integer (Date.Second)); when Short => return Image (Hour) & Sep & Image (Integer (Date.Minute)); end case; end Time_Image; function Date_Image (Date : Time; Date_Style : Date_Format) return String is Sep : Character := '/'; Year : Integer := Integer (Date.Year) mod 100; Month : Integer := Months'Pos (Date.Month) + 1; begin case Date_Style is when Expanded => return Image (Date.Month) & ' ' & Image (Integer (Date.Day), Width => 0) & ',' & Image (Integer (Date.Year), Leading => ' ', Width => 5); when Month_Day_Year => return Image (Month, Leading => ' ') & Sep & Image (Integer (Date.Day)) & Sep & Image (Year); when Day_Month_Year => Sep := '-'; return Image (Integer (Date.Day), Leading => ' ') & Sep & Image (Date.Month, Full_Width => False) & Sep & Image (Year); when Year_Month_Day | Ada => if Date_Style = Ada then Sep := '_'; end if; return Image (Year) & Sep & Image (Month) & Sep & Image (Integer (Date.Day)); end case; end Date_Image; function Separator (Date_Style : Date_Format; Time_Style : Time_Format) return String is begin if Date_Style = Ada and then Time_Style = Ada then return "_at_"; elsif Date_Style = Expanded then return " at "; else return " "; end if; end Separator; function Image (Date : Time; Date_Style : Date_Format := Expanded; Time_Style : Time_Format := Expanded; Contents : Image_Contents := Both) return String is begin case Contents is when Both => return Date_Image (Date, Date_Style) & Separator (Date_Style, Time_Style) & Time_Image (Date, Time_Style); when Date_Only => return Date_Image (Date, Date_Style); when Time_Only => return Time_Image (Date, Time_Style); end case; end Image; function Time_Stamp_Image (Date : Time := Get_Time; Style : Time_Format := Military) return String is begin if Style = Short then return Image (Integer (Date.Minute)) & ':' & Image (Integer (Date.Second)); else return Time_Image (Date, Style); end if; end Time_Stamp_Image; function Convert (I : Interval) return Duration is Seconds : Duration := Duration (I.Elapsed_Milliseconds) / 1000; begin Seconds := Duration (I.Elapsed_Seconds) + Seconds; Seconds := Duration (Duration (I.Elapsed_Minutes) * Minute) + Seconds; Seconds := Duration (Duration (I.Elapsed_Hours) * Hour) + Seconds; Seconds := Duration (Duration (I.Elapsed_Days) * Day) + Seconds; return Seconds; end Convert; function Convert (D : Duration) return Interval is I : Interval; Milliseconds_Per_Second : constant := 1000; Milliseconds_Per_Minute : constant := 60 * Milliseconds_Per_Second; Milliseconds_Per_Hour : constant := 60 * Milliseconds_Per_Minute; Milliseconds_Per_Day : constant := 24 * Milliseconds_Per_Hour; Rest : Integer32 := Integer32 (D) * Milliseconds_Per_Second ; begin if D < 0.0 then return Null_Interval; end if; I.Elapsed_Days := Day_Count (Rest / Milliseconds_Per_Day); Rest := Rest - (Integer32 (I.Elapsed_Days) * Milliseconds_Per_Day); I.Elapsed_Hours := Military_Hours (Rest / Milliseconds_Per_Hour); Rest := Rest - (Integer32 (I.Elapsed_Hours) * Milliseconds_Per_Hour); I.Elapsed_Minutes := Minutes (Rest / Milliseconds_Per_Minute); Rest := Rest - (Integer32 (I.Elapsed_Minutes) * Milliseconds_Per_Minute); I.Elapsed_Seconds := Seconds (Rest / Milliseconds_Per_Second); Rest := Rest - (Integer32 (I.Elapsed_Seconds) * Milliseconds_Per_Second); I.Elapsed_Milliseconds := Milliseconds (Rest); return I; end Convert; package body Interval_Value is separate; function Value (S : String) return Interval is begin return Interval_Value.Value (S); end Value; function Time_Value (S : String) return Time is separate; function Value (S : String) return Time is begin return Time_Value (S); end Value; function Image (D : Duration) return String is begin return Image (Convert (D)); end Image; function Image (I : Interval) return String is begin if I.Elapsed_Days > 99999 then return Image (Natural (I.Elapsed_Days), Width => 0) & 'D'; elsif I.Elapsed_Days > 99 then return Image (Natural (I.Elapsed_Days), Width => 5, Leading => ' ') & '/' & Image (Natural (I.Elapsed_Hours)); elsif I.Elapsed_Days > 0 then return Image (Natural (I.Elapsed_Days), Leading => ' ') & '/' & Image (Natural (I.Elapsed_Hours)) & ':' & Image (Natural (I.Elapsed_Minutes)); elsif I.Elapsed_Hours > 0 then return Image (Natural (I.Elapsed_Hours), Leading => ' ') & ':' & Image (Natural (I.Elapsed_Minutes)) & ':' & Image (Natural (I.Elapsed_Seconds)); elsif I.Elapsed_Minutes > 0 then return Image (Natural (I.Elapsed_Minutes), Leading => ' ') & ':' & Image (Natural (I.Elapsed_Seconds)) & '.' & Image (Natural (I.Elapsed_Milliseconds), Width => 3); else return Image (Natural (I.Elapsed_Seconds), Leading => ' ') & '.' & Image (Natural (I.Elapsed_Milliseconds), Width => 3); end if; end Image; function Nil return Time is begin return Null_Time; end Nil; function Is_Nil (Date : Time) return Boolean is begin return Date = Nil; end Is_Nil; function Nil return Calendar.Time is begin return Null_Calendar_Time; end Nil; function Is_Nil (Date : Calendar.Time) return Boolean is begin return Calendar."=" (Date, Nil); end Is_Nil; function Image (D : Weekday) return String is begin case D is when 1 => return "Monday"; when 2 => return "Tuesday"; when 3 => return "Wednesday"; when 4 => return "Thursday"; when 5 => return "Friday"; when 6 => return "Saturday"; when 7 => return "Sunday"; end case; end Image; function Make_Weekday (D : Integer) return Weekday is Day : Integer := D mod 7; begin if Day = 0 then return 7; else return Weekday (Day); end if; end Make_Weekday; pragma Inline (Make_Weekday); function Day_Of_Week (T : Time := Get_Time) return Weekday is -- Uses Zeller's congruence to compute the day of week of given date. -- See "Problems for Computer Solutions", Gruenberger & Jaffray, Wiley, -- 1965, p. 255ff. Zyear, Zmonth, Zcentury, Zyy : Integer; begin -- Remap month# so Mar=1 & Jan, Feb=11, 12 of PRECEDING year if Months'Pos (T.Month) >= 3 then Zyear := Integer (T.Year); Zmonth := Months'Pos (T.Month) - 1; else -- Jan or Feb Zyear := Integer (T.Year) - 1; Zmonth := Months'Pos (T.Month) + 11; end if; Zcentury := Zyear / 100; Zyy := Zyear rem 100; return Make_Weekday (((26 * Zmonth - 2) / 10) + Integer (T.Day) + Zyy + (Zyy / 4) + (Zcentury / 4) - 2 * Zcentury); end Day_Of_Week; function Day_Of_Week (T : Calendar.Time) return Weekday is begin return Day_Of_Week (Convert_Time (T)); end Day_Of_Week; function "+" (D : Weekday; I : Integer) return Weekday is begin return Make_Weekday (Integer (D) + I); end "+"; function "-" (D : Weekday; I : Integer) return Weekday is begin return Make_Weekday (Integer (D) - I); end "-"; function Duration_Until (T : Calendar.Time) return Duration is begin return Calendar."-" (T, Calendar.Clock); end Duration_Until; function Duration_Until (T : Time) return Duration is begin return Duration_Until (Convert_Time (T)); end Duration_Until; function Duration_Until_Next (H : Military_Hours; M : Minutes := 0; S : Seconds := 0) return Duration is T : Time := Get_Time; D : Duration; Hr : Natural := Natural (H); begin T.Minute := M; T.Second := S; if Hr >= 12 then T.Sun_Position := Pm; Hr := Hr - 12; else T.Sun_Position := Am; end if; if Hr = 0 then T.Hour := 12; else T.Hour := Hours (Hr); end if; D := Duration_Until (T); if D < 0.0 then D := Day + D; end if; return D; end Duration_Until_Next; begin Null_Calendar_Time := Convert_Time (Null_Time); end Time_Utilities;separate (Time_Utilities) package body Interval_Value is function Value (S : String) return Interval is -- format is ddDhh:mm:ss.milli -- upper or lower case D is a deliminator -- all non-numeric non delimiters are ignored -- if only one : is given, it is assumed to separate hrs and seconds -- 10:17 is 10hrs 17min, :10:17 is 0hrs 10min 17sec Position : Natural := S'First; Result : Interval; type Kind_Value is (Day, Hour, Minute, Second, Millisecond, Number); type Item; type Item_Ptr is access Item; type Item is record Kind : Kind_Value; Value : Natural; Next : Item_Ptr; end record; First_Item : Item_Ptr; Last_Item : Item_Ptr; Dot_Observed : Boolean := False; Colons_Observed : Natural := 0; function Is_Digit (Char : Character) return Boolean is begin case Char is when '0' .. '9' => return True; when others => return False; end case; end Is_Digit; function Is_Delimiter (Char : Character) return Boolean is begin case Char is when ':' | 'D' | 'd' | '/' | '.' => return True; when others => return False; end case; end Is_Delimiter; function Get_Number return Item_Ptr is Start : Natural := Position; Last : Natural; function Pad_To_Three_Digits (S : String) return Natural is begin if S'Length = 1 then return Natural'Value (S & "00"); elsif S'Length = 2 then return Natural'Value (S & '0'); else return Natural'Value (S (S'First .. S'First + 2)); end if; end Pad_To_Three_Digits; function Get_Item (N : Natural) return Item_Ptr is begin return new Item'(Kind => Number, Value => N, Next => null); end Get_Item; begin while Position <= S'Last and then Is_Digit (S (Position)) loop Position := Position + 1; end loop; if Position <= S'Last then Last := Position - 1; else Last := S'Last; end if; if Dot_Observed then return Get_Item (Pad_To_Three_Digits (S (Start .. Last))); else return Get_Item (Natural'Value (S (Start .. Last))); end if; end Get_Number; function Get_Item return Item_Ptr is Char : Character; function Item_Value (Ch : Character) return Item_Ptr is Result : Item_Ptr := new Item; begin case Ch is when 'D' | 'd' | '/' => Result.Kind := Day; when ':' => Result.Kind := Hour; Colons_Observed := Colons_Observed + 1; if Colons_Observed > 2 then raise Constraint_Error; end if; when '.' => Result.Kind := Second; Dot_Observed := True; when others => raise Constraint_Error; end case; return Result; end Item_Value; begin while Position <= S'Last loop Char := S (Position); if Is_Delimiter (Char) then Position := Position + 1; return Item_Value (Char); elsif Is_Digit (Char) then return Get_Number; else Position := Position + 1; end if; end loop; return null; end Get_Item; procedure Build_List (First, Last : in out Item_Ptr) is Next_Item : Item_Ptr; begin -- build list of items Next_Item := Get_Item; First := Next_Item; Last := First; loop Next_Item := Get_Item; exit when Next_Item = null; Last.Next := Next_Item; Last := Next_Item; end loop; end Build_List; procedure Normalize (First, Last : in out Item_Ptr) is Hour_Item : Item_Ptr; Next_Item : Item_Ptr := First; procedure Add (Kind : Kind_Value) is New_Item : Item_Ptr := new Item'(Kind, 0, null); begin Last.Next := New_Item; Last := New_Item; end Add; begin if Colons_Observed = 2 or else Dot_Observed then -- find right_most hour and make it minute while Next_Item /= null loop if Next_Item.Kind = Hour then Hour_Item := Next_Item; end if; Next_Item := Next_Item.Next; end loop; if Hour_Item /= null then Hour_Item.Kind := Minute; end if; end if; if Last.Kind = Number then if Dot_Observed then Add (Millisecond); else case Colons_Observed is when 2 => Add (Second); when 1 => Add (Minute); when 0 => Add (Hour); when others => raise Constraint_Error; end case; end if; end if; end Normalize; function Build_Value (First, Last : Item_Ptr) return Interval is Number_Kind : constant Kind_Value := Number; Result : Interval := Null_Interval; Next_Item : Item_Ptr := First; Number : Natural := 0; procedure Get_Number (Ptr : in out Item_Ptr; Value : in out Natural) is begin if Ptr.Kind = Number_Kind then Value := Ptr.Value; Ptr := Ptr.Next; else Value := 0; end if; end Get_Number; procedure Set_Field (Kind : Kind_Value; Number : Natural; Result : in out Interval) is Value : Natural := Number; begin if Value = 0 then return; end if; case Next_Item.Kind is when Day => Result.Elapsed_Days := Result.Elapsed_Days + Day_Count (Value); when Hour => Value := Value + Natural (Result.Elapsed_Hours); Set_Field (Day, Value / 24, Result); Result.Elapsed_Hours := Military_Hours (Value mod 24); when Minute => Value := Value + Natural (Result.Elapsed_Minutes); Set_Field (Hour, Value / 60, Result); Result.Elapsed_Minutes := Minutes (Value mod 60); when Second => Value := Value + Natural (Result.Elapsed_Seconds); Set_Field (Minute, Value / 60, Result); Result.Elapsed_Seconds := Seconds (Value mod 60); when Millisecond => Value := Value + Natural (Result.Elapsed_Milliseconds); Set_Field (Second, Value / 1000, Result); Result.Elapsed_Milliseconds := Milliseconds (Value mod 1000); when others => raise Constraint_Error; end case; end Set_Field; begin while Next_Item /= null loop Get_Number (Next_Item, Number); -- increments next_item (if appropriate) Set_Field (Next_Item.Kind, Number, Result); Next_Item := Next_Item.Next; end loop; return Result; end Build_Value; begin Build_List (First_Item, Last_Item); Normalize (First_Item, Last_Item); return Build_Value (First_Item, Last_Item); end Value; end Interval_Value;separate (Time_Utilities) function Time_Value (S : String) return Time is -- accepts all of the formats output by value -- algorithm consists of parsing for a series of numbers -- and assigning them to positions in the date according -- to heuristics about size and position. -- recognizes unique prefixes of month names Pm_Detected : Boolean := False; Month_Position : Integer := 0; function Value (Month : Positive; Day : Natural; Year : Natural; Hour : Natural; Minute : Natural; Second : Natural) return Time is Result : Time; begin if Year < 100 then Result.Year := Years (Integer'(1900 + Year)); else Result.Year := Years (Year); end if; Result.Month := Months'Val (Month - 1); Result.Day := Days (Day); Result.Minute := Minutes (Minute); Result.Second := Seconds (Second); case Hour is when 0 => Result.Sun_Position := Am; Result.Hour := 12; when 12 => Result.Sun_Position := Pm; Result.Hour := 12; when others => if Hour > 12 then Result.Sun_Position := Pm; Result.Hour := Hours (Hour - 12); else if Pm_Detected then Result.Sun_Position := Pm; else Result.Sun_Position := Am; end if; Result.Hour := Hours (Hour); end if; end case; return Result; end Value; function This_Year return Natural is begin return Natural (Get_Time.Year); end This_Year; function Value (Number : Number_Array) return Time is Now : Time; begin case Number'Length is when 6 => case Month_Position is when 1 => -- May 1, 1985 at 00:00:00 return Value (Number (1), Number (2), Number (3), Number (4), Number (5), Number (6)); when 2 => -- 1-May-85 at 00:00:00 return Value (Number (2), Number (1), Number (3), Number (4), Number (5), Number (6)); when 4 => -- 00:00:00 May 1, 1985 return Value (Number (4), Number (5), Number (6), Number (1), Number (2), Number (3)); when 5 => -- 00:00:00 1-May-85 return Value (Number (5), Number (4), Number (6), Number (1), Number (2), Number (3)); when 0 => -- no alphabetic year given if Number (1) > 23 then -- 85/5/1 00:00:00 return Value (Number (2), Number (3), Number (1), Number (4), Number (5), Number (6)); else -- 5/1/85 00:00:00 return Value (Number (1), Number (2), Number (3), Number (4), Number (5), Number (6)); end if; when others => raise Constraint_Error; end case; when 5 => case Month_Position is when 1 => -- May 1, 1985 at 00:00 return Value (Number (1), Number (2), Number (3), Number (4), Number (5), 0); when 2 => -- 1-May-85 at 00:00 return Value (Number (2), Number (1), Number (3), Number (4), Number (5), 0); when 3 => -- 00:00 May 1, 1985 return Value (Number (3), Number (4), Number (5), Number (1), Number (2), 0); when 5 => -- 00:00:00 1-May return Value (Number (5), Number (4), Natural (Get_Time.Year), Number (1), Number (2), Number (3)); when 0 => -- no alphabetic year given if Number (1) > 23 then -- 85/5/1 00:00 return Value (Number (2), Number (3), Number (1), Number (4), Number (5), 0); elsif Number (3) > 23 then -- 5/1/85 00:00 return Value (Number (1), Number (2), Number (3), Number (4), Number (5), 0); else -- 5/1 00:00:00 return Value (Number (1), Number (2), Natural (Get_Time.Year), Number (3), Number (4), Number (5)); end if; when others => raise Constraint_Error; end case; when 4 => case Month_Position is when 0 | 1 => -- 5/1 00:00 -- May 1 00:00 return Value (Number (1), Number (2), Natural (Get_Time.Year), Number (3), Number (4), 0); when 2 => -- 1-May 00:00 return Value (Number (2), Number (1), Natural (Get_Time.Year), Number (3), Number (4), 0); when others => raise Constraint_Error; end case; when 3 => Now := Get_Time; case Month_Position is when 0 => if Number (1) > 23 then -- 85/5/1 Pm_Detected := Now.Sun_Position = Pm; return Value (Number (2), Number (3), Number (1), Natural (Now.Hour), Natural (Now.Minute), Natural (Now.Second)); elsif Number (3) > 59 then -- 5/1/85 Pm_Detected := Now.Sun_Position = Pm; return Value (Number (1), Number (2), Number (3), Natural (Now.Hour), Natural (Now.Minute), Natural (Now.Second)); else -- 00:00:00 return Value (Natural (Months'Pos (Now.Month) + 1), Natural (Now.Day), Natural (Now.Year), Number (1), Number (2), Number (3)); end if; when 1 => -- May 1, 1985 Pm_Detected := Now.Sun_Position = Pm; return Value (Number (1), Number (2), Number (3), Natural (Now.Hour), Natural (Now.Minute), Natural (Now.Second)); when 2 => -- 1-May-85 Pm_Detected := Now.Sun_Position = Pm; return Value (Number (2), Number (1), Number (3), Natural (Now.Hour), Natural (Now.Minute), Natural (Now.Second)); when others => raise Constraint_Error; end case; when 2 => Now := Get_Time; case Month_Position is when 0 => -- 00:00 return Value (Natural (Months'Pos (Now.Month) + 1), Natural (Now.Day), Natural (Now.Year), Number (1), Number (2), 0); when 1 => -- May 1 Pm_Detected := Now.Sun_Position = Pm; return Value (Number (1), Number (2), Natural (Now.Year), Natural (Now.Hour), Natural (Now.Minute), Natural (Now.Second)); when 2 => -- 1-May Pm_Detected := Now.Sun_Position = Pm; return Value (Number (2), Number (1), Natural (Now.Year), Natural (Now.Hour), Natural (Now.Minute), Natural (Now.Second)); when others => raise Constraint_Error; end case; when others => raise Constraint_Error; end case; end Value; procedure Find_Number (S : String; First : Positive; Position : out Positive; Success : out Boolean) is begin for I in First .. S'Last loop if Is_Numeric (S (I)) then Success := True; Position := I; return; end if; end loop; Position := First; Success := False; end Find_Number; procedure Find_Non_Number (S : String; First : Positive; Position : out Positive) is begin for I in First .. S'Last loop if not Is_Numeric (S (I)) then Position := I; return; end if; end loop; Position := S'Last + 1; end Find_Non_Number; procedure Find_Alphabetic (S : String; First : Positive; Position : out Positive; Success : out Boolean) is begin for I in First .. S'Last loop exit when Is_Numeric (S (I)); if Is_Alphabetic (S (I)) then Success := True; Position := I; return; end if; end loop; Position := First; Success := False; end Find_Alphabetic; procedure Find_Non_Alphabetic (S : String; First : Positive; Position : out Positive) is begin for I in First .. S'Last loop if not Is_Alphabetic (S (I)) then Position := I; return; end if; end loop; Position := S'Last + 1; end Find_Non_Alphabetic; procedure Get_Number (S : String; First : in out Positive; Result : out Natural; Success : out Boolean) is Found : Boolean; Start : Positive; begin Find_Number (S, First, Start, Found); if not Found then Success := False; Result := 0; return; end if; Find_Non_Number (S, Start, First); Success := True; Result := Natural'Value (S (Start .. First - 1)); end Get_Number; procedure Get_Month (S : String; First : in out Positive; Result : out Natural; Success : out Boolean) is Found : Boolean; Start : Natural; Stop : Natural; Prefix : Boolean; M : Months; begin Find_Alphabetic (S, First, Start, Found); if Found then Find_Non_Alphabetic (S, Start, Stop); Unique_Prefix (S (Start .. Stop - 1), M, Prefix, Found); if Found then Result := Months'Pos (M) + 1; First := Stop; Success := True; return; end if; end if; Success := False; Result := 0; exception when others => Result := 0; Success := False; end Get_Month; function Get_Number_Array (S : String) return Number_Array is Result : Number_Array (1 .. 6); First : Positive := S'First; Success : Boolean; I : Integer := Result'First; begin Pm_Detected := String_Utilities.Locate ("PM", S, Ignore_Case => True) /= 0; while I <= Result'Last loop if Month_Position = 0 and then First <= S'Last and then not Is_Numeric (S (First)) then Get_Month (S, First, Result (I), Success); if Success then Month_Position := I; I := I + 1; exit when I > Result'Last; end if; end if; Get_Number (S, First, Result (I), Success); if not Success then return Result (1 .. I - 1); end if; I := I + 1; end loop; return Result; end Get_Number_Array; begin return Value (Get_Number_Array (String_Utilities.Strip (S))); end Time_Value;package Trig_Lib is function Sin (X : Float) return Float; function Cos (X : Float) return Float; function Tan (X : Float) return Float; function Cot (X : Float) return Float; function Asin (X : Float) return Float; function Acos (X : Float) return Float; function Atan (X : Float) return Float; function Atan2 (V, U : Float) return Float; function Sinh (X : Float) return Float; function Cosh (X : Float) return Float; function Tanh (X : Float) return Float; end Trig_Lib;with Text_Io; use Text_Io; with Floating_Characteristics; use Floating_Characteristics; with Numeric_Io; use Numeric_Io; with Numeric_Primitives; use Numeric_Primitives; with Core_Functions; use Core_Functions; package body Trig_Lib is -- PRELIMINARY VERSION ********************************* -- The following routines are coded directly from the algorithms and -- coeficients given in "Software Manual for the Elementry Functions" -- by William J. Cody, Jr. and William Waite, Prentice_Hall, 1980 -- This particular version is stripped to work with FLOAT and INTEGER -- and uses a mantissa represented as a FLOAT -- A more general formulation uses MANTISSA_TYPE, etc. -- The coeficients are appropriate for 25 to 32 bits floating significance -- They will work for less but slightly shorter versions are possible -- The routines are coded to stand alone so they need not be compiled together -- 16 JULY 1982 W A WHITAKER AFATL EGLIN AFB FL 32542 -- T C EICHOLTZ USAFA function Sin (X : Float) return Float is Sgn, Y : Float; N : Integer; Xn : Float; F, G, X1, X2 : Float; Result : Float; Ymax : Float := Float (Integer (Pi * Two ** (It / 2))); Beta : Float := Convert_To_Float (Ibeta); Epsilon : Float := Beta ** (-It / 2); C1 : constant Float := 3.140625; C2 : constant Float := 9.6765_35897_93E-4; function R (G : Float) return Float is R1 : constant Float := -0.16666_66660_883; R2 : constant Float := 0.83333_30720_556E-2; R3 : constant Float := -0.19840_83282_313E-3; R4 : constant Float := 0.27523_97106_775E-5; R5 : constant Float := -0.23868_34640_601E-7; begin return ((((R5 * G + R4) * G + R3) * G + R2) * G + R1) * G; end R; begin if X < Zero then Sgn := -One; Y := -X; else Sgn := One; Y := X; end if; if Y > Ymax then New_Line; Put (" SIN CALLED WITH ARGUMENT TOO LARGE FOR ACCURACY "); New_Line; end if; N := Integer (Y * One_Over_Pi); Xn := Convert_To_Float (N); if N mod 2 /= 0 then Sgn := -Sgn; end if; X1 := Truncate (abs (X)); X2 := abs (X) - X1; F := ((X1 - Xn * C1) + X2) - Xn * C2; if abs (F) < Epsilon then Result := F; else G := F * F; Result := F + F * R (G); end if; return (Sgn * Result); end Sin; function Cos (X : Float) return Float is Sgn, Y : Float; N : Integer; Xn : Float; F, G, X1, X2 : Float; Result : Float; Ymax : Float := Float (Integer (Pi * Two ** (It / 2))); Beta : Float := Convert_To_Float (Ibeta); Epsilon : Float := Beta ** (-It / 2); C1 : constant Float := 3.140625; C2 : constant Float := 9.6765_35897_93E-4; function R (G : Float) return Float is R1 : constant Float := -0.16666_66660_883; R2 : constant Float := 0.83333_30720_556E-2; R3 : constant Float := -0.19840_83282_313E-3; R4 : constant Float := 0.27523_97106_775E-5; R5 : constant Float := -0.23868_34640_601E-7; begin return ((((R5 * G + R4) * G + R3) * G + R2) * G + R1) * G; end R; begin Sgn := 1.0; Y := abs (X) + Pi_Over_Two; if Y > Ymax then New_Line; Put (" COS CALLED WITH ARGUMENT TOO LARGE FOR ACCURACY "); New_Line; end if; N := Integer (Y * One_Over_Pi); Xn := Convert_To_Float (N); if N mod 2 /= 0 then Sgn := -Sgn; end if; Xn := Xn - 0.5; -- TO FORM COS INSTEAD OF SIN X1 := Truncate (abs (X)); X2 := abs (X) - X1; F := ((X1 - Xn * C1) + X2) - Xn * C2; if abs (F) < Epsilon then Result := F; else G := F * F; Result := F + F * R (G); end if; return (Sgn * Result); end Cos; function Tan (X : Float) return Float is Sgn, Y : Float; N : Integer; Xn : Float; F, G, X1, X2 : Float; Result : Float; Ymax : Float := Float (Integer (Pi * Two ** (It / 2))) / 2.0; Beta : Float := Convert_To_Float (Ibeta); Epsilon : Float := Beta ** (-It / 2); C1 : constant Float := 8#1.444#; C2 : constant Float := 4.8382_67948_97E-4; function R (G : Float) return Float is P0 : constant Float := 1.0; P1 : constant Float := -0.11136_14403_566; P2 : constant Float := 0.10751_54738_488E-2; Q0 : constant Float := 1.0; Q1 : constant Float := -0.44469_47720_281; Q2 : constant Float := 0.15973_39213_300E-1; begin return ((P2 * G + P1) * G * F + F) / (((Q2 * G + Q1) * G + 0.5) + 0.5); end R; begin Y := abs (X); if Y > Ymax then New_Line; Put (" TAN CALLED WITH ARGUMENT TOO LARGE FOR ACCURACY "); New_Line; end if; N := Integer (X * Two_Over_Pi); Xn := Convert_To_Float (N); X1 := Truncate (X); X2 := X - X1; F := ((X1 - Xn * C1) + X2) - Xn * C2; if abs (F) < Epsilon then Result := F; else G := F * F; Result := R (G); end if; if N mod 2 = 0 then return Result; else return -1.0 / Result; end if; end Tan; function Cot (X : Float) return Float is Sgn, Y : Float; N : Integer; Xn : Float; F, G, X1, X2 : Float; Result : Float; Ymax : Float := Float (Integer (Pi * Two ** (It / 2))) / 2.0; Beta : Float := Convert_To_Float (Ibeta); Epsilon : Float := Beta ** (-It / 2); Epsilon1 : Float := 1.0 / Xmax; C1 : constant Float := 8#1.444#; C2 : constant Float := 4.8382_67948_97E-4; function R (G : Float) return Float is P0 : constant Float := 1.0; P1 : constant Float := -0.11136_14403_566; P2 : constant Float := 0.10751_54738_488E-2; Q0 : constant Float := 1.0; Q1 : constant Float := -0.44469_47720_281; Q2 : constant Float := 0.15973_39213_300E-1; begin return ((P2 * G + P1) * G * F + F) / (((Q2 * G + Q1) * G + 0.5) + 0.5); end R; begin Y := abs (X); if Y < Epsilon1 then New_Line; Put (" COT CALLED WITH ARGUMENT TOO NEAR ZERO "); New_Line; if X < 0.0 then return -Xmax; else return Xmax; end if; end if; if Y > Ymax then New_Line; Put (" COT CALLED WITH ARGUMENT TOO LARGE FOR ACCURACY "); New_Line; end if; N := Integer (X * Two_Over_Pi); Xn := Convert_To_Float (N); X1 := Truncate (X); X2 := X - X1; F := ((X1 - Xn * C1) + X2) - Xn * C2; if abs (F) < Epsilon then Result := F; else G := F * F; Result := R (G); end if; if N mod 2 /= 0 then return -Result; else return 1.0 / Result; end if; end Cot; function Asin (X : Float) return Float is G, Y : Float; Result : Float; Beta : Float := Convert_To_Float (Ibeta); Epsilon : Float := Beta ** (-It / 2); function R (G : Float) return Float is P1 : constant Float := -0.27516_55529_0596E1; P2 : constant Float := 0.29058_76237_4859E1; P3 : constant Float := -0.59450_14419_3246; Q0 : constant Float := -0.16509_93320_2424E2; Q1 : constant Float := 0.24864_72896_9164E2; Q2 : constant Float := -0.10333_86707_2113E2; Q3 : constant Float := 1.0; begin return (((P3 * G + P2) * G + P1) * G) / (((G + Q2) * G + Q1) * G + Q0); end R; begin return X; end Asin; function Acos (X : Float) return Float is G, Y : Float; Result : Float; Beta : Float := Convert_To_Float (Ibeta); Epsilon : Float := Beta ** (-It / 2); function R (G : Float) return Float is P1 : constant Float := -0.27516_55529_0596E1; P2 : constant Float := 0.29058_76237_4859E1; P3 : constant Float := -0.59450_14419_3246; Q0 : constant Float := -0.16509_93320_2424E2; Q1 : constant Float := 0.24864_72896_9164E2; Q2 : constant Float := -0.10333_86707_2113E2; Q3 : constant Float := 1.0; begin return (((P3 * G + P2) * G + P1) * G) / (((G + Q2) * G + Q1) * G + Q0); end R; begin return X; end Acos; function Atan (X : Float) return Float is F, G : Float; subtype Region is Integer range 0 .. 3; -- ########## N : Region; Result : Float; Beta : Float := Convert_To_Float (Ibeta); Epsilon : Float := Beta ** (-It / 2); Sqrt_3 : constant Float := 1.73205_08075_68877_29353; Sqrt_3_Minus_1 : constant Float := 0.73205_08075_68877_29353; Two_Minus_Sqrt_3 : constant Float := 0.26794_91924_31122_70647; function R (G : Float) return Float is P0 : constant Float := -0.14400_83448_74E1; P1 : constant Float := -0.72002_68488_98; Q0 : constant Float := 0.43202_50389_19E1; Q1 : constant Float := 0.47522_25845_99E1; Q2 : constant Float := 1.0; begin return ((P1 * G + P0) * G) / ((G + Q1) * G + Q0); end R; begin F := abs (X); if F > 1.0 then F := 1.0 / F; N := 2; else N := 0; end if; if F > Two_Minus_Sqrt_3 then F := (((Sqrt_3_Minus_1 * F - 0.5) - 0.5) + F) / (Sqrt_3 + F); N := N + 1; end if; if abs (F) < Epsilon then Result := F; else G := F * F; Result := F + F * R (G); end if; if N > 1 then Result := -Result; end if; case N is when 0 => Result := Result; when 1 => Result := Pi_Over_Six + Result; when 2 => Result := Pi_Over_Two + Result; when 3 => Result := Pi_Over_Three + Result; end case; if X < 0.0 then Result := -Result; end if; return Result; end Atan; function Atan2 (V, U : Float) return Float is X, Result : Float; begin if U = 0.0 then if V = 0.0 then Result := 0.0; New_Line; Put (" ATAN2 CALLED WITH 0/0 RETURNED "); New_Line; elsif V > 0.0 then Result := Pi_Over_Two; else Result := -Pi_Over_Two; end if; else X := abs (V / U); -- If underflow or overflow is detected, go to the exception Result := Atan (X); if U < 0.0 then Result := Pi - Result; end if; if V < 0.0 then Result := -Result; end if; end if; return Result; exception when Numeric_Error => if abs (V) > abs (U) then Result := Pi_Over_Two; if V < 0.0 then Result := -Result; end if; else Result := 0.0; if U < 0.0 then Result := Pi - Result; end if; end if; return Result; end Atan2; function Sinh (X : Float) return Float is begin return X; end Sinh; function Cosh (X : Float) return Float is begin return X; end Cosh; function Tanh (X : Float) return Float is begin return X; end Tanh; begin null; end Trig_Lib;generic Default_Maximum_Length : Natural := 20; package Unbounded_String is ------------------------------------------------------------------------------- -- Managed Pointer Sequential Unbounded Strings: -- Restrictions and assumptions -- Storage management performed -- All new allocations for extensions are twice requirements -- CANNOT be used by multiple tasks unless user guarantees sequential use -- := is reference copy, use copy to assign contents -- uninitialized or Free'd objects are true null's and changes to one -- of the referents will not be reflected in the other; -- use Free prior to assignment to prevent garbage -- = is object identity, use string_utilities for comparison -- ------------------------------------------------------------------------------- subtype String_Length is Natural; type Variable_String is private; -- release storage associated with a string procedure Free (V : in out Variable_String); -- Get information about current length or contents of a string function Length (Source : Variable_String) return String_Length; function Char_At (Source : Variable_String; At_Pos : Positive) return Character; function Extract (Source : Variable_String; Start_Pos : Positive; End_Pos : Natural) return String; function Image (V : Variable_String) return String; function Value (S : String) return Variable_String; -- Image (Target) := Image (Source); procedure Copy (Target : in out Variable_String; Source : Variable_String); procedure Copy (Target : in out Variable_String; Source : String); procedure Copy (Target : in out Variable_String; Source : Character); -- Target := Source; Source := ""; with appropriate storage management procedure Move (Target : in out Variable_String; Source : in out Variable_String); -- Target := Target & Source; procedure Append (Target : in out Variable_String; Source : Variable_String); procedure Append (Target : in out Variable_String; Source : String); procedure Append (Target : in out Variable_String; Source : Character); procedure Append (Target : in out Variable_String; Source : Character; Count : String_Length); -- Target := Target (1..At_Pos-1) & Source & Target (At_Pos..Target'Length) procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : Variable_String); procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : String); procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : Character); procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : Character; Count : String_Length); -- Target (At_Pos .. At_Pos + Count -1) := ""; procedure Delete (Target : in out Variable_String; At_Pos : Positive; Count : String_Length := 1); -- Target (At_Pos .. At_Pos + Source'Length - 1) := Source; procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : Character); procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : Character; Count : String_Length); procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : String); procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : Variable_String); -- Target'Length := New_Length; -- Target (Target'Length .. New_Length) := Fill_With; procedure Set_Length (Target : in out Variable_String; New_Length : String_Length; Fill_With : Character := ' '); private type Pointer is access String; type Real_String; type Variable_String is access Real_String; subtype String_Bound is Integer range -1 .. Integer'Last; type Real_String is record Length : String_Bound; Contents : Pointer; Next_Free : Variable_String; end record; Null_String : Pointer := new String (1 .. 0); Free_List_Item : constant String_Bound := -1; Free_List : Real_String := Real_String'(Free_List_Item, Null_String, new Real_String'(Free_List_Item, Null_String, null)); end Unbounded_String;package body Unbounded_String is function Max (X : Integer; Y : Integer) return Integer is begin if X > Y then return X; else return Y; end if; end Max; pragma Inline (Max); procedure Free (V : in out Variable_String) is begin if V /= null then if V.Length /= Free_List_Item then V.Next_Free := Free_List.Next_Free; V.Length := Free_List_Item; Free_List.Next_Free := V; end if; V := null; end if; end Free; function Length (Source : Variable_String) return String_Length is begin if Source /= null then return Source.Length; else return 0; end if; exception when others => return 0; end Length; function Allocated_Length (Source : Variable_String) return String_Length is begin if Source /= null and then Source.Length /= Free_List_Item then return Source.Contents'Length; else return 0; end if; end Allocated_Length; procedure Real_Allocate (Target : in out Variable_String; Length : String_Length; Room_For_Growth : Boolean := True) is function Allocation (Length : String_Length) return String_Length is begin if Room_For_Growth then return Max (2 * Length, Default_Maximum_Length); else return Max (Length, Default_Maximum_Length); end if; end Allocation; procedure Find (Free : in out Real_String; This : in out Variable_String) is begin This := Free.Next_Free; if This /= null then if This.Contents'Length > Length then Free.Next_Free := This.Next_Free; This.Next_Free := null; else Find (This.all, This); end if; end if; end Find; begin Find (Free_List, Target); if Target = null then Target := new Real_String' (Length => Length, Contents => new String (1 .. Allocation (Length)), Next_Free => null); else Target.Length := Length; Target.Next_Free := null; end if; end Real_Allocate; procedure Move (Target : in out Variable_String; Source : in out Variable_String) is begin Free (Target); Target := Source; Source := null; end Move; procedure Allocate (Target : in out Variable_String; Length : String_Length; Preserve_Contents : Boolean := True) is Max_Length : String_Length := Allocated_Length (Target); begin -- check for alias of freed string and remove pointer to free list if Max_Length = 0 then Real_Allocate (Target, Length, Room_For_Growth => False); elsif Max_Length >= Length then Target.Length := Length; else declare Temp : Variable_String; begin Real_Allocate (Temp, Length, Preserve_Contents); if Preserve_Contents then Temp.Contents (1 .. Target.Length) := Target.Contents (1 .. Target.Length); end if; Move (Target, Temp); end; end if; end Allocate; function Value (S : String) return Variable_String is Result : Variable_String; begin Real_Allocate (Result, S'Length, Room_For_Growth => False); Copy (Result, S); return Result; end Value; procedure Copy (Target : in out Variable_String; Source : Variable_String) is begin Copy (Target, Image (Source)); end Copy; procedure Copy (Target : in out Variable_String; Source : String) is begin Allocate (Target, Source'Length, Preserve_Contents => False); declare T : Real_String renames Target.all; begin T.Contents (1 .. Source'Length) := Source; T.Length := Source'Length; end; end Copy; procedure Copy (Target : in out Variable_String; Source : Character) is begin Allocate (Target, 1, Preserve_Contents => False); Target.Contents (1) := Source; end Copy; function Image (V : Variable_String) return String is begin return V.all.Contents (1 .. V.all.Length); exception when others => return String'(1 .. 0 => ' '); end Image; procedure Append (Target : in out Variable_String; Source : String) is Len : String_Length := Length (Target); begin Allocate (Target, Len + Source'Length, Preserve_Contents => True); declare T : Real_String renames Target.all; begin T.Contents (Len + 1 .. T.Length) := Source; end; end Append; procedure Append (Target : in out Variable_String; Source : Variable_String) is begin Append (Target, Image (Source)); end Append; procedure Append (Target : in out Variable_String; Source : Character) is Len : String_Length := Length (Target) + 1; begin Allocate (Target, Len, Preserve_Contents => True); Target.Contents (Len) := Source; end Append; procedure Append (Target : in out Variable_String; Source : Character; Count : String_Length) is Value_String : String (1 .. Count) := String'(1 .. Count => Source); begin Append (Target, Value_String); end Append; procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : String) is Len : String_Length := Length (Target); begin if At_Pos = Len + 1 then Append (Target, Source); elsif At_Pos <= Len then Allocate (Target, Len + Source'Length); declare T : Real_String renames Target.all; begin T.Contents (At_Pos .. T.Length) := Source & T.Contents (At_Pos .. Len); end; else raise Constraint_Error; end if; end Insert; procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : Variable_String) is begin Insert (Target, At_Pos, Image (Source)); end Insert; procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : Character) is Len : String_Length := Length (Target) + 1; begin if At_Pos = Len then Append (Target, Source); elsif At_Pos > Len then raise Constraint_Error; else Allocate (Target, Len, Preserve_Contents => True); declare T : Real_String renames Target.all; begin T.Contents (At_Pos + 1 .. Len) := T.Contents (At_Pos .. Len - 1); T.Contents (At_Pos) := Source; end; end if; end Insert; procedure Insert (Target : in out Variable_String; At_Pos : Positive; Source : Character; Count : String_Length) is Value_String : String (1 .. Count) := String'(1 .. Count => Source); begin Insert (Target, At_Pos, Value_String); end Insert; procedure Delete (Target : in out Variable_String; At_Pos : Positive; Count : String_Length := 1) is T : Real_String renames Target.all; Len : String_Length := T.Length - Count; begin if At_Pos - 1 > Len then raise Constraint_Error; end if; if At_Pos <= Len then T.Contents (At_Pos .. Len) := T.Contents (At_Pos + Count .. T.Length); end if; T.Length := Len; end Delete; procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : Character) is T : Real_String renames Target.all; begin if At_Pos > T.Length then raise Constraint_Error; else T.Contents (At_Pos) := Source; end if; end Replace; procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : String) is T : Real_String renames Target.all; End_Pos : constant Natural -- not positive JMK 28 Sep 84 := At_Pos + Source'Length - 1; begin if End_Pos > T.Length then raise Constraint_Error; else T.Contents (At_Pos .. End_Pos) := Source; end if; end Replace; procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : Character; Count : String_Length) is Value_String : String (1 .. Count) := String'(1 .. Count => Source); begin Replace (Target, At_Pos, Value_String); end Replace; procedure Replace (Target : in out Variable_String; At_Pos : Positive; Source : Variable_String) is begin Replace (Target, At_Pos, Image (Source)); end Replace; procedure Set_Length (Target : in out Variable_String; New_Length : String_Length; Fill_With : Character := ' ') is Current_Length : String_Length := Length (Target); begin if New_Length > Current_Length then Allocate (Target, New_Length, Preserve_Contents => True); declare C : String renames Target.Contents.all; begin for I in Current_Length + 1 .. New_Length loop C (I) := Fill_With; end loop; end; elsif Target /= null then Target.Length := New_Length; end if; end Set_Length; function Char_At (Source : Variable_String; At_Pos : Positive) return Character is S : Real_String renames Source.all; begin if At_Pos > S.Length then raise Constraint_Error; else return S.Contents (At_Pos); end if; end Char_At; function Extract (Source : Variable_String; Start_Pos : Positive; End_Pos : Natural) return String is begin if End_Pos > Source.Length then raise Constraint_Error; else return Source.Contents (Start_Pos .. End_Pos); end if; end Extract; end Unbounded_String