tree with multiple types

last updated: Oct 20, 2023

David Beazely said on twitter that it's not easy to make something like python's [ '+', ['*', 'a', 'b'], ['*', 'c', ['+', 'd', 'e']], 'f'] in C++; I didn't think it was that hard, and I only know C, so I came up with some code.

I'm a bit proud of it because I'm not a C coder - obviously it's 75 lines of code to replace 1, so it's not that great on that metric - and mostly I'm saving it here because it represents a bit of understanding I gained today and am likely to lose in a month.

#include <stdio.h>

typedef struct tree tree;

typedef enum valtype {
    INT,
    STR,
    TREE
} valtype;

typedef union val {
    char* string;
    int integer;
    tree* child;
} val;

typedef struct datum {
    valtype type;
    val value;
} datum;

struct tree {
  struct datum* children[256];
};

void print_tree(tree *t) {
    printf("[");
    for (int i=0; i < 256; i++) {
        if (t->children[i] == NULL) break;
        switch(t->children[i]->type) {
            case INT:
                printf(" %d ", t->children[i]->value.integer);
                break;
            case STR:
                printf(" \"%s\" ", t->children[i]->value.string);
                break;
            case TREE:
                print_tree(t->children[i]->value.child);
                break;
        }
    }
    printf("]");
}

int main() {
    tree root = { .children = {
        &(datum) { .type = STR, .value = { .string = "+"} },
        &(datum) { .type = TREE, .value = { .child = &(tree) {
            .children = {
                &(datum) { .type = STR, .value = { .string = "*"} },
                &(datum) { .type = INT, .value = { .integer = 7} },
                &(datum) { .type = INT, .value = { .integer = 9} },
            }}
        }},
        &(datum) { .type = TREE, .value = { .child = &(tree) {
            .children = {
                &(datum) { .type = STR, .value = { .string = "*"} },
                &(datum) { .type = STR, .value = { .string = "c"} },
                &(datum) { .type = TREE, .value = { .child = &(tree) {
                    .children = {
                        &(datum) { .type = STR, .value = { .string = "+"} },
                        &(datum) { .type = INT, .value = { .integer = 12} },
                        &(datum) { .type = INT, .value = { .integer = 13} },
                    }}}
                },
                &(datum) { .type = STR, .value = { .string = "d"} },
            }}
        }}
    }};

    print_tree(&root);
    printf("\n");

    return 0;
}

compile and run:

$ gcc dabeaz.c -o ./dabeaz; ./dabeaz [ "+" [ "*" 7 9 ][ "*" "c" [ "+" 12 13 ] "d" ]]

things I would do in a real world:

↑ up