Transforming SELECT CASE
------------------------
`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:
* Pre-evaluate all the `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.
* Make `temp0' above just large enough to hold the longest `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'.