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.
Related
What is the benefit of using paragraphs and sections for executing pieces of code, instead of using a subprogram instead? As far as I can see paragraphs and sections are dangerous because they have an non intuitive control flow, its easy to fall through and execute stuff you never meant to execute, and there is no variable (item) scoping, therefore it encourages a style of programming where everything is visible to everything else. Its a slippery soup.
I read a lot, but I could not find anything related to the comparative benefit of paragraphs/sections vs a subprogram. I also asked online some people in some COBOL forum, but their answers were along the lines of "is this a joke" or "go learn programming"(!!!).
I do not wish to engage in a discussion of stylistic preferences, everyone writes the way that their brain works, I only want to know, is there any benefit to using paragraphs/sections for flow control? As in, are there any COBOL operations that can be done only by using paragraphs/sections? Or is it just a remnant of an early way of thinking about code?
Because no other language I know of has mimicked that, so it either has some mechanical concrete essential reason to exist in COBOL, or it is a stylistic preference of the COBOL people. Can someone illuminate me on what is happening?
These are multiple questions... the two most important ones:
Are there any COBOL operations that can be done only by using paragraphs/sections?
Yes. A likely not complete list:
USE statements in DECLARATIVES can only apply to a paragraph or a section. These are used for handling file errors and exceptions. Not all compilers support this COBOL standard feature in full.
Segmentation (primary: a program that is only partially loaded in memory) is only possible with sections; but that is to be considered a "legacy feature" (at least I don't know of people actually using it this way explicitly); see the comment of Gilbert Le Blanc for more details on this
fall-through, many other languages have this feature with a kind of a switch statement (COBOL's EVALUATE, which is not the same as a common switch but can be used similar has an explicit break and no fall-through)
GO TO DEPENDING ON (could be recoded to achieve something similar with EVALUATE and then either PERFORM, if the paragraphs are expected to fall-through, which is not uncommon, then that creates a lot of extra code)
GO TO in general and especially nice - the old obsolete ALTER statement
PERFORM statement, format 1 "out-of-line"
file state is only shared between programs when you define it as EXTERNAL, and you often want to have a file state being limited to a single program
up to COBOL85: EXIT statement (plain without anything else, actually doing nothing else then a CONTINUE would)
What is the benefit of using paragraphs and sections for executing pieces of code, instead of using a subprogram instead?
shared data (I guess you know of programs with static data or otherwise (module)global data that is shared between functions/methods and also different source code files)
much less overhead than a CALL is
consistency:
you know what's in your code, you don't know what another program does (or at least: you cannot guarantee that it will do the same some years later exactly the same)
easier to extend/change: adding another variable (and also removing part of it, change its size) to a CALL USING means that you also have to adjust the called program - and all programs that call this, even when you place the complete definition in a copybook, which is very reasonable, this means you have to recompile all programs that use this
a section/paragraph is always available (it is already loaded when the program runs), a CALLed program may not be available or lead to an exception, for example because it cannot be loaded as its parameters have changed
less stuff to code
Note: While not all compilers support this you can work around nearly all of the runtime overhead and consistency issue when you use one source files with multiple program definitions in (possibly nested) and using a static call-convention. This likely gives you the "modern" view you aim for with scope-limitation of variables, within the programs either persistent (like local-static) when defined in WORKING-STORAGE or always passed when in LINKAGE or "local-temporary" when in LOCAL-STORAGE.
Should all code of an application be in one program?
[I've added this one to not lead to bad assumptions] Of course not!
Using sub-programs and also user-defined functions (possibly even nested providing the option for "scoped" and "shared" data) is a good thing where you have a "feature boundary" (for example: access to data, user-interface, ...) or with "modern" COBOL where you have a "language boundary" (for example: direct CALLs of C/Java/whatever), but it isn't "jut for limiting a counter to a section" - in this case: either define a variable which state is not guaranteed to be available after any PERFORM or define one for the section/paragraph; in both cases it would be reasonable to use a prefix telling you this.
Using that "separate by boundary" approach also takes care of the "bad habit of everything being seen by everyone" issue (which is in any case only true for "all sections/paragraphs in the same program).
Personal side note: I would only use paragraphs where it is a "shop/team rule" (it is better to stay consistent then to do things different "just because they are better" [still providing an option to possibly change the common rule]) or for GO TO, which I normally not use.
SECTIONs and EXIT SECTION + EXIT PERFORM [CYCLE] (and very rarely GOBACK/EXIT PROGRAM) make paragraphs nearly unnecessary.
very short answer. subroutines!!
Subroutines execute in the context of the calling routine. Two virtues: no parameter passing, easy to create. In some languages, subroutines are private to (and are part of) the calling (invoking) routine (see various dialects of BASIC).
direct answer: Section and Paragraph support a different way of thinking about programming. Higher performance than call subprogram. Supports overlays. The "fall thru" aspect can be quite useful, a feature rather than a vice. They may be necessary depending on what you are doing with a specific COBOL compiler.
See also PL/1, BAL/360, architecture 360/370/...
As a veteran Cobol dinosaur, I would say asking about the benefit is not the right question. I used paragraph (or section) differently than a subprogram. The right question in my opinion is when to use them logically. If I can make an analogy, if you have a Dog java class, you will write Dog-appropriate methods within it. If there's a cat involved, you may need a helper class. In this case the helper class is the subprogram. Though, you can instead code the helper class methods inside the Dog class, but that will be bad coding.
In any other language I would recommend putting self contained functions into subroutines.
However in COBOL not so much. If the code is very likely to be used in other programs then a subroutine is a good idea. Otherwise not!
The reason being the total lack of any checks on the number type or existence of passed parameters at compile time. Small errors in call statements lead to program crashes at run time. Limiting the use of sub-routines and carefully checking the calling code for errors makes for a more reliable program.
Using paragraphs any type mismatch will be flagged at compile time, or, an automatic conversion will occur.
I'm re-building a Lua to ES3 transpiler (a tool for converting Lua to cross-browser JavaScript). Before I start to spend my ideas on this transpiler, I want to ask if it's possible to convert Lua labels to ECMAScript 3. For example:
goto label;
:: label ::
print "skipped";
My first idea was to separate each body of statements in parts, e.g, when there's a label, its next statements must be stored as a entire next part:
some body
label (& statements)
other label (& statements)
and so on. Every statement that has a body (or the program chunk) gets a list of parts like this. Each part of a label should have its name stored in somewhere (e.g, in its own part object, inside a property).
Each part would be a function or would store a function on itself to be executed sequentially in relation to the others.
A goto statement would lookup its specific label to run its statement and invoke a ES return statement to stop the current statements execution.
The limitations of separating the body statements in this way is to access the variables and functions defined in different parts... So, is there a idea or answer for this? Is it impossible to have stable labels if converting them to ECMAScript?
I can't quite follow your idea, but it seems someone already solved the problem: JavaScript allows labelled continues, which, combined with dummy while loops, permit emulating goto within a function. (And unless I forgot something, that should be all you need for Lua.)
Compare pages 72-74 of the ECMAScript spec ed. #3 of 2000-03-24 to see that it should work in ES3, or just look at e.g. this answer to a question about goto in JS. As usual on the 'net, the URLs referenced there are dead but you can get summerofgoto.com [archived] at the awesome Internet Archive. (Outgoing GitHub link is also dead, but the scripts are also archived: parseScripts.js, goto.min.js or goto.js.)
I hope that's enough to get things running, good luck!
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.
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.
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.