COBOL考古(十一)

实验

本实验需要使用两个COBOL程序,CBL0006和CBL0007,以及两个对应的JCL作业,CBL0006J和CBL0007J,来编译和执行COBOL程序。所有这些都提供给您,可以在您的VS Code - Zowe Explorer中找到。

使用VS Code和Zowe Explorer:

  1. 请花点时间查看提供的两个COBOL程序的源代码:CBL0006和CBL0007。

  2. 将CBL0006与上一个实验中的CBL0005进行比较。您是否注意到了其中的区别?

    a. 在WORKING-STORAGE > PROCEDURE DIVISION内部,请观察新的CLIENTS-PER-STATE行。

    b. 注意在同一部分内的新段落IS-STATE-VIRGINIA。

    c. 该段落检查客户是否来自弗吉尼亚。如果满足此条件(true),则程序应将弗吉尼亚客户的总数加1。

    d. 程序在报告的最后一行中写入“Virginia Clients =”。

  3. 提交CBL0006J

  4. 从“JOBS”部分查看作业输出,并验证上述步骤是否已执行。

图 4. Id.JCL(CBL0006J) 输出

  1. 提交CBL0007J

  2. 在作业输出中找到编译错误IGYPS2113-E。

  3. 现在,修改id.CBL(CBL0007)以纠正IGYPS2113-E消息中提到的语法错误。*

  4. 重新提交CBL0007J

  5. 通过获取无错误的输出文件来验证已纠正语法错误。

图 5. 成功编译

实验提示

算术表达式

本章旨在介绍在COBOL程序中实现算术表达式的概念。我们将回顾算术表达式的基本概念、运算符、语句、限制、语句操作数以及表达式内的运算顺序。您将能够跟随一个全面的示例,展示了算术表达式在COBOL程序中的用法,您之前在前几章和实验中已经见过。在本章之后,将进行一个实验,以练习所学的内容的实际实现。

  • 什么是算术表达式?

    • 算术运算符

    • 算术语句

  • 算术表达式的优先规则

    • 括号
  • 算术表达式的限制

  • 算术语句的操作数

    • 操作数的大小
  • COBOL算术语句的示例

  • 实验

什么是算术表达式?

算术表达式用作某些条件和算术语句的操作数。算术表达式可以包括以下任何内容:

  1. 标识符,被描述为数字基本项(包括数字函数)。

  2. 数字文字。

  3. 字面常数ZERO。

  4. 标识符和文字,如第1、2和3项所定义,用算术运算符分隔。

  5. 两个算术表达式,如第1、2、3或4项所定义,用算术运算符分隔。

  6. 算术表达式,如第1、2、3、4或5项所定义,用括号括起来。

  7. 任何算术表达式都可以由一元运算符前置。

出现在算术表达式中的标识符和文字必须代表可以执行算术运算的数字基本项或数字文字。如果要升幂的表达式的值为零,则指数必须具有大于零的值。否则,将存在大小错误条件。在任何情况下,如果评估的结果中不存在实数,则将存在大小错误条件。

算术运算符

在算术表达式中可以使用五个二进制算术运算符和两个一元算术运算符。这些运算符由特定字符表示,必须在前后都有空格。但是,在左括号和一元运算符之间不需要空格。这些二进制和一元算术运算符列在表1中。

  • 什么是算术表达式?

    • 算术运算符

    • 算术语句

  • 算术表达式的优先规则

    • 括号
  • 算术表达式的限制

  • 算术语句的操作数

    • 操作数的大小
  • COBOL算术语句的示例

  • 实验

什么是算术表达式?

算术表达式用作某些条件和算术语句的操作数。算术表达式可以包括以下任何内容:

  1. 标识符,被描述为数字基本项(包括数字函数)。

  2. 数字文字。

  3. 字面常数ZERO。

  4. 标识符和文字,如第1、2和3项所定义,用算术运算符分隔。

  5. 两个算术表达式,如第1、2、3或4项所定义,用算术运算符分隔。

  6. 算术表达式,如第1、2、3、4或5项所定义,用括号括起来。

  7. 任何算术表达式都可以由一元运算符前置。

出现在算术表达式中的标识符和文字必须代表可以执行算术运算的数字基本项或数字文字。如果要升幂的表达式的值为零,则指数必须具有大于零的值。否则,将存在大小错误条件。在任何情况下,如果评估的结果中不存在实数,则将存在大小错误条件。

算术运算符

在算术表达式中可以使用五个二进制算术运算符和两个一元算术运算符。这些运算符由特定字符表示,必须在前后都有空格。但是,在左括号和一元运算符之间不需要空格。这些二进制和一元算术运算符列在表1中。

  • 算术语句的操作数

    • 操作数的大小
  • COBOL算术语句的示例

  • 实验

算术语句的操作数

算术语句中的操作数的数据描述不需要相同。在计算过程中,编译器会执行任何必要的数据转换和小数点对齐。

操作数的大小

如果启用了ARITH(COMPAT)编译器选项,每个操作数的最大大小为18位十进制数字。如果启用了ARITH(EXTEND)编译器选项,则每个操作数的最大大小为31位十进制数字。

操作数的复合是一个假想的数据项,结果是将操作数在小数点上对齐并将它们相互叠加。如何确定算术语句中操作数的复合如表2所示。

如果启用了ARITH(COMPAT)编译器选项,操作数的复合最多可以为30位数字。如果启用了ARITH(EXTEND)编译器选项,操作数的复合最多可以为31位数字。

语句 确定操作数的复合
SUBTRACT, ADD 叠加给定语句中的所有操作数,除了在GIVING之后的那些操作数。
MULTIPLY 叠加所有接收数据项
DIVIDE 叠加所有接收数据项,除了REMAINDER数据项
COMPUTE 无此限制

数据类型

COBOL 程序员必须注意,计算机存储的内部数据表示和格式可能不同,这些差异必须在 COBOL 源代码中定义。了解计算机的内部数据表示需要熟悉二进制、十六进制、ASCII 和 EBCDIC。Packed-Decimal 用于解释 COBOL 计算和显示数据格式。本章旨在使读者熟悉这些不同的“数据表示类型”。

  • 数据表示

    • 数值表示

    • 文本表示

  • COBOL DISPLAY 与 COMPUTATIONAL

  • 实验

数据表示

诸如数值和文本之类的数据在大多数计算机中,包括企业使用的大型计算机中,都是以零和一的形式内部表示的。虽然数据表示是计算机科学中的一个相对复杂的主题,但程序员并不总是需要完全了解各种不同的替代表示方式是如何工作的。然而,重要的是要了解它们之间的差异,以及在需要时如何指定特定的表示方式。

数值表示

COBOL 具有五种计算(数值)值表示方式。了解这些表示方式的原因有两个主要原因。第一个原因是,当 COBOL 程序需要读取或写入数据时,它需要了解数据在数据集中的表示方式。第二个原因是当存在关于所处理的值的精度和范围的特定要求时。有关二进制和十六进制编码以及这些数值表示的其他详细信息,请考虑阅读高级主题课程中的“数字数据表示”章节。

COMP-1

这也被称为单精度浮点数表示。由于其浮点性质,COMP-1 值可以非常小且接近零,或者它可以非常大(大约是 10 的 38 次方)。但是,COMP-1 值的精度有限。这意味着即使 COMP-1 值最多可以达到 10 的 38 次方,它也只能保留大约七位有效的小数位。任何具有超过七位有效数字的值都会被四舍五入。这意味着 COMP-1 值无法精确表示像 $1,234,567.89 这样有九位有效数字的银行余额,因为这个值有九位有效数字。相反,金额会被四舍五入。COMP-1 的主要应用是用于科学数值存储以及计算。

COMP-2

这也被称为双精度浮点数表示。与 COMP-1 相比,COMP-2 扩展了可以表示的值的范围。COMP-2 可以表示大约是 10 的 307 次方的值。与 COMP-1 一样,COMP-2 值也具有有限的精度。由于扩展格式,COMP-2 具有更多的有效位数,大约是 15 位有效的小数位。这意味着一旦一个值达到某个千万亿的数量级(没有小数位数),它将无法在 COMP-2 中精确表示。

COMP-2 用于更精确的科学数据存储和计算,取代了 COMP-1。请注意,COMP-1 和 COMP-2 在金融数据表示或计算中的应用有限。

COMP-3

这也被称为紧缩的 BCD(二进制编码十进制)表示。这是迄今为止在 COBOL 程序中最常用的数值值表示方式。紧缩的 BCD 也是一种在大型计算机(如 IBM z 架构)上具有某种独特性质和本地性质的表示方式。

与 COMP-1 或 COMP-2 不同,紧缩的 BCD 没有与数值范围无关的固有精度限制。这是因为 COMP-3 是一种依赖于实际值格式的可变宽度格式。COMP-3 可以精确表示带有小数位的值。COMP-3 值最多可以有 31 位小数位。

COMP-4

COMP-4 只能表示整数。与 COMP-1 和 COMP-2 相比,COMP-4 可以精确地存储和计算整数值(除非涉及除法运算)。虽然 COMP-3 也可以用于表示整数值,但 COMP-4 更加紧凑。

COMP-5

COMP-5 基于 COMP-4,但具有指定小数点位置的灵活性。COMP-5 具有 COMP-4 的空间效率和 COMP-3 的精确性。然而,与 COMP-3 不同,COMP-5 值不能超过 18 位小数位数。

文本表示

COBOL 程序经常需要表示文本数据,例如姓名和地址。

EBCDIC

扩展的二进制编码十进制交换码(EBCDIC)是一种包含八个二进制数字的字符编码标准,这八个数字位置分为两个部分。EBCDIC 于 1960 年代初为 IBM 计算机而设计。EBCDIC 用于对文本数据进行编码,以便在也了解 EBCDIC 的设备上正确打印或显示文本。

ASCII

美国信息交换标准代码(ASCII)是另一种二进制数字字符编码标准。

EBCDIC 与 ASCII

为什么会有这两种标准,当它们似乎执行相同的功能时?

EBCDIC 是一个可以追溯到 1931 年设计的标准,其根源可以追溯到打孔卡。另一方面,ASCII 是一种独立于 IBM 打孔卡无关的标准,于 1967 年创建。COBOL 程序可以原生地理解 EBCDIC,并且可以轻松地处理早在 1931 年就以打孔卡形式捕获的数据。

ASCII 主要由非 IBM 计算机使用。

COBOL 可以对 EBCDIC 或 ASCII 中的文本数据进行编码和处理。这意味着 COBOL 程序可以同时处理几十年前进行普查时捕获的数据,并将数据导出到使用 ASCII 或 Unicode 的云服务中。但是,重要的是要指出,程序员必须具备相关知识并选择适当的编码方式。

COBOL DISPLAY 与 COMPUTATIONAL

在 z/OS 上,Enterprise COBOL 默认使用 EBCDIC 编码。但是,在 z/OS 上可以读取和写入 ASCII。字母字符的 EBCDIC 格式表示在 DISPLAY 格式中。不带符号的数字的区位十进制格式也在 DISPLAY 格式中。而压缩十进制、二进制和浮点数则不在 DISPLAY 格式中。COBOL 可以使用 COMPUTATIONAL、COMP-1、COMP-2、COMP-3、COMP-4 和 COMP-5 保留字来描述压缩十进制、二进制和浮点数字段。

实验

到目前为止,你已经使用过许多以前的 COBOL 实验程序,这些程序都读取了包含两个压缩十进制字段的记录,即客户账户限额和客户账户余额。在算术表达式实验中,所有客户账户限额和余额的总和都使用了 COMPUTE 语句,其中 COMP-3 字段包含了内部压缩十进制数据。

当内部的压缩十进制字段没有使用 COMP-3 来描述时会发生什么情况?如果没有使用 COMP-3 来描述字段,那么 COBOL 程序会将数据视为 DISPLAY 数据(EBCDIC 格式)。这个实验演示了在没有使用 COMP-3 的情况下程序执行时会发生什么情况。

使用 VS Code 和 Zowe Explorer

  1. 提交作业 id.JCL(CBL0010J)。

  2. 观察 COBOL 源代码的编译是否成功,但同时也注意到作业的执行失败。如何判断?

    在 CBL0010J(JOB#) 旁边没有 CC 代码。相反,有一个 ABENDU4038 消息。U4038 是一个常见的用户代码错误,通常涉及外部数据与 COBOL 数据表示之间的不匹配。

  3. 仔细阅读执行 SYSOUT 消息。SYSOUT 消息错误地认为记录长度为 174 个字符,而程序认为记录长度为 170 个字符。

    解释:压缩十进制(COMP-3)会扩展为两个数字,而通常只会存在一个数字。如果程序在没有将字段描述为 COMP-3 的情况下读取了压缩十进制字段,那么程序执行会对记录的大小感到困惑,因为 PIC 子句 S9(7)V99 期望存储七个数字和一个符号数字,而实际上只读取了三个字位置。因此,执行报告了一个四个记录长度的位置差异。

  4. 编辑 id.CBL(CBL0010) 以识别并纠正源代码问题。*

  5. 提交 id.JCL(CBL0010J) 并验证纠正是否成功,CC 代码为 0000。

实验提示:

ACCT-LIMIT 段中的 PIC 子句应与 ACCT-BALANCE 的 PIC 子句相同。

\newpage

内置函数

今天的 COBOL 不再是你父辈的 COBOL。如今的 COBOL 包括了几十年的功能丰富的先进技术和性能改进。行业规范的几十年经验被应用于 COBOL,以满足企业不断增长的需求。企业版 COBOL for z/OS 所承诺并交付的是,与硬件和操作系统软件的新版本具有几十年的向上兼容性。COBOL 的原始 DNA 演变成了一种功能强大、易于维护、可信赖和经过时间测试的计算机语言,没有终点。

新的 COBOL 能力包括 JSON GENERATE 和 JSON PARSE,提供了一种易于使用的编码机制,将 DATA DIVISION 中定义的数据项转换为 JSON,以便浏览器、智能手机或任何物联网 (IoT) 设备进行格式化,同时还可以将从浏览器、智能手机或任何 IoT 设备接收的 JSON 转换为 DATA DIVISION 中定义的数据项以供处理。经常情况下,智能手机访问的关键数据,例如银行余额,是由 z/OS 存储和控制的,COBOL 程序负责检索并返回银行余额给智能手机。COBOL 已成为支持 Web 的计算机语言。

以前的 COBOL 行业规范包括内置函数,这些函数今天仍然在很大程度上是相关的。有经验的 COBOL 程序员需要熟悉内置函数,并注意是否引入了新的内置函数。本章旨在介绍内置函数的基础知识以及在 COBOL 中的用法。

在Enterprise COBOL for z/OS V6.4中的内部函数

Enterprise COBOL for z/OS V6.4包括一系列的内部函数,用于执行各种任务。让我们从内部函数的不同类别中探讨一些示例。

数学示例

1
2
3
4
5
6
01  Num1      Pic 9(3) Value 123.
01 Num2 Pic 9(3) Value 456.
01 Result Pic 9(5).

Compute Result = Function Num1 + Num2
Display "Sum: " Result

在这个示例中,我们使用Function保留字对数字数据项Num1Num2进行加法运算。结果存储在Result变量中并进行显示。

统计示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
01  Data-Array    Pic 9(3) Occurs 10 Times.
01 Mean-Result Pic 9(3).
01 Stddev-Result Pic 9(3).

Perform Varying I from 1 by 1
Until I > 10
Compute Data-Array(I) = I * 10
End-Perform

Compute Mean-Result = Function Mean(Data-Array)
Compute Stddev-Result = Function Stddev(Data-Array)

Display "Mean: " Mean-Result
Display "Stddev: " Stddev-Result

在这个统计示例中,我们使用MeanStddev函数计算了一个数据数组的平均值和标准差。

日期/时间示例

1
2
3
4
01  Current-Date       Pic 9(8).
01 Current-Time Pic 9(6).
01 Formatted-Date Pic X(10).
01 Formatted-Time Pic X(8).

Call Function Current-date into Current-

内部函数的类别

内部函数可以根据其执行的服务类型分为六类,它们如下:

  1. 数学

  2. 统计

  3. 日期/时间

  4. 金融

  5. 字符处理

  6. 通用

内部函数可操作字母数字、国际、数字和整数数据项。

  • 字母数字 函数属于字母数字类别。返回值具有 DISPLAY 隐式使用方式。返回值中的字符位置数量由函数定义确定。

  • 国际 函数属于国际类别。返回值具有 NATIONAL 隐式使用方式,表示为国际字符(UTF-16)。返回值中的字符位置数量由函数定义确定。

  • 数字 函数属于数字类别。返回值始终被视为具有操作符号,并且是数字中间结果。

  • 整数 函数属于数字类别。返回值始终被视为具有操作符号,并且是整数中间结果。返回值中的数字位置数量由函数定义确定。

Enterprise COBOL for z/OS V6.4 中的内部函数

Enterprise COBOL for z/OS V6.4 的当前版本包括 82 个内部函数,每个函数都属于前述六个类别之一。虽然内部函数可以写一本完整的书,但本节提供了每个类别的一个示例。

数学示例

示例 2. 将 A + B + C 除以 D 的结果的值存储到 X 中。FUNCTION SUM 使算术运算成为可能。

1
Compute x = Function Sum(a b (c / d))

示例 2. 数学内部函数

统计示例

示例 3. 显示了三个 COBOL 函数,MEAN、MEDIAN 和 RANGE,其中算术值存储在 Avg-Tax、Median-Tax 和 Tax-Range 中,使用了带有分配 pic 子句值的数据名称。

1
2
3
4
5
6
7
8
9
10
11
01  Tax-S           Pic 99v999 value .045.
01 Tax-T Pic 99v999 value .02.
01 Tax-W Pic 99v999 value .035.
01 Tax-B Pic 99v999 value .03.
01 Ave-Tax Pic 99v999.
01 Median-Tax Pic 99v999.
01 Tax-Range Pic 99v999.
. . .
Compute Ave-Tax = Function Mean (Tax-S Tax-T Tax-W Tax-B)
Compute Median-Tax = Function Median (Tax-S Tax-T Tax-W Tax-B)
Compute Tax-Range = Function Range (Tax-S Tax-T Tax-W Tax-B)

示例 3. 统计内部函数

日期/时间示例

示例 4. 显示了三个 COBOL 函数的用法,Current-Date、Integer-of-Date 和 Date-of-Integer,应用于 MOVE、ADD 和 COMPUTE 语句。

1
2
3
4
5
6
7
8
01  YYYYMMDD        Pic 9(8).
01 Integer-Form Pic S9(9).
. . .
Move Function Current-Date(1:8) to YYYYMMDD
Compute Integer-Form = Function Integer-of-Date(YYYYMMDD)
Add 90 to Integer-Form
Compute YYYYMMDD = Function Date-of-Integer(Integer-Form)
Display 'Due Date: ' YYYYMMDD

示例 4. 日期/时间内部函数

金融示例

示例 5 展示了 COBOL 函数 ANNUITY 金融算法的应用,其中将贷款金额、付款、利息和期数的值输入到 ANNUITY 函数中。

1
2
3
4
5
6
7
8
9
01  Loan                 Pic 9(9)V99.
01 Payment Pic 9(9)V99.
01 Interest Pic 9(9)V99.
01 Number-Periods Pic 99.
. . .
Compute Loan = 15000
Compute Interest = .12
Compute Number-Periods = 36
Compute Payment = Loan * Function Annuity((Interest / 12) Number-Periods)

示例 5. 金融内部函数