komentare
This commit is contained in:
parent
0426bb04ac
commit
60a8aff329
@ -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;
|
|
||||||
}
|
}
|
||||||
@ -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
41
lex.c
@ -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
63
lex.h
@ -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
10
main.c
@ -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);
|
||||||
|
|||||||
156
math_functions.c
156
math_functions.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 */
|
||||||
9
parser.c
9
parser.c
@ -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");
|
||||||
|
|||||||
38
parser.h
38
parser.h
@ -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
603
tree.c
@ -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
115
tree.h
@ -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 */
|
||||||
Loading…
x
Reference in New Issue
Block a user