Search code examples
c++c-preprocessorpreprocessor

Preprocessor flags suitable for not tokenizing but still do concatenation


I have inherited some PCL (Patran Command Language) code that is preprocessed with a C preprocessor to enable use of macros etc. This code has a number of features that do not work for modern preprocessors such as cpp. Currently I'm using gcc -E or cpp with version 11.3.0.

For example, one issue is caused by `//' being the concatenate operator in PCL, but being recognised as a comment by cpp:

$ A.pcc

#define FUNC(X) ui_write(X)
string variable
FUNC("text "//variable//" more text")

The required result is

string variable
ui_write("text "//variable//" more text")

I can preprocess this successfully with the command

cpp -traditional A.pcc

where -traditional says to use old style cpp which doesn't tokenize, so the comment symbol is not an issue. If not using this flag, the preprocessor fails to match the argument X within FUNC(X) and errors as it ends the token search at the comment.

In the same file (and many others) token concatenation / token pasting is also being used:

$ B.pcc

#define CAT(I,J) command ## I ## J ## s()

CAT(1,2)

The required result is

command12s()

However by using the -traditional flag, token concatenation is turned off, so the result is

command ## 1 ## 2 ## s()

Which isn't valid PCL.

Any suggestions for appropriate flags? These two issues occur in the same files so I am unable to compile different files with different flags. My current best idea is to use sed to replace the comments with other characters, preprocess, then put them back in.

Edit: I've found a cpp only solution via this answer (multipass a source code to cpp), so the line for me would be

cpp -traditional file.pcc | cpp -C

where the -C flag says to keep comments. I'll have to add a macro to each file so the token concatenation doesn't occur in the first pass

#define DEF_CAT #define CAT(I,J) command ## I ## J ## ()
DEF_CAT

Solution

  • Preprocess the // to something cpp ignores, and then preprocess it back. The following /tmp/mycpp:

    #!/bin/bash
    uuid=06ae45e2-dd08-40db-abeb-1089e89e638f
    sed "s@//@$uuid@g" "$@" | cpp -P -xc - | sed "s@$uuid@//@g"
    

    The following shell transcript presents execution:

    $ in='
    #define FUNC(X) ui_write(X)
    string variable
    FUNC("text "//variable//" more text")
    
    #define CAT(I,J) command ## I ## J()
    CAT(1,2)
    '
    $ /tmp/mycpp <<<"$in"
    string variable                                                                                                                 
    ui_write("text "//variable//" more text")
    command12()