为什么我的C / C ++头解析器不起作用?

时间:2015-09-17 08:28:16

标签: c++ c parsing boost header-files

我想将Boost Preprocessor库(以及最终其他的)捆绑到一个合并的标题中,所以我将一个小的实用程序组合在一起以实现这个目标......只是它没有工作!我无法确定我的程序中的错误或实施问题(或两者)是否导致其无法正常工作。

程序应该打开boost\preprocessor\library.hpp标题(包括整个库)并递归输出到stdout库所需的所有标题。 Windows资源管理器报告目录树​​中有(自Boost预处理器v1.59.0起)270个头文件,但我的程序只解析了204个。

我在另一个使用Boost预处理器的项目中使用它来测试合并的头。当使用boost\preprocessor\library.hpp标题时,项目编译并正常工作,但是当使用我的合并版本时,由于没有找到所需的所有Boost预处理器宏,编译失败。

完整的,可编译的代码:(仅使用MSVC v19进行测试)

#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <unordered_map>

// Remember what header files have already been parsed.
std::unordered_map<std::string, bool> have_parsed;

char include_dir[FILENAME_MAX]; // Passed in from the command line.

// Advance given pointer to next non-whitespace character and return it.
char* find_next_nonwhitespace_char(char* start) {
    while(isspace((int)(*start)) != 0) start++;
    return start;
}

#define DIE(condition, str) if(condition) {perror(str); exit(EXIT_FAILURE);}

int headers_parsed = 0;

void parse_header(const char* filename) {
    headers_parsed++;
    char path[FILENAME_MAX];
    strcpy(path, include_dir);
    strcat(path, filename);

    // Open file, get size and slurp it up.
    FILE* file = fopen(path, "rb");
    DIE(file == NULL, "fopen()");
    fseek(file, 0L, SEEK_END);
    long int file_size = ftell(file);
    rewind(file);
    char* file_buffer = (char*)malloc(file_size+1); // +1 for extra '\0'
    DIE(file_buffer == NULL, "malloc()");
    size_t got = fread(file_buffer, 1, file_size, file);
    DIE(got != file_size, "fread()");
    fclose(file);

    char* read_index = file_buffer;
    char* end_of_file = file_buffer + file_size;
    *end_of_file = '\0';

    // File is now in memory, parse each line.
    while(read_index < end_of_file) {
        char* start_of_line = read_index;
        // Scan forward looking for newline or 'EOF'
        char* end_of_line = strchr(start_of_line, '\n');
        if(end_of_line == NULL) end_of_line = end_of_file;
        *end_of_line = '\0';
        // Advance to the start of the next line for the next read.
        read_index += (end_of_line - start_of_line) + 1;
        // Look for #include directive at the start of the line.
        char* first_char = find_next_nonwhitespace_char(start_of_line);
        if(*first_char == '#') {
            // This could be an include line...
            char* next_char = find_next_nonwhitespace_char(first_char + 1);
            const char include[] = "include ";
            if(strncmp(next_char, include, strlen(include)) == 0) {
                char* open_brace = find_next_nonwhitespace_char(next_char + strlen(include));
                if(*open_brace++ == '<') {
                    char* close_brace = strchr(open_brace, '>');
                    assert(close_brace != NULL);
                    *close_brace = '\0';
                    if(have_parsed[open_brace] == false) {
                        have_parsed[open_brace] = true;
                        parse_header(open_brace); // Recurse
                    }
                    continue;
                }
            }
        }
        fprintf(stdout, "%s\n", start_of_line);
    }
    free(file_buffer);
}

int main(int argc, char* argv[]) {
    if(argc < 3) {
        fprintf(stderr, "%s {include directory} {first header}\n", argv[0]);
        return EXIT_FAILURE;
    }

    // Ensure the include directory has trailing slash
    strcpy(include_dir, argv[1]);
    size_t len = strlen(argv[1]);
    if(include_dir[len-1] != '\\') {
        include_dir[len] = '\\';
        include_dir[len+1] = '\0';
    }

    parse_header(argv[2]);

    fprintf(stderr, "headers parsed: %d\n", headers_parsed);
    return EXIT_SUCCESS;
}

运行已编译的程序:( Boost安装在g:\ dev中)

g:\dev\amalgamate\amalgamate.exe g:\dev\ boost\preprocessor\library.hpp > boost_pp.h
headers parsed: 204

生成的boost_pp.h标题:https://copy.com/vL6xdtScLogqnv9z

出了什么问题? 为什么我的程序没有创建一个有效的合并标题?

1 个答案:

答案 0 :(得分:5)

library.hpp实际上不包括树中的某些标题,原因是:

  • 他们将其他标头包装为外部接口(或因为它们已被弃用),例如preprocessor/comma.hpp只包含preprocessor/punctuation/comma.hpp

  • 将通过宏包含,例如:

    # define BOOST_PP_ITERATE() BOOST_PP_CAT(BOOST_PP_ITERATE_, BOOST_PP_INC(BOOST_PP_ITERATION_DEPTH()))
    #
    # define BOOST_PP_ITERATE_1 <boost/preprocessor/iteration/detail/iter/forward1.hpp>
    # define BOOST_PP_ITERATE_2 <boost/preprocessor/iteration/detail/iter/forward2.hpp>
    # define BOOST_PP_ITERATE_3 <boost/preprocessor/iteration/detail/iter/forward3.hpp>
    # define BOOST_PP_ITERATE_4 <boost/preprocessor/iteration/detail/iter/forward4.hpp>
    # define BOOST_PP_ITERATE_5 <boost/preprocessor/iteration/detail/iter/forward5.hpp>
    

可用于:

#define BOOST_PP_ITERATION_PARAMS_1 (...)
#include BOOST_PP_ITERATE()