COBOL考古(十)

Lab

这个实验使用位于您的id.CBL数据集中的COBOL程序CBL0033,以及位于您的id.JCL数据集中的JCL作业CBL0033J。 JCL作业用于编译和执行COBOL程序,如前几章所讨论的那样。

使用VS Code和Zowe Explorer

  1. 请花点时间查看提供的COBOL程序CBL0033的源代码。

  2. 将CBL0033与前一个实验中的CBL0001和CBL0002进行比较。您是否注意到了差异?

    a. 观察工作存储 > 数据部分中的新COUNTER行。

    b. 观察段落被编号,并且它们都明确地以-END语句结束。

    c. 观察PROCEDURE DIVISION中的新段落READ-FIRST-RECORD、READ-TEN-RECORDS、READ-ANOTHER-RECORD、READ-NEXT-RECORDS和CALLING-SUBPROGRAM。

    d. 这些段落以不同的方式使用PERFORM语句执行与CBL0001中相同的循环。CALLING-SUBPROGRAM调用HELLO程序,该程序已经在本课程的第二个实验中介绍过。

  3. 提交作业:CBL0033J。这个JCL首先编译HELLO程序,然后编译CBL0033,并将两次编译的结果链接在一起。

  4. 使用JOBS部分查看CBL0033J的输出,并打开RUN:PRTLINE,观察报告与CBL0001相同。

  5. 使用JOBS部分查看目标程序HELLO的输出,并打开RUN:SYSOUT。

文件输出

设计一个易于阅读和理解的结构化布局是格式化输出的要求。设计结构化布局涉及使用空格、数字格式、货币格式等列标题和变量对齐。本章旨在利用示例COBOL代码来解释这个概念,以设计列标题并在这些标题下对齐数据名称。在本章末尾,您将被要求完成一个实验,练习涵盖的组件的实施。

值得注意的是,虽然本章未涵盖的一个COBOL数据输出格式化功能是COBOL是一种支持Web的计算机语言。COBOL包括将现有COBOL代码快速转换为编写JSON(JavaScript对象表示法)的功能,随后输出将格式化为浏览器、智能手机等设备。经常情况下,智能手机访问的关键数据,如银行余额,是由z/OS存储和控制的,而COBOL程序负责检索并将银行余额返回到智能手机。

  • COBOL写输出流程回顾

    • 环境部分
  • 文件描述符

    • FILLER
  • 报告和列标题

    • HEADER-2
  • 过程部分

    • MOVE语句

    • FROM语句的PRINT-REC

  • 实验

COBOL写输出流程回顾

本节简要回顾了环境部分的某些方面,以便理解它与本章内容的关联。

环境部分

“文件处理”部分涵盖了SELECT和相应的ASSIGN程序员选择的名称,而本章关注输出。图1显示了一个使用PRINT-LINE作为程序员选择的COBOL内部文件名的编码示例。

图1. SELECT和ASSIGN

文件描述符

文件描述符(FD),先前在FILE-CONTROL段落部分描述,表示文件部分中组织的最高级别。FD条目描述了由前面的FILE-CONTROL SELECT语句定义的文件的布局。因此,FD条目将SELECT文件名与文件名的定义布局连接起来。图2显示了PRINT-LINE的示例文件描述符FD。文件描述符后面是PRINT-LINE的定义布局。

FILLER

请注意数据名称FILLER。虽然大多数数据字段都有唯一的名称,但FILLER是COBOL保留字数据名称,用于输出格式化。这部分是因为FILLER分配内存空间而无需名称。此外,FILLER分配的内存在输出行中具有定义的长度,可以包含空格或任何文字。图2显示了多个FILLER的VALUE SPACES示例。SPACES在输出中创建数据项之间的空格,有助于保持代码的可读性。更具体地说,在图2中,FILLER PIC X(02) VALUE SPACES表示包含两个空格的输出行。

图2. FILLER

报告和列标题

编写报告或列标题需要程序员设计的结构化输出布局。图3说明了这样的结构。设计的输出结构布局在DATA DIVISION中实现,并包括下面列出和定义的标题。

  • HEADER-1:

    • 写入文字

    • 例子:’财务报告’

  • HEADER-2:

    • 写入文字

    • 例子:

      • ‘年’后跟一个变量名

      • ‘月’后跟一个变量名

      • ‘日’后跟一个变量名

  • HEADER-3:

    • 写入文字

    • 例子:

      • ‘账户’后跟FILLER间隔

      • ‘姓’后跟FILLER间隔

      • ‘限额’后跟FILLER间隔

      • ‘余额’后跟FILLER间隔

  • HEADER-4:

    • 写入短横线,后跟FILLER间隔

图3. 设计的输出结构布局

HEADER-2

HEADER-2包括报告的年份、月份、日期以及FILLER区域,它们在图3中创建了年份、月份和日期之间的空白间隔。图4是用于存储CURRENT-DATE值的数据名称布局示例。COBOL在CURRENT-DATE中提供的信息用于填充HEADER-2中的输出文件。

图4. CURRENT-DATE内部函数

PROCEDURE DIVISION

图1到图4是一个设计的数据布局,包括数据行和报告标题。使用数据行和报告标题映射的存储,COBOL处理逻辑可以写入报头,然后是每个数据行。图5是一个示例,显示了用于在COBOL程序中编写报头布局结构的执行逻辑。

图5. 编写报头布局结构的执行逻辑

MOVE语句

COBOL MOVE语句位于WRITE-HEADERS段落中的第1行,它从系统中收集当前日期信息并将该信息存储在定义的数据名称布局WS-CURRENT-DATE-DATA中。使用保留字FUNCTION意味着其后的内容是COBOL内部函数。第2、3和4行的语句将日期信息,年份、月份和日期,存储在HEADER-2定义的数据名称区域HDR-YR、HDR-MO和HDR-DAY中。第11行的语句,是段落中的最后一句,将空格写入PRINT-REC区域,以清除准备写入数据行的行存储区。

FROM语句的PRINT-REC

PRINT-REC已经以输出方式打开,接下来的PRINT-REC FROM将按照不同的报头或定义的数据名称布局写入PRINT-REC。第5和6行的语句将PRINT-REC FROM定义的报头数据名称HEADER-1和HEADER-2写入图3中。图2中的PRINT-REC文件描述符数据名称有效地被图3中报头数据名称的内容替换,写入输出。第7和8行的语句在报头之间写入了一行空白。第9和10行的语句将PRINT-REC FROM定义的HEADER-3和HEADER-4数据名称从图3中写入。图2中的PRINT-REC文件描述符数据名称有效地被图3中报头数据名称的内容替换。

使用VS Code和Zowe Explorer

  1. 提交作业:CBL0004J

  2. 观察报告,其中包括如图6所示的报头。

图6. 带有报头的报告

  1. 提交作业:CBL0005J

  2. 观察报告数据行是没有美元货币符号的,如图7所示。

图7. 输出中没有货币符号

  1. 修改id.CBL(CBL0005)以在报告中包含美元货币符号。

    提示:与CBL0004的第33行进行比较

  2. 重新提交作业:CBL0005J

  3. 观察报告数据行现在应该包含美元货币符号,如图8所示。

图8. 输出中添加了货币符号

\newpage

条件表达式

本章深入探讨了程序如何根据程序员编写的逻辑做出决策。具体来说,程序在源代码的PROCEDURE DIVISION中做出这些决策。我们将通过有用的解释、示例以及最终通过实验来练习实现,扩展关于在COBOL中编写的条件表达式的几个主题。

  • 布尔逻辑,运算符,操作数和标识符

    • COBOL条件表达式和运算符

    • 使用布尔运算符的条件表达式示例

  • 条件表达式保留字和术语

    • IF,EVALUATE,PERFORM和SEARCH

    • 条件状态

    • 条件名称

  • 条件运算符

  • 条件表达式

    • IF ELSE(THEN)语句

    • EVALUATE语句

    • PERFORM语句

    • SEARCH语句

  • 条件

    • 关系条件

    • 类条件

    • 符号条件

  • 实验

布尔逻辑,运算符,操作数和标识符

程序基于程序员编写的逻辑做出决策。程序的决策使用布尔逻辑进行,其中条件表达式要么为真,要么为假,是或否。一个简单的例子是一个名为’LANGUAGE’的变量。有许多编程语言存在;因此,变量LANGUAGE的值可以是Java、COBOL等等…假设LANGUAGE的值是COBOL。布尔逻辑是,IF LANGUAGE = COBOL,THEN DISPLAY COBOL,ELSE DISPLAY NOT COBOL。IF触发布尔逻辑以确定条件真/假,是/否,应用于LANGUAGE = COBOL,这是条件表达式。IF条件的结果在条件为真时执行THEN后面的内容,在条件为假时执行ELSE后面的内容。

布尔IF动词操作两个操作数或标识符。在上面的示例中,LANGUAGE是一个操作数,COBOL是一个操作数。布尔关系运算符比较每个操作数的值。

COBOL条件表达式和运算符

COBOL条件表达式的三种最常见类型是:

  1. 一般关系条件

  2. 类条件

  3. 符号条件

COBOL条件表达式的常见类型的每种类型的COBOL布尔关系运算符列表如下图1、图2和图3所示。

图1. 一般关系条件运算符

图2. 类条件运算符

图3. 符号条件运算符

使用布尔运算符的条件表达式示例

一个简单的条件表达式可以写成:

IF 5 > 1 THEN DISPLAY '5 is greater than 1' ELSE DISPLAY '1 is greater than 5'。

复杂的条件表达式括在括号内,它们的布尔运算符是:

AND

OR

下面的代码片段演示了使用AND布尔运算符的复杂条件表达式。

IF (5 > 1 AND 1 > 2) THEN .... ELSE ....

这个条件表达式的结果为false,因为5 > 1为true,1 > 2为false。AND操作要求两个表达式都为true,才能返回复合条件表达式的true。让我们展示另一种实现,这次使用OR布尔运算符。

IF (5 > 1 OR 1 > 2) THEN .... ELSE ....

这个条件表达式的结果为true,因为1 > 2为false,5 > 1为true。OR操作只需要一个表达式为true,就能返回整个复杂条件表达式的true。进一步讨论用于关系、类和符号条件的更多条件运算符将在本章中进一步讨论。

条件表达式保留字和术语

到目前为止,在本书中,我们已经涉及了COBOL保留字的必要性和用法。本节旨在扩展保留字的主题,特别是在处理条件表达式时使用的保留字。

IF、EVALUATE、PERFORM和SEARCH

这些是COBOL保留字,用于处理条件表达式,其中条件是可以设置或更改的状态。

条件状态

TRUE和FALSE是最常见的条件状态之一。

条件名

条件名是带有TRUE条件状态的程序员定义的变量名。条件名在工作存储段中用88级别号声明。88级别的目的是通过简化IF和PERFORM UNTIL语句来提高可读性。

88级别条件数据名在编译时分配一个值。程序在程序执行期间无法更改88级别数据名。但是,程序可以更改88级别条件数据名上面级别号中的数据名值。示例1中的01级别USA-STATE可以更改。引用88级别数据名的程序表达式仅在前一个级别数据名USA-STATE的当前值等于工作存储的88级别条件数据名分配的值时为真。

请注意,在示例1中,“The State is not Texas”是作为第一个IF STATE的结果编写的,因为USA-STATE的值是AZ,不等于88级别条件数据名TX。第二个IF STATE写入“The State is Texas”,因为USA-STATE的值等于TX的分配的88级别值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
WORKING-STORAGE SECTION.
01 USA-STATE PIC X(2) VALUE SPACES.
88 STATE VALUE 'TX'.
....
....
PROCEDURE DIVISION.
....
....
MOVE 'AZ' TO USA-STATE.
....
....
IF STATE DISPLAY 'The State is Texas'
ELSE DISPLAY 'The State is not Texas'
END-IF.
....
....
MOVE 'TX' TO USA-STATE.
....
....
IF STATE DISPLAY 'The State is Texas'
ELSE DISPLAY 'The State is not Texas'
END-IF.

示例1. 使用88级别条件名

许多88级别的条件数据名可以跟随一个01级别的数据名。因此,对01级别的数据名表达式的IF引用可以具有返回true的许多值。

其他级别号数据名要求条件表达式包括布尔运算符,如示例2所示,其中可以将一个值存储在05级别的STATE数据名中,然后与其他存储的值进行比较。因此,需要进行一些额外的编码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
WORKING-STORAGE SECTION.
01 USA-STATE.
05 STATE PIC X(2) VALUE SPACES.
....
....
PROCEDURE DIVISION.
....
....
MOVE 'AZ' TO STATE.
....
....
IF STATE = 'TX' DISPLAY 'The State is Texas'
ELSE DISPLAY 'The State is not Texas'
END-IF.
....
....
MOVE 'TX' TO STATE.
....
....
IF STATE = 'TX' DISPLAY 'The State is Texas'
ELSE DISPLAY 'The State is not Texas'
END-IF.

示例2. 没有88级别条件名

条件运算符

关系运算符比较数字、字符串或逻辑数据。比较的结果,要么是真(1),要么是假(0),可以用来决定程序流程。表1显示了一些关系运算符,它们的书写方式以及它们的含义。

关系运算符 可以写成 含义
大于 > 大于
不大于 不大于 > 不大于
小于 < 小于
不小于 不小于 < 不小于
等于 = 等于
不等于 不等于 = 不等于
大于或等于 >= 大于或等于
小于或等于 <= 小于或等于

表1. 关系运算符

条件表达式

条件表达式使目标程序根据测试的真值选择控制的替代路径。条件表达式在EVALUATE、IF、PERFORM和SEARCH语句中指定。

IF ELSE(THEN)语句

IF语句用于执行或评估关系操作。 IF ELSE用于编写在两个处理操作之间进行选择的情况,并且THEN关键字是可选的。当存在IF语句时,将根据条件表达式的真假来处理IF语句后面的语句。语句将被处理,直到遇到END-IF或ELSE语句为止。ELSE语句可以出现在END-IF之前的任何行上。IF语句,无论有多少行,都要使用END-IF明确终止。

考虑这种情况,在程序处理期间发生某些事情以更改数据名FACIAL-EXP的值。随后的语句,条件表达式,需要检查数据名的值以决定在程序中如何继续进行。示例3中的THEN DISPLAY和ELSE DISPLAY语句进行了说明。

1
2
3
4
IF FACIAL-EXP = 'HAPPY' THEN
DISPLAY 'I am glad you are happy'
ELSE DISPLAY 'What can I do to make you happy'
END-IF.

示例3. IF、THEN、ELSE、END-IF语句

EVALUATE语句

EVALUATE语句用于编写在三个或更多可能操作中进行选择的情况。EVALUATE语句的显式终止符为END-EVALUATE。EVALUATE语句是IF语句的扩展形式,允许您避免嵌套IF语句,这是逻辑错误和调试问题的常见来源。EVALUATE操作文本字符串值和数值变量。使用FACIAL-EXP条件名,可以在示例4中看到实现EVALUATE语句的COBOL代码。

1
2
3
4
5
6
7
8
9
10
EVALUATE FACIAL-EXP
WHEN 'HAPPY'
DISPLAY 'I am glad you are happy'
WHEN 'SAD'
DISPLAY 'What can I do to make you happy'
WHEN 'PERPLEXED'
DISPLAY 'Can you tell me what you are confused about'
WHEN 'EMOTIONLESS'
DISPLAY 'Do you approve or disapprove'
END-EVALUATE

PERFORM语句

带有UNTIL短语的PERFORM语句是一种条件表达式。在UNTIL短语格式中,所引用的过程将执行,直到由UNTIL短语指定的条件评估为真为止。使用FACIAL-EXP条件名,连续执行SAY-SOMETHING-DIFFERENT段,直到FACIAL-EXP包含’HAPPY’,请查看示例5。

1
2
3
4
5
6
7
8
9
10
WORKING-STORAGE SECTION.
01 FACIAL-EXP PIC X(11) VALUE SPACES.
88 HAPPY VALUE 'HAPPY'.
....
....
PROCEDURE DIVISION.
....
....
PERFORM SAY-SOMETHING-DIFFERENT UNTIL HAPPY
END-PERFORM.

示例5. 使用88级条件名的PERFORM语句

也可以在不使用88级条件名的情况下使用PERFORM语句,如示例6所示。

1
2
3
4
5
6
7
8
9
WORKING-STORAGE SECTION.
01 FACIAL-EXP PIC X(11) VALUE SPACES.
....
....
PROCEDURE DIVISION.
....
....
PERFORM SAY-SOMETHING-DIFFERENT UNTIL FACIAL-EXP = "HAPPY"
END-PERFORM.

示例6. 不使用88级条件名的PERFORM语句

SEARCH语句

SEARCH语句在表中搜索满足指定条件的元素,并调整相关的索引以指示该元素。表实际上是一组值的数组,它们是使用应用于WORK-STORAGE数据名的OCCURS子句创建的。在SEARCH语句中,使用WHEN子句来验证搜索的元素是否满足指定的条件。假设FACIAL-EXP有许多可能的值,那么SEARCH WHEN是另一种条件表达式,如示例7所示。

1
2
3
4
5
6
7
8
9
10
11
12
WORKING-STORAGE SECTION.
01 FACIAL-EXP-TABLE REDEFINES FACIAL-EXP-LIST.
05 FACIAL-EXP PIC X(11) OCCURS n TIMES INDEXED BY INX-A.
88 HAPPY VALUE "HAPPY".
....
....
PROCEDURE DIVISION.
....
....
SEARCH FACIAL-EXP
WHEN HAPPY(INX-A) DISPLAY 'I am glad you are happy'
END-SEARCH

条件

条件表达式可以在简单条件或复杂条件中指定。简单条件和复杂条件都可以包含在任意数量的成对括号中;但是,括号不会改变条件是简单还是复杂。本节将涵盖五个简单条件中的三个条件:

  • 关系

  • 符号

关系条件

关系条件指定了两个操作数的比较。连接两个操作数的关系运算符指定了比较的类型。如果两个操作数之间存在指定的关系,则关系条件为真;如果两个操作数之间不存在指定的关系,则关系条件为假。以下是一些定义的比较列表:

  • 数字比较 - 两个数值类操作数

  • 字母数字比较 - 两个字母数字类操作数

  • DBCS(双字节字符集)比较 - 两个DBCS类操作数

  • 国际比较 - 两个国际类操作数

类条件

类条件确定数据项的内容是否为字母、小写字母、大写字母、数字、DBCS、KANJI,或者是否仅包含由环境部分的SPECIAL-NAMES段中的CLASS子句中指定的字符集中的字符。以下是不同类型数据项的类条件的一些有效形式的列表。

  • 数字

    • IS NUMERIC或IS NOT NUMERIC
  • 字母

    • IS ALPHABETIC或IS NOT ALPHABETIC

    • IS ALPHABETIC-LOWER / ALPHABETIC-UPPER

    • IS NOT ALPHABETIC-LOWER / ALPHABETIC-UPPER

  • DBCS

    • IS DBCS或IS NOT DBCS

    • IS KANJI或IS NOT KANJI

符号条件

符号条件确定数值操作数的代数值是否大于、小于或等于零。无符号操作数要么是POSITIVE,要么是ZERO。当使用带有符号的数值条件变量时,可以使用以下条件:

  • IS POSITIVE

  • IS NEGATIVE

  • IS ZERO

注意: 要获取更多关于这些条件的信息,请访问以下链接:

https://www.ibm.com/docs/en/cobol-zos/6.4?topic=structure-conditional-expressions