COBOL(Common Business-Oriented Language)是 1959 年問世的編譯程式語言, 最早是以 Grace Hopper 開發的 FLOW-MATIC 語言為範本, 是最早實施標準化的計算機語言之一,專為商業資料處理設計,語法接近英文並且結構冗長,代碼類似英語句子這使得即使非工程師也比較容易閱讀其邏輯, 廣泛應用於大型主機(Mainframe)金融交易、企業薪資計算、庫存管理等需要高處理量與穩定的領域, 目前最新的語言標準版本為 ISO/IEC 1989:2023。
商業軟體方面,比較有名的編譯器實作為 IBM Enterprise COBOL, Micro Focus Visual COBOL, Fujitsu NetCOBOL 以及 Veryant isCOBOL 等軟體。而開放原始碼的 COBOL 編譯器主要有二套, 一個是將 COBOL 原始碼轉譯為 C 語言以後編譯的 GnuCOBOL, 一個是自 GCC 15.1 開始加入的 COBOL 編譯器 GCC COBOL。
在 openSUSE 安裝 GnuCOBOL:
sudo zypper in gnucobol
在 openSUSE 安裝 GCC COBOL:
sudo zypper in gcc-cobol
COBOL 在語法上不區分大小寫(Case-insensitive),因此保留字、變數名稱、段落名稱等,使用大寫、小寫或混合大小寫書寫, 對編譯器而言都是相同的。在 COBOL-85 標準之前,COBOL 程式通常要求全部使用大寫字母編寫。現代 COBOL 雖然允許使用小寫, 但為了維持舊代碼的兼容性和傳統習慣,許多開發者仍習慣使用全大寫。 程式碼分為四大部:IDENTIFICATION DIVISION(識別部)、ENVIRONMENT DIVISION(設備部)、 DATA DIVISION(資料部)和PROCEDURE DIVISION(程序部)。
All COBOL programs are organized in a structure that consists of divisions, sections, paragraphs, sentences, statements, clauses, and phrases.
This structure is hierarchical--that is, as a general rule,
- a COBOL program is made up of divisions;
- a division is made up of sections;
- a section is made up of paragraphs;
- a paragraph is made up of either sentences or clauses (depending upon the division); a sentence can contain one or more statements;
- a statement or clause can contain one or more phrases.
COBOL can be written in two formats: fixed (the default) or free. In fixed-format, code must be aligned to fit in certain areas (a holdover from using punched cards). Until COBOL 2002, these were:
| Name | Column(s) | Usage |
|---|---|---|
| Sequence number area | 1–6 | Originally used for card/line numbers (facilitating mechanical punched card sorting to assure intended program code sequence after manual editing/handling), this area is ignored by the compiler |
| Indicator area | 7 | The following characters are allowed here:
|
| Area A | 8–11 | This contains: DIVISION, SECTION and procedure headers; 01 and 77 level numbers and file/report descriptors
|
| Area B | 12–72 | Any other code not allowed in Area A |
| Program name area | 73– | Historically up to column 80 for punched cards, it is used to identify the program or sequence the card belongs to |
In COBOL 2002, Areas A and B were merged to form the program-text area, which now ends at an implementor-defined column.
COBOL 2002 also introduced free-format code. Free-format code can be placed in any column of the file, as in newer programming languages. Comments are specified using *>, which can be placed anywhere and can also be used in fixed-format source code. Continuation lines are not present, and the >>PAGE directive replaces the / indicator.
下面是一個 Hello World 的例子 (fixed format):
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO-WORLD.
PROCEDURE DIVISION.
DISPLAY 'Hello, World!'.
STOP RUN.
下面是使用 GOBACK 的寫法:
IDENTIFICATION DIVISION.
PROGRAM-ID. hello.
PROCEDURE DIVISION.
DISPLAY "Hello, world!"
GOBACK.
END PROGRAM hello.
使用 GnuCOBOL 編譯:
cobc -x hello.cob
使用 GCC COBOL 編譯:
gcobol -main hello.cob -o hello
下面是一個 Hello World 的例子 (free format):
*> COBOL Hello World program
identification division.
program-id. hello.
procedure division.
display "Hello World! ".
goback.
使用 GnuCOBOL 編譯:
cobc -x -free hello.cob
使用 GCC COBOL 編譯:
gcobol -ffree-form -main hello.cob -o hello
Data Division
Data Division is used to define the variables used in a program. To describe data in COBOL, one must understand the following terms −
- Level Number
- Data Name
- Picture Clause
- Value Clause
Standard COBOL provides the following data types:
| Data type | Sample declaration | Notes |
|---|---|---|
| Alphabetic | PIC A(30)
|
May contain only letters or spaces. |
| Alphanumeric | PIC X(30)
|
May contain any characters. |
| Boolean | PIC 1 USAGE BIT
|
Data stored in the form of 0s and 1s, as a binary number. |
| Index | USAGE INDEX
|
Used to reference table elements. |
| National | PIC N(30)
|
Similar to alphanumeric, but using an extended character set, e.g. UTF-8. |
| Numeric | PIC 9(5)V9(2)
|
Contains exactly 7 digits (7=5+2). 'V' locates the implicit decimal in a fixed point number. |
| Object | USAGE OBJECT REFERENCE
|
May reference either an object or NULL.
|
| Pointer | USAGE POINTER
|
Data items in COBOL are declared hierarchically through the use of level-numbers which indicate if a data item is part of another. An item with a higher level-number is subordinate to an item with a lower one. Top-level data items, with a level-number of 1, are called records. Items that have subordinate aggregate data are called group items; those that do not are called elementary items. Level-numbers used to describe standard data items are between 1 and 49.
01 some-record. *> Aggregate group record item
05 num PIC 9(10). *> Elementary item
05 the-date. *> Aggregate (sub)group record item
10 the-year PIC 9(4). *> Elementary item
10 the-month PIC 99. *> Elementary item
10 the-day PIC 99. *> Elementary item
A level-number of 66 is used to declare a re-grouping of previously defined items, irrespective of how those items are structured. This data level, also referred to by the associated RENAMES clause.
01 customer-record.
05 cust-key PIC X(10).
05 cust-name.
10 cust-first-name PIC X(30).
10 cust-last-name PIC X(30).
05 cust-dob PIC 9(8).
05 cust-balance PIC 9(7)V99.
66 cust-personal-details RENAMES cust-name THRU cust-dob.
66 cust-all-details RENAMES cust-name THRU cust-balance.
A 77 level-number indicates the item is stand-alone, and in such situations is equivalent to the level-number 01.
An 88 level-number declares a condition name (a so-called 88-level) which is true when its parent data item contains one of the values specified in its VALUE clause.
01 wage-type PIC X.
88 wage-is-hourly VALUE "H".
88 wage-is-yearly VALUE "S", "Y".
A PICTURE (or PIC) clause is a string of characters, each of which represents a portion of the data item and what it may contain. Some picture characters specify the type of the item and how many characters or digits it occupies in memory. For example, a 9 indicates a decimal digit, and an S indicates that the item is signed. Other picture characters (called insertion and editing characters) specify how an item should be formatted.
The USAGE clause declares the format in which data is stored. Depending on the data type, it can either complement or be used instead of a PICTURE clause. While it can be used to declare pointers and object references, it is mostly geared towards specifying numeric types.
- BINARY, where a minimum size is either specified by the PICTURE clause or by a USAGE clause such as BINARY-LONG.
- USAGE COMPUTATIONAL, where data may be stored in whatever format the implementation provides; often equivalent to USAGE BINARY. A computational item is a value used in arithmetic operations. It must be numeric. If a group item is described with a computational usage, the elementary items within the group have that usage.
- USAGE DISPLAY, the default format, where data is stored as a string
- COMPUTATIONAL-1 or COMP-1 specified for internal floating-point items (single precision). COMP-1 items are 4 bytes long.
- COMPUTATIONAL-2 or COMP-2 (long floating-point) specified for internal floating-point items (double precision). COMP-2 items are 8 bytes long.
- COMPUTATIONAL-3 or COMP-3 (internal decimal) is the equivalent of PACKED-DECIMAL. PACKED-DECIMAL specified for internal decimal items.
- USAGE NATIONAL, where data is stored as a string using an extended character set
- USAGE PACKED-DECIMAL, where data is stored in the smallest possible decimal format (typically packed binary-coded decimal)
Value clause is an optional clause which is used to initialize the data items. The values can be numeric literal, alphanumeric literal, or figurative constant. It can be used with both group and elementary items.
下面是一個宣告變數的例子:
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NAME PIC A(6) VALUE 'ABCDEF'.
PROCEDURE DIVISION.
DISPLAY "WS-NAME : "WS-NAME.
STOP RUN.
In COBOL, the WORKING-STORAGE SECTION and LOCAL-STORAGE SECTION are both part of the Data Division used to define internal variables, but they differ fundamentally in how they manage memory and handle program calls. Use WORKING-STORAGE SECTION for standard variables, counters, or flags that need to retain their values if a subprogram is called multiple times without being cancelled. Use LOCAL-STORAGE SECTION when writing recursive programs (where a program calls itself) to ensure each "level" of recursion has its own set of variables. It is also preferred in multi-threaded applications to avoid data corruption between threads.
COBOL Copybook 是一種包含 COBOL 程式碼的外部檔案,主要定義資料結構(如 01 階層式記錄), 可被多個程式透過 COPY 語句引入。它能實現結構定義的統一管理,確保資料一致性,通常使用 .cpy 副檔名儲存。
STUDENT.cpy
01 STUDENT-RECORD.
05 STUDENT-ID PIC 9(05).
05 STUDENT-NAME.
10 FIRST-NAME PIC X(20).
10 LAST-NAME PIC X(20).
05 DATE-OF-BIRTH PIC 9(08).
05 ENROLLMENT-STATUS PIC X(01).
88 ACTIVE-STUDENT VALUE 'A'.
88 INACTIVE-STUDENT VALUE 'I'.
STU-INFO.cob
IDENTIFICATION DIVISION.
PROGRAM-ID. STU-INFO.
DATA DIVISION.
WORKING-STORAGE SECTION.
* The COPY statement pulls in the code from STUDENT.cpy
COPY STUDENT.
PROCEDURE DIVISION.
MOVE 12345 TO STUDENT-ID.
MOVE "JOHN" TO FIRST-NAME.
SET ACTIVE-STUDENT TO TRUE.
DISPLAY "STUDENT ID: " STUDENT-ID.
DISPLAY "STATUS: " ENROLLMENT-STATUS.
STOP RUN.
Initialize 用來初始化變數。MOVE 可以用來設值。
而 ADD, SUBTRACT, MULTIPLY, DIVIDE 用來作為數值加滅乘除之用,
Compute 則是可以用來編寫算術表達式,可以使用 Compute 取代 ADD, SUBTRACT, MULTIPLY, DIVIDE。
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-VAR1 PIC 9(3).
01 WS-VAR2 PIC 9(3).
PROCEDURE DIVISION.
MAIN-PARA.
INITIALIZE WS-VAR1 REPLACING NUMERIC DATA BY 010.
MOVE 010 TO WS-VAR2.
DIVIDE 10 INTO WS-VAR1.
MULTIPLY WS-VAR1 BY 2 GIVING WS-VAR1.
ADD 4 TO WS-VAR1.
SUBTRACT 3 FROM WS-VAR1.
COMPUTE WS-VAR2 = (((WS-VAR2 / 10) * 2) + 4) - 3
DISPLAY "WS-VAR1 is : " WS-VAR1.
DISPLAY "WS-VAR2 is : " WS-VAR2.
STOP RUN.
ACCEPT 可以用來自標準輸入 (STDIN) 取得輸入資料。
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-STUDENT-NAME PIC X(25).
PROCEDURE DIVISION.
ACCEPT WS-STUDENT-NAME.
DISPLAY "Name : " WS-STUDENT-NAME.
STOP RUN.
Conditional Statements
COBOL 使用 IF 進行條件判斷。要注意的是,COBOL 只有 IF ... ELSE 結構,並沒有直接支援 ELSE IF, 但是可以在 ELSE 下使用 IF 條件句進行更多的條件判斷。
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NUM1 PIC 9(9).
01 WS-NUM2 PIC 9(9).
01 WS-NUM3 PIC 9(5).
01 WS-NUM4 PIC 9(6).
PROCEDURE DIVISION.
MOVE 25 TO WS-NUM1 WS-NUM3.
MOVE 15 TO WS-NUM2 WS-NUM4.
IF WS-NUM1 > WS-NUM2 THEN
DISPLAY 'IN LOOP 1 - IF BLOCK'
IF WS-NUM3 = WS-NUM4 THEN
DISPLAY 'IN LOOP 2 - IF BLOCK'
ELSE
DISPLAY 'IN LOOP 2 - ELSE BLOCK'
END-IF
ELSE
DISPLAY 'IN LOOP 1 - ELSE BLOCK'
END-IF.
STOP RUN.
如果需要多於一個以上的比較,可以使用 EVALUATE。
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-A PIC 9 VALUE 0.
PROCEDURE DIVISION.
MOVE 3 TO WS-A.
EVALUATE TRUE
WHEN WS-A > 2
DISPLAY 'WS-A GREATER THAN 2'
WHEN WS-A < 0
DISPLAY 'WS-A LESS THAN 0'
WHEN OTHER
DISPLAY 'INVALID VALUE OF WS-A'
END-EVALUATE.
STOP RUN.
Loop Statements
GO TO 陳述式是 COBOL 無條件轉移控制權的機制。 GO TO 會直接跳轉到程式中指定的段落(Paragraph)或節(Section)繼續執行。 在軟體開發引入結構化程式設計以後,COBOL 使用 PERFORM 進行迴圈控制流程, 一般而言建議盡量使用 PERFORM 進行結構化的程式設計。
PERFORM 用來呼叫其它的 paragraph。
IDENTIFICATION DIVISION.
PROGRAM-ID. COUNT.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-I PIC 9 VALUE 1.
PROCEDURE DIVISION.
MAIN-PARA.
DISPLAY 'Starting Program'
PERFORM 1000-PROCESS-DATA
DISPLAY 'Finished Program'
STOP RUN.
1000-PROCESS-DATA.
DISPLAY 'Inside the paragraph'.
Perform Thru 用來執行一系列的 paragraph。
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
PROCEDURE DIVISION.
A-PARA.
PERFORM DISPLAY 'IN A-PARA'
END-PERFORM.
PERFORM C-PARA THRU E-PARA.
B-PARA.
DISPLAY 'IN B-PARA'.
STOP RUN.
C-PARA.
DISPLAY 'IN C-PARA'.
D-PARA.
DISPLAY 'IN D-PARA'.
E-PARA.
DISPLAY 'IN E-PARA'.
用來執行重覆多少次的迴圈。
IDENTIFICATION DIVISION.
PROGRAM-ID. COUNT.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-I PIC 9 VALUE 1.
PROCEDURE DIVISION.
PERFORM 3 TIMES
DISPLAY "It is " WS-I
ADD 1 TO WS-I
END-PERFORM.
STOP RUN.
PERFORM UNTIL 用來執行類似其它語言 WHILE 語句的迴圈。
IDENTIFICATION DIVISION.
PROGRAM-ID. COUNT.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-COUNTER PIC 9 VALUE 1.
PROCEDURE DIVISION.
PERFORM UNTIL WS-COUNTER > 5
DISPLAY "Counter is: " WS-COUNTER
ADD 1 TO WS-COUNTER
END-PERFORM.
STOP RUN.
PERFORM VARYING 用來執行類似其它語言 FOR 語句的迴圈。下面實作了九九乘法表:
IDENTIFICATION DIVISION.
PROGRAM-ID. MULT-TABLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 I PIC 99 VALUE 1.
01 J PIC 99 VALUE 1.
01 RESULT PIC 99.
PROCEDURE DIVISION.
MAIN-PROCEDURE.
PERFORM VARYING I FROM 1 BY 1 UNTIL I > 9
PERFORM VARYING J FROM 1 BY 1 UNTIL J > 9
COMPUTE RESULT = I * J
DISPLAY I " x " J " = " RESULT
END-PERFORM
END-PERFORM.
STOP RUN.
(注意:經過實測,如果 I 或者是 J 宣告為 PIC 9,因為需要其值為 10 才能夠達成停止條件, 這樣迴圈並無法停止,也就是形成了無窮迴圈)
在 COBOL 2014 標準提出了 EXIT PERFORM CYCLE 中斷迴圈此次循環以及 EXIT PERFORM 中斷迴圈的語句, 但是不是所有的 COBOL 編譯器都有支援。
Write a program that displays the digits from 1 to n then back down to 1; for instance, if n = 5, the program should display 123454321. You are permitted to use only a single for loop. The range is 0 < n < 10.
IDENTIFICATION DIVISION.
PROGRAM-ID. NUMBER-COUNT.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NUMBER PIC 9.
PROCEDURE DIVISION.
ACCEPT WS-NUMBER FROM COMMAND-LINE.
IF WS-NUMBER < 1 OR WS-NUMBER > 9 THEN
DISPLAY 'INVALID VALUE'
STOP RUN
END-IF.
EVALUATE TRUE
WHEN WS-NUMBER = 1
DISPLAY '1'
WHEN WS-NUMBER = 2
DISPLAY '121'
WHEN WS-NUMBER = 3
DISPLAY '12321'
WHEN WS-NUMBER = 4
DISPLAY '1234321'
WHEN WS-NUMBER = 5
DISPLAY '123454321'
WHEN WS-NUMBER = 6
DISPLAY '12345654321'
WHEN WS-NUMBER = 7
DISPLAY '1234567654321'
WHEN WS-NUMBER = 8
DISPLAY '123456787654321'
WHEN WS-NUMBER = 9
DISPLAY '12345678987654321'
WHEN OTHER
DISPLAY 'INVALID VALUE'
END-EVALUATE.
STOP RUN.
要注意的是,命令列通常以空白作為區隔參數的符號, 而這裡使用的 COMMAND-LINE 會拿到一個將全部的命令列參數視為整體的字串(參數之間以空白區隔), 這也是大多數的 COBOL 編譯器都支援的方式。至於命令列參數的總數以及存取個別參數的方式, 因為 COBOL 標準沒有定義,所以不同的 COBOL 編譯器有其自己的實作。
改寫為使用迴圈的寫法:
IDENTIFICATION DIVISION.
PROGRAM-ID. NUMBER-COUNT.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NUMBER PIC 9.
01 WS-POSITIVE PIC 9 VALUE 1.
01 WS-COUNT PIC 9 VALUE 0.
PROCEDURE DIVISION.
ACCEPT WS-NUMBER FROM COMMAND-LINE.
IF WS-NUMBER < 1 OR WS-NUMBER > 9 THEN
DISPLAY 'INVALID VALUE'
STOP RUN
END-IF.
PERFORM UNTIL 1 < 0
IF WS-POSITIVE IS EQUAL TO 1 THEN
ADD 1 TO WS-COUNT
DISPLAY WS-COUNT WITH NO ADVANCING
IF WS-COUNT IS EQUAL TO WS-NUMBER THEN
MOVE 0 TO WS-POSITIVE
END-IF
ELSE
SUBTRACT 1 FROM WS-COUNT
IF WS-COUNT IS GREATER THAN 0 THEN
DISPLAY WS-COUNT WITH NO ADVANCING
ELSE
EXIT PERFORM
END-IF
END-IF
END-PERFORM.
DISPLAY " "
STOP RUN.
下面是一個讓使用者輸入一個數字以後,猜測與隨機製造的數字是否相同的遊戲:
IDENTIFICATION DIVISION.
PROGRAM-ID. RANDOM-EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-RESULT PIC 9(4).
01 WS-ANSWER PIC 9(4).
PROCEDURE DIVISION.
COMPUTE WS-RESULT = (FUNCTION RANDOM * 999) + 1
PERFORM UNTIL 1 < 0
DISPLAY "Please give a number (1-1000): "
WITH NO ADVANCING
ACCEPT WS-ANSWER
IF WS-ANSWER IS EQUAL TO WS-RESULT THEN
EXIT PERFORM
ELSE
IF WS-ANSWER IS GREATER THAN WS-RESULT THEN
DISPLAY "Please guess more lower"
ELSE
DISPLAY "Please guess more higher"
END-IF
END-IF
END-PERFORM.
STOP RUN.
String Handling
Inspect verb is used to count or replace the characters in a string. String operations can be performed on alphanumeric, numeric, or alphabetic values. Inspect operations are performed from left to right.
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CNT1 PIC 9(2) VALUE 0.
01 WS-CNT2 PIC 9(2) VALUE 0.
01 WS-STRING PIC X(18) VALUE 'ABCDACDADEAAAFFABC'.
PROCEDURE DIVISION.
INSPECT WS-STRING TALLYING WS-CNT1 FOR ALL 'A'.
DISPLAY "WS-CNT1 : "WS-CNT1
INSPECT WS-STRING TALLYING WS-CNT2 FOR CHARACTERS.
DISPLAY "WS-CNT2 : "WS-CNT2
STOP RUN.
下面是用來取代某個字元的範例。
Write a program to replace the character ’e’ with ‘E’ in the string ‘Weekly Challenge’. Also print the number of times the character ’e’ is found in the string.
IDENTIFICATION DIVISION.
PROGRAM-ID. REPLACE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-COUNT PIC 9(2) VALUE 0.
01 WS-STRING PIC X(16) VALUE 'Weekly Challenge'.
PROCEDURE DIVISION.
INSPECT WS-STRING TALLYING WS-COUNT FOR ALL 'e'.
DISPLAY "Find e " WS-COUNT " times.".
INSPECT WS-STRING REPLACING ALL "e" BY "E".
DISPLAY "NEW STRING: "WS-STRING.
STOP RUN.
下面是 1-9 位數不重複印出來的練習問題。
這裡使用了 PIC Z 的定義,它的主要作用是抑制前導零(Zero Suppression)。
當對應的數值為零時,Z 字元會將該數字位置顯示為空白,讓輸出結果更易讀。
IDENTIFICATION DIVISION.
PROGRAM-ID. LIST-NUMBER.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-CNT1 PIC 9.
01 WS-FLAG PIC 9.
01 WS-NUMBER PIC Z(8)9.
LOCAL-STORAGE SECTION.
01 LS-NUM PIC 9 USAGE BINARY.
01 LS-MAX PIC 9(9) USAGE BINARY.
01 LS-INDEX PIC 9(10) USAGE BINARY.
PROCEDURE DIVISION.
MAIN-PARA.
DISPLAY "Please give a number: " WITH NO ADVANCING
ACCEPT LS-NUM
IF LS-NUM < 1 OR LS-NUM > 9 THEN
DISPLAY "INVALID DATA."
STOP RUN
END-IF.
COMPUTE LS-MAX = 10 ** LS-NUM - 1
PERFORM VARYING LS-INDEX FROM 1 BY 1 UNTIL LS-INDEX > LS-MAX
MOVE 0 TO WS-FLAG
MOVE LS-INDEX TO WS-NUMBER
PERFORM CHECK-PARA
IF WS-FLAG IS EQUAL TO 0 THEN
DISPLAY FUNCTION TRIM(WS-NUMBER)
END-IF
END-PERFORM.
STOP RUN.
CHECK-PARA.
MOVE 0 TO WS-CNT1
INSPECT WS-NUMBER TALLYING WS-CNT1 FOR ALL '1'.
IF WS-CNT1 IS GREATER THAN 1 THEN
MOVE 1 TO WS-FLAG
EXIT PARAGRAPH
END-IF.
MOVE 0 TO WS-CNT1
INSPECT WS-NUMBER TALLYING WS-CNT1 FOR ALL '2'.
IF WS-CNT1 IS GREATER THAN 1 THEN
MOVE 1 TO WS-FLAG
EXIT PARAGRAPH
END-IF.
MOVE 0 TO WS-CNT1
INSPECT WS-NUMBER TALLYING WS-CNT1 FOR ALL '3'.
IF WS-CNT1 IS GREATER THAN 1 THEN
MOVE 1 TO WS-FLAG
EXIT PARAGRAPH
END-IF.
MOVE 0 TO WS-CNT1
INSPECT WS-NUMBER TALLYING WS-CNT1 FOR ALL '4'.
IF WS-CNT1 IS GREATER THAN 1 THEN
MOVE 1 TO WS-FLAG
EXIT PARAGRAPH
END-IF.
MOVE 0 TO WS-CNT1
INSPECT WS-NUMBER TALLYING WS-CNT1 FOR ALL '5'.
IF WS-CNT1 IS GREATER THAN 1 THEN
MOVE 1 TO WS-FLAG
EXIT PARAGRAPH
END-IF.
MOVE 0 TO WS-CNT1
INSPECT WS-NUMBER TALLYING WS-CNT1 FOR ALL '6'.
IF WS-CNT1 IS GREATER THAN 1 THEN
MOVE 1 TO WS-FLAG
EXIT PARAGRAPH
END-IF.
MOVE 0 TO WS-CNT1
INSPECT WS-NUMBER TALLYING WS-CNT1 FOR ALL '7'.
IF WS-CNT1 IS GREATER THAN 1 THEN
MOVE 1 TO WS-FLAG
EXIT PARAGRAPH
END-IF.
MOVE 0 TO WS-CNT1
INSPECT WS-NUMBER TALLYING WS-CNT1 FOR ALL '8'.
IF WS-CNT1 IS GREATER THAN 1 THEN
MOVE 1 TO WS-FLAG
EXIT PARAGRAPH
END-IF.
MOVE 0 TO WS-CNT1
INSPECT WS-NUMBER TALLYING WS-CNT1 FOR ALL '9'.
IF WS-CNT1 IS GREATER THAN 1 THEN
MOVE 1 TO WS-FLAG
EXIT PARAGRAPH
END-IF.
MOVE 0 TO WS-CNT1
INSPECT WS-NUMBER TALLYING WS-CNT1 FOR ALL '0'.
IF WS-CNT1 IS GREATER THAN 1 THEN
MOVE 1 TO WS-FLAG
EXIT PARAGRAPH
END-IF.
String verb is used to concatenate the strings. Using STRING statement, two or more strings of characters can be combined to form a longer string. Delimited By clause is compulsory.
DELIMITED BY SIZE moves the entire source field regardless of its content. DELIMITED BY SPACE clause indicates that the transfer of characters from a source field stops as soon as the first space is encountered.
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-STRING PIC A(30).
01 WS-STR1 PIC A(15) VALUE 'Tutorialspoint'.
01 WS-STR2 PIC A(7) VALUE 'Welcome'.
01 WS-STR3 PIC A(7) VALUE 'To AND'.
01 WS-COUNT PIC 99 VALUE 1.
PROCEDURE DIVISION.
STRING WS-STR2 DELIMITED BY SIZE
WS-STR3 DELIMITED BY SPACE
WS-STR1 DELIMITED BY SIZE
INTO WS-STRING
WITH POINTER WS-COUNT
ON OVERFLOW DISPLAY 'OVERFLOW!'
END-STRING.
DISPLAY 'WS-STRING : 'WS-STRING.
DISPLAY 'WS-COUNT : 'WS-COUNT.
STOP RUN.
Unstring verb is used to split one string into multiple sub-strings. Delimited By clause is compulsory.
IDENTIFICATION DIVISION.
PROGRAM-ID. EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-STRING PIC A(30) VALUE 'WELCOME TO TUTORIALSPOINT'.
01 WS-STR1 PIC A(7).
01 WS-STR2 PIC A(2).
01 WS-STR3 PIC A(15).
PROCEDURE DIVISION.
UNSTRING WS-STRING DELIMITED BY SPACE
INTO WS-STR1, WS-STR2, WS-STR3
END-UNSTRING.
DISPLAY 'WS-STR1 : 'WS-STR1.
DISPLAY 'WS-STR2 : 'WS-STR2.
DISPLAY 'WS-STR3 : 'WS-STR3.
STOP RUN.
Table Processing
Arrays in COBOL are known as tables. Table is declared in Data Division. Occurs clause is used to define a table. Occurs clause indicates the repetition of data name definition. It can be used only with level numbers starting from 02 to 49. Do not use occurs clause with Redefines.
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-TABLE.
05 WS-A PIC A(10) VALUE 'TUTORIALS' OCCURS 5 TIMES.
PROCEDURE DIVISION.
DISPLAY "ONE-D TABLE : "WS-TABLE.
STOP RUN.
下面是另外一個例子。
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-TABLE.
05 WS-A OCCURS 2 TIMES.
10 WS-B PIC A(10) VALUE ' TUTORIALS'.
10 WS-C OCCURS 2 TIMES.
15 WS-D PIC X(6) VALUE ' POINT'.
PROCEDURE DIVISION.
DISPLAY "TWO-D TABLE : "WS-TABLE.
STOP RUN.
Table individual elements can be accessed by using subscript. Subscript values can range from 1 to the number of times the table occurs. A subscript can be any positive number. It does not require any declaration in data division. It is automatically created with occurs clause.
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-TABLE.
05 WS-A OCCURS 3 TIMES.
10 WS-B PIC A(2).
10 WS-C OCCURS 2 TIMES.
15 WS-D PIC X(3).
PROCEDURE DIVISION.
MOVE '12ABCDEF34GHIJKL56MNOPQR' TO WS-TABLE.
DISPLAY 'WS-TABLE : ' WS-TABLE.
DISPLAY 'WS-A(1) : ' WS-A(1).
DISPLAY 'WS-C(1 1) : ' WS-C(1 1).
DISPLAY 'WS-C(1 2) : ' WS-C(1 2).
DISPLAY 'WS-A(2) : ' WS-A(2).
DISPLAY 'WS-C(2 1) : ' WS-C(2 1).
DISPLAY 'WS-C(2 2) : ' WS-C(2 2).
DISPLAY 'WS-A(3) : ' WS-A(3).
DISPLAY 'WS-C(3 1) : ' WS-C(3 1).
DISPLAY 'WS-C(3 2) : ' WS-C(3 2).
STOP RUN.
Table elements can also be accessed using index. An index is a displacement of element from the start of the table. An index is declared with Occurs clause using INDEXED BY clause. The value of index can be changed using SET statement and PERFORM Varying option.
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-TABLE.
05 WS-A OCCURS 3 TIMES INDEXED BY I.
10 WS-B PIC A(2).
10 WS-C OCCURS 2 TIMES INDEXED BY J.
15 WS-D PIC X(3).
PROCEDURE DIVISION.
MOVE '12ABCDEF34GHIJKL56MNOPQR' TO WS-TABLE.
PERFORM A-PARA VARYING I FROM 1 BY 1 UNTIL I > 3
STOP RUN.
A-PARA.
PERFORM C-PARA VARYING J FROM 1 BY 1 UNTIL J > 2.
C-PARA.
DISPLAY WS-C(I,J).
File Handling
The concept of files in COBOL is different from that in C/C++. COBOL file handling is a core feature designed to process large volumes of structured data efficiently. It operates on logical records rather than raw text files, typically interacting with Physical Sequential (PS) or VSAM files in mainframe environments.
COBOL supports three primary file types defined in the ENVIRONMENT DIVISION:
- Sequential: Records are stored and accessed in the order they were written.
- Indexed: Records are accessed using a unique primary key, allowing both sequential and random access.
- Relative: Records are stored in fixed slots and accessed via a Relative Record Number (RRN).
File handling requires entries across three main divisions:
- ENVIRONMENT DIVISION: Use the FILE-CONTROL Paragraph and SELECT clause to map a program's internal logical file name to an external physical file (often via JCL).
- DATA DIVISION: The FILE SECTION contains the File Description (FD) entry, which defines record length and layout.
- PROCEDURE DIVISION: Contains the logic to manipulate data using file handling verbs.
我們將文字檔視為將一行作為一個 record 儲存並且以換行字元區隔的檔案, 因此可以這樣讀取 Linux 下的 /etc/os-release 並且取得 Linux Distribution Name:
IDENTIFICATION DIVISION.
PROGRAM-ID. READ-NAME.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT MY-FILE ASSIGN TO '/etc/os-release'
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD MY-FILE.
01 MY-RECORD PIC X(80).
WORKING-STORAGE SECTION.
01 WS-EOF PIC X VALUE 'N'.
88 EOF-REACHED VALUE 'Y'.
77 WS-KEY PIC X(20).
77 WS-VAL PIC X(60).
PROCEDURE DIVISION.
MAIN-LOGIC.
OPEN INPUT MY-FILE
PERFORM UNTIL EOF-REACHED
READ MY-FILE
AT END
MOVE 'Y' TO WS-EOF
NOT AT END
PERFORM PARSE-STRING
IF WS-KEY = "NAME" THEN
DISPLAY WS-VAL
EXIT PERFORM
END-IF
END-READ
END-PERFORM
CLOSE MY-FILE
STOP RUN.
PARSE-STRING.
UNSTRING MY-RECORD
DELIMITED BY "="
INTO WS-KEY, WS-VAL
END-UNSTRING.
Subroutines
Cobol subroutine is a program that can be compiled independently but cannot be executed independently. There are two types of subroutines: internal subroutines like Perform statements and external subroutines like CALL verb.
If the values of variables in the called program are modified, then their new values will reflect in the calling program. If BY clause is not specified, then variables are always passed by reference.
The LINKAGE SECTION in COBOL is a part of the DATA DIVISION used to describe data that is available to a program but is not stored within that program's own memory. You cannot use the VALUE clause for items in LINKAGE SECTION, except for level-88 condition names.
main program
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.
Called Program
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.
BY CONTENT on a CALL will copy the content of the identifier to a compiler-managed area of storage. If the values of variables in the called program are modified, then their new values will not reflect in the calling program.
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 BY CONTENT WS-STUDENT-ID,
BY CONTENT WS-STUDENT-NAME.
DISPLAY 'Student Id : ' WS-STUDENT-ID
DISPLAY 'Student Name : ' WS-STUDENT-NAME
STOP RUN.
CALL 除了用來呼叫外部的函數,也可以呼叫 SYSTEM 執行外部的程式。
IDENTIFICATION DIVISION.
PROGRAM-ID. CALL-PROGRAM.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 COMMAND-STRING PIC X(20) VALUE "ls -al".
01 RETURN-CODE-WS PIC 9(4).
PROCEDURE DIVISION.
CALL "SYSTEM" USING COMMAND-STRING RETURNING RETURN-CODE-WS.
GOBACK.
下面是人類猜數字的小遊戲:
GETA.cbl
IDENTIFICATION DIVISION.
PROGRAM-ID. 'GETA'.
DATA DIVISION.
LOCAL-STORAGE SECTION.
01 LS-INDEX PIC 9.
LINKAGE SECTION.
01 LS-ANSWER PIC 9(4).
01 LS-GUESS PIC 9(4).
01 LS-COUNT PIC 9.
PROCEDURE DIVISION USING LS-ANSWER, LS-GUESS, LS-COUNT.
PERFORM VARYING LS-INDEX FROM 1 BY 1 UNTIL LS-INDEX > 4
IF LS-ANSWER(LS-INDEX:1) = LS-GUESS(LS-INDEX:1) THEN
ADD 1 TO LS-COUNT
END-IF
END-PERFORM.
GOBACK.
END PROGRAM 'GETA'.
GETB.cbl
IDENTIFICATION DIVISION.
PROGRAM-ID. 'GETB'.
DATA DIVISION.
LOCAL-STORAGE SECTION.
01 LS-INDEX1 PIC 9.
01 LS-INDEX2 PIC 9.
LINKAGE SECTION.
01 LS-ANSWER PIC 9(4).
01 LS-GUESS PIC 9(4).
01 LS-COUNT PIC 9.
PROCEDURE DIVISION USING LS-ANSWER, LS-GUESS, LS-COUNT.
PERFORM VARYING LS-INDEX1 FROM 1 BY 1 UNTIL LS-INDEX1 > 4
PERFORM VARYING LS-INDEX2 FROM 1 BY 1 UNTIL LS-INDEX2 > 4
IF LS-INDEX1 IS NOT EQUAL TO LS-INDEX2 THEN
IF LS-ANSWER(LS-INDEX1:1) = LS-GUESS(LS-INDEX2:1)
THEN
ADD 1 TO LS-COUNT
END-IF
END-IF
END-PERFORM
END-PERFORM.
GOBACK.
END PROGRAM 'GETB'.
guess.cbl
IDENTIFICATION DIVISION.
PROGRAM-ID. GUESS-GAME.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-ANSWER PIC 9(4).
01 WS-GUESS PIC 9(4).
01 WS-AVALUE PIC 9.
01 WS-BVALUE PIC 9.
PROCEDURE DIVISION.
PERFORM UNTIL 1 < 0
COMPUTE WS-ANSWER = (FUNCTION RANDOM * 9999) + 1
IF WS-ANSWER(1:1) <> WS-ANSWER(2:1) AND
WS-ANSWER(1:1) <> WS-ANSWER(3:1) AND
WS-ANSWER(1:1) <> WS-ANSWER(4:1) AND
WS-ANSWER(2:1) <> WS-ANSWER(3:1) AND
WS-ANSWER(2:1) <> WS-ANSWER(4:1) AND
WS-ANSWER(3:1) <> WS-ANSWER(4:1) THEN
EXIT PERFORM
END-IF
END-PERFORM.
PERFORM UNTIL 1 < 0
DISPLAY "Please input your guess: " WITH NO ADVANCING
ACCEPT WS-GUESS
MOVE 0 TO WS-AVALUE
MOVE 0 TO WS-BVALUE
CALL 'GETA' USING BY CONTENT WS-ANSWER, WS-GUESS,
BY REFERENCE WS-AVALUE
CALL 'GETB' USING BY CONTENT WS-ANSWER, WS-GUESS,
BY REFERENCE WS-BVALUE
DISPLAY "Result: A = " WS-AVALUE " B = " WS-BVALUE
DISPLAY " "
IF WS-AVALUE = 4 AND WS-BVALUE = 0 THEN
DISPLAY "Game is completed."
EXIT PERFORM
END-IF
END-PERFORM.
STOP RUN.
下面是電腦猜數字的小遊戲:
IDENTIFICATION DIVISION.
PROGRAM-ID. RANDOM-EXAMPLE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-SOLUTIONS.
05 WS-NUMBER PIC 9(4) VALUE 0000 OCCURS 5040 TIMES.
01 WS-NEW-NUMBERS.
05 WS-NEW-NUMBER PIC 9(4) VALUE 0000 OCCURS 5040 TIMES.
01 WS-ANSWER PIC 9(4).
01 WS-GUESS PIC 9(4).
77 WS-AVALUE PIC 9.
77 WS-BVALUE PIC 9.
77 WS-AGUESS PIC 9.
77 WS-BGUESS PIC 9.
01 WS-INDEX1 PIC 99.
01 WS-INDEX2 PIC 99.
01 WS-INDEX3 PIC 99.
01 WS-INDEX4 PIC 99.
01 WS-COUNT1 PIC 9(4).
01 WS-COUNT2 PIC 9(4).
01 WS-LOOP1 PIC 9(4).
PROCEDURE DIVISION.
INITIALIZE WS-COUNT1 REPLACING NUMERIC DATA BY 0000.
PERFORM VARYING WS-INDEX1 FROM 0 BY 1 UNTIL WS-INDEX1 > 9
PERFORM VARYING WS-INDEX2 FROM 0 BY 1 UNTIL WS-INDEX2 > 9
PERFORM VARYING WS-INDEX3 FROM 0 BY 1
UNTIL WS-INDEX3 > 9
PERFORM VARYING WS-INDEX4 FROM 0 BY 1
UNTIL WS-INDEX4 > 9
IF WS-INDEX1 <> WS-INDEX2 AND
WS-INDEX1 <> WS-INDEX3 AND
WS-INDEX1 <> WS-INDEX4 AND
WS-INDEX2 <> WS-INDEX3 AND
WS-INDEX2 <> WS-INDEX4 AND
WS-INDEX3 <> WS-INDEX4 THEN
ADD 1 TO WS-COUNT1
STRING WS-INDEX1(2:1) WS-INDEX2(2:1)
WS-INDEX3(2:1) WS-INDEX4(2:1)
INTO WS-NUMBER(WS-COUNT1)
END-STRING
END-IF
END-PERFORM
END-PERFORM
END-PERFORM
END-PERFORM.
PERFORM UNTIL 1 < 0
IF WS-COUNT1 IS EQUAL TO 0 THEN
DISPLAY "Something is wrong."
EXIT PERFORM
END-IF
MOVE WS-NUMBER(1) TO WS-ANSWER
DISPLAY "My answer is " WS-ANSWER
DISPLAY "The a value is: " WITH NO ADVANCING
ACCEPT WS-AVALUE
DISPLAY "The b value is: " WITH NO ADVANCING
ACCEPT WS-BVALUE
IF WS-AVALUE = 4 AND WS-BVALUE = 0 THEN
DISPLAY "Game is completed."
EXIT PERFORM
END-IF
MOVE 0000 TO WS-COUNT2
PERFORM VARYING WS-LOOP1 FROM 1 BY 1 UNTIL WS-LOOP1
IS GREATER THAN WS-COUNT1
MOVE 0000 TO WS-NEW-NUMBER(WS-LOOP1)
END-PERFORM
PERFORM VARYING WS-LOOP1 FROM 1 BY 1 UNTIL WS-LOOP1
IS GREATER THAN WS-COUNT1
MOVE WS-NUMBER(WS-LOOP1) TO WS-GUESS
MOVE 0 TO WS-AGUESS
MOVE 0 TO WS-BGUESS
CALL 'GETA' USING BY CONTENT WS-ANSWER, WS-GUESS,
BY REFERENCE WS-AGUESS
CALL 'GETB' USING BY CONTENT WS-ANSWER, WS-GUESS,
BY REFERENCE WS-BGUESS
IF WS-AVALUE = WS-AGUESS AND WS-BVALUE = WS-BGUESS THEN
ADD 1 TO WS-COUNT2
MOVE WS-GUESS TO WS-NEW-NUMBER(WS-COUNT2)
END-IF
END-PERFORM
MOVE WS-COUNT2 TO WS-COUNT1
PERFORM VARYING WS-LOOP1 FROM 1 BY 1 UNTIL WS-LOOP1
IS GREATER THAN WS-COUNT2
MOVE WS-NEW-NUMBER(WS-LOOP1) TO WS-NUMBER(WS-LOOP1)
END-PERFORM
DISPLAY " "
END-PERFORM.
STOP RUN.
參考資料
- COBOL - Wikipedia
- COBOL Programming Course
- COBOLworx
- GCC COBOL Front-end
- GnuCOBOL
- GnuCOBOL Guides
- COBOL Tutorial
- Coding Cobol: A basic “Hello World”
- Coding Cobol: A picture is worth 1000 words
- Coding Cobol: functions (external)
- Coding Cobol: Tricks with arrays (or tables)
- Coding Cobol: Variable length arrays
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。