Rexx 编程/入门/语法
Rexx 中的循环控制结构以 DO
开始,以 END
结束,但有几种变体。NetRexx 使用关键字 LOOP
代替 DO
进行循环,而 ooRexx 在循环时将 LOOP
和 DO
视为等效。
传统形式
do expression [count]
[instructions]
end
do until [condition]
[instructions]
end
do while [condition]
[instructions]
end
带索引变量
do i = x [to y] [by z]
[instructions]
end
另一种变体
do i = x [by z ] [to y] [for k]
[instructions]
end
步长增量 (z) 可以省略,默认值为 1。上限 (y) 也可以省略,这将使循环永远继续。您还可以使用以下方法在没有索引变量的情况下无限循环
do forever
[instructions]
end
程序可以使用 leave
指令退出当前循环(这是退出“无限”循环的正常方式),或者可以使用 iterate
指令将其短路。
do while
和 do until
形式等效于
do forever
if [condition] then leave /*similar to WHILE*/
[instructions]
end
和
do forever
[instructions]
if [condition] then leave /*similar to UNTIL*/
end
使用 IF
测试条件
if [condition] then
do
[instructions]
end
else
do
[instructions]
end
ELSE
子句是可选的。
或者,更简洁地说
if [condition] then do
[instructions]
end
else do
[instructions]
end
对于单个指令,DO
和 END
也可以省略
if [condition] then
[instruction]
else
[instruction]
或者,在另一个简洁版本中
if [condition] then [instruction]
else [instruction]
缩进是可选的,但它有助于提高可读性。
SELECT
是 Rexx 的 CASE 结构,类似于许多其他从 PL/I 派生的结构
select
when [condition] then
[instruction]
when [condition] then
do
[instructions]
end
otherwise
[instructions] or NOP
end
NOP
表示不执行任何指令。
OTHERWISE 子句是可选的。如果省略且未满足任何 WHEN 条件,则会引发 SYNTAX 条件。
Rexx 中的变量是无类型的,最初被评估为其名称,以大写形式。因此,变量的类型会根据其在程序中的使用而改变
say hello /* => HELLO */
hello = 25
say hello /* => 25 */
hello = "say 5 + 3"
say hello /* => say 5 + 3 */
interpret hello /* => 8 */
drop hello
say hello /* => HELLO */
与许多其他编程语言不同,经典 Rexx 不直接支持由数字索引寻址的变量数组。相反,它提供了复合变量。复合变量由一个词干和一个尾部组成。一个 . (点) 用于将词干连接到尾部。如果使用的尾部是数字,则很容易产生与数组相同的效果。
do i = 1 to 10
stem.i = 10 - i
end
之后将存在以下变量,具有以下值:stem.1 = 9, stem.2 = 8, stem.3 = 7...
与数组不同,词干变量的索引不需要具有整数值。例如,以下代码有效
i = 'Monday'
stem.i = 2
在 Rexx 中,还可以为词干设置默认值。
stem. = 'Unknown'
stem.1 = 'USA'
stem.44 = 'UK'
stem.33 = 'France'
在这些赋值之后,stem.3
将产生 'Unknown'
。
可以使用 DROP 语句删除整个词干。
drop stem.
这也具有删除之前设置的任何默认值的效用。
按照惯例(而不是作为语言的一部分),复合 stem.0
通常用于跟踪词干中的项目数量,例如,将单词添加到列表中的过程可能如下编码
add_word: procedure expose dictionary.
parse arg w
n = dictionary.0 + 1
dictionary.n = w
dictionary.0 = n
return
也可以在复合变量的尾部有多个元素。例如
m = 'July'
d = 15
y = 2005
day.y.m.d = 'Friday'
可以使用多个数字尾部元素来提供多维数组的效果。
与 Rexx 复合变量类似的功能在许多其他语言中都有发现(包括 关联数组 在 AWK 中,哈希 在 Perl 中以及 Java 中的哈希表)。这些语言中的大多数都提供了一条指令来遍历此类结构的所有键(或 Rexx 术语中的尾部),但经典 Rexx 缺少此功能。相反,需要根据需要维护尾部值的辅助列表。例如,在计算单词计数的程序中,可以使用以下过程来记录每个单词的出现次数。
add_word: procedure expose count. word_list
parse arg w .
count.w = count.w + 1 /* assume count. has been set to 0 */
if count.w = 1 then word_list = word_list w
return
然后以后
do i = 1 to words(word_list)
w = word(word_list,i)
say w count.w
end
以牺牲一些清晰度为代价,可以将这些技术组合到一个词干中
add_word: procedure expose dictionary.
parse arg w .
dictionary.w = dictionary.w + 1
if dictionary.w = 1 /* assume dictionary. = 0 */
then do
n = dictionary.0+1
dictionary.n = w
dictionary.0 = n
end
return
然后以后
do i = 1 to dictionary.0
w = dictionary.i
say i w dictionary.w
end
Rexx 在这里没有提供安全网,因此如果某个单词恰好是一个小于 dictionary.0
的整数,则此技术将神秘地失败。
Rexx 的最新实现,包括 IBM 的 Object REXX 和 ooRexx 等开源实现,包含一个新的 语言结构,用于简化对词干的值或其他集合对象的遍历,例如数组、表或列表。
do i over stem.
say i '-->' stem.i
end
PARSE
指令特别强大;它组合了一些有用的字符串处理功能。其语法为
parse [upper] origin [template]
其中origin 指定源
arg
(参数,在命令行的顶层尾部)linein
(标准输入,例如键盘)pull
(Rexx 数据队列或标准输入)source
(有关如何执行程序的信息)value
(表达式)with
:关键字with
用于指示表达式的结尾var
(一个变量)version
(版本/发行版号)
和template 可以是
- 变量列表
- 列号分隔符
- 文字分隔符
upper
是可选的;如果指定,数据将在解析之前转换为大写。
示例
使用变量列表作为模板
myVar = "John Smith"
parse var myVar firstName lastName
say "First name is:" firstName
say "Last name is:" lastName
显示以下内容
First name is: John Last name is: Smith
使用分隔符作为模板
myVar = "Smith, John"
parse var myVar LastName "," FirstName
say "First name is:" firstName
say "Last name is:" lastName
也显示以下内容
First name is: John Last name is: Smith
使用列号分隔符
myVar = "(202) 123-1234"
parse var MyVar 2 AreaCode 5 7 SubNumber
say "Area code is:" AreaCode
say "Subscriber number is:" SubNumber
显示以下内容
Area code is: 202 Subscriber number is: 123-1234
模板可以结合使用变量、文字分隔符和列号分隔符。
INTERPRET 指令评估其参数并将它的值视为 Rexx 语句。有时 INTERPRET 是执行任务的最清晰方式,但它通常用于可以使用(例如)value()
的更清晰的代码的地方。
INTERPRET 指令功能强大,也是编写 Rexx 编译器并非易事的主要原因之一。
其他原因包括 Rexx 的(十进制)任意精度算术(包括模糊比较)、带编程模板的 PARSE 语句的使用、词干数组和稀疏数组。-->
/* a touch of [[w:Lisp (programming language)|LISP]] */
X = 'square'
interpret 'say' X || '(4) ; exit'
SQUARE: return arg(1)**2
这将显示 16 并退出。由于 Rexx 中的变量内容是字符串,包括带指数的有理数甚至整个程序,因此 Rexx 提供将字符串解释为求值的表达式。
此功能可用于将函数作为函数参数传递,例如将 SIN 或 COS 传递给过程以计算积分。
Rexx 仅提供基本的数学函数,例如 ABS、DIGITS、MAX、MIN、SIGN、RANDOM,以及完整的十六进制加二进制转换和位运算。 更复杂的函数,如 SIN,必须从头开始实现或从第三方外部 库 中获取。 一些外部库,通常是在传统语言中实现的库,不支持扩展精度。
后面的版本(非经典)支持 CALL variable
结构。 与内置函数 VALUE
结合使用,CALL 可以代替 INTERPRET
的许多情况。 这是一个经典的程序
/* terminated by input "exit" or similar */
do forever ; interpret linein() ; end
一个稍微复杂一点的“Rexx 计算器”
X = 'input BYE to quit'
do until X = 'BYE' ; interpret 'say' X ; pull X ; end
PULL
是 parse upper pull
的简写。 同样,ARG
是 parse upper arg
的简写。
INTERPRET 指令的功能还有其他用途。 Valour 软件 包依赖于 Rexx 的解释能力来实现 面向对象编程 环境。 另一个用途是在一个未发布的 西屋 产品中发现的,名为“时光机”,它能够在致命错误后完全恢复。
say digits() fuzz() form() /* => 9 0 SCIENTIFIC */
say 999999999+1 /* => 1.000000000E+9 */
numeric digits 10 /* only limited by available memory */
say 999999999+1 /* => 1000000000 */
say 0.9999999999=1 /* => 0 (false) */
numeric fuzz 3
say 0.99999999=1 /* => 1 (true) */
say 0.99999999==1 /* => 0 (false) */
say 100*123456789 /* => 1.23456789E+10 */
numeric form engineering
say 100*123456789 /* => 12.34567890E+9 */
numeric digits 50
n=2
r=1
do forever /* Newton's method */
rr=(n/r+r)/2
if r=rr then leave
r=rr
end
say "root" n '=' r /*root 2=1.414213562373095048801688724209698078569671875377*/
numeric digits 50
e=2.5
f=0.5
do n=3
f=f/n
ee=e+f
if e=ee then leave
e=ee
end
say "e=" e /*e=2.7182818284590452353602874713526624977572470936998*/
SIGNAL 指令用于控制流的异常更改(参见下一节)。 但是,它就像其他语言中的 GOTO 语句一样,可能会被误用,从而创建难以阅读的代码。
在 Rexx 中,可以使用 SIGNAL 指令来拦截和处理错误和其他异常。 有七种系统条件:ERROR、FAILURE、HALT、NOVALUE、NOTREADY、LOSTDIGITS 和 SYNTAX。 可以根据需要在源代码中打开和关闭对每种情况的处理。
以下程序将一直运行,直到用户终止程序。
signal on halt;
do a = 1
say a
do 100000 /* a delay */
end
end
halt:
say "The program was stopped by the user"
exit
几乎所有严肃的 Rexx 程序都包含 signal on novalue
或类似语句。 这将禁用“功能”,其中未定义的变量将获得其自身(大写)名称作为值。 可以使用内置函数 SYMBOL
检查变量的状态,对于已定义的变量,它将返回 VAR。
函数 VALUE
可用于获取变量的值,而不会触发 NOVALUE 条件,但它的主要用途是读取和设置 环境 变量,类似于 POSIX 的 getenv
和 putenv
。
错误
|
系统命令的正 RC |
---|---|
失败
|
系统命令的负 RC(例如,命令不存在) |
停止
|
异常终止 |
无值
|
引用了一个未设置的变量 |
未准备
|
输入或输出错误(例如,读取尝试超出文件末尾) |
语法
|
无效的程序语法,或其他一些错误条件 |
丢失数字
|
丢失有效数字(ANSI Rexx,TRL 第二版中没有) |
当条件由 SIGNAL ON
处理时,可以分析 SIGL
和 RC
系统变量以了解情况。 RC 包含 Rexx 错误代码,SIGL 包含发生错误的行号。
从 Rexx 版本 4 开始,条件可以获得名称,并且还有 CALL ON
结构。 如果外部函数不一定存在,这将非常方便。
ChangeCodePage: procedure /* protect SIGNAL settings */
signal on syntax name ChangeCodePage{{not a typo|.}}Trap
return SysQueryProcessCodePage()
ChangeCodePage.Trap: return 1004 /* windows-1252 on OS/2 */