Sorry, REXX SIGNAL does not suck; you just don't know how to use it. It only trashes the current DO...END structure. It works just fine if you code something like:
DO Outerloop = 1 to n Call processes_item End Process_item: Signal ... Return Any errors encountered in 'Process_item' will not stop Outerloop. John -----Original Message----- From: IBM Mainframe Assembler List [mailto:ASSEMBLER-LIST@LISTSERV.UGA.EDU] On Behalf Of Paul Gilmartin Sent: Friday, February 04, 2011 10:09 AM To: ASSEMBLER-LIST@LISTSERV.UGA.EDU Subject: Re: Best (or any) practices to rewrite "spaghetti" 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 > edja...@phoenixsoftware.com > http://www.phoenixsoftware.com/