Commit c9e91cc

kravantokh <kravantokh@noreply.codeberg.org>
2026-09-12 15:34:10
Make basic proof of concept work.
1 parent 32c3472
a.out
Binary file
common.h
@@ -0,0 +1,28 @@
+#ifndef HEADER_COMMON_INCLUDED
+#define HEADER_COMMON_INCLUDED
+
+#include <stdbool.h>
+
+#define NUM_CHILDREN 4
+
+typedef struct _Node {
+	char *cmd;
+	char *name;
+	struct _Node *children[NUM_CHILDREN];
+	bool seen_decl;
+	bool seen_def;
+} Node;
+
+
+#define NODE( NAME, CMD,  ... )   \
+	Node NAME = (Node){          \
+		.name = #NAME,          \
+		.cmd = CMD,             \
+		.seen_decl = 0,         \
+		.seen_def = 0,          \
+		.children = __VA_ARGS__ \
+	};
+
+
+
+#endif
data.c
@@ -0,0 +1,16 @@
+#include "./common.h"
+
+Node n1;
+Node n2;
+Node n3;
+Node n4;
+Node n5;
+
+NODE( n1, 0, { &n1, &n2, &n3, 0 } );
+NODE( n2, "touch cmd2", { 0, &n4, &n5, &n2 } );
+NODE( n3, "touch cmd3", { &n4, &n5, 0, 0 } );
+NODE( n4, "touch cmd4", { &n5, 0, 0, 0 } );
+NODE( n5, "touch cmd5", { 0, 0, 0, 0 } );
+
+
+Node *root = &n1;
main.c
@@ -0,0 +1,173 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "./common.h"
+
+char controls[NUM_CHILDREN] = { 'w', 'a', 's', 'd' };
+
+typedef struct _NodeListElem {
+	struct _NodeListElem *prev;
+	Node *node;
+} NodeListElem;
+
+void _iterate_nodes( NodeListElem *prev, Node *p, Node *n, void (*f)( Node *parent, Node *current, void* ctx), void *ctx ) {
+
+	NodeListElem start = {
+		.prev = prev,
+		.node = n
+	};
+
+	if( 0 == n ) return;
+
+	/* Ensure we are not recursing back into a previous node on the same branch */
+	for( NodeListElem *e = prev; e->prev != 0; e = e->prev ) {
+		if( e->node == n ) {
+			return;
+		}
+	}
+
+	f( p, n, ctx );
+
+	_iterate_nodes( &start, n, n->children[0], f, ctx );
+	_iterate_nodes( &start, n, n->children[1], f, ctx );
+	_iterate_nodes( &start, n, n->children[2], f, ctx );
+	_iterate_nodes( &start, n, n->children[3], f, ctx );
+}
+
+void iterate_nodes( Node *p, Node *n, void (*f)( Node *parent, Node *current, void* ctx), void *ctx ) {
+	NodeListElem start = {
+		.prev = 0,
+		.node = p
+	};
+
+	_iterate_nodes( &start, p, n, f, ctx );
+}
+
+
+void print_as_current( Node *n ) {
+	printf("%s\n", n->name);
+
+	for( size_t i = 0; i < NUM_CHILDREN; ++i ) {
+		if( n->children[i] ) {
+			printf("[%c] %s\n", controls[i], n->children[i]->name);
+		}
+	}
+}
+
+void execute_node( Node *n ) {
+	system( n->cmd );
+}
+
+void gen_forward_declaration( Node *parent, Node *current, void *ctx ) {
+	FILE *f = ctx;
+
+	if( current->seen_decl ) {
+		return;
+	}
+
+	fprintf( f, "Node %s;\n", current->name );
+}
+
+
+void gen_node_macro( Node *parent, Node *current, void *ctx ) {
+	FILE *f = ctx;
+
+	if( current->seen_def ) {
+		return;
+	}
+
+	fprintf( f, "NODE( %s, ", current->name );
+
+	if( current->cmd ) {
+		fprintf( f, "\"%s\", ", current->cmd );
+	} else {
+		fprintf( f, "0, ");
+	}
+
+	fprintf( f, "{ " );
+
+	for( size_t i = 0; i < NUM_CHILDREN; ++i ) {
+		if( current->children[i] ) {
+			fprintf( f, "&%s, ", current->children[i]->name );
+		} else {
+			fprintf( f, "0, " );
+		}
+	}
+
+	current->seen_def = 1;
+	fprintf( f, "}" );
+	fprintf( f, " )\n" );
+}
+
+void generate_code( Node *root, FILE *f ) {
+	fprintf( f, "#include \"./common.h\"\n\n" );
+
+	iterate_nodes( (void*)&root, root, gen_forward_declaration, f );
+	fprintf( f, "\n\n" );
+	iterate_nodes( (void*)&root, root, gen_node_macro, f );
+	fprintf( f, "\n\n" );
+
+	fprintf( f, "Node *root = &%s;", root->name );
+}
+
+int main(void) {
+	Node *root;
+	Node *current;
+
+	system("gcc -shared -ffreestanding data.c -o data.so");
+
+	void *data_so = dlopen( "./data.so", RTLD_NOW );
+	if( !data_so ) return 1;
+
+	void *sym = dlsym( data_so, "root" );
+	if( !sym ) return 2;
+
+	root = *(Node**)sym;
+
+	current = root;
+	char in;
+
+	print_as_current( current );
+
+	while( (in = getchar()) ) {
+		if( in == 'c' ) { /* codegen */
+			FILE *f = fopen( "./gen.c", "w" );
+			if( !f ) return 3;
+			generate_code( root, f );
+			fclose( f );
+			goto end;
+		}
+
+		for( size_t i = 0; i < NUM_CHILDREN; ++i ) {
+			if( in == controls[i] ) {
+				if( current->children[i] ) {
+					current = current->children[i];
+					execute_node( current );
+				} else {
+					/* Ignore direction that is not present on the current node */
+					break;
+				}
+			}
+		}
+
+		bool has_child = 0;
+		for( size_t i = 0; i < NUM_CHILDREN; ++i ) {
+			if( current->children[i] ) {
+				has_child = 1;
+				break;
+			}
+		}
+
+		if( !has_child ) {
+			break;
+		}
+		print_as_current( current );
+	}
+
+end:
+	dlclose(data_so);
+
+	return 0;
+}