COBOL 程序的基础知识概述
1.COBOL 是什么,怎么来的
COBOL(Common Business-Oriented Language)中文可以理解为“面向商业的通用语言”。它是在 1959 年由美国国防部牵头搞出来的,目标很明确:做一种适合商业数据处理的编程语言。它希望做到跨平台、可读性强,并且能把业务逻辑表达得比较清楚。20 世纪 60 到 80 年代,它在银行、保险、政府和大企业系统里用得非常多,直到现在很多老系统里还在跑 COBOL。
2.COBOL 的语言特点
COBOL 有几个很鲜明的特点:
像自然语言:关键字都是英文单词,比如 READ、WRITE、IF、PERFORM,非程序员也能大致看懂。
面向数据处理:核心是文件操作,支持复杂的数据结构定义和记录处理。
可移植:不绑定硬件,能在 IBM z/OS、UNIX、Windows 等多种系统上跑。
强类型、格式严格:变量必须明确指定类型和长度,程序结构也有固定格式。
3.基本程序结构组成
程序由 4 个部组成的。这 4 个部依次为标志部、环境部、数据部以及过程部。部与部之间的先后顺序不可更改。
标志部:说明程序名称、作者、版本等元信息。
环境部:说明程序跟外部环境的关系,比如文件和计算机的对应关系。
数据部:定义程序里用到的所有数据。
过程部:写程序逻辑,是程序的主体。
3.1 标志部
关键字
- IDENTIFICATION DIVISION:标识程序名称、作者、版本等元信息。
标志部中主要包含以下字段:PROGRAM-ID、AUTHOR、INSTALLATION、DATE-WRITTEN、DATE-COMPILED、SECURITY。
- PROGRAM-ID:用于指明程序名,是必须具备的字段。其他字段则都是可选的。
- AUTHOR:开发程序的程序员名
3.2 环境部
环境部主要用于指定该程序同外部系统环境之间的各种对应关系,在标志部之后。如果没有任何内容,可以省略不写。
关键字
- ENVIRONMENT DIVISION
环境部包含有两个节为配置节和输入/输出节。
3.2.1 配置节
主要用于指定程序同外部环境之间的一些配置信息。
关键字
- ENVIRONMENT DIVISION
字段
SOURCE-COMPUTER:编译程序的计算机。OBJECT-COMPUTER:运行程序的计算机。SPECIAL-NAMES:指定货币符号、选择小数点、提供开关名和定义字母表。
3.2.2 输入/输出节
在 COBOL 程序中,数据主要保存在文件中。数据的输入和输出通常是以文件为对象进行的。因此,输入/输出节主要用于指定程序中所用到文件同外部环境之间的对应关系。
关键字
- INPUT-OUTPUT SECTION
字段
FILE-CONTROL:指定文件的对应关系,是该节中主要用到的字段。I-O-CONTROL:定义程序返回点、不同文件共享的内存区,以及多文件卷中文件的位置。
3.3 数据部
数据部在环境部之后。COBOL 程序中所用到的各项数据都统一在数据部中定义,因此数据部十分重要。数据部中常用的有 3 个节,分别为文件节、工作存储节以及连接节。
关键字
- DATA DIVISION
3.3.1 文件节
对程序中用到的文件里的数据进行定义。文件是指程序中的逻辑文件。其文件名必须和环境部输入/输出节中由SELECT语句指定的文件名一致。
关键字
- FILE-SECTION
在文件节中,主要是通过FD语句实现对文件的定义。在FD语句下,通过PIC语句依次定义文件中每条记录所包含的数据项。任何在程序中所使用到的文件都需要在此处定义。FD是 “File Descriptor” 的缩写,文件描述符的意思。
以下两点需要注意:
FD语句主要用来描述与文件记录相关的物理信息,如记录实际的格式、长度等。FD语句通过句点表示结束。
定义的数据实际上主要分为两大类型。其中一类为数据组,另一类为单元数据项。
数据组是由多个单元数据项或数据分组所组成的。FD语句下所有的数据组和数据项组成了该文件的一条记录。
在文件节中各条FD语句下所定义的数据组和数据项是对相应文件记录逻辑上的一个划分。
在COBOL中,01层属于最高层,需要在程序中顶格写。
各层层号必须按顺序书写,但不一定连续。在COBOL中,最多支持49层,因此49层为最低层。除01层外,还存在几个比较特殊的层如下。
66层:为特殊描述符项目保留,在实际中用得较少。
77层:用于某个组的数据项,如程序中的临时变量。
88层:用于条件判断中。
区分数据组和单元数据项的方式是看该数据后是否有PIC语句。没有PIC语句的为数据组,有PIC语句的则为单元数据项。
PIC实际上是PICTURE的缩写。PIC语句用来定义数据的类型及长度。需注意其中“X”和“9”的区别。“X”表示任意字符,“9”则表示只能为数字。二者后面括号中的数值则表示相应数据的长度。数据长度也可直接通过连续书写“X”或“9”表示。
例如
01TEST-DATAPICX(20).01TEST-DATAPICXXX.....01TEST-DATAPIC9(7).01TEST-DATAPIC999.3.3.2工作存储节
工作存储节主要用于定义本程序中所需用到的各种数据。其中数据的定义方式同在文件节中的类似,不过此处定义的数据与文件是没有直接关系的。
工作存储节应该写在文件节之后。如果程序中没有用到外部文件,文件节是可以省略的。但工作存储节则通常都是会存在的。因为程序中一般会要用到本地数据的。
关键字
- WORKING-STORAGE SECTION
工作存储节中的数据,也是需要使用PIC语句定义其类型和长度的。此外,在使用PIC语句对数据定义的同时,也可以使用VALUE从句对其赋初值。并且,对于FILLER描述的数据项,通常是必须使用VALUE从语对其赋初值。例如,以下代码便将字符“ABC”赋予了 TEST-CHAR,将数字123赋予了TEST-NUM,将空格赋予了 FILLER所描述的数据项。
01TEST-CHARPICX(3)VALUE'ABC'.01TEST-NUMPIC9(3)VALUE123.01FILLERPICX(5)VALUESPACES.3.4 过程部
过程部是COBOL程序中的最后一个部。COBOL程序的所有逻辑处理部分都是在过程部中编写的。过程部是程序的主体部分,程序的处理都是在过程部中实现的。
关键字
- PROCEDUREDIVISION
过程部中的程序代码是由COBOL语句所组成的。同时,可以将实现某一特定功能的多条语句定义为一个语句段。语句段在COBOL中类似于函数的概念,可以直接通过语句段名对其进行调用。语句段名需要在程序中顶格写。
关于过程部中的语句,有一点需要特别注意,就是语句之后的句点“.”。通常情况下,语句之后有无句点并无太大影响,但对于以下两种情况需要特别注意。
(1)语句段名之后必须有句点。
(2)句点能够起到界点同一条件下处理范围的作用。这一点同后面要讲到的END-IF或者END-PERFORM等标识符功能类似,并可用句点将其替换。
需要注意的是,COBOL中的语句是可以换行书写的。但换行书写时,语句中所包含的单个选项或者变量名在每行内需要书写完整,不能将其拆分成两行。
当程序逻辑代码完全结束后,通常使用“STOPRUN”语句表明程序的结束。
在子程序中,也可使用“GOBACK”语句或“EXIT PROGRAM”语句表示程序的结束。
过程部常用语句包括:
OPEN:打开文件
READ:读取记录
MOVE:数据传送
PERFORM:调用段
IF-ELSE:条件判断
WRITE:输出记录
CLOSE:关闭文件
下面基于前文在文件节中定义的CUSTOMER-FILE和PRINT-FILE,以及工作存储节中定义的WS-CUST-NAME、WS-TOTAL-AMOUNT、WS-COUNT,给出一个完整的过程部示例。该示例从客户文件中逐条读取记录,将客户姓名与金额汇总后写入打印文件,并统计处理记录条数:
PROCEDUREDIVISION.MAIN-PROCESS.OPENINPUTCUSTOMER-FILE*>以输入方式打开客户文件OUTPUTPRINT-FILE*>以输出方式打开打印文件MOVE0TOWS-COUNT*>计数器WS-COUNT清零PERFORMREAD-PROCESS*>调用READ-PROCESS段读取并处理记录PERFORMUNTILWS-EOF='Y'*>循环执行,直到文件结束标志为'Y'PERFORMREAD-PROCESS*>再次调用读取处理段END-PERFORM*>循环结束PERFORMPRINT-SUMMARY*>调用打印汇总段CLOSECUSTOMER-FILE*>关闭客户文件PRINT-FILE*>关闭打印文件STOPRUN.*>结束程序运行READ-PROCESS.READCUSTOMER-FILE*>从客户文件读取一条记录ATEND*>若已读到文件末尾MOVE'Y'TOWS-EOF*>设置文件结束标志为'Y'NOTATEND*>若成功读取到记录MOVECLIENT-NAMETOWS-CUST-NAME*>将客户姓名传送到工作存储项ADDPRI-FINANCETOWS-TOTAL-AMOUNT*>累加金额到汇总项ADD1TOWS-COUNT*>计数器加1PERFORMWRITE-LINE*>调用输出段打印该行END-READ.*>READ语句结束WRITE-LINE.MOVEWS-CUST-NAMETOPRINT-LINE(1:20)*>将姓名放入打印行前20位MOVEWS-TOTAL-AMOUNTTOPRINT-LINE(21:9)*>将金额放入打印行后续位置WRITEPRINT-LINE*>将打印行写入打印文件MOVESPACESTOPRINT-LINE.*>清空打印行,准备下一行PRINT-SUMMARY.MOVE'TOTAL RECORDS:'TOPRINT-LINE(1:15)*>写入汇总标题MOVEWS-COUNTTOPRINT-LINE(16:4)*>写入总记录数WRITEPRINT-LINE.*>输出汇总行在上面的示例中,OPEN语句同时打开了输入文件CUSTOMER-FILE和输出文件PRINT-FILE;READ语句配合AT END/NOT AT END判断是否读到文件末尾;MOVE语句用于在文件记录、工作存储项与打印行之间传送数据;ADD语句完成金额累加与计数;PERFORM语句反复调用READ-PROCESS段,直到文件结束;IF-ELSE结构则体现在AT END/NOT AT END的条件分支中;WRITE语句将处理结果输出到打印文件;最后用CLOSE关闭所有文件,并以STOP RUN结束程序。
需要说明的是,示例中PRINT-LINE(1:20)这种带下标范围的写法用于对打印行的指定位置进行赋值,属于 COBOL 中较为常用的字符串定位技巧。通过过程部,前面在数据部中定义的各种数据项真正被“用”了起来,这也正是 COBOL 程序“先定义、后使用”这一设计思想的体现。
总结:
COBOL 程序的基础知识主要内容可概括为以下几点:
- 语法格式:COBOL 每行代码分为 80 列,其中第 7 列为指示符区,写入
*表示注释行;第 8~11 列为 A 区,用于书写部、节、段标识符及 01 层号;第 12~72 列为 B 区,用于书写过程部语句;第 73~80 列为说明区。
下面给出一个完整的 COBOL 程序示例,用于直观展示第 7 列注释符、A 区/B 区书写规范以及数据名称的命名规则。示例中每一行都标注了其内容所对应的列位置:
000100IDENTIFICATIONDIVISION.*>第8~11列(A区):部标识符000200PROGRAM-ID.SAMPLE-PGM.*>第8~11列(A区):PROGRAM-ID顶格书写000300AUTHOR.XXX.*>第8~11列(A区):AUTHOR顶格书写000400ENVIRONMENTDIVISION.*>第8~11列(A区):部标识符000500INPUT-OUTPUTSECTION.*>第8~11列(A区):节标识符000600FILE-CONTROL.*>第8~11列(A区):节内段名顶格书写000700SELECTCUSTOMER-FILEASSIGNTOS-SYSIN.*>第12~72列(B区):SELECT语句000800SELECTPRINT-FILEASSIGNTOS-SYSOUT.*>第12~72列(B区):SELECT语句000900DATADIVISION.*>第8~11列(A区):部标识符001000FILESECTION.*>第8~11列(A区):节标识符001100FDCUSTOMER-FILE*>第8~11列(A区):FD语句顶格书写001200RECORDINGMODEISF.*>第12~72列(B区):FD从句00130001CUST-RECORD.*>第8~11列(A区):01层号顶格书写00140005ACCOUNT-NOPIC9(10).*>第12~72列(B区):数据项定义00150005CLIENT-NAMEPICX(20).*>第12~72列(B区):数据项定义00160005PRI-FINANCEPIC9(7).*>第12~72列(B区):数据项定义001700FDPRINT-FILE*>第8~11列(A区):FD语句顶格书写001800RECORDINGMODEISF*>第12~72列(B区):FD从句001900LABELRECORDSAREOMITTED*>第12~72列(B区):FD从句002000RECORDCONTAINS132CHARACTERS*>第12~72列(B区):FD从句002100DATARECORDISPRINT-LINE.*>第12~72列(B区):FD从句00220001PRINT-LINEPICX(132).*>第8~11列(A区):01层号顶格书写002300WORKING-STORAGESECTION.*>第8~11列(A区):节标识符00240001WS-CUST-NAMEPICX(20).*>第8~11列(A区):01层号顶格书写00250001WS-TOTAL-AMOUNTPIC9(7).*>第8~11列(A区):01层号顶格书写00260001WS-COUNTPIC9(4).*>第8~11列(A区):01层号顶格书写00270001WS-EOFPICX(1)VALUE'N'.*>第8~11列(A区):01层号顶格书写002800PROCEDUREDIVISION.*>第8~11列(A区):部标识符002900MAIN-PROCESS.*>第8~11列(A区):段名顶格书写003000OPENINPUTCUSTOMER-FILE*>第12~72列(B区):过程部语句003100OUTPUTPRINT-FILE*>第12~72列(B区):过程部语句003200MOVE0TOWS-COUNT*>第12~72列(B区):过程部语句003300PERFORMUNTILWS-EOF='Y'*>第12~72列(B区):过程部语句003400READCUSTOMER-FILE*>第12~72列(B区):过程部语句003500ATEND*>第12~72列(B区):过程部语句003600MOVE'Y'TOWS-EOF*>第12~72列(B区):过程部语句003700NOTATEND*>第12~72列(B区):过程部语句003800MOVECLIENT-NAMETOWS-CUST-NAME*>第12~72列(B区):过程部语句003900ADDPRI-FINANCETOWS-TOTAL-AMOUNT*>第12~72列(B区):过程部语句004000ADD1TOWS-COUNT*>第12~72列(B区):过程部语句004100MOVEWS-CUST-NAMETOPRINT-LINE(1:20)*>第12~72列(B区):过程部语句004200MOVEWS-TOTAL-AMOUNTTOPRINT-LINE(21:9)*>第12~72列(B区):过程部语句004300WRITEPRINT-LINE*>第12~72列(B区):过程部语句004400END-READ*>第12~72列(B区):过程部语句004500END-PERFORM*>第12~72列(B区):过程部语句004600MOVE'TOTAL RECORDS:'TOPRINT-LINE(1:15)*>第12~72列(B区):过程部语句004700MOVEWS-COUNTTOPRINT-LINE(16:4)*>第12~72列(B区):过程部语句004800WRITEPRINT-LINE*>第12~72列(B区):过程部语句004900CLOSECUSTOMER-FILE*>第12~72列(B区):过程部语句005000PRINT-FILE*>第12~72列(B区):过程部语句005100STOPRUN.*>第12~72列(B区):过程部语句对上述示例中各列位置的说明如下:
- 第 1~6 列(序号区):示例中每行开头的
000100、000200等即为序号,用于标识行号,通常不作要求,可留空。 - 第 7 列(指示符区):示例中每行末尾的
*>即注释符,表示该位置之后的内容为注释。若将*写在行首第 7 列,则整行成为注释行。 - 第 8~11 列(A 区):部标识符(如
IDENTIFICATION DIVISION)、节标识符(如WORKING-STORAGE SECTION)、段名(如MAIN-PROCESS)以及01层号均从 A 区开始顶格书写。 - 第 12~72 列(B 区):过程部中的各条语句(如
MOVE、DISPLAY、STOP RUN)书写在 B 区,即从第 12 列开始缩进书写。 - 第 73~80 列(说明区):用于书写注释,示例中
*>之后的内容即属于说明区。
同时,示例中的数据名称也遵循了命名规则:WS-CUST-NAME、WS-TOTAL-AMOUNT均由字母、数字和中划线组成,中划线位于名称中间而非开头或结尾,且未与MOVE、DISPLAY、STOP等程序关键字重名。
数据名称由字母、数字和中划线组成,中划线不可位于开头或结尾,且不能与程序关键字重名。
- 四部结构:一个完整的 COBOL 程序由标志部、环境部、数据部、过程部 4 个部依次组成,顺序不可更改。标志部通过
IDENTIFICATION DIVISION标识,其中PROGRAM-ID为必填字段;环境部通过ENVIRONMENT DIVISION标识,用于建立逻辑文件与物理文件的对应关系。 - 文件节:由
FILE-SECTION标识,通过FD语句定义与外部文件相关联的记录结构,数据来源于外部文件,数据项不能指定初始值,适用于读写外部文件的场景。 - 工作存储节:由
WORKING-STORAGE SECTION标识,通过01层号直接定义程序内部的临时数据项,可通过VALUE从句指定初始值,适用于存放中间计算结果、计数器、标志位等临时数据。 - 过程部核心语句:过程部由
PROCEDURE DIVISION标识,是程序的核心。常用语句包括OPEN(打开文件)、READ(读取记录)、MOVE(数据传送)、PERFORM(调用段)、IF-ELSE(条件判断)、WRITE(输出记录)以及CLOSE(关闭文件),配合AT END/NOT AT END可完成对文件记录的处理与汇总。