温习一下你的COBOL:为什么一门有60年历史的语言突然有了需求?

发布于:2021-01-21 15:29:19

0

192

0

COBOL 程序员

从前,当世界和计算机都是新事物的时候,我正在攻读数据处理的副学士学位,那时没有“计算机科学”课程,我必须学习会计学、数学、统计学和三种计算机语言: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:

  1. 如果尚未安装Visual Studio代码,请下载并安装。

  2. 安装比特语言.cobol和Broadcom COBOL语言支持扩展。

  3. 安装GnuCOBOL。(老实说,如果有什么事情会引起麻烦,那就是这个。MacOS上的自制安装运行得很好,我没有其他系统可以测试。在Windows上,MicroFocus免费试用visualstudio COBOL和Azure实验支持。)

现在,您已经安装了所有内容,并准备编写第一个COBOL程序。按照传统,我们将从你的节目“Hello, World”开始

因此,作为一个新的COBOL程序员,这里是您的第一个惊喜:COBOL关心您的代码在哪个列中。在传统的COBOL程序中,源代码有几个组件:

{xunruicms_img_title}

列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在很多方面都是一种过时的、糟糕的编程语言。但对于它的特定领域,它比其他任何东西都好。