#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#define read_num(m) ((int) read(m))
#define write_num(m, num) write(m, (void*)(num))
typedef enum {ADD, MUL} binop_t;
typedef struct tree_node_s {
enum {NUM, BINOP} kind;
union {
modref_t* num;
struct {
binop_t binop;
modref_t* left;
modref_t* right;
} binop;
} u;
} tree_node_t;
void tree_print_rec(FILE* file, tree_node_t* node) {
const char* binop_syms[] = {"+", "*"};
if(node->kind == NUM) {
fprintf(file, "%d", modref_deref(node->u.num));
}
else if(node->kind == BINOP) {
fprintf(file, "(");
tree_print_rec(file, modref_deref(node->u.binop.left));
fprintf(file, " %s ", binop_syms[node->u.binop.binop]);
tree_print_rec(file, modref_deref(node->u.binop.right));
fprintf(file, ")");
}
}
void tree_print(FILE* file, tree_node_t* tree) {
fprintf(file, "tree = ");
tree_print_rec(file, tree);
fprintf(file, "\n");
}
afun tree_eval(tree_node_t* node, modref_t* result) {
if(node->kind == NUM) {
write_num(result, read_num(node->u.num));
}
else if(node->kind == BINOP) {
modref_t *result_left = modref();
tree_eval(read(node->u.binop.left), result_left);
modref_t *result_right = modref();
tree_eval(read(node->u.binop.right), result_right);
if(node->u.binop.binop == ADD) {
write_num(result, read_num(result_left) + read_num(result_right));
}
else if(node->u.binop.binop == MUL) {
write_num(result, read_num(result_left) * read_num(result_right));
}
else {
abort();
}
}
else {
abort();
}
}
ifun node_num_init(tree_node_t* node) {
node->kind = NUM;
node->u.num = modref();
}
tree_node_t* Node_Num(int num) {
tree_node_t* node = alloc(sizeof(tree_node_t), node_num_init);
write_num(node->u.num, num);
return node;
}
ifun node_binop_init(tree_node_t* node, binop_t binop) {
node->kind = BINOP;
node->u.binop.binop = binop;
node->u.binop.left = modref();
node->u.binop.right = modref();
}
tree_node_t* Node_Binop(binop_t binop) {
return alloc(sizeof(tree_node_t), node_binop_init, binop);
}
int tree_rand(int nodes, modref_t* tree) {
if(nodes < 3) {
write(tree, Node_Num(rand() % 10));
return nodes - 1;
}
else {
tree_node_t* binop_node = Node_Binop(rand() % 2);
int a = (nodes - 1) / 2;
int b = (nodes - 1) - a;
int c = tree_rand(a, binop_node->u.binop.left);
int d = tree_rand(b + c, binop_node->u.binop.right);
write(tree, binop_node);
return d;
}
}
int tree_get_nodes(tree_node_t* node, tree_node_t** nodev, int nodec) {
nodev[nodec++] = node;
if(node->kind == NUM) {
return nodec;
}
else if(node->kind == BINOP) {
nodec = tree_get_nodes(modref_deref(node->u.binop.left), nodev, nodec);
nodec = tree_get_nodes(modref_deref(node->u.binop.right), nodev, nodec);
return nodec;
}
else {
abort();
return -1;
}
}
int main(int argc, char** argv)
{
int TREE_SIZE = 16;
slime_t* slime = slime_open();
modref_t* input_tree = modref();
modref_t* result = modref();
srand(0);
tree_rand(TREE_SIZE, input_tree);
tree_print(stdout, modref_deref(input_tree));
tree_eval(read(input_tree), result);
fprintf(stdout, " = %d\n\n", modref_deref(result));
{
tree_node_t** nodev = malloc(sizeof(tree_node_t*) * TREE_SIZE);
int nodec = tree_get_nodes(modref_deref(input_tree), nodev, 0);
int i;
fprintf(stdout, "changing each number in tree, then changing it back ...\n");
for(i = 0; i < nodec; i++) {
if(nodev[i]->kind == NUM) {
int old_result = (int) modref_deref(result);
int old_num = (int) modref_deref(nodev[i]->u.num);
int new_num = rand() % 10;
slime_meta_start();
write_num(nodev[i]->u.num, new_num);
slime_propagate();
tree_print(stdout, modref_deref(input_tree));
fprintf(stdout, " = %d\n", modref_deref(result));
slime_meta_start();
write_num(nodev[i]->u.num, old_num);
slime_propagate();
tree_print(stdout, modref_deref(input_tree));
fprintf(stdout, " = %d\n\n", modref_deref(result));
assert((int) modref_deref(result) == old_result);
}
}
}
slime_close(slime);
return 0;
}