Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Main page
Recent changes
Random page
Help about MediaWiki
Special pages
Niidae Wiki
Search
Search
Appearance
Create account
Log in
Personal tools
Create account
Log in
Pages for logged out editors
learn more
Contributions
Talk
Editing
COBOL
(section)
Page
Discussion
English
Read
Edit
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit
View history
General
What links here
Related changes
Page information
Appearance
move to sidebar
hide
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
====Procedures==== The sections and paragraphs in the procedure division (collectively called procedures) can be used as [[label (programming)|labels]] and as simple [[subroutines]]. Unlike in other divisions, paragraphs do not need to be in sections.{{sfn|ISO/IEC JTC 1/SC 22/WG 4|2014|loc=Β§ 14.4}} Execution goes down through the procedures of a program until it is terminated.{{sfn|ISO/IEC JTC 1/SC 22/WG 4|2014|loc=Β§ 14.6.3}} To use procedures as subroutines, the {{code|PERFORM}} verb is used. A {{code|PERFORM}} statement somewhat resembles a procedure call in a newer languages in the sense that execution returns to the code following the {{code|PERFORM}} statement at the end of the called code; however, it does not provide a mechanism for [[Parameter (computer programming)|parameter passing]] or for returning a result value. If a subroutine is invoked using a simple statement like {{code|PERFORM subroutine|lang=cobolfree}}, then control returns at the end of the called procedure. However, {{code|PERFORM}} is unusual in that it may be used to call a range spanning a sequence of several adjacent procedures. This is done with the {{code|PERFORM sub-1 THRU sub-n|lang=cobolfree}} construct: <syntaxhighlight lang="cobolfree"> PROCEDURE so-and-so. PERFORM ALPHA PERFORM ALPHA THRU GAMMA STOP RUN. ALPHA. DISPLAY 'A'. BETA. DISPLAY 'B'. GAMMA. DISPLAY 'C'. </syntaxhighlight> The output of this program will be: "A A B C". {{code|PERFORM}} also differs from conventional procedure calls in that there is, at least traditionally, no notion of a call stack. As a consequence, nested invocations are possible (a sequence of code being {{code|PERFORM}}'ed may execute a {{code|PERFORM}} statement itself), but require extra care if parts of the same code are executed by both invocations. The problem arises when the code in the inner invocation reaches the exit point of the outer invocation. More formally, if control passes through the exit point of a {{code|PERFORM}} invocation that was called earlier but has not yet completed, the COBOL 2002 standard stipulates that the behavior is [[Undefined behavior|undefined]]. The reason is that COBOL, rather than a "return address", operates with what may be called a continuation address. When control flow reaches the end of any procedure, the continuation address is looked up and control is transferred to that address. Before the program runs, the continuation address for every procedure is initialized to the start address of the procedure that comes next in the program text so that, if no {{code|PERFORM}} statements happen, control flows from top to bottom through the program. But when a {{code|PERFORM}} statement executes, it modifies the continuation address of the called procedure (or the last procedure of the called range, if {{code|PERFORM THRU}} was used), so that control will return to the call site at the end. The original value is saved and is restored afterwards, but there is only one storage position. If two nested invocations operate on overlapping code, they may interfere which each other's management of the continuation address in several ways.<ref name="FR99">{{cite conference | url=http://pages.cs.wisc.edu/~ramali/Papers/paste99.pdf |archive-url=https://web.archive.org/web/20101224060615/http://pages.cs.wisc.edu/~ramali/Papers/paste99.pdf |archive-date=24 December 2010 |url-status=live | title=Identifying Procedural Structure in Cobol Programs | doi=10.1145/381788.316163 | first1=John | last1=Field | first2=G. | last2=Ramalingam | conference=PASTE '99 | isbn=1581131372 | conference-url=http://cseweb.ucsd.edu/~wgg/paste99.html | date=September 1999}}</ref><ref name="VV07">{{cite journal | url=http://www.cs.vu.nl/~nveerman/research/minefield/minefield.pdf | title=Cobol minefield detection | journal=Software: Practice and Experience |date=November 2006 | volume=36 | issue=14 | doi=10.1002/spe.v36:14 | archive-url=https://web.archive.org/web/20070306135410/http://www.cs.vu.nl/~nveerman/research/minefield/minefield.pdf | url-status=dead | archive-date=6 March 2007 | last1=Veerman | first1=Niels | last2=Verhoeven | first2=Ernst-Jan | s2cid=18619757 }}</ref> The following example (taken from {{harvnb|Veerman|Verhoeven|2006}}) illustrates the problem: <syntaxhighlight lang="cobolfree"> LABEL1. DISPLAY '1' PERFORM LABEL2 THRU LABEL3 STOP RUN. LABEL2. DISPLAY '2' PERFORM LABEL3 THRU LABEL4. LABEL3. DISPLAY '3'. LABEL4. DISPLAY '4'. </syntaxhighlight> One might expect that the output of this program would be "1 2 3 4 3": After displaying "2", the second {{code|PERFORM}} causes "3" and "4" to be displayed, and then the first invocation continues on with "3". In traditional COBOL implementations, this is not the case. Rather, the first {{code|PERFORM}} statement sets the continuation address at the end of {{code|LABEL3}} so that it will jump back to the call site inside {{code|LABEL1}}. The second {{code|PERFORM}} statement sets the return at the end of {{code|LABEL4}} but does not modify the continuation address of {{code|LABEL3}}, expecting it to be the default continuation. Thus, when the inner invocation arrives at the end of {{code|LABEL3}}, it jumps back to the outer {{code|PERFORM}} statement, and the program stops having printed just "1 2 3". On the other hand, in some COBOL implementations like the open-source TinyCOBOL compiler, the two {{code|PERFORM}} statements do not interfere with each other and the output is indeed "1 2 3 4 3". Therefore, the behavior in such cases is not only (perhaps) surprising, it is also not portable.<ref name="VV07"/> A special consequence of this limitation is that {{code|PERFORM}} cannot be used to write recursive code. Another simple example to illustrate this (slightly simplified from {{harvnb|Veerman|Verhoeven|2006}}): <syntaxhighlight lang="cobolfree"> MOVE 1 TO A PERFORM LABEL STOP RUN. LABEL. DISPLAY A IF A < 3 ADD 1 TO A PERFORM LABEL END-IF DISPLAY 'END'. </syntaxhighlight> One might expect that the output is "1 2 3 END END END", and in fact that is what some COBOL compilers will produce. But other compilers, like IBM COBOL, will produce code that prints "1 2 3 END END END END ..." and so on, printing "END" over and over in an endless loop. Since there is limited space to store backup continuation addresses, the backups get overwritten in the course of recursive invocations, and all that can be restored is the jump back to {{code|DISPLAY 'END'}}.<ref name="VV07"/>
Summary:
Please note that all contributions to Niidae Wiki may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
Encyclopedia:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)
Search
Search
Editing
COBOL
(section)
Add topic