feat: parse all structs in file and generate cmeta.h file
This commit is contained in:
2
Makefile
2
Makefile
@@ -3,7 +3,7 @@ all: build/cmeta
|
||||
build:
|
||||
mkdir -p build
|
||||
|
||||
build/cmeta: build third_party/stb_c_lexer.h src/main.c
|
||||
build/cmeta: build third_party/stb_c_lexer.h src/cmeta.h src/main.c
|
||||
gcc -Wall -Wextra -pedantic -o build/cmeta -isystem third_party/ third_party/stb_c_lexer.h src/main.c
|
||||
|
||||
run: build/cmeta
|
||||
|
||||
19
src/cmeta.h
Normal file
19
src/cmeta.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef CMETA_H
|
||||
#define CMETA_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
char* type;
|
||||
char* name;
|
||||
} Field_Info;
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
size_t fields_count;
|
||||
Field_Info *fields;
|
||||
} Struct_Info;
|
||||
|
||||
// GENERATE_HERE //
|
||||
|
||||
#endif // CMETA_H
|
||||
139
src/main.c
139
src/main.c
@@ -1,4 +1,5 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -6,6 +7,8 @@
|
||||
#define STB_C_LEXER_IMPLEMENTATION
|
||||
#include "stb_c_lexer.h"
|
||||
|
||||
#include "cmeta.h"
|
||||
|
||||
stb_lexer lexer = {0};
|
||||
|
||||
bool lexer_expect_keyword(const char* expected) {
|
||||
@@ -41,16 +44,18 @@ bool lexer_expect(long expected, const char* expected_str) {
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char* type;
|
||||
char* name;
|
||||
} Field_Info;
|
||||
long lexer_peek() {
|
||||
char* mark = lexer.parse_point;
|
||||
if (!stb_c_lexer_get_token(&lexer)) {
|
||||
lexer.parse_point = mark;
|
||||
return CLEX_eof;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
size_t fields_count;
|
||||
Field_Info *fields;
|
||||
} Struct_Info;
|
||||
long token = lexer.token;
|
||||
lexer.parse_point = mark;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
// parses typedef struct { FIELDS } TYPE_NAME
|
||||
bool parse_struct(Struct_Info* info) {
|
||||
@@ -148,18 +153,112 @@ void generate_struct_info(FILE* stream, Struct_Info info) {
|
||||
free(lowercase_name);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const char *source = "typedef struct { int int_field; bool bool_field; } My_Struct;";
|
||||
char string_store[1024];
|
||||
stb_c_lexer_init(&lexer, source, source + strlen(source), string_store, sizeof(string_store) / sizeof(char));
|
||||
bool read_entire_file(const char* file_path, char** content) {
|
||||
bool result = false;
|
||||
FILE* file = fopen(file_path, "rb");
|
||||
if(file == NULL) goto fail;
|
||||
|
||||
Struct_Info info = {0};
|
||||
if (!parse_struct(&info)) return 1;
|
||||
printf("--- Parsed ------------\n");
|
||||
print_struct(info);
|
||||
printf("--- Generated ---------\n");
|
||||
generate_struct_info(stdout, info);
|
||||
if(fseek(file, 0, SEEK_END) < 0) goto fail;
|
||||
|
||||
long length = ftell(file);
|
||||
if(length < 0) goto fail;
|
||||
|
||||
if(fseek(file, 0, SEEK_SET) < 0) goto fail;
|
||||
|
||||
*content = (char*) malloc((length + 1) * sizeof(char));
|
||||
fread(*content, 1, length, file);
|
||||
|
||||
// TODO: will not set errno
|
||||
if (ferror(file)) goto fail;
|
||||
|
||||
(*content)[length] = '\0';
|
||||
|
||||
result = true;
|
||||
fail:
|
||||
if (!result) {
|
||||
free(content);
|
||||
fprintf(stderr, "ERROR: Could not read `%s`: %s\n", file_path, strerror(errno));
|
||||
}
|
||||
if (file) fclose(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool generate_output_file(const char* output_path, Struct_Info *struct_infos, size_t struct_infos_count) {
|
||||
bool result = false;
|
||||
|
||||
char* header_content;
|
||||
if (!read_entire_file("src/cmeta.h", &header_content)) goto fail;
|
||||
|
||||
char* generate_at = strstr(header_content, "// GENERATE_HERE //");
|
||||
if (generate_at == NULL) {
|
||||
fprintf(stderr, "ERROR: could not found generation mark in cmeta.h\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
FILE* output_file = fopen(output_path, "wb");
|
||||
if (!output_file) {
|
||||
fprintf(stderr, "ERROR: could not write to %s: %s\n", output_path, strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
FILE* stream = output_file;
|
||||
|
||||
// write up to the generation mark
|
||||
fwrite(header_content, generate_at - header_content, 1, stream);
|
||||
|
||||
gen("// Generated by cmeta");
|
||||
for (size_t i = 0; i < struct_infos_count; i += 1) {
|
||||
generate_struct_info(stream, struct_infos[i]);
|
||||
}
|
||||
|
||||
// write the rest after the \n
|
||||
generate_at = strchr(generate_at, '\n');
|
||||
fwrite(generate_at, strlen(generate_at), 1, stream);
|
||||
|
||||
result = true;
|
||||
fail:
|
||||
free(header_content);
|
||||
if (output_file) fclose(output_file);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* program_name = argv[0];
|
||||
if(argc == 1) {
|
||||
fprintf(stderr, "ERROR: missing required argument <input_file>\n");
|
||||
fprintf(stderr, "Usage: %s <input_file>\n", program_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// read input file
|
||||
char* input_content;
|
||||
if(!read_entire_file(argv[1], &input_content)) return 1;
|
||||
|
||||
// init lexer
|
||||
char string_store[1024];
|
||||
stb_c_lexer_init(&lexer, input_content, input_content + strlen(input_content), string_store, sizeof(string_store) / sizeof(char));
|
||||
|
||||
// find and parse all structs
|
||||
size_t struct_infos_count = 0;
|
||||
Struct_Info struct_infos[16]; // TODO: use dynamic array
|
||||
|
||||
while (true) {
|
||||
char* mark = lexer.parse_point;
|
||||
|
||||
if (!stb_c_lexer_get_token(&lexer)) break;
|
||||
|
||||
if (lexer.token == CLEX_id && strcmp(lexer.string, "typedef") == 0) {
|
||||
lexer.parse_point = mark;
|
||||
|
||||
if (parse_struct(&struct_infos[struct_infos_count])) {
|
||||
struct_infos_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!generate_output_file("test/01_simple_struct/cmeta.h", struct_infos, struct_infos_count)) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user