macros
description of macro facility
DESCRIPTION
The following commands and functions are associated with the macro facility.
- def m s
Define or redefine m to have the definition s, where s is a string. Each time m occurs on input, it is replaced with s. The definition is made immediately, so the macro can be used later in the same statement block in in which it is defined and can be redefined within the same statement block.
Note that the macro definition is made regardless of any surrounding flow control statements, since the enclosing mini-program is not yet completely parsed and is not executing.
- rdef m s
- Define or redefine m to have the definition s, where s is a string. Each time m occurs on input, the value s is substituted. Unlike def, described above, the macro definition is not made until all the encompassing statement blocks are parsed and executed and the resulting mini-program is executed.
- def m([a1, ...]) '{ ... }' or rdef m([a1, ...]) '{ ... }'
- Defines a macro function named m, possibly with arguments a1, ..., that can optionally return a value using the return keyword. The string delimiter characters in the macro definition are optional. The curly brackets are required.
- undef m1 [m2 ... ]
- Remove macro definitions.
- lsdef [m1 ...]
- List the names and sizes of all (or selected) macros. The arguments can use literal text with wildcard characters ? and *, which have the usual meaning: ? matches any single character and * matches any string.
- prdef [m1 ... ]
- Print all (or selected) macro definitions. The arguments can contain wildcard characters as described above for lsdef. The definitions include are prepended with def name ' and terminated with ' so if saved to a file can be read back.
- cdef(name, s, [key, [flags]])
The function cdef() is used to define chained macros. The function can be used to maintain a macro definition in pieces that can be selectively included into a complete macro definition. The argument name is the name of the macro. The argument s contains a piece to add to the macro.
The chained macro can have three parts: a front, a middle and a back. Pieces included in each of the parts of the macros are sorted lexicographically by the keys. Pieces without a key are placed in the middle, in the order in which they were added, but after any middle pieces that include a key.
With the optional key argument, the pieces can be selectively replaced or deleted. The flags argument controls whether the pieces are added to the front or to the back of the macro or whether the pieces should be selectively included in the definition based on whether key is a currently configured motor or counter mnemonic.
The bit meanings for flags are as follows:
- 0x01
- only include if key is a motor mnemonic and the motor is not disabled.
- 0x02
- only include if key is a counter mnemonic and the counter is not disabled.
- 0x10
- place in the front part of the macro.
- 0x20
- place in the back part of the macro.
If flag is the string "delete", the piece associated with key is deleted from the named macro, or if the name is the null string, from all the chained macros.
If flag is the string "enable", the parts of the named macro associated with key are enabled, and if flag is the string "disable", the associated parts are disabled. If name is the null string "", then all chained macros that have parts associated with key will have those parts enabled or disabled.
If key is the null string, the flags have no effect.
The cdef() function will remove any existing macro defined using def or rdef. Likewise, def and rdef will removed an existing cdef() macro with the same name. However, the commands lsdef, prdef and undef do work with chained macros. When spec starts, when the reconfig command is run (or the config macro is invoked) or when individual motors or counters are enabled or disabled, all the chained macros are adjusted for the currently configured and enabled motors and counters.
- cdef("?")
- Lists all the pieces of all the chained macros.
- cdef(name, "?")
- Lists the pieces of the macro named name, as will a "?" as the third or fourth argument.
- clone(dest, src)
- Duplicates the macro src as a new macro named dest. Currently a clone of a cdef chained macro becomes an ordinary macro. (Available as of spec release 5.00.03.)
- strdef(s [, arr])
- Returns a string containing the macro definition of s. If s is not a defined macro, returns the string s itself. (Available as of spec release 5.08.02-6.) If an associative array arr is included as an argument and if the macro s is a macro function, elements of arr indexed starting at 0 will be assigned the string names of the arguments to the macro function. The element arr["file"] will be assigned the name of file where the macro was defined or "tty" if the macro was defined at the keyboard. (As of spec release 6.06.01.)
- strdef(s, key [, arr])
- If s is a chained macro, returns a string containing only the definition segment associated with key. If s is not a defined macro, returns the string s itself. If s is a macro, but not a chained macro, returns the definition. If s is a chained macro, but doesn't contain a segment associated with key, returns the null string. (Available as of spec release 6.03.04.) If an associative array arr is included as an argument and if the macro s is a macro function, elements of arr indexed starting at 0 will be assigned the string names of the arguments to the macro function. The element arr["file"] will be assigned the name of file where the macro was defined or "tty" if the macro was defined at the keyboard. (As of spec release 6.06.01.)
MACRO ARGUMENTS
Within an ordinary macro (not a macro function), the symbols $1, $2, ... are replaced with the arguments with which the macro is invoked. Also,
$0 is replaced with the macro name, $* is replaced with all the arguments, $@ is replaced with arguments delimited by \a, $# is replaced with the number of arguments, $$ is a literal $.
A macro argument is a string of characters delimited by spaces. Use quotes to include spaces within a single argument. Use \" or \' to pass literal quotes to the macro. You can continue supplying arguments on subsequent lines by putting a backslash at the end of the previous line.
When a macro is defined without arguments, only the macro name is replaced with the definition.
When a macro is defined with arguments and is encountered by the program, all characters on that line up to a ;, a { or the end of the line are eaten up, whether or not the macro uses them as arguments. When numbered arguments are referred to in the macro definition, but are missing when the macro is invoked, they are replaced with zeros. If $* is used in the definition and there are no arguments, no characters are substituted.
It is often useful when parsing macro arguments, particularly when the macro is called with a variable number of arguments, to use the split() function to place the arguments into an associative array. Typical syntax is:
{
local ac, av[]
ac = split("$*", av)
}
Note, that usage does not respect quoted arguments, since $* removes quotation marks when concatenating the macro arguments.
Introduced in spec release 6.03.04, the sequence $@ is replaced with the concatenated arguments delimited by the special character \a (the audible bell, ^G, ASCII 7). The string can then be split as follows:
{
local ac, av[]
ac = split("$@", av, "\a")
}
The elements of av[] will respect the quoted arguments in the macro invocation. There is no syntax to escape the \a.
The length of a macro definition has been unlimited since spec release 3.03.10. The number of macro arguments has been unlimited since spec release 6.00.10.
CAVEATS
Beware of unwanted side affects when referencing the same argument more than once. For example,
def test 'a = $1; b = 2 * $1'
invoked as test i++, would be replaced with a = i++; b = 2 * i++, with the result that i is incremented twice, even though that action is not apparent to the user. The previous definition also would cause problems if invoked as test 2+3, as that would be replaced with a = 2+3; b = 2 * 2+3. The latter expression evaluates to 7, not 10, as might have been intended by the user. Use of parenthesis to surround arguments used in arithmetic expressions in macro definitions will avoid such problems, as in b = 2 * ($1).
MACRO FUNCTIONS
Macro functions (introduced in spec release 4) are a type of macro that can return values and can be used as an operand in expressions. The macro definition can include function arguments, which then become available to the body of the macro function. For example:
def factorial(n) '{
if (n <= 1)
return(1);
return(n * factorial(n-1))
'
The syntax of macro functions requires the macro name followed by a set of parenthesis which can contain a comma-separated list of argument names. The argument names become local variables within the macro definition. The definition must be a statement block, that is, the statements must be enclosed in curly brackets.
EXAMPLES
def u 'unix("$*")'
Notice the double quotes convert the arguments into a single string, as required by the syntax of the unix() built-in command. When invoked with no arguments, the macro evaluates to unix("").
def ct '{
local c
if ((c = $1) == 0)
tcount(1)
else if (c < 0)
mcount(-c)
else
tcount(c)
waitcount
getcounts
print S[0], S[1], S[2]
}'
Notice that the argument $1 is referred to only once, by using the local variable c. When invoked with no arguments, the first line evaluates to if ((c = 0) == 0).
def hscan ' hklscan $1 $2 K K L L $3 $4 '
