On Feb 3, 2011, at 12:57, Edward Jaffe wrote:

> On 2/3/2011 10:41 AM, Johanson, Adam wrote:
>>         Then, I told myself that the whole point of the exercise was to make 
>> the code more readable, so a branch to a return-to-caller label every now 
>> and then didn't really defeat the purpose and actually _did_ help things. 
>> IMHO, rather than seeing a big nested IF statement and chasing down the end 
>> point just to figure out that you're gonna return to the caller is a bit 
>> more involved than realizing, "Oh, I'm just getting out of Dodge."
>
> Yup. You can find analogs in other languages. For example SIGNAL and EXIT in
> REXX. Programs can become unnecessarily complex if you require every condition
> to be surfaced back up through a deeply-nested logic hierarchy.
>
Rexx SIGNAL sucks.  One one hand, it trashes the DO...END structure; OTOH
it leaves the subroutine return stack hanging (a naive colleague once
authored a Rexx program that used SIGNAL to "get out of Dodge".  He tested
it, apparently successfully.  It crashed on a large input data set when
the stack overflowed.  PITA to refactor.)  Absence of a construct to
exit a nest of procedures impels Rexx programmers to eschew subroutines
in contexts where they'd otherwise be preferable.

I'd cherish an extension to support "LEAVE control-variable" where
control-variable belongs to a loop in an outer procedure exposed in
the inner procedure containing the LEAVE.

But Rexx does support LEAVE and ITERATE for outer DOs.  I habitually
code:

    do OuterLoop = 1 for 1
        ...
        do
            ...
            do
                ...
                leave OuterLoop
                ...
            end
            ...
        end
        ...
    end OuterLoop

> Depending on your program design, an "signal/exit jump from anywhere" can be
> problematic when using a stack for (at least) saving/restoring registers. If 
> you
> "signal/exit" with the stack pushed several levels deep, your current 
> registers
> might not be appropriate for the "signal/exit" routine and, if the stack is
> needed for any processing after that, you'll need a way to unwind the stack to
> the appropriate level or else things might go horribly wrong--for example when
> the "signal/exit" routine itself tries to return to the original caller.
>
> The easiest way to avoid this is to never branch to a "signal/exit" label from
> an inner routine. Or put another way, each stack level has its own 
> "signal/exit"
> routine.
>
> Another way we've handled the "signal/exit jump from anywhere" is to save the
> appropriate stack control and registers in some easily addressable non-stack
> storage from which they are loaded/copied as one of the very first things the
> "signal/exit" routine does.
>
> FWIW, when writing code from scratch it is often possible to avoid 
> "signal/exit"
> branches entirely by enclosing the logic within two nested simple DOs as 
> shown.
> We have used this technique quite effectively in some very large and complex
> programs. (This is only an example. Many other variants of this approach are
> possible.)
>
> | DO LABEL=MainLine            Do for MainLine routine
> |
> |   ************************************
> |   * Process MainLine Logic Here      *
> |   ************************************
> |   DO LABEL=MainLineLogic       Do for MainLine logic
> |     .
> |     .(some deeply nested code here discovers an error)
> |     LHI   R15,ErrorCode1         Load error code
> |     LEAVE MainLineLogic          Go perform error processing
> |     .
> |     .(another error is discovered)
> |     LHI   R15,ErrorCode2         Load error code
> |     LEAVE MainLineLogic          Go perform error processing
> |     .
> |     .(this can be a very large and complex routine)
> |     .
> |     XR    R15,R15                Set return code = 0
> |     LEAVE MainLine               Exit the routine
> |   ENDDO , MainLineLogic        EndDo for MainLine error trap
> |
> |   ************************************
> |   * Process MainLine Errors Here     *
> |   ************************************
> |   SELECT CHI,R15,EQ            Select error code
> |   WHEN ErrorCode1              ErrorCode1
> |     (whatever)                   Issue msg, set retcode/rsn, etc.
> |   WHEN ErrorCode2              ErrorCode2
> |     (whatever)                   Issue msg, set retcode/rsn, etc.
> |   OTHRWISE ,                   Unknown Error Code
> |     J     *+2                    Logic error. Force abend here.
> |   ENDSEL ,                     EndSel error code
> | ENDDO , MainLine             EndDo for MainLine routine
>
>
>>         And you've probably come across it in the SHARE presentations that 
>> you've seen, but if you're going to do this, download Ed Jaffe's FLOWASM 
>> exit. It makes life easier.
>
> I'm glad you found it useful. 8-)
>
> --
> Edward E Jaffe
> Phoenix Software International, Inc
> 831 Parkview Drive North
> El Segundo, CA 90245
> 310-338-0400 x318
> [email protected]
> http://www.phoenixsoftware.com/

Reply via email to