Next: Mixing Objects of Different
Up: Control Flow
Previous: Scope of DO Variables
The SELECT CASE Construct is similar to an IF construct. It is
a useful control construct if one of several paths through an
algorithm must be chosen based on the value of a particular expression.
SELECT CASE (i)
CASE (3,5,7)
PRINT*,"i is prime"
CASE (10:)
PRINT*,"i is > 10"
CASE DEFAULT
PRINT*, "i is not prime and is < 10"
END SELECT
The first branch is executed if i is equal to 3, 5 or
7, the second if i is greater than or equal to 10 and the
third branch if neither of the previous has already been executed.
A slightly more complex example with the corresponding IF structure
given as a comment,
SELECT CASE (num)
CASE (6,9,99,66)
! IF(num==6.OR. .. .OR.num==66) THEN
PRINT*, "Woof woof"
CASE (10:65,67:98)
! ELSEIF((num.GE.10.AND.num.LE.65) .OR. ...
PRINT*, "Bow wow"
CASE (100:)
! ELSEIF (num.GE.100) THEN
PRINT*, "Bark"
CASE DEFAULT
! ELSE
PRINT*, "Meow"
END SELECT
! ENDIF
Important points are,
- the < case-expr > in this case is num.
- the first < case-selector >, (6,9,99,66) means ``if num
is equal to either 6, 9, 66 or 99 then'',
- the second < case-selector >, (10:65,67:98) means ``if num
is between 10 and 65 (inclusive) or 67 and 98 (inclusive) then'',
- (100:) specifies the range of greater than or equal to
one.
- if a case branch has been executed then when the next
< case-selector > is encountered control jumps to the END SELECT
statement.
- if a particular case expression is not satisfied then the next one
is tested.
(An IF .. ENDIF construct could be used but a SELECT CASE is
neater and more efficient.)
SELECT CASE is more efficient than ELSEIF because there is only
one expression
that controls the branching. The expression needs to be evaluated once
and then control transferred to whichever branch corresponds to the
expressions value. An IF .. ELSEIF ... has the potential to have a
different expression to evaluate at each branch point making it less
efficient.
Consider the SELECT CASE construct,
SELECT CASE (I)
CASE(1); Print*, "I==1"
CASE(2:9); Print*, "I>=2 and I<=9"
CASE(10); Print*, "I>=10"
CASE DEFAULT; Print*, "I<=0"
END SELECT CASE
this maps onto the following control flow structure,
Figure 5: Visualisation of a SELECT CASE Construct
The syntax is as follows,
[ < name >:
] SELECT CASE < case-expr >
[ CASE < case-selector > [ < name > ]
< exec-stmts > ] ...
[ CASE DEFAULT [ < name > ]
< exec-stmts > ]
END SELECT [ < name > ]
Note,
-
the < case-expr > must be scalar and INTEGER, LOGICAL or CHARACTER
valued;
- there may be any number of general CASE statements but only
one CASE DEFAULT branch;
- the < case-selector > must be a parenthesised single value or
a range (section with a stride of one), for example, (.TRUE.) or
(99:101). A range specifier is a lower and upper limit separated by
a single
colon. One or other of the bounds is optional giving an open ended range
specifier.
- the < case-expr > is evaluated and compared with the
< case-selector >s in turn to see which branch to take.
- if no branches are chosen then the CASE DEFAULT is executed
(if present).
- when the < exec-stmts > in the selected branch
have been executed, control jumps out of
the CASE construct (via the END SELECT statement).
- as with other similar structures it is not possible to jump into
a CASE construct.
CASE constructs may be named -- if the header is named then so
must be the END SELECT statement. If any of the CASE branches are
named then so must be the SELECT statement and the END statement
A more complex example is given below, this also demonstrates how
SELECT CASE constructs may be named.
...
outa: SELECT CASE (n)
CASE (:-1) outa
M = -1
CASE (1:) outa
DO i = 1, n
inna: SELECT CASE (line(i:i))
CASE ('@','&','*','$')
PRINT*, "At EOL"
CASE ('a':'z','A':'Z')
PRINT*, "Alphabetic"
CASE DEFAULT
PRINT*, "CHAR OK"
END SELECT inna
END DO
CASE DEFAULT outa
PRINT*, "N is zero"
END SELECT outa
Analysis:
- the first SELECT CASE statement is named outa and so
is the corresponding END SELECT statement.
- the < case-expr > in this case is n this is evaluated
first and its value stored somewhere.
- the first < case-selector >, (:-1) means ``if n is less
than or
equal to -1'' so if
this is true then this branch is executed -- when the next
< case-selector > is encountered, control jumps to the END SELECT
statement.
- if the above case expression is not satisfied then the next one
is tested. (1:) specifies the range of greater than or equal to
one. If n satisfies this then the DO loop containing the
nested CASE construct is entered. If it does not then the DEFAULT
action is carried out. In this case this branch corresponds to the
value 0, the only value not covered by the other branches.
- the inner case structure demonstrates a scalar CHARACTER
< case-expr > which is matched to a list of possible values or,
indeed, a list of possible ranges. If the character substring
line(i:i) matches a value from either the list or list of ranges then
the appropriate branch is executed. If it is not matched then the
DEFAULT branch is executed. Note a CHARACTER substring cannot be
written as line(i)
- this inner case structure is executed n times, (due to the
loop,) and then control passes back to the outer case structure. Since the
executable statements of the case branch have now been completed the
construct is exited.
Return to corresponding overview page
Next: Mixing Objects of Different
Up: Control Flow
Previous: Scope of DO Variables
©University of Liverpool, 1997
Wed May 28 20:20:27 BST 1997Not for commercial use.