#include #include #include #include #include "lceb.h" static TREE *trees=NULL; static int ntrees=0; static NODE *freenodes=NULL; static int totnodes=0; NODE *get_node() { NODE *ret; if (!freenodes) { register int i; totnodes+=ALLOCSIZE; # ifdef DEBUG_MEM printf("get_node: allocating %d new nodes - total nodes=%d\n", ALLOCSIZE, totnodes); # endif freenodes=malloc(ALLOCSIZE*sizeof(NODE)); for (i=0; ileft=NULL; (freenodes+i)->right=NULL; (freenodes+i)->next=freenodes+i+1; } (freenodes+ALLOCSIZE-1)->next=NULL; } ret=freenodes; freenodes=ret->next; ret->op=Nop; ret->val=-1; ret->eval=-1; ret->next=NULL; ret->left=NULL; ret->right=NULL; return ret; } int free_node(node) NODE *node; { int n=0; if (node->type==TREE_NODE) { # ifdef DEBUG_TREE2 printf("free tree: "); print_node(node, 3); # endif n+=free_node(node->left); node->left=NULL; n+=free_node(node->right); node->right=NULL; # ifdef DEBUG_TREE2 printf("free tree: "); print_node(node, 3); # endif } node->next=freenodes; freenodes=node; n++; return n; } int compare_nodes(node1, node2, depth) NODE *node1, *node2; int depth; { int equal=0; // we must also consider the case n1->left == n2->right, and vice-et-versa. # ifdef DEBUG_TREE if (depth==0) { printf("compare trees: [ "); print_node(node1, TREE_TOP, 0, 4); printf(" ] and [ "); print_node(node2, TREE_TOP, 0, 4); printf(" ] "); } # endif if (node1->type==node2->type) { switch (node1->type) { case TREE_LEAF: if (node1->val==node2->val) equal=1; break; case TREE_NODE: if (node1->op == node2->op) { if (compare_nodes(node1->left, node2->left, depth+1) && compare_nodes(node1->right, node2->right, depth+1)) { equal=1; } else if (compare_nodes(node1->left, node2->right, depth+1) && compare_nodes(node1->right, node2->left, depth+1)) { equal=1; } } break; } } # ifdef DEBUG_TREE if (depth==0) { printf(" = %d\n", equal); } # endif return equal; } void print_node(node, side, depth, details) NODE *node; char side; int depth; int details; { int i; if (!node) return; switch (details) { case 1: /* prefix */ if (node->type==TREE_NODE) { printf("%c ", node->op); } else { printf("%d ", node->val); } print_node(node->left, TREE_LEFT, depth+1, details); print_node(node->right, TREE_RIGHT, depth+1, details); break; case 0: /* postfix */ case 5: /* dc suitable */ print_node(node->left, TREE_LEFT, depth+1, details); print_node(node->right, TREE_RIGHT, depth+1, details); if (node->type==TREE_NODE) { printf("%c ", node->op); } else { printf("%d ", node->val); } if (details==5 && depth==0) printf("p"); break; case 3: /* lisp */ if (node->type==TREE_NODE) { if (!depth) { printf("(%c", node->op); //printf("(op"); } else { //printf(" (op"); printf(" (%c", node->op); } } else { printf(" %d", node->val); } print_node(node->left, TREE_LEFT, depth+1, details); print_node(node->right, TREE_RIGHT, depth+1, details); if (node->type==TREE_NODE) { printf(")"); } break; case 4: /* infix */ if (node->type==TREE_NODE) { printf("("); } print_node(node->left, TREE_LEFT, depth+1, details); if (node->type==TREE_NODE) { printf(" %c ", node->op); } else { printf("%d", node->val); } print_node(node->right, TREE_RIGHT, depth+1, details); if (node->type==TREE_NODE) { printf(")"); } break; case 2: /* tree */ /* left padding */ for (i=0; i<=depth; ++i) printf(" "); printf("%c: type:%s ", side, node->type==TREE_NODE? "node": "leaf"); if (details) { printf("op=%c val=%d eval=%d", node->op, node->val, node->eval); } putchar('\n'); print_node(node->left, TREE_LEFT, depth+1, details); print_node(node->right, TREE_RIGHT, depth+1, details); break;; } } void print_tree(tree, details) TREE *tree; int details; { switch (details) { case 2: print_node(tree->head, TREE_TOP, 0, details); break; case 0: case 1: case 3: case 4: //printf("Tree [%s] : ", tree->name); print_node(tree->head, TREE_TOP, 0, details); printf("\n"); break; } } void print_trees(details) int details; { TREE *tree=trees; printf("There are %d trees:\n", ntrees); while (tree) { print_tree(tree, details); tree=tree->next; } } TREE *new_tree(name) char *name; { TREE *tree; tree=malloc(sizeof(TREE)); strcpy(tree->name, name); tree->nodes=0; tree->leaves=0; tree->depth=0; tree->head=NULL; tree->next=trees; trees=tree; return tree; } NODE *dup_node(src) NODE *src; { NODE *dst; dst=get_node(); dst->type=src->type; if (src->type==TREE_NODE) { dst->op=src->op; dst->left=dup_node(src->left); dst->right=dup_node(src->right); } else { dst->val=src->val; } return dst; } /* untested - unused */ int calc_prof_node(node) NODE *node; { int left, right; if (node->type==TREE_LEAF) { return 0; } else { left=calc_prof_node(node->left); right=calc_prof_node(node->right); node->prof=MAX(left, right)+1; } return node->prof; } NODE *build_tree(desc, size) char *desc; int size; { NODE *root, *node; NODE *nodestack[1024]; /* TODO: make it dynamic */ int i, curnode=0; # ifdef DEBUG_TREE printf("tree %d desc=", ntrees); for (i=0; itype=TREE_NODE; nodestack[curnode++]=root; for(i=1; ileft = node; } else { nodestack[curnode-1]->right = node; curnode--; } if (desc[i]=='1') { node->type=TREE_NODE; nodestack[curnode++]=node; } else { node->type=TREE_LEAF; } } return root; } /* generate reduced trees from static description */ void gen_reduced_trees(n) int n; { int size=n*2+1, i; TREE *tree; char name[80]; char *seq1[]= { "100" }; char *seq2[]= { "10100" }; char *seq3[]= { "1010100", "1100100" }; char *seq4[]= { "101010100", "101100100", "110010100" }; char *seq5[]= { "10101010100", "10101100100", "10110010100", "11001010100", "11001100100", "11010010100" }; if (n<1 || n>=MAXINPUT) { fprintf(stderr, "gen_reduced_trees: wrong leaves %d\n", n); return; } # ifdef DEBUG_TREE printf("gen_reduced_trees(leaves=%d)\n", n); # endif switch (n) { case 1: ntrees++; sprintf(name, "Tree %d", ntrees); tree=new_tree(name); tree->head=build_tree(seq1[0], size); break; case 2: ntrees++; sprintf(name, "Tree %d", ntrees); tree=new_tree(name); tree->head=build_tree(seq2[0], size); break; case 3: for (i=0; i<2; ++i) { ntrees++; sprintf(name, "Tree %d", ntrees); tree=new_tree(name); tree->head=build_tree(seq3[i], size); } break; case 4: for (i=0; i<3; ++i) { ntrees++; sprintf(name, "Tree %d", ntrees); tree=new_tree(name); tree->head=build_tree(seq4[i], size); } break; case 5: for (i=0; i<6; ++i) { ntrees++; sprintf(name, "Tree %d", ntrees); tree=new_tree(name); tree->head=build_tree(seq5[i], size); } break; } return; } void gen_tree(seq, n, nb1, nb0, reduced) char *seq; int n; /* number of nodes */ int nb1; /* number of "1" */ int nb0; /* number of "0" */ int reduced; { char name[80]; TREE *tree; NODE *node; int i; # ifdef DEBUG_TREE printf("gen_tree(n=%d, nb1=%d, nb0=%d)\n", n, nb1, nb0); # endif if ((nb1 + nb0) == 2*n) { /* end */ seq[2*n] = '0'; seq[2*n+1] = 0; node=build_tree(seq, 2*n+1); if (reduced) { for (i=0; ihead, 0)) { # ifdef DEBUG_TREE printf("gen_tree: skipping unused tree (%d nodes freed)\n", free_node(node)); # else free_node(node); # endif node=NULL; break; } } } if (node) { ntrees++; sprintf(name, "Tree %d", ntrees); tree=new_tree(name); tree->head=node; } return; } if (nb1 >= nb0 && nb1 < n) { seq[nb1+nb0] = '1'; gen_tree(seq, n, nb1+1, nb0, reduced); } if(nb0 < nb1 && nb1 <=n) { seq[nb1+nb0] = '0'; gen_tree(seq, n, nb1, nb0+1, reduced); } } TREE *nth_tree(n) int n; { int i; TREE *tree=trees; for (i=0; inext; } return tree; } int n_trees() { return ntrees; } #ifdef STANDALONE int main(ac, av) int ac; char **av; { int n, details=0, type=0; char array[1024]; if (ac<3 || ac>4) { fprintf(stderr, "usage: %s type nodes [display]\n", *av); fprintf(stderr, "type : 0 for Catalan, 1 for Wedderburn\n"); fprintf(stderr, "display can be 0 (RPN, default, 1 (polish), 2 (details), 3 (lisp notation), 4 (parenthesed notation)\n"); exit (1); } if (ac==4) { details=atoi(av[3]); } type=atoi(av[1]); n=atoi(av[2]); if (type == 0) { printf("generating Calalan tree...\n"); gen_tree(array, n, 0, 0, 0); } else { printf("generating Wedderburn tree...\n"); gen_tree(array, n, 0, 0, 1); //gen_reduced_trees(n); } print_trees(details); exit(0); } #endif