AS400程序使用手册

更新时间:2024-01-17 06:33:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

1 2

简单说明 ................................................................................................................................... 3 程序代码行的编写 ................................................................................................................... 3 2.1 最简单的RPGLE程序 ............................................................................................ 3 2.2 举例准备 ................................................................................................................... 3 2.3 简单的程序流程 ....................................................................................................... 4 2.4 常见的程序流程 ....................................................................................................... 5 2.5 F行说明 ................................................................................................................... 5

2.5.1 内容说明 ........................................................................................................... 5 2.5.2 常用例子 ........................................................................................................... 9 2.5.3 补充说明 ......................................................................................................... 10 2.6 D行说明 ................................................................................................................. 10

2.6.1 内容说明 ......................................................................................................... 10 2.6.2 常用例子 ......................................................................................................... 13 2.6.3 补充说明 ......................................................................................................... 14 2.7 入口参数 ................................................................................................................. 14 2.8 C行说明 ................................................................................................................. 16

2.8.1 写在前面 ......................................................................................................... 16 2.8.2 内容说明 ......................................................................................................... 17 2.8.3 ILE操作码分类: .......................................................................................... 18 2.8.4 ILE操作码...................................................................................................... 19

2.8.4.1 A--C ......................................................................................................... 19 2.8.4.2 D--E .......................................................................................................... 27 2.8.4.3 F--N .......................................................................................................... 32 2.8.4.4 O--R ......................................................................................................... 39 2.8.4.5 S--Z .......................................................................................................... 43

和程序相关的数据库知识 ..................................................................................................... 49 3.1 LF(逻辑文件) .................................................................................................... 49

3.1.1 逻辑文件概念 ................................................................................................. 49 3.1.2 有关编译的问题 ............................................................. 错误!未定义书签。 3.1.3 逻辑文件对效率的影响 ................................................................................. 51 3.2 MEMBER ............................................................................................................... 51 3.3 游标 ......................................................................................................................... 52

3.3.1 游标的概念 ..................................................................................................... 52 3.3.2 不同操作码对应的游标的处理 ..................................................................... 52 3.3.3 “有且仅有”的游标 ..................................................................................... 53 3.3.4 LOVAL、HIVAL对应的游标操作 ............................................................... 53 3.4 事务处理 -- COMMIT ........................................................................................... 54

3.4.1 概念描述 ......................................................................................................... 54 3.4.2 使用方法 ......................................................................................................... 54 3.4.3 注意事项 ......................................................................................................... 55 3.5 关于锁表的问题 LCKW ....................................................................................... 56 DEBUG调试以及常见出错信息 .......................................................................................... 56

3

4

4.1 4.2

5

6 7

写在前面 ................................................................................................................. 56 常规用法 ................................................................................................................. 57 4.2.1 程序编译 ......................................................................................................... 57 4.2.2 执行DEBUG命令 ......................................................................................... 57 4.2.3 运行程序 ......................................................................................................... 57 4.2.4 在DEBUG模式中进行调试 ......................................................................... 58 4.2.5 跟踪被当前程序调用的程序 ......................................................................... 58 4.2.6 一定要退出DEBUG模式 ............................................................................. 59 4.2.7 补充 ................................................................................................................. 59 4.3 跟踪批处理程序( From qingzhou) ......................................................................... 60 4.4 常见的出错信息 ..................................................................................................... 60

4.4.1 编译程序时的出错信息 ................................................................................. 60 4.4.2 运行时的出错信息 ......................................................................................... 62 CL、CMD .............................................................................................................................. 62 5.1 CL程序................................................................................................................... 62

5.1.1 基本认识 ......................................................................................................... 62 5.1.2 CL程序的常用语法及命令: ....................................................................... 63 5.1.3 不常用的语法 ................................................................................................. 65 5.2 CMD........................................................................................................................ 66 屏幕文件及使用 ..................................................................................................................... 67 其它......................................................................................................................................... 67 7.1 报表打印 ................................................................................................................. 72 7.2 SAVF,备份与恢复 ............................................................................................... 77 7.3 菜单--MENU .......................................................................................................... 78 7.4 开发时常用的命令 ................................................................................................. 78 7.5 一点想法 ................................................................................................................. 81

1 简单说明

内部交流、或可作培训使用。对用户作如下假定: 1、 能COPY、修改、编译源代码(RPGLE、CLP),并能运行编译后的程序 2、 能COPY、修改、编译文件(PF、LF、PRTF、DSPF);

3、 对数据文件(PF)有简单的认识(FIELD ? RECORD ? PF),并知道LF与PF的

对应关系。

2 程序代码行的编写

2.1 最简单的RPGLE程序

为便于理解,这里写一个最简单的RPGLE程序

CL0N01Factor1+++++++Opcode&ExtFactor2+++++++Result++++++++Len++D+HiLoEq *************** Beginning of data *************************************

0001.00 C 'HELLO WORLD' DSPLY 0002.00 C RETURN

****************** End of data ****************************************

这个程序编译成功,并调用(CALL 程序名),就是在屏幕上反白显示“HELLO WORLD”字样。(其中,绿色字样,是系统自动显示的,下同)

与自由风格的C语言不同,RPGLE中的编码,是有一定的格式,如果写错,将会在当前代码行上高亮反绿显示。初学者如果不太清楚从何处开始下手,可以使用“F4”键查看(F4键只有用2进入的编辑状态才有效,用5进入的查看状态是无效的)

Level N01 Factor 1 Operation Factor 2 Result 'HELLO WORLD' DSPLY Decimal Length Positions HI LO EQ Comment 关于每一项所对应的内容代表什么意思,该如何填写,即如何写程序,将会在下面的具体讲解。

2.2 举例准备

列出表名,字段,以方便下面的举例。

假设有PF文件叫PFFHS,文件的记录格式叫FMTFHS

每条记录,都是由FHS01、FHS02、FHS03三个字段组成,每个字段都是两位长的字符

型变量。

逻辑文件PFFHSL1的键值为FHS01 逻辑文件PFFHSL2的键值为FHS02

逻辑文件PFFHSL3的键值为FHS01、FHS02 注:

文件的记录格式,可以理解为给这个文件整条记录起的一个名字;或者是说将每条记录视都视做一个类型相同大变量,然后给这个大变量起的名字。所以文件的记录格式信息中,包含有一条记录由多少个字段组成,总计长度是多少这样的信息。

文件的记录格式,与各个字段同时定义。(写文件的源码时) 文件的记录格式在RPGLE的程序中,不能与文件名相同。

2.3 简单的程序流程

为方便起见,系统自动显示的就不再贴出来了,只贴代码段。

FPFFHS UF E DISK C READ FMTFHS C EVAL FHS01=”01” C UPDATE FMTFHS C SETON LR C RETURN

这个程序的意思,是说读PFFHS这个文件,然后将读到的第一条记录中的FHS01这个字段的值修改为“01”。

“SETON LR”,LR的位置可在HI、LO、EQ中任选一处。意思是指将打开指示器*INLR,即赋值使指示器*INLR的值等于1。等价于 “ EVAL *INLR=’1’ ”,意思是强制将内存中的数据写到磁盘中。(基于效率因素,系统在修改文件时,会先将修改的结果先放在内存中,在同一程序中,读取数据也是先从内存中查询。)LR,取自是Last Record

RETURN,表示程序结束,在后面“操作码”一节中,会有讲述。 如果不太明白,就记住 C SETON LR C RETURN 或 C EVAL *INLR=’1’ C RETURN

这两句话加在一起,表示程序结束就可以了。

从这个程序中,我们可以看到,RPGLE的程序,大致上可以分为两个部分: 1、 声明、定义部分:声明程序中使用到的文件(F行),定义程序中使用的变量(D行) 2、 程序运行部分 :即C行,也就是程序段。

在RPGLE程序中,F行必须在D行前面,D行必须在C行前面。

程序执行的起始顺序,将从定义部分之后,第一个C行开始,顺序向下执行。

程序中的F行、D行都不是必须项,一个程序可以没有F行(如仅完成计算功能的公共函数,比如计算利息),也可以没有D行(没有需要特别定义的变量,或者所有变量都在C行进行定义),但不应该没有C行,因为F行与D行都属于非执行行,是起定义作用;C行是执行行。没有C行的程序,是无执行意义的。

2.4 常见的程序流程

FPFFHS UF E DISK //声明文件PFFHS D LSFLD01 S 2 //定义临时变量LSFLD01 C EVAL LSFLD01=’01’ //给变量LSFLD01赋值 C EXSR SUB#UPD //执行子过程SUB#UPD C EVAL LSFLD02=’02’ //给变量LSFLD02赋值 C EXSR SUB#UPD //执行子过程SUB#UPD C SETON LR //数据写入磁盘 C RETURN //程序结束 C SUB#UPD BEGSR //子过程SUB#UPD开始 C READ FMTFHS //读PFFHS文件 C EVAL FLD01=LSFLD01 //给字段FLD01赋值 C UPDATE FMTFHS //修改文件 C ENDSR //子过程结束

“//”后面的,只是简单的解释,如果自已动手写,不需要输入这些内容。 系统在运行这个程序时,是按如下的顺序来执行: 1. 首句EVAL赋值语句,直接执行;

2. 当系统发现操作码“EXSR”时,根据后面的变量名“SUB#UPD”,去查找对应的

“SUB#UPD BEGSR”语句; 3. 然后从“SUB#UPD BEGSR”之后,顺序向下执行,直至“ENDSR”语句 4. 执行到“ENDSR”之后,将会再回到当初的“EXSR SUB#UPD”处,继续向下

执行,直到RETURN语句为止

这里提出一点要注意,如果子过程中,又执行了自身,即在SUB#UPD程序中,又出现了“EXSR SUB#UPD”,是可以编译通过的,但在执行过程中,系统会因为无法定位,而出现死循环,直至报错异常中断退出。也就是RPGLE的程序中,子过程不允许出现递归。

2.5 F行说明 2.5.1

内容说明

首位填上F,然后按F4,会出现如下内容:

D FHS02 3 4 D FHS03 5 6

是等价的,都是定义一个结构变量MYDS(名字可以自行定义),这个结构变量是由三个字符型变量FHS01,FHS02,FHS03拼成的。

第一种定义方法,就是引用外部文件“PFFHS”作为数据结构的定义,注意使用到了“EXTNAME”关键字,而且“E”项的值为“E”。

而第二种定义方法,就是直接定义一个结构“MYDS”。注意没有使用外部文件时,“E”项的值为空。 S/U: 不知道,一般都填空。 Declaration Type: 定义变量的类型,允许的值如下: 不填: 非以下内容:数据结构、常量、独立变量、数组、表。此项为空时,好象只能用来表示当前定义的变量是属于结构的一个变量。在下面会举例 DS: 数据结构,即定义一个结构变量,这个之前已讲过 C: 常量

常量只能使用字符,不需要定义常量的长度、类型。常量的内容写在“Keywords”处,并使用CONST关键字,在程序段中,不能对常量进行赋值操作。

D MYNUM C CONST('abcdefghijklmn')

就是定义一个叫做MYNUM的常量,这个常量包含字母a--n。

PI: 不知道,没有用过 PR: 不知道,没用过 S: 定义以下内容:独立变量、数组、表 定义一个叫MYFIELD1的变量,变量为1位长的字符型 D MYFIELD1 S 1 //1在“To/length”项 定义一个叫MYARRAY的数组,共含3条记录,每条记录为1位字符型 D MYARRAY S 1 DIM(3) //DIM在“Keywords”项 表的定义没有用过 总之,这一项,最常用的,就是“DS”、“S”与空。即结构体与独立变量,其它选项较少用到。 From: 当“Declaration Type”项为“S”时,表示独立变量、数组,此项不填 当“Declaration Type”项为“DS”时,表示结构,此项仍然不填

当“Declaration Type”项为空时,表示当前定义的变量,属于上面定义的结构,此时,此项可以填写,也可以不填写。

当填写时,“From”项表示变量在结构中的起始位置,右对齐;“To/length”表示变量在结构中的结束位置,也是右对齐。

当不填写时,“To/length”表示直接定义为变量长度。 举例: D MYDS DS D DSFLD01 1 2 //1在“From”项,2在“To/length”项 D DSFLD02 3 4 与

D MYDS DS

D DSFLD01 2 //2在“To/length”项 D DSFLD02 2

其实是等价的,都是定义一个结构变量MYDS,这个结构变量中,包含了两个变量DSFLD01,DSFLD02,这两个变量都是两位长字符。所不同的是,第一种定义方法,是指定了变量在结构中的位置;而第二种方法,是直接指定变量的长度和类型

注意到上面的定义中,DSFLD01、DSFLD02的Declaration Type为空,也就是表示这两个字段是属于上面定义的结构MYDS。如果此项为“S”,即表示这个变量与结构无关

D MYDS DS

D DSFLD01 2 //2在“To/length”项 D DSFLD02 S 2

在这个定义中,变量DSFLD02就是一个独立的变量,与结构MYDS无关。

Length: 上面已讲述在定义结构时的使用方法。 在定义非结构时,此项的内容即为定义变量的长度。右对齐 Internal Data Type: 定义变量的类型,允许的值有: 空:变量定义为字符型、压缩型数字 A: 变量定义为字符型 B: 二进制?不知道 D: 变量定义为日期型 F: 变量定义为浮点型? G: 变量定义为图型?(非英文?汉字?) I: 变量定义为带符号的整数 N: 变量定义为指示器变量?(没用过) P: 变量定义为压缩型数字 S: 变量定义为普通的数型 T: 变量定义为时间型 U: 变量定义为无符号的整数 Z: 变量定义为日期+时间型(格式:年-月-日-时.分.秒.微秒) *: 变量定义为指针型 其实我最常用,就是不填,因为一般的程序,有字符和数字这两种类型变量,就足够了。 Decimal Positions: 当变量定义为数字型时,用来标志小数的位数。 当“To/Length”项为3,“Internal Data Type”项为空时 此项为空,表示定义的变量为3位长的字符型 D MYFLD01 S 3 //定义为3位字符型 此项不为空(右对齐),表示定义的变量为数字型 D MYFLD01 S 3 2 //定义数字型变量,1位整数,2位小数(总长为3位) Keywords: 关键字,可以不填,常用的值如下:(同样,这里我也只列出几个常用的,这里先不做详细说明,仅供参考,在后面的例子,看看就知道用法了) CONST: 定义常量的值

DIM: 定义数组

EXTNAME:引用外部文件作为数据结构变量

EXTFLD: 对引用了外部文件作为数据结构的某个变量,进行重命名 LIKE: 定义变量时,参照已存在的变量定义

OCCURS: 定义结构体变量时,指定的结构体变量的记录条数 INZ: 定义变量时,赋值初始值

DATFMT: 定义日期变量时,指定日期格式 *MDY (mm/dd/yy)

*DMY (dd/mm/yy) *YMD (yy/mm/dd) *JUL (yy/ddd) *ISO (yyyy-mm-dd) *USA (mm/dd/yyyy) *EUR (dd.mm.yyyy) *JIS (yyyy-mm-dd)

Comment

注释项,源自RPG,不用填,因为填了也没用。

2.6.2 常用例子

定义一个10位长的字符型变量:

D MYFLD S 10

定义一个10位长,其中含2位小数的字符型变量,并使其初始值为1 D MYFLD S 10 2 INZ(1)

定义一个每条记录为5位长字符型变量,共10条记录的数组 D MYFLD S 5 DIM(10)

定义一个10位长的字符型变量,再定义一个变量,参照前一变量定义 D MYFLD01 S 10 D MYFLD02 S LIKE(MYFLD01)

定义一个结构,由一个3位长的字符变量,和一个10位长,其中2位小数的数字变量组成 D MYDS DS D MYDS01 3 D MYDS02 10 2

定义一个结构变量,结构内容参照外部文件PFFHS D MYDS E DS EXTNAME(PFFHS)

定义一个结构变量,结构内容参照外部文件PFFHS,并且将第二个字段重命名为FHS999 D MYDS E DS EXTNAME(PFFHS) D FHS999 E DS EXTFLD(FHS02) 定义一个日期型变量,格式为yyyy-mm-dd D MYDATE S D DATFMT(*ISO)

2.6.3 补充说明

变量的定义,除了在D行定义之外,还可以在C行通过赋值语句直接定义 如

D FLD01 S 2 INZ(‘01’) 与 C MOVE ‘01’ FLD01 2 //2在length处,右对齐 是等价的

定义结构之后,可以将结构变量视为一个普通的变量进行赋值来改变结构变量的值,也可以通过对组成结构变量的变量进行赋值,来达到修改结构变量的值的目的。

如: D MYDS DS D MYFLD01 2 D MYFLD02 2 在C行中,这两句是等价的 C EVAL %SUBST(MYDS:3:2)=’01’ C EVAL MYFLD02=’01’ 第一句是直接改结构变量MYDS的后两位的值(当然,此时MYFLD02的值也变化了) 第二句是对MYFLD02进行赋值,同样,赋完值之后,MYDS的后两位也变为’01’

在需要频繁进行数字与字符之间转换时,偷懒的人会通过定义这样的结构来达到目的: D MYDS DS D MYFLD01 1 8 D MYFLD02 1 8 0

比如说,给MYFLD01赋值为’20070208’之后,MYFLD02也就自动等于20070208;然后给MYFLD02加1之后,MYFLD02等于20070209,MYFLD01的值也自动等于’20070209’。可以认为结构变量MYDS是字符型(即一直等于MYFLD01的值)

这种方法,当需要字符型变量时,就使用MYFLD01;当需要数字变量时,就使用MYFLD02,不过我总觉得有点类似于作弊,一般没用。

关于数组、结构体的内容,因为要说起来内容还颇多,而也属于略为高级一些的用法,所以将在后面专设章节讲述。

2.7 入口参数

程序可以通过“*ENTRY”定义入口参数,或称之为接口参数,来传递数据。 假设有程序FHS01ILE,其中入口参数的定义如下: C *ENTRY PLIST C PARM FLD01 3 C PARM FLD02 4 其中:

*ENTRY在“Factor 1”项;

PLIST在“Operation”项; PARM在“Operation”项;

FLD01、FLD02都在“Result”项

上述定义,表示这个程序通过两个字段与其它外部程序沟通。那么别的程序(如FHS02ILE)在调用程序FHS01ILE时,就要带上两个字符型变量,如

C CALL ‘FHS01ILE’ C PARM FHSFLD01 3 C PARM FHSFLD02 4

在两个程序里,这两个变量名可以不同(比如说一边叫FHSFLD01,FHSFLD02;一边叫FLD01,FLD02),但长度,类型必须匹配。

如果在FHS02ILE中,FHSFLD01等于’123’,FHSFLD02等于’abcd’,那么系统在运行CALL语句,执行程序FHS01ILE时,将会对字段FLD01初始化赋值,使其一开始就等于’123’,字段FLD02等于’abcd’。

如果FHS01ILE程序中,对FLD01、FLD02进行了改动,比如FLD01最后等于’789’,FLD02最后等于’efgh’,那么程序FHS02ILE在调用完FHS01ILE之后,FHSFLD01、FHSFLD02这两个字段也同样会改变,成为’789’,和’efgh’

也就是入口参数的变化是可以传递的,其实应该很好理解吧。

入口参数的定义,可以写在程序的任何一处,而程序的执行,始终是从C行的顺序第一行开始执行,与入口参数所在的位置无关。

FHS02ILE也可以使用一个大变量来调用FHS01ILE,只要总长相等即可(这种方法仅限于被调用的程序FHS01ILE的入口参数全部为字符型才可使用,仅仅只是不会错,不建议这样使用。

C CALL ‘FHS01ILE’ PARM FHSFLD01 7

其实从上面的例子可以看出,入口参数可以使用结构的形式来表达,所以下面这种写法也不会有错。(如果被调用程序有数字型变量,只要在定义结构时也定义为数字型即可)

D MYDS DS D DS01 3 D DS02 4 C CALl ‘FHS01ILE’ C PARM MYDS

不过要注意,如果RPG程序调用C程序,那么入口参数必须严格按照C程序中的来,比如C程序中带了两个字符型参数,那么RPG程序中也必须是两个字段入口参数,不能使用由两个字符变量组成的结构。原理可以自行想想。

既然可以使用结构做为入口参数,当然,也可以参照外部文件来定义结构做为入口参数

D MYDS E DS EXTNAME(PFFHS) C CALL ‘FHS01ILE’

C PARM MYDS 与 C CALL ‘FHS01ILE’ C PARM FHS01 2 C PARM FHS02 2 C PARM FHS03 2 是等价的。

可以看到,参照外部文件定义结构做为入口参数时,可以有效的节省代码行,而且不会出现遗漏。所以在实际使用中,常会看到,将一些公共程序的入口参数定义成一个PF文件。而调用它的程序,就参照这个PF文件,定义结构做为调用的接口参数。

当接口参数不一致时,如FHS02ILE中漏了第二个参数时: C CALL ‘FHS01ILE’ C PARM FHS01 3 此时,并不是一开始运行FHS01ILE程序,系统判断入口参数不符就报错;实际上,此时,FLD01的值还是正确的,但FLD02的值就处于一个未初始化的状态。于是,当代码执行到与FLD02有关的操作码时,才会报错;如果FHS01ILE在运行的过程中,因为逻辑判断(如IF条件判断)的关系,而未执行任何与FLD02有关的操作码,那么程序会正常运行完毕,不会有报错。

这时,FHS02ILE调用了程序FHS01ILE之后,程序中原有的接口参数的数据就可能因为这次调用程序而发生错位,从而导致数据的错误、混乱。数据的错误、混乱其实还不是最大的问题,更大的问题在于“这时我们不知道数据已经出错了”。解决之道,也是如上所说,对于调用频繁,且入口参数较多的公共程序,考虑将其入口参数写成一个PF文件。这样调整入口参数时,只要修改PF文件并重新编译,再编译相关程序即可(至少发生遗漏时,程序会报错异常中断,不会出现错误的数据而不自知)

2.8 C行说明 2.8.1

写在前面

终于说到程序的执行部分,也是我们写程序的平时接触的最多的一部分:“C”行了。在这里,我想先说一下我个人的看法: 400系统,提供了一些语法,可以大大减少程序代码行数。但是如果这个用法并不普遍,那么并不建议使用(当然自己用来练习无妨),否则会给其它读代码的人带来困难,同时也会给自己带来麻烦(比如出了问题,别人看不懂,自然会打电话来问原作者) 基于这样的道理,同样,我认为FREE格式的程序,虽然可以自由书写,有缩进等优势,但是除非整个项目组所有成员都已熟练掌握FREE格式的程序,或已进行过完善、系统的FREE格式的培训,才能正式使用。如果只是知道几个与RPG,RPGLE对应的语法就用来进行实际处理,可能会造成的维护的不便,尤其是在出现一些不那么明显的错误之后。 至于cycle,不知道是不是基于这个原因,现在用得也比较少了。感觉RPGLE中,至少有一半的内容是与cycle相关的。

2.8.2 内容说明

Level N01 Factor 1 Operation Factor 2 Result

Decimal Length Positions HI LO EQ Comment

Level: 和cycle相关,没研究过,一般不填 N01: 这个含义比较丰富,我只用过其中一种: 首位不带N,后面填写01—99的数字时,表示相应的指示器打开时,执行后面的操作,如: C 12 EVAL FHS01=’01’ 等价于 IF *IN12=’1’ EVAL FHS01=’01’ ENDIF 首位带N,后面填写01—99的数字,表示相应的指示器关闭时,执行后面的操作 要注意,该项内容仅作用于该行操作码。如果指示器打开后,需要执行多条语句,那么每条语句前面,该项都要赋值。 即 C IF *IN12=’1’ C EVAL FHS01=’01’ C EVAL FHS02=’02’ C ENDIF 如果用这种方式来表达,就要写作 C 12 EVAL FHS01=’01’ C 12 EVAL FHS02=’02’ 所以说,根据指示器状态来执行的语句,在执行少量操作码时,可以使用这种方法;如果语句较多,修改起来不方便,还是直接用IF—ENDIF的判断语句比较合适。 该项还有针对其它指示器的用法,看上去似乎又是与CYCLE相关,暂不介绍了。 Factor 1: 操作内容一,将在后面与操作码一起讲 Operation: 操作码,后面有专门章节讲解操作码 Factor 2: 操作内容二,同上 Result: 操作结果,同上 Length: 长度。

变量的定义,除了在D行定义之外,还可以在C行通过赋值语句直接定义 如

D FLD01 S 2 INZ(‘01’) 与 C MOVE ‘01’ FLD01 2 //2在length处,右对齐 是等价的

一个变量,在整个程序中,只要定义一次就可以了,对定义的顺序没有强制要求。 Decimal Positions: 与length相呼应,当此项有值时,表示定义的是一个数字型变量,该项表示小数位长度。 如 C Z-ADD 2 FLD02 3 2 即是说,将FLD02定义为一个3位长,其中1位整数,2位小数的数字变量,并赋值为2.00

HI、LO、EQ 这是三个指示器位置项。可赋值的内容是从01—99,在以后的说明中,如果HI项填写10,LO项填写20,EQ项填写30,那么我所说的HI指示器,即是指*IN10,LO指示器即是*IN20,EQ指示器即是*IN30,依此类推。(也就是说,HI指示器,并不是*INHI,事实上,也没有*INHI这个指示器) Comment:

注释行,源自RPG,不用填,填了也没用。

2.8.3 ILE操作码分类:

1. 程序流程控制

DO、DOU、DOUxx、DOW、DOWxx、ITER、LEVAE IF、ELSE、ELSEIF、IFxx、ORxx、ANDxx SELECT、WHEN、WHENxx、OTHER、 ENDxx、

GOTO、TAG 、

EXSR、BEGSR、ENDSR CABxx 2. 初始化操作

CLEAR、RESET 3. 文件操作

OPEN、CLOSE、

CHAIN、SETGT、SETLL、

READ、READC、READE、READP、READPE、 DELETE、UPDATE、WRITE 、UNLOCK ROLBK、COMMIT、 EXFMT、

ACQ、EXCEPT、FEOD、FORCE、NEXT、POST、REL 4. 程序调用

CALL、CALLB、CALLP、PARM、PLIST、RETURN 5. 赋值语句

6. 7.

8. 9. 10. 11. 12. 13. 14.

MOVE、MOVEA、MOVEL、 EVAL 字符操作

CAT、CHECK、CHECKR、SCAN、SUBST、XLATE 数字操作

ADD、DIV(除)、MULT(乘)、MVR(除法取余)、SQRT(开方)、SUB、XFOOT、Z-ADD、Z-SUB 数组操作符

LOOKUP、MOVEA、SORTA、XFOOT 数据区操作(没用过) IN、OUT、UNLOCK 日期操作

ADDDUR、EXTRCT、SUBDUR、TEST 指示器操作

SETOFF、SETON

信息操作(前两个没用过)

DUMP、SHTDN、TIME、DSPLY 内存管理操作(完全没用过)

ALLOC、DEALLOC、REALLOC 位操作(没用过)

BITOFF、BITON、TESTB

2.8.4 ILE操作码

A--C

2.8.4.1

ACQ {(E)} (Acquire) 取地址位。其实400的程序中也有指针型变量,那么也就会有地址位,这个命令是取地址位的。我试过,不过不知道取出了地址位能干嘛,所以没有实际运用过。 ADD {(H)} (Add) 加法操作

1. 基本语法: Factory 1 Operation Factory 2 Result FHS01 ADD FHS02 FHS03 // RPG的语法 等价于 EVAL FHS03=FHS01+FHS02 //RPGLE的语法 FHS01、FHS02、FHS03必须都为数字型变量(P型,或S型),或者就是数字 意思是将Factory 1项的数据,加上Factory 2项的数据,赋值到Result项上

2. 语法二:

如果这样写的话:

Factory 1 Operation Factory 2 Result ADD FHS02 FHS03

就等价于: EVAL FHS03=FHS03+FHS02

即Factory 1项未填时,就表示将Result 项的数据,加上Factory 2项的数据,然后赋值到Result项上 3. 四舍五入:

(H)表示四舍五入,如FHS02=12.50(4,2),FHS03=3(2,0),那么 ADD(H) FHS02 FHS03 执行之后,FHS03=16(因为进位了) 而 ADD FHS02 FHS03 执行之后,FHS03=15

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

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

Factory 1 Operation Factory 2 Result

FHS01 ADD FHS02 FHS03 10 2

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

5. 关于结果数据超长时的问题:

当加出的结果超长,比如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中:

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中):

Factory 1 Operation Factory 2 Result ADDDUR 3:*M MYDATE1

3. 日期型变量的参数含义: *D表示天,也可用*DAYS *M表示月,也可用*MONTHS *Y表示年,也可用*YEARS

4. 除了日期型之外,还有时间型,日期时间型,都可以使用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

5. Factory 2项中的数字,可以使用负数,使用负数时,表示减去相应的年、月、日,

不过通常我会使用SUBDUR这个操作码来进行日期的减法,语法与ADDDUR相同

6. 既然说到这里,就顺便说一下对于日期型变量(时间型,日期时间型也类似)的处

理。在实际运用时,常需要将日期型变量与8位数字型变量转换。这时要使用MOVE操作码。如MOVE 日期型变量 数字型变量,反之也是。不能用Z-ADD。

ALLOC {(E)} (Allocate Storage) 好象是给指针型变量分配空间的,没有用过 ANDxx (And) 条件判断语句—“与”

1. 在RPG的用法中,有ANDEQ,ANDNE之类的,与IF语句一起联用。 Factory 1 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

3. 不过在实际上,因为RPGLE可以使用类似自由语言的风格,而且可以使用括号来

处理逻辑判断先后顺序(这个是我用RPG写起来比较麻烦的,尤其是ANDxx与ORxx的关系,很复杂的判断写起来就不那么顺畅),所以一般都不会这么写,而是用如下的风格: Factory 1 Operation Factory 2 Result

IF FLD>FLD2 AND FLD2=FLD4 OR FLD4<>FLD5) 。。。处理内容 ENDIF 可以看出,逻辑判断的内容,可以用括号括起来以区分先后顺序; 判断的语句,允许有空格:FLD1 > FLD2,与FLD1>FLD2是相同的 但AND前后,必须要有空格

当逻辑判断条件太长,一行写不下要分行写时,AND在上一行,还是下一行,都没有关系。

Operation项用EVAL操作码时,再按F4,会看到Factory2项变成了一个很长的Extended Factory2项,而原来的Result、Length、Decimal Positions、HI、LO、EQ项都没了。

我们的逻辑判断语句,就都写在这个Extended Factory 2项中

BEGSR (Beginning of Subroutine) 子过程的开始处 Factory 1 Operation Factory 2 Result BEGSR 子过程名

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

BITOFF (Set Bits Off) 没用过

BITON (Set Bits On) 没用过

CABxx (Compare and Branch) 没用过

CALL {(E)} (Call a Program) 调用外部程序 Factory 1 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的程序,从而导致程序异常中断。

CALLB {(D | E)} (Call a Bound Procedure) 也没用过,不过有不少人用,望举例说明

CALLP {(M | R | E)} (Call a Program or Procedure) 也没用过,不过有不少人用,望举例说明

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

1. 表示根据xx项对Factory 1与Factory 2进行判断,当符合条件时,执行Result处

的子过程。需要配合“END”或“ENDCS”语句来表示条件判断的结束。不需要“SELECT”操作码。 2. 举例如下:

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。 上面这段语句,与下面这一段是等价的:

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

如果要用CAT写,就要写多行,不简洁。

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

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. 基本语法:

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. 基本语法:

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. 基本语法

Factory 1 Operation Factory 2 Result

CLEAR 目标名 这个目标名,可以是程序中定义的结构、文件的记录格式名。

所谓文件的记录格式名,包括了程序中声明的磁盘文件、打印报表文件、屏幕文件 CLEAR操作的意思,就是将目标所对应的所有变量/字段都赋上空值。 2. 对结构体的清空

关于结构体,后面会另设章节专门讲述,这里只说明对结构体初始化清空 Factory 1 Operation Factory 2 Result

CLEAR *ALL 目标名 CLOSE {(E)} (Close Files) 关闭文件

1. 基本语法

Factory 1 Operation Factory 2 Result

CLOSE 目标文件名

2. CLOSE所对应的,是文件名,不是文件的记录格式名,要注意

3. CLOSE操作码,仅适用于声明文件时,keyword使用“USROPN”关键字的文件 4. 每一个CLOSE的操作,在之前都必须有OPEN文件的操作。也就是,文件必须打

开了之后,才能关闭。不能关闭未打开的文件

5. 允许使用*ALL变量,来表达关闭所有已打开的文件:

CLOSE *ALL

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

1. 基本语法

Factory 1 Operation Factory 2 Result

COMMIT

2. 该操作码无其它参数,就是指对事务处理进行确认操作。

3. ILE程序中,COMMIT操作可随时进行,也允许在没有声明COMMIT类型的文件

的情况下,仍进行COMMIT操作(对该进程这前的事务进行确认处理)f 4. 关于日志的确认操作,在后面会另设专门章节讲述。 COMP (Compare) 比较

1. 基本语法:

将Factory 1与Factory 2进行比较。

当Factory 1 > Factory 2 时,打开HI指示器; 当Factory 1 = Factory 2 时,打开LO指示器; 当Factory 1 < Factory 2 时,打开EQ指示器。 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’

字符也可以进行比较,好象是按字母排序,然后将内码相加,再比较(类似于ASCII码一样,不过不是特别清楚这个规律,所以一般没用)

坦白说,我觉得这个操作码有点无聊。

2.8.4.2 D--E

DEALLOC {(E | N)} (De-allocate Storage)

没用过,好象是对定义的指针型变量,对其分配地址空间之后,用这个操作码可以回收空间。

DEFINE (Field Definition) 根据已知的字段,来定义新字段,如下:

Factory 1 Operation Factory 2 Result HI LO EQ

*LIKE DEFINE FLD01 FLD02 这句话的意思,就是说“象定义字段FLD01一样,定义字段FLD02的类型、长度” 这个字段FLD01,必须是个已定义的字段/变量。 DELETE {(E)} (Delete Record) 删除当前记录,语法如下:

Factory 1 Operation Factory 2 Result HI LO EQ

DELETE 文件记录格式名 这里,在做DELETE操作前,必须先定位到具体的记录上(使用CHAIN、READ等语句);同时,文件在F行必须使用修改的方式来声明。 当文件定位到目标记录时,目标记录会被锁定,此时,目标记录无法被其它程序修改;如果执行了DELETE操作,自然会解锁,不过别的程序也找不到目标记录了(因为被删除)

实际使用中,通常并不会对文件中的记录进行物理删除,而是修改某个标识状态的字段的值,所以使用这条命令要慎重。 DIV {(H)} (Divide) 数学运算—除

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

Factory 1 Operation Factory 2 Result HI LO EQ

FLD01 DIV FLD02 N MVR M 上面两句话的意思,是说,用FLD01来除FLD02,将商赋值到变量N中,将余数,赋值到变量M中。(N,M都是数字型变量) 再具体一点,如果FLD01 = 10, FLD02 = 3,执行完这两句操作码之后 N = 3 (10 / 3的商) M = 1 (10 / 3的余数) DO (Do) 循环 我最常用的循环方法之一,适用于已知循环次数的循环,与ENDDO搭配使用,每一个DO,必须要配合一个ENDDO。基本语法如下

Factory 1 Operation Factory 2 Result HI LO EQ

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

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项的条件之后,结束循环。如下:

Factory 1 Operation Factory 2 Result HI LO EQ

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

DOUxx (Do Until) 又是循环 这应该是RPG的写法,上面的循环也可以写做:

FLD01 DOUGT FLD02 ENDDO

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

DOW {(M | R)} (Do While) 循环,又见循环 这个循环的意思,与DOU正好相反,它的意思是满足Extend Fatcory 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) 屏幕显示

Factory 1 Operation Factory 2 Result HI LO EQ

FLD01 DSPLY 就是在屏幕上,显示FLD01的内容。FLD01可以是字符、数字型变量。也可以直接就是字符、数字。

DUMP (Program Dump)

没用过

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. 基本语法:

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

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

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

EVAL FLD01=*BLANKS

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)

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的关系。

REALLOC {(E)} (Re-allocate Storage) 没用过

REL {(E)} (Release) 没用过

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的话,将会把所有的记录都修改掉,直到最后找不到可修改的记录,然后系统报错,异常中断。(这种离奇的现象现在又测试不到了,可能是当时写错程序了?把F写成了P?不管它,当是我写错了,总之RETURN是表示程序结束,没有RETURN,主程序无可执行的语句时,它也会结束;如果RETURN出现在主程序的中间,那么RETURN后面的语句将不会执行)

如果只写RETURN,不打开指示器*INLR,根据blogliou所说 “程序不会强制将内存中的数据写到磁盘中。400缺省的是BLOCK输出,即数据记录满一个BLOCK块时才会将这一组记录写到磁盘上。那么如果这时BLOCK没满,数据信息不会立刻写到磁盘上。之后有其它作业用到该文件,读取的数据就不完整。”

但如果文件有唯一键字,或记录日志,必须同步写时,其实BLOCK实际被忽略,也就是此时不会有错。目前我们用的是MIMIX备份,客户实际上将所有的文件都列入日志,这时不写也不会出现上述错误。但为避免一些潜在的问题,养成良好的编程风格,建议将SETON LR与RETURN一同,做为程序结束的标志。当然,如果某个程序频繁被调用,且不涉及文 操作时,可考虑不打开指示器*INLR,仅用RETURN作为结束,这样程序不会被PURGE出内存,可提高调用效率。

如果没写RETURN,也没有打开指示器*INLR,在编译时,系统将会报40级错,说找不到程序结束的语句,所以大可放心。

ROLBK {(E)} (Roll Back)

1. 基本语法

Factory 1 Operation Factory 2 Result ROLBK

2. 该操作码无其它参数,就是指对事务处理进行回滚操作。

3. ILE程序中,ROLBK操作可随时进行,也允许在没有声明COMMIT类型的文件

的情况下,仍进行ROLBK操作(对该进程这前的事务进行确认处理)f 4. 关于日志的确认回滚操作,在后面会另设专门章节讲述。

2.8.4.5 S--Z

SCAN {(E)} (Scan Character String) 扫描字符串 扫描字符或字符串Factory 1 在目标字符串Factory 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”中讲过,为方便读者,列出简单语法如下:

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条记录。那么:

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操作码,会将游标定位到与键值相等的第一条记录之前,仍是上例,如果是 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) 关闭指示器

Factory 1 Operation Factory 2 Result HI LO EQ SETOFF 10 11 12 等价于 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哪里都没关系,都是表示要被关闭的指示器

SHTDN (Shut Down) 没用过 SORTA (Sort an Array) 没用过 SQRT {(H)} (Square Root) 开方

Factory 1 Operation Factory 2 Result HI LO EQ 9 SQRT 3 N 这时,N=3(因为3的平方为9) 9、3都可以是数字型变量,或者直接是数字 SUB {(H)} (Subtract) 减法操作

Factory 1 Operation Factory 2 Result HI LO EQ FLD01 SUB FLD02 FLD03 SUB FLD02 FLD03 看过前面的ADD、MULT操作码,这里不用解释也应该明白是什么意思了吧。那就不多说了。

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

1. 减日期 Factory 1 Operation Factory 2 Result HI LO EQ FLD01 SUBDUR N:*Y FLD02

表示将日期型变量FLD01减去N年,赋值到日期型变量FLD02中; N可以是一个数字型变量,也可以就是一个数字,N允许为负数

*Y,*M,*D(还有其它的参数值,可见ADDDUR,其中有详细解释) 2. 判断两个日期型变量之间的天/月/年数 Factory 1 Operation Factory 2 Result HI LO EQ FLD01 SUBDUR FLD02 N:*D

本文来源:https://www.bwwdw.com/article/ci2o.html

Top