Language Elements and Reference:xpplrm

Macro operator Foundation

The macro operator interprets character strings as program code during runtime of a program and executes the code contained in the character string. When the macro operator is found within a character string or within text, parts of the text are replaced with the contents of the variable which follows the macro operator.

The character string that the macro operator interprets at runtime can contain only expressions and not commands or statements. Also, all names or symbols for functions and variables referenced within the character string must exist at runtime. A character string containing names for LOCAL or STATIC variables or STATIC functions cannot be interpreted by the macro operator, since the corresponding symbol references are resolved at compile time and no longer exist at runtime.

The length of character strings which the macro operator can interpret or compile is not limited in Xbase++.

Text substitution

Within a character string, the names (or symbols) of PRIVATE or PUBLIC variables can appear preceded by the macro operator. A period can appear after the variable name to separate the symbol from the remaining text. In such a character string, the variable references within the character string are replaced at runtime with the contents of the corresponding memory variables. This substitution can only occur when the contents of the memory variable is also a character string. An example of text substitution is shown in the following program code:

PRIVATE cDay, cTime 

cDay  := CDow(Date()) 
cTime := Time() 

? "Today is &cDay., the time is &cTime.!" 

// result: Today is Tuesday, the time is 17:46:28! 

This type of text substitution can only be performed using the contents of PRIVATE and PUBLIC variables. When the symbol for the variable does not exist at runtime, a runtime error occurs.

Compiling at runtime

When the macro operator appears in front of a variable of "character" data type or when it appears in front of a character expression enclosed in parentheses, the character string is interpreted as program code, the code is executed, and the result is returned. The macro operator compiles the contents of the character variable or the result of the character expression during runtime of the program. The following program code shows an example:

cDay := "CDow(Date())"          // variable containing character 
                                // expression 
                                // compile contents of variable 
? &cDay                         // result: Tuesday 

? FieldName(1)                  // result: NAME 

cFieldValue := &(FieldName(1))  // compile character expression 
? cFieldValue                   // result: King 

When the characters to be compiled contain references to functions or variables, the names or symbols must be visible at runtime. Functions referenced in the string cannot be declared using STATIC FUNCTION and must be linked into the program. Note that if a function is called only via the macro operator, its function name only appears within character strings and does not otherwise appear in the program. The corresponding function must, therefore, be identified to the linker using the statement REQUEST in order for the function to be linked into the executable file.

Variables referenced within the character string must be of the storage class PRIVATE or PUBLIC. The symbols for LOCAL and STATIC variables do not exist at runtime of the program and therefore cannot be compiled using the macro operator. The value of a PRIVATE or PUBLIC variable can be of any data type. This means that within a character string that is macro compiled at runtime, arrays and objects can be accessed if they are referenced in a PRIVATE or PUBLIC variable.

PRIVATE nNumber := 100, cString := "Xbase++" 

cMacro := "QOut( nNumber, cString )" 
? &cMacro                               //  result: 100 Xbase++ 
                                        //            NIL 

The macro operator returns the value of the last expression from the compiled character string as the result. For this reason, the &cMacro in the above example outputs the specified values and NIL on two lines. On the first line, the values are output from the compiled character string using QOut(). In the second line the result of the macro operator is displayed using the command ? (the return value of QOut() is NIL). The macro operator compiles a character string at runtime, executes the code resulting from it, and returns the result of the last expression in the character string.

Create variables at runtime

Using the macro operator, it is possible to dynamically create variables at runtime of a program whose name (or identifier) is not known when the application is written. This is demonstrated in the following example:

cVarName := "cPrivate" 
? Type("cPrivate")                      // result: U 

PRIVATE &cVarName := "Xbase++" 

? cVarName                              // result: cPrivate 
? &cVarName                             // result: Xbase++ 

? Type("cPrivate")                      // result: C 
? cPrivate                              // result: Xbase++ 

An example of how this technique could be used would be in programming a command line interpreter using Xbase++.

Nested macro operations

The macro operator can be nested to any depth. The following program code shows an example of nesting:

LOCAL   cLocal   := "Xbase" 
PUBLIC  cString  := "James Bond's BMW" 
PRIVATE Xbase    := "&cString" 

? cLocal                            // result: Xbase 
? &cLocal                           // result: James Bond's BMW 

In the example, the expression &cLocal is compiled to the expression &cString, because the variable cLocal contains the identifier of the PRIVATE variable XBase. Subsequently, &cString is compiled and results in the character string "James Bond's BMW", which is the contents of the PUBLIC variable cString.

The macro operator in commands

The macro operator cannot interpret Xbase++ commands, since these are translated to function calls by the preprocessor. However, the operator can be used in command arguments. The following lines show an example:

PRIVATE cFileName := "CUSTOMER.DBF" 

USE Customer                        // USE with literal 
USE (cFileName)                     // USE with parentheses 

USE &cFileName                      // USE with macro operator 

In the example, the filename for the command USE is specified in three different ways. The file name can be optionally specified as a literal, a character expression in parentheses or a macro expression. This is only possible with commands whose arguments can be specified as a literal or as a character expression in parentheses. Generally, with these commands the argument should be enclosed in parentheses and not be specified using the macro operator.

Feedback

If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.