מה צריך לדעת לפני שקוראים קוד COBOL

· עודכן בתאריך: · · COBOL, legacy, מערכות עסקיות, תחזוקה, Mainframe

היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 17 Mar 2026)
פרסום ראשון
לצטט את המאמר הזה(DOI: 10.5281/zenodo.22173606)

מאמר זה מאוחסן בארכיון Zenodo. להלן גם ה-DOI שתמיד מפנה לגרסה האחרונה וגם ה-DOI המקובע לגרסה שאתם קוראים.

Go Komura (2026). מה צריך לדעת לפני שקוראים קוד COBOL. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22173606 https://comcomponent.com/he/blog/cobol-minimum-reading-guide/

DOI (הגרסה האחרונה)
10.5281/zenodo.22173606
DOI (הגרסה הזו)
10.5281/zenodo.22173607

handover, טיפול בתקלה, תחזוקת חבילה של vendor. במצבים כאלה יכול לקרות שיום אחד נוחת עליכם קוד COBOL.

  • שם הקובץ .cbl או .cpy
  • שמות המשתנים כולם באותיות גדולות
  • 01, 05, 77, 88 בשורה
  • מופיע משהו כמו PIC S9(7)V99 COMP-3 — בין לחש לתוכנת הנהלת חשבונות
  • ובנוסף הכול מלא ב-COPY, ומהקובץ הפתוח לבד לא רואים את התמונה

בשלב הזה רוב האנשים עוצרים לרגע.

אבל המפה לקריאה לא כל כך גדולה. יש הבדלים בין compilers ומוצרים, אבל השלד שצריך לתפוס קודם במערכת עסקית קיימת די משותף. כאן, עם COBOL ממשפחת IBM וקוד COBOL עסקי טיפוסי בראש, נעבור על הסט המינימלי למי שנחת פתאום על הקוד.

למה עוצרים, וכמה גדולה המפהשמות באותיות גדולות, מספרי רמה, PIC S9(7)V99 COMP-3, והרבה COPY שלא מראים את התמונה גורמים לעצור. אבל השלד לקריאת מערכת עסקית די משותף, והמפה לא גדולה.רישום לא מוכר עוצראבל השלד משותף בין compilersקודם מחזיקים רק את המפה המינימליתהרבה COPY, לא רואים את התמונה

איור 1: מה שנראה כמו לחש מתרכז בכמה מושגים משותפים.

1. קודם המסקנה (במשפט)

אם אומרים את זה בגסות, אבל שימושי בשטח:

  • COBOL היא, לפני שהיא שפת לוגיקה, שפה שמתמקדת חזק ב-הגדרת records
  • PROCEDURE DIVISION לבד נותן רק חצי מהתמונה. קודם פותחים DATA DIVISION
  • PIC הוא צורת השדה, USAGE הוא באיזה ייצוג הוא נשמר
  • COMP-3 הוא packed decimal. נפוץ בעולם סכומים ומונים
  • 88 אינו משתנה נפרד. זה condition-name לערך של השדה שמעליו
  • REDEFINES הוא מבט אחר על אותו זיכרון. זו לא copy
  • אם יש COPY, הקובץ הפתוח עדיין לא שלם. בלי copybook אין תמונה מלאה
  • אם עוקבים אחרי PERFORM, IF, EVALUATE, READ, WRITE, CALL — תופסים פחות או יותר את הזרימה
  • קוד ישן הוא fixed format שבו לעמודות יש משמעות. הרווח שנראה עיצוב הוא חלק מהתחביר1

בקיצור: DIVISION, PIC, USAGE, COMP-3, REDEFINES, OCCURS, 88, COPY, PERFORM. אם אלה נקראים, שיעור ההיאבדות יורד חזק.

ב-diagram, solid line מציינת relation שתמיד מתקיים ו-dashed line מציינת relation מותנה (התנאים מופיעים בהסבר של כל relation ב-detail page). הרשימה המלאה של ה-relations (סה”כ 21, כולל evidence ו-certainty) וההגדרות של ה-concepts המרכזיים נמצאות ב-detail page של ה-knowledge map (ביפנית). Data: JSON-LD / Turtle

2. COBOL היא קודם כל שפת “צורת הנתונים”

עם הראש של C# או Java, קודם רוצים לעקוב אחרי if, for וקריאות לפונקציות. ב-COBOL עדיף לעצור לפני זה ולתפוס איזה records התכנית מקבלת, איזה records היא מייצרת, ואילו buffers יש לה.

COBOL עסקי טיפוסי רץ בערך כך:

  1. קורא record מקובץ או מ-DB
  2. שם אותו בשדות ב-WORKING-STORAGE
  3. עושה הסתעפות
  4. ממלא record אחר
  5. כותב החוצה

כלומר: layout לפני אלגוריתם.

הזרימה הטיפוסית של COBOL עסקיקוראים record מקובץ או DB, שמים ב-WORKING-STORAGE, מסתעפים, ממלאים record אחר וכותבים החוצה.קוראים recordשמים ב-WORKING-STORAGEמסתעפיםממלאים record אחרכותבים החוצה

איור 2: הגיבור הוא זרימת ה-records. האלגוריתם יושב ביניהם.

למשל, שלד כזה:

       IDENTIFICATION DIVISION.
       PROGRAM-ID. SAMPLE01.

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT SALES-FILE ASSIGN TO ...

       DATA DIVISION.
       FILE SECTION.
       FD  SALES-FILE.
       01  SALES-REC.
           05  SALE-ID       PIC 9(8).
           05  SALE-AMOUNT   PIC S9(7)V99 COMP-3.

       WORKING-STORAGE SECTION.
       01  WS-EOF            PIC X VALUE 'N'.
           88  EOF           VALUE 'Y'.

       PROCEDURE DIVISION.
           PERFORM UNTIL EOF
               READ SALES-FILE
                   AT END
                       SET EOF TO TRUE
                   NOT AT END
                       PERFORM PROCESS-SALE
               END-READ
           END-PERFORM
           STOP RUN.

כשקוראים את זה, לפני PERFORM כדאי לראות את הטיפוס של SALE-AMOUNT ואת המשמעות של EOF. COBOL נרגעת ברגע שקוראים בסדר הזה.

3. קודם ארבעת ה-DIVISION

קוד COBOL מתחלק קודם לארבעה DIVISION.

DIVISION מה בודקים קודם
IDENTIFICATION DIVISION שם התכנית, הערות ישנות, מקור
ENVIRONMENT DIVISION קבצים, משאבים חיצוניים, הנחות I/O
DATA DIVISION הגדרות records, אזור עבודה, ארגומנטים
PROCEDURE DIVISION סדר הפעולות עצמו

במיוחד אלה חשובים:

  • FILE SECTION הגדרות records של קבצי I/O
  • WORKING-STORAGE SECTION משתנים יומיומיים, דגלים, מונים, buffers
  • LOCAL-STORAGE SECTION לפעמים יש אזור שמתאפס בכל קריאה
  • LINKAGE SECTION לפעמים יש ארגומנטים שמגיעים מבחוץ, או נקודת כניסה לתת-תכנית

אם רואים LINKAGE SECTION ו-PROCEDURE DIVISION USING ..., התכנית כנראה לא עומדת לבד — היא מקבלת נתונים מבחוץ.

מה מראה LINKAGE SECTIONLINKAGE SECTION ו-PROCEDURE DIVISION USING אומרים שהתכנית כנראה מקבלת נתונים מבחוץ ולא עומדת לבד.יש LINKAGE SECTIONכנראה מקבלת נתונים מבחוץיש PROCEDURE DIVISION USINGלא תכנית עצמאית

איור 3: אם רואים נקודת כניסה, קוראים מתוך הנחה שיש קורא.

4. לא להיבהל מ-fixed format

ב-COBOL ישן, מיקום העמודה עצמו הוא חלק מהתחביר. בלי זה, “למה יש רווח מוזר משמאל” נשאר חידה לנצח.1

ב-fixed format זה בערך כך:

  • עמודות 1–6: מספר סידורי
  • עמודה 7: indicator
  • עמודות 8–11: Area A
  • עמודות 12–72: Area B

עמודה 7 חשובה במיוחד.

  • * או /: שורת הערה
  • -: שורת המשך
  • D: debugging line
  • *>: הערה שאפשר לכתוב גם באמצע

עם סרגל זה נראה כך. השורה הראשונה היא ספרת העשרות, השנייה ספרת היחידות.

         1         2         3         4         5         6         7         8
12345678901234567890123456789012345678901234567890123456789012345678901234567890
SSSSSSIAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB........
  • S = מספר סידורי (עמודות 1–6)
  • I = indicator (עמודה 7)
  • A = Area A (עמודות 8–11)
  • B = Area B (עמודות 12–72)
  • . = מעמודה 73 והלאה. בחלק מה-compilers זה שדה זיהוי, אבל זה לא חלק ממשמעות התכנית

על קוד אמיתי זה נראה כך:

000100* זו שורת הערה כי עמודה 7 היא *
000200 IDENTIFICATION DIVISION.
000300 PROGRAM-ID. SAMPLE01.
000400 DATA DIVISION.
000500 WORKING-STORAGE SECTION.
000600 01  WS-ORDER.
000700     05  WS-ORDER-ID    PIC 9(8).
000800     05  WS-LONG-NAME   PIC X(30) VALUE 'ABCDEFGHIJKLMNOPQRST
000900-    'UVWXYZ0123'.

ארבע נקודות קריאה:

  • עמודות 1–6 הן מספר סידורי. בדוגמה זה 000100 ודומיו. זה לא משפיע על הריצה. לפעמים זה ריק.
  • עמודה 7 היא indicator. * = הערה, - = המשך. בדוגמה שורה 000900 ממשיכה את ה-string literal מהשורה הקודמת.
  • עמודות 8–11 הן Area A. מכאן מתחילים DIVISION, SECTION, שמות פסקאות, FD, ומספרי רמה 01 ו-77. בדוגמה IDENTIFICATION DIVISION. ו-01 WS-ORDER. מתחילים ב-Area A.
  • עמודות 12–72 הן Area B. משפטים רגילים ורמות נמוכות כמו 05. בדוגמה 05 WS-ORDER-ID מתחיל ב-Area B.

הרווח כאן הוא לא “עיצוב מודרני”. חלק ממנו הוא תחביר. המרת tabs, יישור לשמאל, או copy-paste גס — שוברים את זה בקלות. כשפותחים קוד ישן, קודם בודקים אם הקובץ הוא fixed format או free format. auto-format מודרני על fixed שובר את הגבול בין Area A ל-Area B, וה-compile נופל.

לפני שנוגעים ב-fixed formatבקוד ישן קודם בודקים fixed או free. ב-fixed מיקום העמודה הוא תחביר. auto-format או המרת tabs שוברים את הגבול בין Area A ל-Area B, וה-compile נופל.fixed formatfree formatפתחנו קוד ישןfixed או free?מיקום העמודה הוא תחבירauto-format והמרת tabs שובריםמגבלת העמודות רכה יותר

איור 4: לפני עיצוב, מקבעים את פורמט הקובץ.

5. המינימום של DATA DIVISION

5.1 מספרי רמה

הגדרת הנתונים ב-COBOL בונה היררכיה לפי מספר רמה, לא לפי הזחה.2

       01  WS-ORDER.
           05  WS-ORDER-ID    PIC 9(8).
           05  WS-AMOUNT      PIC S9(7)V99 COMP-3.
           05  WS-STATUS      PIC X.
               88  WS-OK      VALUE '0'.
               88  WS-ERROR   VALUE '9'.

       77  WS-COUNT           PIC 9(4).

מספיק לזכור את זה:

  • 01: הרשומה או הקבוצה ברמה העליונה
  • 02–49: הרמות מתחת
  • 77: שדה בודד עצמאי
  • 88: condition-name. שם לערך של השדה שמעליו3
  • 66: ל-RENAMES. לא נפוץ, אבל קיים

הנקודה: לא לחשוב על 88 כ-משתנה bool נפרד. אין אזור נפרד בשם WS-OK. כש-WS-STATUS הוא '0', אפשר לקרוא לזה WS-OK.

מה זו רמה 88רמה 88 אינה משתנה bool עצמאי. זה condition-name לערך של השדה שמעליו. כש-WS-STATUS הוא ערך מסוים, השם WS-OK נהיה true.09שדה הבסיס WS-STATUSמה הערך?true בשם WS-OKtrue בשם WS-ERRORאין אזור נפרד

איור 5: 88 אינו משתנה. זה כינוי קריא לערך.

עוד נקודה: את ההיררכיה קובע מספר הרמה, לא הרווח. ההזחה עוזרת לעין, אבל מה שסומכים עליו בסוף הוא 01 / 05 / 10 / 88.2

5.2 PICTURE

PIC מתאר את צורת השדה. הנפוצים:

סימון בערך
X תו
9 ספרה
S עם סימן
V נקודה עשרונית לוגית בלבד
X(10) 10 תווים
9(5) 5 ספרות
S9(7)V99 עם סימן, 7 שלמות + 2 עשרוניות

למשל:

  • PIC X(10) → 10 תווים
  • PIC 9(5)V99 → 5 שלמות + 2 עשרוניות
  • PIC S9(7)V99 → עם סימן, 7 שלמות + 2 עשרוניות

כאן V חשוב במיוחד. V לא מחזיק תו . אמיתי. PIC 9(5)V99 מטופל כמספר עם 2 ספרות אחרי הנקודה, אבל בנתונים אין נקודה. אם מפרשים dump כ”מחרוזת שנראית כמו מספר” — זה בדרך כלל נופל.

V הוא נקודה לוגיתב-PIC 9(5)V99 ה-V הוא נקודה עשרונית לוגית. אין תו נקודה בנתונים. אם מפרשים קובץ או dump כמחרוזת ויזואלית, זה נופל.PIC 9(5)V99מטופל כמספר עם 2 ספרות אחרי הנקודהאין תו נקודה בנתוניםפירוש כמחרוזת ויזואלית נופל

איור 6: הנקודה העשרונית יושבת בהגדרה, לא בנתונים.

5.3 USAGE / DISPLAY / COMP / COMP-3

אם PIC הוא הצורה, USAGE הוא באיזה ייצוג זה נשמר. מספיק לתפוס את אלה כדי לקרוא הרבה.45

סימון בערך מה לשים לב אליו בקריאה
DISPLAY עשרוני חיצוני שנראה כתווים ב-mainframe לפעמים מניחים EBCDIC6
COMP / BINARY בינארי מספר הספרות ב-PIC והייצוג הפנימי הם דברים שונים
COMP-3 / PACKED-DECIMAL packed decimal כטקסט זה נראה שבור

למשל:

       01  WS-AMOUNT-DISP   PIC S9(7)V99.
       01  WS-AMOUNT-BIN    PIC S9(7) COMP.
       01  WS-AMOUNT-PACK   PIC S9(7)V99 COMP-3.

שלושתם “מספר”, אבל הדרך שבה הם יושבים בזיכרון שונה.

אותו מספר, ייצוג אחרגם באותו מספר עם סימן, DISPLAY הוא עשרוני חיצוני שנראה כתווים, COMP הוא בינארי, COMP-3 הוא packed decimal. USAGE משנה את רצף הבייטים.שדה מספרי באותה צורהDISPLAY (נראה כתווים)COMP (בינארי)COMP-3 (packed decimal)כטקסט זה נראה שבור

איור 7: PIC זהה, USAGE שונה — רצף הבייטים הוא דבר אחר.

בשטח, הרפלקס החשוב ביותר הוא ברגע שרואים COMP-3:

  • זה packed decimal
  • כנראה סכום, מס, מונה, תעריף
  • כטקסט זה נראה שבור, וזה צפוי
  • dump בתחושה של CSV או UTF-8 הוא תאונה

עם זה לא נבהלים מ-dump או מקובץ בינארי.

הרפלקס ברגע שרואים COMP-3COMP-3 הוא packed decimal, כנראה סכום או מונה או תעריף. כטקסט זה נראה שבור וזה צפוי. לא מסתכלים על זה כמו CSV או UTF-8.מצאנו COMP-3זה packed decimalחושדים בשדה סכום או מונהלא נבהלים אם זה נראה שבור כטקסט

איור 8: הרפלקס הזה לבד מוריד את מספר הפעמים שנבהלים מול dump.

איך נראה COMP-3 בבייטים

שווה לעקוב אחרי זה פעם אחת ביד. אחר כך ה-dump נראה אחרת.

ל-packed decimal יש רק שני כללים.45

  1. דוחסים שתי ספרות עשרוניות לבייט אחד
  2. אבל הבייט הימני ביותר מחזיק ספרה אחת + סימן

הסימן הוא 4 ביטים: C חיובי, D שלילי, F בלי סימן.

בודקים מול דוגמה במדריך של IBM.4

הגדרה ערך בייטים
PIC S9(4) PACKED-DECIMAL +1234 01 23 4C
PIC S9(4) PACKED-DECIMAL -1234 01 23 4D
PIC 9(4) PACKED-DECIMAL 1234 01 23 4F

1234 הוא 4 ספרות, אז בגלל כלל 2 נשארת ספרה פנויה בהתחלה. זה ה-0 הראשון.

באותו אופן, PIC S9(7)V99 COMP-3 שחוזר במאמר:

  • S9(7)V99 הוא 7 שלמות + 2 עשרוניות = 9 ספרות
  • V רק מסמן איפה הנקודה, לא צורך בייט
  • 9 ספרות, שתיים לבייט = 4 בייטים, ועוד ספרה + סימן בבייט אחד. סה”כ 5 בייטים

אם הערך הוא +12345.67, 9 ספרות זה 001234567:

ערך     : +12345.67
9 ספרות : 0 0 1 2 3 4 5 6 7  וסימן
בייטים  : 00 12 34 56 7C
                        ^ סימן C = חיובי

לערך שלילי -12345.67 רק הסוף נהיה 7D.

בייטים  : 00 12 34 56 7D

ומה רואים אם פותחים את זה כטקסט? אם מנסים למפות 00 12 34 56 7C תו-לבייט ל-ASCII:

  • 00 הוא NUL, 12 הוא תו בקרה — בכלל לא מוצג כתו
  • 34 הוא 4, 56 הוא V, 7C הוא |

על המסך זה נראה כמו “כמה תווים שלא מוצגים ואז 4V|”. הרצף 12345.67 לא מופיע בשום מקום.

זה “נראה garbled אבל לא שבור”. כשפותחים dump ורואים רצף חסר משמעות, קודם חושדים ש-USAGE של השדה הוא COMP-3.

איך בונים את הבייטים של COMP-3ב-packed decimal דוחסים שתי ספרות לבייט, והבייט הימני מחזיק ספרה אחת וסימן. מספר בן 9 ספרות תופס 5 בייטים. כ-ASCII, הרצף המקורי של המספר לא מופיע.שתי ספרות לבייטהבייט האחרון: ספרה אחת + סימן9 ספרות = 5 בייטיםכ-ASCII המספר המקורי לא מופיענראה garbled אבל לא שבור

איור 9: שני כללי הדחיסה הופכים dump חסר משמעות לרצף שאפשר לקרוא.

בדרך, טבלת המרה מספר-ספרות לבייטים. מספר הבייטים הוא מספר ה-9 ב-PIC, חלוקה ב-2 עם עיגול כלפי מטה, ועוד 1.

מספר ה-9 ב-PICTURE בייטים ב-COMP-3
1 1
2–3 2
4–5 3
6–7 4
8–9 5
10–11 6
12–13 7

שתי כמויות ספרות נופלות לאותו מספר בייטים כי רק כשמספר ה-9 זוגי נשארת ספרה פנויה בהתחלה. לכן S9(4) הוא 01 23 4C — 3 בייטים — וגם S9(5) נכנס ל-3 בייטים.

בהתאמת layout לקובץ חיצוני, בלי הטבלה הזו זזים בייט-בייט.

עוד הערה: DISPLAY לא אומר בהכרח מחרוזת ASCII. ב-z/OS מניחים EBCDIC, אז גם אם הספרות נראות כתווים, ערכי הבייטים שונים מ-'0'–'9' ב-ASCII.6

5.4 REDEFINES / OCCURS / COPY / FILLER

ארבעת אלה הם המקומות שנתקעים בהם בקריאה.

REDEFINES

REDEFINES הוא מבט אחר על אותו אזור. זו לא copy.7

       01  REC-BUF.
           05  REC-TYPE      PIC X.
           05  REC-DATA      PIC X(99).

       01  HEADER-REC REDEFINES REC-BUF.
           05  HDR-TYPE      PIC X.
           05  HDR-DATE      PIC 9(8).
           05  FILLER        PIC X(91).

זה קרוב ל-union ב-C. נפוץ בכתיבה של “100 בייטים אחד, שנקראים לפי סוג הרשומה”.

REDEFINES הוא פירוש אחר לאותו אזורREDEFINES אינו copy. זה מבט אחר על אותו זיכרון. אותו buffer נקרא גם כרשומה כללית וגם כ-header. כותבים צד אחד — גם המראה של הצד השני משתנה.אזור זיכרון אחדנקרא כ-REC-BUFנקרא כ-HEADER-RECכותבים צד אחד, שני המראות משתנים

איור 10: שתי הגדרות, רצף בייטים אחד.

OCCURS

OCCURS הוא מערך. ב-COBOL קוראים לזה לרוב table.

       05  WS-ITEM OCCURS 12 TIMES.
           10  WS-PRICE    PIC 9(5).

אם מופיע גם OCCURS DEPENDING ON, זו טבלה באורך משתנה. זה יכול להזיז גם את מיקום השדות שאחריה. אם רצים עם ראש של אורך קבוע, יוצאים מה-offset.8

הזהירות ב-OCCURS DEPENDING ONOCCURS הוא מערך. עם DEPENDING ON זו טבלה באורך משתנה, וגם מיקום השדות שאחריה יכול לזוז לפי הערך. offset באורך קבוע מחטיא.איןישמצאנו OCCURSיש DEPENDING ON?טבלה במספר קבועטבלה באורך משתנהגם מיקום השדות הבאים יכול לזוז

איור 11: שלוש המילים DEPENDING ON משנות את הנחת ה-offset.

COPY

COPY הוא include בזמן compile. כלומר, הקובץ הפתוח כרגע עדיין לא בהכרח הצורה המלאה.9

       COPY CUSTOMER-REC.
       COPY ERROR-MAP.

די שגרתי שהגדרות records, דגלים משותפים, host variables ל-SQL וממשקים חיצוניים דחוסים ב-copybook.

כשיש הרבה COPY וקשה לקרוא, מהיר יותר לבדוק אם יש expanded source או compiler listing. ב-IBM Enterprise COBOL יש גם אפשרות MDECK שמוציאה את מקור הקלט אחרי עיבוד הספרייה.10

איך קוראים קוד עם COPYCOPY הוא include בזמן compile, והקובץ הפתוח אולי לא שלם. בודקים copybook, ואם קשה — מחפשים expanded source, listing או פלט MDECK.כשקשה לקרואמצאנו COPYהקובץ הפתוח אולי לא שלםפותחים copybook ובודקיםמחפשים expanded source או listing

איור 12: מספר השורות שרואים עכשיו הוא לא בהכרח כל התכנית.

FILLER

FILLER הוא שדה בלי שם. אבל “לא מתייחסים אליו” לא אומר שהוא חסר משמעות.

  • אזור שמור
  • חור לתאימות עם מפרט ישן
  • יישור אורך רשומה
  • רווח ל-REDEFINES

כל אלה עובדים.

ל-FILLER אין שם, אבל יש לו אורך בבייטים. שוכחים את זה — והמיפוי לקובץ חיצוני זז בייט-בייט.

מה קורה כששוכחים לספור FILLERל-FILLER אין שם אבל יש אורך. הוא משמש כאזור שמור או ליישור אורך רשומה. אם לא סופרים אותו, המיפוי לקובץ חיצוני זז בייט-בייט.כןשכחנוFILLER הוא שדה בלי שםאבל יש לו אורך בבייטיםנכלל בחישוב ה-layout?תואם לקובץ החיצוניזזים בייט-בייט

איור 13: גם לשדה שלא מתייחסים אליו יש תפקיד: אורך.

6. המינימום של PROCEDURE DIVISION

אם DATA DIVISION היא המפה, PROCEDURE DIVISION הוא מסלול התנועה.

6.1 PERFORM

PERFORM הוא מעבר הבקרה הבסיסי ב-COBOL. בגדול: קוראים לעיבוד וחוזרים.11

הצורה הנפוצה:

       PERFORM INIT-PROC
       PERFORM UNTIL EOF
           PERFORM READ-PROC
           IF NOT EOF
               PERFORM EDIT-PROC
               PERFORM WRITE-PROC
           END-IF
       END-PERFORM

יש שני סוגים עיקריים:

  • out-of-line PERFORM שמצביע על פסקה או section
  • inline PERFORM ... END-PERFORM עם בלוק במקום

בקוד ישן נפוץ גם טווח כמו PERFORM A-100 THRU A-199. זה נוח, אבל אם מוסיפים פסקה באמצע קל למשוך אותה בטעות. בקריאה בודקים את סוף הטווח.

שלוש הצורות של PERFORMPERFORM יכול להיות out-of-line שקורא לפסקה וחוזר, inline עם בלוק במקום, או טווח עם THRU בקוד ישן. בטווח חובה לבדוק את הסוף, כי פסקה שנוספה באמצע נמשכת בקלות.מצאנו PERFORMout-of-line שקורא לפסקהinline במקוםטווח עם THRUתמיד בודקים את סוף הטווח

איור 14: סוג ה-PERFORM קובע לאן חוזרים ומה הטווח.

6.2 IF / EVALUATE / scope

הסתעפות בסיסית היא IF. EVALUATE קרוב ל-switch/case.

מה שצריך לשים לב אליו הוא איך נגמר ה-scope.12

  • END-IF
  • END-PERFORM
  • END-READ

קוד עם סיום מפורש כזה עדיין קריא.

הבעיה היא קוד ישן. ב-COBOL, . עובד כ-scope terminator משתמע, וסוגר בבת אחת משפטים שעדיין פתוחים.12

כלומר, נקודה אחת משנה:

  • עד איפה ה-IF
  • עד איפה ה-PERFORM
  • איפה עוברים ל-sentence הבא

וגם NEXT SENTENCE אינו CONTINUE. NEXT SENTENCE קופץ אחרי הנקודה הבאה, כך שהיעד תלוי במיקום ה-. שאחריו.12

בקוד COBOL ישן, מסתכלים על הנקודה, לא על סוף השורה.

המשקל של הנקודהקוד עם END-IF קריא. בקוד ישן הנקודה היא scope terminator משתמע שסוגר משפטים פתוחים, ונקודה אחת משנה את טווח IF ו-PERFORM.יש END-IF ודומיוקוד ישן בלייש סיום מפורש?הטווח קריאהנקודה היא סיום משתמעמיקום אחד משנה את הטווחמסתכלים על הנקודה, לא על סוף השורה

איור 15: בזרימת הבקרה של קוד ישן, מיקום הנקודה מחזיק את המפתח.

6.3 READ / WRITE / CALL

ב-COBOL עסקי אלה חוזרים הרבה:

  • READ
  • WRITE
  • REWRITE
  • START
  • CALL

במיוחד READ ... AT END ... הוא הקלאסיקה.

       READ IN-FILE
           AT END
               SET EOF TO TRUE
           NOT AT END
               PERFORM PROCESS-REC
       END-READ

אם יש CALL 'SUBPGM' USING ..., קופצים לתכנית אחרת. אז פותחים את LINKAGE SECTION ו-PROCEDURE DIVISION USING של הנקרא — וצורת ההעברה נראית די ברור.

איך עוקבים אחרי CALLCALL קופץ לתכנית אחרת. פותחים LINKAGE SECTION ו-PROCEDURE DIVISION USING של הנקרא כדי לתפוס את צורת הארגומנטים.מצאנו CALLקופצים לתכנית אחרתפותחים LINKAGE SECTION של הנקראתופסים את צורת ההעברה דרך USING

איור 16: משמעות הקריאה נקראת יחד עם נקודת הכניסה של הנקרא.

7. מה שנמצא מחוץ ל-COBOL

ב-COBOL העולם לא תמיד נגמר בקוד.

  • הגדרות קבצים
  • סביבת הרצה
  • חיבור ל-DB
  • סביבת טרנזקציות
  • בקרת job

כל אלה יושבים בחוץ.

לפחות אלה עוזרים לקרוא.

קבצים ו-FILE STATUS

FILE-CONTROL ב-ENVIRONMENT DIVISION ו-FILE SECTION / FD ב-DATA DIVISION נקראים כסט.13

       SELECT IN-FILE ASSIGN TO ...
           FILE STATUS IS WS-FS.

       FD  IN-FILE.
       01  IN-REC.
           05 ...

אם יש FILE STATUS, אחרי כל I/O נכנס קוד תוצאה. בתקלות קבצים ובזיהוי EOF, בלי זה אין מאיפה להתחיל.14

הגדרת קובץ נקראת כסטSELECT ב-FILE-CONTROL ו-FD ב-FILE SECTION הם סט אחד. אם יש FILE STATUS, אחרי כל I/O נכנס קוד תוצאה — ומשם קוראים תקלות ו-EOF.SELECT ב-FILE-CONTROLסט אחד של הגדרת קובץFD ב-FILE SECTIONקוד תוצאה נכנס ל-FILE STATUSנקודת הכניסה לתקלות ול-EOF

איור 17: צורת הקובץ כתובה בשני DIVISION.

EXEC SQL

אם זה מופיע, זה embedded SQL.

       EXEC SQL
           SELECT ...
       END-EXEC.

כאן COBOL הוא “הכלי ל-host variables”, ותנאי השליפה או יעד העדכון יושבים בצד ה-SQL. הקיצור: לקרוא את תוכן EXEC SQL כ-SQL רגיל.

EXEC CICS

אם זה מופיע, זה הקשר טרנזקציה של CICS.15

       EXEC CICS
           RECEIVE MAP(...)
       END-EXEC.

ברגע הזה זו כבר לא קריאת batch רגילה. צריך מסך, טרנזקציה, קודי תשובה, COMMAREA — הקשר חיצוני.

JCL והגדרות הרצה

ב-mainframe batch, איזה dataset באמת משויך ו-באיזה סדר רץ ה-job לעיתים קרובות מחוץ לקוד COBOL. אם מהקוד לבד לא ברור “איפה הקובץ הזה”, זו לא בהכרח בעיה בקוד. פשוט עדיין לא מסתכלים על כל הטווח.

העולם שמחוץ לקודEXEC SQL שם את תנאי השליפה בצד SQL, EXEC CICS שם מסך וטרנזקציה בהקשר חיצוני, וב-mainframe batch שיוך datasets וזרימת job יושבים ב-JCL.EXEC SQLמסתכלים גם מחוץ לקודEXEC CICSJCL והגדרות הרצהתנאי SQL, הקשר מסך, זרימת job

איור 18: לפעמים לא מבינים כי הטווח צר, לא כי הקוד גרוע.

הבדלים בין compilers

המאמר כתוב עם IBM בראש, אבל בשטח פוגשים גם Micro Focus ו-COBOL על Linux / Windows. השלד משותף והקריאה לא משתנה, אבל יש נקודות קבועות שבהן אותה כתיבה נותנת תוצאה אחרת. כדאי לדעת אותן מראש.

מה בודקים z/OS (IBM Enterprise COBOL) open systems (Micro Focus, Linux / Windows וכו’)
encoding מניחים EBCDIC6 מניחים ASCII6
reference format fixed הוא ברירת המחדל המסורתית. אפשר גם free1 יש fixed ו-free, ברירת המחדל תלויה בהגדרת ה-build1
איך מוצאים copybook ציון ספרייה נתיב חיפוש ב-compiler options
דיאלקט — יש אפשרות שמחליפה “לאיזה compiler מכוונים”

מה שמשפיע במיוחד הוא encoding. גם באותו PIC X(10), קובץ שנכתב ב-z/OS ונקרא כמו שהוא ב-Windows נותן ערכי בייטים אחרים גם לספרות. הרבה מקרים של “העברנו והכול garbled” הם זה, וזה בעיה נפרדת מ-COMP-3.

עוד מקום שקל לראות בו הפרש בייצוג מספרי. ב-IBM Enterprise COBOL, BINARY / COMP-4 חותכים לפי מספר הספרות ב-PICTURE, ואילו COMP-5 מחזיק עד הקיבולת הבינארית הנייטיבית של 2 / 4 / 8 בייטים, והחיתוך קורה לפי גודל הבינארי.16 כלומר PIC S9(4) COMP ו-PIC S9(4) COMP-5 נראים דומה, אבל תקרת הערך שונה. אם בקוד שמחליף ערכים בינאריים עם מערכת אחרת מופיע COMP-5, קוראים את זה כ-כתוב כך בכוונה.

הקיצור כשמשווים לסביבה שלכם:

  1. קודם פותחים את הגדרת ה-build (makefile, JCL, הגדרות פרויקט). איזה compiler ובאילו options — זה לפני הקוד.
  2. מקבעים reference format (fixed / free). טעות כאן + עיצוב ב-editor = שבירה.
  3. מקבעים encoding. EBCDIC או ASCII משנים איך קוראים dump.
  4. מסמנים שדות COMP. כמעט כל הפרש compiler יושב כאן.
הקיצור כשמשווים לסביבה שלכםקודם פותחים הגדרת build כדי לדעת compiler ו-options, מקבעים fixed או free, מקבעים EBCDIC או ASCII, ומסמנים שדות COMP שבהם יוצא הפרש compiler.קודם פותחים הגדרת buildמקבעים reference formatמקבעים encodingמסמנים שדות COMP

איור 19: ארבעה מהלכים לפני שקוראים את הקוד מונעים תאונות של הפרש compiler.

8. סדר קריאה מינימלי

כשנוחתים פתאום על COBOL, הסדר הבא בטוח יותר.

  1. לעבור על כל ה-COPY אם אפשר לפתוח copybook — פותחים. אם לא — מחפשים listing או expanded source
  2. לאסוף הגדרות records ברמה 01 לרכז את הרמה העליונה ב-FILE SECTION, WORKING-STORAGE, LINKAGE SECTION
  3. לקרוא PIC ו-USAGE לזהות סכומים, תאריכים, מונים, קודים, דגלים
  4. לחפש READ / WRITE / REWRITE / CALL / EXEC SQL / EXEC CICS קודם תופסים I/O וגבול חיצוני
  5. לעקוב רק אחרי המסלול הראשי הראשון מתחילת PROCEDURE DIVISION לאורך שרשרת PERFORM
  6. לראות 88 ושדות status EOF, תקין/שגוי, קודי סוג נעשים קריאים
  7. לסמן REDEFINES / OCCURS DEPENDING ON / COMP-3 אלה תמיד יחזרו, אז מסמנים אותם מראש כחומר מסוכן
  8. אם זה קובץ — לראות FILE STATUS זה מוריד הרבה קריאות שגויות של שגיאות I/O

בסדר הזה אין צורך לקרוא את כל הקובץ מההתחלה. ב-COBOL עדיף לתפוס קודם records, גבול חיצוני, מסלול ראשי, ורק אז לרדת לפרטים.

סדר קריאה בטוחעוברים על COPY ובודקים copybook, מרכזים רמה 01, קוראים צורה ב-PIC ו-USAGE, תופסים I/O וגבול חיצוני בחיפוש, עוקבים אחרי שרשרת PERFORM במסלול הראשי, ומסמנים חומר מסוכן.עוברים על כל ה-COPYמרכזים רמה 01קוראים צורה ב-PIC ו-USAGEמחפשים I/O וגבול חיצוניעוקבים אחרי שרשרת PERFORM במסלול הראשימסמנים חומר מסוכן

איור 20: לא קריאה צמודה של הכול, אלא חפירת החפיר בסדר הזה.

8.1 תרגול: לקרוא את הגדרת הרשומה הזו

הסבר לבד לא נדבק, אז שמים כאן record קטן. קודם עונים לבד, ואז מסתכלים על הפתרון למטה.

       01  CUST-REC.
           05  CUST-ID          PIC X(8).
           05  CUST-NAME        PIC X(20).
           05  CUST-KBN         PIC X.
               88  CUST-NORMAL  VALUE '0'.
               88  CUST-VIP     VALUE '1'.
           05  CUST-BALANCE     PIC S9(7)V99 COMP-3.
           05  CUST-HIST OCCURS 3 TIMES.
               10  HIST-DATE    PIC 9(8).
               10  HIST-AMOUNT  PIC S9(5)V99 COMP-3.
           05  FILLER           PIC X(4).

שאלות

  1. כמה בייטים יש ל-CUST-REC כולו?
  2. מאיזה בייט, מתחילת הרשומה, מתחיל CUST-BALANCE?
  3. מאיזה בייט מתחיל HIST-AMOUNT של הפריט השני?
  4. כש-CUST-KBN מכיל '1', איזה condition-name true?
  5. אם פותחים את הקובץ הזה ב-editor טקסט, אילו שדות נראים שבורים?
  6. ציינו שני דברים שההגדרה הזו לבדה לא אומרת.

תשובות

  1. 74 בייטים. הפירוק:

    שדה חישוב בייטים
    CUST-ID X(8) 8
    CUST-NAME X(20) 20
    CUST-KBN X 1
    CUST-BALANCE COMP-3 של 9 ספרות 5
    CUST-HIST (8 + 4) × 3 36
    FILLER X(4) 4
    סה”כ   74

    רמה 88 היא condition-name ולכן לא צורכת בייטים. לספור אותה זו טעות נפוצה. ל-FILLER אין שם, אבל 4 הבייטים קיימים לגמרי.

  2. בייט 30. לפניו יש 8 + 20 + 1 = 29 בייטים, והוא מתחיל אחריהם.

  3. בייט 55. CUST-HIST מתחיל בבייט 35, כל פריט 12 בייטים, אז פריט 1 הוא 35–46, פריט 2 הוא 47–58. 8 הבייטים הראשונים הם HIST-DATE, לכן HIST-AMOUNT מתחיל בבייט 55.

  4. CUST-VIP. אין אזור נפרד בשם CUST-VIP. כש-CUST-KBN הוא '1', אפשר לקרוא לזה בשם הזה.

  5. CUST-BALANCE ו-HIST-AMOUNT. שניהם COMP-3, אז כטקסט זה רצף חסר משמעות. HIST-DATE הוא PIC 9(8) ב-DISPLAY, אז בסביבת ASCII אפשר לקרוא אותו כספרות כמו 20260317. ב-EBCDIC הספרות נראות כספרות, אבל ערכי הבייטים שונים מ-ASCII.

  6. למשל:

    • האם ההגדרה עצמה הגיעה ב-COPY. בלי לראות את ה-copybook לא יודעים אם זו הגרסה שבאמת בשימוש.
    • האם encoding של הקובץ הוא EBCDIC או ASCII. זה משנה איך נראים PIC X ו-PIC 9 DISPLAY.
    • האם ב-production נכנס ל-CUST-KBN משהו מלבד '0' ו-'1'. יש רק שני condition-names, וזה לא ערובה שלא יגיעו ערכים אחרים.
    • מאפייני הקובץ עצמו (אורך רשומה, קבוע/משתנה, FILE STATUS). זה לא נראה בלי ENVIRONMENT DIVISION ו-FD.

אם טעיתם בשאלות 1 ו-3, חוזרים לטבלת הספרות והבייטים ב-5.3. רוב קריאות הלא-נכון ב-COBOL מתחילות כאן.

9. איפה נתקעים הרבה

לבסוף, המקומות שמתחילים נתקעים בהם בהסתברות גבוהה.

לחשוב ש-REDEFINES הוא “משתנה אחר”

לא. קוראים את אותו אזור בצורה אחרת. כותבים צד אחד — גם המראה של הצד השני משתנה.7

לחשוב ש-88 הוא “bool עצמאי”

לא. זה רק שם לערך של השדה שמעליו. SET WS-OK TO TRUE שם מאחורי הקלעים את הערך המתאים בשדה הבסיס.3

להתעלם מ-COPY ולקרוא רק את גוף הקובץ

הקובץ הפתוח הוא עדיין חצי מהתמונה. הגדרות שדות, דגלים משותפים ו-host variables יושבים בחוץ די שגרתית.9

לחשוב ש-MOVE הוא השמה פשוטה

MOVE אינו סתם memcpy. לפי טיפוס הצד המקבל יכולות לקרות המרה, יישור ספרות, מילוי אפסים, קיטום, עריכה או ביטול עריכה.17

לזלזל ב-.

ה-. ב-COBOL כבד יותר משנדמה. בקוד ישן בלי סיום מפורש, אם טועים ב-עד איפה הנקודה הזו סוגרת, קוראים לא נכון את זרימת הבקרה.12

לחשוב ש-packed decimal או EBCDIC הם “garbled”

זה לא בהכרח שבור. לפעמים זה פשוט לא מחרוזת מלכתחילה, או שזה לא ASCII.46

לחשוב שמה שאחרי OCCURS DEPENDING ON יושב במיקום קבוע

השדות אחרי טבלה באורך משתנה יכולים לזוז לפי הערך. עם ראש של אורך קבוע, כל חישוב ה-offset זז.8

10. טבלת עזר מהירה

מילה שמצאנו מה בודקים קודם
01 הרמה העליונה של record או קבוצה. מכאן תופסים את התמונה
88 שם משמעות לדגל או לקוד מצב. מפתח להסתעפות
PIC X(...) שדה תווים
PIC 9(...) / S9(...)V... שדה מספרי. בודקים מספר ספרות ומיקום עשרוני
COMP binary
COMP-3 packed decimal. סיכוי גבוה לסכום או מונה
REDEFINES פירוש אחר לאותו אזור
OCCURS מערך / table
OCCURS DEPENDING ON אורך משתנה. שימו לב גם למיקום הבא
FILLER אין שם, אבל יש אורך
COPY בלי copybook אין צורה מלאה
PERFORM שלד המסלול הראשי
READ / WRITE / REWRITE I/O לקובץ
EXEC SQL עיבוד DB
EXEC CICS עיבוד טרנזקציה
FILE STATUS קוד תוצאה של I/O

11. סיכום

COBOL לא קשה כי היא ישנה. הגדרת נתונים, קובץ חיצוני והקשר הרצה קשורים חזק, ולכן רק הכניסה הראשונה קשה לראות.

הסט המינימלי לקריאה, שוב:

  • תופסים מפה עם DIVISION
  • קוראים קודם DATA DIVISION
  • קוראים צורת שדה עם PIC ו-USAGE
  • מסמנים COMP-3, REDEFINES, OCCURS, 88, COPY
  • עוקבים אחרי PERFORM, READ, WRITE, CALL
  • תופסים גבול חיצוני עם FILE STATUS, EXEC SQL, EXEC CICS
  • לא מזלזלים באיך ה-. עובד

ברגע שזה נראה, COBOL עוברת מ”קסם עתיק” ל”שפת עיבוד records”. legacy לא מפחיד כי השם ישן. הוא מפחיד כש-טועים בקנה המידה הראשון. אם קנה המידה של המפה מתאים, זה נקרא די רגיל.

קוראים בקנה מידה מתאיםתופסים מפה עם DIVISION, קוראים קודם DATA DIVISION ותופסים צורה, עוקבים אחרי הזרימה עם PERFORM ו-I/O, ותופסים גבול חיצוני עם FILE STATUS, EXEC SQL ו-EXEC CICS. אז COBOL נקראת כשפת עיבוד records.תופסים מפה עם DIVISIONקוראים צורה ב-DATA DIVISIONעוקבים אחרי הזרימה עם PERFORM ו-I/Oתופסים גבול חיצוניהקסם העתיק הופך לשפת עיבוד records

איור 21: הקושי הוא לא גיל השפה. הוא בחירת קנה המידה הראשון.

12. מקורות

אלה המקורות העיקריים בגוף המאמר. המספרים בגוף הם קישורים לרשימה הזו, ומהחץ בסוף כל פריט אפשר לחזור למקום המקורי.

מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.

העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.

המאמר קשור ישירות לשירותים הבאים.

שאלות נפוצות

שאלות נפוצות בפניות בנושא המאמר.

מאיפה מתחילים לקרוא קוד COBOL?
PROCEDURE DIVISION לבד נותן רק חצי מהתמונה. COBOL היא קודם כל שפת הגדרת records, ורק אחר כך שפת לוגיקה — לכן קודם פותחים DATA DIVISION. סדר בטוח: לעבור על כל ה-COPY ולבדוק copybooks, לרכז את הגדרות הרשומה ברמה 01, לקרוא את צורת השדות דרך PIC ו-USAGE, לחפש READ, WRITE, CALL, EXEC SQL, EXEC CICS כדי לתפוס I/O וגבול חיצוני, ורק אז לעקוב אחרי שרשרת PERFORM בתחילת PROCEDURE DIVISION כדי לתפוס את המסלול הראשי.
מה אומר PIC S9(7)V99 COMP-3?
PIC מתאר את צורת השדה, USAGE מתאר באיזה ייצוג הוא נשמר. S9(7)V99 הוא מספר עם סימן, 7 ספרות שלמות ועוד 2 עשרוניות, אבל V הוא נקודה עשרונית לוגית בלבד — אין תו נקודה בנתונים. COMP-3 הוא packed decimal, ונפוץ בסכומים, מסים, מונים ותעריפים. כטקסט זה נראה שבור, וזה צפוי. dump בתחושה של CSV או UTF-8 הוא מתכון לתאונה.
איך מבינים רמה 88 ו-REDEFINES?
רמה 88 אינה משתנה bool עצמאי. זה condition-name — שם שנתנו לערך של השדה שמעליו. SET WS-OK TO TRUE שם מאחורי הקלעים את הערך המתאים בשדה הבסיס. REDEFINES הוא מבט אחר על אותו שטח זיכרון, לא copy. זה קרוב ל-union ב-C. כותבים צד אחד — גם המראה של הצד השני משתנה. נפוץ כשמזהים את אותו buffer לפי סוג רשומה.
מה עושים כשיש הרבה COPY ולא רואים את התמונה?
COPY הוא include בזמן compile, כך שהקובץ הפתוח כרגע עדיין לא בהכרח הצורה המלאה. די שגרתי שהגדרות רשומה, דגלים משותפים, host variables ל-SQL וממשקים חיצוניים יושבים ב-copybook. כשקשה לקרוא, מהיר יותר לבדוק אם יש expanded source או compiler listing. ב-IBM Enterprise COBOL יש גם אפשרות MDECK שמוציאה את מקור הקלט אחרי עיבוד הספרייה.

פרופיל הכותב

עמוד היכרות עם כותב המאמר.

Go Komura

מנהל KomuraSoft LLC

מתמחה בפיתוח תוכנה עבור Windows, ייעוץ טכני וחקירת תקלות, בעיקר בפרויקטים עם מערכות קיימות ובאגים שקשה לשחזר.

קישורים ציבוריים

חזרה לבלוג