#include #include #include #include struct node_parent { char tag; }; struct stack { int32_t size; int32_t count; struct node_parent** data; }; struct node_app { char tag; struct node_parent* left; struct node_parent* right; }; struct node_num { char tag; int32_t value; }; struct node_global { char tag; int32_t arity; void (*function)(struct stack*); }; struct node_ind { char tag; struct node_parent* next; }; void stack_init(struct stack* stack) { stack->size = 16; stack->count = 0; stack->data = malloc(sizeof(*stack->data) * stack->size); } void stack_free(struct stack* stack) { free(stack->data); } void stack_push(struct stack* stack, struct node_parent* node) { printf("pushing\n"); assert(stack->count < stack->size); stack->data[stack->count++] = node; printf("new size: %d\n", stack->count); } struct node_parent* stack_peek(struct stack* stack, int32_t offset) { assert(offset + 1 <= stack->count); return stack->data[stack->count - offset - 1]; } struct node_parent* stack_pop(struct stack* stack) { printf("popping\nnew size: %d\n", stack->count - 1); assert(stack->count > 0); return stack->data[--stack->count]; } void stack_popn(struct stack* stack, int32_t count) { assert(stack->count >= count); stack->count -= count; printf("popping %d\nnew size: %d\n", count, stack->count); } void stack_update(struct stack* stack, int32_t offset) { assert(stack->count >= offset + 2); struct node_parent* to_replace = stack->data[stack->count - 1 - 1 - offset]; struct node_parent* to_use = stack->data[stack->count - 1]; memcpy(to_replace, to_use, sizeof(struct node_app)); stack->count--; printf("updating\nnew size: %d\n", stack->count); } void stack_alloc(struct stack* stack, int32_t count) { assert(stack->count + count <= stack->size); for(int32_t i = 0; i < count; i++) { stack->data[stack->count++] = malloc(sizeof(struct node_app)); } } void stack_slide(struct stack* stack, int32_t count) { assert(stack->count > count); stack->data[stack->count - 1 - count] = stack->data[stack->count - 1]; stack->count -= count; } void stack_set(struct stack* stack, int32_t index, struct node_parent* parent) { assert(stack->count > index); stack->data[stack->count - 1 - index] = parent; } int32_t stack_size(struct stack* stack) { return stack->count; } struct node_parent* malloc_node_num(int32_t value) { printf("alloced num %d\n", value); struct node_num* node = malloc(sizeof(struct node_app)); node->tag = 0; node->value = value; return (struct node_parent*) node; } struct node_parent* malloc_node_app(struct node_parent* left, struct node_parent* right) { printf("allocated application\n"); struct node_app* node = malloc(sizeof(struct node_app)); node->tag = 1; node->left = left; node->right = right; return (struct node_parent*) node; } struct node_parent* malloc_node_global(int32_t arity, void (*function)(struct stack*)) { printf("allocated global with arity %d\n", arity); struct node_global* node = malloc(sizeof(struct node_app)); node->tag = 2; node->arity = arity; node->function = function; return (struct node_parent*) node; } struct node_parent* malloc_node_indirect(struct node_parent* target) { printf("allocated indirection node\n"); struct node_ind* node = malloc(sizeof(struct node_app)); node->tag = 3; node->next = target; return (struct node_parent*) node; } void unwind(struct stack* stack) { while(1) { assert(stack_size(stack) != 0); struct node_parent* node = stack_peek(stack, 0); if(node->tag == 0) { return; } else if(node->tag == 1) { printf("unwinding an application\n"); stack_push(stack, ((struct node_app*) node)->left); } else if(node->tag == 2) { struct node_global* global = (struct node_global*) node; if(stack->size > global->arity) { for(int i = 0; i < global->arity; i++) { struct node_app* app = (struct node_app*) stack_peek(stack, i + 1); stack_set(stack, i + 1, app->right); } global->function(stack); } else { stack_popn(stack, stack_size(stack) - 1); return; } } else if(node->tag == 3) { struct node_ind* ind = (struct node_ind*) node; stack_pop(stack); stack_push(stack, ind->next); } } } struct node_parent* eval(struct node_parent* start) { struct stack new_stack; stack_init(&new_stack); stack_push(&new_stack, start); unwind(&new_stack); struct node_parent* final_node = stack_pop(&new_stack); stack_free(&new_stack); return final_node; } extern void main_supercomb(struct stack* stack); int main(int argc, char** argv) { struct node_parent* result = eval(malloc_node_global(0, main_supercomb)); if(result->tag == 0) { printf("resulting number: %d\n", ((struct node_num*) result)->value); } }