控制语言(CL)

概念

CL 程序就是和RPG 相对应的,是控制语言(Control Language)。类型为CLP、CLLE 的源代码编译出来的程序,都属于CL 程序。
CL 程序不像RPGLE 程序,在编写时,可以使用自由格式书写;一行的内容如果太长要,在最末尾处用“+”表示换行

image-20201008104723978

编译此程序(一是,使用 CL 命令 CRTCLPGM,二是,使用PDM 菜单选项 14),然后CALL 之,系统就会执行命令WRKACTJOB,查看当前的活动作业,效果与在交互式命令行下输入WRKACTJOB 是一样的。当我们输入F12,退出WRKACTJOB 时,系统就会继续向下执行,发现是ENDPGM,表示程序结束了,于是判定执行完毕,退出至交互式画面。

CL编程

程序的开始与结束

image-20201008104902668

CL 程序,和RPGLE 程序一样,也可以有程序的入口参数,而且程序的入口参数都是可传递的(也就是输入的参数如果在程序中被修改过,那么原调用的程序中的相应参数也会进行变化。不过CL 的入口参数只能为字符型,或数字型的单个字段,不能象RPGLE 程序中那么多样化(字段、结构、数组、指针)。

如果CL 程序没有入口参数时,那么就可以不需要后面的PARM 语句,直接写成PGM即可。

变量及其定义

CL程序中的所有变量,都使用&做为前缀,这一点与RPG 程序不同。比如说
PGM PARM(&A &B)就表示入口参数为A、B 这两个变量

image-20201008105056460

在CL 程序中使用到的变量,都必须使用DCL 语句来定义:
定义变量FLD01,10 位长的字符型变量,定义变量FLD02,10 长,其中2 位小数的数字型变量。
除了字符、数字之外,CL 程序还可以定义逻辑变量(*LGL),逻辑变量允许的值只为’1’或’0’。
不过通常有字符与数字也就够了。CL 程序的主要功能在于进行命令处理,而不是处理字符串以及数据库

CL程序只能接收15位的decimal类型数值 如果超过十五位 接收会变成10位的char

常用命令

  1. CHGVAR – 变量赋值
    CHGVAR VAR(&FLD01) VALUE(‘ABCD’)

    即是将变量FLD01 赋值成为’ABCD’(左对齐), 同理,VALUE 的括号中也可以填写一个变量,即表示将此变量的值赋值到变量FLD01 中。数字型变量的赋值同样也是使用CHGVAR 语句。
    当变量中只包含数字时(0—9),数字型变量与字符型变量可以使用CHGVAR语句进行转换,这一点与RPGLE 中的MOVE 语句比较类似。

  2. IF – 条件判断语句

image-20201008105310823

当变量FLD01 等于’1’时,将变量FLD02 中的值更改为’0’THEN 后面,即是当符合条件时,要执行的命令。写起来其实没有看上去那么复杂,多用F4 就会发现CL 程序简单。

image-20201008105551399

就比如上例,先写IF,然后按F4,在Condition 处填写条件语句,然后在Command 处填上CHGVAR,再按F4,再去填相应的处理语句,这样写,就比直接把整句抄下来就简单多了。
上面这种写法,只能在符合条件时,执行一条CL 语句;如果要执行多条,就必须写做:

1
2
3
4
IF COND(&FLD01 *EQ '1') THEN(DO)
CHGVAR VAR(&FLD02) VALUE(‘0’)
其它执行语句
ENDDO

ENDDO 在这里和循环没有任何关系,表示的是ENDIF 的意思,但是CL 语句里没有ENDIF,只有ENDDO。

IF 语句中,表示判断的关键字与RPGLE 中的Ifxx 操作码类似,有
*EQ *GT *LT *GE *LE *NE
用来表示逻辑关系的关键字有
*AND, *OR, *NOT

  1. GOTO – 跳转语句

GOTO 语句与RPGLE 中的GOTO 是一样的,都是跳转的意思。
FHSTAG:GOTO CMDLBL(FHSTAG)
注意,这里定义标签是用“:” 冒号

  1. MONMSG – 监控错误信息

我们使用CL 语句时,执行的命令可能会报出一些异常错误,从而导致整个程序中断,需要手工干预。MONMSG 命令可以监控我们预定的错误信息,使CL 程序正常的向下运行。举例而言,
如果CL 程序中有如下语句:

1
2
CALL   PGM(FHS01R)
MONMSG MSGID(CPF4131)

则表示当系统调用程序FHS01R 时,如果发现有CPF4131(声明的文件重新编译过,但程序未重新编译)的错,那么CL 程序将不会异常中断,仅仅只是不运行程序FHS01R,然后继续向下执行CL 程序MONMSG 还可以用于在监控到错误信息之后,进行处理,如下:

1
2
3
CALL PGM(FHS01R)
MONMSG MSGID(CPF4131) EXEC(CHGVAR VAR(&FLD01) +
VALUE('0'))

这句话就表示当发现有CPF4131 的错误之时,将变量FLD01 赋值成为’0’如果要执行多句的话,和IF 语句的方法类似,也是使用DO 与ENDDO

1
2
3
4
MONMSG MSGID(CPF4131) EXEC(DO)
CHGVAR VAR(&FLD01) VALUE(‘0’)
其它处理语句
ENDDO
  1. %SST – 取字符串

CHGVAR VAR(&FLD01) VALUE(%SST(&FLD02 3 1))
表示将字符变量FLD02,从第3 位开始,取1 位,左对齐赋值到变量FLD01 中。%SST 的括号的参数中,第一个参数必须为字符型变量,第二个参数表示起始位,第三个参数表示要截取的长度

  1. *CAT – 拼字符串
1
2
DCL    VAR(&FLD01) TYPE(*CHAR) LEN(10)
CHGVAR VAR(&FLD01) VALUE('A' *CAT 'B')

即表示将10 位长的字符型变量赋值成为’AB ‘

‘A’, ‘B’,也可以使用变量,如

1
CHGVAR VAR(&FLD01) VALUE(&FLD02 *CAT &FLD03)

要注意,*CAT 不能去掉字符串末尾的空,从效果上来看,有点类似于RPGLE 中的EVAL 操作码,而不是CAT 操作码

  1. 读取文件
1
2
3
4
DCL VAR(&FLD01) TYPE(*CHAR) LEN(2)
DCLF FILE(FHSLIB/PFFHS)
RCVF
CHGVAR VAR(&FLD01) VALUE(&FHS01)

以上这段CL 的意思,就是在CL 程序中读取PFFHS 文件,然后将读到的第一条记录赋值到CL 的临时变量FLD01 中。
如果要将一个文件从头读到尾,则可以用如下语句来实现:

1
2
3
4
5
6
7
DCLF FILE(FHSLIB/PFFHS)
LOOP:
RCVF
MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(EXIT))
读取到每条记录后的处理语句
GOTO CMDLBL(LOOP)
EXIT:

也就是说,信息CPF0864,即表示未读取到记录。
在CL 程序中声明文件使用DCLF 语句,一个CL 文件中只能声明一个文件,声明语句必须在CL 控制语句之前。使用声明的文件中的字段,同样需要在字段名前加上“&” ;
CL 程序中,无法控制游标,无法对记录进行定位操作。所以CL 程序对文件的操作是比较弱的,

CL过程的组成部分

做为 CL 过程,每部分的源语句实际上都是一个 CL 命令,在典型的 CL 过程中它可以分成下列
几个基本部分:

PGM 命令PGM PARM(&A)这是一个可选值,表示过程的开始及可接收的参数
说明命令(DCL,DCLF)在使用变量时,说明命令要放在除 PGM 命令之外的所有命令前面
CL 处理命令CHGVAR,SNDPGMMSG,OVRDBF,DLTF……用来管理常量及变量
逻辑控制命令IF,THEN,ELSE,DO,ENDDO,GOTO用来控制过程内部的处理
内部函数%SUB,%SWICH,%BIN用于计算、关系或逻辑表达式
程序控制命令CALL,RETURN用来把控制传递给其它程序
过程控制命令CALLPRC,RETURN用来把控制传递给其它过程
ENDPGM 命令ENDPGM这是可选的,表示程序的结束

以上命令使用的顺序、组合及扩展都依据应用程序的逻辑和设计。在生成过程、处理命令时,引用的对象必须已经存在。

变量的使用

变量说明

使用 DCL 命令来定义变量及其属性、长度和初值。标准格式如下:

1
2
3
                     * CHAR
DCL VAR (变量名) TYPE * DEC LEN (长度) VALUE(初值)
* LGL

使用 DCL 命令时,必须遵循的规则如下:

  1. CL 变量名必须以 & 开始,后跟字符不多于 10 个,& 后的第一个字符必须是字母,其
    余的可以是字母或数字。
  2. CL 变量值必须是:字符型最长为 9999 个字符;数值型为压缩十进制数,最长为 15 位,
    其中小数位最长为 9 位;逻辑型为“0”或“1”,表示假或真。
  3. CL 变量的缺省初值为:字符型为空,数值型为 0,逻辑型为“0”。
  4. 对于字符型和数值型,如果指定了初值而未指定长度,则缺省长度为初值长度。

变量值中小写字符的限制

用作变量的保留值必须用大写字母表示,特别是当它们用引号括起来的时候。例如:

1
2
DCL VAR(&LIB) TYPE(*CHAR) LEN(10) VALUE(‘*LIBL’)
DLTPGM &LIB/MY PROG

注意:如果 VALUE 参数不使用引号,则小写是正确的。因为使用 SEU 编辑会自动转换成大写。

变量赋值

使用 CHGVAR 命令给变量赋值,其值可改变成:

  1. 常量: CHGVAR VAR(&A) VALUE(0)

  2. 变量: CHGVAR VAR(&A) VALUE(&B)

  3. 计算量:CHGVAR VAR(&A) VALUE(&A+1)

  4. 函数量:CHGVAR VAR(&A) VALUE(%SST(&B 1 5))
    CHGVAR VAR(%SST(&A 1 5)) VALUE(&B)

赋值时应注意以下几点:

  1. 对逻辑变量,被改变的值必须是一个逻辑值。
  2. 对数值变量,只能赋予十进制数,或者数字字符变量(包括小数点和正负号)。
  3. 对字符变量,既可接受字符,也可接受十进制数。赋十进制数时,该字符变量的值是右对齐,
    前导补零,负号放在最左边。

使用goto命令及标号

GOTO 命令处理无条件转移,无论什么时候遇到 GOTO 命令,都要直接执行过程中的另一部分(用一个标号指出),这种转移不依赖表达式的求值。

转移到标号指定的语句后,从这个语句开始,继续顺序处理。它不返回到 GOTO 命令处,除非由另外指令特别指定返回。可以往前或向后转移,不能用GOTO 语句走到过程外的标号处。GOTO 命令没有参数,它只包含要转移语句的标号:
GOTO CMDLBL(标号)
标号标识过程中的语句,指出 GOTO 命令执行的方向,要使用 GOTO 语句,要转移的去处必须有一个标号:

1
2
3
4
5
6
7
8
9
10
11
		PGM
.
.
START: SNDRCVF RCDFMT(MENU)
IF (&RESP=1) THEN(CALL CUS210)
.
.
GOTO START
.
.
ENDPGM

此例中,标号是 START,标号最多 10 个字符,结尾必须有冒号,命令名和标号之间有空格

使用IF指令

IF 命令用来设置一个条件。如果为真,要规定在过程中运行的语句或一组语句,与 IF 一起可以规定 ELSE 命令,来规定条件不为真时执行的语句。命令包括一个表达式(它用来测试真、假)和一个 THEN 参数,它现定表达式为真时要采取的动作,IF 命令的格式为:

1
IF COND(逻辑表达式) THEN(CL 命令)

如果逻辑表达式的条件为真,处理 THEN 参数中的命令,它可以是一个命令,也可以是一组命令,如果条件不为真,运行下一个顺序的命令。COND 和 THEN 都是命令的键字,它们可以省略。下面是正确的写法:

1
2
3
IF COND(&RESP=1) THEN(CALL CUS210)
IF (&A *EQ &B) THEN(GOTO LABEL)
IF (&A=&B) GOTO LABEL

在IF和键字或值(&A…)之间要有空格,在键字之间不允许有空格,如果有,用左边的括号括住值

使用DO命令和DO组

DO 命令处理一组命令,这一组命令是用 DO 和 ENDDO 之间的命令组成的,这组命令的处理通常是以有关命令为条件的。它经常与 IF、ELSE 或 MONMSG 一起使用。

image-20201008112440634

如果逻辑表达式(&A=&B)为真,则执行 DO 组,如果不为真,则跳过 DO 组,处理 ENDDO 后的命令。

image-20201008112511915

DO 组也能嵌入到另外的 DO 组中,最多可嵌套 10 层,下例中有三层,注意每个 DO 组都由ENDDO 结束。

image-20201008112537771

使用else语句

image-20201008112718245

使用嵌套的 IF 命令

在 CL 程序设计中可允许 10 层嵌套。

使用*AND、*OR、和*NOT 操作

*AND 和*OR 是逻辑操作的保留值,用来表示逻辑表达式操作之间的关系。*AND 可以用&表示,
*OR 可以用¦表示,后边必须有一空格。

除逻辑操作符外,有三类操作符:
_ 算术 (+, -, *, /)
_ 字符 (*CAT, ||, *BCAT, |>, *TCAT, |<)
_ 关系 (*EQ, =, *GT, >, *LT, <, *GE, >=, *LE, <=, *NE, ?=, *NG,?>, *NL, ?<)

image-20201008113012943

系统资源的获取

日期格式转换命令:CVTDAT

检索系统值命令:RTVSYSVAL

检索配置源命令:RTVCFGSRC

配置状态检索命令:RTVCFGSTS

检索网络属性的命令:RTVNETA

检索作业属性命令:RTVJOBA

检索对象描述命令:RTVOBJD

检索用户档案命令:RTVUSRPRF

程序间的通讯

程序间的通讯是指不同程序之间数据或参数的传递和交流。这种通讯可以出现在不同种类的程序中。如:RPG 与 C 语言,也可以出现在不同机器上,如:PC 与 AS/400。针对 OS/400 而言,通常程序间的通讯具有三种方式:

  • CALL、RETURN 命令
  • 数据队列通讯
  • 数据域通讯

CALL 命令的使用

调用程序: CALL PGM(PGMA) PARM(&A &B)
被调用程序:PGM PARM(&C &D)
有关 CALL 命令使用的几点说明:

  1. 参数值可以是字符常量、数值常量、逻辑常量或 CL 常量,最多可达 40 个。
  2. 参数值以 CALL 命令中出现的顺序传送,这必须与被调用程序的参数顺序相匹配,变量
    名不一定相同。
  3. 被调程序中的接收参数必须说明,但接收值不受变量说明中初值的影响。
  4. 接收参数值的改变会反映到调用程序中,但常量传送不会改变。
  5. 字符常量通常以 32 个字节传送,数字常量以 15.5 长度压缩格式传送。