#include <stdio.h> #include <string.h> extern "C" { #include <tree_sitter/api.h> extern const TSLanguage * tree_sitter_c(void); } int tbtraverse(const char * const code) { // init TSParser * parser; TSTree * tree; TSTreeCursor cursor; TSNode current_node; TSNode previous_node; parser = ts_parser_new(); ts_parser_set_language(parser, tree_sitter_c()); tree = ts_parser_parse_string(parser, NULL, code, strlen(code)); cursor = ts_tree_cursor_new(ts_tree_root_node(tree)); current_node = ts_tree_root_node(tree); // meat do { current_node = ts_tree_cursor_current_node(&cursor); const char * previous_node_type = NULL; int tblen = ts_node_end_byte(current_node) - ts_node_start_byte(current_node); char * tbtext = (char *)malloc(sizeof(char) * (tblen + 1)); memcpy(tbtext, code + ts_node_start_byte(current_node), tblen); tbtext[tblen] = '\0'; // XXX INJECTION if (!strcmp("function_definition", ts_node_type(current_node))) { puts("ack"); puts(tbtext); goto end; } if (!strcmp("number_literal", ts_node_type(current_node))) { puts("++"); goto end; } end: free(tbtext); } while ([&] { bool r = false; previous_node = current_node; if (ts_tree_cursor_goto_first_child(&cursor) || ts_tree_cursor_goto_next_sibling(&cursor)) { r = true; goto eval; } while (ts_tree_cursor_goto_parent(&cursor)) { if (!strcmp(ts_node_type(current_node), "translation_unit")) { r = false; break; } if (ts_tree_cursor_goto_next_sibling(&cursor)) { r = true; } eval: if (!strcmp("function_definition", ts_node_type(previous_node))) { puts("^^df"); goto end; } end: if (r) { break; } } return r; }()); // deinit ts_tree_delete(tree); ts_parser_delete(parser); ts_tree_cursor_delete(&cursor); return 0; } // @BAKE g++ $@ $(pkg-config --cflags --libs tree-sitter tree-sitter-c) -ggdb signed main() { tbtraverse("int main() { return 0; }"); }