Requesting and reading numeric input robustly is a very common requirement in programs. It therefore makes sense to consider how we can "package" robust input so that it can just be used, instead of rewritten, for each program needing to do it.
We will do this by analogy with the Ada.Text_IO
libraries,
specifically the Ada.Integer_Text_IO
and
Ada.Float_Text_IO
instances we have been using all along in this
book. These standard packages read input values by calls to procedures that are
called Get
(recall that because of overloading, these procedures
can all have the same name provided they have dfferent parameter profiles). We
shall write a package, Robust_Input
, which provides the necessary
robust Get
operations for integer and floating-point values.
Program
6.10 gives the package specification for Robust_Input
. There
are two procedures, both called Get
(this is permitted because of
the overloading principle). Here is the one for integer input:
PROCEDURE Get (Item : OUT Integer; MinVal : IN Integer; MaxVal : IN Integer);This procedure will read an integer value from the keyboard and return it to the caller in the actual parameter corresponding to
Item
. The other
two parameters specify the range of acceptable input. The procedure
Get
for floating-point values is analogous.
Program 6.10
PACKAGE Robust_Input IS ------------------------------------------------------------------------ --| Package for getting numeric input robustly. --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ PROCEDURE Get (Item : OUT Integer; MinVal : IN Integer; MaxVal : IN Integer); -- Gets an integer value in the range MinVal..MaxVal from the terminal -- Pre: MinVal and MaxVal are defined -- Post: MinVal <= Item <= MaxVal PROCEDURE Get (Item : OUT Float; MinVal : IN Float; MaxVal : IN Float); -- Gets a float value in the range MinVal..MaxVal from the terminal -- Pre: MinVal and MaxVal are defined -- Post: MinVal <= Item <= MaxVal END Robust_Input;
Program 6.11
gives the package body for Robust_Input
. It consists of the bodies
of the two procedures promised in the procedure specification. Note that in the
body for the integer Get
, a subtype is declared corresponding to
the range parameters, and a corresponding variable:
SUBTYPE TempType IS Integer RANGE MinVal..MaxVal; TempItem : TempType; -- temporary copy of MinValThe statement sequence of this procedure is very similar to that of Program 6.9; a loop is used to retain control if an exception is raised. The subtype
TempType
and variable TempItem
are necessary
so that if the input value produced by Ada.Integer_Text_IO.Get
is
out of range, Constraint_Error
will be raised.
Program 6.11
WITH Ada.Text_IO; WITH Ada.Integer_Text_IO; WITH Ada.Float_Text_IO; PACKAGE BODY Robust_Input IS ------------------------------------------------------------------------ --| Body of package for robust numeric input handling --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ PROCEDURE Get (Item : OUT Integer; MinVal : IN Integer; MaxVal : IN Integer) IS SUBTYPE TempType IS Integer RANGE MinVal..MaxVal; TempItem : TempType; -- temporary copy of MinVal BEGIN -- Get LOOP BEGIN -- exception-handler block Ada.Text_IO.Put(Item => "Enter an integer between "); Ada.Integer_Text_IO.Put(Item => MinVal, Width => 0); Ada.Text_IO.Put(Item => " and "); Ada.Integer_Text_IO.Put(Item => MaxVal, Width => 0); Ada.Text_IO.Put(Item => " > "); Ada.Integer_Text_IO.Get(Item => TempItem); Item := TempItem; EXIT; -- valid data EXCEPTION -- invalid data WHEN Constraint_Error => Ada.Text_IO.Put (Item => "Value entered out of range. Please try again."); Ada.Text_IO.New_Line; Ada.Text_IO.Skip_Line; WHEN Ada.Text_IO.Data_Error => Ada.Text_IO.Put (Item => "Value entered not an integer. Please try again."); Ada.Text_IO.New_Line; Ada.Text_IO.Skip_Line; END; -- exception-handler block END LOOP; -- assert: Item is in the range MinVal to MaxVal END Get; PROCEDURE Get (Item : OUT Float; MinVal : IN Float; MaxVal : IN Float) IS SUBTYPE TempType IS Float RANGE MinVal..MaxVal; TempItem : TempType; -- temporary copy of MinVal BEGIN -- Get LOOP BEGIN -- exception-handler block Ada.Text_IO.Put (Item => "Enter a floating-point value between "); Ada.Float_Text_IO.Put(Item => MinVal, Fore=>1, Aft=>2, Exp=>0); Ada.Text_IO.Put(Item => " and "); Ada.Float_Text_IO.Put(Item => MaxVal, Fore=>1, Aft=>2, Exp=>0); Ada.Text_IO.Put(Item => " > "); Ada.Float_Text_IO.Get(Item => TempItem); Item := TempItem; EXIT; -- valid data EXCEPTION -- invalid data WHEN Constraint_Error => Ada.Text_IO.Put (Item => "Value entered out of range. Please try again."); Ada.Text_IO.New_Line; Ada.Text_IO.Skip_Line; WHEN Ada.Text_IO.Data_Error => Ada.Text_IO.Put (Item => "Value entered not float. Please try again."); Ada.Text_IO.New_Line; Ada.Text_IO.Skip_Line; END; -- exception-handler block END LOOP; -- assert: Item is in the range MinVal to MaxVal END Get; END Robust_Input;Finally, Program 6.12 serves to test the package operations. Two integer and two floating-point subtypes are declared; the
Robust_Input
operations
are called. This is an example of a "test driver" program, whose purpose is
just to test the operations provided by a package.
Program 6.12
WITH Robust_Input; PROCEDURE Test_Robust_Input IS ------------------------------------------------------------------------ --| Demonstrates Robust_Input package --| Author: Michael B. Feldman, The George Washington University --| Last Modified: July 1995 ------------------------------------------------------------------------ SUBTYPE SmallInt IS Integer RANGE -10 ..10; SUBTYPE LargerInt IS Integer RANGE -100..100; SUBTYPE SmallFloat IS Float RANGE -10.0 ..10.0; SUBTYPE LargerFloat IS Float RANGE -100.0..100.0; Small : SmallInt; SmallF : SmallFloat; Larger : LargerInt; LargerF : LargerFloat; BEGIN -- Test_Robust_Input Robust_Input.Get(Small,SmallInt'First,SmallInt'Last); Robust_Input.Get(Larger,LargerInt'First,LargerInt'Last); Robust_Input.Get(SmallF,SmallFloat'First,SmallFloat'Last); Robust_Input.Get(LargerF,LargerFloat'First,LargerFloat'Last); END Test_Robust_Input;Sample Run
Enter an integer between -10 and 10 > 11 Value entered is out of range. Please try again. Enter an integer between -10 and 10 > -11 Value entered is out of range. Please try again. Enter an integer between -10 and 10 > 10 Enter an integer between -100 and 100 > 101 Value entered is out of range. Please try again. Enter an integer between -100 and 100 > 99 Enter a floating-point value between -10.00 and 10.00 > 10.001 Value entered out of range. Please try again. Enter a floating-point value between -10.00 and 10.00 > -12 Value entered out of range. Please try again. Enter a floating-point value between -10.00 and 10.00 > x Value entered not float. Please try again. Enter a floating-point value between -10.00 and 10.00 > 0 Enter a floating-point value between -100.00 and 100.00 > 5.0003
BEGIN
and END
. Is
this correct as far as the Ada compiler is concerned? If so, describe the
difference in behavior from the original.
PROCEDURE Get (Item : OUT Integer; MinVal : IN Integer; MaxVal : IN Integer) IS SUBTYPE TempType IS Integer RANGE MinVal..MaxVal; TempItem : TempType; -- temporary copy of MinVal BEGIN -- Get Ada.Text_IO.Put(Item => "Enter an integer between "); Ada.Integer_Text_IO.Put(Item => MinVal, Width => 0); Ada.Text_IO.Put(Item => " and "); Ada.Integer_Text_IO.Put(Item => MaxVal, Width => 0); Ada.Text_IO.Put(Item => " > "); Ada.Integer_Text_IO.Get(Item => TempItem); Item := TempItem; EXCEPTION -- invalid data WHEN Constraint_Error => Ada.Text_IO.Put ("Value entered out of range. Try again."); Ada.Text_IO.New_Line; Ada.Text_IO.Skip_Line; WHEN Ada.Text_IO.Data_Error => Ada.Text_IO.Put ("Value entered not an integer. Try again."); Ada.Text_IO.New_Line; Ada.Text_IO.Skip_Line; END Get;
Copyright © 1996 by Addison-Wesley Publishing Company, Inc.