xHarbour Reference Documentation > Operator Reference |
Macro operator (unary): compiles a character string at runtime.
a) &<cVarName> b) "Text &<cVarName>. substitution" c) &<cExpression> d) <objVar>:&<cIVarName> [:= <xValue>] <objVar>:&<cMethodName>([<params,...>]) e) &<cFunctionName>([<params,...>])
One extremely powerful feature of xHarbour is the Macro operator (&). It allows for compiling and executing program code at runtime of an application. The program code is supplied in form of a character string and can be as simple as a variable name or may include very complex expressions. Despite its power, there are some limitations a programmer must be aware of when using the Macro operator.
As a first rule, no white space characters may follow the macro operator. This is required to distinguish the & sign from the bitwise AND operator. The macro expression must follow the & operator immediately.
All entities that do not have a symbolic name at runtime of an application cannot be accessed by the Macro operator. This applies to memory variables of type GLOBAL, LOCAL and STATIC, to STATIC declared functions and procedures, as well as commands and statements. Also, the Macro operator cannot resolve multiple line expressions, it can only compile expressions programmed within one line of code.
As indicated in the syntax description, there are some typical scenarios where the Macro operator is used. Examples for these scenarios follow:
a) | Acessing and creating variables |
The values of PRIVATE, PUBLIC and FIELD variables can be retrieved by using a character string indicating the symbolic name of a variable. |
LOCAL cPrivate := "myPrivate" LOCAL cPublic := "myPublic" LOCAL cField := "LastName" LOCAL x, y, z PUBLIC myPublic := "A public variable" PRIVATE myPrivate := 10 USE Customer x := &cPrivate y := &cPublic z := &cField ? x, y, z // result: 10 A public variable Miller
The macro operator is used in this example as the right-hand-side expression of the assignments. As a result, the values of the variables whose names are stored in LOCAL variables are retrieved and assigned to the LOCAL variables x, y and z. |
When the macro operator is used on the left-hand-side of an assignment, a value is assigned to the corresponding variable. If the variable does not exist prior to the assignment, it is created as a PRIVATE variable: |
LOCAL cPrivate := "myPrivate" LOCAL cPublic := "myPublic" LOCAL cField := "LastName" PUBLIC myPublic := "A public variable" USE Customer &cPrivate := 10 // creates a PRIVATE variable // named myPrivate &cPublic := "New text" FIELD->&cField := "McBride" ? &cPrivate, &cPublic, &cField // result: 10 New text McBride
Note that PUBLIC variables cannot be created using this technique while field variables must be aliased to assign a value. |
b) | Text substitution |
Text substitution is a special situation where the macro operator appears within a character string. |
LOCAL cText PRIVATE cMacro := "xHarbour" cText := "This is a &cMacro. test." ? cText // result: This is a xHarbour test." cMacro := CDoW(Date()) cText := "Today is &cMacro.!" ? cText // result: Today is Tuesday!"
When a character string contains a macro variable, the macro is substituted with the contents of the macro variable. Note that the end of the macro variable within the text string is indicated with a period. This period does not appear in the result string but serves as "end-of-macro" marker. |
c) | Runtime compilation |
The most common situation for using the Macro operator is the compilation of expressions at runtime. Expressions must be syntactically correct and may only refer to entities whose symbolic names are known at runtime. If, for example, a function is called only within a Macro expression and nowhere else in the program code, the function symbol must be declared with the REQUEST statement so that it is linked to the executable file. |
PROCEDURE Main REQUEST CDoW, Date LOCAL cExpr := "CDoW(Date())" ? &cExpr // result: Tuesday RETURN
The creation of code blocks as complex data types is also a very common usage scenario for the Macro operator. |
PROCEDURE Main LOCAL i, cExpr, cFPos REQUEST FieldGet, FieldPut USE Customer aBlocks := Array( FCount() ) FOR i:=1 TO FCount() cFPos := LTrim( Str(i) ) cExpr := "{|x| IIf(x==NIL,FieldGet(" + cFPos + ")," + ; "FieldPut(" + cFPos + ",x)) }" aBlocks[i] := &cExpr NEXT AEval( aBlocks, {|b| QOut(Eval(b)) } ) USE RETURN
Within the FOR..NEXT loop, the syntax for code blocks accessing different field variables is created as character strings. Each string differs by the value of the loop counter variable which identifies individual field variables by their ordinal position. The character strings are compiled to code blocks and stored in an array. |
d) | Sending messages to objects |
The possibility of sending messages to objects is another field of Macro operator usage that allows for highly dynamic application development. Messages are encoded as character strings: |
#include "hbclass.ch" PROCEDURE Main LOCAL obj := TestClass():new( "Text to display" ) LOCAL cMsg := "display" obj:&cMsg() // displays: Text to display cMsg := "cValue" obj:&cMsg := "New text" obj:display() // displays: New text RETURN CLASS TestClass EXPORTED: DATA cValue METHOD new( cString ) CONSTRUCTOR METHOD display ENDCLASS METHOD new( cString ) CLASS TestClass ::cValue := cString RETURN self METHOD display() CLASS TestClass ? ::cValue RETURN self
When the send operator (:) is followed by the Macro operator, the contents of the variable following the Macro operator is interpreted as message to send to the object. Note that calling an object's method requires the parentheses be added to the expression. |
e) | Calling functions |
There are two possibilities for calling functions using the macro operator: one is to encode a complete function call as a macro expression, the other is to use only the function name. The difference between both possibilities lies in the type of variables that can be passed to a Macro operator called function. |
PROCEDURE Main LOCAL cMacro LOCAL nValue := 2 PRIVATE nNumber := 3 cMacro := "TestFunc( nNumber )" // result: 30 ? &cMacro cMacro := "TestFunc" ? &cMacro( nValue ) // result: 20 RETURN FUNCTION TestFunc( n ) RETURN 10 * n
When the macro expression includes parentheses for the function call, only PRIVATE, PUBLIC or FIELD variables can be passed as parameters, since the variable names appear in the macro string. LOCAL variables, in contrast, can be passed when the parentheses are "hard coded", i.e. the macro string contains only the name of the function to call. |
See also: | @(), ( ), {|| }, HB_MacroCompile(), HB_SetMacro() |
Category: | Indirect execution , Special operators , Operators |
LIB: | xhb.lib |
DLL: | xhbdll.dll |
http://www.xHarbour.com