.DEFINE
WSupported on Windows
|
USupported on Unix
|
VSupported on OpenVMS
|
NSupported in Synergy .NET
|
.DEFINE identifier[, replacement]
or
.DEFINE macro (arg, ...) [replacement2]
Arguments
identifier
The name of the replacement identifier to be defined.
replacement
(optional) The text to replace the identifier. The comma is optional unless replacement begins with a “(”.
macro
The name of the macro to be defined.
arg
One or more replacement arguments.
replacement2
(optional) The text to replace the macro.
Discussion
The .DEFINE compilation control directive defines an identifier and optionally assigns it replacement text. You can define parameterized macros using the second form of the .DEFINE directive above.
Whenever identifier is encountered within a subsequent logical line, replacement is substituted for identifier. The specified replacement text begins with the first non-white space character after the comma (or after identifier if the comma is omitted) and ends with the last non–white space character in the logical line, excluding comments. If replacement is not specified, identifier is removed from each following logical line in which it is encountered.
Replacement can contain another replacement identifier name. If that identifier hasn’t been processed within the current replacement operation, it is also replaced. (See example E.)
Identifier is not replaced with the specified text if the identifier is encountered within an .IFDEF, .IFNDEF, or .UNDEFINE compiler directive line. (See example B.)
By default, if a .DEFINE directive that redefines a previously defined identifier is encountered, the compiler generates a “Symbol already defined” warning (SYMDEFD), and the second definition supersedes the previous one. You can change this default by using the .DEFINE warning compiler option. If you specify this option, the compiler does not generate a warning each time you redefine a symbol or .UNDEFINE something that isn’t already defined. (See Invoking the traditional compiler (dbl) for more information about this compiler option.)
Replacement identifiers remain defined until the entire file is compiled, unless the -qrelaxed:end compiler option is set. If -qrelaxed:end is set, replacement identifiers are cleared at the end of the routine, when the END statement is encountered, instead of at the end of the file.
We recommend that you uppercase all replacement identifiers defined by the .DEFINE directive so that you can easily differentiate them from fields. We also recommend that you use the .DEFINE directive to define constant values instead of hard-coding them throughout your application. The .DEFINE directive enables you to more easily and reliably develop and maintain your applications by localizing constant values. |
Built-in definitions
Several system defines are built into the compiler to enable you to conditionally compile your code based on which defines are set. Since these identifiers already exist, they do not require .DEFINE. See Built-in compiler definitions and Appendix D: Built-in Defines for more information.
A parameterized macro is a macro that can insert specified objects (parameters) when it is expanded. Each arg is a replacement identifier and only has meaning within the scope of a single definition. (In other words, it must be unique within all the arguments of a given definition, but can be duplicated across definitions.)
The replacement2 content starts with the first nonblank character following the closing “)” of the arguments, and continues until the last nonblank character on the logical line.
When a parameterized macro is invoked within code, the text associated with each of the defined arguments is inserted into the .DEFINE’s replacement text. Compilation of the line containing the parameterized define then continues. Nested parameterized macros of the same name are not permitted.
Note that continuation lines within a parameterized macro definition are allowed, but each continuation line reduces to a single space in the replacement text. Thus, the replacement text for
.define a(b) x (b)
and
.define a (b) & x (b)
are not the same. The replacement text for the first is “x (b),” whereas it is “<space>x (b)” for the second. This generally is not a problem, except where a definition will be used as a function.
Using the above definitions, the code
var = %a(num)
generates an error using the second definition because it expands to
var = % x(num)
which is invalid syntax. (A space is not allowed between the “%” and the “x”.) This can be solved by making sure a space is valid in an expansion. For example, the second form above can be fixed by using this form:
.define a (b) x & (b)
because the expansion of
var = %x (num)
is valid syntax.
When invoking a macro, arg is considered to be the first nonblank character following the leading “(” or “,” up to the last nonblank character preceding the trailing “,” or “)”.
There is a special case of the above. If the first nonblank character encountered is a “<”, the replacement text begins with the first character following the “<” and continues until the last character preceding the matching “>”. In other words, the surrounding angle brackets define the text but are stripped when used. Thus,
.define abc(arg) xyz(D_STORE, arg)
when used by
abc(<1,3, "hello">)
expands to
xyz(D_STORE, 1,3, "hello")
String concatenation is supported in the replacement text by using the following rule: If an unquoted accent grave (`) immediately precedes or follows a replacement argument, it is stripped from the final text form. In a quoted string, two accents grave preceding and a single one following a replacement argument are stripped. For example:
.define BASEREG(id,cls) id = `%cls`_cid ("DEF_``cls`_REC")
when used by
BASEREG(class_id, DSPOBJ)
expands to
class_id = %DSPOBJ_cid("DEF_DSPOBJ_REC")
Macro expansions within a string work only at a single level. For example,
.define MYNAME earl .define name(t) "My name is ''t'" main record earl, a*, "Earl" proc open(1,o,"TT:") writes(1,name(MYNAME) ; This will display My name is MYNAME end
We recommend you follow these guidelines when using parameterized macros:
.define MACRO() expansion
.define MYNAME earl .define name(t) "My name is "+t |
Examples
A. | In this example, two simple text replacement operations use the .DEFINE directive. |
.define TTCHN ,1 ;Text replacement does not .define FLAGS ,xcall flags ; include these comment lines. proc FLAGS(4020) ;This statement becomes xcall flags(4020). open(TTCHN, o, "tt:") ;This statement becomes open(1, o, "tt:").
.define TTCHN ,1 . . . .ifndef TTCHN .define TTCHN ,1 ;This statement is not processed .endc
C. | In this example, the compiler generates a “Symbol already defined” warning (SYMDEFD) on the second .DEFINE statement unless |
- you specified the .DEFINE warning compiler option to suppress these warnings.
- you ended the routine with END instead of .END and specified -qrelaxed=end on the command line.
If you ended the routine with END and specified -qrelaxed=end, the identifier ONE is undefined after the main routine is compiled, and no error occurs.
.define ONE ,1 proc . . . .end .define ONE ,1 subroutine sub proc . . . endsubroutine
D. | This example shows how replacement text can span across more than one physical line. See Continuation lines for more about the rules for splitting alpha literals across continuation lines. |
.define SYNERGEX ,"Synergex International & Corporation" ; The replacement text is "Synergex International Corporation".
record synergex ,a8 ,"SYNERGEX" .define TTCHN ,1 .define SYNERGEX ,EMPLOYER .define EMPLOYER ,SYNERGEX proc open(TTCHN, o, "tt:") writes(TTCHN, SYNERGEX + SYNERGEX) end
F. | In this example, the parameterized macro SUBTOTAL is used to output various subtotals following their descriptions. |
.define SUBTOTAL(desc, amount) writes(pchan, "Subtotal for ''desc': "+%string(amount)) SUBTOTAL(Apples, apples_total) SUBTOTAL(Oranges, oranges_total) SUBTOTAL(Mangoes, mangoes_total)
Resulting in the expansion:
writes(pchan, "Subtotal for Apples: "+%string(apples_total)) writes(pchan, "Subtotal for Oranges: "+%string(oranges_total)) writes(pchan, "Subtotal for Mangoes: "+%string(mangoes_total))
Since the names of the total variables are prefixed with their descriptions, the macro can be further simplified:
.define SUBTOTAL(desc) writes(pchan,"Subtotal for ''desc': "+%string(desc'_total)) SUBTOTAL(Apples) SUBTOTAL(Oranges) SUBTOTAL(Mangoes)
which results in the semantically identical expansion:
writes(pchan, "Subtotal for Apples: "+%string(apples_total)) writes(pchan, "Subtotal for Oranges: "+%string(oranges_total)) writes(pchan, "Subtotal for Mangoes: "+%string(mangoes_total))