From d88234f394ea24a19fdca8059186d7f83b6db0ea Mon Sep 17 00:00:00 2001 From: tovjemam Date: Sun, 5 Jan 2025 17:48:34 +0100 Subject: [PATCH] komentare navic --- errors.c | 5 ++++ lex.c | 24 +++++++++++++++++++ main.c | 13 ++++++++++ math_functions.c | 1 + parser.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++- tree.c | 7 ++++-- 6 files changed, 109 insertions(+), 3 deletions(-) diff --git a/errors.c b/errors.c index 991379e..efe91fa 100644 --- a/errors.c +++ b/errors.c @@ -19,19 +19,24 @@ enum error_code error_get(const struct error_buffer *eb) { void error_printf(struct error_buffer *eb, const char *format, ...) { va_list args; + /* volné místo v zásobníku */ int space = MAX_ERROR_MESSAGE_LENGTH - eb->text_len; int write_size; + /* už není volné místo */ if (space == 0) return; + /* zápis */ va_start(args, format); write_size = vsnprintf(eb->text + eb->text_len, MAX_ERROR_MESSAGE_LENGTH - eb->text_len, format, args); va_end(args); + /* chyba */ if (write_size < 0) return; + /* aktualizace délky */ if (write_size < space) { eb->text_len += write_size; } diff --git a/lex.c b/lex.c index dadda47..249cb3a 100644 --- a/lex.c +++ b/lex.c @@ -6,6 +6,7 @@ #include "math_functions.h" +/* konstanty */ #define CONST_PI 3.141592653589793 #define CONST_E 2.718281828459045 #define CONST_S (1.0 / 9.0) @@ -36,11 +37,14 @@ static void skip_whitespace(struct lexer *lex) { static int try_advance(struct lexer *lex, const char *str) { const char *temp_p = lex->p; while (1) { + /* pokud jsme se dostali až na konec řetězce, vrátíme 1 */ if (!*str) { lex->p = temp_p; return 1; } + /* pokud se někde neshoduje, vrátíme 0 */ + /* (je zahrnut případ, že str skončí dřív) */ if (*str != *temp_p) { return 0; } @@ -102,8 +106,14 @@ static int try_fns(struct lexer *lex) { static int try_number(struct lexer *lex) { char *end; double val; + + /* pokus o přečtení čísla */ val = strtod(lex->p, &end); + + /* pokud se na aktuální pozici nenacházelo číslo, vrátíme 0 */ if (lex->p == end) return 0; + + /* nastavit token */ lex->tok.type = TOK_NUMBER; lex->tok.val.num = val; lex->p = end; @@ -121,37 +131,51 @@ static int try_constant(struct lexer *lex, const char *name, double val) { } void lex_next(struct lexer *lex) { + /* přeskočit bílé znaky */ skip_whitespace(lex); + + /* uložit pozici pro případné vypsání chyby */ + /* (v případě úspěšné tokenizace ale chyby syntaxe + by p ukazovalo na další token)*/ lex->prev_p = lex->p; + /* pokud jsme na konci řetězce, nastavit EOF */ if (!*lex->p) { lex->tok.type = TOK_EOF; return; } + /* pokus o rozpoznání tokenů */ + /* operátory */ if (try_token(lex, "+", TOK_PLUS)) return; if (try_token(lex, "-", TOK_MINUS)) return; if (try_token(lex, "*", TOK_MULTIPLY)) return; if (try_token(lex, "/", TOK_DIVIDE)) return; if (try_token(lex, "^", TOK_POWER)) return; + /* závorky a oddělovač */ if (try_token(lex, "(", TOK_LEFT_PAREN)) return; if (try_token(lex, ")", TOK_RIGHT_PAREN)) return; if (try_token(lex, ",", TOK_COMMA)) return; + /* symbolické konstanty */ if (try_constant(lex, "pi", CONST_PI)) return; if (try_constant(lex, "e", CONST_E)) return; if (try_constant(lex, "skibidi", CONST_S)) return; /* easter egg */ + /* proměnná */ if (try_advance_identifier(lex, lex->variable_name)) { lex->tok.type = TOK_VARIABLE; return; } + /* funkce */ if (try_fns(lex)) return; + /* číselná konstanta */ if (try_number(lex)) return; + /* možnosti vyčerpány => chyba */ error_set(&lex->eb, ERR_INVALID_FUNCTION); error_printf(&lex->eb, "Unrecognized sequence \"%s\"\n", lex->p); lex_print_position(lex, &lex->eb); diff --git a/main.c b/main.c index 7f9cc75..8cb9b51 100644 --- a/main.c +++ b/main.c @@ -13,13 +13,16 @@ static void print_usage(FILE *f, const char *name) { } +/* přečte z řetězce číslo a posune ukazatel */ static int read_double(const char **str, double *out) { char *end; *out = strtod(*str, &end); + /* pokud se na aktuální pozici nenacházelo číslo, vrátíme 0 */ if (*str == end) return 0; + /* posuneme ukazatel za číslo */ *str = end; return 1; } @@ -32,6 +35,7 @@ static int read_double(const char **str, double *out) { if (*str++ != c) \ return 0; +/* Zpracuje rozsah vykreslení grafu ve formátu "xmin:xmax:ymin:ymax" */ static int parse_range(const char *str, struct graph_range *range) { EXPECT_DOUBLE(str, &range->xmin); EXPECT_CHAR(str, ':'); @@ -44,6 +48,7 @@ static int parse_range(const char *str, struct graph_range *range) { return 1; } +/* vygeneruje graf funkce do souboru */ 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; @@ -59,6 +64,7 @@ static enum error_code export_to_file(const struct expr_node *node, const struct } #ifdef ENABLE_GRAPHVIZ_EXPORT +/* vygeneruje strom výrazu v .dot formátu pro ladění */ static void export_gv(const struct expr_node *node, const char *out_name) { FILE *file; @@ -79,11 +85,13 @@ int main(int argc, char *argv[]) { struct expr_node *node; struct graph_range range; + /* kontrola argumentů */ if (argc < 3) { print_usage(stderr, argv[0]); return ERR_INVALID_ARGS; } + /* zpracování rozsahu */ if (argc > 3) { if (!parse_range(argv[3], &range)) { fprintf(stderr, "Invalid format of ranges! The correct format is \"xMin:xMax:yMin:yMax\".\n"); @@ -97,20 +105,25 @@ int main(int argc, char *argv[]) { range.ymax = 10.0; } + /* zpracování výrazu */ node = parser_parse(&parser, argv[1], "x"); if (!node) { + /* vypsání chyby */ fprintf(stderr, "%s", parser_get_error_text(&parser)); return parser_get_error(&parser); } + /* vygenerování grafu */ err = export_to_file(node, &range, argv[1], argv[2]); #ifdef ENABLE_GRAPHVIZ_EXPORT export_gv(node, "graph.dot"); #endif /* ENABLE_GRAPHVIZ_EXPORT */ + /* uvolnění paměti */ node_free(node); + /* návratový kód */ return err; } \ No newline at end of file diff --git a/math_functions.c b/math_functions.c index 48670c5..ad6e6af 100644 --- a/math_functions.c +++ b/math_functions.c @@ -3,6 +3,7 @@ #include #include +/* Vytvoří vyhodnocovač matematické funkce s jedním argumentem */ #define MAKE_FUNCTION_1_ARG(name) \ static enum eval_result mf_##name(double *y, const double *args) { \ errno = 0; \ diff --git a/parser.c b/parser.c index 3b176e1..e06f6c5 100644 --- a/parser.c +++ b/parser.c @@ -1,4 +1,4 @@ -#include +#include #include #include #include "parser.h" @@ -48,8 +48,10 @@ static void error_expected_tokens(struct parser *parser, size_t num_tokens, ...) size_t i; va_list ap; + /* vyskytující se token */ enum token_type got = get_token(parser)->type; + /* chyba při lexikální analýze */ if (got == TOK_ERROR) { error_set(&parser->eb, lex_get_error(&parser->lexer)); error_printf(&parser->eb, "%s", lex_get_error_text(&parser->lexer)); @@ -59,6 +61,7 @@ static void error_expected_tokens(struct parser *parser, size_t num_tokens, ...) error_set(&parser->eb, ERR_INVALID_FUNCTION); error_printf(&parser->eb, "Syntax error - expected "); + /* výpis očekávaných tokenů */ va_start(ap, num_tokens); for (i = 0; i < num_tokens; ++i) { enum token_type tok = va_arg(ap, enum token_type); @@ -70,8 +73,10 @@ static void error_expected_tokens(struct parser *parser, size_t num_tokens, ...) } va_end(ap); + /* výpis vyskytlého se tokenu */ error_printf(&parser->eb, " - but got %s\n", lex_token_str(got)); + /* výpis aktuální pozice ve vstupním řetězci */ lex_print_position(&parser->lexer, &parser->eb); } @@ -82,14 +87,17 @@ static int parse_n_expressions(struct parser *parser, struct expr_node **out_nod static struct expr_node *parse_bracketed(struct parser *parser) { struct expr_node *node; + /* požadovat levou závorku */ if (!accept_token(parser, TOK_LEFT_PAREN)) { error_expected_tokens(parser, 1, TOK_LEFT_PAREN); return NULL; } + /* zpracovat výraz v závorkach */ if (!(node = parse_expression(parser))) return NULL; + /* požadovat pravou závorku */ if (!accept_token(parser, TOK_RIGHT_PAREN)) { error_expected_tokens(parser, 1, TOK_RIGHT_PAREN); node_free(node); @@ -103,28 +111,35 @@ static struct expr_node *parse_function(struct parser *parser) { struct expr_node *node; struct expr_node *arg_nodes[MAX_MATH_FUNCTION_ARGS]; size_t i; + + /* funkce */ size_t fn_idx = token_fn_idx(parser); const struct math_function *fn = &fns_get()[fn_idx]; next_token(parser); + /* požadovat levou závorku */ if (!accept_token(parser, TOK_LEFT_PAREN)) { error_expected_tokens(parser, 1, TOK_LEFT_PAREN); return NULL; } + /* zpracovat argumenty funkce */ if (!parse_n_expressions(parser, arg_nodes, fn->num_args)) return NULL; + /* vytvořit uzel funkce */ if (!(node = node_create_fn(fn_idx, arg_nodes))) { error_bad_alloc(parser); + /* uvolnit všechny uzly argumentů */ for (i = 0; i < fn->num_args; ++i) node_free(arg_nodes[i]); return NULL; } + /* požadovat pravou závorku */ if (!accept_token(parser, TOK_RIGHT_PAREN)) { error_expected_tokens(parser, 1, TOK_RIGHT_PAREN); node_free(node); @@ -138,6 +153,7 @@ static struct expr_node *parse_function(struct parser *parser) { static struct expr_node *parse_factor(struct parser *parser) { struct expr_node *node; + /* konstanta */ if (token_is(parser, TOK_NUMBER)) { double val = token_num(parser); next_token(parser); @@ -149,6 +165,7 @@ static struct expr_node *parse_factor(struct parser *parser) { return node; } + /* proměnná */ if (accept_token(parser, TOK_VARIABLE)) { if (!(node = node_create_x())) { error_bad_alloc(parser); @@ -157,10 +174,12 @@ static struct expr_node *parse_factor(struct parser *parser) { return node; } + /* funkce */ if (token_is(parser, TOK_FUNCTION)) { return parse_function(parser); } + /* výraz obalený závorkami */ if (token_is(parser, TOK_LEFT_PAREN)) { return parse_bracketed(parser); } @@ -175,15 +194,19 @@ static struct expr_node *parse_unary(struct parser *parser); static struct expr_node *parse_power(struct parser *parser) { struct expr_node *node, *new_node, *inner; + /* základ (nebo výsledek pokud nenásleduje umocnění) */ if (!(node = parse_factor(parser))) return NULL; + /* umocnění? */ if (accept_token(parser, TOK_POWER)) { + /* exponent */ if (!(inner = parse_unary(parser))) { node_free(node); return NULL; } + /* vytvořit uzel umocnění */ if (!(new_node = node_create_pow(node, inner))) { error_bad_alloc(parser); node_free(node); @@ -199,12 +222,15 @@ static struct expr_node *parse_power(struct parser *parser) { /* Zpracuje unární mínus, resp. plus */ static struct expr_node *parse_unary(struct parser *parser) { + /* unární mínus? */ if (accept_token(parser, TOK_MINUS)) { struct expr_node *node, *inner; + /* operand */ if (!(inner = parse_power(parser))) return NULL; + /* vytvořit uzel negace */ if (!(node = node_create_neg(inner))) { error_bad_alloc(parser); node_free(inner); @@ -214,7 +240,9 @@ static struct expr_node *parse_unary(struct parser *parser) { return node; } + /* unární plus - nehraje roli */ accept_token(parser, TOK_PLUS); + return parse_power(parser); } @@ -222,12 +250,17 @@ static struct expr_node *parse_unary(struct parser *parser) { static struct expr_node *parse_term(struct parser *parser) { struct expr_node *node, *new_node, *inner; + /* výraz před prvním operátorem */ if (!(node = parse_unary(parser))) return NULL; + /* iterovat dokud se za výrazy nachází operátory součinu nebo dělení */ + /* bylo by možné "vyřešit" rekurzí, ale není nutné */ while (1) { + /* funkce pro vytvoření uzlu binární operace na základě operátoru */ struct expr_node *(*create_node)(struct expr_node *left, struct expr_node *right); + /* rozhodnout se na základě operátoru, případně ukončit smyčku */ if (accept_token(parser, TOK_MULTIPLY)) create_node = node_create_mult; else if (accept_token(parser, TOK_DIVIDE)) @@ -235,11 +268,13 @@ static struct expr_node *parse_term(struct parser *parser) { else break; + /* zpracovat další výraz */ if (!(inner = parse_unary(parser))) { node_free(node); return NULL; } + /* vytvořit uzel pro danou operaci */ if (!(new_node = create_node(node, inner))) { error_bad_alloc(parser); node_free(node); @@ -247,6 +282,7 @@ static struct expr_node *parse_term(struct parser *parser) { return NULL; } + /* uzly postupně řetězit */ node = new_node; } @@ -257,12 +293,17 @@ static struct expr_node *parse_term(struct parser *parser) { static struct expr_node *parse_expression(struct parser *parser) { struct expr_node *node, *new_node, *inner; + /* výraz před prvním operátorem */ if (!(node = parse_term(parser))) return NULL; + /* iterovat dokud se za výrazy nachází operátory sčítání nebo odčítání */ + /* bylo by možné "vyřešit" rekurzí, ale není nutné */ while (1) { + /* funkce pro vytvoření uzlu binární operace na základě operátoru */ struct expr_node *(*create_node)(struct expr_node *left, struct expr_node *right); + /* rozhodnout se na základě operátoru, případně ukončit smyčku */ if (accept_token(parser, TOK_PLUS)) create_node = node_create_add; else if (accept_token(parser, TOK_MINUS)) @@ -270,11 +311,13 @@ static struct expr_node *parse_expression(struct parser *parser) { else break; + /* zpracovat další výraz */ if (!(inner = parse_term(parser))) { node_free(node); return NULL; } + /* vytvořit uzel pro danou operaci */ if (!(new_node = create_node(node, inner))) { error_bad_alloc(parser); node_free(node); @@ -282,6 +325,7 @@ static struct expr_node *parse_expression(struct parser *parser) { return NULL; } + /* uzly postupně řetězit */ node = new_node; } @@ -299,49 +343,65 @@ static int parse_n_expressions(struct parser *parser, struct expr_node **out_nod out_nodes[i] = node; + /* akceptovat čárku jakožto oddělovač výrazů */ if (i < n - 1) accept_token(parser, TOK_COMMA); } + /* nebyly zpracovány všechny výrazy? */ if (i != n) { + /* uvolnit všechny doposud alokované uzly */ while (i) { --i; node_free(out_nodes[i]); out_nodes[i] = NULL; } + /* chyba */ return 0; } + /* úspěch */ return 1; } int parser_parse_n(struct parser *parser, const char *str, const char *variable_name, struct expr_node **out_nodes, size_t n) { + /* inicializace chybového bufferu */ error_buffer_init(&parser->eb); + + /* inicializace lexikálního analyzázoru */ lex_init(&parser->lexer, str, variable_name); + /* zpracování n tokenů */ if (!parse_n_expressions(parser, out_nodes, n)) { return 0; } + /* požadovat konec vstupu */ if (!token_is(parser, TOK_EOF)) { size_t i; error_expected_tokens(parser, 1, TOK_EOF); + /* uvolnit všechny uzly */ for (i = 0; i < n; ++i) { node_free(out_nodes[i]); out_nodes[i] = NULL; } + /* chyba */ return 0; } + /* úspěch */ return 1; } struct expr_node *parser_parse(struct parser *parser, const char *str, const char *variable_name) { struct expr_node *out_node = NULL; + + /* zpracování jednoho výrazu */ parser_parse_n(parser, str, variable_name, &out_node, 1); + return out_node; } diff --git a/tree.c b/tree.c index 1da684a..0b9ed20 100644 --- a/tree.c +++ b/tree.c @@ -4,6 +4,7 @@ #include #include "tree.h" +/* alokuje nový uzel */ static struct expr_node *alloc_node(void) { return malloc(sizeof(struct expr_node)); } @@ -24,6 +25,7 @@ struct expr_node *node_create_neg(struct expr_node *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; @@ -75,12 +77,15 @@ struct expr_node *node_create_fn(size_t fn_idx, struct expr_node **args) { 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; @@ -88,8 +93,6 @@ static enum eval_result check_real(double x) { return EVAL_ERROR; } -#define RETURN_CHECK_REAL(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) {