Variables are program data that are allowed to change values. They have names and are stored in memory for the duration of the program. Variables are of different types: character, decimal, signed integer, unsigned integer, logical, and pointer.
Declaring Variables
Before you can use a variable in a CL program, you must first define the variable or declare it to the program. Declaring variables must be done at the very beginning of the program, after the PGM statement.
Before you can use a variable in a CL program, you must first define the variable or declare it to the program. Declaring variables must be done at the very beginning of the program, after the PGM statement.
A variable name can contain up to 11 characters. The first character must be an ampersand (&), which identifies the rest as a variable name. The second character must be a letter (A to Z) or one of the characters @, #, or $. All characters following the second can be letters, digits (0 to 9), or the characters @, #, $, or _ ("break"). You can use the break character to improve readability. &A, &OUTQ, and &VOL_ID are examples of valid variable names.
Examples of invalid variable names would include &NBRDLTPGMMSG, which is too long; &INV%TOTAL, which contains an invalid character; and &4TOTAL, because a digit may not follow the ampersand.
Variables are declared to the program with the Declare (dcl) command. Each variable must be declared with a separate dcl command. The dcl command has eight parameters:
- Var: Receives the name of the variable being declared. Var is a required parameter.
- Type: Receives the values *char, *dec, *INT, *UINT, *lgl, or *PTR, depending on whether the variable type is character, decimal, signed integer, unsigned integer, logical, or pointer. This parameter is required, too.
- STG: Indicates the storage method; that is, the way the variable is allocated in memory. It's optional.
- Len: Indicates the length of the variable. For character, integer, and logical variables, this value indicates the number of bytes to be allocated to the variable. For decimal variables, this value indicates the number of digits the variable should hold. This parameter is optional.
- Value: Indicates the initial value for the variable. It's optional too.
- BASPTR: Indicates the pointer upon which the variable is based. It's optional.
- DEFVAR: Indicates the variable with which this variable shares memory. This parameter is optional.
- ADDRESS: Indicates the initial value of a pointer. It is optional.
Note that, for decimal variables, len can contain two numbers: the total length of the variable (how many digits in length), and the number of decimal places. len(5 2), for example, could hold a number as large as 999.99.
Because logical variables are always 1 byte long, len(1) is optional. When the len parameter is omitted, the compiler assumes len(32) for character variables, len(15 5) for decimal variables, LEN(4) for integer variables, or len(1) for logical variables.
When you omit the len parameter but supply an initial value with the value parameter, the value parameter dictates the length of the variable that will be assumed by the compiler
Examples of declaring the length of the variable based on length of data in the value parameter.
DCL VAR(&PI) TYPE(*DEC) VALUE(3.14159265)
When you compile the program that includes the variables shown in Figure 1, &name will have a length of seven (the initial value, qsysopr, contains seven characters). &pi will have a length of (9 8) because its initial value has nine digits (of which eight fall to the right of the decimal point).
Character variables can be as long as len(32767). Decimal variables are len(15 9). Logical variables are always len(1). This table summarizes the rules for lengths for various data types.
Table 1: Maximum and Default Lengths for Variables | ||
Variable Type | Maximum Length | Default Length |
TYPE(*CHAR) | LEN(32767) | LEN(32) |
TYPE(*DEC) | LEN(15 9) | LEN(15 5) |
TYPE(*INT) | LEN(4) | LEN(4) |
TYPE(*UINT) | LEN(4) | LEN(4) |
TYPE(*LGL) | LEN(1) | LEN(1) |
TYPE(*PTR) | n/a | n/a |
Note: The only acceptable values for length of both *INT and *UINT are 2 and 4. | ||
Although the LEN parameter can be omitted when the default value is suitable, it does make the program harder to read if the programmer does not know the default length. To make your programs easier to read, you should always use the LEN parameter.
Where Variables Can Be Used
When you execute commands from the keyboard, you always enter constant values for all parameters. Consider the Display Library (dsplib) command
Parameter lib is receiving a four-character constant value (qgpl), while parameter output is receiving a six-character constant (*print).
When you code a dsplib command in a CL procedure, however, you have the option of using constants or variables in the parameters. Variables add flexibility when such flexibility is needed. If variable &a has a value of qgpl and variable &b has a value of *print
The DSPLIB command with variables as parameters
Don't be fooled into believing that variables can do all sorts of magic. If variable &c has the value lib(qgpl) and variable &d has the value OUTPUT(*print), the statement shown in Figure 4 will not produce the same result.
Invalid use of variables in a DSPLIB command.
Because it has no way of knowing what values &c and &d will have, the text editors still accept this statement as valid. The source member even compiles correctly because the compiler assumes you are entering the parameters positionally. When the procedure executes, however, it comes to a screeching halt with an error message.
Because it has no way of knowing what values &c and &d will have, the text editors still accept this statement as valid. The source member even compiles correctly because the compiler assumes you are entering the parameters positionally. When the procedure executes, however, it comes to a screeching halt with an error message.
Invalid use of a variable to code a CL command
Another example points to an additional source of errors.
For the example, if we consider something called &E isn't a command; it's a variable. Only commands can be coded in CL programs. Executing commands dynamically requires the use of program qcmdexc.
The CHGJOB command with constant values as parameters
Qualified name such as qgpl/qprint cannot be replaced by only one variable. Two variables, as in &a/&b, take the place of the qualified name. Similarly, a list must be coded with one variable per element of the list, but never with one variable for the entire list.
Invalid use of variables in parameters
The statement is incorrect if &g has the value qgpl/qprint and &i has the value 4 0 *nolist. A single variable can contain only a single value. Outq(&g) would be acceptable if &g had the value qprint only because the command would then use the library list to locate output queue qprint.
Overlaid Variables
Overlaying variables means defining two variables so that they occupy the same memory location. Since the two variables share the same memory, changing one changes the other.
To make one variable overlay another, use the STG (storage) and DEFVAR (defined on variable) parameters of the declare command. The STG parameter takes the value *DEFINED. In the DEFVAR parameter, indicate the name of another variable and the first position of that variable that is to share memory.
DCL &Object *CHAR LEN(10) STG(*DEFINED) DEFVAR(&QualObj 1)
DCL &Library *CHAR LEN(10) STG(*DEFINED) DEFVAR(&QualObj 11)
There is no difference between the contents of the &Object variable and the first ten positions of &QualObj, because &Object overlays &QualObj at the first position and overlays ten positions. In the same way, &Library is an alternate name for the last ten positions of &QualObj.
Pointer Variables
A pointer variable contains the address of another variable. To define a pointer variable, specify TYPE(*PTR) in the DCL command and do not code the LEN parameter.
A pointer variable holds the address of another variable
Since a pointer variable does not hold data, it is of little value until it is assigned the address of another variable. To assign an address to a pointer in a variable declaration, use the ADDRESS parameter of the DCL command. To assign an address in calculations, use the %ADDRESS function. You may shorten %ADDRESS to %ADDR.
DCL VAR(&NextObj) TYPE(*PTR)
DCL VAR(&Pattern) TYPE(*CHAR) LEN(10)
DCL VAR(&List) TYPE(*CHAR) LEN(252)
Example of two pointer variables
The &TopOfList variable contains the memory address of the &List variable. The CHGVAR command assigns the address of &Pattern to the &NextObj pointer variable.
To modify the value of a pointer (i.e., to do "pointer arithmetic"), use the %OFFSET (or %OFS) function. In Figure 13, the &NextObj pointer is adjusted to point to the memory address ten bytes after its current position.
To modify the value of a pointer (i.e., to do "pointer arithmetic"), use the %OFFSET (or %OFS) function. In Figure 13, the &NextObj pointer is adjusted to point to the memory address ten bytes after its current position.
Use the %OFFSET function for pointer arithmetic
To modify the value of a pointer (i.e., to do "pointer arithmetic"), use the %OFFSET (or %OFS) function. In Figure 13, the &NextObj pointer is adjusted to point to the memory address ten bytes after its current position.
Based Variables
The compiler does not allocate storage to based variables. Instead, the based variable uses a pointer in order to access the storage that has been assigned to another variable.
DCL VAR(&File) TYPE(*CHAR) LEN(20) STG(*BASED) BASPTR(&pFile)
DCL VAR(&SalesHist) TYPE(*CHAR) LEN(10)
DCL VAR(&CurrSales) TYPE(*CHAR) LEN(252)
CHGVAR VAR(&pFile) VALUE(%ADDR(&SalesHist)
/* ... do something using &File ... */
/* ... whatever you do will happen to &SalesHist ... */
CHGVAR VAR(&pFile) VALUE(%ADDR(&CurrSales)
/* ... do something using &File ... */
/* ... whatever you do will happen to &CurrSales ... */
That will do for now!
I hope you enjoyed this little insight into CL and it's super powers
