Sorry to bother you all but I am stuck on my homework for COBOL. I've made two attempts, neither of which is working as expected.
The two attempts and their output are shown below followed by the final results it needs to be. I thank you all for your help.
First attempt:
IDENTIFICATION DIVISION.
PROGRAM-ID. MAIL-LABEL.
*
******************************************************************
* This program prints duplicate side by side mailing labels.
******************************************************************
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
开发者_运维百科FILE-CONTROL.
SELECT LABEL-FILE-IN
ASSIGN TO 'MAIL-LABEL.SEQ'
ORGANIZATION IS LINE SEQUENTIAL.
SELECT LABEL-FILE-OUT
ASSIGN TO 'MAIL-LABEL.RPT'
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD LABEL-FILE-IN.
01 LABEL-RECORD-IN.
05 NAME-IN PIC X(20).
05 ADDRESS-IN PIC X(20).
05 CITY-STATE-ZIP-IN PIC X(20).
FD LABEL-FILE-OUT.
01 LABEL-RECORD-OUT.
05 LEFT-LABEL-OUT PIC X(20).
05 BLANK-OUT PIC X(15).
05 RIGHT-LABEL-OUT PIC X(20).
05 BLANK-A-OUT PIC X(5).
WORKING-STORAGE SECTION.
01 ARE-THERE-MORE-RECORDS PIC X(3) VALUE 'YES'.
PROCEDURE DIVISION.
100-MAIN.
OPEN INPUT LABEL-FILE-IN
OPEN OUTPUT LABEL-FILE-OUT
PERFORM UNTIL ARE-THERE-MORE-RECORDS = 'NO'
READ LABEL-FILE-IN
AT END
MOVE 'NO' TO ARE-THERE-MORE-RECORDS
NOT AT END
PERFORM 200-PROCESS-ONE-RECORD
END-READ
END-PERFORM
CLOSE LABEL-FILE-IN
CLOSE LABEL-FILE-OUT
STOP RUN.
200-PROCESS-ONE-RECORD.
MOVE NAME-IN TO LEFT-LABEL-OUT
MOVE ADDRESS-IN TO BLANK-OUT
MOVE CITY-STATE-ZIP-IN TO RIGHT-LABEL-OUT
MOVE SPACES TO BLANK-A-OUT
WRITE LABEL-RECORD-OUT.
This produces:
*IAN HENDERSON 1309 SPRINGBANKDETROIT MI 48024
*JANET LEASA 12700 GRATIOT SWARREN MI 48077
*COREY HAYES 400 BRUSH ST. DETROIT MI 48024
*SCOTT TOKLEY 2003 INDIAN RD.TAYLOR MI 48075
*JUDY FISHER 2200 WOODWARD ADETROIT MI 48025
*SHAWN MITCHELL 510 HOLLYWOOD PDETROIT MI 48025
*MARCUS PILLON 1450 JOY RD DEARBORN MI 48077
*BRIAN GUENETTE 456 TRUMBULL STDETROIT MI 48024
*KIM MIKA 456 LAFAYETTE SDETROIT MI 48024
*KYLE THOMPSON 1617 MAPLE RD. WARREN MI 48056
*SUE DONALDSON 11 CASS AVE. DETROIT MI 48024
My second attempt:
IDENTIFICATION DIVISION.
PROGRAM-ID. MAIL-LABEL.
*
******************************************************************
* This program prints duplicate side by side mailing labels.
******************************************************************
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT LABEL-FILE-IN
ASSIGN TO 'MAIL-LABEL.SEQ'
ORGANIZATION IS LINE SEQUENTIAL.
SELECT LABEL-FILE-OUT
ASSIGN TO 'MAIL-LABEL.RPT'
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD LABEL-FILE-IN.
01 LABEL-RECORD-IN.
05 NAME-IN PIC X(20).
05 ADDRESS-IN PIC X(20).
05 CITY-STATE-ZIP-IN PIC X(20).
FD LABEL-FILE-OUT.
01 LABEL-RECORD-OUT.
05 LEFT-LABEL-OUT PIC X(20).
05 BLANK-OUT PIC X(15).
05 RIGHT-LABEL-OUT PIC X(20).
05 BLANK-A-OUT PIC X(5).
WORKING-STORAGE SECTION.
01 ARE-THERE-MORE-RECORDS PIC X(3) VALUE 'YES'.
PROCEDURE DIVISION.
100-MAIN.
OPEN INPUT LABEL-FILE-IN
OPEN OUTPUT LABEL-FILE-OUT
PERFORM UNTIL ARE-THERE-MORE-RECORDS = 'NO'
READ LABEL-FILE-IN
AT END
MOVE 'NO' TO ARE-THERE-MORE-RECORDS
NOT AT END
PERFORM 200-PROCESS-ONE-RECORD
END-READ
END-PERFORM
CLOSE LABEL-FILE-IN
CLOSE LABEL-FILE-OUT
STOP RUN.
200-PROCESS-ONE-RECORD.
MOVE NAME-IN TO LEFT-LABEL-OUT
MOVE ADDRESS-IN TO LEFT-LABEL-OUT
MOVE CITY-STATE-ZIP-IN TO LEFT-LABEL-OUT
MOVE SPACES TO BLANK-OUT
MOVE NAME-IN TO RIGHT-LABEL-OUT
MOVE ADDRESS-IN TO RIGHT-LABEL-OUT
MOVE CITY-STATE-ZIP-IN TO RIGHT-LABEL-OUT
MOVE SPACES TO BLANK-A-OUT
WRITE LABEL-RECORD-OUT
produced:
*DETROIT MI 48024 DETROIT MI 48024
*WARREN MI 48077 WARREN MI 48077
*DETROIT MI 48024 DETROIT MI 48024
*TAYLOR MI 48075 TAYLOR MI 48075
*DETROIT MI 48025 DETROIT MI 48025
*DETROIT MI 48025 DETROIT MI 48025
*DEARBORN MI 48077 DEARBORN MI 48077
*DETROIT MI 48024 DETROIT MI 48024
*DETROIT MI 48024 DETROIT MI 48024
*WARREN MI 48056 WARREN MI 48056
*DETROIT MI 48024 DETROIT MI 48024
What I need to end up with is something like:
*IAN HENDERSON IAN HENDERSON
*1309 SPRINGBANK ST. 1309 SPRINGBANK ST.
*DETROIT MI 48024 DETROIT MI 48024
*JANET LEASA JANET LEASA
*12700 GRATIOT ST. 12700 GRATIOT ST.
*WARREN MI 48077 WARREN MI 48077
*COREY HAYES COREY HAYES
*400 BRUSH ST. 400 BRUSH ST.
*DETROIT MI 48024 DETROIT MI 48024
*SCOTT TOKLEY SCOTT TOKLEY
*2003 INDIAN RD. 2003 INDIAN RD.
*TAYLOR MI 48075 TAYLOR MI 48075
What's wrong with my code?
Normally, I wouldn't give this much help for homework but, since you've put a fair bit of effort into it already and you're unlikely to find many of us dinosaurs here, I'll help you out.
Your problem is here (ignore the things in parentheses on the right, they're just comments to help you out):
200-PROCESS-ONE-RECORD.
MOVE NAME-IN TO LEFT-LABEL-OUT
MOVE ADDRESS-IN TO LEFT-LABEL-OUT (overwrite)
MOVE CITY-STATE-ZIP-IN TO LEFT-LABEL-OUT (overwrite)
MOVE SPACES TO BLANK-OUT
MOVE NAME-IN TO RIGHT-LABEL-OUT
MOVE ADDRESS-IN TO RIGHT-LABEL-OUT (overwrite)
MOVE CITY-STATE-ZIP-IN TO RIGHT-LABEL-OUT (overwrite)
MOVE SPACES TO BLANK-A-OUT
WRITE LABEL-RECORD-OUT (only wrote one line)
This is the paragraph that processes one record. What you are doing here is putting three things into both the left and right output sections (so that the first two are being overwritten).
What you need is a toggle variable to select whether you're processing a left value or a right value, and the ability to store the left data so you can output them both when you process the right data, something like:
WORKING-STORAGE SECTION.
01 ARE-THERE-MORE-RECORDS PIC X(3) VALUE 'YES'.
01 DOING-LEFT PIC X(3) VALUE 'YES'.
01 LEFT-NAME-IN PIC X(20).
01 LEFT-ADDRESS-IN PIC X(20).
01 LEFT-CITY-STATE-ZIP-IN PIC X(20).
Then modify your record processing code thus (check the IF
syntax, it's been a while since I cut any COBOL code):
200-PROCESS-ONE-RECORD.
IF DOING-LEFT = 'YES' THEN
PERFORM 201-PROCESS-LEFT-RECORD
ELSE
PERFORM 202-PROCESS-RIGHT-RECORD.
201-PROCESS-LEFT-RECORD.
MOVE NAME-IN TO LEFT-NAME-IN. (just store it)
MOVE ADDRESS-IN TO LEFT-ADDRESS-IN.
MOVE CITY-STATE-ZIP-IN TO LEFT-CITY-STATE-ZIP.
MOVE 'NO' TO DOING-LEFT. (and toggle to right)
202-PROCESS-RIGHT-RECORD.
MOVE LEFT-NAME-IN TO LEFT-LABEL-OUT. (first line, both sides)
MOVE SPACES TO BLANK-OUT.
MOVE NAME-IN TO RIGHT-LABEL-OUT.
MOVE SPACES TO BLANK-A-OUT.
WRITE LABEL-RECORD-OUT.
MOVE LEFT-ADDRESS-IN TO LEFT-LABEL-OUT. (second line, both sides)
MOVE SPACES TO BLANK-OUT.
MOVE ADDRESS-IN TO RIGHT-LABEL-OUT.
MOVE SPACES TO BLANK-A-OUT.
WRITE LABEL-RECORD-OUT.
MOVE LEFT-CITY-STATE-ZIP-IN TO LEFT-LABEL-OUT. (third line, both sides)
MOVE SPACES TO BLANK-OUT.
MOVE CITY-STATE-ZIP-IN TO RIGHT-LABEL-OUT.
MOVE SPACES TO BLANK-A-OUT.
WRITE LABEL-RECORD-OUT.
MOVE 'YES' TO DOING-LEFT. (toggle back to left)
Then, at the end, after the file has been fully read, you need to detect if you've populated the left data (i.e., there was an odd number of input lines). This will be the case if DOING-LEFT
is set to 'NO'
.
I'll leave that to you but it involves moving the left data and populating the right data with spaces, in a manner very similar to 202-PROCESS-RIGHT-RECORD
above (nudge, nudge,wink, wink).
And, now that I've had a good look at the desired output, it appears you actually need two copies of each address on both the left and the right. Are you sure that's the way you want to do it since it's a pretty unusual requirement for a mailing label program?
In any case, I'll leave all that code in above since it's a good way to do the one-each method of mailing labels but the code you seem to need is much simpler, a very slight variation of the 202-PROCESS-RIGHT-RECORD
paragraph.
Forget all the extra working storage I mentioned, and just change 200-PROCESS-ONE-RECORD
to:
200-PROCESS-ONE-RECORD.
MOVE NAME-IN TO LEFT-LABEL-OUT.
MOVE SPACES TO BLANK-OUT.
MOVE NAME-IN TO RIGHT-LABEL-OUT.
MOVE SPACES TO BLANK-A-OUT.
WRITE LABEL-RECORD-OUT.
MOVE ADDRESS-IN TO LEFT-LABEL-OUT.
MOVE SPACES TO BLANK-OUT.
MOVE ADDRESS-IN TO RIGHT-LABEL-OUT.
MOVE SPACES TO BLANK-A-OUT.
WRITE LABEL-RECORD-OUT.
MOVE CITY-STATE-ZIP-IN TO LEFT-LABEL-OUT.
MOVE SPACES TO BLANK-OUT.
MOVE CITY-STATE-ZIP-IN TO RIGHT-LABEL-OUT.
MOVE SPACES TO BLANK-A-OUT.
WRITE LABEL-RECORD-OUT.
I think your second attempt was nearly correct. As Paxdiablo pointed out in his answer, the problem you have is overwriting data.
If I understand your problem correctly, you read in a single record containing a complete address (Name, Address, City-State-Zip) and have to print out two copies of it side by side.
Notice that for every line you read, you need to print 3. Also notice that you only have one output record buffer. This means you can only process one output line at a time. The solution is to move each address component into the left and right hand side of the ouput line, output the line and then move on to the next address component. Since there are 3 address components, you end up printing 3 lines for each one read.
Try modifying paragraph 200-PROCESS-ONE-RECORD as follows
200-PROCESS-ONE-RECORD.
MOVE NAME-IN TO LEFT-LABEL-OUT
MOVE SPACES TO BLANK-OUT
MOVE NAME-IN TO RIGHT-LABEL-OUT
MOVE SPACES TO BLANK-A-OUT
WRITE LABEL-RECORD-OUT
MOVE ADDRESS-IN TO LEFT-LABEL-OUT
MOVE SPACES TO BLANK-OUT
MOVE ADDRESS-IN TO RIGHT-LABEL-OUT
MOVE SPACES TO BLANK-A-OUT
WRITE LABEL-RECORD-OUT
MOVE CITY-STATE-ZIP-IN TO LEFT-LABEL-OUT
MOVE SPACES TO BLANK-OUT
MOVE CITY-STATE-ZIP-IN TO RIGHT-LABEL-OUT
MOVE SPACES TO BLANK-A-OUT
WRITE LABEL-RECORD-OUT
This takes one input line, produces 3 output lines. You might want to output a fourth blank line to separate addresses (as illustrated in your sample output - I will let you figure out how to get that done).
I think Paxdiablo's solution solved a slightly different problem where you would be printing one copy of each address but printing addresses 2 across.
BTW... Despite the number of disparaging "drive by" comments your question got, COBOL is still actively used in some segments of this industry.
Your question is already well answered about the overwrites, but I would add two things that will greatly improve your Cobol code in readability and maintainability.
You are using a Cobol '74 meme here with the ARE-THERE-MORE-RECORDS variable and moving 'YES' and 'NO' literals to it. This is very brittle and prone to breakage. A much nicer, less brittle, more readable approach is to use the conditionals that Cobol provides, also known as 88's:
05 Filler Pic x(1) Value 'Y'.
88 More-Records Value 'Y'.
88 No-More-Records Value 'N'.
You can test it with:
Perform until No-More-Records
And trigger it with:
Set No-More-Records to true
This does several things for you.
Nobody will ever accidentally maintain one of your literals to 'no' instead of 'NO' or otherwise munge up your source code. This can be a real problem on older systems that make assumptions about upper/lower case for their users and their attached terminals.
Nobody can move 'BOB' to your flag because you didn't give it a name, you made it filler. They have to go way out of their way to assign to that variable instead of using the condition names. And if they are capable enough to go that far out of their way, they are capable enough to know why they SHOULDN'T do it.
It gives your loop control and file control checks meaningful names. Granted, ARE-THERE-MORE-RECORDS 'YES'/'NO' is pretty meaningful, but in true production code you will encounter many different conditions, often with unusual names and twisted logic behind them, sometimes 'YES'/'NO' isn't as clear as it could be. Giving a nice, 30 character long condition name is much easier for the programmers that will follow you to do maintenance.
The other thing you do is use the paragraph numbering system. It was a poorly though out idea back when graph paper flow charts were all the documentation you had and source control was not yet a twinkle in anyones eye.
100-MAIN.
200-PROCESS-ONE-RECORD.
It doesn't really buy you anything, and it comes with several downsides.
With modern source control, changes to all the other paragraph numbers that are not germane to the specific change you are making will stand out like a sore thumb. (Assuming anyone ever renumbers their paragraphs when their logic changes, which they never do)
It encourages really crappy paragraph names. Consider this, perfectly valid under the paragraph numbering system:
100-Read-File
200-Read-File
300-Read-File
110-Write-File
210-Write-File
310-Write-File
We obviously have three different files, or at least three combinations of files and read types, but absolutely no indication of what is different by the paragraph name. It is also prone to the cut&paste error where someone copies a paragraph, renumbers it, and doesn't fully change the content to hit the new file or set the new conditional flags for the separate file, thus creating subtle and hard to find bugs.
A much better approach is:
Read-Master-File
Read-Transaction-File
Write-Master-File
Write-Transaction-File
Write-Log-File
That is easier to do right and harder to do wrong.
Remember you write source code for other humans to read, the compiler will take any sort of crap, but your maintenance is 90% of a programs lifecycle and that means other people* will spend ten times as much time trying to understand what you wrote as you spent writing it. Make it easy for them.
- Very often, this will be you, but you will not recognize the code you wrote six months ago...
精彩评论