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

它是计算机编程界的罗德尼·丹泽菲尔德,但 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 行末尾的句点感到满意时,为什么不喜欢第 19 行的句点?

句子而不是代码块

要回答这个问题,我们需要追溯到 20 世纪 50 年代末 COBOL 的起源。在此之前,大多数语言都是为解决科学和工程问题而设计的,因此它们的语法类似于数学方程式。(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 页的程序员指南,请访问项目主页

在沃尔特·曼科夫斯基在费城举行的 FOSSCON 8 月 26 日的演讲 一张穿孔卡片吃掉了我的程序! 中了解更多关于 COBOL 的信息。

标签
User profile image.
沃尔特·曼科夫斯基是一位康复中的象牙塔计算机科学家,他最近完成了一项博士后研究,与生物学家合作处理和可视化 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 首次出现时,硬盘驱动器并不存在。大型计算机将数据保存在磁带或纸带上。

对。在我的演讲中,我有一张 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

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

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

回复 作者 Greg P

随着 IBM 的 360 系列计算机和操作系统的发布,磁盘驱动器在 60 年代中期变得很常见。对于那些试图在配备 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 个字符的文本行(在编辑器或终端屏幕上)来自 80 列 120 年历史的(至少!)霍勒里斯穿孔卡片,最终被 IBM 数据处理采用,然后编程库最终在 1970 年代进入磁带(短暂地),然后进入磁盘。
唉,赫尔曼·霍勒里斯在 COBOL 甚至还没有成为格蕾丝海军上将的 80 列卡片中的一个孔之前就去世了。
如果您想为此辩护,您甚至可以争辩说这些穿孔卡片最初是在 18 世纪由纺织工人开发的。

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

回复 作者 Tony Q. King

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

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

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

我在 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 开始,然后是 DEC10,1970 年代。然后是 TRS80 型号 II 和 III,最后是 PC。当前服务器是 Linux Debian,带有 WIN10 用户机器。工作出色且快速。

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

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

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

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

Creative Commons 许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.