COBOL考古(七)
表格处理
本节介绍了表格的概念,表格是具有相同描述的数据项集合。下属的项目称为表格元素。表格是 COBOL 中数组的等价物。
本章的目标是为读者提供足够的信息,以便能够在 COBOL 程序中处理表格。
定义表格
要编写一个表格,我们需要给表格一个组名,并定义一个我们重复 n 次的下属项目。
1 |
|
在上面的示例中,表格名是组项目的名称。表格还包含一个称为下属名的下属项目,我们将其重复 n 次。每个下属项目都有 2 个基本项目,即元素1和元素2。在这种情况下,我们将下属名称为表格元素的定义(因为它包含了OCCURS子句)。请注意,OCCURS子句不能在level-01描述中使用。
或者,我们也可以创建更简单的表格:
1 |
|
在这种情况下,表格名包含 n 个下属项目,每个下属项目最多可以包含 10 个字母数字字符。
我们还可以嵌套多个OCCURS元素,以创建具有附加维度的表格,最多可以有七个维度。请注意下面的示例:
1 |
|
这里,我们正在定义一个包含 10 门课程的学位课程,每门课程将包含 8 项作业。如果我们不知道表格元素会发生多少次怎么办?为了解决这个问题,我们可以使用可变长度表格,使用“OCCURS DEPENDING ON(ODO)”子句,我们将在后面的部分详细讨论。
引用表格中的项目
虽然表格元素具有一个集体名称,但其中的各个项目没有唯一的名称。要引用项目,我们可以使用下标、索引或两者结合使用。
下标引用
下标引用是使用表格元素的数据名称,以及它的发生号码(称为下标)。最小的下标号码是 1,它定义了表格元素的第一个发生。我们还可以使用文字或数据名称作为下标。请注意,如果您使用的是数据名称,它必须是一个基本的数值整数。
1 |
|
在上面的示例中,第二个 TABLE-ELEMENT 将包含 “DEF” 而不是 “ABC”。
索引
或者,我们可以使用 OCCURS 子句的 INDEXED BY 短语创建一个索引。这个索引被添加到表的地址上,用于定位一个项目(作为从表的开头的偏移量)。例如,
1 |
|
这里,INX-A 是一个索引名称。编译器将计算索引中的值,方法是将出现号减去 1,然后乘以表元素的长度。所以,例如,对于 TABLE-ELEMENT 的第二个出现,INX-A 中包含的二进制值是 (2-1) * 3,即 3。
如果您恰好有另一个具有相同数量的相同长度的表,您可以使用一个索引名称来引用这两个表。
我们还可以使用 USAGE IS INDEX 子句来定义索引数据项。这些索引数据项可以与任何表一起使用。例如,
1 |
|
索引名称 INX-A 用于遍历 TABLE-ELEMENT 表,而 INX-B 用于保存表的最后一个元素的索引。通过这样做,我们最小化了偏移量的计算,并且不需要为 UNTIL 条件进行转换。
我们还可以通过一个基本整数数据项来递增或递减索引名称。例如,
1 |
|
那里的整数代表出现次数。因此,在添加或减去索引之前,它将首先转换为索引值。
由于我们正在比较物理位移,因此不能使用索引数据项作为下标或索引。我们只能直接在 SEARCH 和 SET 语句中使用它,或者与索引进行比较。
以下示例显示了如何计算引用索引的元素的位移。
考虑以下二维表 TABLE-2D:
1 |
|
假设我们编写了以下索引:
1 |
|
这将导致计算到 TABLE-COL 元素的位移:
1 |
|
计算是基于元素的长度进行的。TABLE-ROW 的每个出现都有 20 个字节的长度(5 * 4),而 TABLE-COL 的每个出现都有 4 个字节的长度。
装载表格数据
有多种方法可以装载表格数据。第一种方法涉及从屏幕、文件或数据库动态装载表格。我们还可以在硬编码字段值上使用 REDEFINES 子句以及 OCCURS 子句。第三种方法是使用 INITIALIZE 语句,最后,我们还可以在定义表格时使用 VALUE 子句。
动态装载表格
要动态装载表格,我们需要使用 PERFORM 语句以及下标或索引。在执行此操作时,我们需要确保数据不超出分配给表格的空间。我们将在后面的章节中讨论文件处理和 PERFORM 子句的使用。例如,
1 |
|
在上面的示例中,我们执行一个读取文件的段落,然后我们将迭代文件的每一行直到结束,并将每个值放入表格中。
使用 REDEFINES 重新定义硬编码值
考虑以下示例,
1 |
|
在这里,我们将从1到5的拼写数字的硬编码值加载到一个表格中,通过使用 REDEFINES 子句实现。
使用 INITIALIZE 语句初始化表格
我们也可以使用 INITIALIZE 语句将数据加载到表格中。该表格将作为一个组项目进行处理,其中每个元素数据项将被识别和处理。例如,假设我们有以下表格:
1 |
|
在这里,我们有一个包含10个元素的表格,每个元素都有自己的 NUMBER-CODE(值为10)和 ITEM-ID(值为 “R3”)。
我们可以将值3移动到表格中每个元素的数值数据项中,将值 “X” 移动到表格中每个元素的字母数字数据项中:
1 |
|
运行这两个 INITIALIZE 语句后,NUMBER-CODE 将包含值3,而 ITEM-ID 将包含值 “X “。
使用 VALUE 子句分配值
如果一个表格预期包含稳定的值,我们可以在定义表格时设置这些值。以前面章节中的 WEEK-DAY-TABLES 和 TABLE-ONE 为例,它们在定义时都分配了值。以下是一些更多的示例:
1 |
|
在上面的示例中,表格中的字母数字组数据项 TABLE-TWO 使用了 VALUE 子句,用于初始化 TABLE-TWO-DATA 的四个元素。因此,在初始化之后,TABLE-TWO-DATA(1) 将包含字母数字 ‘1’,TABLE-TWO-DATA(2) 将包含字母数字 ‘2’,依此类推。
变长表格
如果在运行时之前无法确定表格元素会出现多少次,我们可以使用 OCCURS DEPENDING ON(ODO)子句定义一个变长表格。
1 |
|
在上面的示例中,X 是 ODO 主体,Y 是 ODO 对象。
有一些因素会影响成功操作变长记录:
- 正确计算记录长度
在这里,变量部分的长度是 DEPENDING ON 子句的对象和 OCCURS 子句的主体长度的乘积。
- ODO 子句的对象数据是否符合其 PICTURE 子句的规范
我们必须确保 ODO 对象正确指定了表格元素的出现次数,否则程序可能会异常终止。
以下示例显示了如何使用 OCCURS DEPENDING ON 子句:
1 |
|
如果我们将 REC-1 移动到 REC-2,REC-1 的长度将在事先使用 FIELD-1 的当前值确定。如果 FIELD-1 不符合其 PICTURE 子句,结果是不可预测的。因此,我们需要确保 ODO 对象(FIELD-1)在将 REC-1 移动到 REC-2 之前具有正确的值。
另一方面,如果我们将 REC-2 移动到 REC-1,长度将使用最大出现次数来确定。但是,如果 REC-1 后跟一个可变位置的组,ODO 对象将用于计算 REC-1 的实际长度。以下提供了这种情况的示例:
1 |
|
因此,在上面的情况下,必须在将组项用作接收字段之前设置ODO对象的值。
搜索表格
有两种搜索表格的技术:串行搜索和二进制搜索。
二进制搜索可能比串行搜索更高效,但它要求表格项已经排序。
串行搜索
我们可以使用 SEARCH 语句进行串行搜索。搜索将从当前索引设置开始,并将一直进行,直到 WHEN 子句中的条件得到满足。要修改索引设置,我们可以使用 SET 语句。如果 WHEN 子句中有多个条件,搜索将在满足其中一个条件并保持索引指向满足条件的元素时结束。
例如,假设我们有一个名字列表:
1 |
|
上面的代码将从索引为1的位置开始搜索名字列表。如果找到 PEOPLE-SEARCH-DATA 的内容,它将显示 “Found”,否则将显示 “Not found”。
对于更复杂的用例,我们还可以使用嵌套的 SEARCH 语句。需要使用 END-SEARCH 来限定每个嵌套的 SEARCH 语句。
二进制搜索
要执行二进制搜索,我们可以使用 SEARCH ALL 语句。我们不需要设置索引,而是使用与 OCCURS 子句相关联的索引。要使用 SEARCH ALL 语句,表格必须指定 OCCURS 子句的 ASCENDING 或 DESCENDING KEY 子句,或两者都指定,并且它必须按指定的关键字排序。
使用 WHEN 子句,您可以测试在 ASCENDING 或 DESCENDING KEY 子句中命名的任何关键字。测试必须是等于条件,并且 WHEN 子句必须指定一个关键字或与关键字相关联的条件名称。
例如,假设我们有一个按升序排序的名字列表:
1 |
|
上面的代码将搜索按字母顺序排序的名字列表。如果找到 PEOPLE-SEARCH-DATA 的内容,它将显示 “Found”,否则将显示 “Not found”。
实验
查看位于’id’.CBL数据集中的SRCHSER COBOL源代码成员。
从id.JCL中提交JCL成员SRCHSERJ,其中id是您的ID。这是编译并成功执行SRCHSER程序的地方。
查看SRCHSERJ作业输出,包括编译和执行的信息。
接下来,查看id.CBL数据集中的SRCHBIN COBOL源代码成员。
查看并从id.JCL下拉菜单中提交JCL成员SRCHBINJ。这是编译并执行SRCHBIN程序的地方。
查看SRCHBINJ作业输出,包括编译和执行的信息。
将SRCHSER与SRCHBIN进行比较。您是否注意到了以下差异?
a. 观察表格的定义。
b. 观察表格是如何从id.DATA数据集加载的。
c. 观察SEARCH和SEARCH ALL语句。