GO BACK Copyright (c) Kyla Computing Ltd 2002
REXX: THE LANGUAGE |
||||
ABOUT TUTOR INTRODUCTION SAY COMMENTS LAYOUT RULES LITERAL STRINGS ABUTTAL CONCATENATION |
COMPARISONS |
template: SAY expression examples: SAY "print this line" SAY "Contents of A=" AWhy the word SAY and not the word PRINT I just don't know? All its doing is printing! If you don't know what I mean by EXPRESSIONS then look up that definition. Note that SAY on its own will print a blank line.
There really are very few rules when it comes to coding REXX. However it is important to understand the few that there are.
/* REXX program. Detailing Literals */ SAY "A Literal strings is a constant." SAY 'Its delimiter can be single or ' SAY 'double quotes, which is "Useful".' SAY "To continue on a second line", "just end with a comma." SAY 'We''ll see here two quotes together' --------------------------------------------- A Literal strings is a constant. Its delimiter can be single or double quotes, which is "Useful". To continue on a second line just end with a comma. We'll see here two quotes togetherThese will litter your program. These really are important. You use them anywhere you want a CONSTANT. These are numbers or strings of letters, which will not change during the execution of the program.
/* REXX program. Concatenation & Abuttal */ SAY "When two literals are" "put next to each" SAY "other they're printed" "with a single" SAY "space between then" SAY "To print without" || "gaps use these." SAY "This is called" || " ABUTTAL" ---------------------------------------- When two literals are put next to each other there printed with a single space between then To print withoutgaps use these. This is called ABUTTAL
A = 5 || 7
/* REXX program. ASSIGNMENT Instructions. */ SAY "An assignment instruction is where tokens are" SAY "are used to change the contents of a variable." A = 2 + 3 SAY A "is the result of '2 + 3'" B = A * 2 SAY B "is" A "times '2'" ---------------------------- An assignment instruction is where tokens are are used to change the contents of a variable. 5 is the result of '2 + 3' 10 is 5 times '2'Assignment instructions are used to change the contents of variables. Variables can be thought of as pigeonholes in the system where letters or a number can be held. We will deal with these in more details later. For now look at the example, Here the instruction A = 2 + 3 is adding two CONSTANTS and putting the result in the VARIABLE called A. Assignment instructions always have an equal sign in them and the name of a variable to the left of this. On the right of the equals sign are EXPRESSIONS and OPERATORS. In these examples the expressions are either single variables or constants but they can be far more complex. What do you think the contents of B would in after the following instructions?
A = 45 B = A || 1 + 3
/* REXX program. Introducing SIMPLE VARIABLES. */ SAY "Simple variable names can contain these chars." SAY "A - Z, a - z, 0 - 9, !, ?, #, $, @ & _ " SAY "0 - 9 can not be used for the first character." SAY "All lowercase chars. are converted to uppercase." SAY "Variables are initialized with their name!" TOTAL_a = 12 ; Text = "Page No." ; Page# = 1 + TOTAL_A SAY ; SAY TOTAL_a " " Text || Page# " " NEW_var ---------------------------- Simple variable names can contain these chars. A - Z, a - z, 0 - 9, !, ?, #, $, @ & _ 0 - 9 can not be used for the first character. All lowercase chars. are converted to uppercase. Variables are initialized with their name! 12 Page No.13 NEW_VAR
Naming Convention
There are rules on the name of your variables. These are detailed in the example. There are several points worth noting. If your name contains lower case characters then these are automatically converted into capitals. See here how the variable TOTAL_a is used in one line and on the next it is referred to a TOTAL_A. Doing this for real would be considered a very sloppy habit but its quite legal (like a lot of sloppy habits).
Initialized Value
This is something worth remembering, in REXX you can use a variable even if you have not given it a value. In the example here we have only used NEW_var on a SAY statement. So what does it print? The answer is its own name (in capitals of course).
Data Type
Another rather weird thing about REXX is that you do not have to tell it whether your variable is going to contain a string of characters or a number - it just doesn't care!
/* REXX program ARITHMETIC operators. */ SAY "ADD: 5 + 2 =" 5 + 2 ; SAY "SUBTRACT:2 - 5 =" 2 - 5 SAY "MULTIPLY:5 * -2 =" 5 * -2 ; SAY "DIVIDE: 5 / +2 =" 5 / +2 SAY "INT. DIV.5 % 2 =" 5 % 2 ; SAY "REMAINER:5 // 2 =" 5 // 2 SAY "POWER: 5 ** 2 =" 5 ** 2 SAY "ABUTTAL:5 || 2'00' =" 5 || 2'00' SAY "USE BRACKETS FOR PRIORITY:" 7 || ((2 + 5) * 5)/3 ---------------------------- ADD: 5 + 2 = 7 SUBTRACT:2 - 5 = -3 MULTIPLY:5 * -2 = -10 DIVIDE: 5 / +2 = 2.5 INT. DIV.5 % 2 = 2 REMAINER:5 // 2 = 1 POWER: 5 ** 2 = 25 ABUTTAL:5|| 2'00' = 5200 USE BRACKETS FOR PRIORITY: 711.6666667
8] + - (as a prefix) 5] + - (not as a prefix) 7] ** 4] Abuttal.
What is an expression?
Simply its several bits of code which will be used to work out one thing, that 'thing' may be a literal string or a number. Let's take an assignment instruction for example
OUTLINE = 'The Total is =' L * 2 + W * 2 + ExtraBitEverything here except the OUTLINE = is one expression. It contains constants, literal strings, arithmetic operators and variables but all the values will be shrunk down to one literal string that in this case will be put into the variable called OUTLINE. We could however print it by coding SAY at the beginning rather than OUTLINE =. Later we will look at functions and the arguments, which are their inputs. Normally we have just a single variable as an argument but in fact it will take a very large and complex expression. In summary an expression can be:
/* REXX program to show the PULL instruction */ SAY "Program to multiple 2 numbers" SAY "Please enter your first number" PULL Num1 SAY "Thank you, now your second number" PULL Num2 SAY "Well done: Now" Num1 "times" Num2 "=" Num1 * Num2 ---------------------------- Program to multiple 2 numbers Please enter your first number 12 Thank you, now your second number 14 Well done: Now 12 times 14 = 168The PULL Instruction is a funny little baby. What it does will depend on where you are executing your program. When running it online it will pause the execution of the routine and wait for you to type something in. When executing the REXX in JCL this instruction will try and get a line from the input queue - more about that later. For now we will worry about running it online. In the example above I typed in the numbers 12 and 14 in 'answer' to the two PULL statements. Its a pretty obvious thing to say but if you are going to use PULL like this then have a good SAY instruction just before it so you will know what to type in!
/* REXX showing Comparative Operators */ SAY 12 = 12 SAY "fred" = "fred" SAY 12 = 13 SAY "fred" = "freda" ---------------------------- 1 1 0 0
= means equals <> or >< or \=, means not equals < means less than >= or \< means not less than > means greater than <= or \> means not greater than
Note sometimes other platforms have other NOT symbols. Sometimes they use a rotated L sometimes a / (not a \).
/* REXX IF program */ A = 10 ; B = 12 IF A = B THEN SAY A "IS EQUAL TO" B ELSE SAY A "IS NOT EQUAL TO" B ---------------------------- 10 IS NOT EQUAL TO 12We can use the result of a comparative operator with an IF instruction to ensure that some instructions are only executed under certain conditions. When the comparison result is 1 (TRUE) then the statment after the THEN instruction is executed. If we want we can add an ELSE on the next line and this statement will be executed if the result is 0 (FALSE), this is optional. Note that the word ELSE has been indented. This makes the code more readable and as you will see in a minute will help you find syntax errors.
/* REXX program showing DO-END blocks */ A = 76 ; B = 76 IF A = B THEN DO SAY "A=" A "B=" B SAY "AND THEY ARE THE SAME" ; END ELSE DO SAY "A=" A "B=" B SAY "AND THEY ARE DIFFERENT"; END ---------------------------- A= 76 B= 76 AND THEY ARE THE SAMEIn the last example we could only execute one single instruction conditionally. There are lots of situations where we will want to execute lots and lots of instructions. Here we have added the keywords DO and END. As it says in the text for every DO you must have an END statements.
/* REXX program. Comparative Operators. */ SAY "Some more complex Comparisons." SAY "Compare ' 010 ' and '+10.00' ";SAY " 010 " = "+10.00" SAY "Compare ' strip ' and 'strip' ";SAY " strip " = "strip" SAY "Compare 'FRED' 'fred'" ;SAY "FRED" = "fred" SAY "Is 'APPLE' less than 'BANANA'?";SAY "APPLE" < "BANANA" SAY "Is 'a' greater than 'A'?" ;SAY "a" > "A" SAY 12 < "Apple" ;SAY 12 < "Apple" ---------------------------- Some more complex Comparisons. Compare ' 010 ' and '+10.00' 1 Compare ' strip ' and 'strip' 1 Compare 'FRED' 'fred' 0 Is 'APPLE' less than 'BANANA'? 1 Is 'a' greater than 'A'? 1 1 0
/* REXX program. Strict Comparative Operators. */ SAY "Now we will look at STRICT comparisons." SAY "Strickly compare ' strip ' & 'strip' " SAY " strip " == "strip" SAY "Check 'FRED' & 'fred' are strictly not equal" SAY "FRED" \== "fred" SAY "Strictly compare ' 010 ' & '+10.00' " SAY " 010 " == "+10.00" SAY "Strictly compare 12 * 3 & 72 / 2" SAY 12 * 3 == 72 / 2 ---------------------------- Now we will look at STRICT comparisons. Strickly compare ' strip ' & 'strip' 0 Check 'FRED' & 'fred' are strictly not equal 1 Strictly compare ' 010 ' & '+10.00' 0 Strictly compare 12 * 3 & 72 / 2 1Another feature of REXX is the 'strict comparisons' . Here the expressions must be exactly the same to get a 1 as the result. Leading and trailing spaces are not removed as you can see in the examples above. It is of course case sensitive as you would expect.
/* REXX program. Logical (Boolean) Operators. */ 1 SAY "Logical operators compare two results." 2 SAY "Print 1 if: 1 = 1 AND 2 = 2" ;SAY 1 = 1 & 2 = 2 3 SAY "Print 1 if: 1 = 3 AND 2 = 2" ;SAY 1 = 3 & 2 = 2 4 SAY "Print 1 if: 1 = 1 OR 1 = 2" ;SAY 1 = 1 | 1 = 2 5 SAY "Print 1 if: 1 = 2 OR 2 = 1" ;SAY 1 = 2 | 2 = 1 6 SAY "Print 1 if: 1 = 1 XOR 1 = 2" ;SAY 1 = 1 && 1 = 2 7 SAY "Print 1 if: 1 = 1 XOR 2 = 2" ;SAY 1 = 1 && 2 = 2 8 SAY 1 | 0 9 SAY 2 & 1 10 SAY 1 && 1 ---------------------------- Logical operators compare two results. Print 1 if: 1 = 1 AND 2 = 2 1 Print 1 if: 1 = 3 AND 2 = 2 0 Print 1 if: 1 = 1 OR 1 = 2 1 Print 1 if: 1 = 2 OR 2 = 1 0 Print 1 if: 1 = 1 XOR 1 = 2 1 Print 1 if: 1 = 1 XOR 2 = 2 0 1 +++ Error 46 in line 9: Boolean value not 0 or 1 Command returned 10/46: Boolean value not 0 or 1
/* REXX. The NOT operator and comparison errors. */ SAY "The NOT operator can be used to reverse a result." SAY " 1 not= 1 will give a:" ; SAY 1 \= 1 SAY " not 1 = 1 will give a:" ; SAY \ 1 = 1 SAY "not 1 = 1 XOR 2 \= 1 gives:" ; SAY \ 1 = 1 && 2 \= 1 SAY " 1 = 1 AND 1 gives:" ; SAY 1 = 1 & 1 ---------------------------- The NOT operator can be used to reverse a result. 1 not= 1 will give a: 0 not 1 = 1 will give a: 0 not 1 = 1 XOR 2 \= 1 gives: 1 1 = 1 AND 1 gives: 1It is possible to reverse the result of a comparison by the use of the NOT operator. The symbol used for this can vary with different platforms. On TSO it is possible to use an inverted and rotated L (which I haven't got in my character set or I would show you) or a / (slash). In the examples above you can see that the NOT symbol can be part of a comparison operator or at the beginning of the expression on its own. When it is used on its own it has a priority of 8, which is very high.
/* REXX The SELECT, WHEN, OTHERWISE and NOP instructions */ A = "120" SELECT WHEN A = "100" THEN NOP /* DO NOTHING */ WHEN A = "200" THEN SAY "A IS 200" WHEN A = "300" THEN DO SAY "DO A BLOCK OF CODE IF ITS 300 END OTHERWISE SAY "NONE ABOVE ARE TRUE" ENDIf you are a matching socks and tie man (person) then this stuff is for you. This can tidy up the crappist code. This is wonderful take a look. If you have several IF instructions all asking the same basic question then here we can handle the situation with wonderful easy, simplicity itself and all sort of other very long words. The idea is that if the first WHEN condition is TRUE it will execute the code after the THEN statement and then go straight to the END statement without doing any of the other tests. If the condition if FALSE it will try the next WHEN condition etc. If all of these conditions are FALSE the you the instructions next to OTHERWISE. Note then you don't code a THEN next to OTHERWISE. If we want to execute a block of statements we just code a DO after the THEN and an END before the next WHEN (what a month full). It's the same as the IF instruction. When there is a condition where you don't want to execute any instructions and you want to go straight to the END you can code NOP (no - operations).
/* REXX. Introducing DO loops */ DO A = 1 TO 7 BY 2 SAY "A=" A ; END DO B = 1 FOR 4 SAY " B=" B ; END ---------------------------- A= 1 A= 3 A= 5 A= 7 B= 1 B= 2 B= 3 B= 4
DO loops come is several shapes and sizes, but it's all about being able to execute a block of code more than once. It's the only way to do it in REXX so they are rather important. In these examples we are controlling the number of times we go round the loop by two different ways but on each we are incrementing a variable (which is very important). In the first example we are incrementing the variable called A. We'll keep going round the loop until A is equal to 7. The BY parameter means that each time we go round the loop A is incremented BY 2 . If BY was not coded A would default to an increment of 1. In the second example the FOR parameter has been used to ensure we go round the loop 4 times. Here B is incremented but its not B's value that will terminate the loop. To be honest you won't see this facility used a lot and I am never quite such why! What you will find is this simulated with less efficient code, where an incremented counter is added with extra statements. Very under-rated / under-used are the FOR and BY parameters.
/* REXX showing UNTIL/WHILE loops*/ A = 6; B = 1; C = 1 DO WHILE A \= B SAY "B=" B B = B + 1 ; END DO UNTIL A = C SAY " C=" C C = C + 1 ; END ---------------------------- B= 1 B= 2 B= 3 B= 4 B= 5 C= 1 C= 2 C= 3 C= 4 C= 5
It is very rare to find a REXX program without one of these two. Here we have a comparison operator and we keep going round the loop WHILE it is TRUE or UNTIL it is TRUE. There is no automatic increment so people will sometimes code there own. While the WHILE and UNTIL parameters look like exact opposites, there is one very important difference between them. The WHILE test is executed at the beginning of the loop and the UNTIL test is executed at the end - look at the red lines. See the following section for the next exciting episode where you can see the effect this can have!
/* REXX program to show the LEAVE instruction */ MaxNum = 10000; MaxLoop = 10 ; A = 2 DO Loop = 1 TO MaxLoop B = A * A SAY "Loop1=" Loop "B =" B A = B If A > MaxNum THEN LEAVE END A = 2 DO Loop = 1 TO MaxLoop WHILE A < MaxNum B = A * A SAY "Loop2=" Loop "B =" B A = B END ---------------------------- Loop1= 1 B = 4 Loop1= 2 B = 16 Loop1= 3 B = 256 Loop1= 4 B = 65536 Loop2= 1 B = 4 Loop2= 2 B = 16 Loop2= 3 B = 256 Loop2= 4 B = 65536Two examples again, both produce the same output with differing code. The first introduces the LEAVE instruction. Very simple and very useful. You leave the loop immediately you hit this instruction. In this example we go straight the SAY instruction Here it is not really necessary to use LEAVE, this is because it is the last instruction within the loop. It is cleaner to code the test on the DO instruction, which is what we have done in the second example. Note I've been a good boy and not coded the constants within the body of the program, they are defined at the top. Strictly speaking there is a mistake here, the it should be WHILE A <= MaxNum.
/* REXX program to show ITERATE & FOREVER */ A = 0; Incr = 1; Divis = 4; MaxNum = 10 DO FOREVER A = A + Incr IF A = MaxNum THEN DO SAY "HIT LOOP END CONDITION" LEAVE SAY "NEVER EXECUTED" ; END IF (A // Divis) = 0 THEN DO SAY "HERE" A "IS DIVISIBLE BY" Divis ITERATE SAY "NEVER EXECUTED" ; END SAY "A=" A END SAY "REACHED END" ---------------------------- A= 1 A= 2 A= 3 HERE 4 IS DIVISIBLE BY 4 A= 5 A= 6 A= 7 HERE 8 IS DIVISIBLE BY 4 A= 9 HIT LOOP END CONDITION REACHED END
/* REXX program to show other types of DO */ LineSpace = 3; Max = 10 DO LineSpace; SAY "***"; END B = ""; A = 0; KeepGoing = 1 DO WHILE KeepGoing A = A + 1 IF A = Max THEN KeepGoing = 0 B = B A ; END SAY B DO LineSpace; SAY "***"; END ---------------------------- *** *** *** 1 2 3 4 5 6 7 8 9 10 *** *** ***
Some more examples of DO loops. The first and third loops are printing the *** lines. Coding DO n is legal when n is a number (or a variable contains a number), it's very simple the loop is performed that number of times. I've broken the normal convention over having one instruction per line because it seemed sensible to do so!
The second loop is just showing you that the expression after the word UNTIL must have a value or 1 or 0. On most of the other examples we have used a comparison - the result of would be a 1 or 0. It's all another way of achieving the same thing. While it looks like this involves more code and therefore is probably less efficient, you will see a lot of code like this and therefore its important for you to be able to understand it.
/* REXX program to show the power of INTERPRET */ A = "SAY 'Input REXX instructions or END'" INTERPRET A DO FOREVER PULL Input IF Input = "END" THEN EXIT 0 INTERPRET Input ; END ---------------------------- Input REXX instructions or END A = 15 B = 20 SAY A * B 300 END
The first instruction here is an assignment. It's putting a complete REXX instruction into a variable, you may think this is a strange thing to do but the INTERPRET instruction can execute this! If the second part of this program doesn't knock your socks off - nothing will. It's providing you with the facility to type in any REXX command online and show you its result! Look at the entries I give the program, its executing each line at a time, in effect it is executing the program as I type it in! Type up the second part of this program and always have it at your fingertips for use as a calculator or trying REXX instructions!
/* REXX : Internal functions. */ SAY "First Line" CALL MyFunction SAY "Last Line" EXIT 0 MyFunction: SAY "Welcome to my own function!" RETURN 0 ---------------------------- First Line Welcome to my own function! Last Line
We are now going to talk about sub-routines, these are used very extensively used in large programs. It is said that the main routine of a program should only really contain CALL statements which invokes blocks of code where the real work is done. It helps you keep sight of what is going on without getting snarled up in the detail. The other time they are very useful is when the same piece of code is required in several places. When the code is in a function you just code it once and then have different CALL instructions. In the example above we have one homemade functions. These are always coded after the EXIT instruction. Their first line is called a LABEL instruction, it always ends with a colon. The function starts here and ends with a RETURN instruction.
/* REXX program to show function communication. */ CALL Funct1 2 SAY "Give the funct1 a" 2 "and you get back a" Result SAY "Give the funct1 a" 4 "and you get back a" Funct1(4) EXIT 0 Funct1: ARG Input Code = Input * 3 RETURN Code ---------------------------- Give the funct1 a 2 and you get back a 6 Give the funct1 a 4 and you get back a 12
Look at the CALL instruction, here you can see two way communication between the calling routine and the function. The argument is put next to the function name and this is picked up by the ARG instruction in the function. The ARG instruction gets very heavy and we will deal with this in detail later in the PARSE section. Look at the line RETURN code, this returns the value of to a variable called RESULT.
The next time the Funct1 function is 'called' we are using a different syntax. Instead of using the instruction CALL we place some brackets next to the function name. Note that there must not be a gap between the function name and the opening bracket! The argument is put inside the brackets. The way the return code is handled is also different. The function becomes the result. You can then put the value into a variable or print it straight out! All clever stuff, as a general rule if you are executing a function and you want the result people tend to code FUNCTION( arguments ) but if they don't need the result they code CALL FUNCTION arguments.
. .
NEXT . .
PREVIOUS . .
SECTION INDEX . .
FUNCTION-LIST . .
Built in Functions
/* REXX : DATATYPE & LENGTH functions */
A = "string" ; B = 12.0000; C = "+12.0456"
SAY "The data type of '" || A || "' is " DATATYPE(A)
SAY "The data type of '" || B || "' is " DATATYPE(B)
SAY "The data type of '" || C || "' is " DATATYPE(C)
SAY "'" || A || "' is" LENGTH(A) "characters in length."
SAY "'" || B || "' is" LENGTH(B) "characters in length."
SAY "'" || C || "' is" LENGTH(C) "characters in length."
EXIT 0
----------------------------
The data type of 'string' is CHAR
The data type of '12.0000' is NUM
The data type of '+12.0456' is NUM
'string' is 6 characters in length.
'12.0000' is 7 characters in length.
'+12.0456' is 8 characters in length.
Here we are calling two different functions, one called DATATYPE and the other called LENGTH, but where are they? They are not listed below the EXIT 0 are they? "No" I hear you cry! That's because there is a library of built in functions that you can access which increases the power of this language immeasurably. You will see what I mean in a minute. These two aren't bad for starters. The first one DATATYPE can tell us whether the contents of a variable is a number or a string of characters. Very very useful for checking data before its going to crash your program by trying to multiple something which is not a number!
Section 2 will now going to go through the more common functions that are built in.