From d1a1ebd54cabc6646f20f6b1b341751a2bf3c2ec Mon Sep 17 00:00:00 2001 From: Physick <96335032+DegustatorPonos@users.noreply.github.com> Date: Sun, 2 Aug 2026 22:52:27 +0500 Subject: puzzle parser --- .clangd | 4 ++ build.zig | 1 + puzzle_specs_v1.md | 12 ++-- puzzles/test.pz | Bin 0 -> 123 bytes src/main.c | 17 +++++- src/puzzles/parser.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/puzzles/puzzle.c | 6 +- src/puzzles/puzzle.h | 3 +- 8 files changed, 191 insertions(+), 12 deletions(-) create mode 100644 .clangd create mode 100644 puzzles/test.pz create mode 100644 src/puzzles/parser.c diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..87a3260 --- /dev/null +++ b/.clangd @@ -0,0 +1,4 @@ +#lsp config +CompileFlags: + Add: [-Iwren/src/include] + Compiler: /usr/bin/cc diff --git a/build.zig b/build.zig index 49c6e86..d8d3037 100644 --- a/build.zig +++ b/build.zig @@ -36,6 +36,7 @@ pub fn build(b: *std.Build) void { "src/scenes/resultView.c", "src/scenes/puzzleScene.c", "src/puzzles/puzzle.c", + "src/puzzles/parser.c", } }); diff --git a/puzzle_specs_v1.md b/puzzle_specs_v1.md index ff9b9bc..360b9a3 100644 --- a/puzzle_specs_v1.md +++ b/puzzle_specs_v1.md @@ -2,7 +2,7 @@ ## Puzzles 1. Termins - The field is depicted as `(Data type) Name` + The field is depicted as `(Data type) Name`. u8 is 8-bit integer (uint8_t in C). u32 is a 32-bit integer (uint32_t in C). string is a null-terminated ASCII byte array. @@ -10,12 +10,12 @@ 2. Puzzles are stored in binary format. The specification for it is as follows: +----------------------------+---------------+----------------------+ | (u8) Specification version | (string) Name | (string) Description | - +----------------------------+---------------+----------------------+ + +----------------------------+-----+---------+----------------------+ | (string) Initial code | (u32) Test count | +----------------------------------+--------------------------------+ | (Test) Test value | | ... | - +--------------------------------------+----------------------------+ + +-------------------------------------------------------------------+ The amount of the tests must be the exact same as specified in test counter. 2. The test is a following struct: @@ -36,7 +36,7 @@ +----------------+--------------+ 4.1. The type is defined by the Type code. The following types are supported: - +------+------+-------------------------------+ + +------+---------+----------------------------+ | Code | Name | Value size | +------+---------+----------------------------+ | 0 | Null | 0 bytes | @@ -49,7 +49,7 @@ +------+---------+----------------------------+ | 4 | List | 4 bytes (See the item 3.2) | +------+---------+----------------------------+ - + 4.2 The list value descriptor contains the amount of elements in the list. The following N Value descriptors will be treated as list elements. - That is the only case where the expected output will contain more than one value + That is the only case where the expected output will contain more than one value. diff --git a/puzzles/test.pz b/puzzles/test.pz new file mode 100644 index 0000000..59b1153 Binary files /dev/null and b/puzzles/test.pz differ diff --git a/src/main.c b/src/main.c index e83454e..9ccb20e 100644 --- a/src/main.c +++ b/src/main.c @@ -5,6 +5,21 @@ int main(void) { + Puzzle *puzzle = ReadPuzzleFromFile("puzzles/test.pz"); + + // printf("Puzzle name: %s\n", puzzle->Name); + // printf("Puzzle description: %s\n", puzzle->Description); + // printf("Puzzle code: %s\n", puzzle->InitialCode); + // printf("Puzzle TestC: %zu\n", puzzle->TestC); + + // for (int i = 0; i < puzzle->TestC; i++) { + // Test t = puzzle->Tests[i]; + // printf("\n"); + // printf("\tTest rec: %s\n", t.RecieverName); + // printf("\tTest sig: %s\n", t.MainMethodSignature); + // printf("\tTest argc: %zu\n", t.argc); + // } + if (!ReadConfig(DEFAULT_CONFIG_LOCATION)) { return 1; } @@ -19,7 +34,7 @@ int main(void) { return 1; } - if (!AddScene(CreatePuzzleScene(GetTestPuzzle()))) { + if (!AddScene(CreatePuzzleScene(puzzle))) { printf("Failed to create a puzzle menu\n"); return 1; } diff --git a/src/puzzles/parser.c b/src/puzzles/parser.c new file mode 100644 index 0000000..cb958e7 --- /dev/null +++ b/src/puzzles/parser.c @@ -0,0 +1,160 @@ +#include +#include "puzzle.h" +#include +#include +#include +#include +#include + +/// Reads a uint8_t from file. +/// Assumes that the file is on the position +uint8_t read_u8(FILE *file) { + uint8_t outp; + fread(&outp, 1, 1, file); + return outp; +} + +/// Reads a uint32_t (little-endian) from file. +/// Assumes that the file is on the position +uint32_t read_u32(FILE *file) { + uint32_t outp = 0; + for (int i = 0; i < 4; i++) { + outp += ((uint32_t)read_u8(file)) << (i * 8); + } + return outp; +} + +/// Reads a double from file. +/// Assumes that the file is on the position +double read_double(FILE *file) { + double outp; + fread(&outp, sizeof(double), 1, file); + return outp; +} + +/// Reads a null terminated string from file. +/// Assumes that the file if on the position. +/// Allocates the string. +char *read_string(FILE *file) { + char buf[8192]; + size_t idx = 0; + int c; + + while (idx < sizeof(buf) - 1) { + c = fgetc(file); + + if (c == 0 || c == EOF) break; + + buf[idx] = (char)c; + idx += 1; + } + + buf[idx] = 0x0; + return strdup(buf); +} + +typedef enum { + TYPE_NULL = 0, + TYPE_BOOL = 1, + TYPE_NUM = 2, + TYPE_STRING = 3, + TYPE_LIST = 4, +} V1_IO_TYPE; + +void ReadPuzzleIO_V1(FILE *file, PuzzleIO *io) { + uint8_t type = read_u8(file); + + switch (type) { + case TYPE_NULL: // NULL + io->type = WREN_TYPE_NULL; + io->value = NULL; + break; + + case TYPE_BOOL: + { + bool *outp = malloc(sizeof(bool)); + *outp = read_u8(file) != 0; + io->type = WREN_TYPE_BOOL; + io->value = outp; + break; + } + + case TYPE_NUM: + { + double *outp = malloc(sizeof(double)); + *outp = read_double(file); + io->type = WREN_TYPE_NUM; + io->value = outp; + break; + } + + case TYPE_STRING: + io->type = WREN_TYPE_STRING; + io->value = read_string(file); + break; + + case TYPE_LIST: + TraceLog(LOG_ERROR, "The arrays are not yet supported"); + io->type = WREN_TYPE_NULL; + io->value = NULL; + break; + + default: + return; + } +} + +void readTestV1(FILE *file, Test *outp) { + outp->RecieverName = read_string(file); + outp->MainMethodSignature = read_string(file); + outp->argc = read_u32(file); + outp->argv = malloc(sizeof(PuzzleIO) * outp->argc); + + for (size_t i = 0; i < outp->argc; i++) { + ReadPuzzleIO_V1(file, &outp->argv[i]); + } + + ReadPuzzleIO_V1(file, &outp->ExpectedResult); +} + +// Reads file with the specification from puzzle_specs_v1.md. +// Assumes the first byte of the file was read and the file was not rewinded. +Puzzle *parseFileV1(FILE *file) { + Puzzle *outp = malloc(sizeof(Puzzle)); + if (outp == NULL) return NULL; + + outp->Name = read_string(file); + outp->Description = read_string(file); + outp->InitialCode = read_string(file); + outp->TestC = read_u32(file); + + outp->Tests = malloc(sizeof(Test) * outp->TestC); + for (size_t i = 0; i < outp->TestC; i++) { + readTestV1(file, &outp->Tests[i]); + } + + return outp; +} + +Puzzle *ReadPuzzleFromFile(const char *path) { + FILE *file = fopen(path, "r"); + if (file == NULL) { + perror("Failed to parse the puzzle file"); + return NULL; + } + + uint8_t spec_version = read_u8(file); + printf("Version: %d\n", spec_version); + Puzzle *outp = NULL; + switch (spec_version) { + case 1: + outp = parseFileV1(file); + break; + default: + TraceLog(LOG_ERROR, "Failed to parse the puzzle file: unknown spec version"); + break; + } + + fclose(file); + return outp; +} diff --git a/src/puzzles/puzzle.c b/src/puzzles/puzzle.c index 2da9ffc..6d0a4a0 100644 --- a/src/puzzles/puzzle.c +++ b/src/puzzles/puzzle.c @@ -41,9 +41,9 @@ void FreeTests(Test *Tests, size_t TestC) { if (TestC == 0 || Tests == NULL) return; for (size_t i = 0; i < TestC; i++) { Test *t = &Tests[i]; - free(t->RecieverName); - free(t->MainMethodSignature); - free(t->argv); + if (t->RecieverName != NULL) free(t->RecieverName); + if (t->MainMethodSignature != NULL) free(t->MainMethodSignature); + if (t->argv != NULL) free(t->argv); } free(Tests); } diff --git a/src/puzzles/puzzle.h b/src/puzzles/puzzle.h index e7aebb1..20193ca 100644 --- a/src/puzzles/puzzle.h +++ b/src/puzzles/puzzle.h @@ -56,8 +56,7 @@ typedef struct { Test *Tests; } Puzzle; -// TODO -void ReadPuzzleFromFile(const char *path); +Puzzle *ReadPuzzleFromFile(const char *path); void FreePuzzle(Puzzle *self); /// A prebuilt puzzle. Used for debuging -- cgit v1.3