mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
170 lines
8.7 KiB
Markdown
170 lines
8.7 KiB
Markdown
|
[#]: subject: "Use Rexx for scripting in 2023"
|
|||
|
[#]: via: "https://opensource.com/article/22/12/rexx-scripting"
|
|||
|
[#]: author: "Howard Fosdick https://opensource.com/users/howtech"
|
|||
|
[#]: collector: "lkxed"
|
|||
|
[#]: translator: " "
|
|||
|
[#]: reviewer: " "
|
|||
|
[#]: publisher: " "
|
|||
|
[#]: url: " "
|
|||
|
|
|||
|
Use Rexx for scripting in 2023
|
|||
|
======
|
|||
|
|
|||
|
In a [previous article][1], I showed how the Rexx scripting language is both powerful and easy to use. It uses specific techniques to reconcile these two goals that are often considered in conflict.
|
|||
|
|
|||
|
This article walks you through two example Rexx scripts so you can get a feel for the language. Rexx purports to be highly capable yet easy to work with.
|
|||
|
|
|||
|
### An example of a Rexx script
|
|||
|
|
|||
|
The [LISP programming language][2] is famous for its overuse of parentheses. It can be a real challenge for programmers to ensure they're all matched up correctly.
|
|||
|
|
|||
|
This short script reads a line of LISP code from the user and determines whether the parentheses in the input are properly matched. If the parentheses aren't properly balanced, the program displays a syntax error.
|
|||
|
|
|||
|
Below are three sample interactions with the program. In the first, the LISP code I entered was correctly typed. But the next two contain mismatched parentheses that the Rexx script identifies:
|
|||
|
|
|||
|
```
|
|||
|
Enter a line to analyze:
|
|||
|
(SECOND (LAMBDA (LIS) (FIRST (CDR LIS)) ))
|
|||
|
Parentheses are balanced
|
|||
|
|
|||
|
Enter a line to analyze:
|
|||
|
((EQSTR (CAR LIS1) (CAR LIS2))
|
|||
|
Syntax error: too many left parens, not balanced
|
|||
|
|
|||
|
Enter a line to analyze:
|
|||
|
(EQSTR (CAR LIS1) CAR LIS2))
|
|||
|
Syntax error: right paren before or without left paren
|
|||
|
```
|
|||
|
|
|||
|
Here's the Rexx program:
|
|||
|
|
|||
|
```
|
|||
|
counter = 0 /* counts parentheses */
|
|||
|
|
|||
|
say 'Enter a line to analyze:' /* prompts user for input */
|
|||
|
pull input_string /* reads line of user input */
|
|||
|
|
|||
|
length_of_string = length(input_string)
|
|||
|
|
|||
|
/* process each character of the input line, one at a time */
|
|||
|
|
|||
|
do j = 1 to length_of_string while counter >= 0
|
|||
|
|
|||
|
character = substr(input_string,j,1)
|
|||
|
if character = '(' then counter = counter + 1
|
|||
|
if character = ')' then counter = counter - 1
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
/* display the appropriate message to the user */
|
|||
|
|
|||
|
if counter = 0 then
|
|||
|
say 'Parentheses are balanced'
|
|||
|
else if counter < 0 then
|
|||
|
say 'Syntax error: right paren before or without left paren'
|
|||
|
else
|
|||
|
say 'Syntax error: too many left parens, not balanced'
|
|||
|
```
|
|||
|
|
|||
|
First, the program prompts the user to enter a line of input with the `say` instruction. Then it reads it with a `pull` instruction.
|
|||
|
|
|||
|
`The say` and `pull` instructions are used for conversational input/output, or direct interaction with users. Rexx also supports character-oriented and line- or record- oriented I/O.
|
|||
|
|
|||
|
Next, the script uses the `length` function to place the length of the input line into the variable `length_of_string`.
|
|||
|
|
|||
|
The `do` loop processes each character from the input line, one at a time. It increments the `counter` each time it encounters a left parenthesis, and decrements it each time it recognizes a right parenthesis.
|
|||
|
|
|||
|
If the `counter` ends up as zero after processing the entire input line, the program knows that any parentheses in the input line match up correctly. If the `counter` is not 0 after processing, the input line has mismatched parentheses.
|
|||
|
|
|||
|
The final `if` statements display the proper message to the user. One could code these `if` statements in any number of styles, as per individual preference. (The main requirement is that whenever multiple statements are coded within a branch, they must be enclosed in a `do...end` group.)
|
|||
|
|
|||
|
This program shows that Rexx is free-form and case-insensitive. It does not rely on reserved words, so you're free to use common words like `counter` or `character` to represent variables.
|
|||
|
|
|||
|
The one key requirement Rexx does impose is that any function must immediately be followed by a left parenthesis. Examples in the program are the `length` and `substr` functions. Put a space between a function name and its following parenthesis, and Rexx won't recognize the function.
|
|||
|
|
|||
|
Outside of a few minimal requirements like these, Rexx requires very little from the programmer in terms of syntax, special characters, or restrictive coding rules.
|
|||
|
|
|||
|
Rexx programs look and read like pseudo-code. This makes them relatively easy to read and work with.
|
|||
|
|
|||
|
### A real-world example of a Rexx script
|
|||
|
|
|||
|
Here's a program from the real world:
|
|||
|
|
|||
|
Les Koehler, a Rexx user, had a legacy accounting program that matched accounting records on hand against those that a vendor sent to him daily. The legacy program ran for several hours every day to process 25,000 records. It employed a sequential "walk the list" technique to match one set of records against the other.
|
|||
|
|
|||
|
Les replaced the legacy program with a Rexx script. The Rexx script performs matching by using associative arrays:
|
|||
|
|
|||
|
```
|
|||
|
/* Create an associative array reflecting */
|
|||
|
/* the values in the first list of names */
|
|||
|
/* by Les Koehler */
|
|||
|
|
|||
|
flag. = 0 /* Create array, set all items to 0 */
|
|||
|
do a = 1 to list_a.0 /* Process all existing records */
|
|||
|
aa = strip(list_a.a) /* Strip preceding/trailing blanks */
|
|||
|
flag.aa = 1 /* Mark each record with a 1 */
|
|||
|
end
|
|||
|
|
|||
|
/* Try to match names in the second list */
|
|||
|
/* against those in the associative array */
|
|||
|
|
|||
|
m = 0 /* M counts number of missing names */
|
|||
|
do b = 1 to list_b.0 /* Look for matching name from LIST_B */
|
|||
|
bb = strip(list_b.b) /* Put LIST_B name into variable BB */
|
|||
|
if \ flag.bb then do /* If name isn't in FLAG array */
|
|||
|
m = m+1 /* add 1 to count of missing names */
|
|||
|
missing.m = bb /* add missing name to MISSING array */
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
missing.0 = m /* Save the count of unmatched names */
|
|||
|
```
|
|||
|
|
|||
|
Les was able to reduce processing time from several hours down to a matter of seconds.
|
|||
|
|
|||
|
The first line of code (`flag. = 0`) creates a new array called `flag` and initializes every element in that array to `0`.
|
|||
|
|
|||
|
The array `list_a` contains all the existing accounting records. Its first element (`list_a.0`) by convention contains the number of elements in the array.
|
|||
|
|
|||
|
So the first `do` loop processes all elements in the array of existing records (`list_a`) and marks each of them as existing in the `flag` array. The statement `flag.aa = 1` marks the content-addressable item in the `flag` array as present.
|
|||
|
|
|||
|
The second `do` loop peddles through each item in the set of new records, contained in the array called `list_b`.
|
|||
|
|
|||
|
The `if` statement checks whether an item from the second array of records is marked present in the `flag` array. If not, the program increments the number of items present in the new list of accounting records that do not exist in the old list of records. And it puts the missing item into the `missing` array: `missing.m = bb`.
|
|||
|
|
|||
|
The final statement (`missing.0 = m`) simply updates the number of items in the `missing` array, by convention stored in array position 0.
|
|||
|
|
|||
|
### Rexx improvements
|
|||
|
|
|||
|
Why is this Rexx program so fast compared to the legacy code it replaces? First, the associative arrays allow direct lookup of a new record against the old records. Direct access is much faster than the sequential "walk-the-list" technique it replaced.
|
|||
|
|
|||
|
Secondly, all the array elements reside in memory. Once the files of the old and new accounting records have been initialized into the Rexx arrays, no further disk I/O is needed. Disk I/O is always orders of magnitude slower than memory access.
|
|||
|
|
|||
|
A Rexx array expands as much as memory allows. This script takes advantage of modern computers with seemingly endless amounts of RAM, and frees the programmer from managing memory.
|
|||
|
|
|||
|
### Conclusion
|
|||
|
|
|||
|
I hope these two simple programs have shown how easy Rexx is to read, write, and maintain. Rexx is designed to put the burden of programming on the machine instead of the programmer. Yet the language still has plenty of power, due to the design techniques I've described in this series of articles.
|
|||
|
|
|||
|
For free Rexx downloads, tools, tutorials, and more, visit [RexxInfo.org][3]. You can join the [Rexx Language Association][4] for free.
|
|||
|
|
|||
|
_This article is dedicated to the memory of Les Koehler, who was active with Rexx and the Rexx community since their very earliest days._
|
|||
|
|
|||
|
--------------------------------------------------------------------------------
|
|||
|
|
|||
|
via: https://opensource.com/article/22/12/rexx-scripting
|
|||
|
|
|||
|
作者:[Howard Fosdick][a]
|
|||
|
选题:[lkxed][b]
|
|||
|
译者:[译者ID](https://github.com/译者ID)
|
|||
|
校对:[校对者ID](https://github.com/校对者ID)
|
|||
|
|
|||
|
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
|||
|
|
|||
|
[a]: https://opensource.com/users/howtech
|
|||
|
[b]: https://github.com/lkxed
|
|||
|
[1]: https://opensource.com/article/22/10/rexx-scripting-language
|
|||
|
[2]: https://opensource.com/article/21/5/learn-lisp
|
|||
|
[3]: http://www.RexxInfo.org
|
|||
|
[4]: http://www.RexxLA.org
|