RPG操作码汇总
RPG操作码汇总
ACQ {(E)} (Acquire)
取地址位。其实400 的程序中也有指针型变量,那么也就会有地址位,这个命令是取地址位的。ADD {(H)} (Add) 加法操作
- 基本语法:
1 | Factory1 Operation Factory 2 Result |
等价于
1 | EVAL FHS03=FHS01+FHS02 //RPGLE 的语法 |
FHS01、FHS02、FHS03 必须都为数字型变量(P 型,或S 型),或者就是数字意思是将Factory
1 项的数据,加上Factory 2 项的数据,赋值到Result 项上
语法二:
如果这样写的话:1
2Factory1 Operation Factory2 Result
ADD FHS02 FHS03就等价于:
EVAL FHS03=FHS03+FHS02
即Factory 1 项未填时,就表示将Result 项的数据,加上Factory 2 项的数据,然后赋值到Result 项上四舍五入:
(H)表示四舍五入,如FHS02=12.50(4,2),FHS03=3(2,0),那么1
ADD(H) FHS02 FHS03执行之后,FHS03=16(因为进位了)
而
1
ADD FHS02 FHS03
执行之后,FHS03=15
不过实际使用中,我们都尽可能使相加的字段小数位数相等,所以ADD 操作码一般都没有使用到四舍五入的功能。可以在ADD 操作时,对Result 项的变量进行定义
1
2Factory 1 Operation Factory 2 Result
FHS01 ADD FHS02 FHS03 10 2EVAL 语句不能对在赋值的同时,对变量进行定义
关于结果数据超长时的问题:
当加出的结果超长,比如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) 日期时间相加
- 对日期型变量进行加操作,比如说已定义日期型变量MYDATE1,MYDATE2,将
MYDATE1 的日期加上3 天,赋值到MYDATE2 中:其中,Factory 1,Result 项,都必须为日期型变量(即在D 行,Internal Data Type项为“D” )1
2Factory 1 Operation Factory 2 Result
MYDATE1 ADDDUR 3:*D MYDATE2 - 与ADD 操作码相同,Factory 1 项为空时,表示直接在Result 项上进行日期相加,如将
MYDATE1 直接加上3 个月(即结果也是赋值到MYDATE1 中):1
2Factory1 Operation Factory2 Result
ADDDUR 3:*M MYDATE1 - 日期型变量的参数含义:
- *D表示天,也可用*DAYS
- *M表示月,也可用*MONTHS
- *Y表示年,也可用*YEARS
- 除了日期型之外,还有时间型,日期时间型,都可以使用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
- Factory 2 项中的数字,可以使用负数,使用负数时,表示减去相应的年、月、日,不过
通常使用SUBDUR 来进行日期的减法,语法与ADDDUR 相同
ANDxx (And) 条件判断语句—“与”
- 在RPG 的用法中,有ANDEQ,ANDNE 之类的,与IF 语句一起联用。。。。处理内容
1
2
3Factory1 Operation Factory 2 Result
FLD01 IFEQ ‘A’
FLD02 ANDEQ ‘B’
ENDIF - 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 | Factory1 Operation Factory 2 Result |
如果是直接调用外部程序,那么程序名称需要用单引号括起来,且该程序必须存在。如
CALL ‘FHSILE01’
就表示调用“FHSILE01”这个外部程序如果没有用单引号,如
CALL FHSILE01
就表示,FHSILE01 这时是个字符型变量(即并非调用“FHSILE01 这个程序),调用的是
变量内容所代表的程序。如:
FHSILE01=’FHS01’时,表示调用“FHS01”这个外部程序;
FHSILE01=’FHS02’时,表示调用“FHS02”这外外部程序
也就是说,CALL 操作码调用的程序名,可以是一个变量名。被调用的外部程序如果有接口参数,那么CALL 操作码之后,也需要有“PARM”操作码相对应。
这一点要注意:虽然400 的程序段代码中,是不区分大小写;但调用的程序名,要区分大
写小。即’FHSILE01’,与fhsile01,表示的是两个不同的程序。在使用时要注意,尤其
是程序名使用字符变量来表达时,可能会因为大小写的问题而导致 CALL 不到想CALL 的程
序,从而导致程序异常中断
CASxx (Conditionally Invoke Subroutine) 带条件的调用子过程
- 表示根据xx 项对Factory 1 与Factory 2 进行判断,当符合条件时,执行Result 处的子
过程。需要配合“END”或“ENDCS”语句来表示条件判断的结束。不需要“SELECT”操作
码。 - 举例如下:表示当FLD01 等于’1’时,执行子过程SUB01;
1
2
3
4
5Factory 1 Operation Factory 2 Result
FLD01 CASEQ ‘1’ SUB01
FLD01 CASEQ ‘2’ SUB02
CAS SUB03
ENDCS
当FLD01 等于’2’时,执行子过程SUB02;
当不满足以上两个条件时,执行子过程SUB03
最后的“ENDCS”必须要有,表示条件判断结束;但不需要SELECT。上面这段语句,与下面
这一段是等价的:1
2
3
4
5
6
7
8
9Factory 1 Operation Factory 2 Result
SELECT
WHEN FLD01=’1’
EXSR SUB01
WHEN FLD01=’2’
EXSR SUB02
OTHER
EXSR SUB03
ENDSL - 可以看出来,CASxx 这种语句,是用于逻辑判断仅一个条件时的分支处理,这样的写法在代
码的阅读上会很直观。而当逻辑判断大于一个条件时,这个语句就不适用了。
CAT {(P)} (Concatenate Two Character Strings) 字符连接
- 基本语法:
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 项可以是字符型变量,也可以就是字符。当是字符时,需要
用单引号将字符括起来 - 其实根据RPG 的语法,Factory1 项如果不填值,就表示将Factory 2 项的内容直接拼在Result 项上,这里就不举例了。
- 字段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 之间有一个空格) - 表示空格个数时,可以使用数字型的变量来表达,如
EVAL N=1
FLD01 CAT FLD02:N FLD03 - CAT 操作码,其实也可以通过EVAL 来实现部分。比如将FLD01 与FLD02 拼起来,中间无空格,赋值到FLD03 中,也可以写做:
EVAL FLD03=FLD01 + FLD02 - EVAL 操作码的优势,在于可以在一行语句中,就把多个字符拼在一起,如:
EVAL FLD05=FLD01+FLD02+FLD03+FLD04 - 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) 按键值对文件记录进行查询定位
基本语法:
举例,对逻辑文件PFFHSL1 进行定位操作。逻辑文件PFFHSL1,是以FHS01 为键值,文件记
录格式名叫FMTFHS1
2Factory 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’, 表示查询时,文件被锁(不确定有没有相应的对象记录)用修改方式声明的文件,当查询成功后,对象记录被锁定,其它程序无法以修改的方式定位
到当前对象记录上。(但可以用只读的方式定位)LO 指示器,仅于用修改方式声明的文件。对于只读方式声明的文件其实无意义
如果用修改方式声明文件,但在LO 处未填写指示器,且有程序锁住对象记录时,当前程序会根据PF 中定义的WAITRCD(Maximum record wait time)参数,等待相应的秒数(如WAITRCD处为10,即表示锁表时,等待10 秒;如果填的是*IMMED,就表示不等待,一判断对象记录被锁就结束操作);如果在等待时间内,对方仍未解锁,当前程序就会异常中断退出;如果LO 处填写指示器,那么程序就不会中断退出,且LO 指示器打开。
当FHS01 键值,在文件PFFHSL1 中,对应有多条记录时(即键值不唯一),程序将会按照文件的内部记录号由小到大的顺序,定位到符合条件的第一条记录。
当一个逻辑文件,KEY 值有多项时,可以使用KLIST 操作码先定义一个组合键值,然后再用
这个组合键值来进行CHAIN 操作。需要注意,组合键值中,必须每一个成员字段都与对象记录
所对应的字段相等,才能查询成功。(所以组合键值,通常使用SETLL 定位较多)当用修改方式声明文件,但希望进行不锁记录的查询操作时,可以将CHAIN 操作码写为CHAIN(N),这个括号(N),就表示当前的查询定位,不对记录进行锁定操作(也就是用只读的方式来处理对象记录,所以只能取出对象记录的信息,不能做修改;如果要修改对象记录的话,还必须进行一个CHAIN 操作)
这一条要特别注意:当没有填写HI 指示器时,RPGLE 是允许编译通过的。而在某些情况之下,运行程序时,如果CHIAN操作成功,找到了符合条件的记录时,没有任何问题;但如果CHAIN 操作没有找到符合条件的记录时,实际上系统会按照键值的排序以及内部记录号,定位到下一条记录上,这时再取出来的数据,就统统都是下一条记录的数据。所以,除非有绝对的把握,CHAIN 操作肯定成功,否则就一定要养成填写HI 指示器的良好习惯。
CHECK {(E)} (Check Characters) 检查对象变量中的字符
- 基本语法:语句CHECK 的意思,是指字段FLD02 中,从第二位字符开始,向右查找(含第二位字符),是否包含有FLD01 中没有的字符。
1
2Factory 1 Operation Factory 2 Result HI LO EQ
FLD01 CHECK FLD02:2 N 42
如果的确有在FLD01 中没有的字符,将字符所在位置赋值到变量N 中,同时打开EQ 指示器;\如果从第二位字开始,向右读取的所有字符,都可以在变量FLD01 中找到,那么N 为0,EQ
指示器处于关闭状态。
“FLD02:2”表示从变量FLD02 的第二位开始,向右作比较。如果仅仅只是“FLD02”,那么就表示从变量FLD02 的首位开始,向右查找 - 实例
假设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
2Factory 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 的末位开始,向左查找
实例
假设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中)计算字符实际长段
根据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
2Factory 1 Operation Factory 2 Result
CLEAR 对象名
所谓文件的记录格式名,包括了程序中声明的磁盘文件、打印报表文件、屏幕文件CLEAR操作的意思,就是将对象所对应的所有变量/字段都赋上空值
CLOSE {(E)} (Close Files) 关闭文件
- 基本语法
1
2Factory 1 Operation Factory 2 Result
CLOSE 对象文件名 - CLOSE 所对应的,是文件名,不是文件的记录格式名,要注意
- CLOSE 操作码,仅适用于声明文件时,keyword 使用“USROPN”关键字的文件
- 每一个CLOSE 的操作,在之前都必须有OPEN 文件的操作。也就是,文件必须打开了之后,才能关闭。不能关闭未打开的文件
- 允许使用*ALL 变量,来表达关闭所有已打开的文件:
COMMIT {(E)} (Commit) 日志事务处理的确认操作
- 基本语法
1
2Factory 1 Operation Factory 2 Result
COMMIT - 该操作码无其它参数,就是指对事务处理进行确认操作。
- ILE 程序中,COMMIT 操作可随时进行,也允许在没有声明COMMIT 类型的文件的情况下,仍进行COMMIT 操作(对该进程这前的事务进行确认处理)
- 关于日志的确认操作,在后面会另设专门章节讲述
COMP (Compare) 比较
- 基本语法:
将Factory 1 与Factory 2 进行比较。
当Factory 1 > Factory 2 时,打开HI 指示器;
当Factory 1 = Factory 2 时,打开LO 指示器;
当Factory 1 < Factory 2 时,打开EQ 指示器。当FLD01=2,FLD02=1 时,*IN56=’1’, *IN57=’0’, *IN58=’0’1
2Factory 1 Operation Factory 2 Result HI LO EQ
FLD01 COMP FLD02 56 57 58
当FLD01=2,FLD02=2 时,*IN56=’0’, *IN57=’0’, *IN58=’1’
当FLD01=1,FLD02=2 时,*IN56=’0’, *IN57=’1’, *IN58=’0’
DEFINE (Field Definition)
根据已知的字段,来定义新字段,如下:
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
这句话的意思,就是说“象定义字段FLD01 一样,定义字段FLD02 的类型、长度”这个字段FLD01,必须是个已定义的字段/变量
DELETE {(E)} (Delete Record)
删除当前记录,语法如下:
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
这里,在做DELETE 操作前,必须先定位到具体的记录上(使用CHAIN、READ 等语句);同时,文件在F 行必须使用修改的方式来声明。当文件定位到对象记录时,对象记录会被锁定,此时,对象记录无法被其它程序修改;
如果执行了DELETE 操作,自然会解锁,不过别的程序也找不到对象记录了(因为被删除)实际使用中,通常并不会对文件中的记录进行物理删除,而是修改某个标识状态的字段的值,所以使用这条命令要慎重
DIV {(H)} (Divide) 数学运算—除
DIV 操作码,表示数学运算的“除”,常与操作码MVR 一起来使用。
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
上面两句话的意思,是说,用FLD01 来除FLD02,将商赋值到变量N 中,将余数,赋值到变量中。
(N,M 都是数字型变量)再具体一点,如果FLD01 = 10, FLD02 = 3,执行完这两句操作码之后
N = 3 (10 / 3 的商)
M = 1 (10 / 3 的余数)
DO (Do) 循环
最常用的循环方法之一,适用于已知循环次数的循环,与ENDDO 搭配使用,每一个DO,必须要配合一个ENDDO。基本语法如下
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
循环中处理的内容
ENDDO
上面的意思,就是说固定循环10 次。
不过呢,在实际使用中,我们常常需要知道当前循环到了第几次处理,这里,可以:
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
处理过程
ENDDO
这个N,是一个整数型变量(小数位为0 的P 型吧),它所表示的就是循环的次数。如第一次循环,N=1;第二次循环,N=2所以, 1 DO 1,就表示只循环一次,而不是表示死循环。
DOU {(M | R)} (Do Until) 还是循环
也是循环,不过当满足Extend Factory 2 项的条件之后,结束循环。如下:
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
处理过程
ENDDO
上面这句话,就是说当FLD01 小于或等于FLD02 时,进行循环;当满足条件,即FLD01大于FLD02时,结束循环。在RPGLE 的写法中,这个条件可以写得很复杂。当然,很复杂的时候,要记得多括号,以免得逻辑判断与设计不一致。
DOUxx (Do Until) 又是循环
这应该是RPG 的写法,上面的循环也可以写做:
1 | FLD01 DOUGT FLD02 |
不过,正如果前面所说的“ANDxx”操作码一样,RPGLE 的表示手法可以比RPG 更直观,更好维护,所以这里也是一样的原理,有了“DOU”之后,我们就可以不用“DOUxx”了
DOW {(M | R)} (Do While) 循环,又见循环
这个循环的意思,与DOU 正好相反,它的意思是满足Extend Fatcory 2 项的条件时,才进行循环,不满足条件时,不循环
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
处理过程
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 | Factory 1 Operation Factory 2 Result HI LO EQ |
就是在屏幕上,显示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
2Factory 1 Operation Factory 2 Result HI LO EQ
EVAL FLD01=FLD02赋值,使用FLD01 的值,等于FLD02 的值。FLD01 与FLD02 的类型必须相同(即
同为字符型,或同为数字型,但长度可以不同。当FLD01、FLD02 同为字符型时,EVAL 语句其实等价于:
1
2EVAL FLD01=\*BLANKS
MOVEL FLD02 FLD01即先清空FLD01(当FLD01 长度长于FLD02,且有初始值时,这个操作就有意义了),然后再将FLD02 左对齐赋值到FLD01 中。所谓左对齐的含义,就是说将FLD02 至左向右(含空字符),依次向FLD01 字段中赋值。当FLD02 长度大于FLD01 时,右边的字符在赋值时将会被截去。
当FLD01、FLD02 同为数字型时,且FLD02 的值,超过FLD01 的长度时,EVAL语句会直接报错,程序异常中断;
当FLD01、FLD02 同为字符型时,且FLD01 的长度大于FLD02 时,将会将FLD02的值左对齐赋值到FLD01 中,并且将后面内容全部清空。
比如FLD01=’12345678’(8 位字符型),FLD02=’54321’(5 位字符型)执行了 EVAL FLD01=FLD02
之后,FLD01=’54321 ‘当FLD01、FLD02 同为字符型,且FLD01 的长度小于FLD02 时,会将FLD02 的内容左对齐,再赋值到FLD02 中。
字符的拼接:
1
2Factory 1 Operation Factory 2 Result HI LO EQ
EVAL FLD01=FLD02+FLD03+’AAA’+’BB’+FLD04FLD01、FLD02、FLD03、FLD04 都必须是字符。FLD02、FLD03 如果字符未满,有空格,EVAL 操
作码不会将空格去掉。如果太长,可以分多行写,“+ ”在上在下都可。即1
2EVAL FLD01 = FLD02 +
FLD03等价于
1
2EVAL FLD01 = FLD02
+ FLD03数学运算:
Factory 1 Operation Factory 2 Result HI LO EQ
EVAL FLD01 =(((LD02+FLD03)* FLD04) / 2) - FLD05
加、减、乘、除都在了。注意多用括号。
如果运算公式太长,一行写不完,也可以分行写,运算符在上行、下行都可以。四舍五入:
对于数字运算,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 | Factory 1 Operation Factory 2 Result HI LO EQ |
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 | Factory 1 Operation Factory 2 Result HI LO EQ |
这时,FLDYEAR 表示当前的年份;FLDHOUR 表示当前的小时所以说,EXTRCT 操作码对应的对象变量,可以是字符型,也可以是数字型,但长度一定要与预期的对象长度相等(比如年份可以是字符,也可以是数字,但长度必须为4 位;月份必须为2 位,依此类推)而冒号后面所跟的参数,与ADDDUR 操作码一样,如下:
对应于日期型变量:
*D表示天,也可用*DAYS
*M表示月,也可用*MONTHS
*Y表示年,也可用*YEARS
对应于时间型变量
*H 表示小时,也可用*HOURS
*MN 表示分钟,也可用*MINUTES
*S 表示秒, 也可用*SECONDS
FOR (For) 又是循环
FOR 操作码,也是一种指定次数的循环,与“DO”循环有异曲同工之妙。
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
处理语句
ENDFOR
等价于
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
都是循环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 | Factory 1 Operation Factory 2 Result HI LO EQ |
当条件判断成立时,才会执行下面的处理语句。
条件判断可以使用括号,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 | Factory 1 Operation Factory 2 Result HI LO EQ |
等价于
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
不知道这个例子能不能让人明白,都是在说当条件判断成立时,就不执行处理语句2,直接从循环头开始处理。ITER 语句执行后,程序相当于跳转至循环体中的第一句,重新向下运行(即执行循环)。当有多层循环嵌套时,ITER 仅作用于最里层的循环。当循环中执行了子过程时,子过程中不能对该循环进行ITER 操作。也就是说:DO,ENDO,ITER 这些语句必须在一块(即要么都在主过程中,要么都在同一个子过程中)
KFLD (Define Parts of a Key) 定义组合键值中的字段
这个其实应该与KLIST 一起来讲,因为这两个操作是在一起使用的。一个PF 对应的逻辑文件LF,可能会有多个KEY 值,那么,我们要根据多个KEY 值,对于该逻辑文件进行查询定位操作时,就需要使用KLIST、KFLD 这两个操作码:
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
组合键值的使用方式,就是将组合键视为一个变量,进行各种操作,如:
FHSKEY CHAIN FMTFHS
或 F
HSKEY SETLL FMTFHS
意思,就是说按组合键值,查询定位到逻辑文件PFFHSL3 中去。
这里要注意,PFFHSL3 的键值是FHS01、FHS02(即PF 文件中的字段),而程序中的组合键
值为FLD01、FLD02 两个程序中定义的变量,只要类型、长度与键值FHS01、FHS02相等即可。同
时,对文件进行查询定位操作后,在没有对FLD01、FLD02 赋值之前,这两个字段的值是不会发
生变化的(即不会更改组合键的键值);但是,组合键中的字段,也可以直接定义为PF 文件中
的字段,如
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
此时,可以将PF 文件中的字段FHS01、FHS02 先视为两个普通的变量,进行赋值,然后用
组合键FHSKEY 对PFFHSL3 进行查询定位;当执行完CHAIN,或READ 语句后,因为读取到了文件
中的数据,所以FHS01、FHS02 的值将发生变化,也即是组合键FHSKEY的键值发生了变化。基于
此,所以通常我不会将组合键的字段设置为查询文件中的字段,而是定义为几个独立的临时字
段,以免需要过于频繁的考虑键值的更改。
KLIST (Define a Composite Key) 以上面的KFLD 操作码
LEAVE (Leave a Do Group) 退出当前循环
退出当前循环,语法和注意事项基本与“ITER”相同:
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
等价于
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
这两个例子都是在说当条件判断成立时,就不执行剩余的循环体,直接跳出循环。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 | Factory 1 Operation Factory 2 Result HI LO EQ |
首句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
2
3Factory 1 Operation Factory 2 Result HI LO EQ
MOVE FLD01 FLD02
FLD01、FLD02 可以是不同的类型。即允许一个为字符,一个为数字 - 允许在MOVE 操作中,对Result 字符进行定义。
- 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 | Factory 1 Operation Factory 2 Result HI LO EQ |
等于
EVAL FLD03 = FLD01 * FLD02
可以对当前行对FLD03 进行定义;
Factory 1 可以不填写;
必须保证FLD03 的位数足够大,否则超长时,程序会报错异常退出。
MVR (Move Remainder) 数学运算—除法运算取余
这个操作码,在讲操作码DIV 时,已讲过:
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
当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 | Factory 1 Operation Factory 2 Result HI LO EQ |
等价于
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 | Factory 1 Operation Factory 2 Result HI LO EQ |
在这个例子中,当满足条件判断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
2Factory 1 Operation Factory 2 Result HI LO EQ
READ 文件记录格式名 45 46READ后面跟的,必须是声明的文件记录格式名;
LO 指示器表示锁表指示器,当在指定的时间(CHGPF,WAITRCD 项可看到),需要读取的
记录仍被锁,将会打开LO 指示器,即*IN45=’1’;
EQ指示器为是否读到指示器。当未读到任何记录时,打开EQ 指示器,即*IN46=’1’当文件在程序中,是用只读的方式声明时,READ 操作并不会造成锁表;
如果文件在程序中是用修改的方式声明,READ 操作成功后,该记录被锁;直到执行解锁操作(UNLOCK,或UPDATE),或READ 该文件的其它记录,才会解锁
如果文件是用修改的方式声明,但希望READ 操作不锁表时,那么就用READ(N),
即1
2Factory 1 Operation Factory 2 Result HI LO EQ
READ(N) 文件记录格式名 45 46这样读文件,就不会锁记录,但是同时也不能修改记录。如果需要修改记录,那么在修改之前(包括对文件字段赋值之前),还必须再对该记录进行一次定位操作(比如CHAIN、READ 语句均可)。也就是说,如果要修改记录,必须先锁住当前记录。
当执行READ 操作时,程序是根据游标当前在文件中所指向的位置,顺序读取下一条记录。
执行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
11Factory 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
2Factory 1 Operation Factory 2 Result
ROLBK - 该操作码无其它参数,就是指对事务处理进行回滚操作。
- ILE 程序中,ROLBK 操作可随时进行,也允许在没有声明COMMIT 类型的文件的情况下,仍
进行ROLBK 操作(对该进程这前的事务进行确认处理)
SCAN {(E)} (Scan Character String) 扫描字符串
扫描字符或字符串Factory 1 在对象字符串Factory 2 中是否存在
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
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 | Factory 1 Operation Factory 2 Result HI LO EQ |
要注意,SELECT 操作码,必须有对应的ENDSL 操作码,否则编译无法通过。
SETGT {(E)} (Set Greater Than) 定位操作—大于
举个例子吧,假设文件中有一个字段,是标识顺序号的,1、2、3、4。即该字段为1,
表示第一条记录,该字段为2,表示第2 条记录。那么:
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
这个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 | Factory 1 Operation Factory 2 Result HI LO EQ |
等价于
1 | EVAL *IN10=’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 | Factory 1 Operation Factory 2 Result HI LO EQ |
这时,N=3(因为3 的平方为9)
9、3 都可以是数字型变量,或者直接是数字
SUB {(H)} (Subtract) 减法操作
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
SUBDUR {(E)} (Subtract Duration) 日期相减
- 减日期表示将日期型变量FLD01 减去N 年,赋值到日期型变量FLD02 中;
1
2Factory 1 Operation Factory 2 Result HI LO EQ
FLD01 SUBDUR N:*Y FLD02
N 可以是一个数字型变量,也可以就是一个数字,N 允许为负数
*Y,*M,*D(还有其它的参数值,可见ADDDUR,其中有详细解释) - 判断两个日期型变量之间的天/月/年数这时,N 做为一结果变量,表示日期型变量FLD01 与FLD02 之间的天数
1
2Factory 1 Operation Factory 2 Result HI LO EQ
FLD01 SUBDUR FLD02 N:*D
SUBST {(P | E)} (Substring) 取字符/字符串
1 | Factory 1 Operation Factory 2 Result HI LO EQ |
表示从字段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 | Factory 1 Operation Factory 2 Result HI LO EQ |
Factory 1 Operation Factory 2 Result HI LO EQ
SELECT
WHEN 条件判断1
处理语句1
WHEN 条件判断2
处理语句2
OTHER
处理语句3
ENDSL
1 | ## WHENxx (When True Then Select) |
Factory 1 Operation Factory 2 Result HI LO EQ
CLEAR 文件记录格式名
EVAL 文件字段1=xxxx
EVAL 文件字段2=xxxx
WRITE 文件记录格式名
1 | 表示在文件中写入一条新记录。文件需要声明为可写的 |
Factory 1 Operation Factory 2 Result HI LO EQ
MOVEL ‘ABCAAAC123’ MYCHAR1
‘A’:’9’ XLATE MYCHAR1 MYCHAR2
1 | 执行过这个语句之后,MYCHAR2 就等于”9BC999C123’,即将字符串MYCHAR1 中所有的“A”都 |
Factory 1 Operation Factory 2 Result HI LO EQ
Z-ADD FLD01 FLD02
1 | 将数字型变量FLD01,赋值到数字型变量FLD02 中。 |
EVAL FLD01=*ALL’0’
1 | 表示将字符型变量FLD01 赋值为全’0’ |
EVAL MYLEN = %LEN(FLD01)
1 | 这句话的意思,是指取字符串FLD01 的长度,不过通常这样用是没意义的,因为直接用%LEN |
EVAL MYLEN = %LEN(%TRIMR(FLD01))
1 | 这时的MYLEN,就是指变量FLD01 中的有效长度(前提条件是FLD01 中如果有值,是左对齐)。 |
EVAL FLD04 = FLD01 + FLD01 + FLD02
1 | FLD04 就等于“A A ”,也就是第二位与第四位都是空的,最后加的FLD02 其实无效。而 |
EVAL FLD04 = %TRIMR(FLD01) + %TRIMR(FLD01) + FLD02
1 | 则FLD04 就等于“AABC”,也就是说,在这里,%TRIMR(FLD01),是等价于单字符“A”的 |