Evaluate all macros in a C++ header file

后端 未结 3 1695
陌清茗
陌清茗 2021-01-23 11:36

I have a requirement to build an automated system to parse a C++ .h file with a lot of #define statements in it and do something with the value that each #def

3条回答
  •  栀梦
    栀梦 (楼主)
    2021-01-23 12:12

    An approach could be to write a "program generator" that generates a program (the printDefines program) comprising statements like std::cout << "MAGIC_NUMBER" << " " << (MAGIC_NUMBER_BASE + 0x2) << std::endl;. Obviously, executing such statements will resolve the respective macros and print out their values.

    The list of macros in a header file can be obtained by g++ with an -dM -E' option. Feeding this "program generator" with such a list of #defines will generate a "printDefines.cpp" with all the requiredcout`-statements. Compiling and executing the generated printDefines program then yields the final output. It will resolve all the macros, including those that by itself use other macros.

    See the following shell script and the following program generator code that together implement this approach:

    Script printing the values of #define-statements in "someHeaderfile.h":

    #  printDefines.sh
    g++ -std=c++11 -dM -E someHeaderfile.h > defines.txt
    ./generateDefinesCpp someHeaderfile.h defines.txt > defines.cpp
    g++ -std=c++11 -o defines.o defines.cpp
    ./defines.o
    

    Code of program generator "generateDefinesCpp":

    #include 
    #include 
    #include 
    #include 
    #include 
    
    using std::cout;
    using std::endl;
    
    /*
     * Argument 1: name of the headerfile to scan
     * Argument 2: name of the cpp-file to generate
     * Note: will crash if parameters are not provided.
     */
    int main(int argc, char* argv[])
    {
        cout << "#include" << endl;
        cout << "#include" << endl;
        cout << "#include \"" << argv[1] << "\"" << endl;
        cout << "int main() {" << endl;
        std::ifstream headerFile(argv[2], std::ios::in);
        std::string buffer;
        char macroName[1000];
        int macroValuePos;
        while (getline(headerFile,buffer)) {
            const char *bufferCStr = buffer.c_str();
            if (sscanf(bufferCStr, "#define %s %n", macroName, ¯oValuePos) == 1) {
                const char* macroValue = bufferCStr+macroValuePos;
                if (macroName[0] != '_' && strchr(macroName, '(') == NULL  && *macroValue) {
                    cout << "std::cout << \"" << macroName << "\" << \" \" << (" << macroValue << ") << std::endl;" << std::endl;
                }
            }
        }
        cout << "return 0; }" << endl;
    
        return 0;
    }
    

    The approach could be optimised such that the intermediate files defines.txt and defines.cpp are not necessary; For demonstration purpose, however, they are helpful. When applied to your header file, the content of defines.txt and defines.cpp will be as follows:

    defines.txt:

    #define CONSTANT_1 MAKE_CONSTANT (MAGIC_NUMBER + 564, MORE_MAGIC_1 | MORE_MAGIC_2)
    #define CONSTANT_2 MAKE_CONSTANT (MAGIC_NUMBER - 84, MORE_MAGIC_1 & MORE_MAGIC_2 ^ 0xA)
    #define Constants_h 
    #define MAGIC_NUMBER MAGIC_NUMBER_BASE + 0x2
    #define MAGIC_NUMBER_BASE 40
    #define MAKE_CONSTANT(A,B) (A | (B << 4))
    #define MORE_MAGIC_1 345
    #define MORE_MAGIC_2 65
    #define OBJC_NEW_PROPERTIES 1
    #define SKIP_CONSTANT "What?"
    #define _LP64 1
    #define __APPLE_CC__ 6000
    #define __APPLE__ 1
    #define __ATOMIC_ACQUIRE 2
    #define __ATOMIC_ACQ_REL 4
    ...
    

    defines.cpp:

    #include
    #include
    #include "someHeaderfile.h"
    int main() {
    std::cout << "CONSTANT_1" << " " << (MAKE_CONSTANT (MAGIC_NUMBER + 564, MORE_MAGIC_1 | MORE_MAGIC_2)) << std::endl;
    std::cout << "CONSTANT_2" << " " << (MAKE_CONSTANT (MAGIC_NUMBER - 84, MORE_MAGIC_1 & MORE_MAGIC_2 ^ 0xA)) << std::endl;
    std::cout << "MAGIC_NUMBER" << " " << (MAGIC_NUMBER_BASE + 0x2) << std::endl;
    std::cout << "MAGIC_NUMBER_BASE" << " " << (40) << std::endl;
    std::cout << "MORE_MAGIC_1" << " " << (345) << std::endl;
    std::cout << "MORE_MAGIC_2" << " " << (65) << std::endl;
    std::cout << "OBJC_NEW_PROPERTIES" << " " << (1) << std::endl;
    std::cout << "SKIP_CONSTANT" << " " << ("What?") << std::endl;
    return 0; }
    

    And the output of executing defines.o is then:

    CONSTANT_1 1887
    CONSTANT_2 -9
    MAGIC_NUMBER 42
    MAGIC_NUMBER_BASE 40
    MORE_MAGIC_1 345
    MORE_MAGIC_2 65
    OBJC_NEW_PROPERTIES 1
    SKIP_CONSTANT What?
    

提交回复
热议问题