跳转到内容

Rexx 编程/入门/语法

来自维基教科书,开放的书籍,开放的世界

Rexx 中的循环控制结构以 DO 开始,以 END 结束,但有几种变体。NetRexx 使用关键字 LOOP 代替 DO 进行循环,而 ooRexx 在循环时将 LOOPDO 视为等效。

传统形式

 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 whiledo 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

对于单个指令,DOEND 也可以省略

 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

[编辑 | 编辑源代码]

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

PULLparse upper pull 的简写。 同样,ARGparse 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 条件,但它的主要用途是读取和设置 环境 变量,类似于 POSIXgetenvputenv

错误 系统命令的正 RC
失败 系统命令的负 RC(例如,命令不存在)
停止 异常终止
无值 引用了一个未设置的变量
未准备 输入或输出错误(例如,读取尝试超出文件末尾)
语法 无效的程序语法,或其他一些错误条件
丢失数字 丢失有效数字(ANSI Rexx,TRL 第二版中没有)

当条件由 SIGNAL ON 处理时,可以分析 SIGLRC 系统变量以了解情况。 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 */
华夏公益教科书