发布于:2021-01-21 15:29:19
0
192
0
从前,当世界和计算机都是新事物的时候,我正在攻读数据处理的副学士学位,那时没有“计算机科学”课程,我必须学习会计学、数学、统计学和三种计算机语言:IBM/360基本汇编语言、FORTRAN和COBOL。到了80年代,学生们被告知COBOL是一种死语言,没有人再学习它了。
现在,到了2020年,政府和银行都在恳求COBOL程序员,一种不会消亡的语言。
那么,你如何学习COBOL,赚大钱,并节省大量的国家机构需要新的代码来处理所有新的政府刺激计划?
COBOL公司?这是什么东西?
COBOL代表面向业务的通用语言。作为最早的高级语言之一,它是由国防部赞助的一个小组组织起来开发的一种通用商务语言。这个小组后来被称为数据系统语言委员会CODASYL,并从Grace Hopper的FLOW-MATIC以及Univac的AIMACO和IBM的COMTRAN等其他语言中定义了一种“面向业务的通用语言”。由此产生的语言经历了更多的修改,但很快就成为构建业务系统的主导语言,并且从那时起它一直处于主导地位。
许多公司仍在使用COBOL,包括IBM、UPS和Cigna。Cigna的软件工程师Mario Ceballos告诉我,“语法保持简单,让非程序员(业务)能够阅读和理解它。COBOL应该是明确的,因为不应该有任何假设的空间。”
当然,它也受到了批评。1975年,Edsgar Dijkstra著名地宣称“使用COBOL会削弱大脑;因此,其教学应被视为刑事犯罪[sic]”。这无疑导致了大学中COBOL教学的衰落,但COBOL仍然是占主导地位的商业语言。
但是找到有COBOL技能的人可能很困难。Ceballos说:“大型机是一个很难学习的平台,这是由于成本问题。”。“个人没有钱租赁主机。极少数学校在大型机和COBOL上教授课程。当IBM开始远程工作和外包时,他们就不再鼓励美国学校教授大型机和COBOL课程。人才库从岸上转移到了离岸。任何本地人才的咨询费都会很贵。”
为什么COBOL仍然占主导地位?
与当今常见的编程语言相比,COBOL是不同的,而且在某些方面非常有限:您不能进行动态内存分配,不能轻松访问操作系统或特定计算机体系结构的低级功能。最常见的语言形式不能使用递归。你永远不会想用COBOL编写编译器。一个计算机科学专业的学生如果被出示COBOL,一定会大吃一惊。
这是类别错误。在现代术语中,COBOL实际上是一种特定于领域的语言,特定于业务编程的特定领域。Robert Glass确定了COBOL比通用语言更适合业务编程的具体方式,其中包括:
面向业务的语言需要声明、管理和操作异构数据。业务程序在复杂的记录结构中混合了固定长度和可变长度的字符串、浮点、整数和十进制数据,通常包含可变部分。数据库程序员熟悉其中的一些问题,对象-关系映射工具经常会忽略这些复杂性。
业务和财务数据需要使用真正的十进制数据类型进行管理。会计系统必须精确到最后一位小数,并且需要精确地再现手工计算的结果;传统的浮点数会导致复杂性和错误。
面向业务的语言需要访问和操作外部维护的大量记录结构化数据。
当然,这一切都超出了通用编程语言的能力。但在COBOL中,它是该语言的原生语言。
我们可以对COBOL的必要性进行辩论,但事实是,存在着数千亿行COBOL代码,而且从COBOL迁移出去的尝试通常并不成功。
你的第一个COBOL程序
源文件是简单的文本文件。对于COBOL来说,拥有一个支持语言的有用的编程编辑器和任何其他语言一样方便,如果不是更方便的话。对于初学者来说,最简单的事情就是使用visualstudio代码,这是自EMACS以来我所喜爱的唯一竞争对手。
COBOL的VSCode扩展多得惊人。现在,我正在使用bitlang代码着色器和Broadcom COBOL语言支持。其他的很多都是为在大型机环境中编程的人准备的,但这增加了我们不需要介绍的复杂性。
因此,总结一下,开始试验COBOL:
如果尚未安装Visual Studio代码,请下载并安装。
安装比特语言.cobol和Broadcom COBOL语言支持扩展。
安装GnuCOBOL。(老实说,如果有什么事情会引起麻烦,那就是这个。MacOS上的自制安装运行得很好,我没有其他系统可以测试。在Windows上,MicroFocus免费试用visualstudio COBOL和Azure实验支持。)
现在,您已经安装了所有内容,并准备编写第一个COBOL程序。按照传统,我们将从你的节目“Hello, World”开始
因此,作为一个新的COBOL程序员,这里是您的第一个惊喜:COBOL关心您的代码在哪个列中。在传统的COBOL程序中,源代码有几个组件:
列1-6表示序列号。第7列称为指示符区域;一般来说,它主要用于通过在该列中添加星号“*”来表示注释。然后代码进入第8列到第72列,第73列到第80列基本上是免费的,供程序员使用。
这一切都是基于当我们把我们的来源到80列霍勒瑞斯卡的日子。
现代COBOL编译器也接受一种免费的格式,这种格式不会强迫您的代码进入80列的限制中,但是现有代码中很大一部分仍然是卡片图像格式。现在,我们将继续使用卡片图像。
振作起来:COBOL并不像你曾经使用过的任何其他语言那样是块结构语言。COBOL从一开始的一个主要设计目标是,它应该是“自文档化”的,具有类似英语的语法。我们没有函数、子例程和块,而是有划分、节、段落和语句。(我们将看到类似下面带有PERFORM
动词的子例程。)。
哦,对了,我们还有COBOL操作符的动词。
以下是COBOL中的“Hello, World”:
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
PROCEDURE DIVISION.
DISPLAY "Hello, world".
END PROGRAM HELLO.
与某些语言相比,它有点冗长,但老实说也不算太糟。将其与简单的Java版本进行比较:
public class Hello {
public static void main(String[] args){
System.out.println("Hello, world!");
}
}
像所有的“Hello,world”程序一样,它的作用不大,但是如果你被告知用COBOL编写一个basic程序需要90行代码,那么,你就被误导了。
现在让我们把“Hello world”程序分解为第一个示例。
第一行是:
IDENTIFICATION DIVISION.
COBOL程序总是至少有一个标识划分和一个过程划分。识别部门有一个重要的段落,即PROGRAM-ID
。你需要在这里给程序起个名字。名称不需要与文件名或几乎任何东西对应,除非从另一个COBOL程序调用您的COBOL程序。这是通过CALL
动词实现的,我们将不讨论。
我们需要一个程序ID,所以我们添加
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
还有很多其他的事情,通常会进入鉴定部门。我将添加几个常见的示例。
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
AUTHOR. CHARLES R MARTIN.
DATE-WRITTEN. 2020-APR-11.
然而,在现代环境中,这些都是评论。
说到现代环境,顺便说一下,COBOL并不像我一直使用的那样需要所有的cap。GnuCOBOL会非常乐意。
identification division.
program-id. tut2.
author. charlie martin.
procedure division.
display "hello, world".
end program tut2.
我只是有点迷茫的怀旧。
别妄下判断我。所以呢让我们结束我们的“你好,世界”。COBOL程序的执行部分在过程部分中。
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
PROCEDURE DIVISION.
DISPLAY "Hello, world".
END PROGRAM HELLO.
这里还有一种卡片图像格式。注意,`DISPLAY“Hello,world”`缩进了四列。这是因为第8-72栏的部分实际上有两部分:第8-11栏的A部分和第12栏的B部分。分部、节和段落需要从A节开始;代码语句应该从B节开始。
扩展COBOL示例
当然,“Hello,World”并不能为任何语言提供一个很好的描述,所以让我们用一些至少类似于真实商业程序的东西来深入研究COBOL。我们将使用一个非常常见的例子:计算小时工的工资,包括计算联邦、州和FICA税。
做了这件事,我可以告诉你这不是一件容易的事,事实上,税率表是复杂和神秘的,所以我们要简化,使联邦税率为16.4%,州税率为7%,并将FICA税率固定在6.2%,同时仔细选择我们的工资率和工作时间,以不达到FICA的上限。我们只做小时工,我们计算超过40小时的加班时间是基准费率的1.5倍。
重复身份划分毫无意义。我们从一个新的部门开始,环境部门,它的存在是为了收集COBOL程序和外部世界之间的接口。
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT TIMECARDS
ASSIGN TO "TIMECARDS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
再一次,我们将练习COBOL的一些方面,这将使那些没有在面向记录的数据处理领域工作过的人感到惊讶。在UNIX、Linux、MacOS或Windows中,记录是一行文本,后跟一些行尾字符。这给传统的COBOL带来了一个问题,但是COBOL编译器实现了一个非标准的扩展来处理这个问题:ORGANIZATION IS LINE SEQUENTIAL。
input-output部分只为文件分配一个符号名(TIMECARDS
),并将其连接到外部环境中的文件。
程序的下一部分描述我们正在处理的数据。在COBOL中,所有数据通常被假定包含在固定格式的记录中。这些记录有一个层次结构,由级别号表示:01是最高层,而细分得到更高的数字。我使用02、03等等,但这是任意的;我们使用01、05等等,因为插入卡片更容易,而不必全部重新装订。
但现在我们介绍另一个部门,数据部门。正如你可能猜到的,这是数据。我们使用了两个部分。首先是文件部分。
DATA DIVISION.
FILE SECTION.
FD TIMECARDS.
01 TIMECARD.
02 EMPLOYEE-NAME.
03 EMP-FIRSTNAME PIC X(10).
03 EMP-SURNAME PIC X(15).
02 HOURS-WORKED PIC 99V9.
02 PAY-RATE PIC 99.
这是我们的输入,是固定格式;我们用FD
行将它连接到TIMECARDS
文件。接下来是工作存储部分。如果您不习惯COBOL,这看起来有点陌生,但实际上,我只是声明了稍后将在程序中使用的变量。
WORKING-STORAGE SECTION.
* temporary variables in computational usage.
* intermediate values for computing paycheck with overtime
01 REGULAR-HOURS PIC 9(4)V99 USAGE COMP.
01 OVERTIME-HOURS PIC 9(4)V99 USAGE COMP.
01 OVERTIME-RATE PIC 9(4)V99 USAGE COMP.
01 REGULAR-PAY PIC 9(4)V99 USAGE COMP.
01 OVERTIME-PAY PIC 9(4)V99 USAGE COMP.
* computed parts of the paycheck
01 GROSS-PAY PIC 9(4)V99 USAGE COMP.
01 FED-TAX PIC 9(4)V99 USAGE COMP.
01 STATE-TAX PIC 9(4)V99 USAGE COMP.
01 FICA-TAX PIC 9(4)V99 USAGE COMP.
01 NET-PAY PIC 9(4)V99 USAGE COMP.
其中不熟悉的部分是PIC
(或PICTURE)子句。COBOL根本不是强类型的。相反,更像C,每个声明都标识一段内存;PIC
告诉COBOL如何用“picture”解释该内存。在这种情况下,9(4)v99
告诉COBOL,一个名为REGULAR-HOURS
的内存块将被解释为一个六位数字,该数字假定在最后两位之前有一个小数点(V
)。告诉COBOL使用适合快速算术的内部格式。这种格式实际上是有点灵活的,并且取决于体系结构,这意味着您最好不要依赖于它在任何地方都是相同的。
如果您想对此有信心,请不要使用USAGE COMP
,这会导致数据的另一部分,即输出检查的格式。这些字段是默认用法,可在USAGE COMP
不可用时打印。
01 PAYCHECK.
02 PRT-EMPLOYEE-NAME PIC X(25).
02 FILLER PIC X.
02 PRT-HOURS-WORKED PIC 99.9.
02 FILLER PIC X.
02 PRT-PAY-RATE PIC 99.9.
02 PRT-GROSS-PAY PIC $,$$9.99.
02 PRT-FED-TAX PIC $,$$9.99.
02 PRT-STATE-TAX PIC $,$$9.99.
02 PRT-FICA-TAX PIC $,$$9.99.
02 FILLER PIC X(5).
02 PRT-NET-PAY PIC $*,**9.99.
这里唯一有趣的是我们有了一些新的格式:$,$$9.99
有一个美元符号,它总是与最左边的数字相对,而$*,**9.99
用*填充美元符号和第一个数字之间的空间。
我将很快展示整个程序,但我确实想指出COBOL处理数学的方式,如COMPUTE-GROSS-PAY
所示:
COMPUTE-GROSS-PAY.
IF HOURS-WORKED > 40 THEN
MULTIPLY PAY-RATE BY 1.5 GIVING OVERTIME-RATE
MOVE 40 TO REGULAR-HOURS
SUBTRACT 40 FROM HOURS-WORKED GIVING OVERTIME-HOURS
MULTIPLY REGULAR-HOURS BY PAY-RATE GIVING REGULAR-PAY
MULTIPLY OVERTIME-HOURS BY OVERTIME-RATE
GIVING OVERTIME-PAY
ADD REGULAR-PAY TO OVERTIME-PAY GIVING GROSS-PAY
ELSE
MULTIPLY HOURS-WORKED BY PAY-RATE GIVING GROSS-PAY
END-IF
.
是的,标准COBOL让你拼出来。
下面是完整的程序。
IDENTIFICATION DIVISION.
PROGRAM-ID. PAYCHECKS.
AUTHOR. CHARLES R. MARTIN.
DATE-WRITTEN. 2020-APR-15.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT TIMECARDS
ASSIGN TO "TIMECARDS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD TIMECARDS.
01 TIMECARD.
02 EMPLOYEE-NAME.
03 EMP-FIRSTNAME PIC X(10).
03 EMP-SURNAME PIC X(15).
02 HOURS-WORKED PIC 99V9.
02 PAY-RATE PIC 99.
WORKING-STORAGE SECTION.
* temporary variables in computational usage.
* intermediate values for computing paycheck with overtime
01 REGULAR-HOURS PIC 9(4)V99 USAGE COMP.
01 OVERTIME-HOURS PIC 9(4)V99 USAGE COMP.
01 OVERTIME-RATE PIC 9(4)V99 USAGE COMP.
01 REGULAR-PAY PIC 9(4)V99 USAGE COMP.
01 OVERTIME-PAY PIC 9(4)V99 USAGE COMP.
* computed parts of the paycheck
01 GROSS-PAY PIC 9(4)V99 USAGE COMP.
01 FED-TAX PIC 9(4)V99 USAGE COMP.
01 STATE-TAX PIC 9(4)V99 USAGE COMP.
01 FICA-TAX PIC 9(4)V99 USAGE COMP.
01 NET-PAY PIC 9(4)V99 USAGE COMP.
* print format of the check
01 PAYCHECK.
02 PRT-EMPLOYEE-NAME PIC X(25).
02 FILLER PIC X.
02 PRT-HOURS-WORKED PIC 99.9.
02 FILLER PIC X.
02 PRT-PAY-RATE PIC 99.9.
02 PRT-GROSS-PAY PIC $,$$9.99.
02 PRT-FED-TAX PIC $,$$9.99.
02 PRT-STATE-TAX PIC $,$$9.99.
02 PRT-FICA-TAX PIC $,$$9.99.
02 FILLER PIC X(5).
02 PRT-NET-PAY PIC $*,**9.99.
* Tax rates -- 77 level aha!
77 Fed-tax-rate Pic V999 Value Is .164 .
77 State-tax-rate Pic V999 Value Is .070 .
77 Fica-tax-rate Pic V999 Value Is .062 .
* 88 Level is for conditions.
01 END-FILE PIC X.
88 EOF VALUE "T".
PROCEDURE DIVISION.
BEGIN.
PERFORM INITIALIZE-PROGRAM.
PERFORM PROCESS-LINE WITH TEST BEFORE UNTIL EOF
PERFORM CLEAN-UP.
STOP RUN.
INITIALIZE-PROGRAM.
OPEN INPUT TIMECARDS.
PROCESS-LINE.
READ TIMECARDS INTO TIMECARD
AT END MOVE "T" TO END-FILE.
IF NOT EOF THEN
PERFORM COMPUTE-GROSS-PAY
PERFORM COMPUTE-FED-TAX
PERFORM COMPUTE-STATE-TAX
PERFORM COMPUTE-FICA
PERFORM COMPUTE-NET-PAY
PERFORM PRINT-CHECK
END-IF.
COMPUTE-GROSS-PAY.
IF HOURS-WORKED > 40 THEN
MULTIPLY PAY-RATE BY 1.5 GIVING OVERTIME-RATE
MOVE 40 TO REGULAR-HOURS
SUBTRACT 40 FROM HOURS-WORKED GIVING OVERTIME-HOURS
MULTIPLY REGULAR-HOURS BY PAY-RATE GIVING REGULAR-PAY
MULTIPLY OVERTIME-HOURS BY OVERTIME-RATE
GIVING OVERTIME-PAY
ADD REGULAR-PAY TO OVERTIME-PAY GIVING GROSS-PAY
ELSE
MULTIPLY HOURS-WORKED BY PAY-RATE GIVING GROSS-PAY
END-IF
.
COMPUTE-FED-TAX.
MULTIPLY GROSS-PAY BY FED-TAX-RATE GIVING FED-TAX
.
COMPUTE-STATE-TAX.
* Compute lets us use a more familiar syntax
COMPUTE STATE-TAX = GROSS-PAY * STATE-TAX-RATE
.
COMPUTE-FICA.
MULTIPLY GROSS-PAY BY FICA-TAX-RATE GIVING FICA-TAX
.
COMPUTE-NET-PAY.
SUBTRACT FED-TAX STATE-TAX FICA-TAX FROM GROSS-PAY
GIVING NET-PAY
.
PRINT-CHECK.
MOVE EMPLOYEE-NAME TO PRT-EMPLOYEE-NAME
MOVE HOURS-WORKED TO PRT-HOURS-WORKED
MOVE PAY-RATE TO PRT-PAY-RATE
MOVE GROSS-PAY TO PRT-GROSS-PAY
MOVE FED-TAX TO PRT-FED-TAX
MOVE STATE-TAX TO PRT-STATE-TAX
MOVE FICA-TAX TO PRT-FICA-TAX
MOVE NET-PAY TO PRT-NET-PAY
DISPLAY PAYCHECK
.
CLEAN-UP.
CLOSE TIMECARDS.
END PROGRAM PAYCHECKS.
数据文件如下:
Charlie Martin 41015
Terry Lacy 32007
输出结果如下:
$ cobc -x paycheck.cob
$ ./paycheck
Charlie Martin 41.0 15.0 $622.50 $102.09 $43.57 $38.59 $**438.25
Terry Lacy 32.0 07.0 $224.00 $36.73 $15.68 $13.88 $**157.71
$
学习COBOL的资源
实际上有相当多的课程和书籍学习COBOL。许多课程来自海外,因为离岸外包公司多年来一直在满足COBOL的需求。
我买了这本书,并完成了我的课程,它相当不错,在Kindle上的几本COBOL书籍中,我喜欢Michael Coughlan的《程序员COBOL入门》。YouTube上的视频堆积如山,我只看了几个。这一个看起来不错,但搜索COBOL,你会发现更多。
接下来还会有更多。4月9日,IBM和openmainframe项目宣布了一个联合项目,用COBOL技能连接各州并教授COBOL编程。它有几个资源,包括一个公告栏,面向那些想重返行业的COBOL程序员,以及一个开源COBOL课程的开始。
为什么COBOL名声不好?
从这个小示例中可以看出,COBOL与普通编程语言不同。不能用COBOL编写编译器或内核模块,而且语法也不是我们所期望的。但是再考虑另一种常见的领域特定语言:SQL。语法有点奇怪,语义依赖于关系代数。
Ceballlos说:“在大型机上编程可以让你一窥软件过去是如何构建的。“对于任何现代程序员来说,它就像一个时间胶囊。与现代的DEVOPS和自动化技术相比,它的大部分仍然是非常手工的。”
COBOL在很多方面都是一种过时的、糟糕的编程语言。但对于它的特定领域,它比其他任何东西都好。
作者介绍