diff --git a/Makefile b/Makefile index b590bb4..9efba6d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -CC := gcc -g -Og -std=c23 -Wall -Wextra -Wpedantic -Isrc -ltree-sitter +CC := gcc -g -Og -std=c23 -Wall -Wextra -Wpedantic -Isrc -ltree-sitter -Ibuild -build/bin/cgen: src/main.c | build/.build-dirs - $(CC) deps/tree-sitter-c/src/parser.c $^ -o build/bin/cgen +build/bin/cgen: src/main.c build/gen/.queries | build/.build-dirs + $(CC) deps/tree-sitter-c/src/parser.c $< -o build/bin/cgen .PHONY: run run: build/bin/cgen @@ -9,8 +9,13 @@ run: build/bin/cgen build/.build-dirs: Makefile mkdir -p build/bin + mkdir -p build/gen touch build/.build-dirs +build/gen/.queries: src/gen_enum.tsq | build/.build-dirs + xxd -i src/gen_enum.tsq > build/gen/gen_enum_tsq.h + touch build/gen/.queries + .PHONY: clean clean: rm -rf build diff --git a/compile_commands.json b/compile_commands.json index 22b4777..00ea465 100644 --- a/compile_commands.json +++ b/compile_commands.json @@ -10,6 +10,27 @@ "-Wextra", "-Wpedantic", "-Isrc", + "-Ibuild", + "-o", + "build/bin/cgen", + "deps/tree-sitter-c/src/parser.c" + ], + "directory": "/home/n/src/cgen", + "file": "/home/n/src/cgen/deps/tree-sitter-c/src/parser.c", + "output": "/home/n/src/cgen/build/bin/cgen" + }, + { + "arguments": [ + "/nix/store/1ciadcliylyyi9vx21id9vi1p1mayjn8-gcc-wrapper-14.2.0/bin/gcc", + "-c", + "-g", + "-Og", + "-std=c23", + "-Wall", + "-Wextra", + "-Wpedantic", + "-Isrc", + "-Ibuild", "-o", "build/bin/cgen", "src/main.c" diff --git a/flake.nix b/flake.nix index ba7dbbb..96a68ee 100644 --- a/flake.nix +++ b/flake.nix @@ -11,12 +11,13 @@ pkgs.mkShell { packages = with pkgs; [ gdb - gcc15 + gcc14 valgrind strace llvmPackages_17.clang-tools bear tree-sitter + tinyxxd ]; }; } diff --git a/src/gen_enum.tsq b/src/gen_enum.tsq index 70b870c..ec88f42 100644 --- a/src/gen_enum.tsq +++ b/src/gen_enum.tsq @@ -1,5 +1,18 @@ -(enum_specifier - name: (type_identifier)? @enum_name - body: (enumerator_list - (enumerator - name: (identifier) @enum_variant)?)) +[ + (translation_unit + (type_definition + (enum_specifier + name: (type_identifier)? @enum_name + body: (enumerator_list + ((enumerator name: (identifier) @enum_variant) ","?)* + )) @enum_spec + declarator: (type_identifier) @enum_declarator_name + )) + + (translation_unit + (enum_specifier + name: (type_identifier)? @enum_name + body: (enumerator_list + ((enumerator name: (identifier) @enum_variant) ","?)* + )) @enum_spec) +] diff --git a/src/main.c b/src/main.c index aafb7d6..0ed6d83 100644 --- a/src/main.c +++ b/src/main.c @@ -5,6 +5,8 @@ #include +#include "gen/gen_enum_tsq.h" + TSLanguage const *tree_sitter_c(void); char const *USAGE = "\ @@ -25,9 +27,6 @@ size_t read_stdin(char *buf, size_t buf_cap) { return at - buf; } -char const gen_enum_query_str[] = { - #embed "./gen_enum.tsq", '\0' -}; void gen_enum_strs() { size_t buf_cap = 2 << 16; char *buf = calloc(buf_cap, sizeof(*buf)); @@ -40,22 +39,91 @@ void gen_enum_strs() { TSTree *tree = ts_parser_parse_string(parser, nullptr, buf, buf_len); TSNode root_node = ts_tree_root_node(tree); - char *string = ts_node_string(root_node); - printf("%s\n", string); - uint32_t err_offset = 0; TSQueryError err = {}; TSQuery *query = ts_query_new( lang_c, - gen_enum_query_str, - strlen(gen_enum_query_str), + (char*)src_gen_enum_tsq, + src_gen_enum_tsq_len, &err_offset, &err ); if (err != TSQueryErrorNone) { - printf("query error %d near: %s\n", err, gen_enum_query_str + err_offset); + printf("query error %d near: %s\n", err, src_gen_enum_tsq + err_offset); assert(false); } + + uint32_t cap_id_poison = 2 << 16; + uint32_t cap_id_enum_name = cap_id_poison; + uint32_t cap_id_enum_variant = cap_id_poison; + uint32_t cap_id_enum_declarator_name = cap_id_poison; + uint32_t cap_count = ts_query_capture_count(query); + for (uint32_t i = 0; i < cap_count; ++i) { + uint32_t len = 0; + char const *name = ts_query_capture_name_for_id(query, i, &len); + + if (!strncmp(name, "enum_name", len)) { + cap_id_enum_name = i; + } + + if (!strncmp(name, "enum_variant", len)) { + cap_id_enum_variant = i; + } + + if (!strncmp(name, "enum_declarator_name", len)) { + cap_id_enum_declarator_name = i; + } + } + + TSQueryCursor *qc = ts_query_cursor_new(); + ts_query_cursor_exec(qc, query, root_node); + + TSQueryMatch match = {}; + while (ts_query_cursor_next_match(qc, &match)) { + char const *poison = "POISON"; + char const *enum_name = poison; + size_t enum_name_len = strlen(poison); + + size_t enum_variants_cap = 512; + struct { + char const *start; + size_t len; + } enum_variants[enum_variants_cap] = {}; + size_t enum_variants_len = 0; + for (uint32_t i = 0; i < match.capture_count; ++i) { + TSQueryCapture cap = match.captures[i]; + + uint32_t start = ts_node_start_byte(cap.node); + uint32_t end = ts_node_end_byte(cap.node); + uint32_t len = end - start; + char const *at = buf + start; + + if ( + cap.index == cap_id_enum_name + || cap.index == cap_id_enum_declarator_name + ) { + enum_name = at; + enum_name_len = len; + } + + if ( + cap.index == cap_id_enum_variant + && enum_variants_len < enum_variants_cap + ) { + enum_variants[enum_variants_len].len = len; + enum_variants[enum_variants_len].start = at; + + enum_variants_len++; + } + } + + printf("char const *%.*s_strs[] = {\n", (int)enum_name_len, enum_name); + for (size_t i = 0; i < enum_variants_len; ++i) { + typeof(enum_variants[0]) evar = enum_variants[i]; + printf("\t[%.*s] = \"%.*s\",\n", (int)evar.len, evar.start, (int)evar.len, evar.start); + } + printf("};\n"); + } } int main(int argc, char **argv) {