implemented kwil parsing

main
Sara 2023-09-11 18:45:33 +02:00
parent e518d1ae47
commit cc159c2244
2 changed files with 299 additions and 0 deletions

282
src/kwil_parse.c Normal file
View File

@ -0,0 +1,282 @@
#include "kwil_parse.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int fpeek(FILE* file) {
int get = fgetc(file);
if(get != EOF) {
ungetc(get, file);
}
return get;
}
static
int read_line_without_whitespace(FILE* file, char* out_buf, int max_size) {
// int read this loop
int c = 0;
// initialize writer and end of buffer pointer
char* out_writer = out_buf;
char* out_end = out_buf + max_size;
do {
c = fgetc(file);
if(!isspace(c)) {
*out_writer = c;
++out_writer;
}
} while(!feof(file) && c != '\n' && out_writer < out_end);
if(out_writer < out_end) {
*out_writer = '\0';
}
return out_writer - out_buf;
}
static
int next_non_whitespace(FILE* file) {
int c = 0;
do {
c = fgetc(file);
} while(isspace(c));
return c;
}
static
int read_typename(FILE* file, char* out_buf, int max_size) {
int c = 0;
char* out_end = out_buf + max_size;
// initialze buffer to check for "struct"
char buffer[7];
buffer[6] = '\0';
for(int i = 0; i < 6; ++i) {
buffer[i] = fgetc(file);
}
// next line is not a compatible type declaration,
// write null terminator and return zero
if(strncmp(buffer, "struct", 7) != 0 && strncmp(buffer, "enum", 4) != 0) {
*out_buf = '\0';
return 0;
}
// ignore the whitespace after "struct"
c = next_non_whitespace(file);
// write all text until the next whitespace or '{' to the out buffer
char* out_writer = out_buf;
for(;(isalnum(c) || ispunct(c)) && c != '{' && out_writer < out_end; ++out_writer) {
*out_writer = c;
c = fgetc(file);
}
if(out_writer < out_end) {
*out_writer = '\0';
}
// read until the end of the line,
// setting the file pointer up for parsing the struct
while(c != '\n') {
c = fgetc(file);
}
return out_writer - out_buf;
}
void kwil_header_parse(struct kwil_header_t* self) {
printf("Reading top level type definitions for header \"%s\"\n", self->file_name);
// .h file associated with self
FILE* file = fopen(self->file_name, "r");
// should be able to store
// KWIL_ENUM() or KWIL_STRUCT() or KWIL_FIELD()
char line_buffer[48];
line_buffer[47] = '\0';
struct kwil_struct_t kwil_struct;
struct kwil_enum_t kwil_enum;
struct kwil_type_t type;
// read the entire file
while(!feof(file)) {
// search for a match with a kwil statemenent
read_line_without_whitespace(file, line_buffer, 47);
if(strncmp(line_buffer, "KWIL_STRUCT()", 48) == 0) {
// get the typename and update the user
read_typename(file, line_buffer, 47);
printf("\"%s\": {\n", line_buffer);
// line matches KWIL_STRUCT() instantiate a struct and pass control to struct parser
kwil_struct_parse(&kwil_struct, file);
// move struct definition into a type struct and store in self
kwil_type_from_struct(&type, &kwil_struct, line_buffer);
kwil_header_add_type(self, &type);
} else if(strncmp(line_buffer, "KWIL_ENUM()", 48) == 0) {
//read typename and update the user
read_typename(file, line_buffer, 47);
printf("\"%s\": [\n", line_buffer);
// line matches KWIL_ENUM() instantiate an enum and pass control to the enum parser
kwil_enum_parse(&kwil_enum, file);
// move enum definition into a type struct and register with header
kwil_type_from_enum(&type, &kwil_enum, line_buffer);
kwil_header_add_type(self, &type);
}
}
// close file after finishing
fclose(file);
}
void kwil_struct_parse(struct kwil_struct_t *self, FILE *file) {
kwil_init_struct(self);
// create a line buffer with a null terminator
// this should always be treated as a 47-character-long array
// this way the string will always be valid
char line_buffer[48];
line_buffer[47] = '\0';
struct kwil_field_t field;
do {
// read the next line
read_line_without_whitespace(file, line_buffer, 47);
if(strncmp("KWIL_FIELD()", line_buffer, 12) == 0) {
kwil_field_parse(&field, file);
kwil_struct_add_field(self, &field);
printf("\t\"%s\": \"%s%s\",\n", field.name_str, field.type_str, field.array_length > 0 ? "*" : "");
}
} while(!feof(file) && line_buffer[0] != '}');
// print an end of line to separate structs when declaring fields
printf("}\n");
}
static
int kwil_field_parse_split(FILE* file, char* line_buffer,
char** o_words, int* o_word_lengths, int* o_word_count,
int* o_is_array) {
// last character read from file
int c = 0;
char* line_buffer_writer = line_buffer;
size_t word_index = 1;
// the "start" of the line is considered a whitespace character, this way leading whitespace is ignored
int last_was_space = 1;
do {
c = fgetc(file);
if(c == '*') {
*o_is_array = 2;
} else if(isalnum(c) || c == '_' || c == ']') {
// write non-whitespace characters to the line buffer
*line_buffer_writer = c;
++line_buffer_writer;
last_was_space = 0;
} else if(c == '[') {
*o_is_array = 1;
// store the start of the next word
o_words[word_index] = line_buffer_writer + 1;
// get the length of the previous word
o_word_lengths[word_index-1] = o_words[word_index] - o_words[word_index-1] - 1;
++word_index;
// add "\0[" or "\0]" to the line buffer
line_buffer_writer[0] = '\0';
line_buffer_writer[1] = c;
line_buffer_writer += 2;
} else if(last_was_space == 0) {
// write a null terminator at the end of the last word
*line_buffer_writer = '\0';
last_was_space = 1;
// store the start of the next word
o_words[word_index] = line_buffer_writer + 1;
// get the length of the previous word
o_word_lengths[word_index-1] = o_words[word_index] - o_words[word_index-1] - 1;
++word_index;
++line_buffer_writer;
}
} while(!feof(file) && c != ';');
*o_word_count = word_index - 1;
// consume the line to set up for the next field
while(c != '\n') {
c = fgetc(file);
}
return line_buffer_writer - line_buffer;
}
void kwil_field_parse(struct kwil_field_t* self, FILE* file) {
// 47 character long temp buffer for reading from file
char line_buffer[48];
// array of pointers into line_buffer that point at the starts of words
char* words[5];
// array of word lengths matched to start_ptrs
int word_lengths[5];
// initialize these as 0x0
memset(words, '\0', sizeof(words));
memset(word_lengths, '\0', sizeof(word_lengths));
// the start of the first word matches the start of the line buffer
words[0] = line_buffer;
// set the terminal element to null
line_buffer[47] = '\0';
// Set to true if this field is a pointer or array
// Both dynamic and static sized arrays are supported,
// though dynamic arrays will need to be marked with their minimum length
int is_array = 0;
// length of the entire buffer
int word_count;
int length = kwil_field_parse_split(file, line_buffer,
words, word_lengths, &word_count, &is_array);
line_buffer[length - 1] = '\0';
// scan for the length of static arrays
int array_len = 0;
if(is_array == 1) {
sscanf(words[word_count-1], "[%d]",
&array_len);
word_count -= 1;
}
// get the typename from the split declaration
char* type = words[0];
if(strncmp("struct", type, 7) == 0 || strncmp("enum", type, 5) == 0) {
words[0][word_lengths[0]] = ' ';
}
kwil_init_field(self, words[word_count - 1], words[0]);
self->array_length = array_len;
self->array_dynamic = is_array == 2;
}
void kwil_enum_parse(struct kwil_enum_t* self, FILE* file) {
kwil_init_enum(self);
char value_buffer[24];
int length;
value_buffer[23] = '\0';
length = read_line_without_whitespace(file, value_buffer, 23);
while(!feof(file) && value_buffer[0] != '}') {
if(value_buffer[length-1] == ',') {
value_buffer[length-1] = '\0';
}
kwil_enum_add_value(self, value_buffer);
length = read_line_without_whitespace(file, value_buffer, 23);
printf("\t\"%s\",\n", self->enum_values[self->enum_values_len-1].name);
}
printf("]\n\n");
}

17
src/kwil_parse.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef _kwil_parse_H
#define _kwil_parse_H
#include <stdio.h>
#include "kwil_def.h"
// Open a header file and parse it for it's kwil types
extern void kwil_header_parse(struct kwil_header_t* self);
// Read a file until the end of struct definition.
extern void kwil_struct_parse(struct kwil_struct_t* self, FILE* file);
// Parse a field without checking custom types.
// Custom types will not be checked yet as they may not be known to kwel yet.
extern void kwil_field_parse(struct kwil_field_t* self, FILE* file);
// Parse an enum and it's possible values.
extern void kwil_enum_parse(struct kwil_enum_t* self, FILE* file);
#endif // !_kwil_parse_H