#include #include #include #include #include "tree.h" /* alokuje nový uzel */ static struct expr_node *alloc_node(void) { return malloc(sizeof(struct expr_node)); } struct expr_node *node_create_const(double val) { struct expr_node *node = alloc_node(); if (!node) return NULL; node->type = EXPR_CONST; node->vals.num = val; return node; } struct expr_node *node_create_neg(struct expr_node *unop) { struct expr_node *node = alloc_node(); if (!node) return NULL; node->type = EXPR_NEG; node->vals.unop = unop; return node; } /* vytvoří uzel binární operace */ static struct expr_node *create_binary_node(enum expr_type type, struct expr_node *left, struct expr_node *right) { struct expr_node *node = alloc_node(); if (!node) return NULL; node->type = type; node->vals.binop.left = left; node->vals.binop.right = right; return node; } struct expr_node *node_create_add(struct expr_node *left, struct expr_node *right) { return create_binary_node(EXPR_ADD, left, right); } struct expr_node *node_create_sub(struct expr_node *left, struct expr_node *right) { return create_binary_node(EXPR_SUB, left, right); } struct expr_node *node_create_mult(struct expr_node *left, struct expr_node *right) { return create_binary_node(EXPR_MULT, left, right); } struct expr_node *node_create_div(struct expr_node *left, struct expr_node *right) { return create_binary_node(EXPR_DIV, left, right); } struct expr_node *node_create_pow(struct expr_node *base, struct expr_node *power) { return create_binary_node(EXPR_POW, base, power); } struct expr_node *node_create_x(void) { struct expr_node *node = alloc_node(); if (!node) return NULL; node->type = EXPR_X; return node; } struct expr_node *node_create_fn(size_t fn_idx, struct expr_node **args) { size_t i, num_args; struct expr_node *node = alloc_node(); if (!node) return NULL; node->type = EXPR_FN; node->vals.fn.fn_idx = fn_idx; num_args = fns_get()[fn_idx].num_args; for (i = 0; i < num_args; ++i) { node->vals.fn.args[i] = args[i]; } return node; } /* pro naše účely definované "nekonečno" */ #define INF (1.0e256) /* zkontroluje, zda je číslo reálné */ static int is_real(double x) { return x == x && x < INF && x > -INF; } /* vrátí výsledek vyhodnocení na základě hodnoty x */ static enum eval_result check_real(double x) { if (is_real(x)) return EVAL_OK; else return EVAL_ERROR; } #define EVAL_CHECK(node, x, y) if (node_eval((node), (x), (y)) != EVAL_OK) return EVAL_ERROR; enum eval_result node_eval(const struct expr_node *node, double x, double *y) { double tmp1, tmp2; switch (node->type) { case EXPR_CONST: *y = node->vals.num; return check_real(*y); case EXPR_X: *y = x; return check_real(*y); case EXPR_NEG: EVAL_CHECK(node->vals.unop, x, &tmp1); *y = -tmp1; return EVAL_OK; case EXPR_ADD: EVAL_CHECK(node->vals.binop.left, x, &tmp1); EVAL_CHECK(node->vals.binop.right, x, &tmp2); *y = tmp1 + tmp2; return check_real(*y); case EXPR_SUB: EVAL_CHECK(node->vals.binop.left, x, &tmp1); EVAL_CHECK(node->vals.binop.right, x, &tmp2); *y = tmp1 - tmp2; return check_real(*y); case EXPR_MULT: EVAL_CHECK(node->vals.binop.left, x, &tmp1); EVAL_CHECK(node->vals.binop.right, x, &tmp2); *y = tmp1 * tmp2; return check_real(*y); case EXPR_DIV: EVAL_CHECK(node->vals.binop.left, x, &tmp1); EVAL_CHECK(node->vals.binop.right, x, &tmp2); if (tmp2 == 0.0) return EVAL_ERROR; *y = tmp1 / tmp2; return check_real(*y); case EXPR_POW: EVAL_CHECK(node->vals.binop.left, x, &tmp1); EVAL_CHECK(node->vals.binop.right, x, &tmp2); errno = 0; *y = pow(tmp1, tmp2); if (errno) return EVAL_ERROR; return check_real(*y); case EXPR_FN: { double inner_results[MAX_MATH_FUNCTION_ARGS]; size_t i; const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx]; for (i = 0; i < fn->num_args; ++i) { EVAL_CHECK(node->vals.fn.args[i], x, &inner_results[i]); } return fn->ptr(y, inner_results); } } return 0.0; } #ifdef ENABLE_GRAPHVIZ_EXPORT static void debug_print_gv(const struct expr_node *node, FILE *output); static void debug_print_binop_gv(const struct expr_node *node, FILE *output, const char *name) { fprintf(output, "node%p [label=\"%s\"]\n", (void*)node, name); debug_print_gv(node->vals.binop.left, output); debug_print_gv(node->vals.binop.right, output); fprintf(output, "node%p -> node%p [label=left]\n", (void*)node, (void*)node->vals.binop.left); fprintf(output, "node%p -> node%p [label=right]\n", (void*)node, (void*)node->vals.binop.right); } static void debug_print_gv(const struct expr_node *node, FILE *output) { switch (node->type) { case EXPR_ADD: debug_print_binop_gv(node, output, "ADD"); break; case EXPR_SUB: debug_print_binop_gv(node, output, "SUB"); break; case EXPR_MULT: debug_print_binop_gv(node, output, "MULT"); break; case EXPR_DIV: debug_print_binop_gv(node, output, "DIV"); break; case EXPR_POW: debug_print_binop_gv(node, output, "POW"); break; case EXPR_NEG: fprintf(output, "node%p [label=\"NEG\"]\n", (void*)node); debug_print_gv(node->vals.unop, output); fprintf(output, "node%p -> node%p [label=unop]\n", (void*)node, (void*)node->vals.unop); break; case EXPR_CONST: fprintf(output, "node%p [label=\"CONST: %.2f\"]\n", (void*)node, node->vals.num); break; case EXPR_X: fprintf(output, "node%p [label=\"X\"]\n", (void*)node); break; case EXPR_FN: { size_t i; const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx]; fprintf(output, "node%p [label=\"FN: %s\"]\n", (void*)node, fn->name); for (i = 0; i < fn->num_args; ++i) { struct expr_node *arg = node->vals.fn.args[i]; debug_print_gv(arg, output); fprintf(output, "node%p -> node%p [label=arg%d]\n", (void*)node, (void*)arg, (int)i + 1); } break; } default: break; } } void node_debug_print_gv(const struct expr_node *node, FILE *output) { fprintf(output, "digraph G {\n"); debug_print_gv(node, output); fprintf(output, "}\n"); } #endif /* ENABLE_GRAPHVIZ_EXPORT */ void node_free(struct expr_node *node) { if (!node) return; switch (node->type) { case EXPR_ADD: case EXPR_SUB: case EXPR_MULT: case EXPR_DIV: case EXPR_POW: node_free(node->vals.binop.left); node_free(node->vals.binop.right); break; case EXPR_NEG: node_free(node->vals.unop); break; case EXPR_FN: { size_t i, num_args = fns_get()[node->vals.fn.fn_idx].num_args; for (i = 0; i < num_args; ++i) { node_free(node->vals.fn.args[i]); } } break; default: break; } free(node); }