home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-11-26 | 44.8 KB | 1,151 lines |
- The REXX Tutorial for Complete Beginners
-
- This document is being ported from a UNIX version for IMC Unix. It was
- written by Ian Collier. If you find any mistakes or unixisms in it, please
- contact Paul Prescod: papresco@undergrad.math.uwaterloo.ca.
-
- Please also contact me if you have suggestions for improvement, or
- text you would like to see added, or files you would like to see in
- the zip file. Also, if you could write a REXX script that turns
- a readable text file into a .inf file, I would love to ship both text
- and .inf versions.
-
-
-
- 1. Creating a Rexx program
-
- Many programmers start by writing a program which displays the message
- "Hello world!". Here is how to do that in Rexx...
-
- Write a file called "hello.cmd" containing the following text. Use any
- text editor, e, edit, or epm will do. To do this in the WorkPlace shell,
- just go to the templates folder and drag a data file object out of it.
- Bring up its settings and rename it to "hello.cmd." The text, as with all
- example text in this guide, starts at the first indented line and ends at
- the last. The four spaces at the start of each line of text should not be
- entered (this is very important!):
-
- /* This program says "Hello world!" */
- say "Hello world!"
-
- This program consists of a comment saying what the program does, and an
- instruction which does it. "say" is the Rexx instruction which displays
- data on the terminal.
-
- The method of executing a Rexx program varies greatly between
- implementations. On OS/2, you would just type "hello.cmd" in that
- file's directory, or double click on its icon in the WorkPlace Shell.
-
- When you execute your first Rexx program using the method detailed above,
- you should see the message "Hello world!" appear on the screen.
-
- 2. Doing arithmetic
-
- Rexx has a wide range of arithmetic operators, which can deal with very
- high precision numbers. Here is an example of a program which does
- arithmetic. Make a file called "arith.cmd" containing the following:
-
- /* This program inputs a number and does some calculations on it */
- pull a
- b=a*a
- c=1/a
- d=3+a
- e=2**(a-1)
- say 'Results are:' a b c d e
-
- in a positive integer. Here is a sample run:
-
- input: 5
- output: Results are: 5 25 0.2 8 16
-
- The results you see are the original number (5), its square (25), its
- reciprocal (0.2), the number plus three (8) and two to the power of one
- less than the number (16).
-
- This example illustrates several things:
-
- * variables: in this example a, b, c, d and e are variables. You can
- assign a value to a variable by typing its name, "=", and a value, and
- you can use its value in an expression simply by typing its name.
- * input: by typing "pull a" you tell the interpreter to ask the user for
- input and to store it in the variable a.
- * arithmetic: the usual symbols (+ - * /) as well as ** (to-power) were
- used to perform calculations. Parentheses (or "brackets") were used to
- group together an expression, as they are in mathematics.
- * string expressions: the last line of the program displays the results by
- saying the string expression
-
- 'Results are:' a b c d e
-
- This has six components: the string constant 'Results are:' and the five
- variables. These components are attached together with spaces into one
- string expression, which the "say" command then displays on the
- terminal. A string constant is any sequence of characters which starts
- and ends with a quotation mark - that is, either " or ' (it makes no
- difference which you use, as long as they are both the same).
-
- If you supply the number 6 as input to the program, you should notice that
- the number 1/6 is given to nine significant figures. You can easily
- change this. Edit the program and insert before the second line:
-
- numeric digits 25
-
- If you run this new program you should see that 25 significant figures are
- produced. In this way you can calculate numbers to whatever accuracy you
- require, within the limits of the machine.
-
- At this point it seems worth a mention that you can put more than one
- instruction on a line in a Rexx program. You simply place a semicolon
- between the instructions, like this:
-
- /* This program inputs a number and does some calculations on it */
- pull a; b=a*a; c=1/a; d=3+a; e=2**(a-1); say 'Results are:' a b c d e
-
- Needless to say, that example went a bit over the top...
-
- 3. Errors
-
- Suppose you ignored the instructions of the previous section and typed a
- non-integer such as 3.4 as input to the program. Then you would get an
- error, because the ** (to-power) operator is only designed to work when
- the second parameter (that is, the power number) is an integer. You might
- see this, for example:
-
- 3.4
- 6 +++ e=2**(a-1)
- Error 26 running arith.cmd, line 6: Invalid whole number
-
- Or if you typed zero, you might see the following (because you cannot
- divide by zero):
-
- rexx arith
- 0
- 4 +++ c=1/a
- Error 42 running arith.cmd, line 4: Arithmetic overflow or underflow
-
- Perhaps most interestingly, if you type a sequence of characters which is
- not a number, you might see this. It does not complain about the
- characters you entered, but at the fact that the program tries to use it
- as a number.
-
- rexx arith
- hello
- 3 +++ b=a*a
- Error 41 running arith.cmd, line 3: Bad arithmetic conversion
-
- In each case, you have generated a "syntax error" (it is classified as a
- syntax error, even though the problem was not directly related to the
- program's syntax). What you see is a "traceback" starting with the line
- which caused the error (no other lines are listed in this traceback,
- because we have not yet considered any Rexx control structures), and a
- description of the error. This information should help you to determine
- where the error occurred and what caused it. More difficult errors can be
- traced with the "trace" instruction (see later).
-
- 4. Untyped data
-
- In the previous section, you found that you could input either a number or
- a sequence of letters and store it in the variable a, although arithmetic
- can only be performed on numbers. That is because data in Rexx are
- untyped. In other words, the contents of a variable or the result of an
- expression can be any sequence of characters. What those characters are
- used for matters only to you, the programmer. However, if you try to
- perform arithmetic on a random sequence of characters you will generate a
- syntax error, as shown in the previous section.
-
- You have seen that you can add strings together by placing a space in
- between them. There are two other ways: the abuttal and the concatenation
- operator. An abuttal is simply typing the two pieces of data next to each
- other without a space. This is not always appropriate: for example you
- cannot type an "a" next to a "b", because that would give "ab", which is
- the name of another unrelated variable. Instead, it is safer to use the
- concatenation operator, ||. Both these operations concatenate the strings
- without a space in between. For example:
-
- /* demonstrates concatenation and the use of untyped data */
- a='A string'
- b='123'
- c='456'
- d=a":" (b||c)*3
- say d
-
- The above program says "A string: 370368". This is because (b||c) is the
- concatenation of strings b and c, which is "123456". That sequence of
- characters happens to represent a number, and so it can be multiplied by 3
- to give 370368. Finally, that is added with a space to the concatenation
- of a with ":" and stored in d.
-
- 5. More on variables
-
- The previous examples only used single-letter variable names. In fact it
- is more useful to have whole words as variable names, and Rexx allows this
- up to an implementation maximum (which should be suitably large, e.g. 250
- characters). Moreover, not only letters but numbers and the six characters
- "@#$!?_" are allowed in variable names - or "symbols", as they are called
- in the liturature. These are valid symbols:
-
- fred
- Dan_Yr_0gof
- HI!
-
- The case of letters is unimportant, so that for example "Hello", "HELLO"
- and "hellO" all mean the same.
-
- If you use a symbol in an expression when it has not been previously given
- a value, that does not cause an error (unless "signal on novalue" is set -
- see later). Instead, it just results in its own name translated into
- upper case.
-
- /* A demonstration of simple symbols */
- foo=3
- bar="Characters"
- say foo bar':' hi!
-
- This program says "3 Characters: HI!".
-
- As well as "simple symbols", which are variables like the above, there are
- arrays. Any ordinary variable name can also be used as the name of an
- array:
-
- /* This program uses an array. */
- pull a
- array.1=a
- array.2=a*a
- array.3=a**3
- say array.1 array.2 array.3 array.1+array.2+array.3
-
- An element of an array is accessed by typing the array name, a dot, and
- the element number. The array name and the dot are together known as the
- "stem" of the array. The name of the element is called a "compound
- symbol". Note that an array does not have to be declared before it is
- used.
-
- In fact not only numbers, but strings and variable names may be used as
- element names. Also, an element name can consist of two or more parts
- separated by dots, so giving two or more dimensional arrays.
-
- /* This program uses an array with various elements */
- book.1.author="M. F. Cowlishaw"
- book.1.title="The REXX Language, a practical approach to programming"
- book.1.pub="Englewood Cliffs 1985"
- book.2.author="A. S. Rudd"
- book.2.title="Practical Usage of REXX"
- book.2.pub="Ellis Horwood 1990"
- /* insert lots more */
- say "Input a book number"
- pull i
- say "Author: " book.i.author
- say "Title: " book.i.title
- say "Publisher:" book.i.pub
-
- In the above program, an array called "book" is created, containing a
- number of records each with elements AUTHOR, TITLE and PUB. Notice that
- these three uppercase names are produced by symbols "author", "title" and
- "pub", because those symbols have not been given values. When a book
- number i has been input, the elements of the ith record are printed out.
- It is not an error to reference an undefined element of an array. If you
- type "3" into the above program, you will see this:
-
- Input a book number
- 3
- Author: BOOK.3.AUTHOR
- Title: BOOK.3.TITLE
- Publisher: BOOK.3.PUB
-
- As before, if a compound symbol has not been given a value, then its name
- is used instead.
-
- There is a way to initialise every element of an array: by assigning a
- value to the stem itself. Edit the above program and insert after the
- comment line:
-
- book.="Undefined"
-
- This gives every possible element of the array the value "Undefined", so
- that if you again type "3" you will see the following:
-
- Input a book number
- 3
- Author: Undefined
- Title: Undefined
- Publisher: Undefined
-
- 6. Functions
-
- The Online Rexx Summary contains a list of the functions which are available
- in Rexx. Each of these functions performs a specific operation upon the
- parameters. For example,
-
- /* Invoke the date function with various parameters */
- say date("W")',' date()
-
- This might say, for example, "Friday, 22 May 1992".
-
- A function is called by typing its name immediately followed by "(". After
- that come the parameters, if any, and finally a closing ")". In the above
- example, the "date" function is called twice. The value of date("W") is
- the name of the weekday, and the value of date() is the date in "default"
- format.
-
- 7. Conditionals
-
- It is time to use some Rexx control structures. The first of these will
- be the conditional. Here is an example:
-
- /* Use a conditional to tell whether a number is less than 50 */
- pull a
- if a<50 then say a "is less than 50"
- else say a "is not less than 50"
-
- The program is executed in the manner in which it reads - so, if a is less
- than 50 then the first instruction is executed, else the second
- instruction is executed.
-
- The "a<50" is a conditional expression. It is like an ordinary
- expression (in fact conditional expressions and ordinary numeric
- expressions are interchangeable), but it contains a comparison operator.
-
- There are many comparison operators, as follows:
-
- = (equal to) < (less than) > (greater than) <= (less or equal)
- >= (greater or equal) <> (greater or less) \= (not equal)
- \> (not greater) \< (not less)
-
- All the above operators can compare numbers, deciding whether one is equal
- to, less than, or greater than the other. They can also compare
- non-numeric strings, first stripping off leading and trailing blanks.
-
- There are analogous comparison operators to these for comparing strings
- strictly. The main difference between them is that 0 is equal to 0.0,
- numerically speaking, but the two are different if compared as strings.
- The other difference is that the strict operators do not strip blanks
- before comparing. The strict operators are
-
- == (equal to) << (less than) >> (greater than) <<= (less or equal)
- >>= (greater or equal) \== (not equal) \>> (not greater) \<< (not less)
-
- Conditional expressions may be combined with the boolean operators:
- & (and), | (or) and && (xor). They may also be reversed with the \ (not)
- operator.
-
- /* Decide what range a number is in */
- pull a
- if a>0 & a<10 then say "1-9"
- if a\<10 & a<20 then say "10-19"
- if \ (a<20 | a>=30) then say "20-29"
- if a<=0 | a>=30 then say "Out of range"
-
- As well as demonstrating the boolean and comparison operators, this
- program shows that the "else" clause is not required to be present.
-
- The above program may also be written using Rexx's other conditional
- instruction, "select":
-
- /* Decide what range a number is in */
- pull a
- select
- when a>0 & a<10 then say "1-9"
- when a\<10 & a<20 then say "10-19"
- when \ (a<20 | a>=30) then say "20-29"
- otherwise say "Out of range"
- end
-
- The "select" instruction provides a means of selecting precisely one from
- a list of conditional instructions, with the option of providing a list of
- instructions to do when none of the above were true. The difference is
- that if no part of a "select" instruction can be executed then a syntax
- error results, whereas it is OK to miss out the "else" part of an "if"
- instruction.
-
- Only one instruction may be placed after "then", "else" and "when", but
- Rexx provides a way of bracketing instructions together so that they can
- be treated as a single instruction. To do this, place the instruction
- "do" before the list of instructions and "end" after it.
-
- /* execute some instructions conditionally */
- pull a
- if a=50 then
- do
- say "Congratulations!"
- say "You have typed the correct number."
- end
- else say "Wrong!"
-
- If you wish for one of the conditional instructions to do "nothing", then
- you must use the instruction "nop" (for "no operation"). Simply placing
- no instructions after the "then", "else" or "when" will not work.
-
- 8. Loops
-
- Rexx has a comprehensive set of instructions for making loops, using the
- words "do" and "end" which you met briefly in the previous section.
-
- a. Counted loops
-
- The instructions within a counted loop are executed the specified number
- of times:
-
- /* Say "Hello" ten times */
- do 10
- say "Hello"
- end
-
- A variation of the counted loop is one which executes forever:
-
- /* This program goes on forever until the user halts it */
- do forever
- nop
- end
-
- b. Control loops
-
- Control loops are like counted loops, but they use a variable (called
- the control variable) as a counter. The control variable may count
- simply in steps of 1:
-
- /* Count to 20 */
- do c=1 to 20
- say c
- end
-
- or in steps of some other value:
-
- /* Print all multiples of 2.3 not more than 20 */
- do m=0 to 20 by 2.3
- say m
- end
-
- It may take a specific number of steps:
-
- /* Print the first six multiples of 5.7 */
- do m=0 for 6 by 5.7
- say m
- end
-
- or it may go on forever:
-
- /* Print all the natural numbers */
- do n=0
- say n
- end n
-
- The "n" at the end of this last example is optional. At the end of any
- controlled loop, the name of the control variable may be placed after
- the "end", where it will be checked to see if it matches the control
- variable.
-
- c. Conditional loops
-
- A set of instructions may be executed repeatedly until some condition is
- true. For example,
-
- /* I won't take no for an answer */
- do until answer \= "NO"
- pull answer
- end
-
- Alternatively, they may be executed as long as some condition is true:
-
- /* It's OK to repeat this as long as there is no error */
- do while error=0
- pull a
- if a="ERROR" then error=1
- else say a
- end
-
- Note that in this example, if there is already an error to start with
- then the set of instructions will not be executed at all. However in
- the previous example the instructions will always be executed at least
- once.
-
- d. Controlled conditional loops
-
- It is possible to combine forms a or b with form c mentioned above, like
- this:
-
- /* I won't take no for an answer unless it is typed three times */
- do 3 until answer \= "NO"
- pull answer
- end
-
- or this:
-
- /* input ten answers, but stop when empty string is entered */
- do n=1 to 10 until ans==""
- pull ans
- a.n=ans
- end
-
- The "iterate" and "leave" instructions allow you to continue with, or to
- leave, a loop respectively. For example:
-
- /* input ten answers, but stop when empty string is entered */
- do n=1 to 10
- pull a.n
- if a.n=="" then leave
- end
-
- /* print all integers from 1-10 except 3 */
- do n=1 to 10
- if n=3 then iterate
- say n
- end
-
- If a symbol is placed after the instructions "iterate" or "leave", then
- you can iterate or leave the loop whose control variable is that symbol.
-
- /* Print pairs (i,j) where 1 <= i,j <= 5, except (2,j) if j>=3 */
- do i=1 to 5
- do j=1 to 5
- if i=2 & j=3 then iterate i /* or "leave j" would work,
- or just "leave" */
- say "("i","j")"
- end
- end
-
- 9. Parsing
-
- The following program examines its arguments:
-
- /* Parse the arguments */
- parse arg a.1 a.2 a.3 a.4 .
- do i=1 to 4
- say "Argument" i "was:" a.i
- end
-
- Execute it as usual, except this time type "alpha beta gamma delta" after
- the program name on the command line, for example:
-
- arguments alpha beta gamma delta
-
- The program should print out:
-
- Argument 1 was: alpha
- Argument 2 was: beta
- Argument 3 was: gamma
- Argument 4 was: delta
-
- The argument "alpha beta gamma delta" has been parsed into four
- components. The components were split up at the spaces in the input. If
- you experiment with the program you should see that if you do not type
- four words as arguments then the last components printed out are empty, and
- that if you type more than four words then the last component contains all
- the extra data. Also, even if multiple spaces appear between the words,
- only the last component contains spaces. This is known as "tokenisation".
-
- It is not only possible to parse the arguments, but also the input. In
- the above program, replace "arg" by "pull". When you run this new program
- you will have to type in some input to be tokenised.
-
- Replace "parse" with "parse upper" in the program. Now, when you supply
- input to be tokenised it will be uppercased.
-
- "arg" and "pull" are, respectively, abbreviations for the instructions
- "parse upper arg" and "parse upper pull". That explains why the "pull"
- instruction appeared in previous examples, and why it was that input was
- always uppercased if you typed letters in response to it.
-
- Other pieces of data may be parsed as well. "parse source" parses
- information about how the program was invoked, and what it is called.
- "parse version" parses information about the interpreter itself. However,
- the two most useful uses of the parse instruction are
- "parse var [variable]" and "parse value [expression] with". These allow
- you to parse arbitrary data supplied by the program.
-
- For example,
-
- /* Get information about the date and time */
- d=date()
- parse var d day month year
-
- parse value time() with hour ':' min ':' sec
-
- The last line above illustrates a different way to parse data. Instead of
- tokenising the result of evaluating time(), we split it up at the
- character ':'. Thus, for example, "17:44:11" is split into 17, 44 and 11.
-
- Any search string may be specified in the "template" of a "parse"
- command. The search string is simply placed in quotation marks, for
- example:
-
- parse arg first "beta" second "delta"
-
- This line assigns to variable first anything which appears before
- "beta", and to second anything which appears between "beta" and "delta".
- If "beta" does not appear in the argument string, then the entire string
- is assigned to first, and the empty string is assigned to "second". If
- "beta" does appear, but "delta" does not, then everything after "beta"
- will be assigned to second.
-
- It is possible to tokenise the pieces of input appearing between search
- strings. For example,
-
- parse arg "alpha" first second "delta"
-
- This tokenises everything between "alpha" and "delta" and places the
- tokens in first and second.
-
- Placing a dot instead of a variable name during tokenising causes that
- token to be thrown away:
-
- parse pull a . c . e
-
- This keeps the first, third and last tokens, but throws away the second
- and fourth. It is often a good idea to place a dot after the last
- variable name, thus:
-
- parse pull first second third .
-
- Not only does this throw away the unused tokens, but it also ensures that
- none of the tokens contain spaces (remember, only the last token may
- contain spaces; this is the one we are throwing away).
-
- Finally, it is possible to parse by numeric position instead of by
- searching for a string. Numeric positions start at 1, for the first
- character, and range upwards for further characters.
-
- parse var a 6 piece1 +3 piece2 +5 piece3
-
- The value of piece1 will be the three characters of a starting at
- character 6; piece2 will be the next 5 characters, and piece3 will be the
- rest of a.
-
-
- 10. Interpret
-
- Suppose you have a variable "inst" which contains the string "a=a+1". You
- can execute that string as an instruction, by typing:
-
- interpret inst
-
- The interpret instruction may be used to accept Rexx instructions from the
- user, or to assign values to variables whose names are not known in
- advance.
-
- /* Input the name of a variable, and set that variable to 42 */
- parse pull var
- interpret var "=" 42
-
- 11. The stack
-
- Rexx has a data stack, which is accessed via the "push", "queue" and
- "pull" instructions. The "pull" instruction (or in full, "parse pull")
- inputs data from the user as we have seen before. However, if there is
- some data on the stack then it will pull that instead.
-
- /* Access the Rexx stack */
- queue "Hello!"
- parse pull a /* a contains "Hello!" */
- parse pull b /* b is input from the user */
- push "67890"
- push "12345"
- parse pull c /* c contains "12345" */
- /* there is one item left on the stack */
-
- The difference between "push" and "queue" is that when the items are
- pulled off the stack, the items which were queued appear in the same order
- that they were queued (FIFO, or first in, first out), and the items which
- were pushed appear in reverse order (LIFO, or last in, first out).
-
- 12. Subroutines and functions
-
- The following program defines an internal function, and calls it with
- some data:
-
- /* Define a function */
- say "The results are:" square(3) square(5) square(9)
- exit
-
- square: /* function to square its argument */
- parse arg in
- return in*in
-
- The output from this program should be: "The results are: 9 25 81"
-
- When Rexx finds the function call "square(3)", it searches the program for
- a label called "square". It finds the label on line 5 - the name followed
- by a colon. The interpreter executes the code which starts at that line,
- until it finds the instruction "return". While that code is being
- executed, the arguments to the function can be determined with "parse arg"
- in the same way as the arguments to a program. When the "return"
- instruction is reached, the value specified is evaluated and used as the
- value of "square(3)".
-
- The "exit" instruction in this program causes it to finish executing
- instead of running into the function.
-
- A function which takes multiple arguments may be defined, simply by
- separating the arguments with a comma. That is, like this:
-
- /* Define a function with three arguments */
- say "The results are:" condition(5,"Yes","No") condition(10,"X","Y")
- exit
-
- condition: /* if the first argument is less than 10, return the second,
- else return the third. */
- parse arg c,x,y
- if c<10 then return x
- else return y
-
- A subroutine is similar to a function, except that it need not give a
- value after the "return" instruction. It is called with the "call"
- instruction.
-
- /* Define a subroutine to print a string in a box, then call it */
- call box "This is a sentence in a box"
- call box "Is this a question in a box?"
- exit
-
- box: /* Print the argument in a box */
- parse arg text
- say "+--------------------------------+"
- say "|"centre(text,32)"|" /* centre the text in the box */
- say "+--------------------------------+"
- return
-
- It is possible to call a function, even a built-in function, as if it were
- a subroutine. The result returned by the function is placed into the
- variable called "result".
-
- /* print the date, using the "call" instruction */
- call date "N"
- say result
-
- If a function or subroutine does not need to use the variables which the
- caller is using, or if it uses variables which the caller does not need,
- then you can start the function with the "procedure" instruction. This
- clears all the existing variables away out of sight, and prepares for a
- new set of variables. This new set will be destroyed when the function
- finishes executing. The following program calculates the factorial of a
- number recursively:
-
- /* Calculate factorial x, that is, 1*2*3* ... *x */
- parse pull x .
- say x"!="factorial(x)
- exit
-
- factorial: /* calculate the factorial of the argument */
- procedure
- parse arg p
- if p<3 then return p
- else return factorial(p-1) * p
-
- The variable p which holds the argument to funtion factorial is unaffected
- during the calculation of factorial(p-1), because it is hidden by the
- "procedure" instruction.
-
- If the subroutine or function needs access to just a few variables, then
- you can use "procedure expose" followed by the list of variable names to
- hide away all except those few variables.
-
- You can write functions and subroutines which are not contained in the
- same Rexx program. In order to do this, write the function and save it
- into a file whose name will be recognised by the interpreter. This type
- of function is called an "external" function, as opposed to an "internal"
- function which can be found inside the currently running program.
-
- If you want to call your function or subroutine using "call foobar" or
- "foobar()", then you should save it in a file named "foobar.cmd" which
- can be found in the current directory or in your path.
-
- The "procedure" instruction is automatically executed before running your
- external function, and so it should not be placed at the start of the
- function. It is not possible for an external function to access any of
- its caller's variables, except by the passing of parameters.
-
- For returning from external functions, as well as the "return" instruction
- there is "exit". The "exit" instruction may be used to return any data to
- the caller of the function in the same way as "return", but "exit" can be
- used return to the caller of the external function even when it is used
- inside an internal function (which is in turn in the external function).
- "exit" may be used to return from an ordinary Rexx program, as we have
- seen. In this case, a number may be supplied after "exit", which will be
- used as the exit code of the interpreter.
-
- 13. Executing commands
-
- Rexx can be used as a control language for a variety of command-based
- systems. The way that Rexx executes commands in these systems is as
- follows. When Rexx encounters a program line which is nether an
- instruction nor an assignment, it treats that line as a string expression
- which is to be evaluated and passed to the environment. For example:
-
- /* Execute a given command upon a set of files */
- parse arg command
- command "file1"
- command "file2"
- command "file3"
- exit
-
- Each of the three similar lines in this program is a string expression
- which adds the name of a file (contained in the string constants) to the
- name of a command (given as a parameter). The resulting string is passed
- to the environment to be executed as a command. When the command has
- finished, the variable "rc" is set to the exit code of the command.
-
- The environment to which a command is given varies widely between systems,
- but in most systems you can select from a set of possible environments by
- using the "address" instruction.
-
- 14. Signal
-
- Where other programming languages have the "goto" command, Rexx has
- "signal". The instruction "signal label" makes the program jump to the
- specified label. However, once this has been done, it is not possible to
- resume any "select" or "do" control structures that have recently been
- entered. Thus the main use of "signal" is to jump to an error handling
- routine when something goes wrong, so that the program can clean up and
- exit.
-
- There is a much more useful way of using "signal", however. That is to
- trap certain kinds of error condition. The conditions which may be
- trapped include: "syntax" (that is, any syntax error), "error" (any
- environment command that results in a non-zero exit code), "halt" (when
- the user interrrupts execution) and "novalue" (which is when a symbol is
- used without having been given a value).
-
- Error trapping for one of these conditions is turned on by
-
- signal on <condition>
-
- and is turned off by
-
- signal off <condition>
-
- When one of these conditions occurs, the program immediately signals to a
- label whose name is the same as that of the condition. Trapping is turned
- off, so another "signal on" will be required if you want to continue to
- trap that condition.
-
- Whenever a "signal" occurs, the variable "sigl" is set to the line number
- of the instruction which caused the jump. If the signal was due to an
- error trap, then the variable "rc" will be set to an error code.
-
- /* This program goes on forever until someone stops it. */
- say "Press Control-C to halt"
- signal on halt
- do i=1
- say i
- do 10000
- end
- end
-
- halt:
- say "Ouch!"
- say "Died at line" sigl
-
-
- 15. Tracing
-
- Full details of how to use Rexx's tracing facility are contained in
- the online rexx reference.
-
- If a program goes wrong and you need more information in order to work out
- why, then Rexx provides you with the ability to trace all or part of your
- program to see what is happening.
-
- The most common form of tracing is turned on by
-
- trace r
-
- This causes each instruction to be listed before it is executed. Also, it
- displays the results of each calculation after it has been found.
-
- Another useful trace command is:
-
- trace ?a
-
- This makes the interpreter list each instruction and stop before it is
- executed. You can execute the instruction by pressing return, or you can
- type in some Rexx to be interpreted, after which the interpreter will
- pause again. You can use this to examine the program's variables and so
- forth.
-
- If you want the interpreter to stop only when passing a label, use:
-
- trace ?l
-
- This is useful for setting breakpoints in the program, or for making the
- program stop at a function call.
-
-
-
-
- The REXX Summary
-
- Summary of the summary
-
- * Section 1: Removed
- * Section 2: Summary of expression syntax
- * Section 3: Summary of instructions
- * Section 4: Summary of builtin functions
-
- [1] The Rexx Language, a practical approach to programming
- M. F. Cowlishaw
- Englewood Cliffs 1985
-
- 2 Summary of expression syntax
-
- Strings: "String constants" 'enclosed in quotes'
- Hex strings: '616263 64'x
- Numbers: 123.4e-56
- Constant symbols: .abc 1d4 7!
- Simple symbols: foo bar xyz3
- Stems: array.
- Compound symbols: c.3 element.bar.45
- Operators: arithmetic: + - * / ** (to-power) % (div) // (mod)
- string: [abuttal] [space] || (concatenation)
- logical: \ (not) & (and) | (or) && (xor)
- comparison: = > < <> <= >= \> \< \=
- == >> << <<= >>= \>> \<< \== (strong comparison)
- Function calls: fn(1,2,3) bar(,5) 'DATE'()
-
- 3 Summary of instructions
-
- /* this is a comment */
-
- expression - execute a host command
-
- symbol=value - assignment
-
- ADDRESS [VALUE] [environment] - change the current environment
- ADDRESS environment command - execute a command in an environment
-
- CALL name [arg][,[arg],...]] - call a function or subroutine
- CALL ON condition [NAME symbol]- turn on condition handling
- CALL OFF condition - turn off condition handling
-
- condition = ERROR | FAILURE | NOTREADY | HALT
-
- DO [ symbol=start [TO finish] ] [WHILE expression_w]
- [ [BY step ] ]
- [ [FOR count ] ] [UNTIL expression_u]
-
- [ expression_c ] [FOREVER ]
-
- - block or repetitive block instruction
-
- DROP symbol [symbol...] - de-assignment
-
- END [symbol] - end block or repetitive block instruction
-
- EXIT [expression] - exit program or external function
-
- IF expression [;] THEN [;] statement [ ; ELSE [;] statement]
- - conditional instruction
-
- INTERPRET expression - dynamically execute a string
-
- ITERATE [symbol] - continue repetitive block
-
- LEAVE [symbol] - leave repetitive block
-
- NOP - do nothing
-
- NUMERIC DIGITS n - set parameters for numeric formatting
- NUMERIC FUZZ n
- NUMERIC FORM SCIENTIFIC
- | ENGINEERING
- | "string constant"
- | [VALUE] expression
-
- OPTIONS expression - Control system-dependent things
-
- [PARSE [UPPER]] ARG template
- [PARSE [UPPER]] PULL [template]
- PARSE [UPPER] LINEIN [template]
- PARSE [UPPER] SOURCE template
- PARSE [UPPER] VERSION template
- PARSE [UPPER] NUMERIC template
- PARSE [UPPER] VAR symbol template
- PARSE [UPPER] VALUE expression WITH template
-
- template -> [firstPosition] assignments [assignments]
- assignments -> [nextPosition] varlist [stopPosition]
- varlist -> varname ' ' [varlist]
- varname -> "non-constant symbol"
- | '.'
- firstPosition -> position
- nextPosition -> position [nextPosition]
- stopPosition -> position
- position -> searchPosition
- | absPosition
- | relPosition
- | '(' "expression" ')'
- searchPosition -> "string constant"
- absPosition -> "integer"
- | '=' numexpr
- relPosition -> '+' numexpr
- | '-' numexpr
- numexpr -> "integer"
- | '(' "integer expression" ')'
-
- PROCEDURE - hide the caller's symbols
- PROCEDURE EXPOSE var1 [var2...]
- PROCEDURE HIDE var1 [var2...]
-
- PUSH expression - stack a value in LIFO order
- QUEUE expression - stack a value in FIFO order
-
- RETURN [value] - return from a function or subroutine
-
- SAY [expression] - echo data
- SAYN expression - echo data without newline
-
- SELECT [expression]
- WHEN expression THEN statements
- WHEN expression THEN statements
- ...
- [OTHERWISE statements]
- END [SELECT] - switch on a list of conditions
-
- SIGNAL [VALUE] name - jump to a label
- SIGNAL ON condition [NAME symbol] - turn on condition handling
- SIGNAL OFF condition - turn off condition handling
-
- condition = ERROR | FAILURE | NOTREADY | HALT | SYNTAX | NOVALUE
-
- TRACE [symbol] - control program tracing. Values are:
- TRACE "string" A (all clauses) C (commands) E (error)
- TRACE VALUE expression F (failure) I (intermediate values)
- L (labels) N (normal, =F) O (off)
- R (results)
-
-
- 4 Summary of builtin functions
-
- Standard functions
-
- ABBREV(information,info[,length]) - check for valid abbreviations
- ABS(number) - return the absolute value
- ADDRESS() - return the current environment
- ARG([n][,opt]) - return or test an argument
- BITAND(string1,string2[,pad])
- BITOR (string1,string2[,pad]) - combine two strings with bit operations
- BITXOR(string1,string2[,pad])
- B2D(binary)
- B2X(binary)
- D2B(decimal)
- C2X(string)
- C2D(string[,n])
- D2C(decimal[,n]) - convert between data formats
- D2X(decimal[,n])
- X2B(hex)
- X2C(hex)
- X2D(hex)
- CENTER(s,n[,pad]) - centre a string in a field
- CENTRE(s,n[,pad])
- COMPARE(s1,s2[,pad]) - compare two strings
- CONDITION([option]) - return information about trapped condition
- Option can be (default I):
- C (condition name) D (description)
- I (instruction) S (status)
-
- COPIES(s,n) - replicate a string
- DATATYPE(string[,type]) - test datatype. Type can be:
- A (alphanumeric) B (bits) L (lowercase)
- M (mixed case) N (number) S (symbol chars)
- U (upper case) W (whole number) X (hex)
-
- DATE([format]) - get date. Format can be:
- B (base date - days since 1/1/1 AD)
- C (days in century) D (days in year)
- E (European) J (Julian) M (month name)
- N (normal: dd Mon yyyy) O (ordered)
- S (sorted) U (USA) W (day of week)
-
- DELSTR(string,n[,length]) - delete substring
- DELWORD(string,n[,length]) - delete words
- DIGITS() - NUMERIC DIGITS setting
- ERRORTEXT(i) - Rexx error message
- FORM() - NUMERIC FORM setting
-
- FORMAT(number [,[before] [,[after] [,[expp] [,expt]]]] )
- - format a number as specified
- FUZZ() - NUMERIC FUZZ setting
- INSERT(new,target[,[n][,[length][,pad]]]) - insert new string into target
- JUSTIFY(s,n[,pad]) - justify text to given width
- LASTPOS(needle,haystack[,start]) - find last occurrence of a string
- LEFT(string,num[,pad]) - return an initial substring
- LENGTH(string) - find the length of a string
- LINESIZE() - find the terminal width
- MAX(number[,number...]) - find the maximum of a set
- MIN(number[,number...]) - find the minimum of a set
- OVERLAY(new,target[,[n][,[length][,pad]]]) - overlay new string on to target
- POS(needle,haystack[,start]) - find the first occurance of a string
- QUEUED() - return the number of items on the stack
- RANDOM([min][,[max][,seed]]) - return a random number
- REVERSE(string) - find the reverse of a string
- RIGHT(string,num[,pad]) - return a final substring
- SOURCELINE([i]) - return a line of the source program
- SPACE(s[,[n][,pad]]) - evenly space words in a sentence
- STRIP(string[,[opt][,char]]) - remove leading/trailing spaces
- SUBSTR(string,n[,length[,pad]]) - return a substring
- SUBWORD(string,n[,k]) - return a substring of words
- SYMBOL(name) - test to see if a symbol is defined
- TIME([format]) - get the time. Format can be:
- C (civil time) N (normal) L (long)
- H (hours since midnight)
- M (minutes since midnight)
- S (seconds since midnight) E (elapsed time)
- R (elapsed time then reset)
-
- TRACE([setting]) - get and/or set trace mode (see trace
- instruction)
-
- TRANSLATE(string[,[tableo][,[tablei][,pad]]])
- - translate characters using given tables
- TRUNC(number[,n]) - truncate floating point number
- VALUE(s[,[newvalue][,selector]]) - get or set value of a symbol
-
- VERIFY(string,reference[,[option][,start]])
- - verify string for valid characters
- WORD(string,n) - return a word from a string
- WORDINDEX(string,n) - return the position of a word in a string
- WORDLENGTH(string,n) - return the length of a word in a string
- WORDPOS(phrase,string[,start]) - find a phrase in a string
- WORDS(string) - return the number of words in a string
- XRANGE([a[,b]]) - return a range of characters
-
- I/O functions (some of which are UNIX-specific)
-
- CHARIN([stream] [,[position] [,count]]) - read characters
- CHAROUT([stream] [,[string] [,position] ]- write characters
- CHARS([stream]) - number of characters available
- CLOSE(stream) - close a stream
- FDOPEN(fd [,[mode] [,stream]]) - open an fd number
- FILENO(stream) - find an fd number
- FTELL(stream) - return the current file pointer
- LINEIN([stream] [,[line] [,count]]) - read a line
- LINEOUT([stream] [,[string] [,line]]) - write a line
- LINES([stream]) - determine whether lines may be read
- OPEN(file [,[mode] [,stream]]) - open a file
- PCLOSE(stream) - close a pipe
- POPEN(command [,[mode] [,stream]]) - open a pipe to a shell command
- STREAM(stream [,[option] [,command]]) - miscellaneous stream operations
-
- UNIX-specific functions
-
- CHDIR(directory) - change to new directory
- GETCWD() - return current working directory
- GETENV(name) - get an environment variable
- PUTENV(string) - set an environment variable
- SYSTEM(s) - return the output of a shell command
- USERID() - return the process owner's login name
-
- Mathematical functions (implemented as separate package)
-
- ACOS(x) the arc-cosine of x in radians (0<=acs(x)<=pi)
- ASIN(x) the arc-sine of x in radians (-pi/2<=asn(x)<=pi/2)
- ATAN(x) the arc-tangent of x in radians (-pi/2<=atn(x)<=pi/2)
- COS(x) the cosine of x radians
- EXP(x) the exponential of x (2.718281... to the power x)
- LN(x) the natural logarithm of x (x>0)
- SIN(x) the sine of x radians
- SQRT(x) the square root of x (x>=0) [arbitrary precision possible]
- TAN(x) the tangent of x radians (x <> pi/2)
- TOPOWER(x,y) x to the power y
-
-
-