cv.cm

Lập trình · Ngôn ngữ lập trình

Hướng dẫn COBOL cho người mới bắt đầu

8 phút đọc

Trả lời nhanh

COBOL (Common Business-Oriented Language) là ngôn ngữ biên dịch được thiết kế cho xử lý dữ liệu nghiệp vụ: bản ghi, tệp, báo cáo và số học thập phân chính xác. Chương trình chia thành bốn division, dữ liệu được mô tả bằng mệnh đề PIC (picture), và mã đọc giống câu tiếng Anh như ADD AMOUNT TO TOTAL. COBOL vẫn vận hành các hệ thống lõi tại ngân hàng, công ty bảo hiểm và cơ quan chính phủ, chủ yếu trên máy chủ mainframe của IBM. Bạn có thể học miễn phí với trình biên dịch GnuCOBOL: cobc -x hello.cob.

COBOL là gì và ai dùng nó

COBOL được ủy ban CODASYL thiết kế năm 1959, chịu ảnh hưởng mạnh từ ngôn ngữ FLOW-MATIC trước đó của Grace Hopper. Ngôn ngữ này được ISO chuẩn hóa; các chuẩn sau bổ sung lập trình có cấu trúc, hướng đối tượng và các tính năng khác, và bản sửa đổi mới nhất được công bố năm 2023.

COBOL được dùng cho xử lý theo lô và hệ thống giao dịch: xử lý tài khoản, bảng lương, bồi thường bảo hiểm, hệ thống thuế và phúc lợi. Phần lớn mã này chạy trên mainframe IBM Z với IBM Enterprise COBOL, cùng CICS cho giao dịch và Db2 cho dữ liệu. Các công việc bảo trì và hiện đại hóa những hệ thống này vẫn còn phổ biến.

Cài GnuCOBOL và chạy Hello, world

GnuCOBOL là trình biên dịch miễn phí, dịch COBOL sang C rồi thành chương trình gốc. Nó có sẵn dưới dạng gói gnucobol trên nhiều bản phân phối Linux và trong Homebrew trên macOS; người dùng Windows có thể dùng WSL hoặc gói dựng sẵn.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. HELLO.
       PROCEDURE DIVISION.
           DISPLAY "Hello, world!".
           STOP RUN.
cobc -x hello.cob
./hello
# Hello, world!

Mã dùng định dạng cố định truyền thống: cột 1 đến 6 dành cho số thứ tự, cột 7 đánh dấu chú thích (*) hoặc dòng nối tiếp, Area A (cột 8 đến 11) chứa tên division, section và paragraph, còn Area B (cột 12 đến 72) chứa các câu lệnh. GnuCOBOL cũng chấp nhận mã nguồn dạng tự do với cobc -x -free. Tùy chọn -x tạo tệp thực thi thay vì module.

Bốn division

DivisionMục đích
IDENTIFICATION DIVISIONĐặt tên chương trình (PROGRAM-ID)
ENVIRONMENT DIVISIONKết nối chương trình với thế giới bên ngoài, ví dụ nó dùng những tệp nào
DATA DIVISIONKhai báo toàn bộ dữ liệu: bản ghi tệp, vùng lưu trữ làm việc, tham số
PROCEDURE DIVISIONCác câu lệnh thực thi, tổ chức thành các paragraph

Mọi biến phải được khai báo trong DATA DIVISION trước khi dùng. WORKING-STORAGE SECTION chứa các biến của chương trình, FILE SECTION mô tả bản ghi tệp, và LINKAGE SECTION mô tả tham số do bên gọi truyền vào.

Dữ liệu và mệnh đề PIC

COBOL mô tả dữ liệu theo đúng bố cục của nó. Số cấp (level number) thể hiện thứ bậc (01 là một bản ghi, 05 là một trường bên trong), còn mệnh đề PIC cho biết định dạng: X là ký tự bất kỳ, 9 là chữ số, S là dấu, và V là dấu thập phân ngầm định.

Khai báoÝ nghĩaGiá trị ví dụ
PIC X(10)10 ký tự, được đệm thêm dấu cách"Ana "
PIC 9(3)Số 3 chữ số không dấu030
PIC S9(5)V99Có dấu, 5 chữ số trước và 2 chữ số sau dấu thập phân-01234.50
PIC $ZZ,ZZ9.99Đầu ra đã biên tập: ký hiệu tiền tệ, số 0 đứng đầu thành dấu cách$ 1,234.50
PIC S9(7)V99 COMP-3Thập phân đóng gói (packed decimal), phổ biến trên mainframelưu trong 5 byte
88 IS-DONE VALUE "Y"Tên điều kiện: phép kiểm tra Boolean trên trường cha của nóIF IS-DONE
       IDENTIFICATION DIVISION.
       PROGRAM-ID. DATA-DEMO.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-NAME        PIC X(10)      VALUE "Ana".
       01  WS-AGE         PIC 9(3)       VALUE 30.
       01  WS-PRICE       PIC S9(5)V99   VALUE 1234.50.
       01  WS-PRICE-OUT   PIC $ZZ,ZZ9.99.
       01  WS-CUSTOMER.
           05  WS-FIRST   PIC X(10).
           05  WS-LAST    PIC X(15).
       PROCEDURE DIVISION.
           MOVE WS-PRICE TO WS-PRICE-OUT
           DISPLAY WS-NAME "is " WS-AGE
           DISPLAY "Price: " WS-PRICE-OUT
           STOP RUN.
      *> Ana       is 030
      *> Price: $ 1,234.50

Số được lưu ở dạng thập phân, nên 0.10 + 0.20 đúng bằng 0.30, đây là một lý do COBOL phù hợp với tiền bạc. WS-CUSTOMER là một mục nhóm: có thể chuyển cả nhóm hoặc từng trường.

Luồng điều khiển: IF, EVALUATE và PERFORM

       IDENTIFICATION DIVISION.
       PROGRAM-ID. CONTROL-DEMO.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-I        PIC 99.
       01  WS-TOTAL    PIC 9(4) VALUE 0.
       01  WS-SCORE    PIC 999  VALUE 85.
       PROCEDURE DIVISION.
           PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 10
               ADD WS-I TO WS-TOTAL
           END-PERFORM
           DISPLAY "Total: " WS-TOTAL
           EVALUATE TRUE
               WHEN WS-SCORE >= 90
                   DISPLAY "A"
               WHEN WS-SCORE >= 80
                   DISPLAY "B"
               WHEN OTHER
                   DISPLAY "C"
           END-EVALUATE
           IF WS-TOTAL > 50
               DISPLAY "big"
           ELSE
               DISPLAY "small"
           END-IF
           STOP RUN.
      *> Total: 0055
      *> B
      *> big

PERFORM VARYING là vòng lặp đếm của COBOL và PERFORM UNTIL condition là vòng lặp while. EVALUATE là câu lệnh switch. Các từ kết thúc phạm vi như END-IF và END-PERFORM đóng từng khối; dấu chấm kết thúc cả câu.

Paragraph, số học và bảng

COBOL không có hàm theo nghĩa thông thường. Bạn tổ chức logic thành các paragraph có tên và chạy chúng bằng PERFORM; các đơn vị lớn hơn trở thành chương trình riêng, được gọi bằng CALL "PROG" USING .... Số học dùng các động từ (ADD, SUBTRACT, MULTIPLY, DIVIDE) hoặc COMPUTE với một công thức. Mảng được gọi là bảng (table) và khai báo bằng OCCURS; chỉ số bắt đầu từ 1.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. PARA-DEMO.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  WS-PRICES.
           05  WS-PRICE   PIC 9(3)V99 OCCURS 3 TIMES.
       01  WS-I           PIC 9.
       01  WS-SUM         PIC 9(4)V99 VALUE 0.
       01  WS-SUM-OUT     PIC Z,ZZ9.99.
       PROCEDURE DIVISION.
       MAIN-PARA.
           MOVE 10.50 TO WS-PRICE(1)
           MOVE 4.25  TO WS-PRICE(2)
           MOVE 7.00  TO WS-PRICE(3)
           PERFORM ADD-PRICE VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 3
           COMPUTE WS-SUM = WS-SUM * 1.1
           MOVE WS-SUM TO WS-SUM-OUT
           DISPLAY "With 10% tax: " WS-SUM-OUT
           STOP RUN.
       ADD-PRICE.
           ADD WS-PRICE(WS-I) TO WS-SUM.
      *> With 10% tax:    23.92

Tổng là 21.75; nhân với 1.1 được 23.925, và COBOL cắt bớt về hai chữ số thập phân đã khai báo (23.92) trừ khi bạn viết COMPUTE ... ROUNDED.

Xử lý lỗi

Trong mã thông thường, COBOL không có ngoại lệ. Thay vào đó, các câu lệnh có mệnh đề điều kiện: ON SIZE ERROR cho tràn số hoặc chia cho không, AT END cho hết tệp, INVALID KEY cho tệp có chỉ mục, và trường FILE STATUS nhận mã hai ký tự sau mỗi thao tác tệp ("00" nghĩa là thành công).

           DIVIDE WS-A BY WS-B GIVING WS-C
               ON SIZE ERROR
                   DISPLAY "Division failed"
               NOT ON SIZE ERROR
                   DISPLAY "Result: " WS-C
           END-DIVIDE

Một chương trình hoàn chỉnh nhỏ: tổng của tệp doanh số

Đọc các bản ghi có bố cục cố định từ tệp là công việc điển hình của COBOL. Chương trình này đọc sales.txt, trong đó mỗi dòng có tên mặt hàng 10 ký tự theo sau là số tiền 7 chữ số với hai chữ số thập phân ngầm định.

apples    0001250
pears     0000899
plums     0002000
       IDENTIFICATION DIVISION.
       PROGRAM-ID. SALES-TOTAL.
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT SALES-FILE ASSIGN TO "sales.txt"
               ORGANIZATION IS LINE SEQUENTIAL
               FILE STATUS IS WS-FS.
       DATA DIVISION.
       FILE SECTION.
       FD  SALES-FILE.
       01  SALES-REC.
           05  SR-ITEM     PIC X(10).
           05  SR-AMOUNT   PIC 9(5)V99.
       WORKING-STORAGE SECTION.
       01  WS-FS           PIC XX.
       01  WS-EOF          PIC X VALUE "N".
           88  NO-MORE-RECORDS       VALUE "Y".
       01  WS-TOTAL        PIC 9(7)V99 VALUE 0.
       01  WS-TOTAL-OUT    PIC Z,ZZZ,ZZ9.99.
       PROCEDURE DIVISION.
           OPEN INPUT SALES-FILE
           IF WS-FS NOT = "00"
               DISPLAY "Cannot open file, status " WS-FS
               STOP RUN
           END-IF
           PERFORM UNTIL NO-MORE-RECORDS
               READ SALES-FILE
                   AT END SET NO-MORE-RECORDS TO TRUE
                   NOT AT END ADD SR-AMOUNT TO WS-TOTAL
               END-READ
           END-PERFORM
           CLOSE SALES-FILE
           MOVE WS-TOTAL TO WS-TOTAL-OUT
           DISPLAY "Total sales: " WS-TOTAL-OUT
           STOP RUN.

Khi chạy, chương trình in Total sales: theo sau là 41.49 căn phải trong trường đã biên tập rộng 12 ký tự. LINE SEQUENTIAL nghĩa là tệp văn bản mỗi dòng một bản ghi; GnuCOBOL và các trình biên dịch PC khác hỗ trợ kiểu này, còn chương trình mainframe thường đọc các dataset độ dài cố định được định nghĩa trong JCL.

Học tiếp ở đâu

  • Các trang dự án GnuCOBOL và Programmer's Guide của nó để có tài liệu tham khảo ngôn ngữ đầy đủ.
  • Tài liệu IBM Enterprise COBOL for z/OS về COBOL trên mainframe, cách dùng CICS và Db2.
  • Luyện đọc và ghi tệp, sắp xếp bằng động từ SORT, và tạo báo cáo có định dạng.
  • Học các công cụ mainframe xung quanh (JCL, TSO/ISPF) nếu bạn muốn làm việc với hệ thống sản xuất.

Câu hỏi thường gặp

COBOL còn được dùng không?

Có. Nhiều ngân hàng, công ty bảo hiểm và cơ quan chính phủ vẫn chạy các chương trình COBOL cho xử lý lô và giao dịch cốt lõi, nên nhu cầu về lập trình viên có thể bảo trì và hiện đại hóa chúng vẫn tiếp diễn.

COBOL có khó học không?

Cú pháp dài dòng nhưng đơn giản, và hầu hết người mới có thể nhanh chóng viết được chương trình chạy được. Phần khó hơn là môi trường mainframe xung quanh: JCL, dataset, CICS và Db2.

Tôi có thể học COBOL mà không cần mainframe không?

Được. GnuCOBOL chạy trên Linux, macOS và Windows và hỗ trợ COBOL chuẩn, nên bạn có thể học ngôn ngữ trên máy tính thông thường trước khi chuyển sang mainframe.

Vì sao COBOL dùng số thập phân?

Dữ liệu nghiệp vụ như tiền bạc phải chính xác. COBOL lưu số dưới dạng chữ số thập phân với số chữ số thập phân cố định, tránh được sai số làm tròn của dấu phẩy động nhị phân.

Tất cả hướng dẫn lập trình