Compare commits
5 Commits
c50551dca8
...
49598cfda3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49598cfda3 | ||
|
|
5742e9af6b | ||
|
|
6e155817dd | ||
|
|
c7eaae547b | ||
|
|
e9beb1c292 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ build/
|
||||
*.png
|
||||
*.svg
|
||||
*.ps
|
||||
*.pdf
|
||||
|
||||
@ -9,12 +9,12 @@
|
||||
* @brief Chybové kódy
|
||||
*/
|
||||
enum error_code {
|
||||
ERR_NO_ERR = 0, ///< Žádná chyba
|
||||
ERR_INVALID_ARGS = 1, ///< Neplatné argumenty programu
|
||||
ERR_INVALID_FUNCTION = 2, ///< Zadaná matematická funkce je neplatná
|
||||
ERR_INVALID_FILENAME = 3, ///< Zadaný název souboru není platný
|
||||
ERR_INVALID_LIMITS = 4, ///< Zadané hranice jsou ve špatném formátu
|
||||
ERR_BAD_ALLOC = 5 ///< Při alokaci paměti nastala chyba
|
||||
ERR_NO_ERR = 0, /* Žádná chyba */
|
||||
ERR_INVALID_ARGS = 1, /* Neplatné argumenty programu */
|
||||
ERR_INVALID_FUNCTION = 2, /* Zadaná matematická funkce je neplatná */
|
||||
ERR_INVALID_FILENAME = 3, /* Zadaný název souboru není platný */
|
||||
ERR_INVALID_LIMITS = 4, /* Zadané hranice jsou ve špatném formátu */
|
||||
ERR_BAD_ALLOC = 5 /* Při alokaci paměti nastala chyba */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
16
lex.c
16
lex.c
@ -212,19 +212,3 @@ const char *lex_token_str(enum token_type token) {
|
||||
default: return "<unknown token>";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LEX_DEBUG
|
||||
|
||||
void lex_debug_print_token(const struct token *tok) {
|
||||
printf("%-20s ", lex_token_str(tok->type));
|
||||
|
||||
if (tok->type == TOK_NUMBER)
|
||||
printf("%.2f\n", tok->val.num);
|
||||
else if (tok->type == TOK_FUNCTION) {
|
||||
printf("%s\n", fns_get()[tok->val.fn_idx].name);
|
||||
}
|
||||
else
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
#endif /* LEX_DEBUG */
|
||||
|
||||
4
lex.h
4
lex.h
@ -114,8 +114,4 @@ const char *lex_get_error_text(const struct lexer *lex);
|
||||
*/
|
||||
const char *lex_token_str(enum token_type token);
|
||||
|
||||
#ifdef LEX_DEBUG
|
||||
void lex_debug_print_token(const struct token *tok);
|
||||
#endif /* LEX_DEBUG */
|
||||
|
||||
#endif /* LEX_H */
|
||||
29
main.c
29
main.c
@ -44,7 +44,7 @@ static int parse_range(const char *str, struct graph_range *range) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static enum error_code export_to_file(const struct expr_node *node, const struct graph_range *range, const char *out_name) {
|
||||
static enum error_code export_to_file(const struct expr_node *node, const struct graph_range *range, const char *function, const char *out_name) {
|
||||
FILE *file;
|
||||
|
||||
if (!(file = fopen(out_name, "w"))) {
|
||||
@ -52,12 +52,27 @@ static enum error_code export_to_file(const struct expr_node *node, const struct
|
||||
return ERR_INVALID_FILENAME;
|
||||
}
|
||||
|
||||
ps_export_graph(file, node, range);
|
||||
ps_generate_graph(file, node, range, function);
|
||||
|
||||
fclose(file);
|
||||
return ERR_NO_ERR;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_GRAPHVIZ_EXPORT
|
||||
static void export_gv(const struct expr_node *node, const char *out_name) {
|
||||
FILE *file;
|
||||
|
||||
if (!(file = fopen(out_name, "w"))) {
|
||||
fprintf(stderr, "GV: Cannot open \"%s\" for writing!\n", out_name);
|
||||
return;
|
||||
}
|
||||
|
||||
node_debug_print_gv(node, file);
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
#endif /* ENABLE_GRAPHVIZ_EXPORT */
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
enum error_code err;
|
||||
struct parser parser;
|
||||
@ -72,7 +87,7 @@ int main(int argc, char *argv[]) {
|
||||
if (argc > 3) {
|
||||
if (!parse_range(argv[3], &range)) {
|
||||
fprintf(stderr, "Invalid format of ranges! The correct format is \"xMin:xMax:yMin:yMax\".\n");
|
||||
return ERR_INVALID_ARGS;
|
||||
return ERR_INVALID_LIMITS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -89,11 +104,11 @@ int main(int argc, char *argv[]) {
|
||||
return parser_get_error(&parser);
|
||||
}
|
||||
|
||||
err = export_to_file(node, &range, argv[2]);
|
||||
err = export_to_file(node, &range, argv[1], argv[2]);
|
||||
|
||||
/* file = fopen("graph.dot", "w");
|
||||
node_debug_print_gv(node, file);
|
||||
fclose(file); */
|
||||
#ifdef ENABLE_GRAPHVIZ_EXPORT
|
||||
export_gv(node, "graph.dot");
|
||||
#endif /* ENABLE_GRAPHVIZ_EXPORT */
|
||||
|
||||
node_free(node);
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ MAKE_FUNCTION_1_ARG(tanh)
|
||||
MAKE_FUNCTION_1_ARG(floor)
|
||||
MAKE_FUNCTION_1_ARG(ceil)
|
||||
|
||||
static double mf_sgn(double *y, const double *args) {
|
||||
static enum eval_result mf_sgn(double *y, const double *args) {
|
||||
if (args[0] < 0.0)
|
||||
*y = -1.0;
|
||||
else if (args[0] > 0.0)
|
||||
@ -39,7 +39,7 @@ static double mf_sgn(double *y, const double *args) {
|
||||
return EVAL_OK;
|
||||
}
|
||||
|
||||
static double mf_min(double *y, const double *args) {
|
||||
static enum eval_result mf_min(double *y, const double *args) {
|
||||
if (args[0] < args[1])
|
||||
*y = args[0];
|
||||
else
|
||||
@ -48,7 +48,7 @@ static double mf_min(double *y, const double *args) {
|
||||
return EVAL_OK;
|
||||
}
|
||||
|
||||
static double mf_max(double *y, const double *args) {
|
||||
static enum eval_result mf_max(double *y, const double *args) {
|
||||
if (args[0] > args[1])
|
||||
*y = args[0];
|
||||
else
|
||||
@ -57,7 +57,7 @@ static double mf_max(double *y, const double *args) {
|
||||
return EVAL_OK;
|
||||
}
|
||||
|
||||
static double mf_mod(double *y, const double *args) {
|
||||
static enum eval_result mf_mod(double *y, const double *args) {
|
||||
errno = 0;
|
||||
*y = fmod(args[0], args[1]);
|
||||
|
||||
|
||||
34
parser.c
34
parser.c
@ -1,5 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "parser.h"
|
||||
|
||||
/* Vrátí ukazatel na aktuální token */
|
||||
@ -42,8 +43,9 @@ static void error_bad_alloc(struct parser *parser) {
|
||||
error_printf(&parser->eb, "Out of memory\n");
|
||||
}
|
||||
|
||||
static void error_expected_one_of(struct parser *parser, const int expected[]) {
|
||||
static void error_expected_tokens(struct parser *parser, size_t num_tokens, ...) {
|
||||
size_t i;
|
||||
va_list ap;
|
||||
|
||||
enum token_type got = get_token(parser)->type;
|
||||
|
||||
@ -56,24 +58,22 @@ static void error_expected_one_of(struct parser *parser, const int expected[]) {
|
||||
error_set(&parser->eb, ERR_INVALID_FUNCTION);
|
||||
error_printf(&parser->eb, "Syntax error - expected ");
|
||||
|
||||
for (i = 0; expected[i] >= 0; ++i) {
|
||||
va_start(ap, num_tokens);
|
||||
for (i = 0; i < num_tokens; ++i) {
|
||||
enum token_type tok = va_arg(ap, enum token_type);
|
||||
|
||||
if (i > 0)
|
||||
error_printf(&parser->eb, ", ");
|
||||
|
||||
error_printf(&parser->eb, "%s", lex_token_str(expected[i]));
|
||||
error_printf(&parser->eb, "%s", lex_token_str(tok));
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
error_printf(&parser->eb, " - but got %s\n", lex_token_str(got));
|
||||
|
||||
lex_print_position(&parser->lexer, &parser->eb);
|
||||
}
|
||||
|
||||
static void error_expected_single(struct parser *parser, enum token_type expected) {
|
||||
static int expected_arr[] = { -1, -1 };
|
||||
expected_arr[0] = expected;
|
||||
error_expected_one_of(parser, expected_arr);
|
||||
}
|
||||
|
||||
static struct expr_node* parse_subexpression(struct parser *parser);
|
||||
int parse_n_expressions(struct parser *parser, struct expr_node **out_nodes, size_t n);
|
||||
|
||||
@ -81,7 +81,7 @@ static struct expr_node* parse_bracketed(struct parser *parser) {
|
||||
struct expr_node* node;
|
||||
|
||||
if (!accept_token(parser, TOK_LEFT_PAREN)) {
|
||||
error_expected_single(parser, TOK_LEFT_PAREN);
|
||||
error_expected_tokens(parser, 1, TOK_LEFT_PAREN);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ static struct expr_node* parse_bracketed(struct parser *parser) {
|
||||
return NULL;
|
||||
|
||||
if (!accept_token(parser, TOK_RIGHT_PAREN)) {
|
||||
error_expected_single(parser, TOK_RIGHT_PAREN);
|
||||
error_expected_tokens(parser, 1, TOK_RIGHT_PAREN);
|
||||
node_free(node);
|
||||
return NULL;
|
||||
}
|
||||
@ -128,7 +128,7 @@ static struct expr_node *parse_base(struct parser *parser) {
|
||||
next_token(parser);
|
||||
|
||||
if (!accept_token(parser, TOK_LEFT_PAREN)) {
|
||||
error_expected_single(parser, TOK_LEFT_PAREN);
|
||||
error_expected_tokens(parser, 1, TOK_LEFT_PAREN);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ static struct expr_node *parse_base(struct parser *parser) {
|
||||
}
|
||||
|
||||
if (!accept_token(parser, TOK_RIGHT_PAREN)) {
|
||||
error_expected_single(parser, TOK_RIGHT_PAREN);
|
||||
error_expected_tokens(parser, 1, TOK_RIGHT_PAREN);
|
||||
node_free(node);
|
||||
return NULL;
|
||||
}
|
||||
@ -157,11 +157,7 @@ static struct expr_node *parse_base(struct parser *parser) {
|
||||
return parse_bracketed(parser);
|
||||
}
|
||||
|
||||
{
|
||||
static const int expected[] = { TOK_NUMBER, TOK_VARIABLE, TOK_FUNCTION, TOK_LEFT_PAREN, -1 };
|
||||
error_expected_one_of(parser, expected);
|
||||
}
|
||||
|
||||
error_expected_tokens(parser, 4, TOK_NUMBER, TOK_VARIABLE, TOK_FUNCTION, TOK_LEFT_PAREN);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -317,7 +313,7 @@ int parser_parse_n(struct parser *parser, const char *str, const char *variable_
|
||||
|
||||
if (!token_is(parser, TOK_EOF)) {
|
||||
size_t i;
|
||||
error_expected_single(parser, TOK_EOF);
|
||||
error_expected_tokens(parser, 1, TOK_EOF);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
node_free(out_nodes[i]);
|
||||
|
||||
160
ps_graph.c
160
ps_graph.c
@ -1,18 +1,77 @@
|
||||
#include "ps_graph.h"
|
||||
#include <math.h>
|
||||
|
||||
#define TEMP_BUF_SIZE 128
|
||||
|
||||
/* rozměry grafu */
|
||||
#define GRAPH_SIZE 400
|
||||
#define HALF_GRAPH_SIZE (GRAPH_SIZE / 2)
|
||||
|
||||
#define GRAPH_CENTER_X 306
|
||||
#define GRAPH_CENTER_Y 500
|
||||
|
||||
/* písmo */
|
||||
#define FONT "Helvetica"
|
||||
#define FONT_SIZE_HEADER 15
|
||||
#define FONT_SIZE_LABEL 12
|
||||
#define FONT_SIZE_VALUE 9
|
||||
|
||||
#define GRID_STEP (GRAPH_SIZE / 10)
|
||||
|
||||
/* posuny popisků */
|
||||
#define HEADER_OFFSET_Y (10)
|
||||
|
||||
#define X_VAL_OFFSET_X (0)
|
||||
#define X_VAL_OFFSET_Y (-13)
|
||||
|
||||
#define Y_VAL_OFFSET_X (-5)
|
||||
#define Y_VAL_OFFSET_Y (-3)
|
||||
|
||||
#define X_LABEL_OFFSET_X (0)
|
||||
#define X_LABEL_OFFSET_Y (-30)
|
||||
|
||||
#define Y_LABEL_OFFSET_X (-40)
|
||||
#define Y_LABEL_OFFSET_Y (-3)
|
||||
|
||||
/* počet částí grafu funkce */
|
||||
#define FUNCTION_SEGMENTS 1000
|
||||
|
||||
void ps_export_graph(FILE *file, const struct expr_node *node, const struct graph_range *range) {
|
||||
int i;
|
||||
double x;
|
||||
int first = 1;
|
||||
/* koeficienty pro zarovnání textu */
|
||||
#define ALIGN_CENTER (-0.5)
|
||||
#define ALIGN_RIGHT (-1.0)
|
||||
|
||||
static void generate_text_align(FILE *file, int x, int y, double alignment, const char *str) {
|
||||
fprintf(file,
|
||||
"newpath\n"
|
||||
/* posun na cílovou pozici */
|
||||
"%d %d moveto\n"
|
||||
/* vložení dvou řetězců s popiskem */
|
||||
"(%s) dup\n"
|
||||
/* zjištění šířky a výšky řetežce, odstranění výšky ze zásobníku (nezajímá) */
|
||||
"stringwidth pop\n"
|
||||
/* koeficient pro zarovnání */
|
||||
"%f mul\n"
|
||||
/* posun o šířku doleva */
|
||||
"0 rmoveto\n"
|
||||
/* zobrazení řetězce */
|
||||
"show\n"
|
||||
"\n",
|
||||
x, y, str, alignment
|
||||
);
|
||||
}
|
||||
|
||||
static void set_font(FILE *file, const char *font, int size) {
|
||||
fprintf(file,
|
||||
"/%s findfont\n"
|
||||
"%d scalefont\n"
|
||||
"setfont\n",
|
||||
font, size
|
||||
);
|
||||
}
|
||||
|
||||
static void generate_grid(FILE *file, const struct graph_range *range) {
|
||||
int i;
|
||||
fprintf(file,
|
||||
"306 500 translate\n"
|
||||
"2 setlinewidth\n"
|
||||
"/gridline {\n"
|
||||
" .5 setlinewidth\n"
|
||||
@ -26,62 +85,38 @@ void ps_export_graph(FILE *file, const struct expr_node *node, const struct grap
|
||||
"\n"
|
||||
);
|
||||
|
||||
/* mrizka */
|
||||
for (i = -HALF_GRAPH_SIZE + GRID_STEP; i < HALF_GRAPH_SIZE; i += GRID_STEP) {
|
||||
fprintf(file, "%5d 0 %5d %5d gridline\n", GRAPH_SIZE, -HALF_GRAPH_SIZE, i);
|
||||
fprintf(file, " 0 %5d %5d %5d gridline\n", GRAPH_SIZE, i, -HALF_GRAPH_SIZE);
|
||||
}
|
||||
|
||||
/* popisky */
|
||||
fprintf(file,
|
||||
"/Arial findfont\n"
|
||||
"12 scalefont\n"
|
||||
"setfont\n"
|
||||
);
|
||||
set_font(file, FONT, FONT_SIZE_VALUE);
|
||||
|
||||
/* hodnoty */
|
||||
for (i = -HALF_GRAPH_SIZE; i <= HALF_GRAPH_SIZE; i += GRID_STEP) {
|
||||
double inorm = (double)i / (double)GRAPH_SIZE + 0.5;
|
||||
double xval = range->xmax * inorm + range->xmin * (1.0 - inorm);
|
||||
double yval = range->ymax * inorm + range->ymin * (1.0 - inorm);
|
||||
char buf[TEMP_BUF_SIZE];
|
||||
|
||||
fprintf(file,
|
||||
"newpath\n"
|
||||
"%d %d moveto\n"
|
||||
"(%.2f) dup\n"
|
||||
"stringwidth pop neg\n"
|
||||
"0 rmoveto\n"
|
||||
"-10 -3 rmoveto\n"
|
||||
"show\n"
|
||||
"\n",
|
||||
-HALF_GRAPH_SIZE, i, yval
|
||||
);
|
||||
/* hodnota osy y */
|
||||
snprintf(buf, TEMP_BUF_SIZE, "%.2f", yval);
|
||||
generate_text_align(file, -HALF_GRAPH_SIZE + Y_VAL_OFFSET_X, i + Y_VAL_OFFSET_Y, ALIGN_RIGHT, buf);
|
||||
|
||||
fprintf(file,
|
||||
"newpath\n"
|
||||
"%d %d moveto\n"
|
||||
"(%.2f) dup\n"
|
||||
"stringwidth pop\n"
|
||||
"2 div neg\n"
|
||||
"-20 rmoveto\n"
|
||||
"show\n"
|
||||
"\n",
|
||||
i, -HALF_GRAPH_SIZE, xval
|
||||
);
|
||||
/* hodnota osy x */
|
||||
snprintf(buf, TEMP_BUF_SIZE, "%.2f", xval);
|
||||
generate_text_align(file, i + X_VAL_OFFSET_X, -HALF_GRAPH_SIZE + X_VAL_OFFSET_Y, ALIGN_CENTER, buf);
|
||||
|
||||
}
|
||||
|
||||
fprintf(file,
|
||||
"[] 0 setdash\n"
|
||||
"newpath\n"
|
||||
"%d %d moveto\n"
|
||||
"%d 0 rlineto\n"
|
||||
"0 %d rlineto\n"
|
||||
"%d 0 rlineto\n"
|
||||
"closepath\n"
|
||||
"gsave\n"
|
||||
"clip\n",
|
||||
-HALF_GRAPH_SIZE, -HALF_GRAPH_SIZE, GRAPH_SIZE, GRAPH_SIZE, -GRAPH_SIZE
|
||||
);
|
||||
set_font(file, FONT, FONT_SIZE_LABEL);
|
||||
generate_text_align(file, -HALF_GRAPH_SIZE + Y_LABEL_OFFSET_X, Y_LABEL_OFFSET_Y, ALIGN_RIGHT, "y");
|
||||
generate_text_align(file, X_LABEL_OFFSET_X, -HALF_GRAPH_SIZE + X_LABEL_OFFSET_Y, ALIGN_CENTER, "x");
|
||||
}
|
||||
|
||||
static void generate_function(FILE *file, const struct expr_node *node, const struct graph_range *range) {
|
||||
int i;
|
||||
int first = 1;
|
||||
|
||||
fprintf(file,
|
||||
"2 setlinewidth\n"
|
||||
@ -92,7 +127,7 @@ void ps_export_graph(FILE *file, const struct expr_node *node, const struct grap
|
||||
for (i = 0; i < FUNCTION_SEGMENTS; ++i) {
|
||||
const char *cmd = "lineto";
|
||||
double xpos, ypos;
|
||||
double y;
|
||||
double x, y;
|
||||
|
||||
x = range->xmin + (range->xmax - range->xmin) * (double)i / (double)FUNCTION_SEGMENTS;
|
||||
|
||||
@ -115,6 +150,35 @@ void ps_export_graph(FILE *file, const struct expr_node *node, const struct grap
|
||||
fprintf(file,
|
||||
"stroke\n"
|
||||
);
|
||||
}
|
||||
|
||||
void ps_generate_graph(FILE *file, const struct expr_node *node, const struct graph_range *range, const char *function) {
|
||||
char buf[TEMP_BUF_SIZE];
|
||||
|
||||
fprintf(file, "%d %d translate\n", GRAPH_CENTER_X, GRAPH_CENTER_Y);
|
||||
|
||||
if (function) {
|
||||
set_font(file, FONT, FONT_SIZE_HEADER);
|
||||
snprintf(buf, TEMP_BUF_SIZE, "y = %s", function);
|
||||
generate_text_align(file, 0, HALF_GRAPH_SIZE + HEADER_OFFSET_Y, ALIGN_CENTER, buf);
|
||||
}
|
||||
|
||||
generate_grid(file, range);
|
||||
|
||||
fprintf(file,
|
||||
"[] 0 setdash\n"
|
||||
"newpath\n"
|
||||
"%d %d moveto\n"
|
||||
"%d 0 rlineto\n"
|
||||
"0 %d rlineto\n"
|
||||
"%d 0 rlineto\n"
|
||||
"closepath\n"
|
||||
"gsave\n"
|
||||
"clip\n",
|
||||
-HALF_GRAPH_SIZE, -HALF_GRAPH_SIZE, GRAPH_SIZE, GRAPH_SIZE, -GRAPH_SIZE
|
||||
);
|
||||
|
||||
generate_function(file, node, range);
|
||||
|
||||
fprintf(file,
|
||||
"grestore\n"
|
||||
@ -122,6 +186,4 @@ void ps_export_graph(FILE *file, const struct expr_node *node, const struct grap
|
||||
"0 0 0 setrgbcolor\n"
|
||||
"stroke\n"
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
@ -9,6 +9,6 @@ struct graph_range {
|
||||
double ymin, ymax;
|
||||
};
|
||||
|
||||
extern void ps_export_graph(FILE *file, const struct expr_node *node, const struct graph_range *range);
|
||||
extern void ps_generate_graph(FILE *file, const struct expr_node *node, const struct graph_range *range, const char *function);
|
||||
|
||||
#endif
|
||||
292
tree.c
292
tree.c
@ -75,187 +75,6 @@ struct expr_node *node_create_fn(size_t fn_idx, struct expr_node **args) {
|
||||
return node;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void debug_indent(int indent) {
|
||||
int i;
|
||||
for (i = 0; i < indent; ++i)
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
static void debug_print(struct expr_node *node, int indent);
|
||||
|
||||
static void debug_print_binop(struct expr_node *node, const char* name, int indent) {
|
||||
debug_indent(indent); printf("[%s]\n", name);
|
||||
debug_print(node->vals.binop.left, indent + 1);
|
||||
debug_print(node->vals.binop.right, indent + 1);
|
||||
}
|
||||
|
||||
static void debug_print(struct expr_node *node, int indent) {
|
||||
|
||||
switch (node->type) {
|
||||
case EXPR_ADD:
|
||||
debug_print_binop(node, "ADD", indent);
|
||||
break;
|
||||
|
||||
case EXPR_SUB:
|
||||
debug_print_binop(node, "SUB", indent);
|
||||
break;
|
||||
|
||||
case EXPR_MULT:
|
||||
debug_print_binop(node, "MULT", indent);
|
||||
break;
|
||||
|
||||
case EXPR_DIV:
|
||||
debug_print_binop(node, "DIV", indent);
|
||||
break;
|
||||
|
||||
case EXPR_POW:
|
||||
debug_print_binop(node, "POW", indent);
|
||||
break;
|
||||
|
||||
case EXPR_NEG:
|
||||
debug_indent(indent); printf("[NEG]\n");
|
||||
debug_print(node->vals.unop, indent + 1);
|
||||
break;
|
||||
|
||||
case EXPR_CONST:
|
||||
debug_indent(indent); printf("[CONST] %.2f\n", node->vals.num);
|
||||
break;
|
||||
|
||||
case EXPR_X:
|
||||
debug_indent(indent); printf("[X]\n");
|
||||
|
||||
break;
|
||||
|
||||
case EXPR_FN:
|
||||
{
|
||||
size_t i;
|
||||
const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx];
|
||||
debug_indent(indent); printf("[FN] %s\n", fn->name);
|
||||
|
||||
for (i = 0; i < fn->num_args; ++i) {
|
||||
debug_print(node->vals.fn.args[i], indent + 1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void node_debug_print(struct expr_node *node) {
|
||||
debug_print(node, 0);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
#define INF (1.0e256)
|
||||
|
||||
static int is_real(double x) {
|
||||
@ -346,3 +165,114 @@ enum eval_result node_eval(const struct expr_node *node, double x, double *y) {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
7
tree.h
7
tree.h
@ -115,9 +115,6 @@ struct expr_node *node_create_x(void);
|
||||
*/
|
||||
struct expr_node *node_create_fn(size_t fn_idx, struct expr_node **args);
|
||||
|
||||
void node_debug_print(struct expr_node *node);
|
||||
void node_debug_print_gv(const struct expr_node *node, FILE *output);
|
||||
|
||||
/**
|
||||
* @brief Vyhodnotí uzel
|
||||
*
|
||||
@ -128,6 +125,10 @@ void node_debug_print_gv(const struct expr_node *node, FILE *output);
|
||||
*/
|
||||
enum eval_result node_eval(const struct expr_node *node, double x, double *y);
|
||||
|
||||
#ifdef ENABLE_GRAPHVIZ_EXPORT
|
||||
void node_debug_print_gv(const struct expr_node *node, FILE *output);
|
||||
#endif /* ENABLE_GRAPHVIZ_EXPORT */
|
||||
|
||||
/**
|
||||
* @brief Uvolní uzel
|
||||
*
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user