Decimals in COBOL - cobol

I'm very new to COBOL. I'm following the tutorials that came with Micro Focus and I can't seem to get the example to work right. I'm trying to print -123.45 and I keep getting the following,
I looked up a number of posts on here and they don't address my problem. I'm using Micro Focus' Visual COBOL in Eclipse. Here's my code,
program-id. tictac as "tictac".
environment division.
configuration section.
data division.
working-storage section.
01 WS-NUM3 PIC S9(3)V9(2) VALUE -123.45.
procedure division.
Display WS-NUM3.
goback.
end program tictac.

The V in your picture clause is an implied decimal point. I think you want a field with PIC -999.99, where the . is an explicit decimal point, for its picture clause.
You might think of this as COBOL making a distinction between how a variable is defined and how it is shown. Sort of like a format string in printf is just specifying how to show a variable, not how it is defined. Though in both cases the definition and how it is shown have to match up to a certain extent.
Choosing the right picture clause for a numeric field is important; if you're doing calculations it can have a significant performance impact.
So it's common to have a field with a definition such as...
PIC 9(4)V99 COMP-3
...and a corresponding field for output purposes such as...
PIC ZZZ9.99
...so that computations can be done on the first, and when displaying the field is necessary one uses a MOVE statement to copy the contents of the first to the second.

Related

Accepting signed values as part of a record

I have a fairly basic Cobol program I'm using to learn about record structures. I'm noticing strange behaviour with gnucobol when passing signed numeric values as part of the record in an ACCEPT statement.
The program is defined as follows:
IDENTIFICATION DIVISION.
PROGRAM-ID. TEST.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Account.
02 Name PIC X(5) VALUE SPACES.
02 Balance PIC S9999V999 VALUE ZEROES.
PROCEDURE DIVISION.
MAIN.
DISPLAY "Enter account details:"
ACCEPT Account.
DISPLAY "Balance is:"
DISPLAY Balance.
STOP RUN.
The behaviour is as follows:
Enter account details:
AAAAA-123.456
Balance is:
+-123.045
I assume this is due to how the value is stored in raw memory.
Is this generally what most cobol compilers do? Is there a way to get cobol interpreting the signed value properly?
I assume this is due to how the value is stored in raw memory.
yes
Is this generally what most cobol compilers do?
a guess: yes (the actual display will vary, but I'm sure most COBOL environments won't do what you seem to want them, at least this way)
Is there a way to get cobol interpreting the signed value properly?
Yes, but there are "COBOL" things to do:
store data in internal format (like you did: signed value with implied 3 decimal positions), but for ACCEPT and likely also DISPLAY use a format that actually has the data as you want, for example a PIC +ZZZ9.999$, for some details look at this answer
never ACCEPT a record, either split into multiple ACCEPT or use a single one with accepting a screen-name, not a record name --> use the SCREEN SECTION for entering the data, this will provide you with two separate fields and with most COBOL environments reasonable input validation.

Variable with usage COMP in COBOL

I am trying to understand how the COBOL variables with COMP Usage clause stores values.
I tried one example as below
01 VAR14 PIC S9(5) USAGE COMP.
MOVE 12345 TO VAR14
DISPLAY VAR14
In SPOOL the value of VAR14 is coming as 0000012345.
S9(5) COMP size is 4 bytes as per manuals so my understanding is VAR14 should be displayed as 000012345.
The binary representation as below:
0000 0000 0000 0000 0011 0000 0011 0100‬
Can someone please help in understanding the output value 0000012345 ?
Thanks
In IBM's Enterprise COBOL, there are four ways to define a binary field: COMP; COMP-4; BINARY; COMP-5.
How does that come about? A COMPUTATIONAL field (COMP for short, and here short for "all COMPUTATIONAL fields") is "implementor defined". Which means what is COMP-something in one compiler, may be COMP-somethingelse in another compiler, or may even have no direct equivalent.
And yes, you can code COMPUTATIONAL, COMPUTATIONAL-4 and COMPUTATIONAL-5 if you want. The compiler will be happy.
To standardise things, the 1985 COBOL Standard introduced BINARY and PACKED-DECIMAL as USAGEs. For portability to other COBOL compilers, these would be the best USAGEs for COMP and COMP-3 (packed-decimal) fields.
What is the difference between these different binary fields? Mostly, none. COMP, COMP-4 and BINARY are in fact synonyms of each other in the compiler (more accurately, COMP-4 and BINARY are synonyms of COMP).
COMP-5, also known as "native binary", is different. COBOL has what you might call "decimal-binary" fields (COMP and siblings). That is, the data is stored as binary but its maximum and minimum values are the number and full value of the PICture clause which is used in the definition.
COMP PIC 9 - can contain zero to nine.
COMP PIC S99 - (signed) can contain -99 to +99.
COMP PIC 999 - can contain zero to 999.
COMP-5 is different.
COMP PIC 9 - can contain zero to 65535.
COMP PIC S99 - (signed) can contain -32768 to +32767.
COMP PIC 999 - can contain zero to 65535.
What happens for COMP-5 is that the PICture is used to define the size of the field (as with other binary fields) but every possible bit-value is valid.
How does the PICture relate to the size of the definition? PIC 9 through PIC 9(4) will be stored in a half-word-sized field (which is two bytes). PIC 9(5) through PIC 9(9) will be stored in a word-sized field (which is four bytes). PIC 9(10) through PIC 9(18) will be stored in a double-word-sized field (eight bytes).
OK, so how does this difference (COMP-5 use all the bits, COMP can only represent the decimal value of the PICture) affect what is defined? Doesn't "native binary" sound much better, and obviously faster, than anything "non-native" would give?
The difference is in how they truncate. And, as scintillating as "native binary" sounds, it is generally slower than using COMP & CO, because of the truncation.
COMP truncates to the decimal value of the PICture. COMP-5 truncates to the size of the field.
Consider (names just for demonstration, only ever use descriptive names):
01 PROGA COMP PIC 9(4).
01 PROGB COMP-5 PIC 9(5).
01 PROGC BINARY PIC 9(4) VALUE 9999.
ADD PROGC TO PROGA
ADD PROGC TO PROGB
Remembering that PROGA has a maximum value of 9999, and noting that 19998 fits easily within the existing size of the field, the compiler can effect the addition and then truncate to the decimal value, all in-place.
Remembering that PROGB has a maximum value of 65535 and there is absolutely fat chance that there is enough room in the original field to successfully add a further 65535, the compiler has to generate a temporary field of double the original size, do the addition, and then truncate back to the original maximum value, getting that result back to the original field.
ADD 1 TO PROGA
ADD 1 TO PROGB
Note that with these two, ADD 1 TO PROGA, since it is less than 9999, will still allow the ADD to be done in place (obviously) but ADD 1 TO PROGB will still require the expansion of the field and all that mucking-about, because PROGB just may have a value of 65535 in it already, so the compiler has to allow for that.
Coming to DISPLAY. You have COMP PIC S9(5), and you get a 10-digit output. Why? OK, size you have worked out, the field is four bytes long. However, that should get you a five-digit output, in the range -99999 to +99999. Let's pretend for a moment that your field was instead COMP-5 PIC S9(5).
With COMP-5 you all the bits are valid, and, for a signed field, your range for a full-word/word is -2,147,483,648 through +2,147,483,647. That's 10 digits, note. Which matches to the 10 digits you got in your output. What happened?
Compiler option TRUNC. If you use compiler option TRUNC(BIN), all your COMP/COMP-4/BINARY fields are treated as COMP-5. End of story. You have TRUNC(BIN) either specifically chosen by you, your project, or as your site default. This is not necessarily a good choice.
Other values of compiler option TRUNC are STD, which does the "normal" truncation for COMP/COMP-4/BINARY, and OPT which does whatever is best (for performance) at the time.
Note, strongly not, that TRUNC(OPT) imposes a contract on the programmer. "I will not, must not, and will never even consider, allow a COMP/COMP-4/BINARY field to have a value which does not conform to it's PICture. If I do, it is all my fault, full-stop, end-of-story, and no crying from me".
Don't, except for the purposes of investigating how things work, ever just up and change a TRUNC setting. If you do, you can break things, and it can be a very, very subtle break.
My advice: TRUNC(BIN), don't use it unless you have to (someone decided, and you have no choice); TRUNC(STD) use if your site is scared of the contract; TRUNC(OPT) use if your site is comfortable with the contract.
Do use COMP-5, for individual field-definitions, where you need to. Where do you need to? For any place you have a binary field whose range is beyond the "decimal value" of its PICture. For instance, look to the size of the CICS COMMAREA and the field which indicates how big an individual example is. Look to a VARCHAR host-field in a COBOL program. Data communicating with JAVA or C/C++ may be like that. Otherwise, for new programs, prefer BINARY, which shows that you are slap-up-to-date with 1985.
Setting TRUNC for investigative purposes.
CBL TRUNC(STD)
ID (or IDENTIFICATION) DIVISION.
Compiler options can also be set by the PARM statement in the JCL for the compile, but you may not have access to that. CBL will override any value set in the PARM. There is an installation option which can prevent the use of CBL (also known as PROCESS). Individual options can also be "fixed" at installation time. If your site has fixed TRUNC or prevented CBL, you won't be able to try these things out.
COMP usage clause will be called as BINARY or COMPUTATION.
COMP usage clause applicable to Numeric data type only.
COMP usage is a binary representation of data.
The data in COMP variables stored memory in pure binary format.
The memory allocation for COMP USAGE is like below.
Picture Number of Bytes
S9 to S9(4) 2
S9(5) to S9(9) 4
S9(9) to S9(18) 8

Different results using OCCURS with different compilers

I'm attempting to output the following row using DISPLAY and am getting the correct result in Micro Focus COBOL in Visual Studio and the Tutorialspoint COBOL compiler, but something strange when running it on a z/OS Mainframe using IBM's Enterprise COBOL:
01 W05-OUTPUT-ROW.
05 W05-OFFICE-NAME PIC X(13).
05 W05-BENEFIT-ROW OCCURS 5 TIMES.
10 PIC X(2) VALUE SPACES.
10 W05-B-TOTAL PIC ZZ,ZZ9.99 VALUE ZEROS.
05 PIC X(2) VALUE SPACES.
05 W05-OFFICE-TOTAL PIC ZZ,ZZ9.99 VALUE ZEROS.
It appears in Enterprise COBOL that the spaces are being ignored, and is adding an extra zero-filled column even though the PERFORM VARYING and DISPLAY code is the exact same in both versions:
PERFORM VARYING W02-O-IDX FROM 1 BY 1
UNTIL W02-O-IDX > W12-OFFICE-COUNT
MOVE W02-OFFICE-NAME(W02-O-IDX) TO W05-OFFICE-NAME
PERFORM 310-CALC-TOTALS VARYING W02-B-IDX FROM 1 BY 1
UNTIL W02-B-IDX > W13-BENEFIT-COUNT
MOVE W02-O-TOTAL(W02-O-IDX) TO W05-OFFICE-TOTAL
DISPLAY W05-OUTPUT-ROW
END-PERFORM
W13-BENEFIT-COUNT is 5 and never changes in the program, so the 6th column is a mystery to me.
Correct output:
Strange output:
Edit: as requested, here is W02-OFFICE-TABLE:
01 W02-OFFICE-TABLE.
05 W02-OFFICE-ROW OCCURS 11 TIMES
ASCENDING KEY IS W02-OFFICE-NAME
INDEXED BY W02-O-IDX.
10 W02-OFFICE-CODE PIC X(6).
10 W02-OFFICE-NAME PIC X(13).
10 W02-BENEFIT-ROW OCCURS 5 TIMES
INDEXED BY W02-B-IDX.
15 W02-B-CODE PIC 9(1).
15 W02-B-TOTAL PIC 9(5)V99 VALUE ZERO.
10 W02-O-TOTAL PIC 9(5)V99 VALUE ZERO.
and W12-OFFICE-COUNT is always 11, never changes:
01 W12-OFFICE-COUNT PIC 99 VALUE 11.
The question is not so much "why does Enterprise COBOL do that?", because it is documented, as "why do those other two compilers generate programs that do what I want?", which is probably also documented.
Here's a quote from the draft of what became the 2014 COBOL Standard (the actual Standard costs money):
C.3.4.1 Subscripting using index-names
In order to facilitate such operations as table searching and
manipulating specific items, a technique called indexing is available.
To use this technique, the programmer assigns one or more index-names
to an item whose data description entry contains an OCCURS clause. An
index associated with an index-name acts as a subscript, and its value
corresponds to an occurrence number for the item to which the
index-name is associated.
The INDEXED BY phrase, by which the index-name is identified and
associated with its table, is an optional part of the OCCURS clause.
There is no separate entry to describe the index associated with
index-name since its definition is completely hardware oriented. At
runtime the contents of the index correspond to an occurrence number
for that specific dimension of the table with which the index is
associated; however, the manner of correspondence is determined by the
implementor. The initial value of an index at runtime is undefined,
and the index shall be initialized before use. The initial value of an
index is assigned with the PERFORM statement with the VARYING phrase,
the SEARCH statement with the ALL phrase, or the SET statement.
[...]
An index-name may be used to reference only the table to which it is
associated via the INDEXED BY phrase.
From the second paragraph, it is clear that how an index is implemented is down to the implementor of the compiler. Which means that what an index actually contains, and how it is manipulated internally, can vary from compiler to compiler, as long as the results are the same.
The last paragraph quoted indicates that, by the Standard, a specific index can only be used for the table which defines that specific index.
You have some code equivalent to this in 310-CALC-TOTALS: take a source data-item using the index from its table, and use that index from the "wrong" table to store a value derived from that in a different table.
This breaks the "An index-name may be used to reference only the table to which it is associated via the INDEXED BY phrase."
So you changed your code in 310-CALC-TOTALS to: take a source data-item using the index from its table, and use a data-name or index defined on the destination table to store a value derived from that in a different table.
So your code now works, and will give you the same result with each compiler.
Why did the Enterprise COBOL code compile, if the Standard (and this was the same for prior Standards) forbids that use?
IBM has a Language Extension. In fact two Extensions, which are applicable to your case (quoted from the Enterprise COBOL Language Reference in Appendix A):
Indexing and subscripting ... Referencing a table with an index-name
defined for a different table
and
OCCURS ... Reference to a table through indexing when no INDEXED BY
phrase is specified
Thus you get no compile error, as using an index from a different table and using an index when no index is defined on the table are both OK.
So, what does it do, when you use another index? Again from the Language Reference, this time on Subscripting using index-names (indexing)
An index-name can be used to reference any table. However, the element
length of the table being referenced and of the table that the
index-name is associated with should match. Otherwise, the reference
will not be to the same table element in each table, and you might get
runtime errors.
Which is exactly what happened to you. The difference in lengths of the items in the OCCURS is down to the "insertion editing" symbols in your PICture for the table you DISPLAY from. If the items in the two tables were the same length, you'd not have noticed a problem.
You gave a VALUE clause for your table items (unnecessary, as you would always put something in them before the are output) and this left your "sixth" column, the five previous columns were written as shorter items. Note the confusion caused when the editing is done to one length and the storing done with a different implicit length, you even overwrite the second decimal place.
IBM's implementation of INDEXED BY means that the length of the item(s) being indexed is intrinsic. Hence the unexpected results when the fields referenced are actually different lengths.
What about the other two compilers? You'd need to hit their documentation to be certain of what was happening (something as simple as the index being represented by an entry-number (so plain 1, 2, 3, etc), and the allowing of an index to reference another table would be enough). There should be two extensions: to allow an index to be used on a table which did not define that index; to allow an index to be used on a table where no index is defined. The two logically come as a pair, and both only need to be specific (the first would do otherwise) because the are specifically against the Standard.
Micro Focus do have a Language Extension whereby an index from one table may be used to reference data from another table. It is not explicit that this includes referencing a table with no indexes defined, but this is obviously so.
Tutorialspoint uses OpenCOBOL 1.1. OpenCOBOL is now GnuCOBOL. GnuCOBOL 1.1 is the current release, which is different and more up-to-date than OpenCOBOL 1.1. GnuCOBOL 2.0 is coming soon. I contribute to the discussion area for GnuCOBOL at SourceForge.Net and have raised the issue there. Simon Sobisch of the GnuCOBOL project has previously approached Ideaone and Tuturialspoint about their use of the out-dated OpenCOBOL 1.1. Ideaone have provided positive feedback, Tutorialspoint, who Simon has again contacted today, nothing yet.
As a side-issue, it looks like you are using SEARCH ALL to do a binary-search of your table. For "small" tables, it is likely that the overhead of the mechanics of the generalised binary-search provided by SEARCH ALL outweighs any expected savings in machine resources. If you were to be processing large amounts of data, it is likely that a plain SEARCH would be more efficient than the SEARCH ALL.
How small is "small" depends on your data. Five is likely to be small close to 100% of the time.
Better performance than SEARCH and SEARCH ALL functionality can be achieved by coding, but remember that SEARCH and SEARCH ALL don't make mistakes.
However, especially with SEARCH ALL, mistakes by the programmer are easy. If the data is out of sequence, SEARCH ALL will not operate correctly. Defining more data than is populated gets a table quickly out of sequence as well. If using SEARCH ALL with a variable number of items, consider using OCCURS DEPENDING ON for the table, or "padding" unused trailing entries with a value beyond the maximum key-value that can exist.
I'd be very hesitant about mixing VALUE with OCCURS and re-code the WS as
01 W05-OUTPUT-ROW.
05 W05-OFFICE-NAME PIC X(13).
05 W05-BENEFITS PIC X(55) VALUE SPACES.
05 FILLER REDEFINES W05-BENEFITS.
07 W05-BENEFIT-ROW OCCURS 5 TIMES.
10 FILLER PIC X(02).
10 W05-B-TOTAL PIC ZZ,ZZ9.99.
05 FILLER PIC X(02) VALUE SPACES.
05 W05-OFFICE-TOTAL PIC ZZ,ZZ9.99 VALUE ZEROS.
Perhaps it has something to do with the missing fieldname?
Ah! evil INDEXED. I'd make both ***-IDX variables simple 99s.

Calling subroutine when using OpenCOBOLIDE

I am using OpenCOBOLIDE and trying to just simply call a subroutine. I am following along in a TutorialPoint document. I followed all the instructions but cannot seem to figure out why when I call the subroutine it still cannot find the module I am trying to link to.
Here is my main file:
IDENTIFICATION DIVISION.
PROGRAM-ID. MAIN.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-STUDENT-ID PIC 9(4) VALUE 1000.
01 WS-STUDENT-NAME PIC A(15) VALUE 'Tim'.
PROCEDURE DIVISION.
CALL 'UTIL' USING WS-STUDENT-ID, WS-STUDENT-NAME.
DISPLAY 'Student Id : ' WS-STUDENT-ID
DISPLAY 'Student Name : ' WS-STUDENT-NAME
STOP RUN.
And here is my subroutine:
IDENTIFICATION DIVISION.
PROGRAM-ID. UTIL.
DATA DIVISION.
LINKAGE SECTION.
01 LS-STUDENT-ID PIC 9(4).
01 LS-STUDENT-NAME PIC A(15).
PROCEDURE DIVISION USING LS-STUDENT-ID, LS-STUDENT-NAME.
DISPLAY 'In Called Program'.
MOVE 1111 TO LS-STUDENT-ID.
EXIT PROGRAM.
I am using OpenCobolIDE-4.6.5 if that helps.
The message I get is:
MAIN.cbl:16: libcob: Cannot find module 'UTIL'
If you look at the COBOL option in the menu-bar at the top of the screen select Program type you'll see two options: Executable; Module.
For the program which is started from the OS, your MAIN, you need that to be set to Executable. For the CALLed program, UTIL, you need that to be set to Module.
You should also try to install GnuCOBOL, which is the new name for OpenCOBOL. GnuCOBOL is actively maintained. The GnuCOBOL site is currently at SourceForge.Net. There is a recent discussion in the Help getting started as to exactly how to do that (for Ubuntu, anyway, if you are using something more different, post a question and you'll get assistance).
Disclosure: I am a Moderator there.
You should be aware that the concept of "main" does not actually exist in COBOL itself, not in the way of other languages you may know. Exactly how the initial program operates is down to implementation and operating system.
On Linux/Unix/Windows the initial program is compiled differently, so it is more like a "main". On an IBM Mainframe it is not compiled differently.
Also note that a subroutine can CALL another subroutine. You would need to compile both as Module in your case. It is not COBOL dictating that, but the OS and the implementation.
If learning COBOL, be modern about it. In the PROCEDURE DIVISION do not attach a full-stop/period to a line of code, and only use them where they are necessary, not where they are optional. In earlier COBOL Standards the full-stop/period was the only scope-terminator available, and for backwards-compatibility it still acts as a "super-scope-terminator" which is usually not what you want, and if it were to be what you want, it is bad practice as any other reader would consider it an error and wonder what you had really intended.
A full-stop/period is needed: to terminate the PROCEDURE DIVISION statement; to terminate a paragraph or SECTION label; to terminate a paragraph or SECTION itself; to terminate a program.
If using a COPY or REPLACE compiler-directive, you also need to terminate those with a full-stop/period.
Your subroutine does not contain a GOBACK, RETURN or EXIT PROGRAM. Even if that were to work, it would be non-Standard, non-portable and would not be a good way to learn COBOL.
In the real-world of COBOL programming you won't/may never find a PIC A used. It is considered of little benefit, as all it does is prevent you using that field as a source and a numeric field as a target in the same statement. Using a PIC X instead of PIC A is what you will normally see, so you may as well start now (despite what any tutorial may say).
That's an opinion, and you've no need to follow that advice, but in practice that is the way it is.
Using commas (or any other non-relevant separator) in COBOL statements only clouds a program. They have no genuine value. This is valid:
PROCEDURE DIVISION USING LS-STUDENT-ID, , , , , LS-STUDENT-NAME.
So what would be the point?
There is no benefit in defining a field as numeric simply because it contains a number. You are never going to do a calculation with the student-id, so it is much better for it to be PIC X not PIC 9.
independantly of Bill's excellent remarks, I did face the same problem with OpenCobolIDE today. And found a solution.
You have to parameter the paths of the .dll created so that the caller programm can find the called module. When you compile [F8] your module, you have a message that tells you where the dll has gone :
Compilation succeeded (output: C:\Users\Mariah Flaim\bin\MyModule.dll)
Now, you have to go to the parameters [F2], to the compiler tab, and add a link to this path in the "Library path" list. And, how miracle, the call happens!!!
A very simple example, just to try, I've made work after this manoeuver, starting from their templates(would need more work to be clean, but it works).
Calling program :
IDENTIFICATION DIVISION.
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
PROGRAM-ID. YOUR-PROGRAM-NAME.
ENVIRONMENT DIVISION.
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
CONFIGURATION SECTION.
*-----------------------
INPUT-OUTPUT SECTION.
*-----------------------
DATA DIVISION.
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
FILE SECTION.
*-----------------------
WORKING-STORAGE SECTION.
01 PARAMETRES.
02 PA-RETURN-CODE PIC 99 VALUE 0.
*-----------------------
PROCEDURE DIVISION.
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
MAIN-PROCEDURE.
**
* The main procedure of the program
**
CALL "MYMODULE"
USING PARAMETRES
DISPLAY "Hello world"
STOP RUN.
** add other procedures here
END PROGRAM YOUR-PROGRAM-NAME.
Called Module :
IDENTIFICATION DIVISION.
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
PROGRAM-ID. MYMODULE.
ENVIRONMENT DIVISION.
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
CONFIGURATION SECTION.
*-----------------------
INPUT-OUTPUT SECTION.
*-----------------------
DATA DIVISION.
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
FILE SECTION.
*-----------------------
WORKING-STORAGE SECTION.
*-----------------------
LINKAGE SECTION.
**-*-*-*-*-*-*-*-*-*-*-*-*-*
01 PARAMETRES.
02 PA-RETURN-CODE PIC 99 VALUE 0.
PROCEDURE DIVISION USING PARAMETRES.
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
MAIN-PROCEDURE.
**
* The main procedure of the program
**
DISPLAY "Glu"
MOVE 0 TO PA-RETURN-CODE
GOBACK.
** add other procedures here
END PROGRAM MYMODULE.
Output :
Glu
Hello world

Why is this causing an error in Cobol?

Why would this if statement below need a NEXT SENTENCE because there is a statement in both the IF and the ELSE part of the statement.
Question: Why is this an error in the if statement.
CHECK-PARM.
IF NAME = 'SW89JS' THEN 1183
E-NAME = 'FALSE'
Expected a verb or "NEXT SENTENCE", but found "E-NAME". The statement was discarded.
ELSE
E-NAME = 'TRUE'
"E-NAME" was invalid. Skipped to the next verb, period or procedure-name definition.
P-NAME = 'SW89JS'
END-IF.
Since it is somewhere buried in this answer, I'm going to repeat it up hear, even expand it a little.
You have a value you are testing. From the name it likely comes from the PARM on the EXEC card in the JCL.
You test the value, set a flag (TRUE/FALSE literals) on the result of the value, and use it later.
With an 88 you can make that parm value into the flag itself.
01 NAME PIC X(6).
88 IT-IS-SW89JS VALUE "SW89JS".
Now you can never get your flags out of step, as you only have one flag. One fewer flag to understand and potentially get wrong.
Because we don't have assignments in COBOL.
MOVE 'TRUE' TO E-NAME
or
MOVE data-name-with-value-true TO E-NAME
or
01 FILLER PIC X VALUE SPACE.
88 IT-IS-SW89JS VALUE "Y".
SET IT-IS-SW89JS TO TRUE
or
01 NAME PIC X(6).
88 IT-IS-SW89JS VALUE "SW89JS".
And with the last forget about anything else.
COBOL is not like many other languages. No strings, as you may know them. No arrays, as you may know them. No assignments. No booleans. No user-written functions. Few Intrinsic Functions. No public function libraries. It does have some other stuff :-)
A couple of points from the comments.
COBOL is a language of fixedness. Fixed-length field, fixed-length tables. The length of the data in a 30-byte field is 30 bytes. The length of the content of the field, in terms of what the data represents, is something the programmer has to work out, if needed. Mostly we don't need it, so we don't have to work it out.
The fixedness also imposes limits. So we think of ways to do things differently, so we don't have a limit, waiting to bust, dangling over our heads. We don't just pick a function which looks like maybe it makes life easy for us (less code to write) regardless of how it carries out the task. Usually we don't have a function anyway, and we write specific code to be re-used, through a CALL, for a specific system or set of systems.
A COBOL program may take longer to write (I say may because 90+% of the time it is a question of starting out by copying a program which is close to what you want, and then making it specific) but that program may have a lifetime of 30 years. It may be changed many times during its life. It may never be changed, but need to be understood many times during that period.
Conceptually, COBOL is a very different language from those with assignments/strings/arrays. If you are supposed to pick up COBOL with no training, there will be many pitfalls.
Yes, Bruce Martin, I suppose COBOL does have an assignment: the COMPUTE. The left-side can only be numeric or numeric-edited, although there can be multiple fields, and the right-side can only have numerics (or intrinsic functions returning numerics). It only supports basic mathematical operators (+, -, , /, *). It does allow rounding of the final answer if desired, and also allows for interception of "overflow" (ON SIZE ERROR).
It can be used as a simple assignment:
COMPUTE A = B
This will generate the same code as:
MOVE B TO A
Some people do this, though I've never really worked out why. There is a rumour that it means you can use ON SIZE ERROR (and don't forget END-COMPUTE if you do use it) to trap an overflow.
However, I always make my fields big enough, or deliberately truncate when that is the result I want, so I don't really get that.
In short, welcome to COBOL. Don't expect it to be like any other language you've used.
As Bill stated the problem is:
E-NAME = 'FALSE'
In Cobol (unlike most other languages), each statement starts with a control word
e.g.
Compute abc = 123
Move 'FALSE' to E-NAME
Perform abc
Call 'xyz'
With Cobol the control word on the far left of a line tells you what the statement is doing.
Also as Bill stated, in Cobol a boolean is normally define using 88 levels:
01 FILLER PIC X VALUE SPACE.
88 IS-ENAME VALUE "Y".
88 ENAME-OFF VALUE "N".
and your code becomes
IF NAME = 'SW89JS' THEN
Set ENAME-OFF to true
ELSE
Set IS-ENAME to true
Move 'SW89JS' to P-NAME
END-IF.

Resources