Commit c9e91cc
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;
+}