Assignments and Symbols

A variable is an object whose value can change during the running of a REXX program. The process of changing the value of a variable is called assigning a new value to it. The value of a variable is a single character string, of any length, that may contain any characters.

You can assign a new value to a variable with the ARG, PARSE, or PULL instructions, the VALUE built-in function, or the variable pool interface, but the most common way of changing the value of a variable is the assignment instruction itself. Any clause of the form:

symbol=expression;

is taken to be an assignment. The result of expression becomes the new value of the variable named by the symbol to the left of the equal sign. Currently, on VM if you omit expression, the variable is set to the null string. However, it is recommended that you explicitly set a variable to the null string: symbol=''.

Example:

/* Next line gives FRED the value "Frederic" */
Fred='Frederic'

The symbol naming the variable cannot begin with a digit (0-9) or a period. (Without this restriction on the first character of a variable name, you could redefine a number; for example 3=4; would give a variable called 3 the value 4.)

You can use a symbol in an expression even if you have not assigned it a value, because a symbol has a defined value at all times. A variable you have not assigned a value is uninitialized. Its value is the characters of the symbol itself, translated to uppercase (that is, lowercase a-z to uppercase A-Z). However, if it is a compound symbol (described under section Compound Symbols), its value is the derived name of the symbol.

Example:

/* If Freda has not yet been assigned a value,   */
/* then next line gives FRED the value "FREDA"   */
Fred=Freda

The meaning of a symbol in REXX varies according to its context. As a term in an expression (rather than a keyword of some kind, for example), a symbol belongs to one of four groups: constant symbols, simple symbols, compound symbols, and stems. Constant symbols cannot be assigned new values. You can use simple symbols for variables where the name corresponds to a single value. You can use compound symbols and stems for more complex collections of variables, such as arrays and lists.

Constant Symbols

A constant symbol starts with a digit (0-9) or a period.

You cannot change the value of a constant symbol. It is simply the string consisting of the characters of the symbol (that is, with any lowercase alphabetic characters translated to uppercase).

These are constant symbols:

77
827.53
.12345
12e5       /* Same as 12E5 */
3D
17E-3

Simple Symbols

A simple symbol does not contain any periods and does not start with a digit (0-9).

By default, its value is the characters of the symbol (that is, translated to uppercase). If the symbol has been assigned a value, it names a variable and its value is the value of that variable.

These are simple symbols:

FRED
Whatagoodidea?    /* Same as WHATAGOODIDEA? */
?12
<.D.A.T.E>

Compound Symbols

A compound symbol permits the substitution of variables within its name when you refer to it. A compound symbol contains at least one period and at least two other characters. It cannot start with a digit or a period, and if there is only one period in the compound symbol, it cannot be the last character.

The name begins with a stem (that part of the symbol up to and including the first period). This is followed by a tail, parts of the name (delimited by periods) that are constant symbols, simple symbols, or null. The derived name of a compound symbol is the stem of the symbol, in uppercase, followed by the tail, in which all simple symbols have been replaced with their values. A tail itself can be comprised of the characters A-Z, a-z, 0-9, and @ # £ $ . ! ? and underscore. The value of a tail can be any character string, including the null string and strings containing blanks. For example:

taila='* ('
tailb=''
stem.taila=99
stem.tailb=stem.taila
say stem.tailb        /* Displays: 99                 */
/* But the following instruction would cause an error */
/*         say stem.* (                               */

You cannot use constant symbols with embedded signs (for example, 12.3E+5) after a stem; in this case, the whole symbol would not be a valid symbol.

These are compound symbols:

FRED.3
Array.I.J
AMESSY..One.2.
<.F.R.E.D>.<.A.B>

Before the symbol is used (that is, at the time of reference), the language processor substitutes the values of any simple symbols in the tail (I, J, and One in the examples), thus generating a new, derived name. This derived name is then used just like a simple symbol. That is, its value is by default the derived name, or (if it has been used as the target of an assignment) its value is the value of the variable named by the derived name.

The substitution into the symbol that takes place permits arbitrary indexing (subscripting) of collections of variables that have a common stem. Note that the values substituted can contain any characters (including periods and blanks). Substitution is done only one time.

To summarize: the derived name of a compound variable that is referred to by the symbol

s0.s1.s2. --- .sn

is given by

d0.v1.v2. --- .vn

where d0 is the uppercase form of the symbol s0, and v1 to vn are the values of the constant or simple symbols s1 through sn. Any of the symbols s1-sn can be null. The values v1-vn can also be null and can contain any characters (in particular, lowercase characters are not translated to uppercase, blanks are not removed, and periods have no special significance).

Some examples follow in the form of a small extract from a REXX program:

a=3       /* assigns '3' to the variable A    */
z=4                 /*   '4'      to Z        */
c='Fred'            /*   'Fred'   to C        */
a.z='Fred'          /*   'Fred'   to A.4      */
a.fred=5            /*   '5'      to A.FRED   */
a.c='Bill'          /*   'Bill'   to A.Fred   */
c.c=a.fred          /*   '5'      to C.Fred   */
y.a.z='Annie'       /*   'Annie'  to Y.3.4    */

say  a  z  c  a.a  a.z  a.c  c.a  a.fred y.a.4
/* displays the string:                     */
/*    "3 4 Fred A.3 Fred Bill C.3 5 Annie"  */

You can use compound symbols to set up arrays and lists of variables in which the subscript is not necessarily numeric, thus offering great scope for the creative programmer. A useful application is to set up an array in which the subscripts are taken from the value of one or more variables, effecting a form of associative memory (content addressable).

Implementation maximum: The length of a variable name, before and after substitution, cannot exceed 250 characters.

Stems

A stem is a symbol that contains just one period, which is the last character. It cannot start with a digit or a period.

These are stems:

FRED.
A.
<.A.B>.

By default, the value of a stem is the string consisting of the characters of its symbol (that is, translated to uppercase). If the symbol has been assigned a value, it names a variable and its value is the value of that variable.

Further, when a stem is used as the target of an assignment, all possible compound variables whose names begin with that stem receive the new value, whether they previously had a value or not. Following the assignment, a reference to any compound symbol with that stem returns the new value until another value is assigned to the stem or to the individual variable.

For example:

hole.  = "empty"
hole.9 = "full"

say  hole.1  hole.mouse  hole.9

/* says "empty empty full" */

Thus, you can give a whole collection of variables the same value. For example:

total. = 0
do forever
   say "Enter an amount and a name:"
   pull amount name
   if datatype(amount)='CHAR' then leave
   total.name = total.name + amount
   end
Note:
You can always obtain the value that has been assigned to the whole collection of variables by using the stem. However, this is not the same as using a compound variable whose derived name is the same as the stem. For example:
total. = 0
null = ""
total.null = total.null + 5
say total. total.null              /* says "0 5" */

You can manipulate collections of variables, referred to by their stem, with the DROP and PROCEDURE instructions. DROP FRED. drops all variables with that stem (see page Purpose), and PROCEDURE EXPOSE FRED. exposes all possible variables with that stem (see page Purpose).

Notes:
  1. When the ARG, PARSE, or PULL instruction or the VALUE built-in function or the variable pool interface changes a variable, the effect is identical with an assignment. Anywhere a value can be assigned, using a stem sets an entire collection of variables.
  2. Because an expression can include the operator =, and an instruction may consist purely of an expression (see section Commands to External Environments), a possible ambiguity is resolved by the following rule: any clause that starts with a symbol and whose second token is (or starts with) an equal sign (=) is an assignment, rather than an expression (or a keyword instruction). This is not a restriction, because you can ensure the clause is processed as a command in several ways, such as by putting a null string before the first name, or by enclosing the first part of the expression in parentheses.

    Similarly, if you unintentionally use a REXX keyword as the variable name in an assignment, this should not cause confusion. For example, the clause:

    Address='10 Downing Street';

    is an assignment, not an ADDRESS instruction.

  3. You can use the SYMBOL function (see page SYMBOL) to test whether a symbol has been assigned a value. In addition, you can set SIGNAL ON NOVALUE to trap the use of any uninitialized variables (except when they are tails in compound variables--see page ***).