aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Beltran del Rio <jj@r.bdr.sh>2025-12-12 12:54:49 +0100
committerRuben Beltran del Rio <jj@r.bdr.sh>2025-12-12 15:05:41 +0100
commit1fec7e9fba5aace20e0b5c5463eca9c0d0692f51 (patch)
treeff681a11559ffa0ce2f5e4fb7bc2653269f75000
parent735e4e1c8f5b51480b801024fd4d142758644810 (diff)
Improve performance
-rw-r--r--Makefile2
-rw-r--r--src/test.c36
-rw-r--r--src/wmap_parser.c896
-rw-r--r--src/wmap_parser.h35
4 files changed, 505 insertions, 464 deletions
diff --git a/Makefile b/Makefile
index 2050035..c1f8243 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
# ANSI C compatible library with clean build structure
CC ?= gcc
-CFLAGS_RELEASE = -ansi -pedantic -Wall -Wextra -O2 -fomit-frame-pointer
+CFLAGS_RELEASE = -ansi -pedantic -Wall -Wextra -O3 -march=native -fomit-frame-pointer
CFLAGS_DEBUG = -ansi -pedantic -Wall -Wextra -g -DDEBUG
# Build configuration
diff --git a/src/test.c b/src/test.c
index 5602853..31b7c6e 100644
--- a/src/test.c
+++ b/src/test.c
@@ -97,13 +97,46 @@ int benchmark_parser(const char* filename, double time_limit_seconds) {
double elapsed_time;
int iterations = 0;
double avg_time_ns;
+ FILE* file;
+ long size;
+ char* buffer;
+ /* Load file once before benchmarking */
+ file = fopen(filename, "r");
+ if (!file) {
+ printf("Error: Failed to open file %s\n", filename);
+ return 1;
+ }
+
+ fseek(file, 0, SEEK_END);
+ size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ if (size < 0 || size > 10 * 1024 * 1024) {
+ fclose(file);
+ printf("Error: Invalid file size\n");
+ return 1;
+ }
+
+ buffer = (char*)malloc(size + 1);
+ if (!buffer) {
+ fclose(file);
+ printf("Error: Failed to allocate buffer\n");
+ return 1;
+ }
+
+ fread(buffer, 1, size, file);
+ buffer[size] = '\0';
+ fclose(file);
+
+ /* Now benchmark only the parse_string function */
start = clock();
while (1) {
- wmap_map_t* map = wmap_parse_file(filename);
+ wmap_map_t* map = wmap_parse_string(buffer);
if (!map) {
printf("Error: Failed to parse file on iteration %d\n", iterations);
+ free(buffer);
return 1;
}
wmap_map_free(map);
@@ -124,6 +157,7 @@ int benchmark_parser(const char* filename, double time_limit_seconds) {
printf(" Avg time: %.2f ns/iter\n", avg_time_ns);
printf(" Ops/sec: %.2f\n", iterations / elapsed_time);
+ free(buffer);
return 0;
}
diff --git a/src/wmap_parser.c b/src/wmap_parser.c
index 0fa8427..09ccd69 100644
--- a/src/wmap_parser.c
+++ b/src/wmap_parser.c
@@ -1,307 +1,178 @@
#include "wmap_parser.h"
-/* Forward declarations for older compilers */
-static int wmap_lexer_is_identifier_char(char c);
-static int wmap_lexer_is_keyword(const char* text, const char* keyword);
+/* Helper macros */
+#define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t')
+#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
+#define IS_NEWLINE(c) ((c) == '\n' || (c) == '\r')
-static void wmap_lexer_init(wmap_lexer_t* lexer, const char* input) {
- lexer->input = input;
- lexer->pos = 0;
- lexer->line = 1;
- lexer->col = 1;
- lexer->current_token = WMAP_TOKEN_EOF;
- lexer->token_text[0] = '\0';
- lexer->token_number = 0.0f;
-}
+/* Forward declarations */
+static void wmap_skip_whitespace(const char** p, const char* end);
+static int wmap_parse_float(const char** p, const char* end, float* result);
+static int wmap_case_insensitive_compare(const char* a, const char* b, int len);
+static int wmap_is_keyword(const char* str, int len, const char* keyword);
+static wmap_shape_t wmap_parse_shape_name(const char* str, int len);
+static wmap_stage_t wmap_parse_stage_name(const char* str, int len);
+static void wmap_parse_line(wmap_parser_t* parser, const char* line, int len);
-static void wmap_lexer_skip_whitespace(wmap_lexer_t* lexer) {
- while (lexer->input[lexer->pos] != '\0' &&
- (lexer->input[lexer->pos] == ' ' || lexer->input[lexer->pos] == '\t')) {
- lexer->pos++;
- lexer->col++;
+/* Skip whitespace in a line */
+static void wmap_skip_whitespace(const char** p, const char* end) {
+ while (*p < end && IS_WHITESPACE(**p)) {
+ (*p)++;
}
}
-static int wmap_lexer_is_identifier_char(char c) {
- return c != '-' && c != '+' && c != ',' && c != '[' && c != ']' &&
- c != '(' && c != ')' && c != '\n' && c != '\r' && c != '\0' && c != ' ' && c != '\t';
-}
-
-static wmap_token_type_t wmap_lexer_next_token(wmap_lexer_t* lexer) {
- char c;
- int start, len, has_dot;
-
- wmap_lexer_skip_whitespace(lexer);
-
- if (lexer->input[lexer->pos] == '\0') {
- return lexer->current_token = WMAP_TOKEN_EOF;
- }
-
- c = lexer->input[lexer->pos];
+/* Parse a float number */
+static int wmap_parse_float(const char** p, const char* end, float* result) {
+ const char* start;
+ char buffer[64];
+ int len;
- if (c == '\n') {
- lexer->pos++;
- lexer->line++;
- lexer->col = 1;
- return lexer->current_token = WMAP_TOKEN_NEWLINE;
- }
-
- if (c == '\r') {
- lexer->pos++;
- if (lexer->input[lexer->pos] == '\n') {
- lexer->pos++;
- }
- lexer->line++;
- lexer->col = 1;
- return lexer->current_token = WMAP_TOKEN_NEWLINE;
- }
+ wmap_skip_whitespace(p, end);
+ start = *p;
- if (c == '(') {
- lexer->pos++;
- lexer->col++;
- return lexer->current_token = WMAP_TOKEN_LPAREN;
+ /* Handle optional leading dot or sign */
+ if (*p < end && (**p == '.' || **p == '-' || **p == '+')) {
+ (*p)++;
}
- if (c == ')') {
- lexer->pos++;
- lexer->col++;
- return lexer->current_token = WMAP_TOKEN_RPAREN;
+ /* Read digits */
+ while (*p < end && (IS_DIGIT(**p) || **p == '.')) {
+ (*p)++;
}
- if (c == '[') {
- lexer->pos++;
- lexer->col++;
- return lexer->current_token = WMAP_TOKEN_LBRACKET;
- }
-
- if (c == ']') {
- lexer->pos++;
- lexer->col++;
- return lexer->current_token = WMAP_TOKEN_RBRACKET;
- }
-
- if (c == ',') {
- lexer->pos++;
- lexer->col++;
- return lexer->current_token = WMAP_TOKEN_COMMA;
- }
-
- if (c == '+') {
- lexer->pos++;
- lexer->col++;
- return lexer->current_token = WMAP_TOKEN_PLUS;
- }
-
- if (c == '-') {
- if (lexer->input[lexer->pos + 1] == '-') {
- lexer->pos += 2;
- lexer->col += 2;
- return lexer->current_token = WMAP_TOKEN_DASH;
- } else if (lexer->input[lexer->pos + 1] == '>') {
- lexer->pos += 2;
- lexer->col += 2;
- return lexer->current_token = WMAP_TOKEN_ARROW;
- } else {
- lexer->pos++;
- lexer->col++;
- return lexer->current_token = WMAP_TOKEN_MINUS;
- }
- }
-
- if (isdigit((unsigned char)c) || c == '.') {
- start = lexer->pos;
- has_dot = 0;
-
- if (c == '.') {
- has_dot = 1;
- lexer->pos++;
- lexer->col++;
- if (!isdigit((unsigned char)lexer->input[lexer->pos])) {
- return lexer->current_token = WMAP_TOKEN_ERROR;
- }
- }
-
- while (isdigit((unsigned char)lexer->input[lexer->pos])) {
- lexer->pos++;
- lexer->col++;
- }
-
- if (!has_dot && lexer->input[lexer->pos] == '.') {
- has_dot = 1;
- lexer->pos++;
- lexer->col++;
- while (isdigit((unsigned char)lexer->input[lexer->pos])) {
- lexer->pos++;
- lexer->col++;
- }
- }
-
- len = lexer->pos - start;
- if (len >= WMAP_MAX_NAME_LEN) {
- return lexer->current_token = WMAP_TOKEN_ERROR;
- }
-
- strncpy(lexer->token_text, lexer->input + start, len);
- lexer->token_text[len] = '\0';
- lexer->token_number = (float)atof(lexer->token_text);
-
- return lexer->current_token = WMAP_TOKEN_NUMBER;
+ len = *p - start;
+ if (len == 0 || len >= 64) {
+ return 0;
}
- if (wmap_lexer_is_identifier_char(c)) {
- start = lexer->pos;
-
- while (lexer->input[lexer->pos] != '\0' &&
- wmap_lexer_is_identifier_char(lexer->input[lexer->pos])) {
- lexer->pos++;
- lexer->col++;
- }
-
- len = lexer->pos - start;
- if (len >= WMAP_MAX_NAME_LEN) {
- len = WMAP_MAX_NAME_LEN - 1;
- }
-
- strncpy(lexer->token_text, lexer->input + start, len);
- lexer->token_text[len] = '\0';
+ memcpy(buffer, start, len);
+ buffer[len] = '\0';
+ *result = (float)atof(buffer);
+ return 1;
+}
- return lexer->current_token = WMAP_TOKEN_IDENTIFIER;
+/* Case-insensitive string comparison */
+static int wmap_case_insensitive_compare(const char* a, const char* b, int len) {
+ int i;
+ for (i = 0; i < len; i++) {
+ char ca = a[i];
+ char cb = b[i];
+ if (ca >= 'A' && ca <= 'Z') ca += 32;
+ if (cb >= 'A' && cb <= 'Z') cb += 32;
+ if (ca != cb) return 0;
}
-
- lexer->pos++;
- lexer->col++;
- return lexer->current_token = WMAP_TOKEN_ERROR;
+ return 1;
}
-static int wmap_lexer_is_keyword(const char* text, const char* keyword) {
- int i = 0;
- while (text[i] && keyword[i]) {
- char tc = text[i];
- char kc = keyword[i];
- if (tc >= 'A' && tc <= 'Z') tc += 32;
- if (kc >= 'A' && kc <= 'Z') kc += 32;
- if (tc != kc) {
- return 0;
- }
- i++;
- }
- return text[i] == keyword[i];
+/* Check if string matches keyword (case-insensitive) */
+static int wmap_is_keyword(const char* str, int len, const char* keyword) {
+ int klen = strlen(keyword);
+ if (len != klen) return 0;
+ return wmap_case_insensitive_compare(str, keyword, len);
}
-static wmap_shape_t wmap_parse_shape(const char* text) {
- if (wmap_lexer_is_keyword(text, "x")) return WMAP_SHAPE_X;
- if (wmap_lexer_is_keyword(text, "square")) return WMAP_SHAPE_SQUARE;
- if (wmap_lexer_is_keyword(text, "triangle")) return WMAP_SHAPE_TRIANGLE;
- if (wmap_lexer_is_keyword(text, "circle")) return WMAP_SHAPE_CIRCLE;
+/* Parse shape name */
+static wmap_shape_t wmap_parse_shape_name(const char* str, int len) {
+ if (wmap_is_keyword(str, len, "x")) return WMAP_SHAPE_X;
+ if (wmap_is_keyword(str, len, "square")) return WMAP_SHAPE_SQUARE;
+ if (wmap_is_keyword(str, len, "triangle")) return WMAP_SHAPE_TRIANGLE;
+ if (wmap_is_keyword(str, len, "circle")) return WMAP_SHAPE_CIRCLE;
return WMAP_SHAPE_NONE;
}
-static wmap_stage_t wmap_parse_stage(const char* text) {
- if (wmap_lexer_is_keyword(text, "i")) return WMAP_STAGE_I;
- if (wmap_lexer_is_keyword(text, "ii")) return WMAP_STAGE_II;
- if (wmap_lexer_is_keyword(text, "iii")) return WMAP_STAGE_III;
- if (wmap_lexer_is_keyword(text, "iv")) return WMAP_STAGE_IV;
+/* Parse stage name */
+static wmap_stage_t wmap_parse_stage_name(const char* str, int len) {
+ if (wmap_is_keyword(str, len, "i")) return WMAP_STAGE_I;
+ if (wmap_is_keyword(str, len, "ii")) return WMAP_STAGE_II;
+ if (wmap_is_keyword(str, len, "iii")) return WMAP_STAGE_III;
+ if (wmap_is_keyword(str, len, "iv")) return WMAP_STAGE_IV;
return 0;
}
-static wmap_parser_t* wmap_parser_create(const char* input) {
- wmap_parser_t* parser = (wmap_parser_t*)malloc(sizeof(wmap_parser_t));
- if (!parser) return NULL;
+/* Parse coordinates (x, y) */
+static int wmap_parse_coordinates(const char** p, const char* end, float* x, float* y) {
+ wmap_skip_whitespace(p, end);
- parser->map = (wmap_map_t*)malloc(sizeof(wmap_map_t));
- if (!parser->map) {
- free(parser);
- return NULL;
- }
+ if (*p >= end || **p != '(') return 0;
+ (*p)++;
- memset(parser->map, 0, sizeof(wmap_map_t));
- wmap_lexer_init(&parser->lexer, input);
- parser->error_count = 0;
+ if (!wmap_parse_float(p, end, x)) return 0;
- wmap_lexer_next_token(&parser->lexer);
+ wmap_skip_whitespace(p, end);
+ if (*p >= end || **p != ',') return 0;
+ (*p)++;
- return parser;
-}
+ if (!wmap_parse_float(p, end, y)) return 0;
-static void wmap_parser_destroy(wmap_parser_t* parser) {
- if (parser) {
- if (parser->map) {
- free(parser->map);
- }
- free(parser);
- }
-}
+ wmap_skip_whitespace(p, end);
+ if (*p >= end || **p != ')') return 0;
+ (*p)++;
-static void wmap_parser_skip_line(wmap_parser_t* parser) {
- while (parser->lexer.current_token != WMAP_TOKEN_NEWLINE &&
- parser->lexer.current_token != WMAP_TOKEN_EOF) {
- wmap_lexer_next_token(&parser->lexer);
- }
- if (parser->lexer.current_token == WMAP_TOKEN_NEWLINE) {
- wmap_lexer_next_token(&parser->lexer);
- }
+ return 1;
}
-static int wmap_parser_parse_position(wmap_parser_t* parser, float* x, float* y) {
- if (parser->lexer.current_token != WMAP_TOKEN_LPAREN) {
- return 0;
- }
- wmap_lexer_next_token(&parser->lexer);
+/* Parse component line: name (x, y) [shape] */
+static int wmap_parse_component_line(wmap_parser_t* parser, const char* line, int len) {
+ const char* p;
+ const char* end;
+ const char* name_start;
+ const char* name_end;
+ const char* shape_start;
+ int name_len, shape_len, i;
+ wmap_component_t* comp;
- if (parser->lexer.current_token != WMAP_TOKEN_NUMBER) {
+ if (parser->map->component_count >= WMAP_MAX_COMPONENTS) {
return 0;
}
- *x = parser->lexer.token_number;
- wmap_lexer_next_token(&parser->lexer);
- if (parser->lexer.current_token != WMAP_TOKEN_COMMA) {
- return 0;
- }
- wmap_lexer_next_token(&parser->lexer);
+ p = line;
+ end = line + len;
- if (parser->lexer.current_token != WMAP_TOKEN_NUMBER) {
- return 0;
- }
- *y = parser->lexer.token_number;
- wmap_lexer_next_token(&parser->lexer);
+ wmap_skip_whitespace(&p, end);
+ if (p >= end) return 0;
- if (parser->lexer.current_token != WMAP_TOKEN_RPAREN) {
- return 0;
+ /* Find component name (everything before '(') */
+ name_start = p;
+ while (p < end && *p != '(') {
+ p++;
}
- wmap_lexer_next_token(&parser->lexer);
-
- return 1;
-}
+ name_end = p;
-static int wmap_parser_parse_component(wmap_parser_t* parser) {
- wmap_component_t* comp;
+ /* Trim trailing whitespace from name */
+ while (name_end > name_start && IS_WHITESPACE(name_end[-1])) {
+ name_end--;
+ }
- if (parser->map->component_count >= WMAP_MAX_COMPONENTS) {
+ name_len = name_end - name_start;
+ if (name_len == 0 || name_len >= WMAP_MAX_NAME_LEN) {
return 0;
}
comp = &parser->map->components[parser->map->component_count];
- if (parser->lexer.current_token != WMAP_TOKEN_IDENTIFIER) {
- return 0;
+ /* Copy name */
+ for (i = 0; i < name_len; i++) {
+ comp->name[i] = name_start[i];
}
- strncpy(comp->name, parser->lexer.token_text, WMAP_MAX_NAME_LEN - 1);
- comp->name[WMAP_MAX_NAME_LEN - 1] = '\0';
- wmap_lexer_next_token(&parser->lexer);
+ comp->name[name_len] = '\0';
- if (!wmap_parser_parse_position(parser, &comp->x, &comp->y)) {
+ /* Parse coordinates */
+ if (!wmap_parse_coordinates(&p, end, &comp->x, &comp->y)) {
return 0;
}
+ /* Optional shape */
comp->shape = WMAP_SHAPE_NONE;
- if (parser->lexer.current_token == WMAP_TOKEN_LBRACKET) {
- wmap_lexer_next_token(&parser->lexer);
- if (parser->lexer.current_token == WMAP_TOKEN_IDENTIFIER) {
- comp->shape = wmap_parse_shape(parser->lexer.token_text);
- wmap_lexer_next_token(&parser->lexer);
+ wmap_skip_whitespace(&p, end);
+ if (p < end && *p == '[') {
+ p++;
+ shape_start = p;
+ while (p < end && *p != ']') {
+ p++;
}
- if (parser->lexer.current_token == WMAP_TOKEN_RBRACKET) {
- wmap_lexer_next_token(&parser->lexer);
+ shape_len = p - shape_start;
+ if (shape_len > 0) {
+ comp->shape = wmap_parse_shape_name(shape_start, shape_len);
}
}
@@ -309,85 +180,136 @@ static int wmap_parser_parse_component(wmap_parser_t* parser) {
return 1;
}
-static int wmap_parser_parse_dependency(wmap_parser_t* parser) {
+/* Parse dependency line: from -> to or from -- to */
+static int wmap_parse_dependency_line(wmap_parser_t* parser, const char* line, int len) {
+ const char* p;
+ const char* end;
+ const char* from_start;
+ const char* from_end;
+ const char* to_start;
+ const char* to_end;
+ int from_len, to_len, is_arrow, i;
wmap_dependency_t* dep;
if (parser->map->dependency_count >= WMAP_MAX_DEPENDENCIES) {
return 0;
}
- dep = &parser->map->dependencies[parser->map->dependency_count];
+ p = line;
+ end = line + len;
- if (parser->lexer.current_token != WMAP_TOKEN_IDENTIFIER) {
- return 0;
+ wmap_skip_whitespace(&p, end);
+ from_start = p;
+
+ /* Find arrow or dash */
+ while (p < end) {
+ if (*p == '-') {
+ if (p + 1 < end && p[1] == '>') {
+ from_end = p;
+ is_arrow = 1;
+ p += 2;
+ goto found_separator;
+ } else if (p + 1 < end && p[1] == '-') {
+ from_end = p;
+ is_arrow = 0;
+ p += 2;
+ goto found_separator;
+ }
+ }
+ p++;
}
- strncpy(dep->from, parser->lexer.token_text, WMAP_MAX_NAME_LEN - 1);
- dep->from[WMAP_MAX_NAME_LEN - 1] = '\0';
- wmap_lexer_next_token(&parser->lexer);
- if (parser->lexer.current_token == WMAP_TOKEN_ARROW) {
- dep->is_arrow = 1;
- wmap_lexer_next_token(&parser->lexer);
- } else if (parser->lexer.current_token == WMAP_TOKEN_DASH) {
- dep->is_arrow = 0;
- wmap_lexer_next_token(&parser->lexer);
- } else {
+ return 0; /* No separator found */
+
+found_separator:
+ /* Trim trailing whitespace from 'from' */
+ while (from_end > from_start && IS_WHITESPACE(from_end[-1])) {
+ from_end--;
+ }
+
+ from_len = from_end - from_start;
+ if (from_len == 0 || from_len >= WMAP_MAX_NAME_LEN) {
return 0;
}
- if (parser->lexer.current_token != WMAP_TOKEN_IDENTIFIER) {
+ wmap_skip_whitespace(&p, end);
+ to_start = p;
+
+ /* Find end of 'to' */
+ while (p < end && !IS_WHITESPACE(*p)) {
+ p++;
+ }
+ to_end = p;
+
+ to_len = to_end - to_start;
+ if (to_len == 0 || to_len >= WMAP_MAX_NAME_LEN) {
return 0;
}
- strncpy(dep->to, parser->lexer.token_text, WMAP_MAX_NAME_LEN - 1);
- dep->to[WMAP_MAX_NAME_LEN - 1] = '\0';
- wmap_lexer_next_token(&parser->lexer);
+ dep = &parser->map->dependencies[parser->map->dependency_count];
+
+ /* Copy 'from' */
+ for (i = 0; i < from_len; i++) {
+ dep->from[i] = from_start[i];
+ }
+ dep->from[from_len] = '\0';
+
+ /* Copy 'to' */
+ for (i = 0; i < to_len; i++) {
+ dep->to[i] = to_start[i];
+ }
+ dep->to[to_len] = '\0';
+
+ dep->is_arrow = is_arrow;
parser->map->dependency_count++;
return 1;
}
-static int wmap_parser_parse_note(wmap_parser_t* parser) {
+/* Parse note line: [note] (x, y) text */
+static int wmap_parse_note_line(wmap_parser_t* parser, const char* line, int len) {
+ const char* p;
+ const char* end;
+ const char* text_start;
+ int text_len, i;
wmap_note_t* note;
- int text_pos;
if (parser->map->note_count >= WMAP_MAX_NOTES) {
return 0;
}
+ p = line;
+ end = line + len;
+
note = &parser->map->notes[parser->map->note_count];
- if (!wmap_parser_parse_position(parser, &note->x, &note->y)) {
+ /* Parse coordinates */
+ if (!wmap_parse_coordinates(&p, end, &note->x, &note->y)) {
return 0;
}
- text_pos = 0;
- while (parser->lexer.current_token != WMAP_TOKEN_NEWLINE &&
- parser->lexer.current_token != WMAP_TOKEN_EOF &&
- text_pos < WMAP_MAX_TEXT_LEN - 1) {
+ /* Get remaining text */
+ wmap_skip_whitespace(&p, end);
+ text_start = p;
+ text_len = end - text_start;
- if (parser->lexer.current_token == WMAP_TOKEN_IDENTIFIER) {
- int len = strlen(parser->lexer.token_text);
- if (text_pos + len + 1 < WMAP_MAX_TEXT_LEN - 1) {
- strncpy(note->text + text_pos, parser->lexer.token_text, len);
- text_pos += len;
- note->text[text_pos++] = ' ';
- note->text[text_pos] = '\0';
- }
- }
- wmap_lexer_next_token(&parser->lexer);
+ if (text_len >= WMAP_MAX_TEXT_LEN) {
+ text_len = WMAP_MAX_TEXT_LEN - 1;
}
- if (text_pos > 0) {
- note->text[text_pos - 1] = '\0';
- } else {
- note->text[0] = '\0';
+ for (i = 0; i < text_len; i++) {
+ note->text[i] = text_start[i];
}
+ note->text[text_len] = '\0';
parser->map->note_count++;
return 1;
}
-static int wmap_parser_parse_stage(wmap_parser_t* parser) {
+/* Parse stage line: [i|ii|iii|iv] value */
+static int wmap_parse_stage_line(wmap_parser_t* parser, const char* stage_name, int name_len,
+ const char* line, int len) {
+ const char* p;
+ const char* end;
wmap_stage_data_t* stage;
if (parser->map->stage_count >= WMAP_MAX_STAGES) {
@@ -395,33 +317,29 @@ static int wmap_parser_parse_stage(wmap_parser_t* parser) {
}
stage = &parser->map->stages[parser->map->stage_count];
-
- if (parser->lexer.current_token != WMAP_TOKEN_IDENTIFIER) {
- return 0;
- }
-
- stage->stage = wmap_parse_stage(parser->lexer.token_text);
+ stage->stage = wmap_parse_stage_name(stage_name, name_len);
if (stage->stage == 0) {
return 0;
}
- wmap_lexer_next_token(&parser->lexer);
- if (parser->lexer.current_token != WMAP_TOKEN_RBRACKET) {
- return 0;
- }
- wmap_lexer_next_token(&parser->lexer);
+ p = line;
+ end = line + len;
- if (parser->lexer.current_token != WMAP_TOKEN_NUMBER) {
+ if (!wmap_parse_float(&p, end, &stage->value)) {
return 0;
}
- stage->value = parser->lexer.token_number;
- wmap_lexer_next_token(&parser->lexer);
parser->map->stage_count++;
return 1;
}
-static int wmap_parser_parse_group(wmap_parser_t* parser) {
+/* Parse group line: [group] member1, member2, ... */
+static int wmap_parse_group_line(wmap_parser_t* parser, const char* line, int len) {
+ const char* p;
+ const char* end;
+ const char* member_start;
+ const char* member_end;
+ int member_len, i;
wmap_group_t* group;
if (parser->map->group_count >= WMAP_MAX_GROUPS) {
@@ -431,18 +349,36 @@ static int wmap_parser_parse_group(wmap_parser_t* parser) {
group = &parser->map->groups[parser->map->group_count];
group->member_count = 0;
- while (parser->lexer.current_token == WMAP_TOKEN_IDENTIFIER &&
- group->member_count < WMAP_MAX_GROUP_MEMBERS) {
+ p = line;
+ end = line + len;
- strncpy(group->members[group->member_count], parser->lexer.token_text, WMAP_MAX_NAME_LEN - 1);
- group->members[group->member_count][WMAP_MAX_NAME_LEN - 1] = '\0';
- group->member_count++;
- wmap_lexer_next_token(&parser->lexer);
+ while (p < end && group->member_count < WMAP_MAX_GROUP_MEMBERS) {
+ wmap_skip_whitespace(&p, end);
+ member_start = p;
- if (parser->lexer.current_token == WMAP_TOKEN_COMMA) {
- wmap_lexer_next_token(&parser->lexer);
- } else {
- break;
+ /* Find end of member (comma or end of line) */
+ while (p < end && *p != ',') {
+ p++;
+ }
+ member_end = p;
+
+ /* Trim trailing whitespace */
+ while (member_end > member_start && IS_WHITESPACE(member_end[-1])) {
+ member_end--;
+ }
+
+ member_len = member_end - member_start;
+ if (member_len > 0 && member_len < WMAP_MAX_NAME_LEN) {
+ for (i = 0; i < member_len; i++) {
+ group->members[group->member_count][i] = member_start[i];
+ }
+ group->members[group->member_count][member_len] = '\0';
+ group->member_count++;
+ }
+
+ /* Skip comma */
+ if (p < end && *p == ',') {
+ p++;
}
}
@@ -454,166 +390,272 @@ static int wmap_parser_parse_group(wmap_parser_t* parser) {
return 0;
}
-static int wmap_parser_parse_inertia(wmap_parser_t* parser) {
+/* Parse inertia line: [inertia] name */
+static int wmap_parse_inertia_line(wmap_parser_t* parser, const char* line, int len) {
+ const char* p;
+ const char* end;
+ const char* name_start;
+ const char* name_end;
+ int name_len, i;
wmap_inertia_t* inertia;
if (parser->map->inertia_count >= WMAP_MAX_INERTIAS) {
return 0;
}
- inertia = &parser->map->inertias[parser->map->inertia_count];
+ p = line;
+ end = line + len;
+
+ wmap_skip_whitespace(&p, end);
+ name_start = p;
+ name_end = end;
+
+ /* Trim trailing whitespace */
+ while (name_end > name_start && IS_WHITESPACE(name_end[-1])) {
+ name_end--;
+ }
- if (parser->lexer.current_token != WMAP_TOKEN_IDENTIFIER) {
+ name_len = name_end - name_start;
+ if (name_len == 0 || name_len >= WMAP_MAX_NAME_LEN) {
return 0;
}
- strncpy(inertia->name, parser->lexer.token_text, WMAP_MAX_NAME_LEN - 1);
- inertia->name[WMAP_MAX_NAME_LEN - 1] = '\0';
- wmap_lexer_next_token(&parser->lexer);
+
+ inertia = &parser->map->inertias[parser->map->inertia_count];
+
+ for (i = 0; i < name_len; i++) {
+ inertia->name[i] = name_start[i];
+ }
+ inertia->name[name_len] = '\0';
parser->map->inertia_count++;
return 1;
}
-static int wmap_parser_parse_evolution(wmap_parser_t* parser) {
+/* Parse evolution line: [evolution] name +/- value */
+static int wmap_parse_evolution_line(wmap_parser_t* parser, const char* line, int len) {
+ const char* p;
+ const char* end;
+ const char* name_start;
+ const char* name_end;
+ int name_len, sign, i;
+ float value;
wmap_evolution_t* evolution;
- int sign;
if (parser->map->evolution_count >= WMAP_MAX_EVOLUTIONS) {
return 0;
}
- evolution = &parser->map->evolutions[parser->map->evolution_count];
+ p = line;
+ end = line + len;
- if (parser->lexer.current_token != WMAP_TOKEN_IDENTIFIER) {
- return 0;
+ wmap_skip_whitespace(&p, end);
+ name_start = p;
+
+ /* Find sign */
+ while (p < end && *p != '+' && *p != '-') {
+ p++;
}
- strncpy(evolution->name, parser->lexer.token_text, WMAP_MAX_NAME_LEN - 1);
- evolution->name[WMAP_MAX_NAME_LEN - 1] = '\0';
- wmap_lexer_next_token(&parser->lexer);
+ name_end = p;
- sign = 1;
- if (parser->lexer.current_token == WMAP_TOKEN_PLUS) {
- sign = 1;
- wmap_lexer_next_token(&parser->lexer);
- } else if (parser->lexer.current_token == WMAP_TOKEN_MINUS) {
- sign = -1;
- wmap_lexer_next_token(&parser->lexer);
+ /* Trim trailing whitespace from name */
+ while (name_end > name_start && IS_WHITESPACE(name_end[-1])) {
+ name_end--;
}
- if (parser->lexer.current_token != WMAP_TOKEN_NUMBER) {
+ name_len = name_end - name_start;
+ if (name_len == 0 || name_len >= WMAP_MAX_NAME_LEN || p >= end) {
return 0;
}
- evolution->change = sign * parser->lexer.token_number;
- wmap_lexer_next_token(&parser->lexer);
+
+ sign = (*p == '+') ? 1 : -1;
+ p++;
+
+ if (!wmap_parse_float(&p, end, &value)) {
+ return 0;
+ }
+
+ evolution = &parser->map->evolutions[parser->map->evolution_count];
+
+ for (i = 0; i < name_len; i++) {
+ evolution->name[i] = name_start[i];
+ }
+ evolution->name[name_len] = '\0';
+
+ evolution->change = sign * value;
parser->map->evolution_count++;
return 1;
}
-static int wmap_parser_parse(wmap_parser_t* parser) {
- while (parser->lexer.current_token != WMAP_TOKEN_EOF) {
- if (parser->lexer.current_token == WMAP_TOKEN_NEWLINE) {
- wmap_lexer_next_token(&parser->lexer);
- continue;
+/* Parse keyword-based line: [keyword] ... */
+static int wmap_parse_keyword_line(wmap_parser_t* parser, const char* line, int len) {
+ const char* p;
+ const char* end;
+ const char* keyword_start;
+ const char* keyword_end;
+ const char* content_start;
+ int keyword_len, content_len;
+
+ p = line;
+ end = line + len;
+
+ wmap_skip_whitespace(&p, end);
+ if (p >= end || *p != '[') return 0;
+ p++;
+
+ keyword_start = p;
+ while (p < end && *p != ']') {
+ p++;
+ }
+ keyword_end = p;
+
+ keyword_len = keyword_end - keyword_start;
+ if (keyword_len == 0 || p >= end) return 0;
+
+ p++; /* Skip ']' */
+
+ wmap_skip_whitespace(&p, end);
+ content_start = p;
+ content_len = end - content_start;
+
+ /* Check keyword type */
+ if (wmap_is_keyword(keyword_start, keyword_len, "note")) {
+ return wmap_parse_note_line(parser, content_start, content_len);
+ } else if (wmap_is_keyword(keyword_start, keyword_len, "group")) {
+ return wmap_parse_group_line(parser, content_start, content_len);
+ } else if (wmap_is_keyword(keyword_start, keyword_len, "inertia")) {
+ return wmap_parse_inertia_line(parser, content_start, content_len);
+ } else if (wmap_is_keyword(keyword_start, keyword_len, "evolution")) {
+ return wmap_parse_evolution_line(parser, content_start, content_len);
+ } else {
+ return wmap_parse_stage_line(parser, keyword_start, keyword_len, content_start, content_len);
+ }
+}
+
+/* Determine if line contains dependency or component */
+static int wmap_line_has_dependency(const char* line, int len) {
+ const char* p;
+ const char* end;
+
+ p = line;
+ end = line + len;
+
+ while (p < end) {
+ if (*p == '(') {
+ return 0; /* Found '(' first - it's a component */
+ }
+ if (*p == '-' && p + 1 < end && (p[1] == '>' || p[1] == '-')) {
+ return 1; /* Found dependency marker */
}
+ p++;
+ }
- if (parser->lexer.current_token == WMAP_TOKEN_LBRACKET) {
- wmap_lexer_next_token(&parser->lexer);
+ return 0;
+}
- if (parser->lexer.current_token == WMAP_TOKEN_IDENTIFIER) {
- if (wmap_lexer_is_keyword(parser->lexer.token_text, "note")) {
- wmap_lexer_next_token(&parser->lexer);
- if (parser->lexer.current_token == WMAP_TOKEN_RBRACKET) {
- wmap_lexer_next_token(&parser->lexer);
- if (!wmap_parser_parse_note(parser)) {
- parser->error_count++;
- wmap_parser_skip_line(parser);
- }
- } else {
- parser->error_count++;
- wmap_parser_skip_line(parser);
- }
- } else if (wmap_lexer_is_keyword(parser->lexer.token_text, "group")) {
- wmap_lexer_next_token(&parser->lexer);
- if (parser->lexer.current_token == WMAP_TOKEN_RBRACKET) {
- wmap_lexer_next_token(&parser->lexer);
- if (!wmap_parser_parse_group(parser)) {
- parser->error_count++;
- wmap_parser_skip_line(parser);
- }
- } else {
- parser->error_count++;
- wmap_parser_skip_line(parser);
- }
- } else if (wmap_lexer_is_keyword(parser->lexer.token_text, "inertia")) {
- wmap_lexer_next_token(&parser->lexer);
- if (parser->lexer.current_token == WMAP_TOKEN_RBRACKET) {
- wmap_lexer_next_token(&parser->lexer);
- if (!wmap_parser_parse_inertia(parser)) {
- parser->error_count++;
- wmap_parser_skip_line(parser);
- }
- } else {
- parser->error_count++;
- wmap_parser_skip_line(parser);
- }
- } else if (wmap_lexer_is_keyword(parser->lexer.token_text, "evolution")) {
- wmap_lexer_next_token(&parser->lexer);
- if (parser->lexer.current_token == WMAP_TOKEN_RBRACKET) {
- wmap_lexer_next_token(&parser->lexer);
- if (!wmap_parser_parse_evolution(parser)) {
- parser->error_count++;
- wmap_parser_skip_line(parser);
- }
- } else {
- parser->error_count++;
- wmap_parser_skip_line(parser);
- }
- } else {
- if (!wmap_parser_parse_stage(parser)) {
- parser->error_count++;
- wmap_parser_skip_line(parser);
- }
- }
- } else {
- parser->error_count++;
- wmap_parser_skip_line(parser);
- }
- } else if (parser->lexer.current_token == WMAP_TOKEN_IDENTIFIER) {
- wmap_lexer_t lookahead = parser->lexer;
- int is_dependency = 0;
+/* Parse a single line */
+static void wmap_parse_line(wmap_parser_t* parser, const char* line, int len) {
+ const char* p;
+ const char* end;
+
+ if (len == 0) return;
+
+ p = line;
+ end = line + len;
+
+ /* Skip leading whitespace */
+ wmap_skip_whitespace(&p, end);
+ if (p >= end) return;
+
+ /* Check for keyword line */
+ if (*p == '[') {
+ if (!wmap_parse_keyword_line(parser, line, len)) {
+ parser->error_count++;
+ }
+ return;
+ }
+
+ /* Check for dependency or component */
+ if (wmap_line_has_dependency(line, len)) {
+ if (!wmap_parse_dependency_line(parser, line, len)) {
+ parser->error_count++;
+ }
+ } else {
+ if (!wmap_parse_component_line(parser, line, len)) {
+ parser->error_count++;
+ }
+ }
+}
+
+/* Create parser - simplified without line array allocation */
+static wmap_parser_t* wmap_parser_create(const char* input) {
+ wmap_parser_t* parser;
+
+ parser = (wmap_parser_t*)malloc(sizeof(wmap_parser_t));
+ if (!parser) return NULL;
+
+ parser->input = input;
+ parser->error_count = 0;
- wmap_lexer_next_token(&lookahead);
- while (lookahead.current_token != WMAP_TOKEN_NEWLINE &&
- lookahead.current_token != WMAP_TOKEN_EOF) {
- if (lookahead.current_token == WMAP_TOKEN_ARROW ||
- lookahead.current_token == WMAP_TOKEN_DASH) {
- is_dependency = 1;
- break;
- }
- wmap_lexer_next_token(&lookahead);
+ parser->map = (wmap_map_t*)malloc(sizeof(wmap_map_t));
+ if (!parser->map) {
+ free(parser);
+ return NULL;
+ }
+
+ memset(parser->map, 0, sizeof(wmap_map_t));
+
+ return parser;
+}
+
+/* Destroy parser - simplified without line array */
+static void wmap_parser_destroy(wmap_parser_t* parser) {
+ if (parser) {
+ if (parser->map) {
+ free(parser->map);
+ }
+ free(parser);
+ }
+}
+
+/* Parse entry point - now just calls direct parsing */
+static int wmap_parser_parse(wmap_parser_t* parser) {
+ const char* p;
+ const char* line_start;
+ int line_len;
+
+ p = parser->input;
+ line_start = p;
+
+ while (*p != '\0') {
+ if (*p == '\n' || *p == '\r') {
+ /* Parse the line if non-empty */
+ line_len = p - line_start;
+ if (line_len > 0) {
+ wmap_parse_line(parser, line_start, line_len);
}
- if (is_dependency) {
- if (!wmap_parser_parse_dependency(parser)) {
- parser->error_count++;
- wmap_parser_skip_line(parser);
- }
- } else {
- if (!wmap_parser_parse_component(parser)) {
- parser->error_count++;
- wmap_parser_skip_line(parser);
- }
+ /* Handle \r\n */
+ if (*p == '\r' && p[1] == '\n') {
+ p++;
}
+ p++;
+ line_start = p;
} else {
- parser->error_count++;
- wmap_parser_skip_line(parser);
+ p++;
}
}
+ /* Parse final line if not empty */
+ line_len = p - line_start;
+ if (line_len > 0) {
+ wmap_parse_line(parser, line_start, line_len);
+ }
+
return parser->error_count == 0;
}
+/* Public API implementation */
wmap_map_t* wmap_parse_string(const char* input) {
wmap_parser_t* parser;
wmap_map_t* result;
diff --git a/src/wmap_parser.h b/src/wmap_parser.h
index fa4371b..e1b006f 100644
--- a/src/wmap_parser.h
+++ b/src/wmap_parser.h
@@ -17,14 +17,6 @@
#define WMAP_MAX_INERTIAS 256
#define WMAP_MAX_EVOLUTIONS 256
-#ifdef __mc68000__
-#define WMAP_68K_INLINE static
-#define WMAP_68K_FAST_CALL __attribute__((regparm(2)))
-#else
-#define WMAP_68K_INLINE static
-#define WMAP_68K_FAST_CALL
-#endif
-
/* Public Types */
typedef enum {
@@ -98,35 +90,8 @@ typedef struct {
/* Internal Types (needed for implementation) */
-typedef enum {
- WMAP_TOKEN_EOF = 0,
- WMAP_TOKEN_IDENTIFIER,
- WMAP_TOKEN_NUMBER,
- WMAP_TOKEN_LPAREN,
- WMAP_TOKEN_RPAREN,
- WMAP_TOKEN_LBRACKET,
- WMAP_TOKEN_RBRACKET,
- WMAP_TOKEN_COMMA,
- WMAP_TOKEN_ARROW,
- WMAP_TOKEN_DASH,
- WMAP_TOKEN_PLUS,
- WMAP_TOKEN_MINUS,
- WMAP_TOKEN_NEWLINE,
- WMAP_TOKEN_ERROR
-} wmap_token_type_t;
-
typedef struct {
const char* input;
- int pos;
- int line;
- int col;
- wmap_token_type_t current_token;
- char token_text[WMAP_MAX_NAME_LEN];
- float token_number;
-} wmap_lexer_t;
-
-typedef struct {
- wmap_lexer_t lexer;
wmap_map_t* map;
int error_count;
} wmap_parser_t;