Files
slex/Source/slex_parser.c
2026-05-26 04:45:32 +10:00

250 lines
9.0 KiB
C

#include "../Headers/slex_core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// Helper: Trim leading and trailing whitespace
static char* trim_whitespace(char* str) {
while (isspace((unsigned char)*str)) {
str++;
}
if (*str == '\0') {
return str;
}
char* end = str + strlen(str) - 1;
while (end > str && isspace((unsigned char)*end)) {
end--;
}
*(end + 1) = '\0';
return str;
}
// Helper: Get next line from buffer
static bool get_next_line(char** cursor, char* line_buf, int max_len) {
char* c = *cursor;
if (*c == '\0') return false;
int idx = 0;
while (*c != '\0' && *c != '\n' && *c != '\r' && idx < max_len - 1) {
line_buf[idx++] = *c++;
}
line_buf[idx] = '\0';
// Skip newline characters
if (*c == '\r') c++;
if (*c == '\n') c++;
*cursor = c;
return true;
}
bool slex_read_rule_from_cstr(char *content, slex_rules *output_rule) {
if (!content || !output_rule) return false;
// Initialize output structure
output_rule->rules = NULL;
output_rule->rule_count = 0;
output_rule->mappings = NULL;
output_rule->mapping_count = 0;
output_rule->code_blocks = NULL;
output_rule->code_block_count = 0;
typedef enum {
STATE_NONE,
STATE_RULE,
STATE_MAPPING,
STATE_CODE
} ParserState;
ParserState state = STATE_NONE;
slex_target_language current_lang = c_language;
bool has_lang = false;
char* cursor = content;
char line[4096];
while (get_next_line(&cursor, line, sizeof(line))) {
char* trimmed = trim_whitespace(line);
// Skip comments and empty lines
if (trimmed[0] == '\0' || trimmed[0] == '#' || (trimmed[0] == '/' && trimmed[1] == '/')) {
continue;
}
// Section switches
if (strcmp(trimmed, "rule:") == 0) {
state = STATE_RULE;
continue;
} else if (strcmp(trimmed, "mapping:") == 0) {
state = STATE_MAPPING;
continue;
} else if (strcmp(trimmed, "code:") == 0) {
state = STATE_CODE;
continue;
}
if (state == STATE_RULE) {
// Split into <Tag> and <MatchingPattern>
// Tag is first space-delimited token
char* tag = trimmed;
char* pattern = trimmed;
while (*pattern != '\0' && !isspace((unsigned char)*pattern)) {
pattern++;
}
if (*pattern != '\0') {
*pattern = '\0';
pattern++;
pattern = trim_whitespace(pattern);
}
if (strlen(tag) > 0 && strlen(pattern) > 0) {
output_rule->rule_count++;
output_rule->rules = (slex_rule*)realloc(output_rule->rules, output_rule->rule_count * sizeof(slex_rule));
output_rule->rules[output_rule->rule_count - 1].Tag = strdup(tag);
output_rule->rules[output_rule->rule_count - 1].Pattern = strdup(pattern);
}
} else if (state == STATE_MAPPING) {
// Split into <Id> and <Tag>
char* id = trimmed;
char* tag = trimmed;
while (*tag != '\0' && !isspace((unsigned char)*tag)) {
tag++;
}
if (*tag != '\0') {
*tag = '\0';
tag++;
tag = trim_whitespace(tag);
}
if (strlen(id) > 0 && strlen(tag) > 0) {
output_rule->mapping_count++;
output_rule->mappings = (slex_mapping*)realloc(output_rule->mappings, output_rule->mapping_count * sizeof(slex_mapping));
output_rule->mappings[output_rule->mapping_count - 1].Id = strdup(id);
output_rule->mappings[output_rule->mapping_count - 1].Tag = strdup(tag);
}
} else if (state == STATE_CODE) {
int len = (int)strlen(trimmed);
if (trimmed[0] == '%' && trimmed[len - 1] == '%') {
// Language definition block like %c% or %c#% or %csharp%
char lang_name[256];
strncpy(lang_name, trimmed + 1, len - 2);
lang_name[len - 2] = '\0';
char* trimmed_lang = trim_whitespace(lang_name);
if (strcmp(trimmed_lang, "c") == 0) {
current_lang = c_language;
has_lang = true;
} else if (strcmp(trimmed_lang, "c#") == 0 || strcmp(trimmed_lang, "csharp") == 0) {
current_lang = csharp;
has_lang = true;
} else {
has_lang = false;
}
} else if (has_lang && strcmp(trimmed, "%post_processor") == 0) {
// Read all lines until "post_processor%"
int cap = 4096;
char* code = (char*)malloc(cap);
code[0] = '\0';
int code_len = 0;
char code_line[4096];
while (get_next_line(&cursor, code_line, sizeof(code_line))) {
char* trimmed_code = trim_whitespace(code_line);
if (strcmp(trimmed_code, "post_processor%") == 0) {
break;
}
int line_len = (int)strlen(code_line);
if (code_len + line_len + 2 >= cap) {
cap *= 2;
code = (char*)realloc(code, cap);
}
strcat(code, code_line);
strcat(code, "\n");
code_len += line_len + 1;
}
// Add or update code block
int block_idx = -1;
for (uint64_t i = 0; i < output_rule->code_block_count; i++) {
if (output_rule->code_blocks[i].target_languge == current_lang) {
block_idx = (int)i;
break;
}
}
if (block_idx == -1) {
output_rule->code_block_count++;
output_rule->code_blocks = (code_block*)realloc(output_rule->code_blocks, output_rule->code_block_count * sizeof(code_block));
block_idx = (int)output_rule->code_block_count - 1;
output_rule->code_blocks[block_idx].target_languge = current_lang;
output_rule->code_blocks[block_idx].post_processor_code = NULL;
output_rule->code_blocks[block_idx].variables = NULL;
}
output_rule->code_blocks[block_idx].post_processor_code = code;
} else if (has_lang && strcmp(trimmed, "%variables") == 0) {
// Read all lines until "variables%"
int cap = 4096;
char* vars = (char*)malloc(cap);
vars[0] = '\0';
int vars_len = 0;
char vars_line[4096];
while (get_next_line(&cursor, vars_line, sizeof(vars_line))) {
char* trimmed_vars = trim_whitespace(vars_line);
if (strcmp(trimmed_vars, "variables%") == 0) {
break;
}
int line_len = (int)strlen(vars_line);
if (vars_len + line_len + 2 >= cap) {
cap *= 2;
vars = (char*)realloc(vars, cap);
}
strcat(vars, vars_line);
strcat(vars, "\n");
vars_len += line_len + 1;
}
// Add or update code block
int block_idx = -1;
for (uint64_t i = 0; i < output_rule->code_block_count; i++) {
if (output_rule->code_blocks[i].target_languge == current_lang) {
block_idx = (int)i;
break;
}
}
if (block_idx == -1) {
output_rule->code_block_count++;
output_rule->code_blocks = (code_block*)realloc(output_rule->code_blocks, output_rule->code_block_count * sizeof(code_block));
block_idx = (int)output_rule->code_block_count - 1;
output_rule->code_blocks[block_idx].target_languge = current_lang;
output_rule->code_blocks[block_idx].post_processor_code = NULL;
output_rule->code_blocks[block_idx].variables = NULL;
}
output_rule->code_blocks[block_idx].variables = vars;
}
}
}
return true;
}
bool slex_read_rule_from_file(FILE *f, slex_rules *output_rule) {
if (!f || !output_rule) return false;
// Determine file size
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
char* content = (char*)malloc(size + 1);
if (!content) return false;
size_t read_bytes = fread(content, 1, size, f);
content[read_bytes] = '\0';
bool success = slex_read_rule_from_cstr(content, output_rule);
free(content);
return success;
}