by Fred Brack
The REXX programming language was developed by IBM employee Mike Cowlishaw on his own time around 1980, then used heavily throughout the company. The underlying words for the acronym REXX are irrelevant today, and the language is normally referred without all-caps as simply Rexx. While I learned and used Rexx as an IBM employee myself in the 1990s, I relearned it around 2015 and now use it extensively to support a website. My skill level is advanced intermediate, not expert, but I would love to share what I know with you!
Rexx is not a "modern" programming language, and you are very unlikely to be hired as a programmer for this language. However, because of its simplicity, it is GREAT first language to learn how to program, and it is also great for home projects: maintaining sports league scores, home inventory or any simple database application, or automating the process of building web pages for your own website (which is my primary use). Let me stress "simplicity." You don't have to declare variable types or even declare them at all prior to first use; the "language" consists mainly of simple and fairly obvious words (like SAY, LINEIN, LINEOUT, LEFT, CENTER, and UPPER); and the control structures of DO/END and IF/THEN/ELSE are pretty obvious and easy to use.
My experience these days is solely with the "port" of the Rexx language called Regina Rexx, which runs on Windows and many other operating systems. See these resources:
I found that it installed easily on my Windows machine. The Rexx Manual comes with the installation as a PDF. You also get a subroutine library called Rexx Utility Functions (for advanced users). You will need an editor to create your source file (I use Notepad++, but you could use plain Notepad or any other editor).
You run Rexx programs in a Command window (WIN-R, cmd for example); you simply type the name of the program as a command - you don't have to "start" the Rexx Interpreter. However, you must "associate" the extension of your Rexx programs (I use ".rexx" but ".rex" and ".rx" are also allowed) with the Interpreter. So I created a BAT file to get me all setup, and I execute it every time I want to execute a Rexx program. Here it is:
REM SetupRexx.bat: Setup for issuing Rexx programs
REM Two of the lines below are suppressed because they have been preset
REM ftype Regina=C:\Program Files\rexx.org\Regina\regina.exe "%1" %*
REM assoc .rexx=Regina
I left the REM'd statements there in case you need them on your machine. And here's great news: A program called REXXTRY (Rexx Try) comes with your installation. When you execute it, you are put into an INTERACTIVE MODE with the Rexx interpreter, so you can try out statements one by one. Set a variable or two and begin typing Rexx commands.
This is as good a place as any to cover the matter of multiple Rexx statements on a line. Normally you put one complete Rexx statement on a line. You don't need to end the line with anything. If it is a very long statement, you may continue on the next line by ending the first line with a comma. But if you want to put multiple Rexx statements on one line, you separate them by semicolons. I mention this here because if you want to do something like test a DO loop with REXXTRY, you need to put all the statements on one line.
Here is a simple Rexx program to add two numbers:
/* Sample: Add two numbers */
SAY "Enter the first number ..."
SAY "Enter the second number ..."
SAY number1 "+" number2 "=" number1+number2
While you may find the term "PULL" a bit odd, its meaning should be fairly
obvious in context: it opens the keyboard so you can type a response, which is then
PULLed (loaded) into the variable specified, number1 or number2. Responding with 1
and 2 will result in the output: "1 + 2 = 3". And that's the
complete program -- nothing else is required. (And yes, if you know
something about programming you will realize the program will fail if the user
enters a character like "a" instead of a number, so of course you should error-check
each input, and the Rexx statement to do this would look like this:
IF DATATYPE(number1)<>"NUM" THEN ...)
A typical Rexx program would be divided like this:
Let's overview each of these four categories.
Because the developer felt so strongly about the need for good programming habits, he actually REQUIRED that at least the first statement of a program be a comment! That's not necessarily true in today's implementations, but it's a great idea that I fully support. Comment well and frequently!
The way you enter comments varies by programming language. In Rexx, a comment is DELINIATED as follows:
/* This is a comment */
You can start a comment (
/*) anywhere on a line (the whole line or after a
Rexx line of code) and the comment doesn't end until the notation "
which can be on a different line if you wish. The Rexx Interpreter (the
program that executes your code) IGNORES EVERYTHING in a comment. Comment
/* A comment by itself */
/* A comment that starts on one line
and ends on a different line */
SAY "Hello" /*** a comment after a Rexx statement ***/
You do NOT have to declare variables, but it's a good idea. Some programming languages mandate it and even require you to specify a data type (i.e., numeric versus character). Rexx is super flexible, and you can even reuse the same variable for both numeric and character data. In fact, if you set a variable to a number, you can use it as a number (in math) OR as a string (a character).
I like to set almost all the variables I use up front just so I can see similarity in names or refer to the list to find out what name I used within the code. I typically set number variables to 0 and character variables to null (""). Examples:
input_line = ""
input_lines = 0
max# = 99
asterisk = "*"
Yes, you can use a decimal point, binary notation, or even hexadecimal notation, but I'm trying to keep it simple! You can also bicapitilize your variable names, as in inputLine. Note that Rexx doesn't care about case here: inputline and inputLine both get converted to INPUTLINE internally! Do what YOU like, but stick with your convention. I personally recommend lowercase or bicapitalized variable names with ALL REXX COMMANDS IN UPPERCASE. This will make reading your programs a LOT easier.
I'm not going to go into stems except to say that a stem in Rexx is what other languages call an array: one variable name suffixed by an index number representing many related data points. The zero element of a stem is reserved by convention for the number of elements in the stem, though it is not mandatory. Example:
fruit.0 = 3
fruit.1 = "apple"
fruit.2 = "banana"
fruit.3 = "pear"
Once you have declared your variables, you are ready to write your program. Rexx programs consist of Instructions and Built-in Functions (which taken together I call commands). I think of the Instructions as primarily control structures (like CALL, DO, IF, LEAVE, ITERATE, which all control which Rexx instructions or functions will be executed next rather than do anything by themselves), but they also contain certain environmental instructions (like PUSH and PULL) and, somewhat oddly to me, one data manipulation instruction (PARSE). The Built-In Functions consist of all the rest of the functionality of the Rexx language: Data Manipulation (like LEFT, INSERT, POS (position), LENGTH, and UPPER) and system-related (like LINEIN, LINEOUT, BEEP, DATE, and TIME); and, of course, a few oddball instructions not important for an introduction to the language.
The most important thing I have to say about the Main Program is that IN MY OPINION it is best to do almost all the work of your program in Subroutines (the next section) and have the Main Program section simply use the Rexx Instruction CALL over and over to set the order of operation and call all the applicable subroutines where the real work is done! Thus I might suggest:
/* Comments first */
/* Variables here */
/* Main Program */
This is where your primary coding goes. You create a subroutine for each logical operation in your program. For example:
Some subroutines will stand alone: just a convenient named place to go to work on whatever it does. Other subroutines will be called repeatedly within your program. For instance, I have an "Error" subroutine which "beeps" and issues a message passed as an operand. And if I call my ErrorExit subroutine, it will first call the Error subroutine with my passed message, then Exit, rather than return to the caller.
Here is an example of calling a subroutine without passing an operand (like we showed above):
/* here is where my Rexx commands go */
If you need to pass one or more operands to your subroutine (common for reusable subroutines called by other subroutines), the code might look like this:
CALL MySub operand1,operand2
PARSE ARG op1,op2
/* Rexx commands here, which can use variables op1 and op2 */
Program flow is directed by what I call control structures. Either data is tested and control flow is altered depending on what is found, or the use of a certain section of code is controlled by conditions established at the start, end, or even in the middle of its execution.
There are two primary control structures: DO/END and IF-THEN-ELSE (and its variation, SELECT). This section is not a complete tutorial on these structures, just an introduction.
The concept of a DO/END structure is to say DO (execute) the following section of code up to the END statement. You establish conditions for when and how the code will be executed via operands on the DO statement. The "when" concept is whether the code will run at all and whether or not it will repeat itself. You can tell DO to execute the code:
Here's a simple example:
DO n=1 TO 10
If you are running this in REXXTRY, you need to put all the statments on one line:
DO n=1 TO 10;SAY n;END
The output of running this code is ten lines specifying the number 1 on the first line and 10 on the last one. If you want to end the looping prematurely, you can issue the instruction LEAVE. If you want to stop processing any more code in the loop at this particular point but continue the loop with the next iteration, you issue the ITERATE instruction. For example, to print only even numbers through 6 (where the "//" notation means "remainder divide" which returns the remainder from division):
limit = 6
DO n=1 TO 10
IF n//2=1 THEN ITERATE
IF n=limit THEN LEAVE
The output is three lines: 2, 4, 6.
A DO loop is often used to read in all the lines from a file and perform processing on the data. The LINES function in Rexx tells you whether or not you have reached end-of-file by returning a 1 for more lines and 0 for none; so you can use it as follows in a DO loop:
DO WHILE LINES(myfile)>0
input = LINEIN(myfile)
For other purposes, you can say UNTIL instead of WHILE to determine whether or not to exit the loop when you hit the END statement. "DO FOREVER" will require you to figure out within the loop when to exit via a LEAVE statement. There are a few other options, but now you have the basics.
This fundamental structure of all programming languages is implemented very simply using those words. As always, ELSE is not required, but if used, you can continue with as many ELSEs as you wish. (A follow-on ELSE other than the final one looks like: ELSE IF ...) As usual, the "condition" after the IF must evaluate to either TRUE (1) or FALSE (0), and it can be a very complex condition, optionally followed by an "&" to AND with another condition or a "|" to OR with another condition, and you can have as many of these as you wish. Example:
IF n=0 THEN SAY "n is 0"
ELSE IF n<0 THEN SAY "n is negative"
ELSE IF n>0 & n<10 THEN SAY "n is between 1 and 9"
ELSE SAY "n is greater than 9"
SELECT is a variation of IF-THE-ELSE. See the manual!
PARSE is one of the most useful instructions in the Rexx language, but it is complicated. Therefore I have devoted a separate page to just PARSE.
Yep, I created a separate page for that, too: Using Rexx to Manage a Database Application.
I'm not sure where to go from here in this Introductory page! Please offer your feedback via the email link below. Thanks.