Cobol Read statement format. Can it be redone a different way? - cobol

On this read statement below couldn't it be made into the form of the following? I think personaly it might be easier to understand and read.
Basically the read statement is simply reading through a file and making decision on which paragraph performs should be executed. It probably is difficult to see exaclty what the program does but what I was really interested to know was if you can change the read to a different format as listed below.
READ DATA-FILE
AT END
...do some code
NOT AT END
...do code that is below
END-READ.
Class:
INIT-READ.
READ C AT END
GO TO EOJ.
IF C-ID = ' ' AND C-S = 'P'
GO TO I-R
END-IF.
IF CID = ' ' AND C-S = 'D'
IF F = 'Y'
MOVE 'N' TO F
MOVE 'your text here' TO RPT-ID
MOVE A TO H6
MOVE B TO H7
PERFORM PA THRU H-A-X
END-IF
PERFORM WD-CLAIM THRU W-X
GO TO I-R
END-IF.
PERFORM N-V THRU N-V-X.

At the bottom of a discussion thread, captured in the GNU Cobol FAQ, http://opencobol.add1tocobol.com/gnucobol/#performing-forever Roger While mentioned a pretty nice idiom for READ control without paragraphs.
One thing that I saw on earlier posts to
the newsgroup cobol was
What is the need/justification for an
empty inline perform group.
ie.
PERFORM
...
END-PERFORM
None of the discussions then realized that
there is a -
EXIT PERFORM [CYCLE]
Therefore, it is a method to to
define an exit condition without having paragraphs.
ie. (very simply)
PERFORM
READ xxx
AT END
EXIT PERFORM
END-READ
MOVE something TO somewhere
END-PERFORM
.. test xxx status and somewhere
There are, of course, other variations.
Basically, it means that you code without
using section/paragraphs.
(Recommended, if only from performance point of view)
Note that the CYCLE option offers interesting possibilities.
Roger

Have a look here. COBOL read/store in table. for a way of avoiding GO TO, and even the AT END/NOT AT END. No END-READ needed either.
To avoid the AT END/NOT AT END, simply use the File Status, which you should already be using anyway to check that all IO operations were successful. For an input file, READ will give a file status of 10 when end-of-file is detected.
Use an 88 on your file status. So you can say things like END-OF-PAYMENTS-TRANSACTIONS.
Then, to process your file, you use a "priming read". This is a read outside the loop.
priming read
processing-loop until END-OF-PAYMENTS-TRANSACTIONS
do the processing
read
EXIT PERFORM (and some other EXIT options) is not available in all COBOLs currently. Be aware that if you are part of a large team and put an EXIT PERFORM in your program you will likely find several EXIT PERFORMs in the same block of code within a couple of years. So they may have well been GO TOs all along. The new EXIT options are just a way of have a GO TO which is spelled differently. OK, a little tongue-in-cheek, but there we go.
Of course, the priming read and read above both PERFORM a single paragraph to do the actual read and check the validity of the io (file status zero or 10 is OK, else a problem).
Be careful about considering avoiding PERFORM paragraph/SECTION for "performance". Write for clarity unless performance is critical. With IBM's Enterprise COBOL, using OPT, PERFORM code can be "inlined" anyway.

Related

What is the use of the EXIT keyword?

I've seen many COBOL programs contain sections with at the end
XX-99.
EXIT.
Many times that paragraph is used to exit the section, for instance with GO TO XX-99. I have read that EXIT is a no-operation, as it doesn't do anything. But the same goes for CONTINUE. One could easily replace EXIT with CONTINUE. Alternatively, one could replace GO TO XX-99 with EXIT SECTION.
Is there any compelling reason to use EXIT rather than CONTINUE? Why was EXIT introduced anyway? Was EXIT introduced before CONTINUE was?
Note: I'm not talking about EXIT in combination with another reserved word, like EXIT PROGRAM or EXIT PERFORM.
Is there any compelling reason to use EXIT rather than CONTINUE?
Why was EXIT introduced anyway?
Was EXIT introduced before CONTINUE was?
There is no "compelling" reason to choose one over the other. There is no practical difference. The reason to choose EXIT over CONTINUE is conformance to existing coding standards.
EXIT was part of the original COBOL 60 Report where it was a "Compiler Directing Verb." Its purpose was to mark the end of a performed procedure, directing the compiler to transfer control to the statement following the invoking PERFORM statement or to the PERFORM statement for the next iteration of a loop.
In the ANSI COBOL 68 standard, it became a statement to mark the end of a performed procedure. It was no longer required, since the end of the perform range was the end of the last (or only) performed paragraph or section. It remained as a convenient target for a GO TO statement.
[With the introduction of the SORT statement, an EXIT statement may also be used to mark the end of an input or output procedure.]
CONTINUE was introduced in the 1985 standard as part of the changes for structured programming. It purpose was to replace the NEXT SENTENCE statement used within the IF and SEARCH statements or wherever an imperative statement is required by a statement format, but nothing need be done. It is in this last use that a CONTINUE statement may be used to replace an EXIT statement.
EXIT SECTION was introduced in the 2002 standard.
The 2014 standard still says:
The EXIT statement provides a common end point for a series of procedures [...]
[it] shall appear in a sentence by itself that shall be the only sentence in the paragraph [...]
[and] serves only to enable the user to assign a procedure-name to a given point in a procedure division.
Such an EXIT statement has no other effect on the compilation or execution.
Even in COBOL 202x this format it still is not marked archaic (while the EXIT PROGRAM format is, because of the same functionality provided by GOBACK).
With its different syntax rules to the CONTINUE statement it is already not the same (though some COBOL compilers don't enforce this rule and some of those also don't have an option to even create a warning if this rule is broken).
Concerning the originating: COBOL-74 does not seem to have a CONTINUE statement (at least my copy of VAX-11 COBOL-74 does not list it), it seems to have come in together with the inline format of the PERFORM statement in COBOL-85.
I personally would also prefer the procedure format of EXIT (EXIT SECTION or even EXIT PARAGRAPH if no sections are used in the program) over a GO TO, but as always with COBOL: follow whatever your team-/house-rules are, some may also forbid those.

Multiple exit causing compiler warnings

I have a program where under several conditions I would want to exit early, rather than continuing through the flow, and rather than having to check for that exit-early condition in calling paragraphs.
To do this, I have a paragraph "EXIT-FAILURE", that checks to make sure that the general return flag field is not ok (0), logs a message (DISPLAY), and finally has the statement GOBACK.
However, doing this is giving me a compiler warning on every PERFORM that calls this "EXIT-FAILURE" paragraph:
IGYCB7310-W The "PERFORM" statement at "PERFORM (line [line-number])" cannot reach its exit.
Is there any way to have this logic (which is basically multiple-exit/early-exit rather than single-exit), without having a compiler warning?
Is this idea entirely contrary to the COBOL way of doing things (my experience is more in Java, where this would be entirely normal in the context of guard statements or exceptions)?
EDIT: Adding minimal program requested by Simon:
IDENTIFICATION DIVISION.
PROGRAM-ID. SOQUEST.
ENVIRONMENT DIVISION.
DATA DIVISION.
PROCEDURE DIVISION.
PERFORM A100-INITIALIZE
PERFORM A200-VALIDATE
PERFORM B200-PROCESS-STEP-1
GOBACK
.
A100-INITIALIZE.
DISPLAY "INITIALIZED"
.
A200-VALIDATE.
PERFORM Z900-EXIT-FAILURE
.
B200-PROCESS-STEP-1.
DISPLAY "COMPLETED STEP 1"
.
Z900-EXIT-FAILURE.
GOBACK
.
Results in these two warnings related to my question:
IGYCB7310-W The "PERFORM" statement at "PERFORM (line 58.1)" cannot reach its exit.
IGYCB7310-W The "PERFORM" statement at "PERFORM (line 68.1)" cannot reach its exit.
(line 58.1 maps to the line "PERFORM A200-VALIDATE"; line 68.1 maps to the line "PERFORM Z900-EXIT-FAILURE")
As seen in the compiler warning and the additional explanation from the compiler manual, the issue is that you PERFORM something and PERFORM says "do this and then come back".
If Enterprise COBOL for z/OS adds support for RAISE exception-name (and ideally user-defined exceptions) this would be the way to go (both being "COBOL" as requested in the question and "exceptional" like in java) and you'd place the paragraph into DECLARATIVES as EXIT-FAILURE SECTION. USE AFTER EXCEPTION CONDITION exception-name. Until then [= maybe forever]:
If there's no rule against this on-site: use GO TO EXIT-FAILURE - this COBOL verb says "go there" (and likely don't come back, especially with a well named paragraph as in your case).
If there's a rule against GO TO - go with the approach from #cschneid - add a comment in the header about this warning and reference this comment directly where it happens with another comment.
Side-note: I personally would still try to put the paragraph into DECLARATIVES (unchanged, as it is now, just move it "up" to DECLARATIVES) to stretch the point "this is only called if something goes wrong" even more. But your compiler may raise another warning or even error in this case (at least "standard"-COBOL requires a use-statement there).
My reaction to this compiler warning would be to add a comment in the source indicating that the warning is expected. IBM Enterprise COBOL 6.3 (the latest release as of this date) does not support the RAISE statement.
It's not unlike PERFORMing a paragraph that does an EXEC CICS RETURN.
#SimonSobisch knows more about COBOL than I ever will, and will hopefully supply an example of how to solve this more in keeping with the "COBOL way" which will be useful to future seekers of knowledge here.
Using EXIT PARAGRAPH can help to avoid Go TO, compilation warnings, and comments ...
IDENTIFICATION DIVISION.
PROGRAM-ID. SOQUEST.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 FLAGS.
03 WS-VALIDATION PIC 9 VALUE ZERO.
88 WS-VALIDATION-OK VALUE 0.
88 WS-VALIDATION-ERROR VALUE 1.
PROCEDURE DIVISION.
MAIN.
PERFORM A100-INITIALIZE
PERFORM A200-VALIDATE
IF WS-VALIDATION-ERROR
EXIT PARAGRAPH
END-IF
PERFORM B200-PROCESS-STEP-1
.
CLOSE-FILES.
CLOSE XXXX
CLOSE YYY
.
EXIT-PROGRAM.
GOBACK
.
A100-INITIALIZE.
DISPLAY "INITIALIZED"
.
A200-VALIDATE.
* Do next when validation fails ...
MOVE 1 TO WS-VALIDATION
ANY-VALIDATION-HERE
IF ERROR-FOUND
EXIT PARAGRAPH
END-IF
CONTINUE-WITH-OTHER-VALIDATIONS
IF ERROR-FOUND
EXIT PARAGRAPH
END-IF
* Arriving here .. MEANS VALIDATION IS ok
MOVE O TO WS-VALIDATION
.
B200-PROCESS-STEP-1.
DISPLAY "COMPLETED STEP 1"
.
Try the following:
Z900-EXIT-FAILURE.
IF <some condition that is always true>
GOBACK
END-IF
.
As long as the compiler optimizer cannot determine the fact that the IF condition is always true, it won't raise the warning message.
A response to comment below and a few other suggestions...
Compiler optimization in some future release may determine the condition to be always true and remove it:
This would cause the warning message to return. Face that problem when it occurs. For the present,
something like: IF FUNCTION WHEN-COMPILED <= FUNCTION CURRENT-DATE
will not be optimized away, and probably won't be for many years to come.
May produce less efficient code:
The whole point of this paragraph is to exit the program. The
extra instructions needed for the IF test should not have a measurable affect
on performance.
Disable the diagnostic:
This can be done using a compiler exit to catch and
nullify the message, see: https://www.ibm.com/support/knowledgecenter/en/SS6SG3_6.3.0/pg/ref/rpext10.html .
I would caution against this because valid warnings may also be suppressed, some of which
probably should not be ignored.
Put a comment in the code indicating the warning is acceptable:
Not all programmers are so diligent as to continue reviewing compiler warnings once
they find out they are sometimes acceptable. Chances are good that valid warnings will be missed
in the future.
Using DECLARATIVES:
The IBM Enterprise COBOL compiler supports DECLARATIVES for I/O related errors
and debugging only making their usage fairly restrictive. Furthermore, there are a number of additional restrictions as to whether a STOP RUNor GOBACK
may be issued while a DECLARATIVE procedure is active. I would hesitate to advise using DECLARATIVES.
Language Environment provides facilities to
establish user defined condition handling but this is a fairly advanced topic.
see: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.1.0/com.ibm.zos.v2r1.ceea800/ceea824.htm
Use GO TO Z900-EXIT-FAILURE:
GO is recognized by the compiler as a go-there-and-don't-come-back transfer of control
and will not issue message IGYCB7310-W provided the GO TO is conditionally
executed (e.g. contained within an IF or other conditional statement). This is probably the best solution provided
local coding standards permit
usage of GO TO in these circumstances. Some places have an unjustified pathological fear of GO TO
and won't allow it under any circumstances.

How to get the current paragraph name?

I would like to know how to get the current paragraph name in COBOL (using MVS Enterprise COBOL V4.2 here).
Let's say I have this code in the PROCEDURE DIVISION :
MAIN-LOGIC.
MOVE SPACE TO ABT-MSG
PERFORM PARAGRAPH-1
PERFORM PARAGRAPH-2
GO TO CLOSE-PROGRAM.
*
* SEARCH FOR A VALUE IN AN ARRAY AND GET THE RELATED INDEX
*
PARAGRAPH-1.
MOVE 42 TO SEARCH-VALUE
PERFORM VARYING I-SEARCH FROM 1 BY 1
UNTIL SOME-ARRAY(I-SEARCH) = SEARCH-VALUE
IF (I-SEARCH = MAX-ARRAY-POSITION)
MOVE SEARCH-ABORT TO ABT-MSG
MOVE 'PARAGRAPH-1' TO ABT-LOC
GO TO CLOSE-PROGRAM
END-IF
END-PERFORM
DISPLAY 'VALUE WAS FOUND AT POSITION ' I-SEARCH '.'.
*
* STORE A NEW VALUE AT THE END OF AN ARRAY
*
PARAGRAPH-2.
MOVE 42 TO STORAGE-VALUE
ADD 1 TO I-STORAGE
IF (I-STORAGE > MAX-ARRAY-POSITION)
MOVE STORAGE-ABORT TO ABT-MSG
MOVE 'PARAGRAPH-2' TO ABT-LOC
GO TO CLOSE-PROGRAM
END-IF
MOVE STORAGE-VALUE TO SOME-ARRAY(I-STORAGE).
*
* CLOSE THE PROGRAM
*
CLOSE-PROGRAM.
IF ABT-MSG > SPACE
DISPLAY ABT-MSG
DISPLAY '(FOUND IN ' ABT-LOC ')'
MOVE 20 TO RETURN-CODE
ELSE
DISPLAY SUCCESS-MESSAGE
END-IF
STOP RUN.
I would like to be able to access the current paragraph name (and store it in ABT-LOC) instead of having to write it.
Is there a COBOL system variable to do so, like 'CURR-PARA-NAME' or something ?
Thank you.
------ UPDATE 1 -------
I have updated my code example to make it more specific.
Know that, in my real COBOL program, there are various occurences of SEARCH-ABORT and STORAGE-ABORT possibilities (I am working with many arrays).
I want to make my code as good as possible, hence my will to access the current paragraph name instead of having to write it.
Thank you again.
------- UPDATE 2 ------
Well then. It seems I cannot do it (the users of my program will probably reject any debug messages they are not used to get - For your information, I am rewriting a 50 years old program with very, very bad programming practices such as upward GO TOs, fall-through logic and the godforsaken ALTER, and I want to get the same output at the end).
Don't worry, I will not cry tonight. This was just an esthetical improvement to my code, and I can live without it (my code is already a lot prettier than what I based myself on).
I thank all of you for your time, and wish you a good... Stack Overday !
As Simon Sobisch has correctly indicated in his answer, the only way to do exactly what you want is to use the "debugging declaratives". See later in the answer for making that work, but no-one should allow you to do this to a Production program.
COBOL is a compiled language so there is no no automatic access to any data-name or procedure name (paragraph or SECTION) unless the compiler makes something available. Which, excluding the case above, it doesn't.
That leaves three approaches: doing it manually (which you correctly want to avoid, as sure as peaches someone is going to copy or relocate code without changing the literal); pre-processing (with a program or the editor) to automatically populate your field with the correct label; doing something else.
Since you are implicitly discounting the first, again I believe correctly, let's consider the second. What if you have two, three or eight things in the same paragraph/SECTION which are all "business errors" (although usually these types of things are more "integrity errors", a state which should not exist, so don't continue)?
Since you will get those, a "pre-processing" solution starts to get more ugly.
What else can be done?
Well, it's something we've faced for many, many years. The answer is, unique (within the program) error numbers. The individual errors can be named, well, and given a number. The well-named error reference is difficult to use "incorrectly". When adding a new error, it is difficult to duplicate an existing number. Or, to put it another way, it is easy to duplicate but horribly easy to spot in testing - "hey, that's produced 1234, that's wrong".
It's in no way bullet-proof, but the data-name (and any associated text) give better indication of the problem than a paragraph-name (which is not going to be, except artificially, any indication of what the error is, just the location of it). The error references are very easy to find in the program, and from that it is easy to locate the procedure name, except you don't actually need it any more.
Whether the program with error-numbers outweigh the dross of manually maintained MOVE 'literal' TO some-standard-name programs is unknown. But you can guess which I favour and recommend.
Now, how to do it for Enterprise COBOL with DECLARATIVES.
IDENTIFICATION DIVISION.
PROGRAM-ID. STAB39.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SOURCE-COMPUTER. FRED DEBUGGING MODE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 W-WHEN-COMPILED PIC X(8)BX(8).
01 ABT-LOC PIC X(30).
PROCEDURE DIVISION.
DDECLARATIVES.
DSOME-SECTION SECTION.
D USE FOR DEBUGGING ON ALL PROCEDURES
D .
DSOME-PARA.
D MOVE DEBUG-NAME TO ABT-LOC
D .
DEND DECLARATIVES.
STARTING-UP SECTION.
DISPLAY
ABT-LOC
D DISPLAY
D "IT IS STARTING UP"
MOVE WHEN-COMPILED TO W-WHEN-COMPILED
DISPLAY
"STAB39 "
W-WHEN-COMPILED
.
A-PARA.
DISPLAY
ABT-LOC
PERFORM
10 TIMES
D DISPLAY
"ITERATING"
END-PERFORM
.
ANOTHER-PARA.
DISPLAY
ABT-LOC
PERFORM THE-PARA
10 TIMES
PERFORM THE-SECOND-PARA
GOBACK
.
THE-PARA.
DISPLAY
ABT-LOC
.
THE-SECOND-PARA.
DISPLAY
ABT-LOC
.
Some notes:
The SOURCE-COMPUTER paragraph is required to use COBOLs in-built debugging features, to turn them on. So the ENVIRONMENT DIVISION and CONFIGURATION SECTION are also required. The "computer name", FRED in the example, is required, but it is irrelevant. You can "name" your computer after your favourite pet or relative if you like, or put anything there, there just has to be something.
DECLARATIVES can only be specified at the start of the PROCEDURE DIVISION. They must be within a SECTION and all actions must be within a paragraph belonging to a SECTION. The names of the SECTION and paragraph are irrelevant, but make them meaningful anyway.
Because the DECLARATIVES must contain a SECTION, you will be subject to an informational diagnostic message if your first procedure label is not also a SECTION. This does not require using SECTIONS over paragraphs in your program, it has no further effect.
The D in column seven indicates a "debugging line". These lines only get code generated when you turn debugging on with the SOURCE-COMPUTER paragraph.
The program exercises all use of a paragraph (and use of a SECTION is no different for this example) except GO TO. Paragraphs which are GO TO'd will produce the same results as any other reference, but you won't see GO TOs in my programs :-)
It is possible to name the procedure or procedures you want to "trap" with the DECLARATIVES instead of using "ALL PROCEDURES".
You may have multiple DEBUGGING procedures, and you can include extensive code within them if you wish (setting up conditions for testing, for instance).
Although this feature has existed in COBOL for a long time, it is probably fair to say that it is not widely used, especially as specific "debugging products" became available.
It is not enough just to have this program, the "run time" needs to have DEBUG turned on, if it is not the default. The run-time on z/OS is called Language Environment and is shared by multiple languages (allowing easy inter-language communication). Languages include C/C++, PL/I and Java as well as COBOL. There are Language Environment routines and macros available to make HLASM/Assembler programs "LE Compliant" to also provide ready interfacing.
To see what run-time options your site has as default, the easiest thing to do is to include a CEEOPTS DD statement in your run JCL.
//CEEOPTS DD *
RPTOPTS(ON)
This will list out all the options used for your "Enclave" (your run environment) and indicate where each option is sourced from.
If, in the OPTION column, you see NODEBUG, then COBOL debugging is turned off by default. To turn it on for a particular run:
//CEEOPTS DD *
DEBUG
This will allow all the D-labelled debugging lines and the debugging DECLARATIVES to execute.
This will do what you want, but no-one will allow a program with debugging on into Production, so you can't use it for what you want.
In order of preference, I advise error-numbers (and testing), automation, hand-coded procedure-name literals.
IBM fully documents all its products, and you can find the documentation (Language Reference and Programming Guide amongst others) for Enterprise COBOL V4.2 and also Language Environment (several) for your release of z/OS.
One final point. Don't use GO TO to "break out" of your normal processing flow. Use PERFORM. Even when, logically, the PERFORM cannot return. Using GO TO will turn off compiler optimisation for paragraphs/SECTIONs containing the GO TO which can easily cause a noticeable impact on execution. This is the reverse of the advice from before IBM COBOL ensured that the state of PERFORMed paragraphs/SECTIONs is not preserved between CALLs. At that time the correct advice was to use GO TO. It is no longer the correct advice.
As you have the pseudo-code "something bad happened here" I assume an exception. In this case the standard (COBOL 2002, COBOL 2014) function EXCEPTION-LOCATION may help (although the actual string is implementor-defined I assume the paragraph may be in there [GnuCOBOL for example has the format: program-id; paragraph [or paragraph OF section or section, depending on your program]; source-line]).
If your COBOL compiler provides this information in this function and there is no exception in the offending part already: create one via subtract 1 from unsigned-var or similar.
As Bill already said (or implied): this is a question where the actual COBOL compiler used will be the most important part if you must have the names in as identifier and as label or not.
Edit (after the actual COBOL compiler is known):
IBM MVS Enterprise COBOL doesn't have the EXCEPTION-LOCATION function. Therefore I see only one built-in solution:
DECLARATIVES.
debug-declaratives SECTION.
USE FOR DEBUGGING ON ALL PROCEDURES.
debug-par.
MOVE debug-name TO current-procedure.
END DECLARATIVES.
But as this is only active if your program runs in debugging-mode (which may causes a lot of debugging messages to occur) I don't suggest to actual use this.
Try to use an Editor providing macros (or run a shell script on your actual source) to create the source you pass to the compiler afterwards.

PERFORM THRU VARYING : exact behavior?

I am trying to understand the behavior of a COBOL program and I am stumbling upon the following lines:
PERFORM 525-NUMERIC THRU 525-EXIT
VARYING K FROM 1 BY 1 UNTIL K > CAR-L.
I understand the global concept that it is some kind of loop based on the value of K, but I fail to understand the impact of the THRU 525-EXIT words?
A PERFORM can execute a range of paragraphs or SECTIONS serially. This is done by using THRU/THROUGH to name the last paragraph/SECTION of the series, the PERFORM having already named the starting point.
A simple PERFORM of a paragraph:
PERFORM 10-OPEN-INPUT-FILES
This establishes a "range" for the PERFORM starting with 10-OPEN-INPUT-FILES and ending with the last statement of that paragraph.
A PERFORM of multiple paragraphs, one after the other:
PERFORM 10-OPEN-INPUT-FILES
THRU 10-OPEN-INPUT-FILES-EXIT
This establishes a wider range for the PERFORM, starting from 10-OPEN-INPUT-FILES and ending with the last statement of 10-OPEN-INPUT-FILES-EXIT.
This isn't really a good or useful thing, but it gets used a lot in a specific way, and that is perhaps what you have. This is to have an "exit paragraph" associated with each paragraph that is PERFORMed. One original paragraph, followed by one unique exit-paragraph associated (by the second paragraph's position, nothing else) with that original paragraph.
This is never necessary, programs work fine without them. However, since there is an "exit-paragraph" of course there is now a label which can be the target of a GO TO. Code something stupid, or come across something already coded that way, and just jam a GO TO in to get you (but perhaps not the next person) out of trouble. This is not a good thing to do, although it will often be seen as "expedient". And the next time in the same code the expedient route will be taken, and the next time, and then something which should always have been simple has become... complex.
Stunningly (my opinion, for many this is normal practice), more than a few sites have it in their local standards that an exit-paragraph must be included for each PERFORMed paragraph and PERFORM ... THRU ... must be coded.
As well as asking for trouble by inviting the use of GO TO, another problem is that the physical location of the code is now relevant. If you put a new paragraph before the exit-paragraph, then it becomes part of the PERFORM range, whether intended or not. Some people intend, even going so far as to code several paragraphs to be within the range of a PERFORM, with the ever-handy GO TO as their "get out of mess" tool.
A further problem is that when you encounter the PERFORM ... with THRU ... you don't know how many paragraphs (or SECTIONS) are included in the PERFORM without looking at the paragraphs (or SECTIONS) themselves.
You can also PERFORM a SECTION. This is a procedure label followed by the word SECTION and terminated by a full-stop/period.
A SECTION can contain paragraphs. When you PERFORM a SECTION, all paragraphs in the SECTION are within the PERFORM range, until the last statement of the SECTION. It is like a PERFORM ... THRU ... without the THRU ... bit. It has the same problems as the PERFORM ... THRU ... plus the additional one that if unique paragraphs are used as the target of a GO TO, great care must be taken if a SECTION is copied to make a new one. It is perfectly legal to GO TO out of a SECTION (or paragraph) but this would usually be unintended and can cause chaos, as program control wanders of somewhere else. If using a GO TO to an exit-paragraph in a SECTION, the best thing to do is to use identical names for the exit-paragraph. Any GO TO within a SECTION will be automatically "qualified" by the compiler to the paragraph within that SECTION (if there are non-unique paragraph-names referenced in a SECTION, but no paragraph of that name in the SECTION itself, the compiler will spot the error).
With your code, locate the paragraph being PERFORMed, and search sequentially for the paragraph named on the THRU. It is probably just a dumb exit (a paragraph with just an EXIT statement and a full-stop/period). There may be other paragraphs in between those two, if you are very unlucky. Any such paragraphs are included within the range of the PERFOR, without being explicit on the PERFORM statement. The
It is worth noting that the EXIT statement itself does nothing. It is a "No Operation" or NOP (or NOOP). At the end of a paragraph which is PERFORMed a number of instructions will be generated to do the exit-processing, this is automatic and does not (and never has) relied on the presence of an EXIT statement.
It used to be the case, prior to the 1985 Standard, that EXIT had to be coded in a paragraph on its own. This is no longer the case. You can fill a paragraph with EXIT statements (say 20) and then finish the paragraph with a DISPLAY. PERFORM the paragraph, and you will see the DISPLAY output.
A paragraph which is PERFORMed without a THRU should not contain a GO TO. It is not a compile-error if it does contain a GO TO. It is an accident waiting to happen.
People who feel the need to use GO TO have to use PERFORM ... THRU ... or to use a PERFORM of a SECTION. Unfortunately, even if the original coder does not use GO TO, the use of PERFORM ... THRU ... or PERFORM of a SECTION does make it easy for someone in the future to use GO TO. If there is somewhere for a GO TO to go to, then it is more likely that a GO TO will appear at some point. If there is no existing target for a GO TO, then the next coder will be put off from using GO TO by having to make additional changes.
In the current Standard, from 2014, there are some new versions of EXIT. (The EXIT PROGRAM version of EXIT has been around a long time already, although these days the IBM-inspired GOBACK is more likely to be used to return to the CALLing program).
The new possibilities include EXIT PARAGRAPH and EXIT SECTION. Check the documentation for your compiler to see what variants of EXIT are available. All the variants of EXIT generate executable code, it is just the plain EXIT which does not.
If your compiler does allow EXIT PARAGRAPH and EXIT SECTION, it means you no longer need to have a label to allow use of a (now "secret") GO TO, it just won't be called GO TO, it'll be called EXIT somevariant. Just remember that all those (except EXIT PROGRAM) are GO TOs in disguise, and that code can always be rearranged (and often simplified) to obviate the need for GO TO.
It does require experience to structure for no-GO TO code, so don't be too concerned with it for now. If your site uses GO TO (implied by the use of THRU) then it will be very important that you understand the ramifications of the use of GO TO because existing code will use it.
Then start in a small way to avoid GO TO yourself, increasing the scope of your efforts as you become familiar with techniques to do so. Remember, the aim is to simplify the code, or at least not make it worse, not just to not code GO TO by rote. If you make your code complicated simply to avoid a GO TO, then use GO TO until you know how to do it better.
Many, many, good and experienced COBOL programmers write understandable programs using GO TO. Unfortunately the majority of programmers are not "good and experienced" so are happy to short-circuit something with GO TO and move on.
The VARYING on a PERFORM is a means to repeat the execution, with a starting point, an increment and termination condition. This is the same whether or not THRU is coded.
An example of what can happen with an errant GO TO going outside the range of a PERFORM can be found here: https://codegolf.stackexchange.com/a/20889/16411. That is coded with SECTIONs but it could equally be done with PERFORM ... TRHU ...
Very good to read this in conjunction with Bruce Martin's answer.
Following on on from Bill's answer, I will try and add a more visual answer.
Perform Proc-A thru Proc-D.
...
Proc-A.
....
Proc-B.
....
Proc-C.
....
Proc-D.
....
In the above, the Perform Proc-A thru Proc-D executes procedure's Proc-A, Proc-B, Proc-C and Proc-D. It is a shorthand for
Perform Proc-A
Perform Proc-B
Perform Proc-C
Perform Proc-D
The Perform Thru syntax has several problems:
It is not always clear what is being executed.
Perform B100-Load-From-DB thru B500-Save-To-Db
I think the following tells you more
Perform B100-Load-From-DB
Perform B200-Adjust-Stock-for-Purchases
Perform B300-Adjust-Stock-for-Sales
Perform B400-Calculate-Markdowns
Perform B500-Save-To-Db
It makes it easy to introduce problems i.e. if you add a procedure in the wrong position, you will be introducing code without realizing it
Proc-B.
....
Proc-in-wrong-position.
....
Proc-C.
....
An error like the above is easy to make but hard to spot
It is one of those Cobol features that Seemed like a good idea at the time it was introduced; but should be avoided !!!
Expounding on both Bill's and Bruce's excellent answers.
Starting with code from Bruce's example.
Perform B100-Load-From-DB thru B500-Save-To-Db
...
B100-Load-From-DB
...
B200-Adjust-Stock-for-Purchases
...
B300-Adjust-Stock-for-Sales
...
Some-Danged-Ol-Thing
...
B400-Calculate-Markdowns
...
B500-Save-To-Db
This still seems reasonably simple enough. Code in each paragraph will be processed in top down order: B100-Load-From-DB, B200-Adjust-Stock-for-Purchases, B300-Adjust-Stock-for-Sales, Some-Danged-Ol-Thing, B400-Calculate-Markdowns, B500-Save-To-Db
As Bill indicated, the addition of GO TO statements to a PERFORM ... THRU block introduces the author of said code to a special quadrant in the Ninth Circle of Hell.
Perform B100-Load-From-DB thru B500-Save-To-Db
...
B100-Load-From-DB
...
GO TO B400-Calculate-Markdowns
...
B200-Adjust-Stock-for-Purchases
...
B300-Adjust-Stock-for-Sales
...
GO TO B200-Adjust-Stock-for-Purchases
...
Some-Danged-Ol-Thing
...
B400-Calculate-Markdowns
...
B500-Save-To-Db
The Hell is exacerbated by yet more "clever thinking" when someone decides to run a portion of the PERFORM ... THRU block.
Perform B200-Adjust-Stock-for-Purchases thru B300-Adjust-Stock-for-Sales
...
Perform B100-Load-From-DB thru B200-Adjust-Stock-for-Purchases
...
Perform B100-Load-From-DB thru Some-Danged-Ol-Thing
There are numerous opportunities to fall through the Looking Glass and continue on into several Alternate Realities. I'm not just pontificating about theoretical possibilities. I'm talking actual experiences in code I've had over the years.
Whilst I was growing up, er I mean learning to code in COBOL, I was all but threatened with being beaten by a large man with a rattan stick if I stepped outta line. As such, I know how to walk on the edge of the precipice and use PERFORM ... THRU with GO TO interspersed throughout and not fall off the edge of the world. However, it makes for very dangerous code that can kill, so more importantly I know how to de-fang code like this and turn it into something civilized.

how to use GO TO in COBOL

I have the following code snippet in one of my COBOL program.
IF FIRST < SECOND
MOVE FIRST TO WS
END-IF.
MOVE SECOND TO WS.
MOVE WS TO RESULT.
I need to use GO TO inside the IF block to jump to the last statement (MOVE WS TO RESULT).
IF FIRST < SECOND
MOVE FIRST TO WS
GO TO <last line.(MOVE WS to RESULT)>
END-IF.
MOVE SECOND TO WS.
MOVE WS TO RESULT.
in other word, i need to skip "MOVE SECOND TO WS.".
what is the simplest way to jump to a specific line in cobol?
I read somewhere that this is possible by defining a PARAGRAPH, but don't know how to define it.
It might seems very simple but I'm newbie to COBOL programming.
Thanks.
----------------* UPDATE *----------
based on #lawerence solution, is this correct?
IF FIRST < SECOND
MOVE FIRST TO WS
GO TO C10-END.
END-IF.
MOVE SECOND TO WS.
C10-END.
MOVE WS TO RESULT.
i just moved back the last statement to be in first level.
GOTO can do what you're looking for, but IF/ELSE would be more direct. You want MOVE SECOND TO WS to run iff the IF block does not, correct?
IF FIRST < SECOND
MOVE FIRST TO WS
ELSE
MOVE SECOND TO WS
END-IF.
MOVE WS TO RESULT.
I hope I got the syntax right, I have never used COBOL and just tried to work off your snippet and this example http://www.fluffycat.com/COBOL/If-and-End-If/. There probably will be situations in the future where you need GOTO, but it A) should be avoided when another control structure will work and B) I haven't the slightest idea how its done
to be honest, COBOL looks pretty miserable lol. ive never seen a language so verbose. good luck with everytihng
EDIT
Mostly for joe...
Cant this all be better done with a min function? I'm sure the syntax is wrong, but:
Move Function Min(FIRST, SECOND) to RESULT
OMFSM! It is not 1974, why are you writing Cobol like that? This:
IF FIRST < SECOND
MOVE FIRST TO WS
END-IF.
MOVE SECOND TO WS.
MOVE WS TO RESULT.
Has a number of problems:
It uses periods to delimit scope, that is nearly three decades deprecated.
It isn't using ELSE
It is trying to use GO TO.
May I suggest the following as the way to approach it since 1985:
If FIRST < SECOND
Move FIRST to WS
Else
Move SECOND to WS
End-IF
Move WS to RESULT
But really, the code should simply read:
If FIRST < SECOND
Move FIRST to RESULT
Else
Move SECOND to RESULT
End-If
Unless the intermediate result is needed in WS. Cobol 66 and 74 used GOTO and periods because they lacked modern control structures. I realize you are a 'newbie', but you should suggest to whoever is teaching you that they really need to upgrade their skills.
jon_darkstar is right when it comes to improving the logic, however if you want to see how GO TO works here goes:
IF FIRST < SECOND
MOVE FIRST TO WS
GO TO C10-RESULT.
END-IF.
MOVE SECOND TO WS.
C10-RESULT.
MOVE WS TO RESULT.
C10-RESULT. starts a paragraph and has to be a unique name in your code SECTION. By convention it should also start with the same prefix as the enclosing section. Therefore this example assumes that your code SECTION is something like C00-MAIN-PROCESS SECTION.
A new non-Answer has brought this silly question to light.
ELSE in the IF is the 100% obvious answer. It is deeply odd that GO TO has to be used whereas ELSE may not be used.
Another way, surprised it didn't come up:
MOVE SECOND TO WS
IF FIRST LESS THAN SECOND
MOVE FIRST TO WS
END-IF
MOVE WS TO RESULT
No ELSE, no GO TO. Extra MOVE executed when FIRST is less than second, though.
To include a GO TO is simple, but stupid. Add a GO TO. A GO TO has to go somewhere (unless using ALTER ... TO PROCEED TO ..., which everyone hopes you weren't), so make a label at the point you want it to arrive, and add the name of that label to the GO TO.
A label is a user-defined word. If referenced (as in this case) it must be unique within a SECTION, if you use SECTIONs, which you don't need to, otherwise unique within the program and whether referenced or not it may not be the same name as something else (like a data-definition or the internal name of a file).
A label is a procedure-name. A procedure-name should terminate with a period/full-stop and the procedure itself should also terminate with a period/full-stop.
What about the MOVE FUNCTION MIN ( ... ) ... as a solution?
Well, it works. If other staff at your site are not used to it, you will not be thanked for using it (without prior discussion, anyway).
What does it do? Well, in Enterprise COBOL, the compiler generates an extra little area, copies the first argument to that area, tests against the second argument, copies the copy of the first argument, or the second argument, whichever is relevant, to the result.
Vs the ELSE, that is an extra storage area defined, an extra instruction for addressability of that, and an extra Assembler move (MVC) plus the lack of ready recognition.
Better for programmers new to COBOL, used to a multitude of functions in other languages? Not really, as they will be soundly beaten if they don't write programs that can be understood (at 2am) by the rest of the staff.
IF FUNCTION MIN(VAR1 VAR2 VAR3 VAR4 VAR5) = 17
It's another downside of FUNCTION. You see, you can do that. Then, at 2am, when the program has crashed 32 lines later, after VAR1 and VAR3 have been changed, are you going to be able to find the result of that IF in the core dump? Maybe, maybe not. Depends if any other functions, and of what type, have been used. At 2am, you don't want that. Not at all.
On the upside, it is less typing. For those who type, rather than use the editor.
In our shop, we'd use the example provided by Bill Woodger. However, we do use periods as scope-terminators. COBOL should be structured and use the KISS principle, just like any other language. This:
MOVE SECOND TO WS.
IF FIRST LESS THAN SECOND
MOVE FIRST TO WS.
MOVE WS TO RESULT.
Note that this only works if we are assured that SECOND and FIRST have numeric values, or that WS is a PIC X() string, not a numeric PIC 9().
This is by far the easiest to read. No ELSE or GO TO required.

Resources