diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbce466 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.vs/ +.vscode/ +build/ +*.cppcheck +*.dot +*.png +*.svg +*.ps \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d6d934..8e8a3fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,9 @@ else() target_compile_options(Graph PRIVATE -Wall -Wextra -pedantic) endif() +# link math +target_link_libraries(Graph PRIVATE m) + # Optionally, set the output directory for the executable # set_target_properties(Graph PROPERTIES # RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" diff --git a/lex.c b/lex.c index 37067d5..7283047 100644 --- a/lex.c +++ b/lex.c @@ -130,7 +130,7 @@ struct token *lex_token(struct lexer *lex) { return &lex->tok; } -void lex_print_position(struct lexer *lex) { +void lex_print_position(const struct lexer *lex) { int i; int pos = lex->prev_p - lex->start; @@ -146,7 +146,7 @@ void lex_print_position(struct lexer *lex) { #ifdef LEX_DEBUG -void lex_debug_print_token(struct token *tok) { +void lex_debug_print_token(const struct token *tok) { static const char *token_str[] = { "TOK_EOF", "TOK_ERROR", @@ -162,28 +162,30 @@ void lex_debug_print_token(struct token *tok) { "TOK_RIGHT_PAREN" }; - static const char *fn_str[] = { - "FN_ABS", - "FN_EXP", - "FN_LN", - "FN_LOG", - "FN_SIN", - "FN_COS", - "FN_TAN", - "FN_ASIN", - "FN_ACOS", - "FN_ATAN", - "FN_SINH", - "FN_COSH", - "FN_TANH" - }; printf("%-20s ", token_str[tok->type]); if (tok->type == TOK_NUMBER) printf("%.2f\n", tok->val.num); - else if (tok->type == TOK_FUNCTION) + else if (tok->type == TOK_FUNCTION) { + static const char *fn_str[] = { + "FN_ABS", + "FN_EXP", + "FN_LN", + "FN_LOG", + "FN_SIN", + "FN_COS", + "FN_TAN", + "FN_ASIN", + "FN_ACOS", + "FN_ATAN", + "FN_SINH", + "FN_COSH", + "FN_TANH" + }; + printf("%s\n", fn_str[tok->val.fn]); + } else printf("\n"); } diff --git a/lex.h b/lex.h index cc5dca6..503660c 100644 --- a/lex.h +++ b/lex.h @@ -51,11 +51,11 @@ extern void lex_free(struct lexer *lex); extern void lex_next(struct lexer *lex); extern struct token *lex_token(struct lexer *lex); -extern void lex_print_position(struct lexer *lex); +extern void lex_print_position(const struct lexer *lex); #ifdef LEX_DEBUG -extern void lex_debug_print_token(struct token *tok); +extern void lex_debug_print_token(const struct token *tok); #endif /* LEX_DEBUG */ #endif /* LEX_H */ \ No newline at end of file diff --git a/main.c b/main.c index 164963b..c46f9d4 100644 --- a/main.c +++ b/main.c @@ -32,9 +32,14 @@ int main(int argc, char *argv[]) { file = fopen("out.ps", "w"); ps_export_graph(file, node, &graph); fclose(file); + + file = fopen("graph.dot", "w"); + node_debug_print_gv(node, file); + fclose(file); + + node_free(node); } - node_free(node); return 0; } \ No newline at end of file diff --git a/parser.c b/parser.c index 6855ba4..5c457ce 100644 --- a/parser.c +++ b/parser.c @@ -84,8 +84,8 @@ static struct expr_node* parse_bracketed(struct lexer* lex) { return node; } -static struct expr_node* parse_base(struct lexer* lex) { - struct expr_node* inner; +static struct expr_node *parse_base(struct lexer *lex) { + struct expr_node *node, *inner; if (token_is(lex, TOK_NUMBER)) { double val = token_num(lex); @@ -104,7 +104,11 @@ static struct expr_node* parse_base(struct lexer* lex) { if (!(inner = parse_bracketed(lex))) return NULL; - return node_create_fn(fn, inner); + if (!(node = node_create_fn(fn, inner))) { + node_free(inner); + } + + return node; } if (token_is(lex, TOK_LEFT_PAREN)) { diff --git a/ps_graph.c b/ps_graph.c index 85ac994..3aea447 100644 --- a/ps_graph.c +++ b/ps_graph.c @@ -4,7 +4,7 @@ #define HALF_GRAPH_SIZE (GRAPH_SIZE / 2) #define GRID_STEP (GRAPH_SIZE / 10) -void ps_export_graph(FILE *file, struct expr_node *node, struct graph_range *range) { +void ps_export_graph(FILE *file, const struct expr_node *node, const struct graph_range *range) { int i; double x; int first = 1; diff --git a/ps_graph.h b/ps_graph.h index be4fb6d..2f2ea8f 100644 --- a/ps_graph.h +++ b/ps_graph.h @@ -10,6 +10,6 @@ struct graph_range { double step; }; -extern void ps_export_graph(FILE *file, struct expr_node *node, struct graph_range *range); +extern void ps_export_graph(FILE *file, const struct expr_node *node, const struct graph_range *range); #endif \ No newline at end of file diff --git a/tree.c b/tree.c index 6989833..9356611 100644 --- a/tree.c +++ b/tree.c @@ -112,22 +112,23 @@ static void debug_print_binop(struct expr_node *node, const char* name, int inde debug_print(node->vals.binop.right, indent + 1); } +static const char* fn_str[] = { + "FN_ABS", + "FN_EXP", + "FN_LN", + "FN_LOG", + "FN_SIN", + "FN_COS", + "FN_TAN", + "FN_ASIN", + "FN_ACOS", + "FN_ATAN", + "FN_SINH", + "FN_COSH", + "FN_TANH" +}; + static void debug_print(struct expr_node *node, int indent) { - static const char* fn_str[] = { - "FN_ABS", - "FN_EXP", - "FN_LN", - "FN_LOG", - "FN_SIN", - "FN_COS", - "FN_TAN", - "FN_ASIN", - "FN_ACOS", - "FN_ATAN", - "FN_SINH", - "FN_COSH", - "FN_TANH" - }; switch (node->type) { case EXPR_ADD: @@ -181,7 +182,72 @@ void node_debug_print(struct expr_node *node) { debug_print(node, 0); } -double node_eval(struct expr_node *node, double x) { +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: + fprintf(output, "node%p [label=\"FN: %s\"]\n", (void*)node, fn_str[node->vals.fn.fn]); + debug_print_gv(node->vals.fn.arg, output); + fprintf(output, "node%p -> node%p [label=arg]\n", (void*)node, (void*)node->vals.fn.arg); + 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"); +} + + +double node_eval(const struct expr_node *node, double x) { switch (node->type) { case EXPR_CONST: return node->vals.num; diff --git a/tree.h b/tree.h index cd9be8f..ff99970 100644 --- a/tree.h +++ b/tree.h @@ -42,8 +42,9 @@ extern struct expr_node *node_create_x(void); extern struct expr_node *node_create_fn(enum math_fn fn, struct expr_node *arg); extern void node_debug_print(struct expr_node *node); +extern void node_debug_print_gv(const struct expr_node *node, FILE *output); -extern double node_eval(struct expr_node *node, double x); +extern double node_eval(const struct expr_node *node, double x); extern void node_free(struct expr_node *node);