komentare

This commit is contained in:
tovjemam 2024-12-18 15:52:01 +01:00
parent 0426bb04ac
commit 60a8aff329
11 changed files with 767 additions and 502 deletions

View File

@ -1,47 +1,44 @@
#include "error_buffer.h" #include "error_buffer.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
void error_buffer_init(struct error_buffer *eb) { void error_buffer_init(struct error_buffer *eb) {
eb->err = ERR_NO_ERR; eb->err = ERR_NO_ERR;
eb->text_len = 0; eb->text_len = 0;
eb->text[0] = 0; eb->text[0] = 0;
/* memset(eb->text, 0xAA, MAX_ERROR_MESSAGE_LENGTH); */ }
}
void error_set(struct error_buffer *eb, enum error_code err) {
void error_set(struct error_buffer *eb, enum error_code err) { eb->err = err;
eb->err = err; }
}
enum error_code error_get(const struct error_buffer *eb) {
enum error_code error_get(const struct error_buffer *eb) { return eb->err;
return eb->err; }
}
void error_printf(struct error_buffer *eb, const char *format, ...) {
void error_printf(struct error_buffer *eb, const char *format, ...) { va_list args;
va_list args; int space = MAX_ERROR_MESSAGE_LENGTH - eb->text_len;
int space = MAX_ERROR_MESSAGE_LENGTH - eb->text_len; int write_size;
int write_size;
if (space == 0)
if (space == 0) return;
return;
va_start(args, format);
va_start(args, format); write_size = vsnprintf(eb->text + eb->text_len, MAX_ERROR_MESSAGE_LENGTH - eb->text_len, format, args);
write_size = vsnprintf(eb->text + eb->text_len, MAX_ERROR_MESSAGE_LENGTH - eb->text_len, format, args); va_end(args);
va_end(args);
if (write_size < 0)
if (write_size < 0) return;
return;
if (write_size < space) {
if (write_size < space) { eb->text_len += write_size;
eb->text_len += write_size; } else {
} else { eb->text_len = MAX_ERROR_MESSAGE_LENGTH;
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;
const char *error_get_text(const struct error_buffer *eb) {
return eb->text;
} }

View File

@ -1,31 +1,67 @@
#ifndef ERROR_CODE_H #ifndef ERROR_CODE_H
#define ERROR_CODE_H #define ERROR_CODE_H
#include <stdlib.h> #include <stdlib.h>
#define MAX_ERROR_MESSAGE_LENGTH 512 #define MAX_ERROR_MESSAGE_LENGTH 512
enum error_code { /**
ERR_NO_ERR = 0, * @brief Chybové kódy
ERR_INVALID_ARGS = 1, */
ERR_INVALID_FUNCTION = 2, enum error_code {
ERR_INVALID_FILENAME = 3, ERR_NO_ERR = 0, ///< Žádná chyba
ERR_INVALID_LIMITS = 4, ERR_INVALID_ARGS = 1, ///< Neplatné argumenty programu
ERR_BAD_ALLOC = 5 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
struct error_buffer { ERR_BAD_ALLOC = 5 ///< Při alokaci paměti nastala chyba
enum error_code err; };
char text[MAX_ERROR_MESSAGE_LENGTH];
size_t text_len; /**
}; * @brief Zásobník pro chybový kód a řetězec popisující chybu
*/
void error_buffer_init(struct error_buffer *eb); struct error_buffer {
enum error_code err;
void error_set(struct error_buffer *eb, enum error_code err); char text[MAX_ERROR_MESSAGE_LENGTH];
void error_printf(struct error_buffer *eb, const char *format, ...); size_t text_len;
};
enum error_code error_get(const struct error_buffer *eb);
const char *error_get_text(const struct error_buffer *eb); /**
* @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 */ #endif /* ERROR_CODE_H */

41
lex.c
View File

@ -1,4 +1,4 @@
#include "lex.h" #include "lex.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -6,6 +6,10 @@
#include "math_functions.h" #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) { void lex_init(struct lexer *lex, const char *str, const char *variable_name) {
error_buffer_init(&lex->eb); 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); lex_next(lex);
} }
static int is_whitespace(char p) { /* Vrátí 1, pokud je c "bílý znak" */
return p == ' ' || p == '\t' || p == '\n' || p == '\r'; 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) { static void skip_whitespace(struct lexer *lex) {
while (is_whitespace(*lex->p)) while (is_whitespace(*lex->p))
++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) { static int try_advance(struct lexer *lex, const char *str) {
const char *temp_p = lex->p; const char *temp_p = lex->p;
while (1) { 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) { static int is_identifier_char(char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); 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) { static int try_advance_identifier(struct lexer *lex, const char *str) {
const char *temp_p = lex->p; const char *temp_p = lex->p;
if (!try_advance(lex, str)) if (!try_advance(lex, str))
return 0; return 0;
/* overit konec identifikatoru */ /* ověřit konec identifikátoru */
if (is_identifier_char(*lex->p)) { if (is_identifier_char(*lex->p)) {
lex->p = temp_p; lex->p = temp_p;
return 0; return 0;
@ -60,6 +73,7 @@ static int try_advance_identifier(struct lexer *lex, const char *str) {
return 1; 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) { static int try_token(struct lexer *lex, const char *tok_str, enum token_type type) {
if (try_advance(lex, tok_str)) { if (try_advance(lex, tok_str)) {
lex->tok.type = type; 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; 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) { static int try_fns(struct lexer *lex) {
const struct math_function *const fns = fns_get(); const struct math_function *const fns = fns_get();
size_t i; size_t i;
@ -83,7 +98,8 @@ static int try_fns(struct lexer *lex) {
return 0; 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; char *end;
double val; double val;
val = strtod(lex->p, &end); val = strtod(lex->p, &end);
@ -94,6 +110,16 @@ static int try_number(struct lexer* lex) {
return 1; 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) { void lex_next(struct lexer *lex) {
skip_whitespace(lex); skip_whitespace(lex);
lex->prev_p = lex->p; 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_RIGHT_PAREN)) return;
if (try_token(lex, ",", TOK_COMMA)) 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)) { if (try_advance_identifier(lex, lex->variable_name)) {
lex->tok.type = TOK_VARIABLE; lex->tok.type = TOK_VARIABLE;
return; 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");
/* error_printf(eb, "\n----------------------------------------------------\n"); */
} }
enum error_code lex_get_error(const struct lexer *lex) { enum error_code lex_get_error(const struct lexer *lex) {

63
lex.h
View File

@ -1,10 +1,13 @@
#ifndef LEX_H #ifndef LEX_H
#define LEX_H #define LEX_H
#include "error_buffer.h" #include "error_buffer.h"
#define LEX_DEBUG #define LEX_DEBUG
/**
* @brief Typ tokenu
*/
enum token_type { enum token_type {
TOK_EOF, TOK_EOF,
TOK_ERROR, TOK_ERROR,
@ -24,6 +27,11 @@ enum token_type {
TOK_COMMA TOK_COMMA
}; };
/**
* @brief Token
*
* Struktura popisující konkrétní token, který se vyskytnul při lexikální analýze funkce.
*/
struct token { struct token {
enum token_type type; enum token_type type;
union token_val { union token_val {
@ -32,6 +40,11 @@ struct token {
} val; } val;
}; };
/**
* @brief Lexikální analyzátor (lexer)
*
* Struktura uchovávající stav lexikálního analyzátoru.
*/
struct lexer { struct lexer {
const char *start; const char *start;
const char *prev_p; const char *prev_p;
@ -41,16 +54,64 @@ struct lexer {
const char *variable_name; 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); 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); 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); 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); 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); 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); 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); const char *lex_token_str(enum token_type token);
#ifdef LEX_DEBUG #ifdef LEX_DEBUG

10
main.c
View File

@ -23,11 +23,11 @@ int main(int argc, char *argv[]) {
return parser_get_error(&parser); return parser_get_error(&parser);
} }
graph.xmin = -20.0; graph.xmin = 0.0;
graph.xmax = 20.0; graph.xmax = 6.28;
graph.ymin = -20.0; graph.ymin = 0.0;
graph.ymax = 20.0; graph.ymax = 2.0;
graph.step = 0.01; graph.step = 0.001;
file = fopen("out.ps", "w"); file = fopen("out.ps", "w");
ps_export_graph(file, node, &graph); ps_export_graph(file, node, &graph);

View File

@ -1,78 +1,78 @@
#include "math_functions.h" #include "math_functions.h"
#include <math.h> #include <math.h>
#define MAKE_FUNCTION_1_ARG(name) \ #define MAKE_FUNCTION_1_ARG(name) \
static double mf_##name(const double *args) { \ static double mf_##name(const double *args) { \
return name(args[0]); \ return name(args[0]); \
} }
MAKE_FUNCTION_1_ARG(fabs) MAKE_FUNCTION_1_ARG(fabs)
MAKE_FUNCTION_1_ARG(exp) MAKE_FUNCTION_1_ARG(exp)
MAKE_FUNCTION_1_ARG(log) MAKE_FUNCTION_1_ARG(log)
MAKE_FUNCTION_1_ARG(log10) MAKE_FUNCTION_1_ARG(log10)
MAKE_FUNCTION_1_ARG(sin) MAKE_FUNCTION_1_ARG(sin)
MAKE_FUNCTION_1_ARG(cos) MAKE_FUNCTION_1_ARG(cos)
MAKE_FUNCTION_1_ARG(tan) MAKE_FUNCTION_1_ARG(tan)
MAKE_FUNCTION_1_ARG(asin) MAKE_FUNCTION_1_ARG(asin)
MAKE_FUNCTION_1_ARG(acos) MAKE_FUNCTION_1_ARG(acos)
MAKE_FUNCTION_1_ARG(atan) MAKE_FUNCTION_1_ARG(atan)
MAKE_FUNCTION_1_ARG(sinh) MAKE_FUNCTION_1_ARG(sinh)
MAKE_FUNCTION_1_ARG(cosh) MAKE_FUNCTION_1_ARG(cosh)
MAKE_FUNCTION_1_ARG(tanh) MAKE_FUNCTION_1_ARG(tanh)
MAKE_FUNCTION_1_ARG(floor) MAKE_FUNCTION_1_ARG(floor)
MAKE_FUNCTION_1_ARG(ceil) MAKE_FUNCTION_1_ARG(ceil)
static double mf_sgn(const double *args) { static double mf_sgn(const double *args) {
if (args[0] < 0.0) if (args[0] < 0.0)
return -1.0; return -1.0;
else if (args[0] > 0.0) else if (args[0] > 0.0)
return 1.0; return 1.0;
else else
return 0.0; return 0.0;
} }
static double mf_min(const double *args) { static double mf_min(const double *args) {
if (args[0] < args[1]) if (args[0] < args[1])
return args[0]; return args[0];
return args[1]; return args[1];
} }
static double mf_max(const double *args) { static double mf_max(const double *args) {
if (args[0] > args[1]) if (args[0] > args[1])
return args[0]; return args[0];
return args[1]; return args[1];
} }
static double mf_mod(const double *args) { static double mf_mod(const double *args) {
return fmod(args[0], args[1]); return fmod(args[0], args[1]);
} }
const struct math_function *fns_get(void) { const struct math_function *fns_get(void) {
static const struct math_function fns[] = { static const struct math_function fns[] = {
{ "abs", 1, mf_fabs }, { "abs", 1, mf_fabs },
{ "exp", 1, mf_exp }, { "exp", 1, mf_exp },
{ "ln", 1, mf_log }, { "ln", 1, mf_log },
{ "log", 1, mf_log10 }, { "log", 1, mf_log10 },
{ "sin", 1, mf_sin }, { "sin", 1, mf_sin },
{ "cos", 1, mf_cos }, { "cos", 1, mf_cos },
{ "tan", 1, mf_tan }, { "tan", 1, mf_tan },
{ "asin", 1, mf_asin }, { "asin", 1, mf_asin },
{ "acos", 1, mf_acos }, { "acos", 1, mf_acos },
{ "atan", 1, mf_atan }, { "atan", 1, mf_atan },
{ "sinh", 1, mf_sinh }, { "sinh", 1, mf_sinh },
{ "cosh", 1, mf_cosh }, { "cosh", 1, mf_cosh },
{ "tanh", 1, mf_tanh }, { "tanh", 1, mf_tanh },
{ "min", 2, mf_min }, { "min", 2, mf_min },
{ "max", 2, mf_max }, { "max", 2, mf_max },
{ "mod", 2, mf_mod }, { "mod", 2, mf_mod },
{ "sgn", 1, mf_sgn }, { "sgn", 1, mf_sgn },
{ "floor", 1, mf_floor }, { "floor", 1, mf_floor },
{ "ceil", 1, mf_ceil }, { "ceil", 1, mf_ceil },
{ NULL } { NULL }
}; };
return fns; return fns;
} }

View File

@ -1,18 +1,33 @@
#ifndef MATH_FUNCTIONS_H #ifndef MATH_FUNCTIONS_H
#define MATH_FUNCTIONS_H #define MATH_FUNCTIONS_H
#include <stdlib.h> #include <stdlib.h>
#define MAX_MATH_FUNCTION_ARGS 2 #define MAX_MATH_FUNCTION_ARGS 2
typedef double (*math_function_ptr)(const double*); /**
* @brief Ukazatel na vyhodnocovač matematické funkce
struct math_function { */
const char *name; typedef double (*math_function_ptr)(const double*);
size_t num_args;
math_function_ptr ptr; /**
}; * @brief Matematická funkce
*
const struct math_function *fns_get(void); * 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 */ #endif /* MATH_FUNCTIONS_H */

View File

@ -1,27 +1,33 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include "parser.h" #include "parser.h"
/* Vrátí ukazatel na aktuální token */
static struct token *get_token(struct parser *parser) { static struct token *get_token(struct parser *parser) {
return lex_token(&parser->lexer); return lex_token(&parser->lexer);
} }
/* Vrátí 1, pokud aktuální token je typu <type> */
static int token_is(struct parser *parser, enum token_type type) { static int token_is(struct parser *parser, enum token_type type) {
return get_token(parser)->type == type; return get_token(parser)->type == type;
} }
/* Vrátí hodnotu tokenu, který je konstanta */
static double token_num(struct parser *parser) { static double token_num(struct parser *parser) {
return get_token(parser)->val.num; return get_token(parser)->val.num;
} }
/* Vrátí index funkce tokenu, který reprezentuje funkci */
static size_t token_fn_idx(struct parser *parser) { static size_t token_fn_idx(struct parser *parser) {
return get_token(parser)->val.fn_idx; return get_token(parser)->val.fn_idx;
} }
/* Načte další token */
static void next_token(struct parser *parser) { static void next_token(struct parser *parser) {
lex_next(&parser->lexer); lex_next(&parser->lexer);
} }
/* Vrátí 1, pokud je aktuální token typu <type> a načte další */
static int accept_token(struct parser *parser, enum token_type type) { static int accept_token(struct parser *parser, enum token_type type) {
if (token_is(parser, type)) { if (token_is(parser, type)) {
next_token(parser); next_token(parser);
@ -30,6 +36,7 @@ static int accept_token(struct parser *parser, enum token_type type) {
return 0; return 0;
} }
/* Nastaví chybu při alokaci */
static void error_bad_alloc(struct parser *parser) { static void error_bad_alloc(struct parser *parser) {
error_set(&parser->eb, ERR_BAD_ALLOC); error_set(&parser->eb, ERR_BAD_ALLOC);
error_printf(&parser->eb, "Out of memory\n"); error_printf(&parser->eb, "Out of memory\n");

View File

@ -1,18 +1,54 @@
#ifndef PARSER_H #ifndef PARSER_H
#define PARSER_H #define PARSER_H
#include "tree.h" #include "tree.h"
#include "lex.h" #include "lex.h"
/**
* @brief Syntaktický analyzátor (parser)
*/
struct parser { struct parser {
struct lexer lexer; struct lexer lexer;
struct error_buffer eb; 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); 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); 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); 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); const char *parser_get_error_text(const struct parser *parser);
#endif /* PARSER_H */ #endif /* PARSER_H */

603
tree.c
View File

@ -1,303 +1,300 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include "tree.h" #include "tree.h"
static struct expr_node *alloc_node(void) { static struct expr_node *alloc_node(void) {
return malloc(sizeof(struct expr_node)); return malloc(sizeof(struct expr_node));
} }
struct expr_node *node_create_const(double val) { struct expr_node *node_create_const(double val) {
struct expr_node *node = alloc_node(); struct expr_node *node = alloc_node();
if (!node) return NULL; if (!node) return NULL;
node->type = EXPR_CONST; node->type = EXPR_CONST;
node->vals.num = val; node->vals.num = val;
return node; return node;
} }
struct expr_node *node_create_neg(struct expr_node *unop) { struct expr_node *node_create_neg(struct expr_node *unop) {
struct expr_node *node = alloc_node(); struct expr_node *node = alloc_node();
if (!node) return NULL; if (!node) return NULL;
node->type = EXPR_NEG; node->type = EXPR_NEG;
node->vals.unop = unop; node->vals.unop = unop;
return node; return node;
} }
static struct expr_node *create_binary_node(enum expr_type type, struct expr_node *left, struct expr_node *right) { 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(); struct expr_node *node = alloc_node();
if (!node) return NULL; if (!node) return NULL;
node->type = type; node->type = type;
node->vals.binop.left = left; node->vals.binop.left = left;
node->vals.binop.right = right; node->vals.binop.right = right;
return node; return node;
} }
struct expr_node *node_create_add(struct expr_node *left, struct expr_node *right) { struct expr_node *node_create_add(struct expr_node *left, struct expr_node *right) {
return create_binary_node(EXPR_ADD, left, right); return create_binary_node(EXPR_ADD, left, right);
} }
struct expr_node *node_create_sub(struct expr_node *left, struct expr_node *right) { struct expr_node *node_create_sub(struct expr_node *left, struct expr_node *right) {
return create_binary_node(EXPR_SUB, left, right); return create_binary_node(EXPR_SUB, left, right);
} }
struct expr_node *node_create_mult(struct expr_node *left, struct expr_node *right) { struct expr_node *node_create_mult(struct expr_node *left, struct expr_node *right) {
return create_binary_node(EXPR_MULT, left, right); return create_binary_node(EXPR_MULT, left, right);
} }
struct expr_node *node_create_div(struct expr_node *left, struct expr_node *right) { struct expr_node *node_create_div(struct expr_node *left, struct expr_node *right) {
return create_binary_node(EXPR_DIV, left, right); return create_binary_node(EXPR_DIV, left, right);
} }
struct expr_node *node_create_pow(struct expr_node *base, struct expr_node *power) { struct expr_node *node_create_pow(struct expr_node *base, struct expr_node *power) {
return create_binary_node(EXPR_POW, base, power); return create_binary_node(EXPR_POW, base, power);
} }
struct expr_node *node_create_x(void) { struct expr_node *node_create_x(void) {
struct expr_node *node = alloc_node(); struct expr_node *node = alloc_node();
if (!node) return NULL; if (!node) return NULL;
node->type = EXPR_X; node->type = EXPR_X;
return node; return node;
} }
struct expr_node *node_create_fn(size_t fn_idx, struct expr_node **args) { struct expr_node *node_create_fn(size_t fn_idx, struct expr_node **args) {
size_t i, num_args; size_t i, num_args;
struct expr_node *node = alloc_node(); struct expr_node *node = alloc_node();
if (!node) return NULL; if (!node) return NULL;
node->type = EXPR_FN; node->type = EXPR_FN;
node->vals.fn.fn_idx = fn_idx; node->vals.fn.fn_idx = fn_idx;
num_args = fns_get()[fn_idx].num_args; num_args = fns_get()[fn_idx].num_args;
for (i = 0; i < num_args; ++i) { for (i = 0; i < num_args; ++i) {
node->vals.fn.args[i] = args[i]; node->vals.fn.args[i] = args[i];
} }
return node; return node;
} }
void node_free(struct expr_node *node) { void node_free(struct expr_node *node) {
if (!node) return; if (!node) return;
switch (node->type) { switch (node->type) {
case EXPR_ADD: case EXPR_ADD:
case EXPR_SUB: case EXPR_SUB:
case EXPR_MULT: case EXPR_MULT:
case EXPR_DIV: case EXPR_DIV:
case EXPR_POW: case EXPR_POW:
node_free(node->vals.binop.left); node_free(node->vals.binop.left);
node_free(node->vals.binop.right); node_free(node->vals.binop.right);
break; break;
case EXPR_NEG: case EXPR_NEG:
node_free(node->vals.unop); node_free(node->vals.unop);
break; break;
case EXPR_FN: case EXPR_FN:
{ {
size_t i, num_args = fns_get()[node->vals.fn.fn_idx].num_args; size_t i, num_args = fns_get()[node->vals.fn.fn_idx].num_args;
for (i = 0; i < num_args; ++i) { for (i = 0; i < num_args; ++i) {
node_free(node->vals.fn.args[i]); node_free(node->vals.fn.args[i]);
} }
} }
break; break;
default: default:
break; break;
} }
free(node); free(node);
} }
static void debug_indent(int indent) { static void debug_indent(int indent) {
int i; int i;
for (i = 0; i < indent; ++i) for (i = 0; i < indent; ++i)
printf(" "); printf(" ");
} }
static void debug_print(struct expr_node *node, int indent); static void debug_print(struct expr_node *node, int indent);
static void debug_print_binop(struct expr_node *node, const char* name, 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("[%s]\n", name);
/*debug_indent(indent); printf("left:\n");*/ debug_print(node->vals.binop.left, indent + 1);
debug_print(node->vals.binop.left, indent + 1); debug_print(node->vals.binop.right, 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) {
static void debug_print(struct expr_node *node, int indent) { switch (node->type) {
case EXPR_ADD:
switch (node->type) { debug_print_binop(node, "ADD", indent);
case EXPR_ADD: break;
debug_print_binop(node, "ADD", indent);
break; case EXPR_SUB:
debug_print_binop(node, "SUB", indent);
case EXPR_SUB: break;
debug_print_binop(node, "SUB", indent);
break; case EXPR_MULT:
debug_print_binop(node, "MULT", indent);
case EXPR_MULT: break;
debug_print_binop(node, "MULT", indent);
break; case EXPR_DIV:
debug_print_binop(node, "DIV", indent);
case EXPR_DIV: break;
debug_print_binop(node, "DIV", indent);
break; case EXPR_POW:
debug_print_binop(node, "POW", indent);
case EXPR_POW: break;
debug_print_binop(node, "POW", indent);
break; case EXPR_NEG:
debug_indent(indent); printf("[NEG]\n");
case EXPR_NEG: debug_print(node->vals.unop, indent + 1);
debug_indent(indent); printf("[NEG]\n"); break;
/*debug_indent(indent); printf("unop:\n");*/
debug_print(node->vals.unop, indent + 1); case EXPR_CONST:
break; debug_indent(indent); printf("[CONST] %.2f\n", node->vals.num);
break;
case EXPR_CONST:
debug_indent(indent); printf("[CONST] %.2f\n", node->vals.num); case EXPR_X:
break; debug_indent(indent); printf("[X]\n");
case EXPR_X: break;
debug_indent(indent); printf("[X]\n");
case EXPR_FN:
break; {
size_t i;
case EXPR_FN: const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx];
{ debug_indent(indent); printf("[FN] %s\n", fn->name);
size_t i;
const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx]; for (i = 0; i < fn->num_args; ++i) {
debug_indent(indent); printf("[FN] %s\n", fn->name); debug_print(node->vals.fn.args[i], indent + 1);
}
for (i = 0; i < fn->num_args; ++i) {
debug_print(node->vals.fn.args[i], indent + 1); break;
} }
break; default:
} break;
}
default: }
break;
}
} void node_debug_print(struct expr_node *node) {
debug_print(node, 0);
}
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) {
static void debug_print_gv(const struct expr_node *node, FILE *output); fprintf(output, "node%p [label=\"%s\"]\n", (void*)node, name);
debug_print_gv(node->vals.binop.left, output);
static void debug_print_binop_gv(const struct expr_node *node, FILE *output, const char *name) { debug_print_gv(node->vals.binop.right, output);
fprintf(output, "node%p [label=\"%s\"]\n", (void*)node, name); fprintf(output, "node%p -> node%p [label=left]\n", (void*)node, (void*)node->vals.binop.left);
debug_print_gv(node->vals.binop.left, output); fprintf(output, "node%p -> node%p [label=right]\n", (void*)node, (void*)node->vals.binop.right);
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) {
static void debug_print_gv(const struct expr_node *node, FILE *output) { case EXPR_ADD:
debug_print_binop_gv(node, output, "ADD");
switch (node->type) { break;
case EXPR_ADD:
debug_print_binop_gv(node, output, "ADD"); case EXPR_SUB:
break; debug_print_binop_gv(node, output, "SUB");
break;
case EXPR_SUB:
debug_print_binop_gv(node, output, "SUB"); case EXPR_MULT:
break; debug_print_binop_gv(node, output, "MULT");
break;
case EXPR_MULT:
debug_print_binop_gv(node, output, "MULT"); case EXPR_DIV:
break; debug_print_binop_gv(node, output, "DIV");
break;
case EXPR_DIV:
debug_print_binop_gv(node, output, "DIV"); case EXPR_POW:
break; debug_print_binop_gv(node, output, "POW");
break;
case EXPR_POW:
debug_print_binop_gv(node, output, "POW"); case EXPR_NEG:
break; fprintf(output, "node%p [label=\"NEG\"]\n", (void*)node);
debug_print_gv(node->vals.unop, output);
case EXPR_NEG: fprintf(output, "node%p -> node%p [label=unop]\n", (void*)node, (void*)node->vals.unop);
fprintf(output, "node%p [label=\"NEG\"]\n", (void*)node); break;
debug_print_gv(node->vals.unop, output);
fprintf(output, "node%p -> node%p [label=unop]\n", (void*)node, (void*)node->vals.unop); case EXPR_CONST:
break; fprintf(output, "node%p [label=\"CONST: %.2f\"]\n", (void*)node, node->vals.num);
break;
case EXPR_CONST:
fprintf(output, "node%p [label=\"CONST: %.2f\"]\n", (void*)node, node->vals.num); case EXPR_X:
break; fprintf(output, "node%p [label=\"X\"]\n", (void*)node);
break;
case EXPR_X:
fprintf(output, "node%p [label=\"X\"]\n", (void*)node); case EXPR_FN:
break; {
size_t i;
case EXPR_FN: const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx];
{
size_t i; fprintf(output, "node%p [label=\"FN: %s\"]\n", (void*)node, fn->name);
const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx];
for (i = 0; i < fn->num_args; ++i) {
fprintf(output, "node%p [label=\"FN: %s\"]\n", (void*)node, fn->name); struct expr_node *arg = node->vals.fn.args[i];
debug_print_gv(arg, output);
for (i = 0; i < fn->num_args; ++i) { fprintf(output, "node%p -> node%p [label=arg%d]\n", (void*)node, (void*)arg, (int)i + 1);
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;
} }
break; default:
} 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);
void node_debug_print_gv(const struct expr_node *node, FILE *output) { fprintf(output, "}\n");
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:
double node_eval(const struct expr_node *node, double x) { return node->vals.num;
switch (node->type) {
case EXPR_CONST: case EXPR_X:
return node->vals.num; return x;
case EXPR_X: case EXPR_NEG:
return x; return -node_eval(node->vals.unop, x);
case EXPR_NEG: case EXPR_ADD:
return -node_eval(node->vals.unop, x); return node_eval(node->vals.binop.left, x) + node_eval(node->vals.binop.right, x);
case EXPR_ADD: case EXPR_SUB:
return node_eval(node->vals.binop.left, x) + node_eval(node->vals.binop.right, x); return node_eval(node->vals.binop.left, x) - node_eval(node->vals.binop.right, x);
case EXPR_SUB: case EXPR_MULT:
return node_eval(node->vals.binop.left, x) - node_eval(node->vals.binop.right, x); return node_eval(node->vals.binop.left, x) * node_eval(node->vals.binop.right, x);
case EXPR_MULT: case EXPR_DIV:
return node_eval(node->vals.binop.left, x) * node_eval(node->vals.binop.right, x); return node_eval(node->vals.binop.left, x) / node_eval(node->vals.binop.right, x);
case EXPR_DIV: case EXPR_POW:
return node_eval(node->vals.binop.left, x) / node_eval(node->vals.binop.right, x); return pow(node_eval(node->vals.binop.left, x), node_eval(node->vals.binop.right, x));
case EXPR_POW: case EXPR_FN:
return pow(node_eval(node->vals.binop.left, x), node_eval(node->vals.binop.right, x)); {
double inner_results[MAX_MATH_FUNCTION_ARGS];
case EXPR_FN: size_t i;
{ const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx];
double inner_results[MAX_MATH_FUNCTION_ARGS];
size_t i; for (i = 0; i < fn->num_args; ++i) {
const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx]; inner_results[i] = node_eval(node->vals.fn.args[i], x);
}
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 fn->ptr(inner_results);
} return 0.0;
} }
return 0.0;
}

115
tree.h
View File

@ -1,9 +1,12 @@
#ifndef TREE_H #ifndef TREE_H
#define TREE_H #define TREE_H
#include "lex.h" #include "lex.h"
#include "math_functions.h" #include "math_functions.h"
/**
* @brief Typ uzlu
*/
enum expr_type { enum expr_type {
EXPR_CONST, EXPR_CONST,
EXPR_NEG, EXPR_NEG,
@ -16,6 +19,9 @@ enum expr_type {
EXPR_FN EXPR_FN
}; };
/**
* @brief Uzel výrazu
*/
struct expr_node { struct expr_node {
enum expr_type type; enum expr_type type;
union expr_vals { union expr_vals {
@ -32,22 +38,103 @@ struct expr_node {
} vals; } vals;
}; };
extern struct expr_node *node_create_const(double val); /**
extern struct expr_node *node_create_neg(struct expr_node *unop); * @brief Vytvoří uzel reprezentující konstantu
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); * @param val Hodnota konstanty
extern struct expr_node *node_create_mult(struct expr_node *left, struct expr_node *right); * @return Adresa uzlu
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); struct expr_node *node_create_const(double val);
extern struct expr_node *node_create_x(void);
extern struct expr_node *node_create_fn(size_t fn_idx, struct expr_node **args);
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 */ #endif /* TREE_H */