Previous | Next | Table of Contents | Index | Program List | Copyright

6.7 System Structures: A Package for Robust Input

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
Specification for Package Robust_Input

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 MinVal
The 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
Body of Package Robust_Input

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
A Program that Uses Robust_Input

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

Exercises for Section 6.7

Self-Check

  1. The following procedure is like the ones in Program 6.11 but does not have a loop or special block for the exception handlers; the handlers are just written to go with the procedure's 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;      
    


Previous | Next | Table of Contents | Index | Program List | Copyright

Copyright © 1996 by Addison-Wesley Publishing Company, Inc.