C++ 计算C+中的所有宏+;头文件

C++ 计算C+中的所有宏+;头文件,c++,macros,c-preprocessor,constants,compile-time-constant,C++,Macros,C Preprocessor,Constants,Compile Time Constant,我有一个要求,建立一个自动化系统来分析一个C++ .h文件,其中有很多 >定义< /Cord>语句,并用每个定义< 的值来完成。除了#define语句外,.h文件中还有许多其他垃圾 目标是创建一个键值列表,其中键值是由#define语句定义的所有关键字,值是对与定义相对应的宏的求值。#defines使用一系列嵌套宏定义关键字,这些宏最终解析为编译时整数常量。有些无法解析为编译时整数常量,必须跳过这些 h文件将随着时间的推移而演变,因此该工具不能是一个长的硬编码程序,它实例化一个等于每个关键字的变

我有一个要求,建立一个自动化系统来分析一个C++ .h文件,其中有很多<代码> >定义< /Cord>语句,并用每个<代码>定义< <代码>的值来完成。除了
#define
语句外,.h文件中还有许多其他垃圾

目标是创建一个键值列表,其中键值是由
#define
语句定义的所有关键字,值是对与定义相对应的宏的求值。
#defines
使用一系列嵌套宏定义关键字,这些宏最终解析为编译时整数常量。有些无法解析为编译时整数常量,必须跳过这些

h文件将随着时间的推移而演变,因此该工具不能是一个长的硬编码程序,它实例化一个等于每个关键字的变量。我无法控制.h文件的内容。唯一的保证是它可以用标准的C++编译器构建,并且更多的代码< >代码>将被添加但不会被删除。宏公式可能随时更改

我看到的解决方案有:

实现部分(或钩住现有的)C++编译器,并在预处理器步骤中拦截宏的值。
  • 使用正则表达式动态构建一个源文件,该文件将使用当前定义的所有宏,然后编译并执行源文件以获得所有宏的计算形式。不知何故(?)跳过不计算编译时整数常量的宏。(另外,不确定正则表达式是否具有足够的表达能力来捕获所有可能的多行宏定义)
  • 这两种方法都会给这个项目的构建过程增加大量的复杂性和脆弱性,我希望避免这种情况。是否有更好的方法来评估C++中的所有代码< >代码>宏? 下面是我希望解析的示例:

    #ifndef Constants_h
    #define Constants_h
    
    namespace Foo
    {
    #define MAKE_CONSTANT(A, B) (A | (B << 4))
    #define MAGIC_NUMBER_BASE 40
    #define MAGIC_NUMBER MAGIC_NUMBER_BASE + 0x2
    #define MORE_MAGIC_1 345
    #define MORE_MAGIC_2 65
    
    
        // Other stuff...
    
    
    #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)
        // etc...
    
    #define SKIP_CONSTANT "What?"
    
        // More CONSTANT_N mixed with more other stuff and constants which do
        // not resolve to compile-time integers and must be skipped
    
    
    }
    
    #endif Constants_h
    

    这个输出采用什么格式并不重要,只要我能将它作为一个键值对列表进一步使用。

    以下是一个概念,基于澄清评论中的假设

    • 只有一个标题
    • 不包括
    • 不依赖于包含代码的文件
    • 不依赖以前包含的标题
    • 不依赖于包含顺序
    其他主要要求:

    • 不要冒险影响二进制构建过程 (构成实际软件产品的部分)
    • 不要试图模拟二进制构建编译器/解析器
    如何:

    • 复印
    • 从专用代码文件中包含它,
      仅包含“#包括“copy.h”;
      或者直接对表头进行预处理
      (这与我的习惯格格不入)
    • 删除除预处理器和pragmas之外的所有内容, 注意线路延续
    • 将所有“#define”替换为“HaPoDefine”, 除了一个(例如第一个)
    • 重复
      • 对包含的代码文件进行预处理 (大多数编译器都有一个开关来执行此操作)
      • 保存输出
      • 将另一个“HaPoDefine”变回“#define”
    • 直到没有“HaPoDefine”留下
    • 从中间存储的增量中获取所有宏展开
    • 抛弃一切不相关的东西
    • 因为最终的实际数值很可能是编译器(而不是预处理器)的结果,所以使用bashs“expr”之类的工具来计算人眼可读性的值,
      小心不要让差异影响二进制构建过程
    • 使用一些正则表达式魔术来实现任何想要的格式

      • 一种方法是编写一个“程序生成器”,生成一个程序(printDefines程序),该程序由
        std::cout等语句组成。您可以使用
        g++
        gcc
        和-E选项,并处理该输出吗

        -E在预处理阶段后停止;不要正确运行编译器。 输出是预处理源代码的形式,它 发送到标准输出。不需要 预处理被忽略

        有了这个,我想:

      • 从源代码创建所有
        #define
        键的列表
      • 对源文件运行下面适当的命令,让GNU预处理器完成它的工作
      • 从stdout中获取预处理的结果,过滤以仅获取整数形式的结果,并将其输出到您想要表示键/值对的位置
      • 以下两个命令之一:

        gcc -E myFile.c
        g++ -E myFile.cpp
        

        只需使用现有的C预处理器就可以了。常规的GNU
        cpp
        -dU
        选项应该可以让你非常接近你想要的结果。为什么输出中
        常量_1
        常量_2
        ,但是
        魔数基数
        魔数
        更多魔数
        RE_MAGIC_2
        不是吗?它们似乎符合您的标准(定义编译时整数常量的解析)至少和其他两个一样好。@BenVoigt它们应该在输出中,我现在就解决它。@MatteoItalia我在cpp上使用-dU标志时没有得到任何预期的输出值。我需要另一个标志吗?@Techrocket9:问题是预处理器的规则根本不能满足您的要求。当外部宏被使用,而不是在它被定义的地方。因此,
        CONSTANT_1
        在被使用之前不是编译时整数表达式……而且可能有些用法是,有些用法不是。澄清一下:至少现在,我必须解析的是单个头文件,所以我不需要担心includes。使用了.h文件并修改了它ied由许多使用多个编译器的团队(我知道GCC和MSVC)编写,应该仍然是C++/14。该文件只需要符合二进制bu
        #  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
        
        #include <stdio.h>
        #include <string>
        #include <iostream>
        #include <fstream>
        #include <cstring>
        
        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<iostream>" << endl;
            cout << "#include<stdio.h>" << 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, &macroValuePos) == 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;
        }
        
        #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
        ...
        
        #include<iostream>
        #include<stdio.h>
        #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; }
        
        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?
        
        gcc -E myFile.c
        g++ -E myFile.cpp