Previous: Transforming Block IF, Up: Transforming Statements
SELECT CASE
poses a few interesting problems for code generation,
if efficiency and frugal stack management are important.
Consider `SELECT CASE (I('PREFIX'//A))',
where `A' is CHARACTER*(*)
.
In a case like this—basically,
in any case where largish temporaries are needed
to evaluate the expression—those temporaries should
not be “live” during execution of any of the CASE
blocks.
So, evaluation of the expression is best done within its own block,
which in turn is within the SELECT CASE
block itself
(which contains the code for the CASE blocks as well,
though each within their own block).
Otherwise, we'd have the rough equivalent of this pseudo-code:
{ char temp[large]; libg77_catenate (temp, 'prefix', a); switch (i (temp)) { case 0: ... } }
And that would leave temp[large] in scope during the CASE blocks (although a clever back end *could* see that it isn't referenced in them, and thus free that temp before executing the blocks).
So this approach is used instead:
{ int temp0; { char temp1[large]; libg77_catenate (temp1, 'prefix', a); temp0 = i (temp1); } switch (temp0) { case 0: ... } }
Note how `temp1' goes out of scope before starting the switch, thus making it easy for a back end to free it.
The problem that solution has, however, is with `SELECT CASE('prefix'//A)' (which is currently not supported).
Unless the GBEL is extended to support arbitrarily long character strings
in its case
facility,
the FFE has to implement SELECT CASE
on CHARACTER
(probably excepting CHARACTER*1
)
using a cascade of
if
, elseif
, else
, and endif
constructs
in GBEL.
To prevent the (potentially large) temporary,
needed to hold the selected expression itself (`'prefix'//A'),
from being in scope during execution of the CASE
blocks,
two approaches are available:
CASE
tests,
producing an integer ordinal that is used,
a la `temp0' in the earlier example,
as if `SELECT CASE(temp0)' had been written.
Each corresponding CASE
is replaced with `CASE(i)',
where i is the ordinal for that case,
determined while, or before,
generating the cascade of if
-related constructs
to cope with CHARACTER
selection.
CASE
string
that'll actually be compared against the expression
(in this case, `'prefix'//A').
Since that length must be constant
(because CASE
expressions are all constant),
it won't be so large,
and, further, `temp1' need not be dynamically allocated,
since normal CHARACTER
assignment can be used
into the fixed-length `temp0'.
Both of these solutions require SELECT CASE
implementation
to be changed so all the corresponding CASE
statements
are seen during the actual code generation for SELECT CASE
.