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

7.6 Control Structures: The CASE Statement

The CASE statement is used in Ada to select one of several alternatives. It is especially useful when the selection is based on the value of a single variable or a simple expression. The type of this variable or expression must be discrete. that is, it must be an integer or enumeration type or subtype.

Example 7.26

The CASE statement

    CASE MomOrDad IS
        WHEN 'M' => 
        	Ada.Text_IO.Put (Item => "Hello Mom - Happy Mother's Day");
        WHEN 'D' =>
        	Ada.Text_IO.Put (Item => "Hello Dad - Happy Father's Day");
        WHEN OTHERS =>
        	Ada.Text_IO.Put (Item => "invalid character ");
        	Ada.Text_IO.Put (Item => MomOrDad);
    END CASE;

has the same behavior as the IF statement below:

    IF MomOrDad = 'M' THEN
        Ada.Text_IO.Put (Item => "Hello Mom - Happy Mother's Day");
    ELSIF MomOrDad = 'D' THEN
        Ada.Text_IO.Put (Item => "Hello Dad - Happy Father's Day");
    ELSE
        Ada.Text_IO.Put (Item => "invalid character ");
        Ada.Text_IO.Put (Item => MomOrDad);
    END IF;
The message displayed by the CASE statement depends on the value of the CASE selector MomOrDad. If the CASE selector matches the first CASE choice, 'M', the first message is displayed. If the CASE selector matches the second CASE choice, 'D', the second message is displayed. Otherwise, the WHEN OTHERS clause is executed.

The WHEN OTHERS choice is necessary whenever the other choices of the CASE statement do not exhaust all possible values of the selector; if it were not present in this case (assuming MomOrDad is type Character), a compilation error would arise.

Example 7.27

Given the enumeration type Days

    TYPE Days IS ( Mon, Tue, Wed, Thu, Fri, Sat, Sun);

if Today is of type Days, the CASE statement below displays the full name of a day of the week:

    CASE Today IS
        WHEN Mon =>
        	Ada.Text_IO.Put (Item => "Monday");
        WHEN Tue =>
        	Ada.Text_IO.Put (Item => "Tuesday");
        WHEN Wed =>
        	Ada.Text_IO.Put (Item => "Wednesday");
        WHEN Thu =>
        	Ada.Text_IO.Put (Item => "Thursday");
        WHEN Fri =>
        	Ada.Text_IO.Put (Item => "Friday");
        WHEN Sat =>
        	Ada.Text_IO.Put (Item => "Saturday");
        WHEN Sun =>
    	    Ada.Text_IO.Put (Item => "Sunday");
    END CASE;

Seven different choices are shown in this program; the value of OneDay (type Day) is used to select one of these for execution. The seven possible values of OneDay are listed in CASE choices; the task for that CASE choices, a sequence of statements, follows the => ("arrow") symbol. Because all seven values of Today are listed in CASE choices, no WHEN OTHERS is necessary. After the appropriate Ada.Text_IO.Put statement is executed, the CASE statement and procedure are exited.

Example 7.28

The CASE statement below could be used to compute the numeric value of the hexadecimal digit stored in HexDigit (type Character). In the hexadecimal number system, the valid "digits" are the characters '0' through '9' and 'A' through 'F'. The characters '0' through '9' have the numeric value 0 through 9; the characters 'A' through 'F' have the numeric values 10 (for 'A') through 15 (for 'F').

    CASE HexDigit IS
        WHEN '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' =>
        	Decimal := Character'Pos(HexDigit) - Character'Pos('0') ;
        WHEN 'A'|'B'|'C'|'D'|'E'|'F' =>
        	Decimal := Character'Pos( HexDigit)-Character'Pos('A') + 10;
        WHEN OTHERS =>
        	Ada.Text_IO.Put (Item => "Illegal hexadecimal digit ");  
        	Ada.Text_IO.Put (Item =>HexDigit);  
        	Ada.Text_IO.New_Line;
    END CASE;

This CASE statement causes the first assignment statement to be executed when HexDigit is one of the digits '0' through '9'; the second assignment statement is executed when HexDigit is one of the letters 'A' through 'F'. If HexDigit is not one of the characters listed above, the WHEN OTHERS alternative executes and displays an error message.

We can use range notation to abbreviate CASE choices. The CASE statement of Example 7.28 is rewritten below using ranges.

    CASE HexDigit IS
        WHEN '0'..'9' =>
        	Decimal := Character'Pos( HexDigit) - Character'Pos('0') ;
        WHEN 'A'..'F' =>
    	    Decimal := Character'Pos( HexDigit)-Character'Pos('A') + 10;
        WHEN OTHERS =>
        	Ada.Text_IO.Put (Item => "Illegal hexadecimal digit ");  
        	Ada.Text_IO.Put (Item =>HexDigit);  
        	Ada.Text_IO.New_Line;
    END CASE;

Example 7.29

A CASE statement can be used in a student transcript program that computes grade point average (GPA). For each case shown, the total points (Points) earned toward the GPA increase by an amount based on the letter grade (Grade); the total credits earned toward graduation (GradCredits) increase by 1 if the course is passed. The expression

    Character'Pos('A') - Character'Pos(Grade) + 4

evaluates to 4 when the Grade is 'A', 3 when Grade is 'B', and so on.

    CASE Grade IS
        WHEN 'A'..'D'  => 
        	Points := Points+Character'Pos('A')-Character'Pos(Grade)+4;		GradCredits := GradCredits + 1;
        WHEN 'P' =>
        	GradCredits := GradCredits + 1;
        WHEN 'F', 'I', 'W' =>
        	Ada.Text_IO.Put (Item => "No points to GPA or graduation");
        	Ada.Text_IO.New_Line;
        WHEN OTHERS =>
        	Ada.Text_IO.Put (Item => "Illegal grade ");  
        	Ada.Text_IO.Put (Item =>grade);  
        	Ada.Text_IO.New_Line;
    END CASE;

A grade of A through D earns a variable number of points (4 for an A, 3 for a B, etc.) and one graduation credit; a grade of P earns one graduation credit; and a grade of F, I, or W earns neither graduation credits nor points. The WHEN OTHERS clause displays an error message if the program user enters a grade that is not listed in a CASE choice.

Example 7.30

Given an enumeration type

    TYPE Months IS
      ( Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
and variables ThisYear in the range 1901..2099 (the range of Year_Number in Calendar), DaysInMonth of type Positive, and ThisMonth of type Months, this CASE statement saves in DaysInMonth the number of days in ThisMonth:
    CASE ThisMonth IS
        WHEN Feb => 
        	IF (ThisYear MOD 4 = 0) AND
        	   ((ThisYear MOD 100 /= 0) OR (ThisYear MOD 400 = 0)) THEN
        		NumberOfDays := 29;             -- leap year
        	ELSE
        		NumberOfDays := 28;
        	END  IF;
        WHEN Apr | Jun | Sep | Nov => 
        	NumberOfDays := 30;
        WHEN Jan | Mar | May | Jul | Aug | Oct | Dec => 
        	NumberOfDays := 31;
    END CASE;

Because all values of ThisMonth are covered in the choices, no WHEN OTHERS is needed.

SYNTAX DISPLAY
CASE Statement

Form:
CASE selector IS
    WHEN choice1 =>
    	 statement sequence1  

    WHEN choice2 => 
    	statement sequence2  
    	. 
    	. 
    	. 
    WHEN choicen  =>
	    statement sequencen  
    WHEN OTHERS =>
    	statement sequence0 
END CASE;  

Example:
CASE N IS
    WHEN 1 | 2 =>
    	Ada.Text_IO.Put (Item => "Buckle my shoe");
    WHEN 3 | 4 =>
    	Ada.Text_IO.Put (Item => "Shut the door");
    WHEN 5 | 6 =>
    	Ada.Text_IO.Put (Item => "Pick up sticks");
    WHEN OTHERS =>
    	Ada.Text_IO.Put (Item => "Forget it...");
END CASE; 

Interpretation:
The selector expression is evaluated and compared to each of the CASE choices. Each choice is a list of one or more possible values for the selector. Only one statement sequence will be executed; if the selector value is listed in choicei, statement sequencei is executed. If the selector value is not listed in any choicei, statement sequence0 is executed. Control is next passed to the first statement following the END CASE.

Notes:
1. A WHEN OTHERS alternative must be present if the other choices do not cover all possible values in the type of selector.

2. A particular selector value may appear in, at most, one choicei.

3. The type of each value listed in choicei must correspond to the type of the selector expression.

4. Any discrete data type is permitted as the selector type.

PROGRAM STYLE
Comparison of the IF and the CASE Statements
You can use an IF-THEN-ELSIF statement, which is more general than the CASE statement, to implement a multiple-alternative decision. The CASE statement, however, is more readable and should be used whenever practical.

You should use the CASE statement when each case choice contains a list of values of reasonable size (ten or less). However, if the number of values in a case choice is large or there are large gaps in those values, an IF-THEN-ELSIF structure may be better.

Exercises for Section 7.6

Self-Check

  1. Write an IF statement that corresponds to the CASE statement below.
    CASE X > Y IS
        WHEN True  =>
        	Ada.Text_IO.Put(Item => "X greater");
        WHEN False =>
        	Ada.Text_IO.Put(Item => "Y greater or equal");
    END CASE;
    

Programming

  1. Rewrite the CASE statement in Example 7.28 as an IF structure.
  2. If type Color is defined as the enumeration type (Red, Green, Blue, Brown, Yellow), write a CASE statement that assigns a value to Eyes (type Color), given that the first two letters of the color name are stored in Letter1 and Letter2.
  3. Write a CASE statement that displays a message indicating whether NextCh (type Character) is an operator symbol (+, -, *, =, <, >, /), a punctuation symbol (comma, semicolon, parenthesis, brace, bracket), or a digit. Your statement should display the category selected. Write the equivalent IF statement.


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

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