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

Advanced Examples

Here are some examples of advanced constructions using gpp. They tend to be pretty awkward and should be considered as evidence of gpp's limitations.

The first example is a recursive macro. The main problem is that, since gpp evaluates everything, a recursive macro must be very careful about the way in which recursion is terminated, in order to avoid undefined behavior (most of the time gpp will simply crash). In particular, relying on a #if/#else/#endif construct to end recursion is not possible and results in an infinite loop, because gpp scans user macro calls even in the unevaluated branch of the conditional block. A safe way to proceed is for example as follows (we give the example in TeX mode):

  \define{countdown}{
    \if{#1}
    #1...
    \define{loop}{\countdown}
    \else
    Done.
    \define{loop}{}
    \endif
    \loop{\eval{#1-1}}
  }
  \countdown{10}
The following is an (unfortunately very weak) attempt at implementing functional abstraction in gpp (in standard mode). Understanding this example and why it can't be made much simpler is an exercise left to the curious reader.
  #mode string "`" "`" "\\"
  #define ASIS(x) x
  #define SILENT(x) ASIS()
  #define EVAL(x,f,v) SILENT(
    #mode string QQQ "`" "`" "\\"
    #defeval TEMP0 x
    #defeval TEMP1 (
      \#define \TEMP2(TEMP0) f
    )
    TEMP1
    )TEMP2(v)
  #define LAMBDA(x,f,v) SILENT(
    #ifneq (v) ()
    #define TEMP3(a,b,c) EVAL(a,b,c)
    #else
    #define TEMP3(a,b,c) \LAMBDA(a,b)
    #endif
    )TEMP3(x,f,v)
  #define EVALAMBDA(x,y) SILENT(
    #defeval TEMP4 x
    #defeval TEMP5 y
    ) 
  #define APPLY(f,v) SILENT(
    #defeval TEMP6 ASIS(\EVA)f
    TEMP6
    )EVAL(TEMP4,TEMP5,v)
This yields the following results:
  LAMBDA(z,z+z)
    => LAMBDA(z,z+z)

  LAMBDA(z,z+z,2)
    => 2+2

  #define f LAMBDA(y,y*y)
  f
    => LAMBDA(y,y*y)

  APPLY(f,blah)
    => blah*blah

  APPLY(LAMBDA(t,t t),(t t))
    => (t t) (t t)

  LAMBDA(x,APPLY(f,(x+x)),urf)
    => (urf+urf)*(urf+urf)

  APPLY(APPLY(LAMBDA(x,LAMBDA(y,x*y)),foo),bar)
    => foo*bar

  #define test LAMBDA(y,`#ifeq y urf
  y is urf#else
  y is not urf#endif
  `)
  APPLY(test,urf)
    => urf is urf

  APPLY(test,foo)
    => foo is not urf


Luis Fernando P. de Castro 2003-06-27