Tivoli 服务台 6.0 开发工具包脚本程序设计指南
本章向用户介绍在开发工具包中最经常使用的数据类型。除了讨论数据类型本身外,本章还有关于常量、变量和表达式的信息。
数据类型定义变量或常量中的数据的属性。可能的属性包括:
开发工具包有六种简单数据类型。
句柄是包括另一变量地址的变量。地址是变量的位置。句柄使程序能访问特定资源。
句柄类型有特定用途,不从任何其它类型导出。开发人员使用句柄标识逻辑实体(在其上执行操作)。下列是句柄类型列表:
外部参数类型是简单类型的带注释版本,它帮助开发工具包解释器在调用外部 DLL 前,把开发工具包值转换为响应的 C 或 Pascal 类型:
三种聚集类型不能单独使用,但可与任何其它类型一起使用,以创建用户定义类型:
常量是已命名的项,在程序执行过程中它保持不变,即始终如一。在知识库的 CONSTANTS 段进行所有的常量说明。
要在知识库中说明常量,用户必须完成下列步骤:
像所有开发工具包语句一样,常量说明总以分号(;)结尾。
使用不同数据类型进行常量说明的实例如下:
CONSTANTS (* 字符串常量 *) fileName IS 'MYFILE.DAT'; pathName IS 'EADVISOR\ADVISOR\DATA'; driveName IS 'E:';
(* 整常数 *) MAX_EMPLOYEES IS 500; ERROR_CODE IS -1;
(* 实常数 *) PI_VALUE IS 3.14159; MAX_SALARY IS 999999.99; LO_VALUE IS -5134.1348;
(* 布尔常量 *) SAVE_TO_DISK IS TRUE; OVERWRITE_FILE IS FALSE;
(* 日期常量 *) CHRISTMAS IS {12,25,1996}: DATE; BIRTH_DAY IS {2,13,1956}: DATE;
(* 时间常量 *) START_OF_DAY IS {8,30,0}: TIME; END_OF_DAY IS {18,0,0}: TIME;
注:国际用户应了解,在开发工具包初始状态中日期“部分”顺序是(月,日,年),且不随语言环境更改。
变量是已命名的项,包括程序执行过程中可修改的数据类型。在知识库的 VARIABLES 段中说明变量。
要在知识库中说明变量,用户必须完成下列步骤:
如下例所示,通过用逗号分隔变量名,用户可说明同类型的多个变量:
VARIABLES first_name, last_name : STRING; i,j : INTEGER; salary : REAL; married : BOOLEAN; entryDate : DATE; startTime : TIME;
用赋值运算符(:=)为变量赋值。
下列代码段显示为在上例中定义的变量进行变量赋值:
first_name := 'Amy'; last_name := 'Alec'; i := 7; j := 32; salary := 37500.00; married := FALSE; entryDate := {1,31,1991}: DATE; startTime := {10,30,0}: TIME;
用户有时可能需要转换数据类型。当表示信息的方法有所更改时,需要进行数据转换。例如,用户可把二进制表示法更改为十进制或十六进制表示法,或把整数更改为字符串。
开发工具包使用大括号{}指示要转换哪个值。
在此例中,把大括号中的值转换为整数:
i := {s}: INTEGER;
当开发工具包遇到此行时,它完成下列工作:
转换数值不破坏原值。
下面是数据转换的更复杂的实例,显示开发工具包如何计算两个给定日期间的天数:
d1 := {1,1,1990}: DATE; d2 := $Today; daysBetween = {d2}: INTEGER - {d1}: INTEGER;
要完成此操作,开发工具包使用存储在{d1}和{d2}中的日期值,把它们转换为其阳历值,并用这些值相减。
此例假定{d1}和{d2}是日期变量,变量 daysBetween 是整数。
开发工具包是强类型语言,这意味着如果把一个类型的变量赋值给另一类型的变量,会出现错误。
例如,如果假定 entryDate 是日期变量,startTime 是时间变量,则下列赋值操作产生运行时错误:
entryDate := startTime;
开发工具包自动转换整数和实数。例如,假使变量 i 是整数,则语句
i := 37.0;
把 37 赋值给 i 变量,不需显式类型转换。
同样,如果 r 是实数,语句
r := i;
把 37.0 赋值给 r 变量。
知道赋值时,总把混合表达式作为实数处理,这样可以保持精度。
而且,当需要时,开发工具包自动把所有数据类型转换为字符串。例如,语句:
s := i;
把字符串值 37 赋值给 s 变量。
开发工具包中的字符串是由单引号括起来的一系列字符。开发工具包提供字符串处理运算符和语句,使用户可执行操作以:
在下述列表中总结字符串运算符和语句。
s1 := 'F:\CODE'; s2 := 'PROGRAM.EXE'; s3 := s1 & '\' & s2;
在此实例中,s3 变量包括字符串'F:\CODE\PROGRAM.EXE'。s1 和 s2 变量没有任何更改,保持它们原来的值。可用与符号连接任意个常量、变量或表达式,形成一个新字符串。在执行连接前,与符号也自动把非字符串值转换为字符串。例如:
s1 := 'The date is ' & $Today & 'and the time is ' & $Now;
在上述实例中,开发工具包常量 $Today(系统日期) 和 $Now(系统时间)自动转换为字符串形式,以供连接。
s := 'LIB(ase) FILE(qrpgsrc); s := StrUpper(s); (* now s = 'LIB(ASE) FILE(QRPGSRC) *)
注:对国际用户,开发工具包遵循当前语言环境的相应大写规则。例如,在法国和加拿大的法语区“eclair”转换成“ECLAIR”。
s := 'LIB(ase) FILE(qrpgsrc); s := StrLower(s); (* 现在 s = 'lib(ase) file(qrpgsrc) *)
注:对国际用户,开发工具包遵循工作站的当前语言环境的相应大小写规则。
~ 新字符串要插入其中的字符串变量
~ 要插入的字符串
~ 新字符串要插入其中的字符串参数的下标
例如:
s := StrInsert('LIB(ASE) MBR(MYPROG)', 'FILE(QRPGSRC) ',10); (* now s = 'LIB(ASE) FILE(QRPGSRC) MBR(MYPROG) *)
注: 为多个语言环境编写代码的国际用户应避免从不同的段和块“组装”句子。当用这种方法组装句子时,会破坏在许多语言中存在的性和性一致。
~ 字符串参数的名称
~ 起始下标
~ 要删除的字符数
例如:
s := StrDelete('LIB(ASE) FILE(QRPGSRC) MBR(MYPROG)',10,14); (* now s = 'LIB(ASE) MBR(MYPROG)' *)
~ 源字符串的名称
~ 源字符串中的起始下标
~ 要复制的字符数
例如:
fileName := 'LIB(ASE) FILE(QRPGSRC) MBR(MYPROG)'; s := StrCopy(fileName,15,7); (* now S = 'QRPGSRC' *)
注:StrPos 搜索不区分大小写。第一个位置下标为 1,而不像在 C 和一些其它程序设计语言中第一个位置下标为 0。
如果找不到第二个字符串,返回“0”。例如:
company := 'Tivoli Systems'; loc := StrPos(company, 'Sys'); (*loc = 8*)
执行此代码后,loc 变量的值为 8。
例如:
IF StrMatch(s,'*.BAK') THEN FErase(s); END;
开发工具包有其它字符串处理语句,包括 StrToken(破坏性字符串 tokenizer),StrTrim,StrLTrim 和 StrLength。
开发工具包支持算术表达式和运算符,于下表中总结。
运算符 说明 + 把两个数字表达式相加(i:=3+5) - 从一个数字表达式中减去另一个数字表达式(r:=3.7-2.0) * 把两个数字表达式相乘(i:=3.0*6) / 把两个数字表达式相除(r:=3.0/4.0) MOD 当一个整数被另一个整数除时,计算余数(6 MOD 4=2)
除了这些运算符,开发工具包支持下列函数:
三角函数 | 对数函数 | 指数函数 |
Sin | Log | Exp |
Cos | Ln | Power |
Tan | Sqrt | n/a |
ACos | n/a | n/a |
ASin | n/a | n/a |
ATan | n/a | n/a |
CosH | n/a | n/a |
SinH | n/a | n/a |
TanH | n/a | n/a |
可使用逻辑运算符 AND、OR 和 NOT 来创建复杂的布尔表达式,如:
b := (i > 0) AND (j = 0);
开发工具包执行短路布尔判定。这种判定形式保证对布尔表达式只判定到可确定其值的地方。
在上面的实例中,如果 i 是 0,在判定 j 前,确定 b 变量的值为 FALSE。规则如下:
开发工具包提供下列关系运算符,供在布尔表达式中使用。
运算符 | 说明 |
< | 小于 |
<= | 小于或等于 |
> | 大于 |
>= | 大于或等于 |
= | 等于 |
<> | 不等于 |
注:当比较两个字符串时,上面列出的运算符忽略大小写。这意味着下列表达式是 TRUE:
'F:\MYFILE' = 'f:\myfile'
下列运算符用于区分大小写的字符串比较。
运算符 | 说明 |
<< | 小于 |
<<== | 小于或等于 |
>> | 大于 |
>>== | 大于或等于 |
== | 等于 |
<<>> | 不等于 |
参考页面上的注,获取实例。
虽然被认为是简单数据类型,但是日期值使用不可见结构,该结构使用户能获得月、日和年值。使用加点的表示法,如下例所示。
dayValue := $Today.day; monthValue := $Today.month; yearValue := $Today.year; (* $Today 是系统日期*)
如上例所示,任何日期表达式后面可跟一个点和一个关键字(day、month 或 year),他用来访问日期的相应值。在上面的实例中,dayValue、monthValue 和 yearValue 是整数变量。
用户可更改日期变量的月、日或年值,如下所示:
d := $Today; d.year := d.year + 1;
在上面实例中,把当前系统日期值赋值给日期变量(d)。d 的年值增加一。
开发工具包保证用户不使用无效日期。在下面实例中,日期变量使用“2/1/1999”(而不是“1/32/1999”):
d := {1,31,1999}: DATE; d.day := d.day + 1;
开发工具包提供 DateDif 函数,来以月、日或年计算两个日期间的间隔。
DateDif 需要三个自变量:
例如:
age := DateDif($Today,birthDate,$Years);
开发工具包提供几个工具,使用户可以操纵时间表达式。像日期一样,时间包括多个值:小时、分钟和秒。
可使用加点表示法(在日期中也这样用)来访问时间值的不同部分:
currentHour := $Now.hour; currentMinute := $Now.minute; currentSecond := $Now.second; (* $Now 是系统时间*)
用户也可更改时间变量的特定部分:
t := $Now; t.hour := t.hour + 3;
时间变量(t)包括的时间值距现在三小时。时间值使用内部 24 小时格式,可以表示半夜。下例的结果是 t 包括值{1,0,0}:TIME,即凌晨 1 点:
t := {23,0,0}: TIME; t.hour := t.hour + 2;
开发工具包提供 TimeDif 函数,计算两个时间之间的间隔。下例以小时、分钟和秒计算当前时间和前一时间 startTime 之间时间间隔:
hoursDiff := TimeDif($Now,startTime,$Hours); minutesDiff := TimeDif($Now,startTime,$Minutes); secondsDiff := TimeDif($Now,startTime,$Seconds);
数组是相同数据类型的数据值列表。它也是一种结构化数据类型。结构化数据类型允许对数据执行特定的操作。
数组名后跟下标表达式组成的表达式可引用数组中的任何单个元素(数据值)。数组中的元素是有顺序的,从一(1)开始。要访问特定的元素,使用值,或下标。
在下例中,每个下标由中括号括起来:
VARIABLES name[10]: ARRAY OF String; ACTIONS name[1] := 'Tom'; name[2] := 'Dick'; name[3] := 'Harry';
在此实例中,name 是字符串数组。name 变量可保存最多十个字符串值,放在标号 1 到 10 的元素中。
一般用变量访问数组。下例显示如何使用整数变量 i 访问给定数组元素,把 name 数组的所有十个值写入文件:
FOR i := 1 TO 10 DO FWriteLN(outputFile,name[i]); END;
试图在定义的数组界限之外访问数组元素,会导致出现运行时错误消息。这些语句都会产生错误:
name[-1] := 'Dick'; name[45] := 'Harry';
可把字符串值当作字符数组处理。在下列代码实例的结束后,s 变量的值是 G:\EADVISOR\ADVISOR\DATA。
VARIABLES s : STRING; ACTIONS s := 'F:\EADVISOR\ADVISOR\DATA'; s[1] := 'G';
开发工具包数组可动态改变大小。即在运行时可更改数组大小。开发工具包语句 SetArrayLength 用来更改任何数组的大小。例如:
SetArrayLength(name,100);
给前面说明的十槽数组增加 90 个新元素。前十槽中的信息不受影响。也可减小数组的大小,如下例所示:
SetArrayLength(name,5);
在这种情况下,会丢失 6 到 10 槽中的任何值。
与数组类似,开发工具包列表是结构化数据类型,可包括相同类型的多个值。使用方括号括住的整数,可为列表标下标。
使用开发工具包,用户不需要地址、内存分配或内存释放以创建完全链接表结构。列表比数组更容易改变大小。用户还可以在列表中间插入新值,这在数组中很费事。
下例显示如何说明和使用列表:
VARIABLES name: List of String; ACTIONS ListInsert(name,'Tom'); ListInsert(name,'Dick'); ListInsert(name,'Harry');
此代码实例结束时,name 列表包括三个值:'Tom'、'Dick'和'Harry'。
每个列表有一个指针,指示列表中的当前元素。这称为列表指针。当把新元素插入列表时,列表指针指示新插入的元素。在前面实例结束处,当前指针指向'Harry'。
下一个实例显示如何在前面列表的中部插入新元素。
ListSetPos(name,1); ListInsert(name,'Ellen');
Name 现在包括四个值:'Tom'、'Ellen'、'Dick'和'Harry'。
注:'Ellen'在第二个位置是因为 $ListInsert 缺省情况是 $After。列表指针指向'Ellen'。ListSetPos 把列表指针移到给定元素。
开发工具包提供许多其它函数,使用户可操纵列表。
函数 | 说明 |
ListDelete | 从列表删除元素。(List Delete(name,2)从前面实例中删除'Ellen')。 |
ListLength | 返回列表中的元素数。 |
ListNext | 在列表中把指针移到下一个元素。 |
ListPrev | 在列表中把指针移到前一个元素。 |
ListPos | 返回当前元素的下标。 |
ListFind | 扫描列表,查找给定值。如果找到该值,返回 TRUE。列表指针移到匹配值。例如,ListFind(name, 'Dick')返回 TRUE 并把当前指针移到'Dick'。 |
ListSort | 按升序排序列表。 |
ListPush | 向列表的前面添加新元素。 |
ListPop | 删除列表中的第一个元素并返回它。 |
因为列表可像数组一样标下标,语句,
s:= name[1];
把值'Tom'赋给 s 变量。
开发工具包为列表提供特殊循环结构。FOR 语句可用来重复列表中的值。嵌套在 FOR...END 块中的语句为列表中的每个元素执行一次。列表指针总指向列表中的第一个数。循环每执行一遍,列表中的当前项增加一。
下例显示 FOR 语句的使用:
FOR name DO FWriteLN(outputFile,name[$Current]); END;
前面的实例也显示名为 $Current 的特殊常量的使用。此常量可用来访问列表的当前元素。其它列表常量包括:
这些常量分别用来访问列表的第一个和最后一个元素。例如:
FWriteLN(outputFile,name[$First]); FWriteLN(outputFile,name[$Last]);
这两行把"Tom"和"Harry"写到输出文件。
很多开发工具包语句支持自动列表“碎片”。在列表碎片中,语句接受给定类型的单个项或项的列表。
如果传送一列表,则语句作用于列表中的所有元素。这也称作带隐含 FOR 循环的语句。
WinWriteLN 是这种语句的一个例子:
WinWriteLN(myWindow,name);
此语句把变量 name 的每个值写到名为 myWindow 的窗口。有几个 Window 语句和 SQL 语句支持列表碎片。
数组和列表可保存类型相同的多个值,与它们不同,记录可保存类型不同的多个值。
说明记录类型变量有两步:
注:当说明记录类型变量时,用户用自己的数据类型扩展开发工具包语言。
阅读下列代码实例:
TYPES EmployeeRecord IS RECORD first_name, last_name: String; age : Integer; salary : Real; married : Boolean; hireDate : Date; startTime, stopTime : Time; END; VARIABLES employee: EmployeeRecord;
前面实例说明名为 EmployeeRecord 的新记录类型。此记录包括八个字段,每个字段是简单数据类型。
像使用日期和时间一样,用户可使用<变量>.<字段>(加点)
表示法来引用记录中的任何字段。
例如,下列语句可用来初始化前面说明的 employee 变量:
employee.first_name := 'Calbert'; employee.last_name := 'Chaney'; employee.age := 21; employee.salary := 2500000.0; employee.married := FALSE; employee.hireDate := {2,15,1993}: DATE; employee.startTime := {8,30,0}: TIME; employee.stopTime := {17,30,0}: TIME;
相同记录类型的变量是赋值兼容的。如果说明变量(employee2) 为 EmployeeRecord 类型,添加下列语句会使 employee 变量的所有字段复制到 employee2 变量:
employee2 := employee;
用户也可创建记录的列表和数组:
employeeList: List Of EmployeeRecord;
记录说明可包括数组、列表和其它记录。例如,可用下列方法更改 EmployeeRecord 说明:
EmployeeRecord IS RECORD first_name, last_name: String; age : Integer; salary : Real; married : Boolean; hireDate : Date; startTime, stopTime : Time; manages : List of String; END;
manages 值可用来记录由给定员工管理的员工姓名。
开发工具包提供几个语句,执行数据库记录输入和输出。
例如,下列语句可用来把 EMPLOYEES 表的一行装载到前面说明的 employee 变量:
SQLSelectInto('SELECT * FROM EMPLOYEES WHERE EMPLOYEE_ID=105',employee);
开发工具包:
类似的,开发工具包允许用户把记录中的字段映射到表单。完成表单后用户按 ENTER 键时,屏幕上的信息保存到记录的相应字段,用户可以检查和操纵记录。
除了记录,用户可创建其它用户定义类型。用户定义类型是在程序中定义的数据类型,它通常由数据类型的组合组成。用户定义类型经常用来创建数据结构。
对于在变量说明中使用的列表、数组、记录和简单数据类型的任意组合,可在数据类型说明中可给它一个重复使用的名称。例如,用户可定义一个新的数据类型,如下例所示:
TYPES StringList = LIST OF STRING;
一旦说明后,用户就可使用 StringList 可用 LIST OF STRING 来说明变量。
下列规则涉及用户定义数据类型和结构化数据类型的赋值兼容性。
当在两个变量或表达式之间检查赋值兼容性时,开发工具包只检查类型名称是否匹配。它不检查记录说明是否一样。
初始化一个已说明的变量意味着给它赋初始值。在说明变量时,开发工具包允许用户初始化变量,如下例所示:
VARIABLES i {1} : INTEGER; s {'F:\MYFILE'} : STRING; d {2,11,1956} : DATE; l {'Tom','Dick','Harry'} : LIST OF STRING; r {'Steve','Wantz',32,189000.00,TRUE, {3,30,1986} : DATE, {6,30,0} : TIME, {4,30,0} : TIME, {'Tom','Dick','Harry'} : LIST OF STRING : EmployeeRecord;
一般情况下,变量名后面是:
对于像列表、数组和记录这样的结构化类型的变量,可用同样的方法初始化。
注意初始值化与变量相关联,而与类型无关。所以在下列行中,
VARIABLES i, j {27}: INTEGER;
只初始化了 j 变量;未初始化 i 变量。每个变量必须单独初始化。
在开发工具包中没有赋值的所有未初始化的变量都以值 $Unknown 开始。这一点不同于 C 和 Pascal,它们的变量以随机值开始。
把所有变量初始化为 0、1或空字符串防止公共错误。例如,如果在下行:
newSalary := oldSalary*1.05;
未把变量 oldSalary 初始化为非 $Unknown 值,运行时间会发生错误,因为 1.05 会与 $Unknown 相乘。
Tivoli 服务台 6.0 开发工具包脚本程序设计指南