RPG操作码汇总

ACQ {(E)} (Acquire)

取地址位。其实400 的程序中也有指针型变量,那么也就会有地址位,这个命令是取地址位的。
ADD {(H)} (Add) 加法操作

  1. 基本语法:
1
2
Factory1 Operation Factory 2 Result
FHS01 ADD FHS02 FHS03 // RPG 的语法

等价于

1
EVAL FHS03=FHS01+FHS02 //RPGLE 的语法

FHS01、FHS02、FHS03 必须都为数字型变量(P 型,或S 型),或者就是数字意思是将Factory
1 项的数据,加上Factory 2 项的数据,赋值到Result 项上

  1. 语法二:
    如果这样写的话:

    1
    2
    Factory1 Operation Factory2 Result
    ADD FHS02 FHS03

    就等价于:
    EVAL FHS03=FHS03+FHS02
    即Factory 1 项未填时,就表示将Result 项的数据,加上Factory 2 项的数据,然后赋值到Result 项上

  2. 四舍五入:
    (H)表示四舍五入,如FHS02=12.50(4,2),FHS03=3(2,0),那么

    1
    ADD(H) FHS02 FHS03执行之后,FHS03=16(因为进位了)

    1
    ADD FHS02 FHS03

    执行之后,FHS03=15
    不过实际使用中,我们都尽可能使相加的字段小数位数相等,所以ADD 操作码一般都没有使用到四舍五入的功能。

  3. 可以在ADD 操作时,对Result 项的变量进行定义

    1
    2
    Factory 1 Operation Factory 2 Result
    FHS01 ADD FHS02 FHS03 10 2

    EVAL 语句不能对在赋值的同时,对变量进行定义

  4. 关于结果数据超长时的问题:
    当加出的结果超长,比如FHS03 定义为3,2(1 位整数,2 位小数,下同)时,再假设FHS01=10,FHS02=4。那么FHS01+FHS02 本来应该等于14,但用ADD 操作之后,系统会自动将超长位截去,即FHS03 最后等于4;
    而用EVAL 语句时,系统判断超长后,会直接报错“The target for a numeric operation is too small to hold the result”,然后异常中断。
    使用ADD 操作码程序不会异常中断,但有可能发生了错误的数据我们也不知道;使用EVAL 操作码可以避免产生错误的数据,但程序会异常中断,需要进行人工干预。可根据实际情况选择使用ADD 还是EVAL.

ADDDUR {(E)} (Add Duration) 日期时间相加

  1. 对日期型变量进行加操作,比如说已定义日期型变量MYDATE1,MYDATE2,将
    MYDATE1 的日期加上3 天,赋值到MYDATE2 中:
    1
    2
    Factory 1 Operation Factory 2 Result
    MYDATE1 ADDDUR 3:*D MYDATE2
    其中,Factory 1,Result 项,都必须为日期型变量(即在D 行,Internal Data Type项为“D” )
  2. 与ADD 操作码相同,Factory 1 项为空时,表示直接在Result 项上进行日期相加,如将
    MYDATE1 直接加上3 个月(即结果也是赋值到MYDATE1 中):
    1
    2
    Factory1 Operation Factory2 Result
    ADDDUR 3:*M MYDATE1
  3. 日期型变量的参数含义:
  • *D表示天,也可用*DAYS
  • *M表示月,也可用*MONTHS
  • *Y表示年,也可用*YEARS
  1. 除了日期型之外,还有时间型,日期时间型,都可以使用ADDDUR 操作码.
    在D 行,Internal Data Type 定义为“T”,表示时间型(时、分、秒)Internal Data Type 定义为“Z”,表示日期时间型(年、月、日、时、分、秒、微秒)在使用ADDDUR 操作码,时间型的参数如下:
  • *H 表示小时,也可用*HOURS
  • *MN 表示分钟,也可用*MINUTES
  • *S 表示秒, 也可用*SECONDS
    而日期时间型,除了可以使用*Y、*M、*D、*H、*MN、*S(以及相应的全称)之外,还可以对微秒进行处理,参数为*MS,或*MSECONDS
  1. Factory 2 项中的数字,可以使用负数,使用负数时,表示减去相应的年、月、日,不过
    通常使用SUBDUR 来进行日期的减法,语法与ADDDUR 相同

ANDxx (And) 条件判断语句—“与”

  1. 在RPG 的用法中,有ANDEQ,ANDNE 之类的,与IF 语句一起联用。
    1
    2
    3
    Factory1 Operation Factory 2 Result
    FLD01 IFEQ ‘A’
    FLD02 ANDEQ ‘B’
    。。。处理内容
    ENDIF
  2. AND 后面跟的xx,可以有如下用法:
    EQ Factory 1 = Factory2
    NE Factory 1 <> Factory2
    GT Factory 1 > Factory2
    LT Factory 1 < Factory2
    GE Factory 1 >= Factory 2
    LE Factory 1 <= Factory 2

BEGSR (Beginning of Subroutine) 子过程的开始处

BEGSR 子过程名
在前面,讲述程序流程时,已经对子过程进行了解释。这里,BEGSR 本身用法没什么特别的,只是要注意有BEGSR 语句,就一定要有ENDSR 对应。否则程序编译会报错。所以这里建议,免遗漏。
在程序中,可以写一个子过程,但是不调用它。(也允许就是子过程没有相应的EXSR语句)也
允许写一个空的子过程。(也就是BEGSR 语句与ENDSR 语句之间没有别的执行语句了)

CALL {(E)} (Call a Program) 调用外部程序

1
2
Factory1 Operation Factory 2 Result
CALL ‘外部程序名’
  1. 如果是直接调用外部程序,那么程序名称需要用单引号括起来,且该程序必须存在。如
    CALL ‘FHSILE01’
    就表示调用“FHSILE01”这个外部程序

  2. 如果没有用单引号,如
    CALL FHSILE01
    就表示,FHSILE01 这时是个字符型变量(即并非调用“FHSILE01 这个程序),调用的是
    变量内容所代表的程序。如:
    FHSILE01=’FHS01’时,表示调用“FHS01”这个外部程序;
    FHSILE01=’FHS02’时,表示调用“FHS02”这外外部程序
    也就是说,CALL 操作码调用的程序名,可以是一个变量名。

  3. 被调用的外部程序如果有接口参数,那么CALL 操作码之后,也需要有“PARM”操作码相对应。

  4. 这一点要注意:虽然400 的程序段代码中,是不区分大小写;但调用的程序名,要区分大
    写小。即’FHSILE01’,与fhsile01,表示的是两个不同的程序。在使用时要注意,尤其
    是程序名使用字符变量来表达时,可能会因为大小写的问题而导致 CALL 不到想CALL 的程
    序,从而导致程序异常中断

CASxx (Conditionally Invoke Subroutine) 带条件的调用子过程

  1. 表示根据xx 项对Factory 1 与Factory 2 进行判断,当符合条件时,执行Result 处的子
    过程。需要配合“END”或“ENDCS”语句来表示条件判断的结束。不需要“SELECT”操作
    码。
  2. 举例如下:
    1
    2
    3
    4
    5
    Factory 1 Operation Factory 2 Result
    FLD01 CASEQ ‘1’ SUB01
    FLD01 CASEQ ‘2’ SUB02
    CAS SUB03
    ENDCS
    表示当FLD01 等于’1’时,执行子过程SUB01;
    当FLD01 等于’2’时,执行子过程SUB02;
    当不满足以上两个条件时,执行子过程SUB03
    最后的“ENDCS”必须要有,表示条件判断结束;但不需要SELECT。上面这段语句,与下面
    这一段是等价的:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Factory 1 Operation Factory 2 Result
    SELECT
    WHEN FLD01=’1’
    EXSR SUB01
    WHEN FLD01=’2’
    EXSR SUB02
    OTHER
    EXSR SUB03
    ENDSL
  3. 可以看出来,CASxx 这种语句,是用于逻辑判断仅一个条件时的分支处理,这样的写法在代
    码的阅读上会很直观。而当逻辑判断大于一个条件时,这个语句就不适用了。

CAT {(P)} (Concatenate Two Character Strings) 字符连接

  1. 基本语法:
    Factory 1 Operation Factory 2 Result
    FLD01 CAT FLD02:0 FLD03
    这句话的意思,是将FLD02 拼在FLD01 后面,中间没有空格,然后将拼出的结果赋值到FLD03
    中。
    FLD02:0,表示FLD02 与FLD01 之间的空格数为0,依此类推
    FLD02:1,就表示FLD01 后面加一个空格,再拼上FLD02
    FLD02:3,就表示FLD01 后面加三个空格,再拼上FLD02
    Factory 1 项,与Factory 2 项可以是字符型变量,也可以就是字符。当是字符时,需要
    用单引号将字符括起来
  2. 其实根据RPG 的语法,Factory1 项如果不填值,就表示将Factory 2 项的内容直接拼在Result 项上,这里就不举例了。
  3. 字段FLD01 如果内容后面有空格,如“ABC ”,那么在CAT 操作时,系统会自动将后面的空格截去,只取’ABC’。举例:
    FLD01=’ABC ‘ (8 位字符型),
    FLD02=’1’ (1 位字符型),
    FLD03=’’ (8 位字符型)
    那么,执行了下述语句之后
    FLD01 CAT FLD02:0 FLD03
    FLD03 就等于’ABC1 ’
    而如果执行:
    FLD01 CAT FLD02:1 FLD03
    FLD03 就等于’ABC 1 ‘ (C 与1 之间有一个空格)
  4. 表示空格个数时,可以使用数字型的变量来表达,如
    EVAL N=1
    FLD01 CAT FLD02:N FLD03
  5. CAT 操作码,其实也可以通过EVAL 来实现部分。比如将FLD01 与FLD02 拼起来,中间无空格,赋值到FLD03 中,也可以写做:
    EVAL FLD03=FLD01 + FLD02
  6. EVAL 操作码的优势,在于可以在一行语句中,就把多个字符拼在一起,如:
    EVAL FLD05=FLD01+FLD02+FLD03+FLD04
  7. EVAL 操作码的不足之处,在于只能进行最简单的拼接,无法自动将字符后面的空格去除,如:
    FLD01=’ABC ‘ (8 位字符型),
    FLD02=’1’ (1 位字符型),
    FLD03=’’ (8 位字符型)
    在执行语句EVAL FLD03=FLD01+FLD02
    后,
    FLD03=’ABC ‘
    因为FLD01 是8 位,FLD03 也是8 位,在操作时,不能去掉ABC 后面的5 位空格,此时后面再
    拼FLD02 已无意义,所以FLD03 仍是’ABC ‘

CHAIN {(N | E)} (Random Retrieval from a File) 按键值对文件记录进行查询定位

  1. 基本语法:
    举例,对逻辑文件PFFHSL1 进行定位操作。逻辑文件PFFHSL1,是以FHS01 为键值,文件记
    录格式名叫FMTFHS

    1
    2
    Factory 1 Operation Factory 2 Result HI LO EQ
    FHS01 CHAIN FMTFHS 17 18

    这个例子中,FHS01 应该是一个与文件PFFHSL1 中键值(FLD01)类型、长度都
    相等的一个字符型变量,或者字符。
    Factory 2 项中,要填文件的记录格式名,而不是文件名
    HI 指示器表示是否查询到相应记录,查询不成功时,打开HI 指示器
    LO 指示器表示查询时,文件是否被锁。文件被锁时,打开LO 指示器
    也就是说:
    *IN17=’0’,表示查询到了对象记录。
    *IN17=’1’, *IN18=’0’,表示无相应的对象记录
    *IN17=’1’, *IN18=’1’, 表示查询时,文件被锁(不确定有没有相应的对象记录)

  2. 用修改方式声明的文件,当查询成功后,对象记录被锁定,其它程序无法以修改的方式定位
    到当前对象记录上。(但可以用只读的方式定位)

  3. LO 指示器,仅于用修改方式声明的文件。对于只读方式声明的文件其实无意义

  4. 如果用修改方式声明文件,但在LO 处未填写指示器,且有程序锁住对象记录时,当前程序会根据PF 中定义的WAITRCD(Maximum record wait time)参数,等待相应的秒数(如WAITRCD处为10,即表示锁表时,等待10 秒;如果填的是*IMMED,就表示不等待,一判断对象记录被锁就结束操作);如果在等待时间内,对方仍未解锁,当前程序就会异常中断退出;如果LO 处填写指示器,那么程序就不会中断退出,且LO 指示器打开。

  5. 当FHS01 键值,在文件PFFHSL1 中,对应有多条记录时(即键值不唯一),程序将会按照文件的内部记录号由小到大的顺序,定位到符合条件的第一条记录。

  6. 当一个逻辑文件,KEY 值有多项时,可以使用KLIST 操作码先定义一个组合键值,然后再用
    这个组合键值来进行CHAIN 操作。需要注意,组合键值中,必须每一个成员字段都与对象记录
    所对应的字段相等,才能查询成功。(所以组合键值,通常使用SETLL 定位较多)

  7. 当用修改方式声明文件,但希望进行不锁记录的查询操作时,可以将CHAIN 操作码写为CHAIN(N),这个括号(N),就表示当前的查询定位,不对记录进行锁定操作(也就是用只读的方式来处理对象记录,所以只能取出对象记录的信息,不能做修改;如果要修改对象记录的话,还必须进行一个CHAIN 操作)

  8. 这一条要特别注意:当没有填写HI 指示器时,RPGLE 是允许编译通过的。而在某些情况之下,运行程序时,如果CHIAN操作成功,找到了符合条件的记录时,没有任何问题;但如果CHAIN 操作没有找到符合条件的记录时,实际上系统会按照键值的排序以及内部记录号,定位到下一条记录上,这时再取出来的数据,就统统都是下一条记录的数据。所以,除非有绝对的把握,CHAIN 操作肯定成功,否则就一定要养成填写HI 指示器的良好习惯。

CHECK {(E)} (Check Characters) 检查对象变量中的字符

  1. 基本语法:
    1
    2
    Factory 1 Operation Factory 2 Result HI LO EQ
    FLD01 CHECK FLD02:2 N 42
    语句CHECK 的意思,是指字段FLD02 中,从第二位字符开始,向右查找(含第二位字符),是否包含有FLD01 中没有的字符。
    如果的确有在FLD01 中没有的字符,将字符所在位置赋值到变量N 中,同时打开EQ 指示器;\如果从第二位字开始,向右读取的所有字符,都可以在变量FLD01 中找到,那么N 为0,EQ
    指示器处于关闭状态。
    “FLD02:2”表示从变量FLD02 的第二位开始,向右作比较。如果仅仅只是“FLD02”,那么就表示从变量FLD02 的首位开始,向右查找
  2. 实例
    假设FLD01 为8 位长字符,且当前值为’12345678’
    而FLD02 为5 位长字符,且当前值为’A3456’
    那么执行上述CHECK 操作后,N=0, *IN42=’0’(从第二位开始,3456 都存在于变量FLD01
    中)
    假设FLD01 为8 位长字符,且当前值为’12345678’
    而FLD02 为5 位长字符,且当前值为’34ABDC’
    那么执行CHECK 操作后,N=3 *IN42=’1’ (即第三位“A”, 不存在于变量FLD01 中)

CHECKR {(E)} (Check Reverse) 反向检查对象变量中的字符

  1. 基本语法:

    1
    2
    Factory 1 Operation Factory 2 Result HI LO EQ
    FLD01 CHECKR FLD02:3 N 42

    语句CHECKR 的意思,是指字段FLD02 中,从第三位字符开始,向左查找(含第三位字符),是否包含有FLD01 中没有的字符。(基本与CHECK 类似,所不同的,就是CHECK 是自左向右的查找;而CHECKR 是自右向左查找)如果有,将字符所在位置赋值到变量N 中,同时打开EQ 指示器;如果从第二位字开始,向左读取的所有字符,都可以在变量FLD01 中找到,那么N 为0,EQ指示器处于关闭状态。“FLD02:3”表示从变量FLD02 的第三位开始,向左作比较。如果仅仅只是“FLD02”,那么就表示从变量FLD02 的末位开始,向左查找

  2. 实例
    假设FLD01 为8 位长字符,且当前值为’12345678’而FLD02 为5 位长字符,且当前值为’23A56’
    那么执行上述CHECK 操作后,N=0, *IN42=’0’(从第三位开始,向左,23 都存在于变量FLD01 中)
    假设FLD01 为8 位长字符,且当前值为’12345678’
    而FLD02 为5 位长字符,且当前值为’BC3B45’
    那么执行CHECK 操作后,N=2,*IN42=’1’ (即第二位“C”,不存在于变量FLD01中)

  3. 计算字符实际长段
    根据CHECKR 的这个操作码的用法,我们可以使用它来取出变量截去尾部空格后的实际长度:
    Factory 1 Operation Factory 2 Result HI LO EQ
    ‘ ‘ CHECKR FLD02 N 42
    Factory 1 项,是一个空格字符。
    N 表示的意思是:从变量FLD02 的尾部,向前数第一个非空格字符,在FLD02 中所处的位置。
    那么这个N 当然就是变量FLD02 的实际长度;
    如果指示器未打开,那么说明整行都是空,实际长度为0,也没错。

CLEAR (Clear) 清除内容

  1. 基本语法
    1
    2
    Factory 1 Operation Factory 2 Result
    CLEAR 对象名
    这个对象名,可以是程序中定义的结构、文件的记录格式名。
    所谓文件的记录格式名,包括了程序中声明的磁盘文件、打印报表文件、屏幕文件CLEAR操作的意思,就是将对象所对应的所有变量/字段都赋上空值

CLOSE {(E)} (Close Files) 关闭文件

  1. 基本语法
    1
    2
    Factory 1 Operation Factory 2 Result
    CLOSE 对象文件名
  2. CLOSE 所对应的,是文件名,不是文件的记录格式名,要注意
  3. CLOSE 操作码,仅适用于声明文件时,keyword 使用“USROPN”关键字的文件
  4. 每一个CLOSE 的操作,在之前都必须有OPEN 文件的操作。也就是,文件必须打开了之后,才能关闭。不能关闭未打开的文件
  5. 允许使用*ALL 变量,来表达关闭所有已打开的文件:

COMMIT {(E)} (Commit) 日志事务处理的确认操作

  1. 基本语法
    1
    2
    Factory 1 Operation Factory 2 Result
    COMMIT
  2. 该操作码无其它参数,就是指对事务处理进行确认操作。
  3. ILE 程序中,COMMIT 操作可随时进行,也允许在没有声明COMMIT 类型的文件的情况下,仍进行COMMIT 操作(对该进程这前的事务进行确认处理)
  4. 关于日志的确认操作,在后面会另设专门章节讲述

COMP (Compare) 比较

  1. 基本语法:
    将Factory 1 与Factory 2 进行比较。
    当Factory 1 > Factory 2 时,打开HI 指示器;
    当Factory 1 = Factory 2 时,打开LO 指示器;
    当Factory 1 < Factory 2 时,打开EQ 指示器。
    1
    2
    Factory 1 Operation Factory 2 Result HI LO EQ
    FLD01 COMP FLD02 56 57 58
    当FLD01=2,FLD02=1 时,*IN56=’1’, *IN57=’0’, *IN58=’0’
    当FLD01=2,FLD02=2 时,*IN56=’0’, *IN57=’0’, *IN58=’1’
    当FLD01=1,FLD02=2 时,*IN56=’0’, *IN57=’1’, *IN58=’0’

DEFINE (Field Definition)

根据已知的字段,来定义新字段,如下:

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
*LIKE DEFINE FLD01 FLD02

这句话的意思,就是说“象定义字段FLD01 一样,定义字段FLD02 的类型、长度”这个字段FLD01,必须是个已定义的字段/变量

DELETE {(E)} (Delete Record)

删除当前记录,语法如下:

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
DELETE 文件记录格式名

这里,在做DELETE 操作前,必须先定位到具体的记录上(使用CHAIN、READ 等语句);同时,文件在F 行必须使用修改的方式来声明。当文件定位到对象记录时,对象记录会被锁定,此时,对象记录无法被其它程序修改;

如果执行了DELETE 操作,自然会解锁,不过别的程序也找不到对象记录了(因为被删除)实际使用中,通常并不会对文件中的记录进行物理删除,而是修改某个标识状态的字段的值,所以使用这条命令要慎重

DIV {(H)} (Divide) 数学运算—除

DIV 操作码,表示数学运算的“除”,常与操作码MVR 一起来使用。

1
2
3
Factory 1 Operation Factory 2 Result HI LO EQ
FLD01 DIV FLD02 N
MVR M

上面两句话的意思,是说,用FLD01 来除FLD02,将商赋值到变量N 中,将余数,赋值到变量中。
(N,M 都是数字型变量)再具体一点,如果FLD01 = 10, FLD02 = 3,执行完这两句操作码之后
N = 3 (10 / 3 的商)
M = 1 (10 / 3 的余数)

DO (Do) 循环

最常用的循环方法之一,适用于已知循环次数的循环,与ENDDO 搭配使用,每一个DO,必须要配合一个ENDDO。基本语法如下

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
1 DO 10

循环中处理的内容
ENDDO
上面的意思,就是说固定循环10 次。
不过呢,在实际使用中,我们常常需要知道当前循环到了第几次处理,这里,可以:

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
1 DO 10 N

处理过程
ENDDO
这个N,是一个整数型变量(小数位为0 的P 型吧),它所表示的就是循环的次数。如第一次循环,N=1;第二次循环,N=2所以, 1 DO 1,就表示只循环一次,而不是表示死循环。

DOU {(M | R)} (Do Until) 还是循环

也是循环,不过当满足Extend Factory 2 项的条件之后,结束循环。如下:

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
DOU FLD01>FLD02

处理过程
ENDDO
上面这句话,就是说当FLD01 小于或等于FLD02 时,进行循环;当满足条件,即FLD01大于FLD02时,结束循环。在RPGLE 的写法中,这个条件可以写得很复杂。当然,很复杂的时候,要记得多括号,以免得逻辑判断与设计不一致。

DOUxx (Do Until) 又是循环

这应该是RPG 的写法,上面的循环也可以写做:

1
2
FLD01 DOUGT FLD02
ENDDO

不过,正如果前面所说的“ANDxx”操作码一样,RPGLE 的表示手法可以比RPG 更直观,更好维护,所以这里也是一样的原理,有了“DOU”之后,我们就可以不用“DOUxx”了

DOW {(M | R)} (Do While) 循环,又见循环

这个循环的意思,与DOU 正好相反,它的意思是满足Extend Fatcory 2 项的条件时,才进行循环,不满足条件时,不循环

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
DOW FLD01>FLD02

处理过程
ENDDO
上面这句话,就是说当FLD01 小于或等于FLD02 时,不进行循环循环;当满足条件,即FLD01 大于FLD02 时,才进行循环。在RPGLE 的写法中,这个条件可以写得很复杂。当然,很复杂的时候,要记得多用括号,以免得逻辑判断与设计不一致。
注意:在实际使用过程中,我常常只使用DO,DOW 这两种循环。而且使用DOW 时,常常使其条件永远成立(即死循环,比如说1=1 就永远成立,那么 DOW 1=1 就是个死循环),然后在循环体中用IF 语句判断何时退出循环(使用LEAVE 语句),我认为这样会比较直观,而且很少会在逻辑上出错。
DOWxx (Do While) 最后一个循环了
跟 DOU 与DOUxx 的关系一样,有了DOW 之后,就不需要DOWxx 了,不多说了。

DSPLY {(E)} (Display Function) 屏幕显示

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
FLD01 DSPLY

就是在屏幕上,显示FLD01 的内容。FLD01 可以是字符、数字型变量。也可以直接就是字符、数字。
ELSE (Else) 逻辑判断语句
常见用法:
Factory 1 Operation Factory 2 Result HI LO EQ
IF 条件判断
处理内容一
ELSE
处理内容二
ENDIF

不满足条件判断的时候,就执行ELSE 与ENDIF 之间的处理内容二;
满足条件判断时,执行IF 与ELSE 之间的处理内容一。
IF 与它最临近的ELSE、ENDIF 配对;
同理,ELSE 也是与它最临近的IF、ENDIF 配对。
注意多层IF 嵌套时的逻辑判断,这个要自己多尝试,不讲了。
ELSEIF {(M | R)} (Else/If) 逻辑判断语句
与ELSE 类似,不过将条件判断语句也写在了同一行。
ELSEIF 不需要相应的ENDIF 语句。即
IF 条件判断1
处理内容一
ELSEIF 条件判断2
处理内容二
ELSE
处理内容三
ENDIF
当程序满足条件判断1,将执行IF 与ELSEIF 之间的处理内容一;
当程序不满足条件判断1,满足条件判断2,执行ELSEIF 与ELSE 之间的处理内容二;
当程序连条件判断2 的内容都不满足时,执行ELSE 与ENDIF 之间的内容处理内容三。
也就是说,这时的ELSE,是和ELSEIF 进行配对的,要注意。
ENDyy (End a Structured Group)
ENDIF 对应 IF、IFxx
ENDSR 对应 BEGSR
ENDDO 对应 DO、DOW、DOU、DOUxx、DOWxx
ENDSC 对应 CASxx
ENDSL 对应 SELECT
ENDFOR 对应 FOR
ENDSR (End of Subroutine) 子过程结束语句

EVAL {(H | M | R)} (Evaluation) 赋值语句

  1. 基本语法:

    1
    2
    Factory 1 Operation Factory 2 Result HI LO EQ
    EVAL FLD01=FLD02

    赋值,使用FLD01 的值,等于FLD02 的值。FLD01 与FLD02 的类型必须相同(即
    同为字符型,或同为数字型,但长度可以不同。

  2. 当FLD01、FLD02 同为字符型时,EVAL 语句其实等价于:

    1
    2
    EVAL FLD01=\*BLANKS
    MOVEL FLD02 FLD01

    即先清空FLD01(当FLD01 长度长于FLD02,且有初始值时,这个操作就有意义了),然后再将FLD02 左对齐赋值到FLD01 中。所谓左对齐的含义,就是说将FLD02 至左向右(含空字符),依次向FLD01 字段中赋值。当FLD02 长度大于FLD01 时,右边的字符在赋值时将会被截去。

  3. 当FLD01、FLD02 同为数字型时,且FLD02 的值,超过FLD01 的长度时,EVAL语句会直接报错,程序异常中断;

  4. 当FLD01、FLD02 同为字符型时,且FLD01 的长度大于FLD02 时,将会将FLD02的值左对齐赋值到FLD01 中,并且将后面内容全部清空。
    比如FLD01=’12345678’(8 位字符型),FLD02=’54321’(5 位字符型)执行了 EVAL FLD01=FLD02
    之后,FLD01=’54321 ‘

  5. 当FLD01、FLD02 同为字符型,且FLD01 的长度小于FLD02 时,会将FLD02 的内容左对齐,再赋值到FLD02 中。

  6. 字符的拼接:

    1
    2
    Factory 1 Operation Factory 2 Result HI LO EQ
    EVAL FLD01=FLD02+FLD03+’AAA’+’BB’+FLD04

    FLD01、FLD02、FLD03、FLD04 都必须是字符。FLD02、FLD03 如果字符未满,有空格,EVAL 操
    作码不会将空格去掉。如果太长,可以分多行写,“+ ”在上在下都可。即

    1
    2
    EVAL FLD01 = FLD02 +
    FLD03

    等价于

    1
    2
    EVAL FLD01 = FLD02
    + FLD03
  7. 数学运算:
    Factory 1 Operation Factory 2 Result HI LO EQ
    EVAL FLD01 =(((LD02+FLD03)* FLD04) / 2) - FLD05
    加、减、乘、除都在了。注意多用括号。
    如果运算公式太长,一行写不完,也可以分行写,运算符在上行、下行都可以。

  8. 四舍五入:
    对于数字运算,EVAL(H),是四舍五入的运算,如
    EVAL(H) FLD01 = FLD02 / FLD03
    而EVAL,仅仅只是四舍,没有五入。
    EXFMT {(E)} (Write/Then Read Format) 显示屏幕文件并等待输入
    这个操作码的意思,是显示屏幕,并等待输入,语法为:

Factory 1 Operation Factory 2 Result HI LO EQ

EXFMT 记录格式名
当程序执行到这一句时,表示显示“记录格式名”所对应的子文件(由DSPF 定义,显示在屏幕上),同时等待用户进行输入操作

当用户输入预定义的热键(F3,F4 等等)、或执行输入操作后(按下输入键),程序才会继续向下执行。

EXSR (Invoke Subroutine) 执行子过程

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
EXSR 子过程名

EXTRCT {(E)}(Extract Date/Time) 取日期、时间型变量中的具体内容

首先,必须要有一个日期或时间型变量,这个可以在D 行定义,然后使用该变量中有值,比如
D FLD01 S D
D FLD02 S T
C MOVE *DATE FLD01
C TIME FLD02
这样,就有了一个日期型变量FLD01,一个时间型变量FLD02,且两个变量中都有值。再假设变量FLDYEAR 为四位字符型、FLDHOUR 为两位数字型

1
2
3
Factory 1 Operation Factory 2 Result HI LO EQ
EXTRCT FLD01:\*Y FLDYEAR
EXTRCT FLD02:\*H FLDHOUR

这时,FLDYEAR 表示当前的年份;FLDHOUR 表示当前的小时所以说,EXTRCT 操作码对应的对象变量,可以是字符型,也可以是数字型,但长度一定要与预期的对象长度相等(比如年份可以是字符,也可以是数字,但长度必须为4 位;月份必须为2 位,依此类推)而冒号后面所跟的参数,与ADDDUR 操作码一样,如下:
对应于日期型变量:
*D表示天,也可用*DAYS
*M表示月,也可用*MONTHS
*Y表示年,也可用*YEARS
对应于时间型变量
*H 表示小时,也可用*HOURS
*MN 表示分钟,也可用*MINUTES
*S 表示秒, 也可用*SECONDS

FOR (For) 又是循环

FOR 操作码,也是一种指定次数的循环,与“DO”循环有异曲同工之妙。

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
FOR N=1 TO 10

处理语句
ENDFOR
等价于

1
2
3
4
5
Factory 1 Operation Factory 2 Result HI LO EQ
1 DO 10 N
处理语句

ENDDO

都是循环10 次,并且将当前循环次数赋值到数字型变量N 中
GOTO (Go To) 跳转语句
GOTO,跳转语句。跳转到指定的标签处,需要用“TAG”语句来定义,如:
Factory 1 Operation Factory 2 Result HI LO EQ
处理语句1
IF 条件判断
GOTO FHSTAG
ENDIF
处理语句2
FHSTAG TAG
在这里,执行完处理语句1 时,如果“条件判断”成立,将会直接跳至“FHSTAG TAG”处,不
执行处理语句2。主过程不能跳转至子过程;(主过程我用来表示是与子过程相对应的词,指C 行
顺序第一行,至程序结束语句之间的语句)子过程不能跳转至其它子过程,只能在本子过程内
部跳转,或跳转到主过程;技术可以使用跳转语句来实现循环,不过不建议。

IF {(M | R)} (If) 条件判断

条件判断语句,必须与ENDIF 一起使用

1
2
3
4
5
6
Factory 1 Operation Factory 2 Result HI LO EQ
IF ((FLD01=FLD02)
OR (FLD01>FLD03))
AND(FLD03=FLD04)
处理语句
ENDIF

当条件判断成立时,才会执行下面的处理语句。
条件判断可以使用括号,OR,AND,来表达复杂的逻辑关系
IF 必须有对应的ENDIF,所以建议写程序时,写无IF 就加个ENDIF,然后再来写中间的处理语
句,以免遗漏。
IF 语句,还可以这种用法:
IF *IN(20)
ENDIF
这时,等价于
IF *IN20=’1’
ENDIF
IFxx (If) 条件判断
与ANDxx 类似,这是RPG 的语法,一行代码只能表示一个条件,如

Factory 1 Operation Factory 2 Result HI LO EQ
FLD01 IFEQ FLD02
FLD01 ORGT FLD03
处理语句
ENDIF
与AND 和ANDxx 类似,由于IF 语句在表达复杂的逻辑关系时更直观,所以通常我只使用IF,而
不是IFxx 了。

ITER (Iterate) 循环中,不处理此语句之后的语句

1
2
3
4
5
6
7
8
Factory 1 Operation Factory 2 Result HI LO EQ
1 DO 10 N
处理语句1
IF 条件判断
ITER
ENDIF
处理语句2
ENDDO

等价于

1
2
3
4
5
6
7
8
9
Factory 1 Operation Factory 2 Result HI LO EQ
1 DO 10 N
ITERTAG TAG
处理语句1
IF 条件判断
GOTO ITERTAG
ENDIF
处理语句2
ENDDO

不知道这个例子能不能让人明白,都是在说当条件判断成立时,就不执行处理语句2,直接从循环头开始处理。ITER 语句执行后,程序相当于跳转至循环体中的第一句,重新向下运行(即执行循环)。当有多层循环嵌套时,ITER 仅作用于最里层的循环。当循环中执行了子过程时,子过程中不能对该循环进行ITER 操作。也就是说:DO,ENDO,ITER 这些语句必须在一块(即要么都在主过程中,要么都在同一个子过程中)

KFLD (Define Parts of a Key) 定义组合键值中的字段

这个其实应该与KLIST 一起来讲,因为这两个操作是在一起使用的。一个PF 对应的逻辑文件LF,可能会有多个KEY 值,那么,我们要根据多个KEY 值,对于该逻辑文件进行查询定位操作时,就需要使用KLIST、KFLD 这两个操作码:

1
2
3
4
Factory 1 Operation Factory 2 Result HI LO EQ
FHSKEY KLIST //定义组合键值FHSKEY
KFLD FLD01 //组合键的首个字段为FLD01
KFLD FLD02 //组合键的第二个字段FLD02

组合键值的使用方式,就是将组合键视为一个变量,进行各种操作,如:
FHSKEY CHAIN FMTFHS
或 F
HSKEY SETLL FMTFHS
意思,就是说按组合键值,查询定位到逻辑文件PFFHSL3 中去。
这里要注意,PFFHSL3 的键值是FHS01、FHS02(即PF 文件中的字段),而程序中的组合键
值为FLD01、FLD02 两个程序中定义的变量,只要类型、长度与键值FHS01、FHS02相等即可。同
时,对文件进行查询定位操作后,在没有对FLD01、FLD02 赋值之前,这两个字段的值是不会发
生变化的(即不会更改组合键的键值);但是,组合键中的字段,也可以直接定义为PF 文件中
的字段,如

1
2
3
4
Factory 1 Operation Factory 2 Result HI LO EQ
FHSKEY KLIST
KFLD FHS01
KFLD FHS02

此时,可以将PF 文件中的字段FHS01、FHS02 先视为两个普通的变量,进行赋值,然后用
组合键FHSKEY 对PFFHSL3 进行查询定位;当执行完CHAIN,或READ 语句后,因为读取到了文件
中的数据,所以FHS01、FHS02 的值将发生变化,也即是组合键FHSKEY的键值发生了变化。基于
此,所以通常我不会将组合键的字段设置为查询文件中的字段,而是定义为几个独立的临时字
段,以免需要过于频繁的考虑键值的更改。

KLIST (Define a Composite Key) 以上面的KFLD 操作码

LEAVE (Leave a Do Group) 退出当前循环

退出当前循环,语法和注意事项基本与“ITER”相同:

1
2
3
4
5
6
7
8
Factory 1 Operation Factory 2 Result HI LO EQ
1 DO 10 N
处理语句1
IF 条件判断
LEAVE
ENDIF
处理语句2
ENDDO

等价于

1
2
3
4
5
6
7
8
9
10
Factory 1 Operation Factory 2 Result HI LO EQ
1 DO 10 N
处理语句1

IF 条件判断
GOTO LEAVETAG
ENDIF
处理语句2
ENDDO
LEAVE TAG

这两个例子都是在说当条件判断成立时,就不执行剩余的循环体,直接跳出循环。LEAVE 语句执行后,程序相当于跳转至ENDDO 循环结束处,然后向下执行ENDDO之后的循环外的执行语句。当有多层循环嵌套时,LEAVE 仅作用于最里层的循环。当循环中执行了子过程时,子过程中不能对该循环进行LEAVE 操作。也就是说:DO,ENDO,LEAVE这些语句必须在一块(即要么都在主过程中,要么都在同一个子过程中)

LOOKUP (Look Up a Table or Array Element) 对数组的查询定位

假设已定义数组DIMDATA,每条记录四位长,共三条记录的数组,且数组中已赋
值如下:
DIMDATA(1) = ‘0001’
DIMDATA(2) = ‘0002’
DIMDATA(3) = ‘0003’
那么,下面的语句就是对数组的查询定位操作:

1
2
3
Factory 1 Operation Factory 2 Result HI LO EQ
EVAL N=1
'0002' LOOKUP DIMDATA(N) 54

首句N=1,表示从第一条记录开始查询;如果N=2,即表示从第2 条记录开始查询;如果N 大
于数组定义时的总记录数(如N=4),则下面的LOOKUP 语句会报错,跳出程序;
第二句,表示查询 数组DIMDATA 中,内容为’0002’的,是第几条记录;其中,54 为EQ 指示器。当找到记录时,打开指示器,*IN54 = ‘1’;当未找到记录时, 指示器处于关闭状态,*IN54=’0’。与操作码CHINA 的指示器含义刚好相反;
在这个例子中,执行完LOOKUP 语后,*IN54=’1’, N = 2(即数组DIMDATA 中,有内容
为’0002’的记录,是第二条记录。当数组中有多条内容相同的记录时,N 为顺序查询到的第
一条记录当数组中无相应记录时,*IN54=’0’, N = 初始值,此例中,即N = 1

MOVE (Move) 赋值语句

  1. 基本语法:
    1
    2
    3
    Factory 1 Operation Factory 2 Result HI LO EQ
    MOVE FLD01 FLD02
    FLD01、FLD02 可以是不同的类型。即允许一个为字符,一个为数字
  2. 允许在MOVE 操作中,对Result 字符进行定义。
  3. MOVE 操作码,使用右对齐赋值。所谓右对齐,即是将Factory 2 的最右边一个字符,赋值

到Result 的最右边的一个字符;然后再将Factory 2 向左取一位字符,赋值到Result 从最右
边起,左移一位的字符是,依此类推。直到取完Factory 2 的值,或Result 已赋满值。
4. 由上述其实已可看出,MOVE 操作码在对字符赋值时,使用的是覆盖方式赋值。即如果FLD02
将在赋值的字符处,原来有值,将会将原来的值覆盖;如果已有值时,未执行赋值操作,将仍
然保留原值。
5. 当FLD01、FLD02 都为字符型:如果FLD01 的长度为5 位,FLD02 的长度为8 位。FLD01 的
内容为’12345’,FLD02的内容为’ABCDEFGH’,当执行了MOVE 操作后,FLD02 的内容为’
ABC12345’,可以看到,后5 位由’DEFGH’变成了FLD01 的’12345’,而前三位仍然保留原
来的值’ABC’;
要注意的是,在字符型变量中,空字符也会参与赋值。如果FLD01 的内容为’12 ‘,即后
三位是空时,那么执行MOVE 操作后,FLD02的值将会是’ABC12 ‘。看到了没有,最后三位也
与FLD01 一样,是空;而前三位FLD01的值保持不变,仍为’ABC’。反之,当FLD01 的长度为8
位,’12345678’,而FLD02 的长度为5 位’ABCDE’时,执行完MOVE 操作后,FLD02 的值为’
45678’,即从最右边开始,向左赋值;MOVE操作表示右对齐,空也算字符。
6. 数字赋值到字符的处理:
当FLD01 为数字(5,2),FLD02 为字符(8)时,MOVE 操作将会把数字的小数点去掉,
将数字转换为字符,右对齐赋值到字符变量中。数字型变量如果未满,前面都视为空,而不是0;
如果FLD01 为123.45 , FLD02 为’ABCDEFGH’ , 赋值之后,FLD02=’ABC12345’,首三位
保持FLD02 原有的值。如果FLD01=123.45,FLD02 原来为空, 赋值之后,FLD02=’ 12345’;
(字符型变量首三位保持原来的空值)如果FLD01=3.45,FLD02 原来为空, 赋值之后,FLD01=’
345’。 (数型变量未满足,前面也视为空,而不是0)如果数字的长度大于字符的长度,系统
将会自动从左边开始,将大于的部分截去。如FLD01 长度为10,2,等于12345678.90 时,赋值
后,FLD02 会等于’34567890’
7. 字符赋值到数字的处理:
当FLD01 为字符(8),FLD02 为数字(5,2)时,MOVE 操作会将字符右对齐赋值到数字中,如
果字符后面有空,系统会自动做补零处理;如果FLD01 为’12345678’,FLD02 为0,赋值之后,
FLD02=456.78;如果FLD01 为’12345 ‘,即后三位为空时,赋值之后,FLD02=450.00,自动
补0;当数字长度大于字符的长度,如FLD02 为(10,2)时,数字最高位在赋值时,将会保持原值,
如FLD02=12345678.90 , FLD01=’87654321’ , 赋值之后,FLD02=12876543.21,注意最高
位的12 保持未变所以通常,字符转数字时,长度最好保持一致,以免得赋值时有意外。
8. 日期、时间型变量与字符、数字的转换
日期型变量与字符的转换,会带上分隔符。如果日期型变量为’2007-02-12’时,字符型
变量也需要定义为8+2 位,当执行完赋值操作时,字符型变量即为’2007-02-12’,注意,是
有分隔符的;时间型变量也一样,只是长度要需要6+2位。反之,当字符型变量赋值到日期型变
量中,也是需要有这个分隔符的;
日期型变量与数字的转换,将会自动去掉分隔符(非常好吧),如果日期型变量为’
2007-02-12’时,赋值到一个8 位的数字型变量,该变量就等于20070212;反之,数字赋值到

日期型变量中时,也是需要8 位纯数字;时间型变量也一样处理,只要长度需要为6 位。

MOVEA {(P)} (Move Array) 数组赋值

该操作码仅作用于数组。
假设已定义数组DIMDATA,每条记录二位长,共三条记录的数组,且数组中已赋值如下:
DIMDATA(1) = ‘01’
__ DIMDATA(2) = ‘02’
DIMDATA(3) = ‘03’
当执行完MOVEA 操作后:
Factory 1 Operation Factory 2 Result HI LO EQ
MOVEA BLANK DIMDATA
DIMDATA 中所有的要素都变成了空值。
MOVEA 还可以将一个变量拆分赋值到数组中,仍是上例,假设有一个6 位字符型变量 FLD01,
其值为’ABCDEF’,那么执行语句:
MOVEA FLD01 DIMDATA
后,数组中的值将是如下:
DIMDATA(1) = ‘AB’
DIMDATA(2) = ‘CD’
DIMDATA(3) = ‘EF’
当变量的长度,小于(数组单条记录长度
总记录数)时,超出部分的数组的值,保持原值。
仍是上例,假设FLD01 为4 位长的字符变量,值为’ABCD’时,执行MOVEA 操作后,数组中的
值如下:
DIMDATA(1) = ‘AB’
DIMDATA(2) = ‘CD’
DIMDATA(3) = ‘03’
注意,最后一个记录DIMDATA(3)的值仍保持原’03’不变,没有被清空。
MOVEL {(P)} (Move Left) 左对齐赋值语法
与MOVE 操作码相同,所不同的是对齐方式为左对齐,即是将Factory 2 的最左边一个字符,
赋值到Result 的最左边的一个字符;然后再将Factory 2 向右取一位字符,赋值到Result 从
最左边起,右移一位的字符,依此类推。直到取完Factory 2 的值,或Result 已赋满值。
在进行长度不同的字符之间赋值时,可按照上面这个原则,根据MOVE 操作码中的案例,想
想不同情况的结果,这里不做一一列举。
要注意的是,当使用MOVEL,由字符转为数字时,后面的空格会自动补0,如’123‘(后面
5 位都为空),转到数字型变量中,就变成了123000.00。因为大部分情况下,我们定义的标准,
都是字符型左对齐,数字型右对齐。所以此时字符转数字要注意,以免无端扩大倍数。

MULT {(H)} (Multiply) 数学运算—乘

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
FLD01 MULT FLD02 FLD03

等于
EVAL FLD03 = FLD01 * FLD02
可以对当前行对FLD03 进行定义;
Factory 1 可以不填写;
必须保证FLD03 的位数足够大,否则超长时,程序会报错异常退出。

MVR (Move Remainder) 数学运算—除法运算取余

这个操作码,在讲操作码DIV 时,已讲过:

1
2
3
Factory 1 Operation Factory 2 Result HI LO EQ
FLD01 DIV FLD02 FLD03
MVR FLD04

当FLD01=11,FLD02=时4,
FLD03=2 (商)
FLD04=3 (余)

OPEN {(E)} (Open File for Processing) 打开文件

Factory 1 Operation Factory 2 Result HI LO EQ
OPEN 文件名
OPEN 后面的对象,必须是在当前程序中已声明的文件名(不是文件的记录格式名),而且
在OPEN 操作之后,在程序结束之前之前,必须有对应的CLOSE 操作。使用OPEN 操作,文件在
声明时,必须使用USROPN 关键字(详见D 行说明)。

ORxx (Or) 逻辑判断—或

1
2
3
Factory 1 Operation Factory 2 Result HI LO EQ
FLD01 IFGT FLD03
FLD01 OREQ FLD02

等价于
IF FLD01>FLD03 OR FLD01=FLD02
与IF、IFxx,AND、ANDxx 类似,RPGLE 的写法OR,比RPG 的写法ORxx 要灵活,
而且可以用来表达一些复杂的逻辑关系。有鉴于此,所以通常IF 语句中,我会以OR 为主,基
本不用ORxx。如果在编程序方面,公司/项目组无硬性要求,那我觉得还是少用ORxx 吧,总觉
得这种写法的逻辑关系看起来不直接,尤其是有很复杂的AND,OR 时。

OTHER (Otherwise Select) 分支语句的判断

与分支语句SELECT 一起使用,表示不符合上述所有条件时的操作,如下:

1
2
3
4
5
6
7
8
9
Factory 1 Operation Factory 2 Result HI LO EQ
SELECT
WHEN 条件判断1
处理语句1
WHEN 条件判断2
处理语句2
OTHER
处理语句3
ENDSL

在这个例子中,当满足条件判断1 时,运行处理语句1,运行结束后跳至ENDSL 处;如果不
满足条件判断1,则程序继续向下执行,判断是否满足条件判断2。
当满足条件判断2 时,运行处理语句2,跳至ENDSL;当不满足
当不满足条件判断2 时,程序继续向下执下,当读到OTHER 操作码时,无条件运行处理语
句3(即当程序当前不满足以上所以条件判断时,则执行OTHER 之后的语句。
处理语句允许有很多句;条件判断可以写得很复杂,也允许对不同的字段进行判断;比如
说C 语言也有分支语句switch,但是这个语句只能对一个字段进行分支判断,ILE 语言与它不
同,允许对不同的字段进行判断就我目前掌握的测试情况,上述的SELECT—WHEN–OTHER—
ENDSL,其实也可以写做:
IF 条件判断1
处理语句1
ELSEIF 条件判断2
处理语句2
ELSE
处理语句3
ENDIF
即WHEN 与ELSEIF 是类似的,这样说,应该可以明白了吧。
总之,SELECT—ENDSL 是一个很好用的语法,尤其是在表示很多不同的分支处理时。

READ {(N | E)} (Read a Record) 读取记录

  1. 基本语法:

    1
    2
    Factory 1 Operation Factory 2 Result HI LO EQ
    READ 文件记录格式名 45 46

    READ后面跟的,必须是声明的文件记录格式名;
    LO 指示器表示锁表指示器,当在指定的时间(CHGPF,WAITRCD 项可看到),需要读取的
    记录仍被锁,将会打开LO 指示器,即*IN45=’1’;
    EQ指示器为是否读到指示器。当未读到任何记录时,打开EQ 指示器,即*IN46=’1’

  2. 当文件在程序中,是用只读的方式声明时,READ 操作并不会造成锁表;
    如果文件在程序中是用修改的方式声明,READ 操作成功后,该记录被锁;直到执行解锁操作(UNLOCK,或UPDATE),或READ 该文件的其它记录,才会解锁
    如果文件是用修改的方式声明,但希望READ 操作不锁表时,那么就用READ(N),

    1
    2
    Factory 1 Operation Factory 2 Result HI LO EQ
    READ(N) 文件记录格式名 45 46

    这样读文件,就不会锁记录,但是同时也不能修改记录。如果需要修改记录,那么在修改之前(包括对文件字段赋值之前),还必须再对该记录进行一次定位操作(比如CHAIN、READ 语句均可)。也就是说,如果要修改记录,必须先锁住当前记录。

  3. 当执行READ 操作时,程序是根据游标当前在文件中所指向的位置,顺序读取下一条记录。

  4. 执行READ 操作时,允许声明的文件没有键值。(即PF 文件)
    READC {(E)} (Read Next Changed Record)
    读下一次修改过的记录
    READE {(N | E)} (Read Equal Key) 读取键值相等的记录
    语法与READ 操作码大致一样,这里不再重复,只说不同的:
    假设程序中已声明逻辑文件PFFHSL3(键值为FHS01+FHS02)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Factory 1 Operation Factory 2 Result HI LO EQ
    FHSKEY KLIST
    KFLD FLD01
    KFLD FLD02
    FHSKEY SETLL FMTFHS
    DOW 1=1
    FHSKEY READE FMTFHS 15
    IF *IN15=’1’
    LEAVE
    ENDIF
    ENDDO

    这段话的意思,就是定义组合键值FHSKEY,然后根据这个FHSKEY 在逻辑文件PFFHSL3 中去
    定位,循环读取PFFHSL3 中,FHS01、FHS03 与FLD01、FLD02 相等的记录。
    当读取记录结束,或键值不等时,退出循环(*IN15 是EQ 指示器)。如果将READE 操作码
    换成READ 操作码的话(当然,Factory 1 处也就不能有值),就没有“键值不等时退出循环”
    这一层意思,只是读不到记录时就退出循环,但有时我们使用逻辑文件,仅仅是需要它的排序,
    而不需要读不到键值相等的记录就退出循环。
    所以说,使用READ 操作码,还是READE 操作码,需要根据实际的要求来决定。以上的Factory
    1 处填写值的系统处理,当READE 操作码在Factory 1 处未填写值时,系统实际上是将当前的
    值与读到的上一条记录的关键字进行比较,而不是与SETLL 时的键值做比较(读第一条记录不做比较!),如果键值不等时,置EQ 指示器为1。也就是说,如果没有与FHSKEY 键值相同的录,
    那么系统并不是直接找开EQ 指示器,而是会一直保持正常地往下读,直到找到与读到的第一条
    记录关键字不同的记录,才会打开EQ 指示器,所以要注意。

READP {(N | E)} (Read Prior Record) 读取记录—游标上移

简单来说,READ、READE 操作时,游标在数据文件中,是下移的;即读完第一条记录,游
标指向第二条记录;读完第二条记录,游标指向第三条记录,依此类推,直至最后一条记录。
但READP 则正好相反,游标是上移的,即读完第三条记录后,游标指向第二条记录;读完第二
条记录后,游标指向第一条记录,直至读完第一条记录。一般来说,用READ、READE 的概率会
比READP、READPE 的概率高得多,不过在某些情况下,使用READP 操作,又的确会很省事,大
家可在编程序时多实践。

READPE {(N | E)} (Read Prior Equal)

是指游标上移,按键值去读取文件。与READP 的关系,就类似于READE 与READ 的关系。

RESET {(E)} (Reset)

将数据结构赋值成为初始值。
注意是初始值,不是清空。
如定义结构:
D FHSDS DS
D FHS01 10 INZ(’ABCD’)
D FHS02 5 INZ(’EFGH’)
那么,不管对该结构如何赋值,当执行语句:
C RESET FHSDS
之后,FHS01 将会变成’ABCD,FHS02 将会变成’EFGH’,即恢复成为初始值。

RETURN {(H | M | R)} (Return to Caller)

RETURN 是程序结束。
在前面,“简单的程序流程”中,我们讲过,“SETON LR” 与RETURN 这两句话一起,做
为程序的结束。这里,再详细解释一下两者之间的区别,以及关系:如果不写RETURN,只写“SETON
LR”,程序执行完最后一句之后,将会再从第一句开始执行,造成死循环。
在简单的程序流程这个例子中,程序原来只想修改读到的第一条记录,而如果没有RETURN
的话,将会把所有的记录都修改掉,直到最后找不到可修改的记录,然后系统报错,异常中断。
如果只写RETURN,不打开指示器*INLR,根据blogliou 所说 “程序不会强制将内存中的数据写
到磁盘中。400 缺省的是BLOCK 输出,即数据记录满一个BLOCK 块时才会将这一组记录写到磁
盘上。那么如果这时BLOCK 没满,数据信息不会立刻写到磁盘上。之后有其它作业用到该文件,
读取的数据就不完整。”但如果文件有唯一键字,或记录日志,必须同步写时,其实BLOCK 实
际被忽略,也就是此时不会有错。

ROLBK {(E)} (Roll Back)

  1. 基本语法
    1
    2
    Factory 1 Operation Factory 2 Result
    ROLBK
  2. 该操作码无其它参数,就是指对事务处理进行回滚操作。
  3. ILE 程序中,ROLBK 操作可随时进行,也允许在没有声明COMMIT 类型的文件的情况下,仍
    进行ROLBK 操作(对该进程这前的事务进行确认处理)

SCAN {(E)} (Scan Character String) 扫描字符串

扫描字符或字符串Factory 1 在对象字符串Factory 2 中是否存在

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
FLD01 SCAN FLD02 N 26

FLD01 可以是字符,也可以是字符变量;可以是一位长,也可以是多位长。
当FLD01 在FLD02 中存在时,EQ 指示器打开,即IN26=’1’,同时将FLD02 中的起始位置,
赋值给N;
当FLD01 在FLD02 中不存在时,EQ 指示器保持关闭状态,即
IN26=’0’,同时N=0允许从
FLD02 中的指定位置开始检查:
FLD01 SCAN FLD02:2 N 26
如上句,即表示从FLD02 的第2 位,开始扫描。在实际使用中,比如说我们判断某个字符
是否为数字,就可以先定义一个0—9 的常量,然后将要判断的字符去SCAN 一下这个常量。
SELECT (Begin a Select Group) 分支语句
在操作码“OTHER”中讲过,为方便读者,列出简单语法如下:

1
2
3
4
5
6
7
8
9
Factory 1 Operation Factory 2 Result HI LO EQ
SELECT
WHEN 条件判断1
处理语句1
WHEN 条件判断2
处理语句2
OTHER
处理语句3
ENDSL

要注意,SELECT 操作码,必须有对应的ENDSL 操作码,否则编译无法通过。
SETGT {(E)} (Set Greater Than) 定位操作—大于
举个例子吧,假设文件中有一个字段,是标识顺序号的,1、2、3、4。即该字段为1,
表示第一条记录,该字段为2,表示第2 条记录。那么:

1
2
3
Factory 1 Operation Factory 2 Result HI LO EQ
2 SETGT 文件记录格式名
READ 文件记录格式名

这个READ 操作,READ 到的,是第3 条记录。也就是说,SETGT 操作码,会将游标定位到
大于键值的第一条记录前。在实际使用中,如果我们是按逻辑文件读取,而且读了一条记录之
后,对其键值相同的记录都不需要再读取时,就可以用SETGT,不过需要注意,Factory 1 项,
需要是与键值相同的变量,即如果文件是使用多个字段做为键值,那么我们也需要先定义一个
组合键值的变量,然后Factory 1 处填写这个组合键值的变量名。
当声明文件的键值有多项时,Factory 1 项的键值,允许小于文件的键值,但顺序必须一
致。即声明的文件如果键值为:FHS01、FHS02、FHS03,那么我们在程序中定义三个类型与之相
同的变量FLD01、FLD02、FLD03,以下写法都是有效的
FLDKEY KLIST
KFLD FLD01
KFLD FLD02
KFLD FLD03
FLDKEY SETGT 文件记录格式名
FLDKEY KLIST
KFLD FLD01
KFLD FLD02
FLDKEY SETGT 文件记录格式名
FLD01 SETLL 文件记录格式名

SETLL {(E)} (Set Lower Limit) 定位操作—小于语法

与SETGT 相同,含义与SETGT 不同。SETLL 操作码,会将游标定位到与键值相等的第一条
记录之前,仍是上例,如果是
Factory 1 Operation Factory 2 Result HI LO EQ
2 SETLL 文件记录格式名
READ 文件记录格式名
那么READ 操作码读到的记录,就是第2 条记录,看到了吧,和SETGT 不同。
SETLL 操作码还可以用来简单判断当前键值是否存在有记录,以PFFHSL3 为例(键值为FHS01、
FHS02)
Factory 1 Operation Factory 2 Result HI LO EQ
FHSKEY KLIST
KFLD FLD01
KFLD FLD02
EVAL FLD01=’01’
EVAL FLD02=’02’

FHSKEY SETLL 文件记录格式名 44
当文件中有相应记录时,EQ 指示器打开,即IN44=’1’
当文件中无相应记录时,EQ 指示器关闭,即
IN44=’0’(与CHAIN 正好相反,要注意)而在
这种用法中,SETLL 与CHAIN 的区别在于,CHAIN 是定位读取了记录,而SETLL仅仅只是判断该
记录是否存在。所以用SETLL 操作,不能修改记录,也无法取出记录的值。只能判断记录是否
存在。如果要修改记录,或取出记录的值,还需要有一个读取定位的操作,如READ,或READE、
READP 等(最常用的,应该就是READ 操作)

SETOFF (Set Indicator Off) 关闭指示器

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
SETOFF 10 11 12

等价于

1
2
3
EVAL *IN10=’0’
EVAL *IN11=’0’
EVAL *IN12=’0’

在SETOFF 这个操作码中,指示器填在HI、LO、EQ 哪里都没关系,都是表示要被关闭的指示器

SETON (Set Indicator On) 打开指示器

Factory 1 Operation Factory 2 Result HI LO EQ
SETOFF 10 11 12
等价于
EVAL *IN10=’1’
EVAL *IN11=’1’
EVAL *IN12=’1’
在SETON 这个操作码中,指示器填在HI、LO、EQ 哪里都没关系,都是表示要被关闭的指示器
SORTA (Sort an Array)
数组排序

SQRT {(H)} (Square Root) 开方

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
9 SQRT 3 N

这时,N=3(因为3 的平方为9)
9、3 都可以是数字型变量,或者直接是数字

SUB {(H)} (Subtract) 减法操作

1
2
3
Factory 1 Operation Factory 2 Result HI LO EQ
FLD01 SUB FLD02 FLD03
SUB FLD02 FLD03

SUBDUR {(E)} (Subtract Duration) 日期相减

  1. 减日期
    1
    2
    Factory 1 Operation Factory 2 Result HI LO EQ
    FLD01 SUBDUR N:*Y FLD02
    表示将日期型变量FLD01 减去N 年,赋值到日期型变量FLD02 中;
    N 可以是一个数字型变量,也可以就是一个数字,N 允许为负数
    *Y,*M,*D(还有其它的参数值,可见ADDDUR,其中有详细解释)
  2. 判断两个日期型变量之间的天/月/年数
    1
    2
    Factory 1 Operation Factory 2 Result HI LO EQ
    FLD01 SUBDUR FLD02 N:*D
    这时,N 做为一结果变量,表示日期型变量FLD01 与FLD02 之间的天数

SUBST {(P | E)} (Substring) 取字符/字符串

1
2
Factory 1 Operation Factory 2 Result HI LO EQ
2 SUBST FLD01:3 FLD02

表示从字段FLD01 的第3 位开始,取2 位,左对齐赋值到字段FLD02 中。
要求字段FLD01 的长度必须大于或等于3+2 位,否则程序会报错。
可以尝试用%SUBST 语句,也是等价的,如下
EVAL FLD02=%SUBST(FLD01:3:2)
表示的是同样的意思。
起始位数3,取的长度2,在两种写法之下,都可以使用数字型变量来表达。
相比较之下,%SUBST 还有一种用法,就是对字符的指定位置赋值,这个就厉害了:
EVAL %SUBST(FLD02:3:2)=’01’
看到了吧,这句话就是说,使字段FLD02 的第3、4 位(即从第三位开始,两位长)等于“01”
TAG (Tag) 定义标签,与GOTO 同用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Factory 1 Operation Factory 2 Result HI LO EQ
FHSTAG TAG
TESTN (Test Numeric)
检查字段是否全是数字
TESTZ (Test Zone)
测试区位
TIME (Time of Day) --取当前系统时间
Factory 1 Operation Factory 2 Result HI LO EQ
TIME FLD01
FLD01 可以是时间型或数字型变量
UNLOCK {(E)} (Unlock a Data Area or Release a Record) 解锁
Factory 1 Operation Factory 2 Result HI LO EQ
UNLOCK 文件记录格式名

UNLOCK 是解锁操作,在某种程度上,可以将UNLOCK 视为ROLBK,将UPDATE视为COMMIT。即
如果锁定某条记录,并对其字段进行赋值之后,使用UPDATE 语句,将会把修改后的结果保存下
来,即修改文件,而UNLOCK 语句则不会修改文件,即否认了之前对文件字段做的赋值修改。
从程序的执行效率上来讲,UNLOCK 的执行效率是高于UPDATE 的,因为UPDATE操作时,系
统需要对文件的每一个字段进行确认处理(DEBUG 时可以看到),而UNLOCK 就是简单的解锁而
已。

## UPDATE (Modify Existing Record) 修改记录

这里需要说明一下,在执行UPDATE 的时候,必须先使用READ、CHAIN 等操作码锁定一条记录。如果未锁住记录,UPDATE 操作码将会报错。当执行了UNLOCK、UPDATE、以及ROLBK 语句时,等于是解锁,此时再执行UPDATE 操作码之前,必须再次锁住记录操作;

## WHEN {(M | R)} (When) 分支判断语句中的条件判断

在操作码“OTHER”,“SELECT”中都讲过,仍列出简单语法如下:

Factory 1 Operation Factory 2 Result HI LO EQ
SELECT
WHEN 条件判断1
处理语句1
WHEN 条件判断2
处理语句2
OTHER
处理语句3
ENDSL

1
2
3
4
5
6
7
8
9
10
11
12
13
## WHENxx (When True Then Select)

上面的语法,是RPGLE 的语法,WHENxx 是RPG 的语法,也就是
SELECT
FLD01 WHENEQ FLD02
处理语句1
……..
这样的语法,在表达复杂的逻辑关系时,必须与ANDxx,ORxx 一起使用,所以我不
使用WHENxx 这个操作码。

## WRITE (Create New Records) 写记录

常用的方式:

Factory 1 Operation Factory 2 Result HI LO EQ
CLEAR 文件记录格式名
EVAL 文件字段1=xxxx
EVAL 文件字段2=xxxx
WRITE 文件记录格式名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
表示在文件中写入一条新记录。文件需要声明为可写的

通常会在给文件字段赋值之前,作一次CLEAR 操作来进行初始化,以避免不必要的麻烦。

## XFOOT {(H)} (Sum the Elements of an Array)

对数组字段的累加统计。
假设DIMDATA 定义为一个数字型的数组变量,FHS01 为一个足够大的数字型变量
Factory 1 Operation Factory 2 Result HI LO EQ
XFOOT DIMDATA FHS01
就表示将数组DIMDATA 中的所有记录的值都取出来,汇总相加,赋值到数字变量FHS01 中

## XLATE {(P | E)} (Translate)


将一个字符串中指定的字符,更换成另外的字符。
举例:如MYCHAR1, MYCHAR2 都是两个20 位长的字符型变量

Factory 1 Operation Factory 2 Result HI LO EQ
MOVEL ‘ABCAAAC123’ MYCHAR1
‘A’:’9’ XLATE MYCHAR1 MYCHAR2

1
2
3
4
5
6
执行过这个语句之后,MYCHAR2 就等于”9BC999C123’,即将字符串MYCHAR1 中所有的“A”都
变成了“9”;XLATE 也可能指定起始位置。如上句更改为:
'A':'9' XLATE MYCHAR1:4 MYCHAR2
则MYCHAR2 等于“ABC999C123”,指从第4 位开始(含第4 位),将“A”变成“9”赋值。

## Z-ADD {(H)} (Zero and Add) 向数字型变量赋值

Factory 1 Operation Factory 2 Result HI LO EQ
Z-ADD FLD01 FLD02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
将数字型变量FLD01,赋值到数字型变量FLD02 中。
Z-ADD、MOVE 虽然同是赋值操作码,但Z-ADD 的用法就远没有MOVE 那么变化多
端,只能在数字型变量之间赋值。所以也没有什么可说的了。zero
如果要对数字型变量赋初值,使用\*ZERO
Z-ADD \*ZERO FLD02

## Z-SUB {(H)} (Zero and Subtract) 用0 减

Factory 1 Operation Factory 2 Result HI LO EQ
Z-SUB FLD01 FLD02
等价于
0 SUB FLD01 FLD02
等价于
EVAL FLD02=FLD01*(-1)

## *ALL

\*ALL 是个很有意义的变量,举例:

EVAL FLD01=*ALL’0’

1
2
3
4
5
6
7
表示将字符型变量FLD01 赋值为全’0’
而CLOSE *ALL就表示关闭所有文件,意义与上面是不同的

## %LEN

取字符串的长度,举例:
(MYLEN 为数字型变量,FLD01 为字符型变量)

EVAL MYLEN = %LEN(FLD01)

1
2
3
4
5
6
7
8
9
10
这句话的意思,是指取字符串FLD01 的长度,不过通常这样用是没意义的,因为直接用%LEN
操作码,取到的是字符串的总长度,不是有效字符的长度,也就是说FLD01 长度为2,那么MYLEN
就恒等于2,不会变。就算变量FLD01 中没有值,取出的MYLEN 也等于2.。所以,%LEN 通常会
与%TRIM 或是%TRIMR 一起使用,语法在下面介绍。

## %TRIM,%TRIMR

都是去字符串变量中的空字符意思,%TRIM 是去字符串左边的空字符;%TRIMR 是去字符串
右边的空格。通常我们在写程序中,都是默认字符串变量左对齐,所以我们使用%TRIMR 操作码
的概率应该高一点。举例:

EVAL MYLEN = %LEN(%TRIMR(FLD01))

1
2
3
4
5
这时的MYLEN,就是指变量FLD01 中的有效长度(前提条件是FLD01 中如果有值,是左对齐)。
如果FLD01 为空,那么MYFLEN 为0;如果FLD01 首位有值,第二位为空,那么MYLEN 为1;如果
FLD01 两位都不为空,那么MYLEN 就等于2。如果字符串左对齐,那么就使用%TRIMR还有一种用
法,假设字符串FLD04 为4 位长的字符,FLD01,FLD02 都是2 位长的字符,且FLD01 等于“A ”,
FLD02 等于“BC”,那我们执行:

EVAL FLD04 = FLD01 + FLD01 + FLD02

1
2
FLD04 就等于“A A ”,也就是第二位与第四位都是空的,最后加的FLD02 其实无效。而
如果执行

EVAL FLD04 = %TRIMR(FLD01) + %TRIMR(FLD01) + FLD02

1
2
3
4
5
则FLD04 就等于“AABC”,也就是说,在这里,%TRIMR(FLD01),是等价于单字符“A”的

## MONITOR

监控程序信息。据说是可以屏蔽掉出错信息,避免程序异常中断,未经测试。