The humble EJECT statement…
Back in the day when dinosaurs still roamed the earth and programmers still knew how to use a card punch, there were printers. Not your desktop printer of today but huge big, noisy things with all the characters on a chain, a ‘ribbon’ as wide as the paper that fed vertically on rollers and a a row of hammers that stuck the correct character as it went past on the chain, if you got it setup right that is! These things also used a paper loop for carriage control that told it where various spots where on the page, in particular the top of the page. Happy days!
In those days your program listing got printed out, so to make it more readable you’d put EJECT statements into the source code, usually before a subroutine so that the subroutine and all the comments about what it did, its inputs and outputs etc; (you did document all that stuff didn’t you?) were at the top of a page.
Fast (or not) forward to today and I doubt anyone actually prints program listings anymore. If you are anything like me it’s all online, either in SDSF, sent to a member of a ‘listings’ dataset or, if your source is off platform, your tool set grabs the output after the assembly has run and FTPs it back to your workstation/PC where again, you can view it online.
So, since the output is now all just one big stream, why would you bother putting EJECT statements into your source, other than from habit?
Now I will admit that I did this from habit until I got to thinking about it (hence this post!) and there is actually a very good reason to include EJECT statements in your source, especially before the start of a subroutine.
Here’s a little test program:
TEST CSECT BAKR 14,0 LR R10,R15 USING TEST,R10 USING WSA,R2 * * XR R15,R15 PR LTORG * SUB1 DS 0H LA R1,FIELD1 XR R15,R15 BR R14 * LTORG * WSA DSECT FIELD1 DS F'0' FIELD2 DS F'0' * END
If you assemble this, the output looks like this:
20 TEST RMODE ANY 000000 00000 00018 21 TEST CSECT 000000 B240 00E0 22 BAKR 14,0 000004 18AF 23 LR R10,R15 R:A 00000 24 USING TEST,R10 R:2 00000 25 USING WSA,R2 26 * 27 * 000006 17FF 28 XR R15,R15 000008 0101 29 PR 000010 30 LTORG 31 * 000010 32 SUB1 DS 0H 000010 4110 2000 00000 33 LA R1,FIELD1 000014 17FF 34 XR R15,R15 000016 07FE 35 BR R14 36 * 000018 37 LTORG 38 * 000000 00000 00008 39 WSA DSECT 000000 40 FIELD1 DS F'0' 000004 41 FIELD2 DS F'0' 42 * 43 END
In this code, I have let the using for WSA in the main line code ‘fall through’ into the sub routine (something I normally hate to do except for working storage based on R13). The only way you can tell that the LA,R1,FIELD1 instruction in the subroutine is using R2 as a base register for WSA is by looking at the assembled instruction.
However, if you add an EJECT before the SUB1 label like this:
EJECT SUB1 DS 0H LA R1,FIELD1
The output now looks like this:
000000 00000 00018 21 TEST CSECT 000000 B240 00E0 22 BAKR 14,0 000004 18AF 23 LR R10,R15 R:A 00000 24 USING TEST,R10 R:2 00000 25 USING WSA,R2 26 * 27 * 000006 17FF 28 XR R15,R15 000008 0101 29 PR 000010 30 LTORG 31 * Active Usings: WSA(X'1000'),R2 TEST(X'1000'),R10 Loc Object Code Addr1 Addr2 Stmt Source Statement 000010 33 SUB1 DS 0H 000010 4110 2000 00000 34 LA R1,FIELD1 000014 17FF 35 XR R15,R15 000016 07FE 36 BR R14 37 * 000018 38 LTORG 39 * 000000 00000 00008 40 WSA DSECT 000000 41 FIELD1 DS F'0' 000004 42 FIELD2 DS F'0' 43 * 44 END
The difference is that you now get one or more lines (depends on how many usings are active) that show the current usings in effect at the very start of the subroutine. As a result I can see exactly which usings are active and whether I have inadvertently ‘inherited’ one from an earlier routine that should have been dropped.
As a matter of coding style, I prefer to always drop all active usings, including code base regs except for working storage that is based on R13, at the end of each routine. That way I
know I am using the correct registers and usings in each routine and by putting an EJECT statement in the source before each routine, I can easily see from the listing that I am not inadvertently inheriting a using from an earlier block of code that may allow the code to assemble but ultimately fail when it runs because I picked up the wrong base register.