为什么我的 C/C++ header 解析器不工作?
Why does my C/C++ header parser not work?
我想将 Boost Preprocessor 库(最终还有其他库)捆绑到一个合并的 header 中,所以我拼凑了一个小的实用程序来实现这个目标......只是它不起作用!我无法确定是我的程序中的错误还是实现问题(或两者)导致它无法正常工作。
该程序应该打开 boost\preprocessor\library.hpp
header(包括整个库)并递归输出到 stdout
库需要的所有 header。 Windows Explorer 报告目录树中有(自 Boost Preprocessor v1.59.0 起)270 个 header 个文件,但我的程序仅解析 204 个。
我通过在另一个使用 Boost 预处理器的项目中使用它来测试合并的 header。当使用 boost\preprocessor\library.hpp
header 时,项目编译并工作正常,但是当使用我的合并版本时,编译失败,因为没有找到所有需要的升压预处理器宏。
完整的可编译代码:(仅使用 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 '[=12=]'
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 = '[=12=]';
// 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 = '[=12=]';
// 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 = '[=12=]';
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] = '[=12=]';
}
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
header:https://copy.com/vL6xdtScLogqnv9z
怎么了? 为什么我的程序没有创建一个有效的合并 header?
树中的某些 headers 实际上并未包含在 library.hpp
中,原因是:
它们将其他 headers 包装为外部接口(或者因为它们已被弃用),例如 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()
我想将 Boost Preprocessor 库(最终还有其他库)捆绑到一个合并的 header 中,所以我拼凑了一个小的实用程序来实现这个目标......只是它不起作用!我无法确定是我的程序中的错误还是实现问题(或两者)导致它无法正常工作。
该程序应该打开 boost\preprocessor\library.hpp
header(包括整个库)并递归输出到 stdout
库需要的所有 header。 Windows Explorer 报告目录树中有(自 Boost Preprocessor v1.59.0 起)270 个 header 个文件,但我的程序仅解析 204 个。
我通过在另一个使用 Boost 预处理器的项目中使用它来测试合并的 header。当使用 boost\preprocessor\library.hpp
header 时,项目编译并工作正常,但是当使用我的合并版本时,编译失败,因为没有找到所有需要的升压预处理器宏。
完整的可编译代码:(仅使用 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 '[=12=]'
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 = '[=12=]';
// 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 = '[=12=]';
// 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 = '[=12=]';
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] = '[=12=]';
}
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
header:https://copy.com/vL6xdtScLogqnv9z
怎么了? 为什么我的程序没有创建一个有效的合并 header?
树中的某些 headers 实际上并未包含在 library.hpp
中,原因是:
它们将其他 headers 包装为外部接口(或者因为它们已被弃用),例如
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()