在尝试 COBOL 之前,请不要讨厌它

COBOL 是计算机编程界的罗德尼·丹泽菲尔德,它一直不受尊重,因其冗长而被经常贬低,并被视为过时。然而,COBOL 远非一种死语言。据估计,它处理了所有商业交易的 85%,并且每年编写 50 亿行新的 COBOL 代码。
485 位读者喜欢这篇文章。
What to like about COBOL

Rainer Gerhards。由 Opensource.com 修改。CC BY-SA 4.0

COBOL 是编程语言中的罗德尼·丹泽菲尔德——它不受任何尊重。它经常因其冗长而被贬低,并被斥为过时。然而,COBOL 远非一种死语言。据估计,它处理了所有商业交易的 85%,并且每年编写 50 亿行新的 COBOL 代码。

我做了 10 年的 COBOL 程序员,我不认为它像它的名声所暗示的那样糟糕。事实上,它非常擅长处理货币和固定格式的记录。但是 COBOL 确实有它的怪癖,其中许多怪癖都根植于早期编程的计算环境。这是一个关于一张穿孔卡片如何吃掉我的程序的故事。

一个神秘的错误

这是一个问题代码的示例,它试图计算订单的运费和预计发货日期

 1      identification division.
 2      program-id.
 3          test-ship.
 4
 5      data division.
 6      working-storage section.
 7
 8      01 shipping-method            pic x(2) value 'US'.
 9      01 cust-type                  pic x(2) value 'EM'.
10      01 normal-ship-date-yyyymmdd  pic 9(8) value 20170522.
11      01 nextday-ship-date-yyyymmdd pic 9(8) value 20170508.
12      01 expected-shipping-date     pic 9(8).
13      01 shipping-charge            pic 99v99 value 4.99.
14
15      procedure division.
16          if shipping-method <> 'FX'
17              move normal-ship-date-yyyymmdd to expected-shipping-date
18          else
19              move nextday-ship-date-yyyymmdd to expected-shipping-date.
20
21          if cust-type = 'EM'
22              move 0 to shipping-charge.
23
24          display expected-shipping-date.
25          display shipping-charge.

即使您以前从未见过 COBOL 代码,逻辑也应该很容易理解。如果运输方式是“FX”,则客户获得次日达服务,否则运输需要两周时间。(这是 90 年代。)员工可以享受免费送货;其他人则支付 4.99 美元。这段代码在我看来是正确的,但它有一个错误——发货日期计算正确,但员工被收取全额运费。

问题原来是第 19 行末尾的句点。那时,追踪到这一点需要一些侦探工作,但现代的语法高亮编辑器会立即标记出来。但是为什么这是一个问题?为什么 COBOL 不喜欢那个句点,而它对第 22 行末尾的句点却非常满意呢?

句子而不是代码块

要回答这个问题,我们需要追溯到 COBOL 在 1950 年代后期的起源。在此之前,大多数语言都是为解决科学和工程问题而设计的,因此它们的语法类似于数学方程式。(Fortran 是此类语言的经典示例。)另一方面,COBOL 旨在用于商业计算。为了让非专业人士更容易学习,格蕾丝·霍珀和她的国防部和 IBM 工程师团队赋予了 COBOL 英语语言语法。与大多数现代语言的递归语法不同,COBOL 程序具有分层结构。COBOL 不是代码块,而是将语句组合成“句子”。就像英语一样,每个句子都以句点结尾。

虽然这在理论上似乎是个好主意,但在实践中却被证明是有问题的。这使得移动代码变得困难,因为一个意外的句点可能会意外地终止一个代码块。句点也很难注意到——在 90 年代的 CRT 终端上,它们通常只是一个像素。但这里存在一个更深层次的问题,这个问题与程序员在 COBOL 首次开发时编写代码的方式有关。

穿孔卡片

COBOL punch card

opensource.com

当 COBOL 被设计出来时,硬盘驱动器非常昂贵,因此大多数程序都是在穿孔卡片上编写的。最常见的穿孔卡片由 12x80 的网格组成,其中孔代表 1,非孔代表 0。每列是一个 12 位字符,每张卡片是一行 80 个字符的文本。要运行您的程序,您需要将一叠穿孔卡片送入读卡器。每张卡片的前六列和最后八列保留用于序号和标识符。这样,如果您不小心掉了卡片(这可能是您的程序的唯一副本),您可以将卡片通过机械分类器送入,以将其放回正确的顺序。

这意味着 COBOL 会忽略第 72 列之后的任何字符。如果恰好是一个句点,您代码的整个逻辑都可能会改变。而且,正如您现在无疑猜到的那样,第 19 行的句点在第 73 列。以下是 COBOL 编译器实际解释这些行的方式

16          if shipping-method <> 'FX'
17              move normal-ship-date-yyyymmdd to expected-shipping-date
18          else
19              move nextday-ship-date-yyyymmdd to expected-shipping-date
20
21              if cust-type = 'EM'
22                  move 0 to shipping-charge.

一旦我发现问题所在,修复就很容易了:我从第 19 行的开头删除了一个空格字符,这使句点位于第 72 列。虽然我以前从未遇到过这种情况,但这是一个非常常见的错误,以至于许多大型机 COBOL 程序员会在他们的终端上在第 72 列和第 73 列之间粘贴一根线。

今天的 COBOL

COBOL-85 标准添加了诸如 end-if 之类的范围终止符,因此不再需要句点来结束句子。COBOL 2002 标准允许自由格式代码,尽管许多编译器在此之前很久就已支持。按照 2002 标准编写的相同代码看起来更像是一种现代编程语言

16 if shipping-method <> 'FX'
17     move normal-ship-date-yyyymmdd to expected-shipping-date
18 else
19     move nextday-ship-date-yyyymmdd to expected-shipping-date
20 end-if
21
22 if cust-type = 'EM'
23     move 0 to shipping-charge
24 end-if

请注意,行首的空格也不再是必需的。我通常使用的系统同时支持范围终止符和自由格式代码,因此直到我不得不在另一个系统上进行一些更改时,我才遇到这个问题。

对于开源爱好者来说,学习 COBOL 一直很困难。COBOL 编译器传统上是闭源且昂贵的,并且大多数 COBOL 代码都是在公司环境中编写的。然而,一个名为 OpenCOBOL 的开源编译器的开发工作始于 2002 年。2013 年,它被正式接受为 GNU 软件包并更名为 GnuCOBOL。要了解有关 GnuCOBOL 的更多信息,包括访问 400 页的程序员指南,请访问项目主页

在 Walt Mankowski 的演讲 一张穿孔卡片吃掉了我的程序! 中了解更多关于 COBOL 的信息,该演讲将于 8 月 26 日在费城的 FOSSCON 上进行。

标签
User profile image.
Walt Mankowski 是一位从象牙塔计算机科学家转型而来的人,他最近完成了一个博士后研究,与生物学家合作处理和可视化 TB 级的 2D 和 3D 时间推移显微镜图像。在他的过去生活中,他曾在一家大型有线家庭购物网络公司担任了 10 年的 COBOL 程序员。他喜欢 Perl、正则表达式、高性能计算和《飞出个未来》。

39 条评论

感谢这篇精彩的文章!我在职业生涯的早期做过一些 COBOL,现在仍然是它的粉丝。

我已经使用 COBOL-85 标准三十年了,从来没有遇到过句点问题。事实上,我写的每个段落都以 EXIT 语句结尾,而段落中的最后一件事是 EXIT 语句前一行的句点。

在编写过程部门的代码时要严谨;在 WORKING-STORAGE SECTION 中要有创新性和条理性,用 COBOL 可以做到任何事情。

1000-段落。

如果
啦啦啦啦
END-IF
.
1000-退出。退出。

:)

只是一个小小的吹毛求疵... 第 72 列是特殊的。如果它包含连字符或“C”,则编译器应该将下一行附加为单行进行处理。

老实说,我 99% 的时间使用的系统都使用自由格式代码,所以这个问题从来没有出现过。但我在线找到的所有内容都说,延续符由第 7 列中的“-”表示,这意味着当前行应该附加到前一行。我找不到任何迹象表明第 72 列被特殊对待。也许您把它与另一种语言混淆了?

回复 作者:Martin DiViaio (未验证)

抱歉... 但绝对是第 72 列。已经过去 30 多年了,所以我忘记它是 COBOL66 的一部分还是 ANSI COBOL 74“标准”。我记得有人曾经尝试使用它,直到系统管理员告诉他使用更短的变量名并继续前进。

回复 作者:waltman

自 1983 年以来,我一直是 IBM 大型机软件开发人员。特殊的是第 7 列,而不是第 72 列。“-”表示从上一行延续,“*”表示注释行,“/”是编译器指令,用于在编译器列表中强制分页符。任何其他内容都不是标准。

回复 作者:Martin DiViaio (未验证)

JCL 和一些大型机汇编程序似乎使用第 72 列来表示延续,所以我猜可能早期版本的 COBOL 也这样做过。

回复 作者:Scott Spurlock (未验证)

如果我没记错的话,早在 1960 年代,COBOL 刚问世时,硬盘驱动器还不存在。大型计算机将数据保存在磁带或纸带上。

IBM 在 1956 年发布了他们的第一个硬盘驱动器 IBM 305 RAMAC。那是在 COBOL 出现之前的几年,COBOL 的历史可以追溯到 1959 年。硬盘存储非常昂贵,这可能就是它们仍然不常见的原因。

回复 作者:Greg P

当我查找时,硬盘驱动器似乎确实存在,但尚不清楚它们是如何使用的,因为它们最初通常只有几 MB 的存储空间。

回复 作者:Greg P

是的。在我的演讲中,我有一张 1956 年工人们搬运 5 MB 硬盘的照片,它有几个冰箱那么大。但是,我曾经使用过的第一个 PC 硬盘驱动器只有 3 MB 的存储空间,但它看起来已经非常大了!

回复 作者:Greg P

这叫做臃肿软件。今天的电脑和手机都充满了它。

回到嬉皮士时代(60 年代和 70 年代),您有时只有 40 KB 的大型机空间来运行程序。
所以您非常努力地使其适应。如果 COBOL 做不到,那么您就用汇编程序来做(至少我们中的一些人是这样做的)。
与今天的后起之秀不同,只有强者才能生存。

回复 作者:Greg P

我在 80 年代早期开始在那些早期的 PC 上编程。当我还是象牙塔计算机科学家时,我仍然有一台 PC,但它有 32 个 CPU、64 GB 的 RAM 和 TB 级的存储空间。我们能够处理当时难以想象的计算问题。而且编程已经够难了,不必再微观管理内存。虽然回顾过去很有趣,但它让我更加欣赏现代硬件和软件!

回复 作者:Tony Q. King

除非您见过 COBOL 程序在配备 12 个大型磁带驱动器的 4K Remington-Rand Univac-II 上编译,并且所有磁带驱动器同时旋转,否则您什么也没见过。在 1960 年代早期,一个小型程序需要大约 1 到 2 个小时才能编译完成。
但是一旦 IBM 360 在 1965 年左右推出,配备了大型 2311 磁盘驱动器 - 每个 7 兆!- 那个程序将在不到 10 分钟的时间内编译完成。

是的,那是 4K,而不是 4 兆。

回复 作者:Greg P

磁盘驱动器在 60 年代中期随着 IBM 的 360 系列计算机和操作系统的发布而变得普遍。对于试图在配备 4K RAM 和 12 个大型磁带驱动器的 Remington-Rand Univac-II 上编译 COBOL 程序的人来说,这是一个受欢迎的解脱。
您应该看看所有这些磁带在小型 COBOL 程序编译时是如何运行的。通常需要 1 到 2 个小时(自然是在夜间运行)
(咕哝咕哝...诅咒你,格蕾丝·霍珀...!)

** 是的,那是 4 K!不是 4 MB。

回复 作者:Greg P

很久以前用过 Cobol,现在仍然喜欢它!简单易懂。如果我今天想编写一行代码,我必须安装 25 个开源工具和库,破解一些命令行,并在任何东西出现之前祈祷。

当您在第 7 列中放入星号时,它会将该行的其余部分变成注释。你猜怎么着,我有一个注释掉了一个 GOTO 语句。(哎呀)

第 7 列和第 72 列协同工作。第 7 列有几个用途,但它可以与第 72 列结合使用,以表示延续和连接几个涉及国家字符集(解析为非拉丁字符代码的多字节序列)的特殊情况。请参阅:https://www.ibm.com/support/knowledgecenter/en/SS6SGM_3.1.0/com.ibm.aix…

关于穿孔卡片的另一个小观察或趣闻。
今天很少有程序员/IT“专家”意识到 80 个字符的文本行(在编辑器或终端屏幕上)来自 120 年前(至少!)的霍勒里斯穿孔卡片,最终被 IBM 数据处理部门采用,然后在 1970 年代编程库最终进入磁带(短暂地)并最终进入磁盘。
唉,赫尔曼·霍勒里斯在 COBOL 甚至在格蕾丝海军上将的 80 列卡片中打孔之前就去世了。
如果您想为此辩护,您甚至可以争辩说这些穿孔卡片最初是在 18 世纪由纺织织工开发的。

附录:在任何人试图追溯到更久远的历史之前
有些人声称穿孔卡片的宽度(或长度)最初是基于罗马战车车轮的轨道宽度及其在 2000 年前的罗马道路上留下的特殊矩形压痕。
胡说八道!就像土星 1 号火箭助推器尺寸是基于罗马道路的说法一样,这只是另一个都市传说。;-)

回复 作者:Tony Q. King

硬盘驱动器的容量有限和成本与穿孔卡片的使用(在存储程序方面)有关,但也存在缺乏廉价终端的问题。在 1970 年代后期马里兰大学,学生可以使用的 ASCII 电传打字机数量有限,这意味着大多数学生不得不使用穿孔卡片。(当我在那里时,电传打字机被类似于 DECwriter 的点阵键盘/打印机取代。)UNIVAC 大型机的磁鼓已被硬盘驱动器取代,但操作系统继续提供鼓 API,该 API 在硬盘驱动器上模拟鼓。

我只在 1981 年的数据库课程中使用过一次 COBOL,但我事先读过 Daniel McCracken 关于 COBOL 的经典著作(以及他的关于 Fortran 和 Algol 的著作)。我使用 COBOL 没有任何问题;每种编程语言都需要不同的思维方式,了解 COBOL(在有限的时间内)与了解我使用过的所有其他语言一样令人在智力上感到满足。

在 1990 年代,我认为,一位 COBOL 布道者曾经经常在美国 USENET 新闻组 comp.os.unix 或 comp.lang.c 上发帖。他主要关注的不是 COBOL;它只是偶尔出现。在一篇文章中,他展示了一个 *完整*、*可移植* 的 4 行 COBOL 程序来对文件进行排序。(我记得是这样...)可移植性是可能的,因为 COBOL 内置了排序功能,而大多数其他语言则没有。在另一种语言中使用特定于操作系统的系统调用来运行外部“sort”程序,例如,不是一种可移植的解决方案。

我在 80 年代早期去了宾夕法尼亚大学。我从未使用过穿孔卡片,但仍然有很多旧硬件正在逐步淘汰。但我真正谈论的是 COBOL 的早期。计算机终端直到 70 年代初才开始出现,而 COBOL 在那时已经使用了十年了。电传打字机更早出现,但我不确定它们与大型机配合使用效果如何,因为我见过的所有电传打字机都需要双同步连接。

今天,当我用 C++、Perl 或 Python 等语言编程时,我经常想知道我是否可以用更好的方式编写某些东西。我应该使用哈希还是对象?结构还是类?循环还是列表推导式?我在 COBOL 中从未这样做过,因为通常只有一种方法可以做任何事情。它可能不是一个好方法,但这就是你的做法。因此,我的大部分精力都投入到解决业务问题而不是语言问题上。当然,当您知道有很多更好的方法可以做事时,也会感到沮丧,但有时缺少选项可以帮助集中注意力。:)

回复 作者:Alex Measday (未验证)

很棒的文章。我很高兴看到 COBOL 仍然活着并且被大量使用。

我是一家仍然活着的大型机公司的 COBOL 编译器开发人员。

其中一家大型机公司?您的意思是 Amdahl 和 Hitachi 仍然在游戏中?
45-50 年前,只有“白雪公主”和七个小矮人。
如果您能告诉我那可怜的七个的名字,我会给您额外的分数!

回复 作者:用户

一个问题... 哪个版本的 COBOL 在 IF 语句中添加了 ELSE 子句?

我是一个 DBA 团队的成员,该团队必须使用不支持 ELSE 子句的 COBOL 从大型机数据库中提取和转换数据以进行 Y2K。我们称之为“COBOL I”,但我在网上找不到使用该名称的参考文献。

这太奇怪了!我不能说我听说过任何不支持 ELSE 的编程语言。如果您想做等效于 ELSE 的事情,您是否必须使用条件的否定重复 IF?您的 COBOL 是在大型机上还是在其他平台上运行?

回复 作者:DocSalvager

Jean Sammet 将“强大的条件(即 IF THEN ELSE)结构”列为 COBOL 的第一个版本 COBOL '60 的核心贡献之一。(参见 Jean Sammet 的“COBOL 的早期历史”,第 199-243 页,《编程语言历史 I》(1978 年)。)我想知道您遇到的版本是否存在特定的实现问题。

回复 作者:DocSalvager

不,问题是第 73 列中的句点被忽略了。我第一次在 Stratus VOS 编译器上看到它,我能够在 GnuCOBOL 中复制它。它会发生在任何控制结构中。

回复 作者:Jeff B (未验证)

但是 GnuCOBOL 没有使用旧编译器,而是说“第 72 列之后的源文本” :-)

回复 作者:waltman

那是我的第一篇文章,我没有看到编辑它的方法。我的意思是,哪个是最后一个不支持 ELSE 子句的版本?

我仍然使用 Cobol。我所有的业务程序都是用 Cobol 编写的。刚刚完成了一个新程序的开发。GUI 界面,MySQL 数据库。最初在 IBM 360 上开始,然后在 1970 年代的 DEC10 上,然后是 TRS80 型号 II 和 III,最后是 PC。当前的服务器是 Linux Debian,带有 WIN10 用户机器。运行良好且速度快。

不错的文章。我在 80 年代在大学里学习了 COBOL,并在 90 年代早期用 COBOL 做了一些编程。我不能说我喜欢它,但它确实完成了工作。
您提到 COBOL“处理了估计 85% 的所有商业交易”。这个估计有具体的来源吗?
谢谢

很高兴在 cobol 代码中看到小写字母。

我几十年前就这样做了;没有人这样做。很高兴发现代码编译得很好。无法忍受所有大写字母,因为它总是对你大喊大叫。呃。

我们的代码库都是小写的。也许他们那样做是因为我们使用的是 Stratus 计算机,而不是大型机?我从没想过问任何人。

回复 作者:dwight (未验证)

我有很多 Cobol 编程工作。我也使用穿孔卡片作为编程工作的输入。最初,语句被键入并打孔,然后像其中一篇博客中显示的那样被读卡器读取。我在 PDP/11 上完成了所有业务应用程序。
编写代码非常容易,我的心仍然倾向于 Cobol。后来,我在 1984 年至 1994 年间在中东为 IBM 计算机工作时,用 MF Cobol、RM Cobol、MS Cobol 编写了程序 10 年。我还用 AS/400 Cobol/400 编写了几个程序。我想即使在今天,我也很乐意用 Cobol 编写代码。祝你好运。我在 Cobol 中做得很好

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 获得许可。
© . All rights reserved.