CPP (antaŭtraktilo)

CPP, mallongigo de la angla the C PreProcessor, t.e. Antaŭtraktilo por C estas komputila programo kiu plenumas la antaŭtraktadon de tradukotaj programoj prezentitaj en C aŭ en C++. Ĝi estas enkonstruita en la tradukilojn de tiuj programlingvoj, sed estas antaŭ disponebla kiel aparta utilaĵo cpp.

Plimulto da esprimiloj de CPP havas la formon de direktivoj (escepto estas la makrokomandoj). Ĉiu direktivo okupas apartan linion en la fonta teksto, kaj estas markita per antaŭmetita kradsigno #.

En sia rolo de antaŭtraktilo CPP realigas la sekvajn taskojn:

  • ĝi importas ĉapdosierojn per la direktivo #include
  • ĝi plenumas la makrotraktadon;
  • ĝi forigas nedeziratajn partojn de la fonta programo ĉe kondiĉa traduko.

Inkludo redakti

La inkludo-direktivo estas la plej ofte uzata en la C-programoj; en ĉi-suba programo la direktivo #include <stdio.h> anstataŭiĝos per la enhavo de la dosiero stdio.h:

#include <stdio.h>
int main(void)
{
    printf("Saluton, mondo!\n");
    return 0;
}

La kondiĉa traduko redakti

Ĝin regas la direktivoj #if, #ifdef, #ifndef, #else, #elif and #endif. Ekz-e oni povas ordoni al la tradukilo programi erarserĉan printadon nur tiam, kiam oni kreas tre babileman version:

#if BABILEMO >= 2
  print("Hello world!");
#endif

Makrooj redakti

La direktivo #define servas por enkonduki makrodifinojn. Tiuj povas esti tre simplaj mallongigoj, ekz-e

#define pi 3.1415926536

aŭ parametrohava teksto, ekz-e

#define MAX(a,b) (a)>(b)?(a):(b)

Kun ĉi tiuj difinoj CPP transformos la fontotekstan ordonon

x = MAX(x, z + pi/2);

ĉi tiel:

x = (x)>(z + 3.1415926536/2)?(x):(z + 3.1415926536/2);

   Esperantigo de la ŝlosilvortoj de C redakti

Ĉi-suba ekzemplo, pruntita el la Komputada Leksikono, demonstras uzon de CPP por esperantigi la ŝlosilvortojn de C. Interalie, ĝi ankaŭ klarigas la signifon de la anglaj ŝlosilvortoj.

Estu jena ĉapdosieo eoc.h:

#define AUXTO auto
#define ELIRU break
#define OKAZO case
#define SIGNA char
#define SIGNAJ char
#define KOMPLEKSA complex
#define KOMPLEKSAJ complex
#define KONST const
#define PLU continue
#define CETERE default
#define FARU do
#define DUOBLA double
#define DUOBLAJ double
#define ALIE else
#define ENUM enum
#define EKSTERA extern
#define EKSTERAJ extern
#define REELA float
#define REELAJ float
#define POR for
#define AL goto
#define SE if
#define IMAGINARA imaginary
#define MALFERMITA inline
#define ENTJERA int
#define ENTJERAJ int
#define LONGA long
#define LONGAJ long
#define REGXISTRO register
#define REGXISTROJ register
#define EKSKLUZIVA restrict
#define EKSKLUZIVAJ restrict
#define REEN return
#define KURTA short
#define KURTAJ short
#define SIGNUMA signed
#define SIGNUMAJ signed
#define DABAJTOJ sizeof
#define STATIKA static
#define STATIKAJ static
#define RIKORDO struct
#define STRUKTURO struct
#define ELEKTU switch
#define TIPDIFINO typedef
#define UNIO union
#define NATURA unsigned
#define NATURAJ unsigned
#define VAKA void
#define VARIEMA volatile
#define VARIEMAJ volatile
#define DUM while

La programoj uzantaj ĉi tiun dosieron devas ĝin importi, ekz-e kiel en la sekva deklaro de funkcio cxen_al_ent, konvertanta signoĉenojn kiuj prezentas nombrojn (ekz-e "+127") en enjerojn (samkiel la konata C-funkcio atoi):

#include "eoc.h"
ENTJERA cxen_al_ent(SIGNA *cx)
{
    ENTJERAJ i, n, minuso = 0;    /* lokaj variabloj */
    POR(i = 0; cx[i] == ' ' || cx[i] == '\n' || cx[i] == '\t'; i++) ;
     ELEKTU(cx[i]) {
        OKAZO '-': minuso = 1;
        OKAZO '+': i++;
     }
     POR(n = 0; cx[i] >= '0' && cx[i] <= '9';)
        n = 10 * n + cx[i++] - '0';
     REEN minuso ? -n : n ;
}

Metinte ĉi tiun programon en dosieron al_ent.c, oni povas rekte ĝin traduki per gcc (kaj ricevi celkodan dosieron al_ent.o), aŭ aparte trakti per cpp, kaj ricevi programon en la norma C:

$ gcc -c al_ent.c && ls -s *.o
4 al_ent.o
$
$ cpp -P al_ent.c
int cxen_al_ent(char *cx)
{
    int i, n, minuso = 0;
    for(i = 0; cx[i] == ' ' || cx[i] == '\n' || cx[i] == '\t'; i++) ;
    switch(cx[i]) {
        case '-': minuso = 1;
        case '+': i++;
    }
    for(n = 0; cx[i] >= '0' && cx[i] <= '9';)
        n = 10 * n + cx[i++] - '0';
    return minuso ? -n : n ;
}
$