Rexx (Restructured Extended Executor) 是 Mike Cowlishaw 在 IBM 任職時, 於 1979 年 3 月 20 日到 1982 年中作為個人專案開發的程式語言,而後被 IBM 採用, 主要用於 IBM 的 Mainframe computer 上,而在其它大部份的平台也可以找到解釋器或編譯器。 Rexx 還有物件導向的版本,稱為 Object Rexx。
自由軟體的實作主要為符合 1996 年 ANSI 標準實作的 Regina Rexx Interpreter, 加入物件導向程式設計的 Open Object Rexx, 以及與 Java 整合的 NetRexx。 我在學習時使用的是 ooRexx。
Rexx 是一個不區分大小寫 (Case-insensitive) 的程式語言。
下面就是 Rexx 版的 Hello World 程式:
/* Main program */
say "Hello, World!"
就如同上面的例子所看到的,Rexx 的註解使用 /* 與 */,中間的文字就是註解要寫的說明。
Variables
In Rexx, all variables are bound with the '=' statement. Variables in Rexx are typeless, and initially are evaluated as their names, in upper case. Thus a variable's type can vary with its use in the program:
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 has no direct support for arrays of variables addressed by a numerical index. Instead it provides compound variables. A compound variable consists of a stem followed by a tail. A . (dot) is used to join the stem to the tail. If the tails used are numeric, it is easy to produce the same effect as an array.
do i = 1 to 10
stem.i = 10 - i
end
do i over stem.
say i '-->' stem.i
end
ooRexx 提供了 do over 的方式可以用來迭代 stem 內的值(注意:這不是 REXX 標準所規範的語言特性)。
Control Structures
對於迴圈而言,Rexx 提供了 do loop, do while loop 與 do until loop 等方式。
do while [condition]
[instructions]
end
do until [condition]
[instructions]
end
Like most languages, Rexx can loop while incrementing an index variable and stop when a limit is reached:
do index = start [to limit] [by increment] [for count]
[instructions]
end
Rexx permits counted loops, where an expression is computed at the start of the loop and the instructions within the loop are executed that many times:
do expression
[instructions]
end
Rexx can even loop until the program is terminated:
do forever
[instructions]
end
Like PL/I, Rexx allows both conditional and repetitive elements to be combined in the same loop:
do index = start [to limit] [by increment] [for count] [while condition]
[instructions]
end
do expression [until condition]
[instructions]
end
下面是一個迴圈的例子:
/* Main program */
do i = 1 to 9 by 1
do j = 1 to 9 by 1
say i 'x' j '=' i*j
end
end
對於條件判斷來說,Rexx 提供了 if 與 select 等方式。
if [condition] then do
[instructions]
end
else do
[instructions]
end
For single instructions, DO and END can also be omitted:
if [condition] then
[instruction]
else
[instruction]
SELECT is Rexx's CASE structure.
select
when [condition] then
[instruction] or NOP
when [condition] then
do
[instructions] or NOP
end
otherwise
[instructions] or NOP
end
The NOP instruction performs "no operation", and is used when the programmer wishes to do nothing in a place where one or more instructions would be required.
下面是使用 select 的例子:
/* Main program */
say "Enter your temperature in degrees Celsius:"
pull degrees
select
when DataType(degrees) \= "NUM" then
say "That's not a number. I can't help you."
when degrees < 36.5 then
say "Your body temperature is a bit low."
when degrees > 37.5 then
say "I think you have a fever."
otherwise
say "You're temperature seems normal."
end
Write a program that displays the digits from 1 to n then back down to 1; for instance, if n = 5, the program should display 123454321. You are permitted to use only a single for loop. The range is 0 < n < 10.
/* Main program */
parse arg n
if DataType(n) \= "NUM" then do
say "That's not a number."
exit
end
if n < 1 | n > 9 then do
say "Out of range."
exit
end
select
when n == 1 then
say "1"
when n == 2 then
say "121"
when n == 3 then
say "12321"
when n == 4 then
say "1234321"
when n == 5 then
say "123454321"
when n == 6 then
say "12345654321"
when n == 7 then
say "1234567654321"
when n == 8 then
say "123456787654321"
when n == 9 then
say "12345678987654321"
otherwise
say "Please input 0 < n < 10"
end
exit
使用迴圈的解法:
/* Main program */
parse arg n
if DataType(n) \= "NUM" then do
say "That's not a number."
exit
end
if n < 1 | n > 9 then do
say "Out of range."
exit
end
positive = 1
count = 0
do forever
if positive == 1 then do
count = count + 1
call charout , count
if count == n then do
positive = 0
iterate
end
end
else do
count = count - 1
if count > 0 then
call charout , count
else
leave
end
end
say
exit
下面是一個簡單的猜測數字遊戲:
/* A guess number game */
the_number = random(1, 1000)
do forever
call charout , 'Please input a number: '
pull the_guess
if the_number = the_guess then do
say 'You guesses it!'
leave
end
else if the_number > the_guess then do
say 'Please guess more higher'
iterate
end
else do
say 'Please guess more lower'
iterate
end
end
exit
Numbers
Rexx 一般而言預設處理的位數為 9(或者使用 digits() function 取得目前的設定)。 因此如果在程式使用的位數超過預設值,需要使用 numeric digits 設定。
numeric digits 12
Subroutines
Rexx 的程式可以分割為 function 或者是 subroutine,二者的差別在於 function 一定會傳回回傳值, 而 subroutine 沒有(或者說不一定有)回傳值。
下面是一個 function 的例子:
/* Main program */
say add(5,6)
exit
add:
PARSE ARG a,b
return a + b
下面是 recursive function 的例子:
/* Main program */
do n = 1 to 5
say 'The factorial of' n 'is:' factorial( n )
end
return
/* Function to get factorial */
factorial: procedure
n = arg(1)
if n = 1 then
return 1
return n * factorial( n - 1 )
我們可以使用 call statements 來呼叫 subroutine。如果呼叫之後有回傳值返回,可以使用 RESULT 變數取得其值。
/* Main program */
call subr
exit 0
subr:
say 'You are inside internal subroutine.'
return
如果要取得參數的數目,可以使用 arg() 取得。
/* Main program */
call add 1, 2
exit
add:
PARSE ARG a,b
say 'Arg number:' arg()
c = a + b
say 'Result:' c
return
File IO
下面是讀取檔案的例子,一行一行的從 /etc/os-release 讀出資料,然後判斷目前 Linux distribution 的名稱。
/* Main program */
filename = '/etc/os-release'
do while lines(filename) > 0
line_str = linein(filename)
parse var line_str key "=" value
if compare(key, 'NAME') == 0 then do
say value
leave
end
end
System Commands
REXX 支援執行外部程式的能力,下面是一個例子:
/* Main program */
'ls'
if rc == 0 then
say 'The command executed successfully'
else
say 'The command failed, The error code is =' rc
再來是另外一個例子,1-9位數不重複印出來的練習問題,
使用者輸入1 印1-9
使用者輸入2 印1-98 (11, 22, 33等重複的不印)
使用者輸入3 印1-987 (121, 988, 667等有重複的不印):
call charout , 'Please input a number: '
pull num
if num < 1 | num > 9 then do
say "Out of range."
exit
end
'seq '10**num - 1 '| egrep -v "([0-9]).*\1"'
To send a command to a specific environment, use this format of the address instruction:
address environment expression
下面就是一個使用的例子:
address system 'ls'
address 也可以作為輸入與輸出的重新導向的設定(input, output 與 error),下面是一個例子:
/* Main program */
address system 'ls' with output stem files.
do i = 1 to files.0
say files.i
end
在上面的例子中,輸出的結果將會放到 files. 這個 compound variable 中, 而 files.0 會記錄結果的數目。
下面則是從 /etc/os-release 檔案取得內容,然後輸出到 compound variable 的例子。
/* Main program */
address system 'cat' with input stream '/etc/os-release' output stem files.
do i = 1 to files.0
say files.i
end
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。