编码 · 编程语言
COBOL 入门教程
简短回答
COBOL(Common Business-Oriented Language,通用商业导向语言)是为商业数据处理而设计的编译型语言:记录、文件、报表和精确的十进制运算。程序分为四大部(division),数据用 PIC(picture)子句描述,代码读起来像英文句子,例如 ADD AMOUNT TO TOTAL。它至今仍在银行、保险公司和政府的核心系统中运行,大多在 IBM 大型机上。你可以用 GnuCOBOL 编译器免费学习:cobc -x hello.cob。
COBOL 是什么,谁在用
COBOL 由 CODASYL 委员会于 1959 年设计,深受 Grace Hopper 早期语言 FLOW-MATIC 的影响。它由 ISO 标准化;后来的标准加入了结构化编程、面向对象等特性,最近一次修订发布于 2023 年。
COBOL 用于批处理和事务系统:账户处理、薪资、保险理赔、税务和福利系统。这些代码很多运行在 IBM Z 大型机上,使用 IBM Enterprise COBOL,配合用于事务的 CICS 和用于数据的 Db2。维护和现代化这些系统的工作岗位依然常见。
安装 GnuCOBOL 并运行 Hello, world
GnuCOBOL 是一个免费的编译器,先把 COBOL 翻译成 C,再编译成原生程序。许多 Linux 发行版里有名为 gnucobol 的软件包,macOS 上可以用 Homebrew;Windows 用户可以使用 WSL 或预构建的软件包。
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
PROCEDURE DIVISION.
DISPLAY "Hello, world!".
STOP RUN.cobc -x hello.cob
./hello
# Hello, world!这段代码使用传统的固定格式:第 1 到 6 列用于序号,第 7 列标记注释(*)或续行,A 区(第 8 到 11 列)放部、节和段落的名字,B 区(第 12 到 72 列)放语句。GnuCOBOL 也接受自由格式的源码,用 cobc -x -free。选项 -x 构建可执行文件,而不是模块。
四大部
| 部 | 用途 |
|---|---|
| IDENTIFICATION DIVISION | 为程序命名(PROGRAM-ID) |
| ENVIRONMENT DIVISION | 把程序与外部世界相连,例如使用哪些文件 |
| DATA DIVISION | 声明所有数据:文件记录、工作存储区、参数 |
| PROCEDURE DIVISION | 可执行语句,组织成段落 |
每个变量在使用前都必须在 DATA DIVISION 中声明。WORKING-STORAGE SECTION 存放程序的变量,FILE SECTION 描述文件记录,LINKAGE SECTION 描述调用者传入的参数。
数据与 PIC 子句
COBOL 按精确的布局来描述数据。层级号表示层次结构(01 是记录,05 是其中的字段),PIC 子句给出格式:X 是任意字符,9 是数字,S 是符号,V 是隐含的小数点。
| 声明 | 含义 | 示例值 |
|---|---|---|
PIC X(10) | 10 个字符,用空格填充 | "Ana " |
PIC 9(3) | 无符号 3 位数字 | 030 |
PIC S9(5)V99 | 带符号,小数点前 5 位、后 2 位 | -01234.50 |
PIC $ZZ,ZZ9.99 | 编辑后的输出:货币符号,前导零显示为空格 | $ 1,234.50 |
PIC S9(7)V99 COMP-3 | 压缩十进制,大型机上很常见 | 占 5 个字节 |
88 IS-DONE VALUE "Y" | 条件名:对其父字段的布尔测试 | 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数字以十进制存储,所以 0.10 + 0.20 恰好等于 0.30,这是 COBOL 适合处理金额的原因之一。WS-CUSTOMER 是组项:可以整体移动,也可以逐个字段移动。
控制流:IF、EVALUATE 与 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
*> bigPERFORM VARYING 是 COBOL 的计数循环,PERFORM UNTIL condition 是它的 while 循环。EVALUATE 相当于 switch 语句。END-IF、END-PERFORM 这样的作用域终止符关闭每个代码块;句点则结束整个句子。
段落、算术与表
COBOL 没有通常意义上的函数。你把逻辑组织成具名段落,用 PERFORM 执行;更大的单元成为独立的程序,用 CALL "PROG" USING ... 调用。算术使用动词(ADD、SUBTRACT、MULTIPLY、DIVIDE)或带公式的 COMPUTE。数组称为表,用 OCCURS 声明;索引从 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总和是 21.75;乘以 1.1 得 23.925,COBOL 会截断到声明的两位小数(23.92),除非你写 COMPUTE ... ROUNDED。
错误处理
日常 COBOL 代码里没有异常。取而代之的是语句上的条件短语:ON SIZE ERROR 处理算术溢出或除以零,AT END 处理文件结束,INVALID KEY 用于索引文件,还有一个 FILE STATUS 字段,在每次文件操作之后接收一个两字符的代码("00" 表示成功)。
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一个完整的小程序:销售文件汇总
从文件中读取固定布局的记录是典型的 COBOL 工作。这个程序读取 sales.txt,其中每行有一个 10 个字符的商品名,后跟一个带两位隐含小数的 7 位数字金额。
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.运行后会打印 Total sales:,后面是在 12 个字符的编辑字段中右对齐的 41.49。LINE SEQUENTIAL 表示每行一条记录的文本文件;GnuCOBOL 和其他 PC 编译器支持它,而大型机程序通常读取 JCL 中定义的定长数据集。
接下来读什么
- GnuCOBOL 项目页面及其《程序员指南》(Programmer's Guide),其中有完整的语言参考。
- IBM 的 Enterprise COBOL for z/OS 文档,介绍大型机 COBOL、CICS 和 Db2 的用法。
- 练习读写文件,用
SORT动词排序,并生成格式化报表。 - 如果想在生产系统上工作,还要学习周边的大型机工具(JCL、TSO/ISPF)。
常见问题
COBOL 现在还有人用吗?
有。许多银行、保险公司和政府机构仍在运行 COBOL 程序处理核心批处理和事务,因此对能维护和现代化这些程序的开发者一直有需求。
COBOL 难学吗?
它的语法冗长但简单,大多数初学者很快就能写出可运行的程序。更难的是它周边的大型机环境:JCL、数据集、CICS 和 Db2。
没有大型机也能学 COBOL 吗?
可以。GnuCOBOL 可在 Linux、macOS 和 Windows 上运行,支持标准 COBOL,所以你可以先在普通电脑上学习这门语言,再转向大型机。
COBOL 为什么使用十进制数?
金额之类的商业数据必须精确。COBOL 把数字存储为十进制数位,小数位数固定,从而避免了二进制浮点数的舍入误差。