Language Elements and Reference:xpplrm

Extending the language scope of Xbase++ Foundation

The directives #command / #xcommand and #translate / #xtranslate define translation rules for the preprocessor which determine how it should modify the source code. These directives allow user-defined commands to be created as well as user specific adaptation of the Xbase++ language scope. Each of these four directives consists of two parts: a search rule and a replacement rule. The search rule appears on the left of the symbol => and the replacement rule appears on the right side of it. The search rule specifies the characters or character pattern that the preprocessor is to search for in the source code. The replacement rule defines the characters used to replace the search characters in the resulting source code.

#command     <Search rule>     =>     <Replacement rule> 
#xcommand    <Search rule>     =>     <Replacement rule> 

#translate   <Search rule>     =>     <Replacement rule> 
#xtranslate  <Search rule>     =>     <Replacement rule> 

The characters => are a component of the syntax for these preprocessor directives and must always be specified between the <Search rule> and the <Replacement rule>. These characters are the separators between the two rules and have nothing in common with the >=, <= or -> operators.

Search rules

The first part of a translation rule is the search rule. These are characters or character patterns that the preprocessor searches for in the source code. A search rule is made up of three components: keywords, literals and what are called match markers. The meaning of each of the components can be illustrated in the following example of a #translate directive. It defines a pseudofunction MinMax(), which is translated by the preprocessor to an .AND. expression:

|-------------------- Keyword 
|    |--------------- Match marker 
|    |    |     | 
#translate  MinMax(<x>,<min>,<max>) => (<x> >= <min>.AND.<max> >= <x>) 
   |   |     |     | 
   |----------------- Literal 

A keyword is an identifier which is governed by dBase conventions. Because of this, only the first four characters are significant and case is not significant. However, when the directives #xcommand and #xtranslate are used, all characters of all keywords are significant. This is the only difference between #command / #xcommand and #translate / #xtranslate.

Literals are characters which must appear within the source code exactly as they appear in the search rule. The preprocessor uses keywords to recognize and translate code fragments in the source code.

Match markers can be thought of as symbolic names for parts of a code fragment that are copied into the translated code. They must always appear within angle brackets and are governed by the same rules as variable names. A match marker must begin with a letter or an underscore (_) and otherwise consist of alphanumeric characters.

The effect of the #translate directive MinMax() is demonstrated in the following code:

// Code in the source file (PRG file) 
   IF MinMax( 5, 1, 10 ) 

// Code for the compiler 
   IF (5 >= 1.AND.10 >= 5) 

The search rule of a directive specifies the pattern for a code fragment within the source code which the preprocessor replaces with other characters. Keywords and literals determine the constant characters in the source code that are used when the preprocessor analyzes the source code. Match markers define the parts of a code fragment that are variable in the source code. These are analogous to symbolic names for memory variables that can be assigned a value. The preprocessor assigns parts of a code fragment to a match marker, which it can then identify by the symbolic name and, if appropriate, insert into the translated code.

Replacement rules

The second part of a translation rule is the replacement rule. These are characters or character patterns used to replace matched code fragments in the source code. This means that they determine the code into which the preprocessor translates a program's source code. No characters are changed in the actual source code file (the PRG file), instead the changes are performed in memory. A PPO file (preprocessed output file) can also be created where the results of the preprocessor are written. The PPO file is created when the PRG file is compiled using the compiler switch /P.

A replacement rule, like a search rule, is made up of three components: keywords, literals, and what are called result markers. Keywords (for example, statements and function names) and literals (for example, operators and constants) are written directly into the code as they appear in the replacement rule. Result markers (like match markers) consist of a symbolic name enclosed in angle brackets. The only names that can be used are the names of the match markers used within the corresponding search rule. In other words, result markers correspond to the code identified by the match marker. The preprocessor inserts into the resulting code the code fragment corresponding to the match marker with the same symbol name.

A detailed discussion of search and replacement rules is given in the reference documentation of the #command directive.

The #command directive is used to define translation rules for source code that represents a complete statement or a complete command. This means that the search rule the preprocessor uses in searching the source code must contain a complete statement. However, the #translate statement can be used to translate incomplete commands or statements. This includes pseudofunctions and individual clauses of commands.

Only the first four letters of keywords within the search rule are significant when #command and #translate are used. In other words, the preprocessor tests only the first four letters for a match between the characters in the search rule and the names of commands and functions in the source code. It also does not distinguish between upper and lower case letters. The preprocessor tests all letters of keywords when the directives #xcommand and #xtranslate are used.

The directives #command and #translate or #xcommand and #xtranslate are used to translate source code for the compiler. They are more powerful than the directive #define. #define defines only those symbolic names that are translated to constant values or that lead to conditional compilation. #define distinguishes between upper and lower case. #command and #translate directives within a program file cannot be undefined. In this way they differ from the #define directive, whose effects can be "undefined" by using #undef.

For the preprocessor, #define is the directive with the highest precedence and is translated first. The #translate directive is next in precedence and #command has the lowest precedence.

The preprocessor first reads the entire source code from a file and then processes each line according to the precedence of the directives. Directives of equal precedence are evaluated with the last directive defined being evaluated first. This means that the order of directives within #include files is significant. The directives at the end of an #include file are used before the directives at the beginning of the #include file. The source code is processed until there are no more characters in the translated code that correspond to the search rule of a directive.

The order of directives within an #include file is especially significant when commands are defined that require more than one translation rule. This is always the case when keywords that mutually exclude each other occur within a command or when a command can be coded in a universal form as well as in various specialized forms. In this case, multiple directives must be specified for the same command. In general, the universal form of the command must appear at the beginning of an #include file and the specialized forms of the command must appear later in the #include file. Examples for this rule are found in the STD.CH #include file, where all of the Xbase++ commands are implemented as #command directives.


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.