Pre-processor Terms

Abbreviation :

A source token whose leftmost characters exactly match the leftmost characters of a keyword in a translation directive. Abbreviations must be at least four characters in length.

Blockify :

To change an expression in the source text into a code block definition. Blockifying is accomplished by surrounding the source text with braces and placing an empty block parameter list (a pair of vertical bars) just inside the braces. When the resulting code block is evaluated at runtime, the original expression will be evaluated.

Blockify Result Marker :

A result marker of the form <{id}>. id must correspond to the name of a match marker. A blockify result marker specifies that the corresponding source text is to be blockified. If the matched source text is a list of expressions, each expression in the list is individually blockified. If no source text matched the corresponding match marker, an empty result is produced.

Conditional Compilation :

Selective exclusion by the preprocessor of certain source code. The affected source code is bracketed by the #ifdef and #endif directives. It is excluded if the argument in the #ifdef directive is not a #defined identifier.

Define :

To #define an identifier to the preprocessor and optionally specify text to be substituted for occurrences of the identifier.

Directive :

An instruction to the preprocessor. Preprocessor directives must appear on a separate line, and must begin with a hash mark (#). Their scope or effect extends from the point where they are encountered to the end of the source file in which they appear.

Dumb Stringify Result Marker :

A result marker of the form #<{id}>. id must correspond to the name of a match marker. A dumb stringify result marker specifies that the corresponding source text is to be enclosed in quotes. If the matched source text constitutes a list of expressions, each expression in the list is individually stringified. If no source text was matched, an empty pair of quotes is produced.

Empty Result :

An absence of result text; the effect of certain result markers when the corresponding match marker did not match any source text (but when the translation directive as a whole was matched). An empty result simply implies that no result text is written to output.

Header File :

A source file containing manifest constant definitions; command or pseudofunctions; and/or program statements merged into another source file using the #include preprocessor directive.

Identifier :

A name that identifies a function, procedure, variable, constant or other named entity in a source program. In Clipper language, identifiers must begin with an alphabetic character and may contain alphabetic characters, numeric characters, and the underscore character.

Include File :

A source file included another source file via #include directive. Though it is a header file by convention, pratically may be any source file.

See : Header File, source file

List Match Marker :

A match marker indicating a position that will successfully match a list of one or more arbitrarily complex expressions. A list match marker marks a part of a command that is expected to consist of a list of programmer-supplied expressions. A list match marker has the form <id,…>. id associates a name with the match marker. The name can be used in a result marker to specify how the matching source text is to be handled.

Logify :

To change an expression in the source text into a logical value. Logifying is accomplished by surrounding the expression with periods.

Logify Result Marker :

A result marker of the form #<.id.>. id must correspond to the name of a match marker. This result marker writes true (.T.) to the result text if any input text is matched; otherwise, it writes false (.F.) to the result text. The input text itself is not written to the result text.

Manifest Constant :

An identifier specified in a #define directive. The preprocessor substitutes the specified result text whenever it encounters the identifier in the source text.

Match :

A successful comparison of source text with a match pattern (or part of a match pattern).

Match Marker :

A construct used in a match pattern to indicate a position that will successfully match a particular type of source text. There are several types of match markers, each of which will successfully match a particular type of source text.

Match Pattern :

The part of a translation directive that specifies the format of source text to be affected by the directive. A match pattern generally consists of words and match markers.

Normal Stringify Result Marker :

A result marker of the form <“id”>. id must correspond to the name of a match marker. A normal stringify result marker specifies that the corresponding source text is to be enclosed in quotes. If the matched source text is a list, each element of the list is individually stringified. If no source text was matched, an empty result is produced.

Optional Clause :

A portion of a match pattern that is enclosed in square ([ ]) brackets. An optional clause specifies part of a match pattern that need not be present for source text to match the pattern. An optional clause may contain any of the components legal within a match pattern, including other optional clauses. When a match pattern contains a series of optional clauses that are immediately adjacent to each other, the matching portions of the source text are not required to appear in the same order as the clauses in the match pattern. If an optional clause is matched by more than one part of the source text, the multiple matches may be handled using a repeating clause in the result pattern.

Preprocessor :

A translation program that prepares source code for compilation by applying selective text replacements. The replacements to be made are specified by directives in the source file. In Clipper language, the preprocessor operates transparently as a part of the compiler program.

See Also : Compiler

Pseudofunction :

A function-like construct that is replaced with another expression via the #define directive, rather than compiled into a conventional function call. Pseudofunctions may contain parenthesized arguments that may be included in the substituted text.

Regular Match Marker :

A match marker indicating a position that will successfully match an arbitrarily complex expression in the source text. A regular match marker generally marks a part of a command that is expected to consist of arbitrary programmer-supplied text, as opposed to a keyword or other restrictive component. In order for the source text to match, it must constitute a properly formed expression. A regular match marker has the form <id>. id associates a name with the match marker. The name can be used in a result marker to specify how the matching source text is to be handled.

Regular Result Marker :

A result marker of the form <id>. id must correspond to the name of a match marker. This result marker writes the matched input text to the result text, or nothing if no input text is matched.

Repeating Clause :

A portion of a result pattern surrounded by square ([ ]) brackets. The text specified by the repeating clause is written to output once for each successfully matched match marker in the corresponding match pattern.

Restricted Match Marker :

A match marker indicating a position that will successfully match one or more specified keywords. A restricted match marker marks a part of a command that is expected to be a keyword. A restricted match marker has the form <id: wordList> where wordList is a list of one or more keywords. Source text is successfully matched only if it matches one of the keywords (or is an acceptable abbreviation). id associates a name with the match marker. The name can be used in a result marker to specify how the matching source text is to be handled.

Result Text :

The text that results from formatting matched source text using a result pattern. If the result text matches a match pattern in another preprocessor directive, then it becomes the source text for that directive. Otherwise, the result text is passed as input to the compiler.

Result Pattern :

The part of a translation directive that specifies the text to be substituted for source text that matches the match pattern. A result pattern generally consists of operators and result markers.

Smart Stringify Result Marker :

A result marker of the form <(id)>. id must correspond to the name of a match marker. A smart stringify result marker specifies that the corresponding source text is to be enclosed in quotes unless the source text was enclosed in parentheses. If the matched source text is a list, each element of the list is individually processed. If no source text was matched, an empty result is produced. The smart stringify result marker is used to implement commands that allow extended expressions (a part of a command that may be either an unquoted literal or a character expression).

Source Text :

Text from a source file, processed by the preprocessor. Source text is examined to see if it matches a previously specified match pattern. If so, the corresponding result pattern is substituted for the matching source text

STD.CH :

The standard header file containing definitions for all Clipper language commands.

Stringify :

To change source text into a literal character string by surrounding the text with quotes.

Text Replacement :

The process of removing portions of input text and substituting different text in its place.

Token :

An elemental sequence of characters having a collective meaning. The preprocessor groups characters into tokens as it reads the input text stream. Tokens include identifiers, keywords, constants, and operators. White space, and certain special characters, serve to mark the end of a token to the preprocessor.

Translation Directive :

A preprocessor instruction containing a translation rule. The two translation directives are #command and #translate.

Translation Rule :

The portion of a translation directive containing a match pattern followed by the special symbol (=>) followed by a result pattern.

Undefine :

To remove an identifier from the preprocessor’s list of defined identifiers via the #undefine directive.

Wild Match Marker :

A match marker indicating a position that will successfully match any source text. A wild match marker matches all source text from the current position to the end of the source line. A wild match marker has the form <*id*>. id associates a name with the match marker. The name can be used in a result marker to specify how the matching source text is to be handled.

Procedure and Function Terms

Activation :

The commencement of execution of a procedure. Each call to a procedure is referred to as an activation of that procedure. If the procedure in turn calls another procedure (or calls itself recursively), a new activation is said to have occurred. The earlier activation is then referred to as a pending activation.

Pending activations are often referred to as higher-level activations or higher-level procedures. When one procedure calls another (i.e., creates a new activation), the latter is often referred to as a lower-level activation or a lower-level procedure.

See Also : Activation Record, Activation Stack, Function, Procedure

Activation Record :

An internal data structure that contains information pertaining to an activation.

See Also : Activation, Activation Stack

Activation Stack :

An internal data structure that contains an activation record for the current activation and all pending activations.

See Also : Activation, Activation Record, Stack

Calling Program :

The procedure, or user-defined function that transferred control to the currently executing procedure or function. When the current procedure or user-defined function terminates with a RETURN statement, this is where control will return.

Function :

An executable block of code with an assigned name. Alternately, the collection of source code statements that define a function. Certain functions are supplied as part of Clipper; others are defined by the programmer using the FUNCTION or PROCEDURE declaration statements. The latter are referred to as user-defined functions.

The terms procedure and function are generally interchangeable. By convention, a function returns a value, while a procedure does not.

See Also: Activation, Parameter, Procedure

Identifier :

A name that identifies a function, procedure, variable, constant or other named entity in a source program. In Clipper language, identifiers must begin with an alphabetic character and may contain alphabetic characters, numeric characters, and the underscore character.

Information Hiding :

A fundamental programming principle that states that functions and programs should conceal their inner workings from other functions and programs. Stated simply: a function should possess only the knowledge necessary for it to accomplish its task. When one function calls another, the calling function should possess only the knowledge explicitly required to call the other function.

See Also: Encapsulation, Lexical Scoping, Modularity, Side Effect

Primitive :

A simple, low-level function used by other high-level functions or programs to perform a more complex task.

Procedure :

An executable block of code with an assigned name. Alternately, the collection of source code statements that define a procedure. In Clipper language, this can be a source file (.prg), a format file (.fmt), an explicitly declared procedure (PROCEDURE), or an explicitly declared function (FUNCTION).

The terms procedure and function are generally interchangeable. By convention, a function returns a value, while a procedure does not.

See Also: Activation, Function, Parameter

Return Value :

The value or reference returned by a function or method from a function call or message send.

Source Code :

The textual representation of a program or procedure.

See Also: Object File, Program File

User-defined Function :

See : Function

Word :

A series of characters in a match pattern or result pattern. Source text matches a word in a match pattern if the text is identical to the word or is an acceptable abbreviation of it. A word that appears in a result pattern is copied unmodified into the result text.

#define and #undef

What are #define and #undef directives ?

#define : Define a manifest constant or pseudofunction.

Syntax :

#define <idConstant> [<resultText>]
#define <idFunction>([<arg list>]) [<exp>]

Arguments :

<idConstant> is the name of an identifier to define.

<resultText> is the optional replacement text to substitute whenever a valid <idConstant> is encountered.

<idFunction> is a pseudofunction definition with an optional argument list (<arg list>). If you include <arg list>, it is delimited by parentheses (()) immediately following <idFunction>. <exp> is the replacement expression to substitute when the pseudofunction is encountered. Enclose this expression in parentheses to guarantee precedence of evaluation when the pseudofunction is expanded.

Note: #define identifiers are case-sensitive, where #command and #translate identifiers are not.

Description :

The #define directive defines an identifier and, optionally, associates a text replacement string. If specified, replacement text operates much like the search and replace operation of a text editor. As each source line from a program file is processed by the preprocessor, the line is scanned for identifiers. If a currently defined identifier is encountered, the replacement text is substituted in its place.

Identifiers specified with #define follow most of the identifier naming rules. Defined identifiers can contain any combination of alphabetic and numeric characters, including underscores. Defined identifiers, however, differ from other identifiers by being case- sensitive. As a convention, defined identifiers are specified in uppercase to distinguish them from other identifiers used within a program. Additionally, identifiers are specified with a one or two letter prefix to group similar identifiers together and guarantee uniqueness. Refer to one of the supplied header files.

When specified, each definition must occur on a line by itself. Unlike statements, more than one directive cannot be specified on the same source line. You may continue a definition on a subsequent line by employing a semicolon (;). Each #define directive is specified followed by one or more white space characters (spaces or tabs), a unique identifier, and optional replacement text. Definitions can be nested, allowing one identifier to define another.

A defined identifier has lexical scope like a filewide static variable. It is only valid in the program (.prg) file in which it is defined unless defined in Std.ch or the header file specified on the compiler command line with the /U option. Unlike a filewide static variable, a defined identifier is visible from the point where it is defined in the program file until it is either undefined, redefined, or the end of the program file is reached.

You can redefine or undefine existing identifiers. To redefine an identifier, specify a new #define directive with the identifier and the new replacement text as its arguments. The current definition is then overwritten with the new definition, and a compiler warning is issued in case the redefinition is inadvertent. To undefine an identifier, specify an #undef directive with the identifier as its argument.

#define directives have three basic purposes:

. To define a control identifier for #ifdef and #ifndef

. To define a manifest constant : an identifier defined to represent a constant value

. To define a compiler pseudofunction

The following discussion expands these three purposes of the #define directive in your program.

Preprocessor Identifiers :

The most basic #define directive defines an identifier with no replacement text. You can use this type of identifier when you need to test for the existence of an identifier with either the #ifdef or #ifndef directives. This is useful to either exclude or include code for conditional compilation. This type of identifier can also be defined using the /D compiler option from the compiler command line. See the examples below.

Manifest Constants :

The second form of the #define directive assigns a name to a constant value. This form of identifier is referred to as a manifest constant. For example, you can define a manifest constant for the INKEY() code associated with a key press:

#define K_ESC 27
IF LASTKEY() = K_ESC
 .
 . <statements>
 .
ENDIF

Whenever the preprocessor encounters a manifest constant while scanning a source line, it replaces it with the specified replacement text.

Although you can accomplish this by defining a variable, there are several advantages to using a manifest constant: the compiler generates faster and more compact code for constants than for variables; and variables have memory overhead where manifest constants have no runtime overhead, thus saving memory and increasing execution speed. Furthermore, using a variable to represent a constant value is conceptually inconsistent. A variable by nature changes and a constant does not.

Use a manifest constant instead of a constant for several reasons. First, it increases readability. In the example above, the manifest constant indicates more clearly the key being represented than does the INKEY() code itself. Second, manifest constants localize the definition of constant values, thereby making changes easier to make, and increasing reliability. Third, and a side effect of the second reason, is that manifest constants isolate implementation or environment specifics when they are represented by constant values.

To further isolate the effects of change, manifest constants and other identifiers can be grouped together into header files allowing you to share identifiers between program (.prg) files, applications, and groups of programmers. Using this methodology, definitions can be standardized for use throughout a development organization. Merge header files into the current program file by using the #include directive.

For examples of header files, refer to the supplied header files.

Compiler Pseudo-functions :

In addition to defining constants as values, the #define directive can also define pseudofunctions that are resolved at compile time. A pseudofunction definition is an identifier immediately followed by an argument list, delimited by parentheses, and the replacement expression.

For example:

#define AREA(nLength, nWidth) (nLength * nWidth)
#define SETVAR(x, y) (x := y)
#define MAX(x, y) (IF(x > y, x, y))

Pseudofunctions differ from manifest constants by supporting arguments. Whenever the preprocessor scans a source line and encounters a function call that matches the pseudofunction definition, it substitutes the function call with the replacement expression. The arguments of the function call are transported into the replacement expression by the names specified in the argument list of the identifier definition. When the replacement expression is substituted for the pseudofunction, names in the replacement expression are replaced with argument text. For example, the following invocations,

? AREA(10, 12)
SETVAR(nValue, 10)
? MAX(10, 9)

are replaced by :

? (10 * 12)
nValue := 10
? (IF(10 > 9, 10, 9)

It is important when defining pseudofunctions, that you enclose the result expression in parentheses to enforce the proper order of evaluation. This is particularly important for numeric expressions. In pseudofunctions, you must specify all arguments. If the arguments are not specified, the function call is not expanded as a pseudofunction and exits the preprocessor to the compiler as encountered.

Pseudofunctions do not entail the overhead of a function call and are, therefore, generally faster. They also use less memory. Pseudofunctions, however, are more difficult to debug within the debugger, have a scope different from declared functions and procedures, do not allow skipped arguments, and are case-sensitive.

You can avoid some of these deficiencies by defining a pseudofunction using the #translate directive. #translate pseudofunctions are not case- sensitive, allow optional arguments, and obey the dBASE four-letter rule. See the #translate directive reference in this chapter for more information.

Examples :

. In this example a manifest constant conditionally controls the compilation of debugging code:

 #define DEBUG
 .
 . <statements>
 .
 #ifdef DEBUG
     Assert(FILE("System.dbf"))
 #endif

. This example defines a manifest constant and substitutes it for an INKEY() value:

 #define K_ESC 27
 .
 . <statements>
 .
 IF INKEY() != K_ESC
    DoIt()
 ELSE
    StopIt()
 ENDIF

. This example defines pseudofunctions for the standard functions, MAX() and ALLTRIM():

 #define MAX(arg1, arg2) (IF(arg1 > arg2, arg1, arg2))
 #define ALLTRIM(cString) (RTRIM(LTRIM(cString)))
 .
 . <statements>
 .
 ? MAX(1, 2)
 ? ALLTRIM(" Hello ")
 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#undef : Remove a #define macro definition

Syntax :

#undef <identifier>

Arguments :

<identifier> is the name of the manifest constant or pseudofunction to remove.

Description :

#undef removes an identifier defined with the #define directive. After an #undef, the specified identifier becomes undefined. Use #undef to remove an identifier before you redefine it with #define, preventing the compiler warning that occurs when an existing identifier is redefined. Also, use #undef to make conditional compilation specific to certain sections of a program.

Examples :

. To define and then undefine a manifest constant and a pseudofunction:

 #define K_ESC 27
 #define MAX(x, y) IF(x > y, x, y)
 .
 . <statements>
 .
 #undef K_ESC
 #undef MAX

. To use #undef to undefine an identifier before redefining it:

 #define DEBUG
 .
 . <statements>
 .
 #undef DEBUG
 #define DEBUG .T.

. To undefine an identifier if it exists, and otherwise define it for later portions of the program file:

 #ifdef TEST
    #undef TEST
 #else
    #define TEST
 #endif

			

Conditional compilation

What are conditional compilation directives ?

They are : #ifdef#ifndef#else and #endif.

#ifdef

Compile a section of code if an identifier is defined.

Syntax :

  #ifdef <identifier>
    <statements>...
  [#else]
    <statements>...
  #endif

Arguments :

<identifier> is the name of a definition whose existence is being verified.

Description :

#ifdef…#endif lets you perform a conditional compilation. It does this by identifying a section of source code to be compiled if the specified <identifier> is defined. The <identifier> can be defined using either the #define directive or the /D compiler option which lets you define an identifier or manifest constant from the compiler command line.

The #else directive specifies the code to compile if <identifier> is undefined. The #endif terminates the conditional compilation block.

Conditional compilation is particularly useful when maintaining many different versions of the same program. For example, the demo code and full system code could be included in the same program file and controlled by a single #define statement.

Examples :

. This code fragment is a general skeleton for conditional compilation with #ifdef:

   #define DEMO
    .
    . <statements>
    .
  #ifdef DEMO
   <demo specific statements>
  #endif

. This example controls conditional compilation with an identifier defined on the compiler command line with the /D option.

In the program (.prg) file:

 #ifdef DEBUG
    Assert(<some condition>)
 #endif

. This example defines a manifest constant to one value if it does not exist and redefines it to another if it exists:

 #ifdef M_MARGIN
    #undef M_MARGIN
    #define M_MARGIN 15
 #else
    #define M_MARGIN 10
 #endif

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#ifndef

Compile a section of code if an identifier is undefined

Syntax :

  #ifndef <identifier>
    <statements>...
  [#else]
    <statements>...
  #endif

Arguments :

<identifier> is the name of a definition whose absence is being verified.

Description :

#ifndef…#endif lets you perform conditional compilation by identifying a section of source code to compile if the specified <identifier> is undefined.

The #else directive specifies the code to compile if <identifier> is defined. The #endif terminates the conditional compilation block.

Examples :

. This code fragment is a general skeleton for conditional compilation with #ifndef:

 #define DEBUG
   .
   . <statements>
   .
 #ifndef DEBUG
   <optimized version of code>
 #else
   <debugging version of code>
 #endif

. This example compiles a section of code if a specific identifier is undefined.

In the program (.prg) file:

  #ifndef NODEBUG
     Assert(<some condition>)
  #endif

. This example overrides a default definition in the program (.prg) file using a manifest constant defined on the compiler command line with the /D option

In the program (.prg) file:

 #ifndef M_MARGIN
   #define M_MARGIN 15
 #endif