next up previous contents index
Next: Advanced Examples Up: GPP - Generic Preprocessor Previous: Meta-macros   Contents   Index

Examples

Here is a basic self-explanatory example in standard or cpp mode:

  #define FOO This is
  #define BAR a message.
  #define concat #1 #2
  concat(FOO,BAR)
  #ifeq (concat(foo,bar)) (foo bar)
  This is output.
  #else
  This is not output.
  #endif
Using argument naming, the concat macro could alternately be defined as

  #define concat(x,y) x y
In TeX mode and using argument naming, the same example becomes:

  \define{FOO}{This is}
  \define{BAR}{a message.}
  \define{\concat{x}{y}}{\x \y}
  \concat{\FOO}{\BAR}
  \ifeq{\concat{foo}{bar}}{foo bar}
  This is output.
  \else
  This is not output.
  \endif
In HTML mode and without argument naming, one gets similarly:

  <#define FOO|This is>
  <#define BAR|a message.>
  <#define concat|#1 #2>
  <#concat <#FOO>|<#BAR>>
  <#ifeq <#concat foo|bar>|foo bar>
  This is output.
  <#else>
  This is not output.
  <#endif>
The following example (in standard mode) illustrates the use of the quote character:

  #define FOO This is \
     a multiline definition.
  #define BLAH(x) My argument is x
  BLAH(urf)
  \BLAH(urf)
Note that the multiline definition is also valid in cpp and Prolog modes despite the absence of quote character, because '$\backslash$' followed by a newline is then interpreted as a comment and discarded.

In cpp mode, C strings and comments are understood as such, as illustrated by the following example:


  #define BLAH foo
  BLAH "BLAH" /* BLAH */
  'It\'s a /*string*/ !'
The main difference between Prolog mode and cpp mode is the handling of strings and comments: in Prolog, a '...' string may not begin immediately after a digit, and a /*...*/ comment may not begin immediately after an operator character. Furthermore, comments are not removed from the output unless they occur in a #command.

The differences between cpp mode and default mode are deeper: in default mode #commands may start anywhere, while in cpp mode they must be at the beginning of a line; the default mode has no knowledge of comments and strings, but has a quote character ('$\backslash$'), while cpp mode has extensive comment/string specifications but no quote character. Moreover, the arguments to meta-macros need to be correctly parenthesized in default mode, while no such checking is performed in cpp mode.

This makes it easier to nest meta-macro calls in default mode than in cpp mode. For example, consider the following HTML mode input, which tests for the availability of the #exec command:


  <#ifeq <#exec echo blah>|blah
  > #exec allowed <#else> #exec not allowed <#endif>
There is no cpp mode equivalent, while in default mode it can be easily translated as

  #ifeq (#exec echo blah
  ) (blah
  )
  \#exec allowed
  #else
  \#exec not allowed
  #endif
In order to nest meta-macro calls in cpp mode it is necessary to modify the mode description, either by changing the meta-macro call syntax, or more elegantly by defining a silent string and using the fact that the context at the beginning of an evaluated string is a newline character:

  #mode string QQQ "$" "$"
  #ifeq $#exec echo blah
  $ $blah
  $
  \#exec allowed
  #else
  \#exec not allowed
  #endif
Note however that comments/strings cannot be nested ("..." inside $...$ would go undetected), so one needs to be careful about what to include inside such a silent evaluated string.

Remember that macros without arguments are actually understood to be aliases when they are called with arguments, as illustrated by the following example (default or cpp mode):


  #define DUP(x) x x
  #define FOO and I said: DUP
  FOO(blah)
The usefulness of the #defeval meta-macro is shown by the following example in HTML mode:

  <#define APPLY|<#defeval TEMP|<\##1 \#1>><#TEMP #2>>
  <#define <#foo x>|<#x> and <#x>>
  <#APPLY foo|BLAH>
The reason why #defeval is needed is that, since everything is evaluated in a single pass, the input that will result in the desired macro call needs to be generated by a first evaluation of the arguments passed to APPLY before being evaluated a second time.

To translate this example in default mode, one needs to resort to parenthesizing in order to nest the #defeval call inside the definition of APPLY, but need to do so without outputting the parentheses. The easiest solution is


  #define BALANCE(x) x
  #define APPLY(f,v) BALANCE(#defeval TEMP f
  TEMP(v))
  #define foo(x) x and x
  APPLY(\foo,BLAH)
As explained above the simplest version in cpp mode relies on defining a silent evaluated string to play the role of the BALANCE macro.

The following example (default or cpp mode) demonstrates arithmetic evaluation:


  #define x 4
  The answer is:
  #eval x*x + 2*(16-x) + 1998%x

  #if defined(x)&&!(3*x+5>17)
  This should be output.
  #endif
To finish, here are some examples involving mode switching. The following example is self-explanatory (starting in default mode):

  #mode push
  #define f(x) x x
  #mode standard TeX
  \f{blah}
  \mode{string}{"$" "$"}
  \mode{comment}{"/*" "*/"}
  $\f{urf}$ /* blah */
  \define{FOO}{bar/* and some more */}
  \mode{pop}
  f($FOO$)
A good example where a user-defined mode becomes useful is the gpp source of this document (available with gpp's source code distribution).

Another interesting application is selectively forcing evaluation of macros in C strings when in cpp mode. For example, consider the following input:


  #define blah(x) "and he said: x"
  blah(foo)
Obviously one would want the parameter x to be expanded inside the string. There are several ways around this problem:

  #mode push
  #mode nostring "\""
  #define blah(x) "and he said: x"
  #mode pop

  #mode quote "`"
  #define blah(x) `"and he said: x`"

  #mode string QQQ "$$" "$$"
  #define blah(x) $$"and he said: x"$$
The first method is very natural, but has the inconvenient of being lengthy and neutralizing string semantics, so that having an unevaluated instance of 'x' in the string, or an occurrence of '/*', would be impossible without resorting to further contorsions.

The second method is slightly more efficient, because the local presence of a quote character makes it easier to control what is evaluated and what isn't, but has the drawback that it is sometimes impossible to find a reasonable quote character without having to either significantly alter the source file or enclose it inside a #mode push/pop construct. For example any occurrence of '/*' in the string would have to be quoted.

The last method demonstrates the efficiency of evaluated strings in the context of selective evaluation: since comments/strings cannot be nested, any occurrence of '"' or '/*' inside the '$$' gets output as plain text, as expected inside a string, and only macro evaluation is enabled. Also note that there is much more freedom in the choice of a string delimiter than in the choice of a quote character.


next up previous contents index
Next: Advanced Examples Up: GPP - Generic Preprocessor Previous: Meta-macros   Contents   Index
Baoqiu Cui
2000-04-23