9.6 'switch/SWITCH' statement
-------------------------------
Syntax:
switch(<expression>){
case <constant>:
<operator>
...
case <constant>:
<operator>
...
...
default:
<operator>
}
The statement 'switch' is used for choosing among several alternate
ways of executing a program. Execution begins by calculating the value of
<expression>. After this control passes to one <statement> of the switch
body. The switch body contains the constructions <constant> case which are
syntactically statement labels. The statement which gets control is the one
whose constant value coincides with the <expression> value of the switch.
The <constant> value must be unique.
Execution of the body of 'switch' begins with the chosen statement and
continues to the end of the body or until some statement does not pass
control beyond the body.
A statement following the keyword 'default' is executed if one of the
constants is equal to <expression>. If 'default' is omitted, none of the
statements in the switch body is executed and control passes to the
statement following 'switch'.
'break' or 'BREAK' are usually used to exit the body of 'switch'.
Example:
switch (i){
case 'A':
WRITE(i);
i++;
BREAK;
case 32:
WRITE('_');
i++;
BREAK;
default:
WRITE('i');
}
There are currently three ways to implement 'switch': two-table,
table, and method of sequential verification.
The table method is fastest, but with a large number of 'case'
statements and a small difference between maximum and minimum values of
'case' it can be even more compact. It has certain drawbacks: in 16-bit
mode register BX is always used, and in 32-bit mode if 'switch' is a
register then its value is destroyed.
In the sequential verification method, a comparison block is found at
the beginning of the body of 'switch' which saves one or two extra jumps.
But the compiler cannot determine which type of jump to used when checking
the values of 'case'. This is the job of the programmer. If the code size
from the start of the body of 'switch' to 'case' is less than 128 bytes, a
short jump can be used. In this event 'CASE' can be used, which results in
the generation of more compact code. The compiler will suggest using
'CASE'. Using 'CASE' when the code is over 128 bytes will produce an error
message.
In the two-table method two tables are created - an input address table
in the body of 'switch' or 'SWITCH' and a table of values of 'case'. The
input value is compared with the value in the second table. If they are the
same then a jump is made by the address in the second table. This method if
the slowest but if there are many values of 'case' (more than 15) it is the
most compact.
If code is being optimized for size, the compiler first calculates the
code size which will be obtained by all the methods and produces the most
compact code. When optimizing for speed, priority is given to the table
method if the table size is not too large.
There is a short form 'SWITCH' used if the code block between the
beginning of the body of 'SWITCH' and 'default' (or the end of the body of
'SWITCH' if there is no 'default') is less than 128 bytes. The compiler
will suggest the use of the short form.
You can specify a range of values for 'case' or 'CASE', which can be
used only the body of 'switch' or 'SWITCH'. The smaller value is given
first, followed by an ellipsis and the larger value. For example:
switch(AX){
case 1...5:
WRITESTR("Range AX from 1 to 5");
BREAK;
};
It used to be necessary to write:
switch(AX){
case 1:
case 2:
case 3:
case 4:
case 5:
WRITESTR("Range AX from 1 to 5");
BREAK;
};
The new format is also more compact and more readable, and will
generate smaller and faster code.