PROCEDURE DIVISION USING Input Cipher Temp.
INSPECT Input
CONVERTING Alpha-String(1) TO Alpha-String(Cipher)
MOVE Input TO Temp.
EXIT PROGRAM.
COBOL 85 is not taking EXIT PROGRAM. at the end of my program. Whether I use STOP RUN. or not.
prog.cbl: 75: error: syntax error, on or before '.'
prog.cbl: 75: error: unknown or wrong statement, on or before '.'
Try moving the Exit to the right inline with the move. Cobol is not a free format language
the columns on the right are reserved for 01's Section / Divisions
It is going to depend on what you are trying to do.
In the IBM World, "EXIT PROGRAM" means leave this program and return to the CALLer. Since your program is a CALLed program (your have PROCEDURE DIVISION USING) your intent is probably to return to CALLer (although you do mention STOP RUN, which will stop the processing then and there) you either need to shift it to the right, as Bruce has said, if that is what your (unknown) compiler has for returning to the CALLer. Otherwise try GOBACK, in column 12. Otherwise consult your documentation for the compiler. Otherwise tell us which compiler you are using.
Isn't it "End Program", not "Exit Program."?
I think what you actually want is:
End Program YourProgramNameHereThatAgreesWithIdentificationDivisionName.
Related
Is it possible to get and display the current line number in the Cobol program?
For example, C allows do it by the next way:
...
printf("Current line = %d\n", __LINE__);
...
Short answer: No.
There is no portable COBOL way in doing this, especially not in all places like __LINE__ does.
Long answer with potential alternatives:
COBOL 2002 added intrinsic functions for exception handling. Using these you can get the location where the last error happened, which checks are activated.
You could hack something by raising a non-fatal exception and ideally in the same line use that function...
From the standard:
The EXCEPTION-LOCATION function returns an alphanumeric character string, part of which is the implementor-defined location of the statement associated with the last exception status.
So this may provide you with the line number, as the returned value depends on the implementation, additional it seems that - at the time of writing - neither IBM nor MicroFocus nor Fujitsu compilers support that intrinsic function at all.
The GnuCOBOL implementation returns a semicolon-separated list with the last entry being the line number.
The upcoming COBOL standard added the MODULE-NAME intrinsic function - but this will only give the name, not the line reference.
If you are free to choose which implementation you use, then an addition of an extra register COB_SOURCE_LINE / COB_SOURCE_FILE in GnuCOBOL should be relative easy to add...
If the intend is a tracing of some kind: many compilers have an extension READY TRACE/ RESET TRACE. With those two statements (and possibly compiler directives / options) they will at least show the name of sections and paragraphs reached, some may also show the line number. Often this could be redirected to a file and will otherwise go to the default error stream.
If you use GnuCOBOL and compile with -ftrace-all you can also use that for line or statement tracing with self-defined format as specified in COB_TRACE_FORMAT [which can also be adjusted within the COBOL program and limited to the line number].
Q: Is it possible to get and display the current line number in the Cobol program?
There was a feature through COBOL 85 called the DEBUG module. The feature was made obsolete in COBOL 85 and subsequently removed in COBOL 2002. While DEBUG lines were available in the 2002 standard, the DEBUG module was removed from the standard.
NOTE: The DEBUG module may still be available in current compilers.
The feature requires debugging mode in the source-computer paragraph. If the line is removed, source lines with a D or d in column 7 are treated as comments.
Declaratives must be added to access debug-line which is the standard name for the source line number.
I have coded the source such that the source line number of wherever I place perform show-line will be displayed. Notice that show-line doesn't do anything.
Source:
program-id. dbug.
environment division.
source-computer. computer-name debugging mode.
object-computer. computer-name.
data division.
working-storage section.
01 char pic x.
procedure division.
declaratives.
ddebug section.
duse for debugging show-line.
d display "Source-line: " debug-line.
end declaratives.
main-line.
begin.
display "Before"
d perform show-line
display "After"
accept char
stop run.
dshow-line.
end program dbug.
Each implementor has their own means for activating the feature. For the system I use, it's a switch parameter (+D) on the command line. Without the switch parameter the line number will not show. (For GnuCOBOL 3.2 it is, apparently, the environment variable COB_SET_DEBUG with a value of 'Y', 'y' or '1'. ;-))
Command line:
dbug (+D)
Display:
Before
Source-line: 17
After
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.
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.
I am preparing overall knowledge on building a Forth interpreter and want to disassemble some of the generic Forth code words such as +, -, *, etc.
My Gforth (I currently have version 0.7.3, installed on Ubuntu Linux) will allow me to disassemble colon definitions that I make with the command see, as well as the single code word .. But when I try it with other code words, see + or see /, I get an error that says, Code +, and then I'm not able to type in my terminal anymore, even when I press control-c.
I should be able to decompile/disassemble the code words, as shown by the Gforth manual: https://www.complang.tuwien.ac.at/forth/gforth/Docs-html/Decompilation-Tutorial.html
Has anyone else had this issue, and do you know how to fix it?
Reverting to the old ptrace method did it for me.
First, from the command line as user root run:
echo 0 >/proc/sys/kernel/yama/ptrace_scope
After which see should disassemble whatever it can't decompile. Command line example (need not be root):
gforth -e "see + bye"
Output:
Code +
0x000055a9bf6dad66 <gforth_engine+2454>: mov %r14,0x21abf3(%rip) # 0x55a9bf8f5960 <saved_ip>
0x000055a9bf6dad6d <gforth_engine+2461>: lea 0x8(%r13),%rax
0x000055a9bf6dad71 <gforth_engine+2465>: mov 0x0(%r13),%rdx
0x000055a9bf6dad75 <gforth_engine+2469>: add $0x8,%r14
0x000055a9bf6dad79 <gforth_engine+2473>: add %rdx,(%rax)
0x000055a9bf6dad7c <gforth_engine+2476>: mov %rax,%r13
0x000055a9bf6dad7f <gforth_engine+2479>: mov -0x8(%r14),%rcx
0x000055a9bf6dad83 <gforth_engine+2483>: jmpq *%rcx
end-code
Credit: Anton Ertl
Most versions of SEE that I've seen are meant only for decompiling colon definitions. + and / and other arithmetic operations are usually written in assembly code and SEE doesn't know what to do with them. That's why you were getting the CODE error message: they're written in code, not Forth. There are several Forth implementations I've seen that have built in assemblers, but I don't think I've ever seen a dis-assembler. Your best bet for seeing the inner workings of + or / or other such words might be to use DUMP or another such word to get a list of the bytes in the word and either disassemble the word by hand or feed the data into an external disassembler. Or see if you can find the source code for your implementation or a similar one.
SEE is a word that has not a tightly controlled behaviour. It is a kind of best effort to show the code of a word X if invoked as
SEE X
It behaves slightly different according how difficult it is to do this. If you defined the word yourself in the session, you're pretty much guaranteed to get your code back. If it is a built in word, especially if it is a very elementary word like + , it is harder. It may look nothing much like the original definition, because of optimisation or compilation into machine code.
Specifically for gforth, if it gets hard gforth invokes the standard tools that are present on the system to analyse object files. So it may be necessary to install gdb and/or investigate how gforth tries to connect to it. For the concrete example of Ubuntu and gforth 0.7.3 Lutz Mueller gives a recipee.
.
I think SEE does it's job as designed.
There are words in FORTH defined in machine code (often called as primitives) and also there is a possibility to define machine code via assembler by the user ie.:
: MYCODE assembler memonics ;CODE
So the output of SEE shows not Code error, but that (ie.) + word was defined as machine code and one can see the disassembled mnenonics on the right of it's output.
Given the following module:
run(N)->
timer:tc(?MODULE,fct,[N]).
I call it by run(100). from a shell and I have this:
{1,
{'EXIT',{undef,[{parser,loop,"d"},
{timer,tc,3},
{erl_eval,do_apply,5},
{shell,exprs,7},
{shell,eval_exprs,7},
{shell,eval_loop,3}]}}}
100 is interpreted as a char ($d = 100) and not as an integer !
Where is my fault ?
In Erlang, [100] and "d" are indistinguishable, the code you show above isn't the problem. The Erlang shell is being helpful (for certain values of help) and printing [100] as "d" because it's a list containing only integers representing printable characters.
The real problem is the undef error in the above, my guess is that your parser module doesn't contain a function parser:loop/1 that you call via parser:fct/1.
Did you get any warnings on your compilation ? I suspect you will see at least one message about an unused function. As you are learning, if you see a warning message then investigate it, understand it and correct it. Generally speaking, you want your code to have no warning messages.
If a function is called in MFA style then it has to be exported in the source code. From what you've shown it's not clear if it is named "fct" or "loop". So, make sure your naming is consistent, and make sure it is exported : You need this in your source code (assuming the function is called "loop" and takes 1 argument) :
-export([loop/1]).
Error messages in Erlang can be tricky to decipher at first. Take some time to read more and become more familiar with them and you will save yourself lots of time going forward.