Executable program requested but PROCEDURE/ENTRY has USING clause - cobol

Does anyone one know what is causing this compilation error? I'm trying to compile a legacy COBOL program using OpenCOBOL. This is the error that I'm getting :
Error: Executable program requested but PROCEDURE/ENTRY has USING clause
This is how my procedure division looks:
procedure division using array-area, m, err, sum1.
And this is the linkage section from my working station:
working-storage section.
77 i picture s99 usage is computational.
77 prev picture s9(8) usage is computational.
77 d picture s9(4) usage is computational.
01 error-mess.
02 filler picture x(22) value ' illegal roman numeral'.
linkage section.
77 m picture s99 usage is computational.
77 err picture s9 usage is computational-3.
77 sum1 picture s9(8) usage is computational.
01 array-area.
02 s picture x(1) occurs 30 times.

working-storage section.
77 i picture s99 usage is computational.
77 prev picture s9(8) usage is computational.
77 d picture s9(4) usage is computational.
01 error-mess.
02 filler picture x(22) value ' illegal roman numeral'.
linkage section.
77 m picture s99 usage is computational.
77 err picture s9 usage is computational-3.
77 sum1 picture s9(8) usage is computational.
01 array-area.
02 s picture x(1) occurs 30 times.
Firstly, there is no need for the words usage and is. I use USAGE for INDEX and POINTER. computational does not need to be spelled in full, COMP is sufficient, and that include COMP-3.
Level-77's are well past their sell-by date, and it would be rare to see them in the LINKAGE SECTION. It will not affect the operation of the program if you change them all to 01-levels.
The data-names are terrible, almost without meaning. We have 30 character to play with, so make them meaningful. What are I, D and M? You can only tell by looking, in detail, at the code.
That seems to be the entire WORKING-STORAGE SECTION (which the LINKAGE SECTION is not part of, they are both instead part of the DATA DIVISION). This would indicate that the program does not have much in the PROCEDURE DIVISION, but also that what does have involves a lot of literals. Which is bad. Makes the program more difficult to maintain.
The program seems to be something to do with Roman numerals. To highlight the confusion that the data-names can cause, the numerals D, I and M are nothing to do with the data-names D, I and M respectively, but if you are more unlucky, one or more of the data-names will be associated with a data-name with a single-character name, but a different one.
Can't say more without more code. If you want a review of it, Stack Exchange has a side, Code Review, exactly for that purpose. Working code, how to do it better...
From the code you have now shown, you need to compile that as a loadable module, so use the -m switch instead of -x:
cobx -m ..otherswitches.. yourprogramname
A program which has been called by z/OS would only have one item on the USING of the PROCEDURE DIVISION, and it would be a group-item which would consist of a two-byte binary (likely COMP, perhaps COMP-4, COMP-5 or BINARY, it would not matter) and a PIC X of up to 100 bytes, perhaps defined with an OCCURS but most likely not. Possibly it would have the word PARM in the name.
The code you have shown does not look much like a legacy z/OS COBOL program :-)
First, you may want to consider upgrading to GnuCOBOL, the new name for OpenCOBOL. There is a discussion area here, https://sourceforge.net/p/open-cobol/discussion/?source=navbar, for any problem, large or small.
GnuCOBOL knows that if you have a USING on the PROCEDURE DIVISION or an ENTRY statement, you cannot expect the program to work if it is compiled as an executable, with the -x switch. It would have to be compiled as a loadable module, with -m.
However, as cschneid has pointed out, in IBM Mainframe COBOLs it is common and valid to have a USING in the first program executed, as this is the way to take a parameter value from the JCL which is running the program.
If this is the case, you will need to change the code, to allow for a parameter from the command-line.
So, which do you have? A CALLed program that should be compiled with -m, or a program which expects a parameter from the operating system?
Whether you upgrade or not, you should get yourself a copy of Gary Cutler's Programming Guide for the OpenCOBOL/GnuCOBOL that you will be using. A search with gary cutler cobol programming guide will allow you to locate the correct one.

Related

Can level 49 be used for STRING purpose

As I'm new to cobol, please help me with the below piece of code.
WORKING-STORAGE SECTION.
01 BAS-REC.
02 INPT-REC.
49 INPT-LEN PIC S9(4) COMP.
49 INPT-TEXT PIC X(150).
02 INPT1-REC.
49 INPT1-LEN PIC S9(4) COMP.
49 INPT1-TEXT PIC X(150).
02 INPT2-REC.
49 INPT2-LEN PIC S9(4) COMP.
49 INPT2-TEXT PIC X(150).
77 VAR1 PIC X(5) VALUE 'APT'.
77 NUM1 PIC 9(1).
I'm using the level 49 for character varying here (to truncate trailing spaces)
Then I have cursor fetch.
After few modification under PROCEDURE DIVISION I'm doing the below.
PERFORM UNTIL SQLCODE=100
PERFORM VARYING NUM1 FROM 1 BY 1 UNTIL NUM1=6
STRING INPT-REC DELIMITED BY ' ',' ',
VAR1 DELIMITED BY ' ',' '
NUM1 DELIMITED BY ' ' INTO INPT2-REC
EXEC SQL
insert query here (which will run 5 times)
END-EXEC
END- PERFORM
END- PERFORM
but in the table the data got inserted only once but it shold have got inserted 5 times and also the INPT2-REC hasn't been concatenated. The INPT2 -REC just contains the value of INPT-REC alone
My question is this a special characteristic of level 49 or am I wrong somewhere?
Note that if you use INPT-REC2 as a host-variable for a VARCHAR-field you will only see the part from INPT-REC since you never update the length-field: it still contains the length it was assigned from INPT-REC.
So you'll have to somehow get the actual length of INPT2-TEXT (e.g. INSPECT the REVERSE of INPT2-TEXT for LEADING SPACES) and move it to INPT2-LENGTH before your EXEC SQL.
As I already said in my comment: there is nothing special about level 49 - you could as well use 48, 33,30 or 05 with the same results. The samples in the DB2 manual probably use 49 since it is the last valid level-number without any special meaning, so it is least likely to cause problems with any level-numbers already used in the program.
As for the query being executed only once: in your loop you are varying NUM1 but are checking whether I=6 - since we don't see I anywhere in your example I can only guess that it is already equal to 6 upon entering the loop.
Level 49 can be treated specially when Embedded SQL is involved, depending on system; this text is copied from the IBM Knowledge Center
Host structure declarations in COBOL must satisfy the following requirements:
COBOL host structures can have a maximum of two levels, even though the host structure might occur within a structure with multiple levels. However, you can declare a varying-length character string, which must be level 49.
A host structure name can be a group name whose subordinate levels name elementary data items.
If you are using the DB2® precompiler, do not declare host variables or host structures on any subordinate levels after one of the following items:
A COBOL item that begins in area A
Any SQL statement (except SQL INCLUDE)
Any SQL statement within an included member
When the DB2 precompiler encounters one of the preceding items in a host structure, it considers the structure to be complete.
So, this seems like a little implementation detail (level 49 for var char) that may spill over into other implementations of COBOL ESQL. Like many details buried in systems, Knowing that would require knowing that.
This particular detail is news to me as of a few minutes ago.
Looking more just now, this came up in the esqlOC contribution for GnuCOBOL recently. A level 49 specific tweak to ensure there was no need to worry about little end big end storage between host and service. So it seems to be a thing.
And an answer to the original question is; depends on compiler environment and ESQL preprocessor, but yeah maybe level 49 fields can be used for VARCHAR.

How to write a cobol code to do the below logic?

1) Read a line of 2000 characters and replace all SPACES with a single "+" plus character. i.e. Convert "A B" to "A+B" or "A B" to "A+B"
2)Read a line of 2000 characters, then search for a specific patterns like "PWD" or "INI" or etc and finally store next 6 characters into a variable.
3) Read a line of 2000 characters and store the last word in the string to a variable.
Edit:
I use Micro Focus COBOL.
This is a screenshot of my piece of code so far.
My code is below. It removes a few spaces but not all. Try writing any sentence with random numbers of spaces in between words in and input file for test-data.
IDENTIFICATION DIVISION.
PROGRAM-ID. SALAUT.
ENVIRONMENT DIVISION.
FILE-CONTROL.
SELECT IN-FILE ASSIGN TO "INFILE"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-IN-FILE-STATUS.
SELECT OUT-FILE ASSIGN TO "OUTFILE"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-OUT-FILE-STATUS.
DATA DIVISION.
FILE SECTION.
FD IN-FILE.
01 FS-IN-FILE PIC X(200).
FD OUT-FILE.
01 FS-OUT-FILE PIC X(200).
WORKING-STORAGE SECTION.
01 WS-ATMA-C.
03 WS-OUT-FILE-STATUS PIC X(02).
03 WS-IN-FILE-STATUS PIC X(02).
03 WS-LOOP-COUNTER PIC 9(03) VALUE 1.
03 WS-IN-EOF PIC X value 'N'.
03 WS-IN-FILE-LEN PIC 9(03).
03 WS-IN-SPACE-CNT PIC 9(03) VALUE 1.
03 FS-IN-FILE-2 PIC X(200).
03 WS-TRIL-SPACE-CNT PIC 9(03).
03 WS-TOT-SPACE-CNT PIC 9(03).
PROCEDURE DIVISION.
MAIN-PARA.
OPEN INPUT IN-FILE.
IF WS-IN-FILE-STATUS <> '00'
EXHIBIT 'IN-FILE-OPEN-ERROR : STOP-RUN'
EXHIBIT NAMED WS-IN-FILE-STATUS
PERFORM MAIN-PARA-EXIT
END-IF.
OPEN OUTPUT OUT-FILE.
IF WS-OUT-FILE-STATUS <> '00'
EXHIBIT 'OUT-FILE-OPEN-ERROR : STOP-RUN'
EXHIBIT NAMED WS-OUT-FILE-STATUS
PERFORM MAIN-PARA-EXIT
END-IF.
PERFORM SPACE-REMOVER-PARA THRU SPACE-REMOVER-PARA-EXIT.
CLOSE IN-FILE.
IF WS-IN-FILE-STATUS <> '00'
EXHIBIT 'IN-FILE-CLOSE-ERROR : STOP-RUN'
EXHIBIT NAMED WS-IN-FILE-STATUS
PERFORM MAIN-PARA-EXIT
END-IF.
CLOSE OUT-FILE.
IF WS-OUT-FILE-STATUS <> '00'
EXHIBIT 'IN-FILE-CLOSE-ERROR : STOP-RUN'
EXHIBIT NAMED WS-OUT-FILE-STATUS
PERFORM MAIN-PARA-EXIT
END-IF.
MAIN-PARA-EXIT.
STOP RUN.
SPACE-REMOVER-PARA.
PERFORM UNTIL WS-IN-EOF = 'Y'
INITIALIZE FS-IN-FILE FS-OUT-FILE WS-IN-FILE-LEN FS-IN-FILE-2
READ IN-FILE
AT END
MOVE 'Y' TO WS-IN-EOF
NOT AT END
INSPECT FS-IN-FILE TALLYING WS-IN-FILE-LEN FOR CHARACTERS
EXHIBIT NAMED WS-IN-FILE-LEN
MOVE 1 TO WS-LOOP-COUNTER
IF WS-IN-FILE-LEN <> 0
PERFORM UNTIL WS-IN-SPACE-CNT <= ZEROS
INSPECT FS-IN-FILE TALLYING WS-TOT-SPACE-CNT FOR ALL " "
INSPECT FUNCTION REVERSE (FS-IN-FILE) TALLYING
WS-TRIL-SPACE-CNT FOR LEADING " "
INITIALIZE WS-IN-SPACE-CNT
COMPUTE WS-IN-SPACE-CNT =
WS-TOT-SPACE-CNT - WS-TRIL-SPACE-CNT
PERFORM VARYING WS-LOOP-COUNTER FROM 1 BY 1
UNTIL WS-LOOP-COUNTER >=
WS-IN-FILE-LEN - (2 * WS-TRIL-SPACE-CNT)
IF FS-IN-FILE(WS-LOOP-COUNTER:2) = " "
STRING FS-IN-FILE(1:WS-LOOP-COUNTER - 1) DELIMITED BY SIZE
FS-IN-FILE(WS-LOOP-COUNTER + 2
: WS-IN-FILE-LEN - WS-LOOP-COUNTER - 2)
DELIMITED BY SIZE
INTO FS-IN-FILE-2
END-STRING
INITIALIZE FS-IN-FILE
MOVE FS-IN-FILE-2 TO FS-IN-FILE
INITIALIZE FS-IN-FILE-2
END-IF
END-PERFORM
INITIALIZE WS-LOOP-COUNTER WS-TRIL-SPACE-CNT WS-TOT-SPACE-CNT
END-PERFORM
WRITE FS-OUT-FILE FROM FS-IN-FILE
IF WS-OUT-FILE-STATUS <> '00'
EXHIBIT 'OUT-FILE-WRITE-ERROR : STOP-RUN'
EXHIBIT NAMED WS-OUT-FILE-STATUS
PERFORM MAIN-PARA-EXIT
END-IF
END-IF
END-READ
END-PERFORM.
SPACE-REMOVER-PARA-EXIT.
EXIT.
As INSPECT REPLACING only allows to replace the same number of bytes you can not use it. As Brian pointed out your COBOL runtime may comes with options like GnuCOBOL's FUNCTION SUBSTITUTE. In any case the question "Which COBOL" is still useful to be answered.
To do Thraydor's approach use UNSTRING to a table using a string pointer. Something along
MOVE 1 TO strpoint
PERFORM VARYING table-idx FROM 1 BY 1
UNTIL table-idx = table-max
UNSTRING your2000line DELIMITED BY ALL SPACES
INTO tmp-table (table-idx)
WITH POINTER strpoint
NOT ON OVERFLOW
EXIT PERFORM
END-UNSTRING
END-PERFORM
Another approach which always work is a simple PERFORM over the 2000 bytes with a bunch of IF your2000line (pos:1) statements (if possible: combine it to a single EVALUATE) checking byte by byte (comparing the last byte for removing the duplicate bytes) transferring the source with replacements to a temporary field and MOVE it back once you're finished
Please edit your question to show what exactly you've tried and you can get much better answers.
Firstly, bear in mind that COBOL is a language of dialects. There are also active commercial compilers which target the 1974, 1985, 2002 (now obsolete, incorporated in 2014) and 2014 Standards. All with their own Language Extensions, which may or many not be honoured in a different COBOL compiler.
If you are targeting your learning to a particular environment (IBM Mainframe COBOL you have said) then use that dialect as a subset of what is available to you in the actual COBOL you are using. Which means using the IBM Manuals.
Don't pick and chose stuff from places and use it just because it somehow seemed like a good idea at the time.
I have to admit that EXHIBIT was great fun to use, but it was only ever a Language Extension, and IBM dropped it by at least the later releases of OS/VS COBOL. It, like ON, was a "debugging" statement, although that didn't prevent their being used "normally". There's additional overhead to using EXHIBIT over a simple DISPLAY. IBM Enterprise COBOL only has a simple DISPLAY.
Whilst you may think it fun to use pictograms (the "oh my goodness, what symbol should I use for this" of a figure attempting to pull his own hair out) be aware that that particular symbol was a latecomer to the 2014 Standard, and if it appears in Enterprise COBOL within the next 20 to 50 years I'd be surprised (very low of the list of things to do, another cute way to write "not equal to" when many already exist, and COBOL even has an ELSE).
Some pointers. Don't have a procedure called "remove-all-the-spaces" if what it does is itself is "everything-including-install-a-new-kitchen-sink". Is it any wonder you can't find why it doesn't work?
Many, many, many COBOL programs have the task of reading a file, until the end, and processing the records in the file. Get yourself one of those working well first. Is that relevant to the "business process" the program is addressing? No, it's just technical stuff, which you can't do without so hide it somewhere. Where? in PERFORMed procedures (paragraphs or SECTIONS). Don't expect someone who quickly wants to know what your program is doing to want to read the stuff which every program does. Hide it.
You can find quite a bit of general advice here about writing COBOL programs. Pay attention to those which advise of the use of full-stops/periods, priming reads, and the general structure of COBOL programs.
It is very important to describe things accurately. Work on good, descriptive, accurate names for data-names and procedures. A file is a collection of records.
You have cut down the size of your data to make testing easier, without realising that you have a problem with your data-definitions when you go back to full-length data. Your "counters" can only hold three digits, when they need to be able to cope with the numbers up to 2000.
There is no point in doing something to a piece of data, and then immediately squishing that something with something else which is not related in any way to the original something.
MOVE SPACE TO B
MOVE A TO B
The first MOVE is redundant, superflous, and does nothing but suck up CPU time and confuse the next reader of your program. "Is there some code missing, because otherwise that's just plain dumb".
This is a variant of that example with the MOVE, and you are doing this all over the place:
INITIALIZE WS-IN-SPACE-CNT
COMPUTE WS-IN-SPACE-CNT =
WS-TOT-SPACE-CNT - WS-TRIL-SPACE-CNT
The INITIALIZE is a waste of space, resources, and an introducer of confusion, and extra lines of code to make your program more difficult to understand.
Also, don't "reset" things after they are used, so that they are "ready for next time". That creates dependencies which a future amender of your program will not expect. Even when expected/noticed, they make the code harder to follow.
Exactly what is wrong with your code is impossible to say without knowing what you think is wrong with it. For instance, there is not even a sign of a "+" replacing any spaces, so if you feel that is what it wrong, you simply haven't coded for it.
You've also only attempted one of the three tasks. If once of those not working is what you think is wrong...
Knowing what you think is wrong is one thing, but there are a lot of other problems. If you sit down and sort those out, methodically, then you'll come up with a "structurally" COBOL program which you'll find its easier to understand what your own code does, and where problems lie.
A B C D E
A+B+C+D+E
To get from the first to the second using STRING, look into Simon's suggestion to use WITH POINTER.
Another approach you could take would be using reference-modification.
Either way, you'd be build your result field a piece at a time
This field intentionally blank
A
A+B
A+B+C
A+B+C+D
A+B+C+D+E
Rather than tossing all the data around each time. There are also other ways to code it, but that can be for later.

Programs hangs when opening COBOL Indexed file

I've recently started a COBOL course and, because of my computer configuration (Windows 7 64 Bits and GNU/Linux 64Bits) I have to use Dosbox to compile and execute programs.
Everything is going well but, I'n finding some troubles when I try to open an Indexed file, either I-O or Ouput mode. I can compile and link but at execution time, dosbox get frozen.
My compiler version is MS-COBOL 5.0 and DosBox is 0.74 (last version).
Does anybody have had this issue? Can someone tell how to fix it.
My code is this one.
Thanks in advance.
IDENTIFICATION DIVISION.
PROGRAM-ID. AGENDA.
AUTHOR. JOSE MARIA RAMIREZ MIRA.
DATE-WRITTEN. 06/05/2014.
DATE-COMPILED. 06/05/2014.
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
SOURCE-COMPUTER. IBM-PC.
OBJECT-COMPUTER. IBM-PC.
SPECIAL-NAMES.
DECIMAL-POINT IS COMMA.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT AGENDA ASSIGN TO DISK "AGENDA.DAT"
ORGANIZATION IS INDEXED
ACCESS IS RANDOM
RECORD KEY IS AG-NICK
FILE STATUS IS AG-STATUS.
DATA DIVISION.
FILE SECTION.
FD AGENDA
RECORD CONTAINS 112 CHARACTERS
LABEL RECORD IS STANDARD
DATA RECORD IS AG-PERSONA.
01 AG-PERSONA.
03 AG-NICK PIC X(25).
03 AG-NOMBRE PIC X(25).
03 AG-APELLIDOS PIC X(50).
03 AG-TELEFONO PIC X(12).
WORKING-STORAGE SECTION.
77 AG-STATUS PIC 99.
88 EXITO VALUE 00.
88 CLAVE-DUPLICADA VALUE 22.
88 CLAVE-NO-ENCONTRADA VALUE 23.
88 SIN-ESPACIO-EN-DISCO VALUE 34.
88 FICHERO-NO-EXISTE VALUE 35.
88 EOF VALUE 10.
PROCEDURE DIVISION.
MAIN-PROCEDURE.
DISPLAY "PROCEDO A ABRIR EL ARCHIVO".
OPEN I-O AGENDA.
IF EXITO THEN
DISPLAY "EL ARCHIVO SE HA ABIERTO"
ELSE
EVALUATE TRUE
WHEN FICHERO-NO-EXISTE
DISPLAY "EL ARCHIVO NO EXISTE"
END-EVALUATE
END-IF.
CLOSE AGENDA.
STOP RUN.
END PROGRAM AGENDA.
Have you tried selecting the file using the OPTIONAL phrase. For example,
SELECT OPTIONAL AGENDA ASSIGN TO DISK "AGENDA.DAT"
ORGANIZATION IS INDEXED
ACCESS IS RANDOM
RECORD KEY IS AG-NICK
FILE STATUS IS AG-STATUS.
The OPTIONAL phrase must be specified for files opened for INPUT, I-O, or EXTEND that need not be present when the program runs.
Against this being the problem is your statement that the problem also occurs with OPEN OUTPUT and the program should in any case be producing some output but as others have remarked the version of COBOL is not well known.
By the way I plugged your program into the online COBOL at http://www.compileonline.com/compile_cobol_online.php
and it worked fine triggering the FICHERO-NO-EXISTE condition name.
But this does raise another point. In my Microfocus manual the file status code of 35 is given as being returned when an OPEN INPUT, I-O or EXTEND is attempted on a NON-OPTIONAL file that does not exist. A file status of 05 is returned if you have used the OPTIONAL phrase and the file does not exist at the time the OPEN is executed.
What is the absolute path to AGENDA.DAT?
Sometimes with legacy DOS programs you can't read/write files inside folders with spaces on its name. Say, if your current folder is C:\ms cobol\ , rename it to C:\mscobol\.
It's worth a try, if this is your case.
DOSBox was designed for gaming.
The problem could be DOSBox missing file and record locking.
DOSBox has more issues like internal file caching, a time bomb with multi-user enabled programs.
You could try vDos: http://sourceforge.net/projects/vdos/.
It is Windows only, but integrates better with it.

What is a Cobol 88-type equivalent in another languages?

I'm learning COBOL now and really liking the 88-type of variables, and I want to know if there are anything like them in another languages (most known languages also, such as C, Objective-C), even using a library.
The only thing I can think being similar is using
#define booleanResult (variableName==95)
But it isn't possible to set boolenResult to true and make variableName assume 95 as value.
05 nicely-named-data PIC X.
88 a-meangingful-condition VALUE "A".
88 another-meaingingful-condition
VALUE "A" "B"
"X" THRU "Z"
SPACE ZERO.
IF a-meaningful-condition
IF another-meaningful-condition
SET a-meaningful-condition TO TRUE
SET another-meaningful-condition
TO TRUE
The IFs test the value referenced by the data-name (conditional variable) that the 88 (condition name) is associated with, for a single value or one of multiple value, which can included ranges (THRU) and figurative-constants (ZERO, SPACE, LOW-VALUES, etc).
The SET, which in this form is a more recent addition to COBOL from the 1985 Standard, will change the value of the data-name to the first value specified on the 88, such that if you immediately referenced the 88 in a test, the test would be true.
COBOL does not have booleans in the sense of something resolving to 0 or 1, or anything else, being false/true.
Any language which supports Objects could be used to mimic the behaviour. Perhaps you've even done it already without really realising it.
As NealB points out in the comments, functions could be used (or a procedure, or a transfer of control to another module) but the data and references to it would not be together and protected from accidental mischief.
COBOL has great flexibility in defining data-structures. The 88-level is a powerful aid to maintaining and understanding programs, as well as writing them in the first place.
I don't know of another language which has a direct and natural element which is equivalent to this, but then there are lots of languages I don't know.
Again NealB makes an important point in the comments about the use of THRU/THROUGH to specify a range of values.
Care does need to be taken. Although the author may think that the data that they want to select can be represented by the range "010" THRU "090", they may not realise that what the compiler does is to include every single possible value in that range, by generating code for greater than or equal to "010" and less than or equal to "090".
If using THRU, ensure that your data cannot contain anything in the range which is not expected. If you mean "010" "020" "030" ... "090" that is fine, as long as the data is validated at its entry-point, so that it can never include any intervening values.
The classic example is "A" THRU "Z" on the Mainframe. We all know what the author means, but the compiler takes it literally. You cannot use "A" THRU "Z" on its own for validation, because in EBCDIC there are "gaps" between three groups of letters, and using "A" THRU "Z" would treat those gaps as true for a use of the 88.
Where the 88 level in some COBOL compilers does fall down, is in the missing "FALSE".
To re-use from the above example:
88 a-meaingingful-condition VALUE "A".
88 a-meaingingful-condition-NOT
VALUE "N".
To test the switch/flag, you use the first 88. To turn the flag.switch off, you have to use the second. Not ideal. See one of the links below for an example of FALSE on the 88 definition.
In olden times, flags/switches were set and reset with MOVE statements. As soon as the MOVE is involved, you have the same problem as you have in trying to use functions. There is no bound relationship between the MOVE and the 88-level VALUE.
These days, SET can be used to change the value of a field, to turn a flag/switch on or off.
05 FILLER PIC X.
88 a-meaingingful-condition
VALUE "A".
88 a-meaingingful-condition-NOT
VALUE "N".
The field being tested does not even need a name (it can be FILLER or omitted (an implied FILLER)).
Of course, as NealB points out in a comment on one of the links below, someone can still get at the field with a MOVE using reference-modification on a group item. So...
01 FILLER.
05 FILLER PIC X.
88 a-meaingingful-condition
VALUE "A".
88 a-meaingingful-condition-NOT
VALUE "N".
Now they can't use reference-modification even, as there is no field to name. The value of the field can only come from a VALUE clause on the definition, or from a SET statement setting one of the 88s to TRUE.
At the stage, the value that a flag/switch has, its actual value, becomes irrelevant.
01 FILLER.
05 FILLER PIC X(7).
88 a-meaingingful-condition
VALUE "APPLE".
88 a-meaingingful-condition-NOT
VALUE "BICYCLE".
Because nothing can be used to test against a literal/data-name, and the field cannot be the target of any verb except SET, you no longer have to check that all fields which say they contain N, or Y, or 0, or 1, do so, and they're not the wrong case, and no other values get placed in those fields.
I'm not suggesting the use of APPLE and BICYCLE, just using them to illustrate the point.
An 88 can also have a value expressed in hexadecimal notation, like any alpha-numeric field:
88 a-meaingingful-condition VALUE X"25".
An 88 can also be specified on a group item, typically with a figurative-constant as the value:
01 a-group-item.
88 no-more-data-for-matching VALUE HIGH-VALUES.
05 major-key PIC X(10).
05 minor-key PIC X(5).
In a file-matching process, the keys can be set to high-values at end-of-file, and the use of the keys will still cause the other file(s) to be processed correctly (keys lower than on this file).
Here are links to a number of questions from SO relating directly, or tangentially with important aspects, to 88-levels.
COBOL level 88 data type
Group variable in cobol
In Cobol, to test "null or empty" we use "NOT = SPACE [ AND/OR ] LOW-VALUE" ? Which is it?
Does a prefix of "NO" have any special meaning in a COBOL variable?
COBOL Data Validation for capital letter?
My first programming language was Cobol, now I am using c# and here is my solution to Cobol's 88 level:
In Cobol:
01 ws-valid-countries pic xx.
88 valid-country 'US', 'UK' 'HK'.
move ws-country to ws-valid-countries
if valid-country
perform...
in C#
string[] ValidCountries = {"US","UK","HK"} ;
if ( ValidCountries.Contains(newCountry.Trim().ToUpper()) )
{
// do something
Think of it as a boolean getter (essentially as in your macro) and a setter (forcing the variable to be the corresponding value). Who says COBOL wasn't modern in 1965?
As others said, just some object programming. Which is more powerful, but far less elegant. Like :
01 MY-DATASET.
05 MY-DEPARTEMENT PIC 9(2).
88 ILE-DE-FRANCE VALUES 75, 77, 78, 91 THRU 95.
Can be roughly translated in old VBA in a class named MyDataset :
Public MyDepartement As Integer
Property Get IleDeFrance() As Boolean
Dim MyArray() As Variant
MyArray = Array(75, 77, 78, 91, 92, 93, 94, 95)
IleDeFrance = UBound(Filter(MyArray, MyDepartement, True)) > -1
End Property
(just tested, it works on VBA-excel2013)
And I made the VBA as simple as possible, no clean getter or setter for the departement number, just a public data. As a class is a depot of data plus coded actions against them, you can do more things inside than a simple 88-level(that's probably why this feature didn't make up to more modern languages). But at a the price of complexity & readability.
Less elegant because the array has to be specifically defined, and testing presence in it has to be specified also. While it's inherent to the wonderful 88 level.

How to display the actual value of a comp variable in cobol

I have the following variable in COBOL program which gets its value from a file, when it is read:
01 Employee-number PIC 09(8) comp
01 Employee-number-x redefines
Employee-number PIC x(04)
I have another variable in the same program:
01 D-element-number PIC 9(04)
Now,
Move Employee-number to D-element-number
Then I write this D-element-number to a file
value read from input file is :
0013
0024
so this value comes to Employee-number and Employee-number-x and I move this value to D-Element-number and write this variable to a output file.
But I get this in the output file:
4660
FFFF
4660
4660 is the decimal equivalent of X'1234'
But I want to see something like:
1234
FFFF
1234
How can I achieve this ?
I am allowed to change the definition of D-element-number but nothing else.
Assuming that when you have X'00001234' you want C'00001234', have a look here. http://ibmmainframes.com/viewtopic.php?p=234231#234231
Ignore the rest of the discussion for now, just concentrate on that post.
This is the key part:
PERFORM UNTIL X-WS-1000 > X-WS-1000-MAX
MOVE WS-1000-BYTE-TBL (X-WS-1000)
TO WS-PACKED-X (1:1)
MOVE WS-PACKED TO WS-DISPLAY
MOVE WS-DISPLAY-X TO WS-2000-BYTE-TBL (X-WS-2000)
SET X-WS-1000 UP BY 1
SET X-WS-2000 UP BY 1
END-PERFORM
You need the exact storage definitions to go with it (don't "correct" anything).
It works by getting the compiler to use the "unpack" instruction (UNPK). This one is working one byte at a time, so simple to explain.
X'12' (an example on-byte field) is put in a two-byte field. X'12ii' (where the value of ii is "irrelevant").
UNPK will then turn this "packed" number into a "zoned" number. A "Zone" is the first four bts of a byte, and for a Zoned number, the four bits are all set to one. So you get an F. Then you get the left-most digit from the first byte. Then you get the second output byte, first four bits set to F, then the second input digit.
Then the UNPK continues with the final byte, which contains one irrelevant digit, and an irrelevant sign. For a Zoned number, the sign and right-most digit occupy the same byte (the sign in the zone) so you get a whole byte of irrelevance.
X'12' -> X'12ii' -> X'F1F1ii'.
The first two bytes of the three-byte output are C'12'.
Nos, what is all fine for numbers, but letters make a mess:
X'AB' -> X'ABii' -> X'FAFBii'
Although F and a digits gives a displayable number, for F and a letter, the result does not mean much directly.
Now the INSPECT ... CONVERTING comes to the rescue: FA gets translated to C'A' (X'C1), and the same for the letters through to F.
Your results after the CONVERTING will be C'AB'.
Should give you enough to work on.
There are other methods, but this is a fair COBOL approximation to the classic Assembler technique with UNPK and a TRANSLATE (TR) and a table of translation values.
If you use your favourite search engine. you should be able to fine more methods, using calculation (more than one), table-lookups, I've even seen a 256-WHEN EVALUATE that "works", but I guess it is a little on the "slow" side.
Thinking further, you actually have a BCD (Binary Coded Decimal) don't you? This is a Packed Decimal, without the sign. You don't have any alphas in your field.
This is even simpler to convert.
01 the-converted-value PACKED-DECIMAL PIC 9(8)V9 VALUE ZERO.
01 FILLER REDEFINES the-converted-value.
05 the-binary-value PIC X(4).
05 FILLER PIC X.
MOVE Employee-number-x TO the-binary-value
MOVE the-converted-value TO D-element-number (with Gilbert's correction to PIC 9(8)).
The "decimal place" is the ii, the ignore value and ignore sign. You no longer need the INSPECT ... CONVERTING ... as you only have numeric digits. If you have a BCD...
A really good way for you to have answered your own question would have been to find out how the number was created in the binary field in the first place.
Didn't try this, but I think it might work:
01 WN-GROUP.
05 Employee-number PIC 9(8) comp.
05 PACKED-ZERO PIC 9(1) COMP-3 VALUE ZERO.
01 WN-PACKED redefines WN-GROUP PIC 9(9) COMP-3.
01 WN-UNPACKED PIC 9(9).
Then in your procedure:
MOVE your-number TO Employee-number
MOVE WN-PACKED TO WN-UNPACKED.
And finally you can move or display WN-PACKED(1:8).

Resources