SELECTION (CASE)


1. OVERVIEW

An "if-else" statement supports selection from only two alternatives; we can of course nest such statements or use constructs such as "if-elsif-else", but it is usually more succinct to use a case statement. Case statements allow selection from many alternatives where each alternative is linked to a predicate, referred to as a selector, which when evaluated to true causes an associated program statement (or statements) to be executed.

2. ADA CASE STATEMENT

In Ada the general format of a case statement is as follows:

case SELECTOR is
        when  `=>' 
        ...
end case;

Selections may be made according to:

  1. A distinct value of a given selector.
  2. A number of alternatives (each separated by a bar |).
  3. Ranges expressed using the .. operator.
  4. A default value.

Selectors must be of a discrete type (such as an integer or a character). Example case statement:

case N is
        when 0 =>
                PUT_LINE("N equals 0");
        when 1 | 5 =>
                PUT_LINE("N equals 1 or 5");
        when 2..4 =>
                PUT_LINE("N equals 2, 3 or 4");
        when others =>
                PUT_LINE("N less than 0 or greater than 5");
end case;

where N is of type integer. The above states that:


3. EXAMPLE PROBLEM CALCULATOR

(Reference: Skansholm 1997, pp129-130).


3.1. Requirements

Design and develop a simple calculator Ada program. The calculator should be able to resolve simple arithmetic expressions of the form:

< OPERAND > < OPERATOR > < OPERAND >

Where < OPERAND > is an integer of some kind and < OPERATOR > is one of the operators `+', `-', `*' or `/' (integer division). Thus given the expression:

63*35

The program should calculate the value of the expression and display the result.

Note: remember to include a divide by zero test.


3.2. Design

A top down analysis of the problem is given below:

TOP DOWN ANALYSIS

We have established that the default integer range is -2147483647..2147483647. Thus the highest value that we can compute is 14654*14654 (14655*14655 > 2147483647), and the lowest value is -14654*14654 (-14654*14654 < -2147483647). Will therefore define the operands as subtypes of the type integer with a range of -14654..14654. We will implement this analysis using the following three procedures:

  1. CALCULATOR (top level procedure) - Read expression and call MAKE_CALCULATION procedure. Definition for subtype OPERAND_T.
    NAMEDESCRIPTIONTYPERANGE
    OPERAND_1Global input variableOPERAND_T-14654..14654
    OPERAND_2Global input variableOPERAND_T-14654..14654
    OPERATOR Global input variableCHARACTERDefault
  2. MAKE_CALCULATION (level 2 procedure) - case statement to direct arithmetic operation, implementation of addition, subtraction and multiplication, call to DIVISION procedure.
    NAMEDESCRIPTIONTYPERANGE
    OPERAND_1Formal parameteOPERAND_T-14654..14654
    OPERAND_2Formal parameteOPERAND_T-14654..14654
    SELECTORFormal parameteCHARACTERDefault
  3. DIVISION (level 3 procedure) - test for divide by zero and implement division.
    NAMEDESCRIPTIONTYPERANGE
    OP_1Formal parameterOPERAND_T-14654..14654
    OP_2Formal parameterOPERAND_T-14654..14654

A complete Nassi-Shneiderman design for the above is given below. Note how the case statement is included in the design.

NASSI_SHNEIDERMAN CHART

The flow of control associated with this design is indicated by the data flow diagram given below. There is not an official construct to indicate a case statement in a DFD, however, the construct given below adequately allows us to identify the paths through the proposed software.

FLOW CHART

3.3. Implementation

As with all top down designs we commence the implementation at the highest level:

-- CALCULATOR
-- 7 August 1997
-- Frans Coenen
-- Dept Computer Science, University of Liverpool

with TEXT_IO;
use TEXT_IO;

procedure CALCULATOR is
    subtype OPERAND_T is INTEGER range -14654..14654;
    package INTEGER_INOUT is new INTEGER_IO(INTEGER);
    use INTEGER_INOUT;
    OPERAND_1, OPERAND_2 : OPERAND_T;
    OPERATOR             : CHARACTER;

    -----------------------------------------------------------------
    -- MAKE_CALCULATION procedure to direct calculation
    procedure MAKE_CALCULATION(OPERAND_1: OPERAND_T; OPERATOR: CHARACTER;
            OPERAND_2: OPERAND_T) is
    begin
        PUT_LINE("In MAKE_CALCULATION");
        PUT("  OPERAND_1 = ");
        PUT(OPERAND_1);
        NEW_LINE;
        PUT("  OPERATOR = ");
        PUT(OPERATOR);
        NEW_LINE;
        PUT("  OPERAND_2 = ");
        PUT(OPERAND_2);
        NEW_LINE;
    end MAKE_CALCULATION;
    -----------------------------------------------------------------

-- TOP LEVEL
begin
-- Input expression
    PUT_LINE("Write a simple arithmetic expression: ");
    GET(OPERAND_1);
    GET(OPERATOR);
    GET(OPERAND_2);
-- Process expression
    MAKE_CALCULATION(OPERAND_1,OPERATOR,OPERAND_2);
end CALCULATOR;

We should now test this part of the implementation. No calculation is carried out at this stage, however we are in a position to carry out some BVA and limit testing. A set of appropriate test cases is given in the Table below.

TEST CASEEXPECTED RESULT
OPERAND_1OPERATOROPERAND_2OUTPUT
-14655 * * CONSTRAINT_ERROR
14655 * * CONSTRAINT_ERROR
-14653 + -14655CONSTRAINT_ERROR
14653 - 14655CONSTRAINT_ERROR
-14653 * -14653OK
14653 \ 14653OK

The second part of the implementation is as follows (we will implement levels 2 and 3 together).

-- CALCULATOR
-- 7 August 1997
-- Frans Coenen
-- Dept Computer Science, University of Liverpool

with TEXT_IO;
use TEXT_IO;

procedure CALCULATOR is
    subtype OPERAND_T us INTEGER range -14654..14654;
    package INTEGER_INOUT is new INTEGER_IO(INTEGER);
    use INTEGER_INOUT;
    OPERAND_1, OPERAND_2 : INTEGER;
    OPERATOR             : CHARACTER;

    -----------------------------------------------------------------------
    -- MAKE_CALCULATION procedure to direct calculation
    procedure MAKE_CALCULATION(OP_1: OPERAND_T; SELECTOR: CHARACTER;
            OP_2: OPERAND_T) is
        -------------------------------------------------------------------
        -- DIVIDE BY ZERO CHECK
        procedure DIVISION(OP_1, OP_2: OPERAND_T) is
        begin
            if (OP_2 /= 0) then
                PUT(OP_1 / OP_2);
            else
                PUT("Divide by zero not permitted");
            end if;
        end DIVISION;
        -------------------------------------------------------------------
    begin
        case SELECTOR is
            when '+' =>
                PUT(OP_1 + OP_2);
            when '-' =>
                PUT(OP_1 - OP_2);
            when '*' =>
                PUT(OP_1 * OP_2);
            when '/' =>
                DIVISION(OP_1,OP_2);
            when others =>
                PUT("Unrecognised operator: ");
                PUT(SELECTOR);
        end case;
        NEW_LINE;
    end MAKE_CALCULATION;
    -----------------------------------------------------------------------

-- TOP LEVEL
begin
-- Input expression
    PUT_LINE("Write a simple arithmetic expression: ");
    GET(OPERAND_1);
    GET(OPERATOR);
    GET(OPERAND_2);
-- Process expression
    MAKE_CALCULATION(OPERAND_1,OPERATOR,OPERAND_2);
end CALCULATOR;

3.4. Testing


3.4.1. Black box testing

BVA and Limit Testing: Already undertaken after the top level implementation.

Arithmetic testing: We should also include test to ensure the correct operation of the arithmetic expressions (it is not good practice to assume that such simple expressions will operate correctly). Thus the following test cases would be appropriate.

TEST CASEEXPECTED RESULT
OPERAND_1OPERATOROPERAND_2OUTPUT
3+36
3+03
3+-30
0+33
0+00
0+-3-3
-3+30
-3+0-3
-3+-3-6
Addition

TEST CASEEXPECTED RESULT
OPERAND_1OPERATOROPERAND_2OUTPUT
3-30
3-03
3--36
0-3-3
0-00
0--33
-3-3-6
-3-0-3
-3--30
Subtraction

TEST CASEEXPECTED RESULT
OPERAND_1OPERATOROPERAND_2OUTPUT
3*39
3*00
3*-3-9
0*30
0*00
0*-30
-3*3-9
-3*00
-3*-39
Multiplication

TEST CASEEXPECTED RESULT
OPERAND_1OPERATOROPERAND_2OUTPUT
3/31
3/0Divide by zero error
3/-3-1
0/30
0/0Divide by zero error
0/-30
-3/3-1
-3/0Divide by zero error
-3/-31
Division

3.4.2. White box testing

Path Testing: The above code should be tested so that each path through the code (resulting from the case statement and the if-else statement) is tested. A suggested set of test cases is given in the table below. All these test cases, except the last, will already have been run as part of black box testing strategies and therefore do not need to be run again.

TEST CASEEXPECTED RESULT
OPERAND_1OPERATOROPERAND_2OUTPUT
3+36
3-30
3*39
3/0Error message
3/31
3^3Error message

3.4.3. Data validation testing

This should also be done.


Example Problem Calculator Report.


4. FURTHER EXAMPLE PROBLEMS USING CASE STATEMENTS

Example Problem Temperature Conversion Plus Report.




Created and maintained by Frans Coenen. Last updated 11 October 1999