funkce vice promennych
This commit is contained in:
parent
a62531d893
commit
14477d73b0
@ -16,6 +16,7 @@ add_executable(Graph
|
|||||||
"tree.c"
|
"tree.c"
|
||||||
"ps_graph.c"
|
"ps_graph.c"
|
||||||
"error_buffer.c"
|
"error_buffer.c"
|
||||||
|
"math_functions.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Optionally, you can set compiler warnings
|
# Optionally, you can set compiler warnings
|
||||||
|
|||||||
120
lex.c
120
lex.c
@ -4,12 +4,15 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
void lex_init(struct lexer *lex, const char *str) {
|
#include "math_functions.h"
|
||||||
|
|
||||||
|
void lex_init(struct lexer *lex, const char *str, const char *variable_name) {
|
||||||
error_buffer_init(&lex->eb);
|
error_buffer_init(&lex->eb);
|
||||||
|
|
||||||
lex->start = str;
|
lex->start = str;
|
||||||
lex->prev_p = str;
|
lex->prev_p = str;
|
||||||
lex->p = str;
|
lex->p = str;
|
||||||
|
lex->variable_name = variable_name;
|
||||||
lex_next(lex);
|
lex_next(lex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +42,24 @@ static int try_advance(struct lexer *lex, const char *str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int is_identifier_char(char c) {
|
||||||
|
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||||
|
}
|
||||||
|
|
||||||
|
static int try_advance_identifier(struct lexer *lex, const char *str) {
|
||||||
|
const char *temp_p = lex->p;
|
||||||
|
if (!try_advance(lex, str))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* overit konec identifikatoru */
|
||||||
|
if (is_identifier_char(*lex->p)) {
|
||||||
|
lex->p = temp_p;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
@ -47,12 +68,18 @@ static int try_token(struct lexer *lex, const char *tok_str, enum token_type typ
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int try_fn(struct lexer *lex, const char *tok_str, enum math_fn fn) {
|
static int try_fns(struct lexer *lex) {
|
||||||
if (try_advance(lex, tok_str)) {
|
const struct math_function *const fns = fns_get();
|
||||||
lex->tok.type = TOK_FUNCTION;
|
size_t i;
|
||||||
lex->tok.val.fn = fn;
|
|
||||||
return 1;
|
for (i = 0; fns[i].name; ++i) {
|
||||||
|
if (try_advance_identifier(lex, fns[i].name)) {
|
||||||
|
lex->tok.type = TOK_FUNCTION;
|
||||||
|
lex->tok.val.fn_idx = i;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,24 +109,16 @@ void lex_next(struct lexer *lex) {
|
|||||||
if (try_token(lex, "/", TOK_DIVIDE)) return;
|
if (try_token(lex, "/", TOK_DIVIDE)) return;
|
||||||
if (try_token(lex, "^", TOK_POWER)) return;
|
if (try_token(lex, "^", TOK_POWER)) return;
|
||||||
|
|
||||||
if (try_token(lex, "x", TOK_X)) return;
|
|
||||||
|
|
||||||
if (try_token(lex, "(", TOK_LEFT_PAREN)) return;
|
if (try_token(lex, "(", TOK_LEFT_PAREN)) return;
|
||||||
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_fn(lex, "abs", FN_ABS)) return;
|
if (try_advance_identifier(lex, lex->variable_name)) {
|
||||||
if (try_fn(lex, "exp", FN_EXP)) return;
|
lex->tok.type = TOK_VARIABLE;
|
||||||
if (try_fn(lex, "ln", FN_LN)) return;
|
return;
|
||||||
if (try_fn(lex, "log", FN_LOG)) return;
|
}
|
||||||
if (try_fn(lex, "sinh", FN_SINH)) return;
|
|
||||||
if (try_fn(lex, "sin", FN_SIN)) return;
|
if (try_fns(lex)) return;
|
||||||
if (try_fn(lex, "cosh", FN_COSH)) return;
|
|
||||||
if (try_fn(lex, "cos", FN_COS)) return;
|
|
||||||
if (try_fn(lex, "tanh", FN_TANH)) return;
|
|
||||||
if (try_fn(lex, "tan", FN_TAN)) return;
|
|
||||||
if (try_fn(lex, "asin", FN_ASIN)) return;
|
|
||||||
if (try_fn(lex, "acos", FN_ACOS)) return;
|
|
||||||
if (try_fn(lex, "atan", FN_ATAN)) return;
|
|
||||||
|
|
||||||
if (try_number(lex)) return;
|
if (try_number(lex)) return;
|
||||||
|
|
||||||
@ -125,7 +144,7 @@ void lex_print_position(const struct lexer *lex, struct error_buffer *eb) {
|
|||||||
error_printf(eb, " ");
|
error_printf(eb, " ");
|
||||||
|
|
||||||
for (i = 0; i < input_len; ++i) {
|
for (i = 0; i < input_len; ++i) {
|
||||||
char c = '_';
|
char c = '~';
|
||||||
if (i == pos)
|
if (i == pos)
|
||||||
c = '^';
|
c = '^';
|
||||||
|
|
||||||
@ -144,47 +163,36 @@ const char *lex_get_error_text(const struct lexer *lex) {
|
|||||||
return error_get_text(&lex->eb);
|
return error_get_text(&lex->eb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *lex_token_str(enum token_type token) {
|
||||||
|
switch (token)
|
||||||
|
{
|
||||||
|
case TOK_EOF: return "<eof>";
|
||||||
|
case TOK_ERROR: return "<error>";
|
||||||
|
case TOK_NUMBER: return "<number>";
|
||||||
|
case TOK_PLUS: return "'+'";
|
||||||
|
case TOK_MINUS: return "'-'";
|
||||||
|
case TOK_MULTIPLY: return "'*'";
|
||||||
|
case TOK_DIVIDE: return "'/'";
|
||||||
|
case TOK_POWER: return "'^'";
|
||||||
|
case TOK_VARIABLE: return "<variable>";
|
||||||
|
case TOK_FUNCTION: return "<function>";
|
||||||
|
case TOK_LEFT_PAREN: return "'('";
|
||||||
|
case TOK_RIGHT_PAREN: return "')'";
|
||||||
|
case TOK_COMMA: return "','";
|
||||||
|
|
||||||
|
default: return "<unknown token>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef LEX_DEBUG
|
#ifdef LEX_DEBUG
|
||||||
|
|
||||||
void lex_debug_print_token(const struct token *tok) {
|
void lex_debug_print_token(const struct token *tok) {
|
||||||
static const char *token_str[] = {
|
printf("%-20s ", lex_token_str(tok->type));
|
||||||
"TOK_EOF",
|
|
||||||
"TOK_ERROR",
|
|
||||||
"TOK_NUMBER",
|
|
||||||
"TOK_PLUS",
|
|
||||||
"TOK_MINUS",
|
|
||||||
"TOK_MULTIPLY",
|
|
||||||
"TOK_DIVIDE",
|
|
||||||
"TOK_POWER",
|
|
||||||
"TOK_X",
|
|
||||||
"TOK_FUNCTION",
|
|
||||||
"TOK_LEFT_PAREN",
|
|
||||||
"TOK_RIGHT_PAREN"
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
printf("%-20s ", token_str[tok->type]);
|
|
||||||
|
|
||||||
if (tok->type == TOK_NUMBER)
|
if (tok->type == TOK_NUMBER)
|
||||||
printf("%.2f\n", tok->val.num);
|
printf("%.2f\n", tok->val.num);
|
||||||
else if (tok->type == TOK_FUNCTION) {
|
else if (tok->type == TOK_FUNCTION) {
|
||||||
static const char *fn_str[] = {
|
printf("%s\n", fns_get()[tok->val.fn_idx].name);
|
||||||
"FN_ABS",
|
|
||||||
"FN_EXP",
|
|
||||||
"FN_LN",
|
|
||||||
"FN_LOG",
|
|
||||||
"FN_SIN",
|
|
||||||
"FN_COS",
|
|
||||||
"FN_TAN",
|
|
||||||
"FN_ASIN",
|
|
||||||
"FN_ACOS",
|
|
||||||
"FN_ATAN",
|
|
||||||
"FN_SINH",
|
|
||||||
"FN_COSH",
|
|
||||||
"FN_TANH"
|
|
||||||
};
|
|
||||||
|
|
||||||
printf("%s\n", fn_str[tok->val.fn]);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|||||||
32
lex.h
32
lex.h
@ -15,33 +15,20 @@ enum token_type {
|
|||||||
TOK_MULTIPLY,
|
TOK_MULTIPLY,
|
||||||
TOK_DIVIDE,
|
TOK_DIVIDE,
|
||||||
TOK_POWER,
|
TOK_POWER,
|
||||||
TOK_X,
|
|
||||||
TOK_FUNCTION,
|
|
||||||
TOK_LEFT_PAREN,
|
|
||||||
TOK_RIGHT_PAREN
|
|
||||||
};
|
|
||||||
|
|
||||||
enum math_fn {
|
TOK_VARIABLE,
|
||||||
FN_ABS,
|
TOK_FUNCTION,
|
||||||
FN_EXP,
|
|
||||||
FN_LN,
|
TOK_LEFT_PAREN,
|
||||||
FN_LOG,
|
TOK_RIGHT_PAREN,
|
||||||
FN_SIN,
|
TOK_COMMA
|
||||||
FN_COS,
|
|
||||||
FN_TAN,
|
|
||||||
FN_ASIN,
|
|
||||||
FN_ACOS,
|
|
||||||
FN_ATAN,
|
|
||||||
FN_SINH,
|
|
||||||
FN_COSH,
|
|
||||||
FN_TANH
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct token {
|
struct token {
|
||||||
enum token_type type;
|
enum token_type type;
|
||||||
union token_val {
|
union token_val {
|
||||||
double num;
|
double num;
|
||||||
enum math_fn fn;
|
size_t fn_idx;
|
||||||
} val;
|
} val;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -51,9 +38,10 @@ struct lexer {
|
|||||||
const char *p;
|
const char *p;
|
||||||
struct token tok;
|
struct token tok;
|
||||||
struct error_buffer eb;
|
struct error_buffer eb;
|
||||||
|
const char *variable_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
void lex_init(struct lexer *lex, const char *str);
|
void lex_init(struct lexer *lex, const char *str, const char *variable_name);
|
||||||
|
|
||||||
void lex_next(struct lexer *lex);
|
void lex_next(struct lexer *lex);
|
||||||
struct token *lex_token(struct lexer *lex);
|
struct token *lex_token(struct lexer *lex);
|
||||||
@ -63,6 +51,8 @@ void lex_print_position(const struct lexer *lex, struct error_buffer *eb);
|
|||||||
enum error_code lex_get_error(const struct lexer *lex);
|
enum error_code lex_get_error(const struct lexer *lex);
|
||||||
const char *lex_get_error_text(const struct lexer *lex);
|
const char *lex_get_error_text(const struct lexer *lex);
|
||||||
|
|
||||||
|
const char *lex_token_str(enum token_type token);
|
||||||
|
|
||||||
#ifdef LEX_DEBUG
|
#ifdef LEX_DEBUG
|
||||||
void lex_debug_print_token(const struct token *tok);
|
void lex_debug_print_token(const struct token *tok);
|
||||||
#endif /* LEX_DEBUG */
|
#endif /* LEX_DEBUG */
|
||||||
|
|||||||
2
main.c
2
main.c
@ -17,7 +17,7 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parser_init(&parser);
|
parser_init(&parser);
|
||||||
node = parser_parse(&parser, argv[1]);
|
node = parser_parse(&parser, argv[1], "x");
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
fprintf(stderr, "%s", parser_get_error_text(&parser));
|
fprintf(stderr, "%s", parser_get_error_text(&parser));
|
||||||
|
|||||||
64
math_functions.c
Normal file
64
math_functions.c
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#include "math_functions.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#define MAKE_FUNCTION_1_ARG(name) \
|
||||||
|
static double mf_##name(const double *args) { \
|
||||||
|
return name(args[0]); \
|
||||||
|
}
|
||||||
|
|
||||||
|
MAKE_FUNCTION_1_ARG(fabs)
|
||||||
|
MAKE_FUNCTION_1_ARG(exp)
|
||||||
|
MAKE_FUNCTION_1_ARG(log)
|
||||||
|
MAKE_FUNCTION_1_ARG(log10)
|
||||||
|
MAKE_FUNCTION_1_ARG(sin)
|
||||||
|
MAKE_FUNCTION_1_ARG(cos)
|
||||||
|
MAKE_FUNCTION_1_ARG(tan)
|
||||||
|
MAKE_FUNCTION_1_ARG(asin)
|
||||||
|
MAKE_FUNCTION_1_ARG(acos)
|
||||||
|
MAKE_FUNCTION_1_ARG(atan)
|
||||||
|
MAKE_FUNCTION_1_ARG(sinh)
|
||||||
|
MAKE_FUNCTION_1_ARG(cosh)
|
||||||
|
MAKE_FUNCTION_1_ARG(tanh)
|
||||||
|
|
||||||
|
static double mf_min(const double *args) {
|
||||||
|
if (args[0] < args[1])
|
||||||
|
return args[0];
|
||||||
|
|
||||||
|
return args[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static double mf_max(const double *args) {
|
||||||
|
if (args[0] > args[1])
|
||||||
|
return args[0];
|
||||||
|
|
||||||
|
return args[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static double mf_mod(const double *args) {
|
||||||
|
return fmod(args[0], args[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct math_function *fns_get(void) {
|
||||||
|
static const struct math_function fns[] = {
|
||||||
|
{ "abs", 1, mf_fabs },
|
||||||
|
{ "exp", 1, mf_exp },
|
||||||
|
{ "ln", 1, mf_log },
|
||||||
|
{ "log", 1, mf_log10 },
|
||||||
|
{ "sin", 1, mf_sin },
|
||||||
|
{ "cos", 1, mf_cos },
|
||||||
|
{ "tan", 1, mf_tan },
|
||||||
|
{ "asin", 1, mf_asin },
|
||||||
|
{ "acos", 1, mf_acos },
|
||||||
|
{ "atan", 1, mf_atan },
|
||||||
|
{ "sinh", 1, mf_sinh },
|
||||||
|
{ "cosh", 1, mf_cosh },
|
||||||
|
{ "tanh", 1, mf_tanh },
|
||||||
|
{ "min", 2, mf_min },
|
||||||
|
{ "max", 2, mf_max },
|
||||||
|
{ "mod", 2, mf_mod },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
return fns;
|
||||||
|
}
|
||||||
18
math_functions.h
Normal file
18
math_functions.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef MATH_FUNCTIONS_H
|
||||||
|
#define MATH_FUNCTIONS_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define MAX_MATH_FUNCTION_ARGS 2
|
||||||
|
|
||||||
|
typedef double (*math_function_ptr)(const double*);
|
||||||
|
|
||||||
|
struct math_function {
|
||||||
|
const char *name;
|
||||||
|
size_t num_args;
|
||||||
|
math_function_ptr ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct math_function *fns_get(void);
|
||||||
|
|
||||||
|
#endif /* MATH_FUNCTIONS_H */
|
||||||
114
parser.c
114
parser.c
@ -14,8 +14,8 @@ static double token_num(struct parser *parser) {
|
|||||||
return get_token(parser)->val.num;
|
return get_token(parser)->val.num;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum math_fn token_fn(struct parser *parser) {
|
static size_t token_fn_idx(struct parser *parser) {
|
||||||
return get_token(parser)->val.fn;
|
return get_token(parser)->val.fn_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void next_token(struct parser *parser) {
|
static void next_token(struct parser *parser) {
|
||||||
@ -36,21 +36,6 @@ static void error_bad_alloc(struct parser *parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void error_expected_one_of(struct parser *parser, const int expected[]) {
|
static void error_expected_one_of(struct parser *parser, const int expected[]) {
|
||||||
static const char* token_name[] = {
|
|
||||||
"end of expression",
|
|
||||||
"lexer error",
|
|
||||||
"constant",
|
|
||||||
"+",
|
|
||||||
"-",
|
|
||||||
"*",
|
|
||||||
"/",
|
|
||||||
"^",
|
|
||||||
"x",
|
|
||||||
"function name",
|
|
||||||
"(",
|
|
||||||
")"
|
|
||||||
};
|
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
enum token_type got = get_token(parser)->type;
|
enum token_type got = get_token(parser)->type;
|
||||||
@ -68,10 +53,10 @@ static void error_expected_one_of(struct parser *parser, const int expected[]) {
|
|||||||
if (i > 0)
|
if (i > 0)
|
||||||
error_printf(&parser->eb, ", ");
|
error_printf(&parser->eb, ", ");
|
||||||
|
|
||||||
error_printf(&parser->eb, "'%s'", token_name[expected[i]]);
|
error_printf(&parser->eb, "%s", lex_token_str(expected[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
error_printf(&parser->eb, " - but got '%s'\n", token_name[got]);
|
error_printf(&parser->eb, " - but got %s\n", lex_token_str(got));
|
||||||
|
|
||||||
lex_print_position(&parser->lexer, &parser->eb);
|
lex_print_position(&parser->lexer, &parser->eb);
|
||||||
}
|
}
|
||||||
@ -83,6 +68,7 @@ static void error_expected_single(struct parser *parser, enum token_type expecte
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct expr_node* parse_subexpression(struct parser *parser);
|
static struct expr_node* parse_subexpression(struct parser *parser);
|
||||||
|
int parse_n_expressions(struct parser *parser, struct expr_node **out_nodes, size_t n);
|
||||||
|
|
||||||
static struct expr_node* parse_bracketed(struct parser *parser) {
|
static struct expr_node* parse_bracketed(struct parser *parser) {
|
||||||
struct expr_node* node;
|
struct expr_node* node;
|
||||||
@ -105,7 +91,7 @@ static struct expr_node* parse_bracketed(struct parser *parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct expr_node *parse_base(struct parser *parser) {
|
static struct expr_node *parse_base(struct parser *parser) {
|
||||||
struct expr_node *node, *inner;
|
struct expr_node *node;
|
||||||
|
|
||||||
if (token_is(parser, TOK_NUMBER)) {
|
if (token_is(parser, TOK_NUMBER)) {
|
||||||
double val = token_num(parser);
|
double val = token_num(parser);
|
||||||
@ -118,7 +104,7 @@ static struct expr_node *parse_base(struct parser *parser) {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accept_token(parser, TOK_X)) {
|
if (accept_token(parser, TOK_VARIABLE)) {
|
||||||
if (!(node = node_create_x())) {
|
if (!(node = node_create_x())) {
|
||||||
error_bad_alloc(parser);
|
error_bad_alloc(parser);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -127,15 +113,33 @@ static struct expr_node *parse_base(struct parser *parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (token_is(parser, TOK_FUNCTION)) {
|
if (token_is(parser, TOK_FUNCTION)) {
|
||||||
enum math_fn fn = token_fn(parser);
|
struct expr_node *arg_nodes[MAX_MATH_FUNCTION_ARGS];
|
||||||
|
size_t i;
|
||||||
|
size_t fn_idx = token_fn_idx(parser);
|
||||||
|
const struct math_function *fn = &fns_get()[fn_idx];
|
||||||
|
|
||||||
next_token(parser);
|
next_token(parser);
|
||||||
|
|
||||||
if (!(inner = parse_bracketed(parser)))
|
if (!accept_token(parser, TOK_LEFT_PAREN)) {
|
||||||
|
error_expected_single(parser, TOK_LEFT_PAREN);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parse_n_expressions(parser, arg_nodes, fn->num_args))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!(node = node_create_fn(fn, inner))) {
|
if (!(node = node_create_fn(fn_idx, arg_nodes))) {
|
||||||
node_free(inner);
|
|
||||||
error_bad_alloc(parser);
|
error_bad_alloc(parser);
|
||||||
|
|
||||||
|
for (i = 0; i < fn->num_args; ++i)
|
||||||
|
node_free(arg_nodes[i]);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!accept_token(parser, TOK_RIGHT_PAREN)) {
|
||||||
|
error_expected_single(parser, TOK_RIGHT_PAREN);
|
||||||
|
node_free(node);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +151,7 @@ static struct expr_node *parse_base(struct parser *parser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
static const int expected[] = { TOK_NUMBER, TOK_X, TOK_FUNCTION, TOK_LEFT_PAREN, -1 };
|
static const int expected[] = { TOK_NUMBER, TOK_VARIABLE, TOK_FUNCTION, TOK_LEFT_PAREN, -1 };
|
||||||
error_expected_one_of(parser, expected);
|
error_expected_one_of(parser, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,29 +273,63 @@ static struct expr_node *parse_subexpression(struct parser *parser) {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct expr_node *parse_expression(struct parser *parser) {
|
int parse_n_expressions(struct parser *parser, struct expr_node **out_nodes, size_t n) {
|
||||||
struct expr_node *node;
|
size_t i;
|
||||||
|
|
||||||
if (!(node = parse_subexpression(parser)))
|
for (i = 0; i < n; ++i) {
|
||||||
return NULL;
|
struct expr_node *node;
|
||||||
|
if (!(node = parse_subexpression(parser)))
|
||||||
|
break;
|
||||||
|
|
||||||
if (!token_is(parser, TOK_EOF)) {
|
out_nodes[i] = node;
|
||||||
error_expected_single(parser, TOK_EOF);
|
|
||||||
node_free(node);
|
if (i < n - 1)
|
||||||
return NULL;
|
accept_token(parser, TOK_COMMA);
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
if (i != n) {
|
||||||
|
while (i) {
|
||||||
|
--i;
|
||||||
|
node_free(out_nodes[i]);
|
||||||
|
out_nodes[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parser_init(struct parser *parser) {
|
void parser_init(struct parser *parser) {
|
||||||
error_buffer_init(&parser->eb);
|
error_buffer_init(&parser->eb);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct expr_node *parser_parse(struct parser *parser, const char *str) {
|
int parser_parse_n(struct parser *parser, const char *str, const char *variable_name, struct expr_node **out_nodes, size_t n) {
|
||||||
lex_init(&parser->lexer, str);
|
lex_init(&parser->lexer, str, variable_name);
|
||||||
return parse_expression(parser);
|
|
||||||
|
|
||||||
|
if (!parse_n_expressions(parser, out_nodes, n)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!token_is(parser, TOK_EOF)) {
|
||||||
|
size_t i;
|
||||||
|
error_expected_single(parser, TOK_EOF);
|
||||||
|
|
||||||
|
for (i = 0; i < n; ++i) {
|
||||||
|
node_free(out_nodes[i]);
|
||||||
|
out_nodes[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *parser_parse(struct parser *parser, const char *str, const char *variable_name) {
|
||||||
|
struct expr_node *out_node = NULL;
|
||||||
|
parser_parse_n(parser, str, variable_name, &out_node, 1);
|
||||||
|
return out_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum error_code parser_get_error(const struct parser *parser) {
|
enum error_code parser_get_error(const struct parser *parser) {
|
||||||
|
|||||||
3
parser.h
3
parser.h
@ -10,7 +10,8 @@ struct parser {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void parser_init(struct parser *parser);
|
void parser_init(struct parser *parser);
|
||||||
struct expr_node *parser_parse(struct parser *parser, const char *str);
|
int parser_parse_n(struct parser *parser, const char *str, const char *variable_name, struct expr_node **out_nodes, size_t n);
|
||||||
|
struct expr_node *parser_parse(struct parser *parser, const char *str, const char *variable_name);
|
||||||
|
|
||||||
enum error_code parser_get_error(const struct parser *parser);
|
enum error_code parser_get_error(const struct parser *parser);
|
||||||
const char *parser_get_error_text(const struct parser *parser);
|
const char *parser_get_error_text(const struct parser *parser);
|
||||||
|
|||||||
87
tree.c
87
tree.c
@ -59,12 +59,18 @@ struct expr_node *node_create_x(void) {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct expr_node *node_create_fn(enum math_fn fn, struct expr_node *arg) {
|
struct expr_node *node_create_fn(size_t fn_idx, struct expr_node **args) {
|
||||||
|
size_t i, num_args;
|
||||||
struct expr_node *node = alloc_node();
|
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 = fn;
|
node->vals.fn.fn_idx = fn_idx;
|
||||||
node->vals.fn.arg = arg;
|
|
||||||
|
num_args = fns_get()[fn_idx].num_args;
|
||||||
|
for (i = 0; i < num_args; ++i) {
|
||||||
|
node->vals.fn.args[i] = args[i];
|
||||||
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +92,12 @@ void node_free(struct expr_node *node) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EXPR_FN:
|
case EXPR_FN:
|
||||||
node_free(node->vals.fn.arg);
|
{
|
||||||
|
size_t i, num_args = fns_get()[node->vals.fn.fn_idx].num_args;
|
||||||
|
for (i = 0; i < num_args; ++i) {
|
||||||
|
node_free(node->vals.fn.args[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -112,22 +123,6 @@ static void debug_print_binop(struct expr_node *node, const char* name, int inde
|
|||||||
debug_print(node->vals.binop.right, indent + 1);
|
debug_print(node->vals.binop.right, indent + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* fn_str[] = {
|
|
||||||
"FN_ABS",
|
|
||||||
"FN_EXP",
|
|
||||||
"FN_LN",
|
|
||||||
"FN_LOG",
|
|
||||||
"FN_SIN",
|
|
||||||
"FN_COS",
|
|
||||||
"FN_TAN",
|
|
||||||
"FN_ASIN",
|
|
||||||
"FN_ACOS",
|
|
||||||
"FN_ATAN",
|
|
||||||
"FN_SINH",
|
|
||||||
"FN_COSH",
|
|
||||||
"FN_TANH"
|
|
||||||
};
|
|
||||||
|
|
||||||
static void debug_print(struct expr_node *node, int indent) {
|
static void debug_print(struct expr_node *node, int indent) {
|
||||||
|
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
@ -167,10 +162,17 @@ static void debug_print(struct expr_node *node, int indent) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EXPR_FN:
|
case EXPR_FN:
|
||||||
debug_indent(indent); printf("[FN] %s\n", fn_str[node->vals.fn.fn]);
|
{
|
||||||
/*debug_indent(indent); printf("arg:\n");*/
|
size_t i;
|
||||||
debug_print(node->vals.fn.arg, indent + 1);
|
const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx];
|
||||||
|
debug_indent(indent); printf("[FN] %s\n", fn->name);
|
||||||
|
|
||||||
|
for (i = 0; i < fn->num_args; ++i) {
|
||||||
|
debug_print(node->vals.fn.args[i], indent + 1);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -230,10 +232,20 @@ static void debug_print_gv(const struct expr_node *node, FILE *output) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EXPR_FN:
|
case EXPR_FN:
|
||||||
fprintf(output, "node%p [label=\"FN: %s\"]\n", (void*)node, fn_str[node->vals.fn.fn]);
|
{
|
||||||
debug_print_gv(node->vals.fn.arg, output);
|
size_t i;
|
||||||
fprintf(output, "node%p -> node%p [label=arg]\n", (void*)node, (void*)node->vals.fn.arg);
|
const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx];
|
||||||
|
|
||||||
|
fprintf(output, "node%p [label=\"FN: %s\"]\n", (void*)node, fn->name);
|
||||||
|
|
||||||
|
for (i = 0; i < fn->num_args; ++i) {
|
||||||
|
struct expr_node *arg = node->vals.fn.args[i];
|
||||||
|
debug_print_gv(arg, output);
|
||||||
|
fprintf(output, "node%p -> node%p [label=arg%d]\n", (void*)node, (void*)arg, (int)i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -275,22 +287,15 @@ double node_eval(const struct expr_node *node, double x) {
|
|||||||
|
|
||||||
case EXPR_FN:
|
case EXPR_FN:
|
||||||
{
|
{
|
||||||
double inner = node_eval(node->vals.fn.arg, x);
|
double inner_results[MAX_MATH_FUNCTION_ARGS];
|
||||||
switch (node->vals.fn.fn) {
|
size_t i;
|
||||||
case FN_ABS: return fabs(inner);
|
const struct math_function *fn = &fns_get()[node->vals.fn.fn_idx];
|
||||||
case FN_EXP: return exp(inner);
|
|
||||||
case FN_LN: return log(inner);
|
for (i = 0; i < fn->num_args; ++i) {
|
||||||
case FN_LOG: return log10(inner);
|
inner_results[i] = node_eval(node->vals.fn.args[i], x);
|
||||||
case FN_SIN: return sin(inner);
|
|
||||||
case FN_COS: return cos(inner);
|
|
||||||
case FN_TAN: return tan(inner);
|
|
||||||
case FN_ASIN: return asin(inner);
|
|
||||||
case FN_ACOS: return acos(inner);
|
|
||||||
case FN_ATAN: return atan(inner);
|
|
||||||
case FN_SINH: return sinh(inner);
|
|
||||||
case FN_COSH: return cosh(inner);
|
|
||||||
case FN_TANH: return tanh(inner);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fn->ptr(inner_results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
7
tree.h
7
tree.h
@ -2,6 +2,7 @@
|
|||||||
#define TREE_H
|
#define TREE_H
|
||||||
|
|
||||||
#include "lex.h"
|
#include "lex.h"
|
||||||
|
#include "math_functions.h"
|
||||||
|
|
||||||
enum expr_type {
|
enum expr_type {
|
||||||
EXPR_CONST,
|
EXPR_CONST,
|
||||||
@ -23,8 +24,8 @@ struct expr_node {
|
|||||||
struct expr_node *right;
|
struct expr_node *right;
|
||||||
} binop;
|
} binop;
|
||||||
struct expr_fn_vals {
|
struct expr_fn_vals {
|
||||||
enum math_fn fn;
|
size_t fn_idx;
|
||||||
struct expr_node *arg;
|
struct expr_node *args[MAX_MATH_FUNCTION_ARGS];
|
||||||
} fn;
|
} fn;
|
||||||
struct expr_node *unop;
|
struct expr_node *unop;
|
||||||
double num;
|
double num;
|
||||||
@ -39,7 +40,7 @@ extern struct expr_node *node_create_mult(struct expr_node *left, struct expr_no
|
|||||||
extern struct expr_node *node_create_div(struct expr_node *left, struct expr_node *right);
|
extern struct expr_node *node_create_div(struct expr_node *left, struct expr_node *right);
|
||||||
extern struct expr_node *node_create_pow(struct expr_node *base, struct expr_node *power);
|
extern struct expr_node *node_create_pow(struct expr_node *base, struct expr_node *power);
|
||||||
extern struct expr_node *node_create_x(void);
|
extern struct expr_node *node_create_x(void);
|
||||||
extern struct expr_node *node_create_fn(enum math_fn fn, struct expr_node *arg);
|
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(struct expr_node *node);
|
||||||
extern void node_debug_print_gv(const struct expr_node *node, FILE *output);
|
extern void node_debug_print_gv(const struct expr_node *node, FILE *output);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user