From 60a8aff3290fbdd8a12fc4d41711266331f2c526 Mon Sep 17 00:00:00 2001 From: tovjemam Date: Wed, 18 Dec 2024 15:52:01 +0100 Subject: [PATCH] komentare --- error_buffer.c | 89 ++++--- error_buffer.h | 96 +++++--- lex.c | 41 +++- lex.h | 63 ++++- main.c | 10 +- math_functions.c | 156 ++++++------ math_functions.h | 49 ++-- parser.c | 9 +- parser.h | 38 ++- tree.c | 603 +++++++++++++++++++++++------------------------ tree.h | 115 +++++++-- 11 files changed, 767 insertions(+), 502 deletions(-) diff --git a/error_buffer.c b/error_buffer.c index bb87692..d8bc92e 100644 --- a/error_buffer.c +++ b/error_buffer.c @@ -1,47 +1,44 @@ -#include "error_buffer.h" -#include -#include -#include - -void error_buffer_init(struct error_buffer *eb) { - eb->err = ERR_NO_ERR; - eb->text_len = 0; - eb->text[0] = 0; - /* memset(eb->text, 0xAA, MAX_ERROR_MESSAGE_LENGTH); */ -} - -void error_set(struct error_buffer *eb, enum error_code err) { - eb->err = err; -} - -enum error_code error_get(const struct error_buffer *eb) { - return eb->err; -} - -void error_printf(struct error_buffer *eb, const char *format, ...) { - va_list args; - int space = MAX_ERROR_MESSAGE_LENGTH - eb->text_len; - int write_size; - - if (space == 0) - return; - - va_start(args, format); - write_size = vsnprintf(eb->text + eb->text_len, MAX_ERROR_MESSAGE_LENGTH - eb->text_len, format, args); - va_end(args); - - if (write_size < 0) - return; - - if (write_size < space) { - eb->text_len += write_size; - } else { - eb->text_len = MAX_ERROR_MESSAGE_LENGTH; - } - - /* eb->text[eb->text_len] = 0; */ -} - -const char *error_get_text(const struct error_buffer *eb) { - return eb->text; +#include "error_buffer.h" +#include +#include +#include + +void error_buffer_init(struct error_buffer *eb) { + eb->err = ERR_NO_ERR; + eb->text_len = 0; + eb->text[0] = 0; +} + +void error_set(struct error_buffer *eb, enum error_code err) { + eb->err = err; +} + +enum error_code error_get(const struct error_buffer *eb) { + return eb->err; +} + +void error_printf(struct error_buffer *eb, const char *format, ...) { + va_list args; + int space = MAX_ERROR_MESSAGE_LENGTH - eb->text_len; + int write_size; + + if (space == 0) + return; + + va_start(args, format); + write_size = vsnprintf(eb->text + eb->text_len, MAX_ERROR_MESSAGE_LENGTH - eb->text_len, format, args); + va_end(args); + + if (write_size < 0) + return; + + if (write_size < space) { + eb->text_len += write_size; + } else { + eb->text_len = MAX_ERROR_MESSAGE_LENGTH; + } +} + +const char *error_get_text(const struct error_buffer *eb) { + return eb->text; } \ No newline at end of file diff --git a/error_buffer.h b/error_buffer.h index 64d7d4c..daffe8c 100644 --- a/error_buffer.h +++ b/error_buffer.h @@ -1,31 +1,67 @@ -#ifndef ERROR_CODE_H -#define ERROR_CODE_H - -#include - -#define MAX_ERROR_MESSAGE_LENGTH 512 - -enum error_code { - ERR_NO_ERR = 0, - ERR_INVALID_ARGS = 1, - ERR_INVALID_FUNCTION = 2, - ERR_INVALID_FILENAME = 3, - ERR_INVALID_LIMITS = 4, - ERR_BAD_ALLOC = 5 -}; - -struct error_buffer { - enum error_code err; - char text[MAX_ERROR_MESSAGE_LENGTH]; - size_t text_len; -}; - -void error_buffer_init(struct error_buffer *eb); - -void error_set(struct error_buffer *eb, enum error_code err); -void error_printf(struct error_buffer *eb, const char *format, ...); - -enum error_code error_get(const struct error_buffer *eb); -const char *error_get_text(const struct error_buffer *eb); - +#ifndef ERROR_CODE_H +#define ERROR_CODE_H + +#include + +#define MAX_ERROR_MESSAGE_LENGTH 512 + +/** + * @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 +}; + +/** + * @brief Zásobník pro chybový kód a řetězec popisující chybu + */ +struct error_buffer { + enum error_code err; + char text[MAX_ERROR_MESSAGE_LENGTH]; + size_t text_len; +}; + +/** + * @brief Inicializuje zásobník + * + * @param eb Zásobník + */ +void error_buffer_init(struct error_buffer *eb); + +/** + * @brief Nastaví chybový kód + * + * @param eb Zásobník + * @param err Chybový kód + */ +void error_set(struct error_buffer *eb, enum error_code err); + +/** + * @brief Přidá do zásobníku formátovaný řetězec + * + * @param eb Zásobník + */ +void error_printf(struct error_buffer *eb, const char *format, ...); + +/** + * Vrátí chybový kód + * + * @param eb Zásobník + * @return Chybový kód + */ +enum error_code error_get(const struct error_buffer *eb); + +/** + * Vrátí řetězec popisující chybu + * + * @param eb Zásobník + * @return Řetězec popisující chybu + */ +const char *error_get_text(const struct error_buffer *eb); + #endif /* ERROR_CODE_H */ \ No newline at end of file diff --git a/lex.c b/lex.c index 69b27bd..80d8d0b 100644 --- a/lex.c +++ b/lex.c @@ -1,4 +1,4 @@ -#include "lex.h" +#include "lex.h" #include #include @@ -6,6 +6,10 @@ #include "math_functions.h" +#define CONST_PI 3.141592653589793 +#define CONST_E 2.718281828459045 +#define CONST_S (1.0 / 9.0) + void lex_init(struct lexer *lex, const char *str, const char *variable_name) { error_buffer_init(&lex->eb); @@ -16,15 +20,19 @@ void lex_init(struct lexer *lex, const char *str, const char *variable_name) { lex_next(lex); } -static int is_whitespace(char p) { - return p == ' ' || p == '\t' || p == '\n' || p == '\r'; +/* Vrátí 1, pokud je c "bílý znak" */ +static int is_whitespace(char c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; } +/* Přeskočí bílé znaky v řetězci */ static void skip_whitespace(struct lexer *lex) { while (is_whitespace(*lex->p)) ++lex->p; } +/* Posune ukazatel, pokud se v řetězci na aktuální pozici nachází + řetězec str a vrátí 1, jinak ukazatel nezmění a vrátí 0 */ static int try_advance(struct lexer *lex, const char *str) { const char *temp_p = lex->p; while (1) { @@ -42,16 +50,21 @@ static int try_advance(struct lexer *lex, const char *str) { } } +/* Vrátí 1, pokud se c smí vyskytovat v identifikátorech */ static int is_identifier_char(char c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } +/* Stejné jako try_advance, ale přidává podmínku, že následující znak + není znakem s povoleným výskytem v identifikátorech. + Např. "sin" bude rozpoznán v "sin(...)", ale v "sinh" ne. +*/ static int try_advance_identifier(struct lexer *lex, const char *str) { const char *temp_p = lex->p; if (!try_advance(lex, str)) return 0; - /* overit konec identifikatoru */ + /* ověřit konec identifikátoru */ if (is_identifier_char(*lex->p)) { lex->p = temp_p; return 0; @@ -60,6 +73,7 @@ static int try_advance_identifier(struct lexer *lex, const char *str) { return 1; } +/* Vrátí 1, pokud je na začátku řetězce nalezen daný token a nastaví příslušně aktuální token. */ static int try_token(struct lexer *lex, const char *tok_str, enum token_type type) { if (try_advance(lex, tok_str)) { lex->tok.type = type; @@ -68,6 +82,7 @@ static int try_token(struct lexer *lex, const char *tok_str, enum token_type typ return 0; } +/* Vrátí 1, pokud je na začátku řetězce nalezena daná funkce a nastaví příslušně aktuální token. */ static int try_fns(struct lexer *lex) { const struct math_function *const fns = fns_get(); size_t i; @@ -83,7 +98,8 @@ static int try_fns(struct lexer *lex) { return 0; } -static int try_number(struct lexer* lex) { +/* Vrátí 1, pokud je na začátku řetězce nalezena číselná konstanta a nastaví příslušně aktuální token. */ +static int try_number(struct lexer *lex) { char *end; double val; val = strtod(lex->p, &end); @@ -94,6 +110,16 @@ static int try_number(struct lexer* lex) { return 1; } +/* Vrátí 1, pokud je na začátku řetězce nalezena speciální číselná konstanta a nastaví příslušně aktuální token. */ +static int try_constant(struct lexer *lex, const char *name, double val) { + if (!try_advance_identifier(lex, name)) + return 0; + + lex->tok.type = TOK_NUMBER; + lex->tok.val.num = val; + return 1; +} + void lex_next(struct lexer *lex) { skip_whitespace(lex); lex->prev_p = lex->p; @@ -113,6 +139,10 @@ void lex_next(struct lexer *lex) { if (try_token(lex, ")", TOK_RIGHT_PAREN)) return; if (try_token(lex, ",", TOK_COMMA)) return; + if (try_constant(lex, "pi", CONST_PI)) return; + if (try_constant(lex, "e", CONST_E)) return; + if (try_constant(lex, "skibidi", CONST_S)) return; + if (try_advance_identifier(lex, lex->variable_name)) { lex->tok.type = TOK_VARIABLE; return; @@ -152,7 +182,6 @@ void lex_print_position(const struct lexer *lex, struct error_buffer *eb) { } error_printf(eb, "\n"); - /* error_printf(eb, "\n----------------------------------------------------\n"); */ } enum error_code lex_get_error(const struct lexer *lex) { diff --git a/lex.h b/lex.h index 76b82c9..ba76136 100644 --- a/lex.h +++ b/lex.h @@ -1,10 +1,13 @@ -#ifndef LEX_H +#ifndef LEX_H #define LEX_H #include "error_buffer.h" #define LEX_DEBUG +/** + * @brief Typ tokenu + */ enum token_type { TOK_EOF, TOK_ERROR, @@ -24,6 +27,11 @@ enum token_type { TOK_COMMA }; +/** + * @brief Token + * + * Struktura popisující konkrétní token, který se vyskytnul při lexikální analýze funkce. + */ struct token { enum token_type type; union token_val { @@ -32,6 +40,11 @@ struct token { } val; }; +/** + * @brief Lexikální analyzátor (lexer) + * + * Struktura uchovávající stav lexikálního analyzátoru. + */ struct lexer { const char *start; const char *prev_p; @@ -41,16 +54,64 @@ struct lexer { const char *variable_name; }; +/** + * @brief Inicializuje lexikální analyzátor + * + * @param lex Lexer + * @param str Řetězec pro analýzu + * @param variable_name Název proměnné + */ void lex_init(struct lexer *lex, const char *str, const char *variable_name); +/** + * @brief Načte další token + * + * @param lex Lexer + */ void lex_next(struct lexer *lex); + +/** + * @brief Vrátí adresu na aktuální token + * + * @param lex Lexer + * @return Adresa na token + */ struct token *lex_token(struct lexer *lex); +/** + * @brief Vypíše informaci o aktuální pozici ve vstupním řetězci + * + * Tato funkce je volána, když při zpracování vstupní funkce nastane chyba. + * + * @param lex Lexer + * @param eb Zásobník, do kterého bude informace vypsána + */ void lex_print_position(const struct lexer *lex, struct error_buffer *eb); +/** + * @brief Vrátí kód chyby, která nastala při lexikální analýze + * + * @param lex Lexer + * @return Chybový kód + */ enum error_code lex_get_error(const struct lexer *lex); + +/** + * @brief Vrátí textovou reprezentaci chyby, která nastala při lexikální analýze + * + * @param lex Lexer + * @return Řetězec s chybou + */ const char *lex_get_error_text(const struct lexer *lex); +/** + * @brief Vrátí textovou reprezentaci tokenu + * + * Tato funkce zohledńuje pouze typ tokenu, hodnota (např. číselná u konstanty) nebude v řetězci obsažena. + * + * @param token Token + * @return Textová reprezentace + */ const char *lex_token_str(enum token_type token); #ifdef LEX_DEBUG diff --git a/main.c b/main.c index ed60ef7..cbc004f 100644 --- a/main.c +++ b/main.c @@ -23,11 +23,11 @@ int main(int argc, char *argv[]) { return parser_get_error(&parser); } - graph.xmin = -20.0; - graph.xmax = 20.0; - graph.ymin = -20.0; - graph.ymax = 20.0; - graph.step = 0.01; + graph.xmin = 0.0; + graph.xmax = 6.28; + graph.ymin = 0.0; + graph.ymax = 2.0; + graph.step = 0.001; file = fopen("out.ps", "w"); ps_export_graph(file, node, &graph); diff --git a/math_functions.c b/math_functions.c index a2e03ef..1eb3c1f 100644 --- a/math_functions.c +++ b/math_functions.c @@ -1,78 +1,78 @@ -#include "math_functions.h" - -#include - -#define MAKE_FUNCTION_1_ARG(name) \ - static double mf_##name(const double *args) { \ - return name(args[0]); \ - } - -MAKE_FUNCTION_1_ARG(fabs) -MAKE_FUNCTION_1_ARG(exp) -MAKE_FUNCTION_1_ARG(log) -MAKE_FUNCTION_1_ARG(log10) -MAKE_FUNCTION_1_ARG(sin) -MAKE_FUNCTION_1_ARG(cos) -MAKE_FUNCTION_1_ARG(tan) -MAKE_FUNCTION_1_ARG(asin) -MAKE_FUNCTION_1_ARG(acos) -MAKE_FUNCTION_1_ARG(atan) -MAKE_FUNCTION_1_ARG(sinh) -MAKE_FUNCTION_1_ARG(cosh) -MAKE_FUNCTION_1_ARG(tanh) -MAKE_FUNCTION_1_ARG(floor) -MAKE_FUNCTION_1_ARG(ceil) - -static double mf_sgn(const double *args) { - if (args[0] < 0.0) - return -1.0; - else if (args[0] > 0.0) - return 1.0; - else - return 0.0; -} - -static double mf_min(const double *args) { - if (args[0] < args[1]) - return args[0]; - - return args[1]; -} - -static double mf_max(const double *args) { - if (args[0] > args[1]) - return args[0]; - - return args[1]; -} - -static double mf_mod(const double *args) { - return fmod(args[0], args[1]); -} - -const struct math_function *fns_get(void) { - static const struct math_function fns[] = { - { "abs", 1, mf_fabs }, - { "exp", 1, mf_exp }, - { "ln", 1, mf_log }, - { "log", 1, mf_log10 }, - { "sin", 1, mf_sin }, - { "cos", 1, mf_cos }, - { "tan", 1, mf_tan }, - { "asin", 1, mf_asin }, - { "acos", 1, mf_acos }, - { "atan", 1, mf_atan }, - { "sinh", 1, mf_sinh }, - { "cosh", 1, mf_cosh }, - { "tanh", 1, mf_tanh }, - { "min", 2, mf_min }, - { "max", 2, mf_max }, - { "mod", 2, mf_mod }, - { "sgn", 1, mf_sgn }, - { "floor", 1, mf_floor }, - { "ceil", 1, mf_ceil }, - { NULL } - }; - - return fns; -} +#include "math_functions.h" + +#include + +#define MAKE_FUNCTION_1_ARG(name) \ + static double mf_##name(const double *args) { \ + return name(args[0]); \ + } + +MAKE_FUNCTION_1_ARG(fabs) +MAKE_FUNCTION_1_ARG(exp) +MAKE_FUNCTION_1_ARG(log) +MAKE_FUNCTION_1_ARG(log10) +MAKE_FUNCTION_1_ARG(sin) +MAKE_FUNCTION_1_ARG(cos) +MAKE_FUNCTION_1_ARG(tan) +MAKE_FUNCTION_1_ARG(asin) +MAKE_FUNCTION_1_ARG(acos) +MAKE_FUNCTION_1_ARG(atan) +MAKE_FUNCTION_1_ARG(sinh) +MAKE_FUNCTION_1_ARG(cosh) +MAKE_FUNCTION_1_ARG(tanh) +MAKE_FUNCTION_1_ARG(floor) +MAKE_FUNCTION_1_ARG(ceil) + +static double mf_sgn(const double *args) { + if (args[0] < 0.0) + return -1.0; + else if (args[0] > 0.0) + return 1.0; + else + return 0.0; +} + +static double mf_min(const double *args) { + if (args[0] < args[1]) + return args[0]; + + return args[1]; +} + +static double mf_max(const double *args) { + if (args[0] > args[1]) + return args[0]; + + return args[1]; +} + +static double mf_mod(const double *args) { + return fmod(args[0], args[1]); +} + +const struct math_function *fns_get(void) { + static const struct math_function fns[] = { + { "abs", 1, mf_fabs }, + { "exp", 1, mf_exp }, + { "ln", 1, mf_log }, + { "log", 1, mf_log10 }, + { "sin", 1, mf_sin }, + { "cos", 1, mf_cos }, + { "tan", 1, mf_tan }, + { "asin", 1, mf_asin }, + { "acos", 1, mf_acos }, + { "atan", 1, mf_atan }, + { "sinh", 1, mf_sinh }, + { "cosh", 1, mf_cosh }, + { "tanh", 1, mf_tanh }, + { "min", 2, mf_min }, + { "max", 2, mf_max }, + { "mod", 2, mf_mod }, + { "sgn", 1, mf_sgn }, + { "floor", 1, mf_floor }, + { "ceil", 1, mf_ceil }, + { NULL } + }; + + return fns; +} diff --git a/math_functions.h b/math_functions.h index 13d21b5..279253c 100644 --- a/math_functions.h +++ b/math_functions.h @@ -1,18 +1,33 @@ -#ifndef MATH_FUNCTIONS_H -#define MATH_FUNCTIONS_H - -#include - -#define MAX_MATH_FUNCTION_ARGS 2 - -typedef double (*math_function_ptr)(const double*); - -struct math_function { - const char *name; - size_t num_args; - math_function_ptr ptr; -}; - -const struct math_function *fns_get(void); - +#ifndef MATH_FUNCTIONS_H +#define MATH_FUNCTIONS_H + +#include + +#define MAX_MATH_FUNCTION_ARGS 2 + +/** + * @brief Ukazatel na vyhodnocovač matematické funkce + */ +typedef double (*math_function_ptr)(const double*); + +/** + * @brief Matematická funkce + * + * Struktura popisující matematickou funkci, kterou lze použít ve vstupním výrazu + */ +struct math_function { + const char *name; + size_t num_args; + math_function_ptr ptr; +}; + +/** + * @brief Vrátí ukazatel na pole obsahující matematické funkce + * + * Toto pole je ukončené položkou s atributem name == NULL. + * + * @return Ukazatel na pole funkcí + */ +const struct math_function *fns_get(void); + #endif /* MATH_FUNCTIONS_H */ \ No newline at end of file diff --git a/parser.c b/parser.c index 79cbaee..d6f9d26 100644 --- a/parser.c +++ b/parser.c @@ -1,27 +1,33 @@ -#include +#include #include #include "parser.h" +/* Vrátí ukazatel na aktuální token */ static struct token *get_token(struct parser *parser) { return lex_token(&parser->lexer); } +/* Vrátí 1, pokud aktuální token je typu */ static int token_is(struct parser *parser, enum token_type type) { return get_token(parser)->type == type; } +/* Vrátí hodnotu tokenu, který je konstanta */ static double token_num(struct parser *parser) { return get_token(parser)->val.num; } +/* Vrátí index funkce tokenu, který reprezentuje funkci */ static size_t token_fn_idx(struct parser *parser) { return get_token(parser)->val.fn_idx; } +/* Načte další token */ static void next_token(struct parser *parser) { lex_next(&parser->lexer); } +/* Vrátí 1, pokud je aktuální token typu a načte další */ static int accept_token(struct parser *parser, enum token_type type) { if (token_is(parser, type)) { next_token(parser); @@ -30,6 +36,7 @@ static int accept_token(struct parser *parser, enum token_type type) { return 0; } +/* Nastaví chybu při alokaci */ static void error_bad_alloc(struct parser *parser) { error_set(&parser->eb, ERR_BAD_ALLOC); error_printf(&parser->eb, "Out of memory\n"); diff --git a/parser.h b/parser.h index e414889..b3d9d3c 100644 --- a/parser.h +++ b/parser.h @@ -1,18 +1,54 @@ -#ifndef PARSER_H +#ifndef PARSER_H #define PARSER_H #include "tree.h" #include "lex.h" +/** + * @brief Syntaktický analyzátor (parser) + */ struct parser { struct lexer lexer; struct error_buffer eb; }; +/** + * @brief Zpracuje n výrazů ze vstupního řetězce + * + * @param parser Parser + * @param str Vstupní řetězec + * @param variable_name Název proměnné + * @param out_nodes Adresa na pole, kam budou adresy kořenových uzlů výrazů uloženy + * @param n Počet výrazů + * + * @return 1 při úspěchu, 0 při chybě + */ int parser_parse_n(struct parser *parser, const char *str, const char *variable_name, struct expr_node **out_nodes, size_t n); + +/** + * @brief Zpracuje jeden výraz ze vstupního řetězce + * + * @param parser Parser + * @param str Vstupní řetězec + * @param variable_name Název proměnné + * @return Adresa kořenového uzlu výrazu + */ struct expr_node *parser_parse(struct parser *parser, const char *str, const char *variable_name); +/** + * @brief Vrátí kód chyby nastalé během syntaktické analýzy + * + * @param parser Parser + * @return Chybový kód + */ enum error_code parser_get_error(const struct parser *parser); + +/** + * @brief Vrátí textovou reprezentaci chyby nastalé během syntaktické analýzy + * + * @param parser Parser + * @return Řetězec obsahující text chyby + */ const char *parser_get_error_text(const struct parser *parser); #endif /* PARSER_H */ \ No newline at end of file diff --git a/tree.c b/tree.c index d97d7d3..3c62d88 100644 --- a/tree.c +++ b/tree.c @@ -1,303 +1,300 @@ -#include -#include -#include -#include "tree.h" - -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; -} - -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; -} - -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_indent(indent); printf("left:\n");*/ - debug_print(node->vals.binop.left, indent + 1); - /*debug_indent(indent); printf("right:\n");*/ - 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_indent(indent); printf("unop:\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"); -} - - -double node_eval(const struct expr_node *node, double x) { - switch (node->type) { - case EXPR_CONST: - return node->vals.num; - - case EXPR_X: - return x; - - case EXPR_NEG: - return -node_eval(node->vals.unop, x); - - case EXPR_ADD: - return node_eval(node->vals.binop.left, x) + node_eval(node->vals.binop.right, x); - - case EXPR_SUB: - return node_eval(node->vals.binop.left, x) - node_eval(node->vals.binop.right, x); - - case EXPR_MULT: - return node_eval(node->vals.binop.left, x) * node_eval(node->vals.binop.right, x); - - case EXPR_DIV: - return node_eval(node->vals.binop.left, x) / node_eval(node->vals.binop.right, x); - - case EXPR_POW: - return pow(node_eval(node->vals.binop.left, x), node_eval(node->vals.binop.right, x)); - - 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) { - inner_results[i] = node_eval(node->vals.fn.args[i], x); - } - - return fn->ptr(inner_results); - } - } - - return 0.0; -} +#include +#include +#include +#include "tree.h" + +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; +} + +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; +} + +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"); +} + + +double node_eval(const struct expr_node *node, double x) { + switch (node->type) { + case EXPR_CONST: + return node->vals.num; + + case EXPR_X: + return x; + + case EXPR_NEG: + return -node_eval(node->vals.unop, x); + + case EXPR_ADD: + return node_eval(node->vals.binop.left, x) + node_eval(node->vals.binop.right, x); + + case EXPR_SUB: + return node_eval(node->vals.binop.left, x) - node_eval(node->vals.binop.right, x); + + case EXPR_MULT: + return node_eval(node->vals.binop.left, x) * node_eval(node->vals.binop.right, x); + + case EXPR_DIV: + return node_eval(node->vals.binop.left, x) / node_eval(node->vals.binop.right, x); + + case EXPR_POW: + return pow(node_eval(node->vals.binop.left, x), node_eval(node->vals.binop.right, x)); + + 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) { + inner_results[i] = node_eval(node->vals.fn.args[i], x); + } + + return fn->ptr(inner_results); + } + } + + return 0.0; +} diff --git a/tree.h b/tree.h index bc08d20..8987c87 100644 --- a/tree.h +++ b/tree.h @@ -1,9 +1,12 @@ -#ifndef TREE_H +#ifndef TREE_H #define TREE_H #include "lex.h" #include "math_functions.h" +/** + * @brief Typ uzlu + */ enum expr_type { EXPR_CONST, EXPR_NEG, @@ -16,6 +19,9 @@ enum expr_type { EXPR_FN }; +/** + * @brief Uzel výrazu + */ struct expr_node { enum expr_type type; union expr_vals { @@ -32,22 +38,103 @@ struct expr_node { } vals; }; -extern struct expr_node *node_create_const(double val); -extern struct expr_node *node_create_neg(struct expr_node *unop); -extern struct expr_node *node_create_add(struct expr_node *left, struct expr_node *right); -extern struct expr_node *node_create_sub(struct expr_node *left, struct expr_node *right); -extern struct expr_node *node_create_mult(struct expr_node *left, struct expr_node *right); -extern struct expr_node *node_create_div(struct expr_node *left, struct expr_node *right); -extern struct expr_node *node_create_pow(struct expr_node *base, struct expr_node *power); -extern struct expr_node *node_create_x(void); -extern struct expr_node *node_create_fn(size_t fn_idx, struct expr_node **args); +/** + * @brief Vytvoří uzel reprezentující konstantu + * + * @param val Hodnota konstanty + * @return Adresa uzlu + */ +struct expr_node *node_create_const(double val); -extern void node_debug_print(struct expr_node *node); -extern void node_debug_print_gv(const struct expr_node *node, FILE *output); +/** + * @brief Vytvoří uzel reprezentující negaci výrazu + * + * @param unop Negovaný výraz (unární operand) + * @return Adresa uzlu + */ +struct expr_node *node_create_neg(struct expr_node *unop); -extern double node_eval(const struct expr_node *node, double x); +/** + * @brief Vytvoří uzel reprezentující sčítání + * + * @param left Levý operand + * @param right Pravý operand + * @return Adresa uzlu + */ +struct expr_node *node_create_add(struct expr_node *left, struct expr_node *right); -extern void node_free(struct expr_node *node); +/** + * @brief Vytvoří uzel reprezentující odčítání + * + * @param left Levý operand + * @param right Pravý operand + * @return Adresa uzlu + */ +struct expr_node *node_create_sub(struct expr_node *left, struct expr_node *right); + +/** + * @brief Vytvoří uzel reprezentující násobení + * + * @param left Levý operand + * @param right Pravý operand + * @return Adresa uzlu + */ +struct expr_node *node_create_mult(struct expr_node *left, struct expr_node *right); + +/** + * @brief Vytvoří uzel reprezentující dělení + * + * @param left Levý operand + * @param right Pravý operand + * @return Adresa uzlu + */ +struct expr_node *node_create_div(struct expr_node *left, struct expr_node *right); + +/** + * @brief Vytvoří uzel reprezentující mocnění + * + * @param left Levý operand + * @param right Pravý operand + * @return Adresa uzlu + */ +struct expr_node *node_create_pow(struct expr_node *base, struct expr_node *power); + +/** + * @brief Vytvoří uzel reprezentující proměnnou + * + * @return Adresa uzlu + */ +struct expr_node *node_create_x(void); + +/** + * @brief Vytvoří uzel reprezentující funkci + * + * @param fn_idx Index funkce v poli vráceném fns_get() + * @param args Ukazatel na pole uzlů, které funkce obdrží jako argumenty + * @return Adresa uzlu + */ +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 + * + * @param node Uzel + * @param x Proměnná + * @return Hodnota v bodě x + */ +double node_eval(const struct expr_node *node, double x); + +/** + * @brief Uvolní uzel + * + * Tato funkce uvolní i potomky uzlu (operandy, argumenty, ...) + * + * @param node Uzel pro uvolnění + */ +void node_free(struct expr_node *node); #endif /* TREE_H */ \ No newline at end of file