414 lines
12 KiB
C
414 lines
12 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include "parser.h"
|
|
|
|
/* Vrátí ukazatel na aktuální token */
|
|
static const struct token *get_token(const struct parser *parser) {
|
|
return lex_token(&parser->lexer);
|
|
}
|
|
|
|
/* Vrátí 1, pokud aktuální token je typu <type> */
|
|
static int token_is(const struct parser *parser, enum token_type type) {
|
|
return get_token(parser)->type == type;
|
|
}
|
|
|
|
/* Vrátí hodnotu tokenu, který je konstanta */
|
|
static double token_num(const struct parser *parser) {
|
|
return get_token(parser)->val.num;
|
|
}
|
|
|
|
/* Vrátí index funkce tokenu, který reprezentuje funkci */
|
|
static size_t token_fn_idx(const struct parser *parser) {
|
|
return get_token(parser)->val.fn_idx;
|
|
}
|
|
|
|
/* Načte další token */
|
|
static void next_token(struct parser *parser) {
|
|
lex_next(&parser->lexer);
|
|
}
|
|
|
|
/* Vrátí 1, pokud je aktuální token typu <type> a načte další */
|
|
static int accept_token(struct parser *parser, enum token_type type) {
|
|
if (token_is(parser, type)) {
|
|
next_token(parser);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Nastaví chybu při alokaci */
|
|
static void error_bad_alloc(struct parser *parser) {
|
|
error_set(&parser->eb, ERR_BAD_ALLOC);
|
|
error_printf(&parser->eb, "Out of memory\n");
|
|
}
|
|
|
|
/* Vyhodí chybu při neočekávaném tokenu */
|
|
static void error_expected_tokens(struct parser *parser, size_t num_tokens, ...) {
|
|
size_t i;
|
|
va_list ap;
|
|
|
|
/* vyskytující se token */
|
|
enum token_type got = get_token(parser)->type;
|
|
|
|
/* chyba při lexikální analýze */
|
|
if (got == TOK_ERROR) {
|
|
error_set(&parser->eb, lex_get_error(&parser->lexer));
|
|
error_printf(&parser->eb, "%s", lex_get_error_text(&parser->lexer));
|
|
return;
|
|
}
|
|
|
|
error_set(&parser->eb, ERR_INVALID_FUNCTION);
|
|
error_printf(&parser->eb, "Syntax error - expected ");
|
|
|
|
/* výpis očekávaných tokenů */
|
|
va_start(ap, num_tokens);
|
|
for (i = 0; i < num_tokens; ++i) {
|
|
enum token_type tok = va_arg(ap, enum token_type);
|
|
|
|
if (i > 0)
|
|
error_printf(&parser->eb, ", ");
|
|
|
|
error_printf(&parser->eb, "%s", lex_token_str(tok));
|
|
}
|
|
va_end(ap);
|
|
|
|
/* výpis vyskytlého se tokenu */
|
|
error_printf(&parser->eb, " - but got %s\n", lex_token_str(got));
|
|
|
|
/* výpis aktuální pozice ve vstupním řetězci */
|
|
lex_print_position(&parser->lexer, &parser->eb);
|
|
}
|
|
|
|
static struct expr_node *parse_expression(struct parser *parser);
|
|
static int parse_n_expressions(struct parser *parser, struct expr_node **out_nodes, size_t n);
|
|
|
|
/* Zpracuje výraz obalený závorkami */
|
|
static struct expr_node *parse_bracketed(struct parser *parser) {
|
|
struct expr_node *node;
|
|
|
|
/* požadovat levou závorku */
|
|
if (!accept_token(parser, TOK_LEFT_PAREN)) {
|
|
error_expected_tokens(parser, 1, TOK_LEFT_PAREN);
|
|
return NULL;
|
|
}
|
|
|
|
/* zpracovat výraz v závorkach */
|
|
if (!(node = parse_expression(parser)))
|
|
return NULL;
|
|
|
|
/* požadovat pravou závorku */
|
|
if (!accept_token(parser, TOK_RIGHT_PAREN)) {
|
|
error_expected_tokens(parser, 1, TOK_RIGHT_PAREN);
|
|
node_free(node);
|
|
return NULL;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
static struct expr_node *parse_function(struct parser *parser) {
|
|
struct expr_node *node;
|
|
struct expr_node *arg_nodes[MAX_MATH_FUNCTION_ARGS];
|
|
size_t i;
|
|
|
|
/* funkce */
|
|
size_t fn_idx = token_fn_idx(parser);
|
|
const struct math_function *fn = &fns_get()[fn_idx];
|
|
|
|
next_token(parser);
|
|
|
|
/* požadovat levou závorku */
|
|
if (!accept_token(parser, TOK_LEFT_PAREN)) {
|
|
error_expected_tokens(parser, 1, TOK_LEFT_PAREN);
|
|
return NULL;
|
|
}
|
|
|
|
/* zpracovat argumenty funkce */
|
|
if (!parse_n_expressions(parser, arg_nodes, fn->num_args))
|
|
return NULL;
|
|
|
|
/* vytvořit uzel funkce */
|
|
if (!(node = node_create_fn(fn_idx, arg_nodes))) {
|
|
error_bad_alloc(parser);
|
|
|
|
/* uvolnit všechny uzly argumentů */
|
|
for (i = 0; i < fn->num_args; ++i)
|
|
node_free(arg_nodes[i]);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* požadovat pravou závorku */
|
|
if (!accept_token(parser, TOK_RIGHT_PAREN)) {
|
|
error_expected_tokens(parser, 1, TOK_RIGHT_PAREN);
|
|
node_free(node);
|
|
return NULL;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/* Zpracuje část výrazu, která už má nejvyšší precedenci (číselnou konstantu, proměnnou, funkci, nebo výraz obalený závorkami) */
|
|
static struct expr_node *parse_factor(struct parser *parser) {
|
|
struct expr_node *node;
|
|
|
|
/* konstanta */
|
|
if (token_is(parser, TOK_NUMBER)) {
|
|
double val = token_num(parser);
|
|
next_token(parser);
|
|
if (!(node = node_create_const(val))) {
|
|
error_bad_alloc(parser);
|
|
return NULL;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/* proměnná */
|
|
if (accept_token(parser, TOK_VARIABLE)) {
|
|
if (!(node = node_create_x())) {
|
|
error_bad_alloc(parser);
|
|
return NULL;
|
|
}
|
|
return node;
|
|
}
|
|
|
|
/* funkce */
|
|
if (token_is(parser, TOK_FUNCTION)) {
|
|
return parse_function(parser);
|
|
}
|
|
|
|
/* výraz obalený závorkami */
|
|
if (token_is(parser, TOK_LEFT_PAREN)) {
|
|
return parse_bracketed(parser);
|
|
}
|
|
|
|
error_expected_tokens(parser, 4, TOK_NUMBER, TOK_VARIABLE, TOK_FUNCTION, TOK_LEFT_PAREN);
|
|
return NULL;
|
|
}
|
|
|
|
static struct expr_node *parse_unary(struct parser *parser);
|
|
|
|
/* Zpracuje umocnění */
|
|
static struct expr_node *parse_power(struct parser *parser) {
|
|
struct expr_node *node, *new_node, *inner;
|
|
|
|
/* základ (nebo výsledek pokud nenásleduje umocnění) */
|
|
if (!(node = parse_factor(parser)))
|
|
return NULL;
|
|
|
|
/* umocnění? */
|
|
if (accept_token(parser, TOK_POWER)) {
|
|
/* exponent */
|
|
if (!(inner = parse_unary(parser))) {
|
|
node_free(node);
|
|
return NULL;
|
|
}
|
|
|
|
/* vytvořit uzel umocnění */
|
|
if (!(new_node = node_create_pow(node, inner))) {
|
|
error_bad_alloc(parser);
|
|
node_free(node);
|
|
node_free(inner);
|
|
return NULL;
|
|
}
|
|
|
|
return new_node;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/* Zpracuje unární mínus, resp. plus */
|
|
static struct expr_node *parse_unary(struct parser *parser) {
|
|
/* unární mínus? */
|
|
if (accept_token(parser, TOK_MINUS)) {
|
|
struct expr_node *node, *inner;
|
|
|
|
/* operand */
|
|
if (!(inner = parse_power(parser)))
|
|
return NULL;
|
|
|
|
/* vytvořit uzel negace */
|
|
if (!(node = node_create_neg(inner))) {
|
|
error_bad_alloc(parser);
|
|
node_free(inner);
|
|
return NULL;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/* unární plus - nehraje roli */
|
|
accept_token(parser, TOK_PLUS);
|
|
|
|
return parse_power(parser);
|
|
}
|
|
|
|
/* Zpracuje součin nebo dělení */
|
|
static struct expr_node *parse_term(struct parser *parser) {
|
|
struct expr_node *node, *new_node, *inner;
|
|
|
|
/* výraz před prvním operátorem */
|
|
if (!(node = parse_unary(parser)))
|
|
return NULL;
|
|
|
|
/* iterovat dokud se za výrazy nachází operátory součinu nebo dělení */
|
|
/* bylo by možné "vyřešit" rekurzí, ale není nutné */
|
|
while (1) {
|
|
/* funkce pro vytvoření uzlu binární operace na základě operátoru */
|
|
struct expr_node *(*create_node)(struct expr_node *left, struct expr_node *right);
|
|
|
|
/* rozhodnout se na základě operátoru, případně ukončit smyčku */
|
|
if (accept_token(parser, TOK_MULTIPLY))
|
|
create_node = node_create_mult;
|
|
else if (accept_token(parser, TOK_DIVIDE))
|
|
create_node = node_create_div;
|
|
else
|
|
break;
|
|
|
|
/* zpracovat další výraz */
|
|
if (!(inner = parse_unary(parser))) {
|
|
node_free(node);
|
|
return NULL;
|
|
}
|
|
|
|
/* vytvořit uzel pro danou operaci */
|
|
if (!(new_node = create_node(node, inner))) {
|
|
error_bad_alloc(parser);
|
|
node_free(node);
|
|
node_free(inner);
|
|
return NULL;
|
|
}
|
|
|
|
/* uzly postupně řetězit */
|
|
node = new_node;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/* Zpracuje sčítání nebo odečítání */
|
|
static struct expr_node *parse_expression(struct parser *parser) {
|
|
struct expr_node *node, *new_node, *inner;
|
|
|
|
/* výraz před prvním operátorem */
|
|
if (!(node = parse_term(parser)))
|
|
return NULL;
|
|
|
|
/* iterovat dokud se za výrazy nachází operátory sčítání nebo odčítání */
|
|
/* bylo by možné "vyřešit" rekurzí, ale není nutné */
|
|
while (1) {
|
|
/* funkce pro vytvoření uzlu binární operace na základě operátoru */
|
|
struct expr_node *(*create_node)(struct expr_node *left, struct expr_node *right);
|
|
|
|
/* rozhodnout se na základě operátoru, případně ukončit smyčku */
|
|
if (accept_token(parser, TOK_PLUS))
|
|
create_node = node_create_add;
|
|
else if (accept_token(parser, TOK_MINUS))
|
|
create_node = node_create_sub;
|
|
else
|
|
break;
|
|
|
|
/* zpracovat další výraz */
|
|
if (!(inner = parse_term(parser))) {
|
|
node_free(node);
|
|
return NULL;
|
|
}
|
|
|
|
/* vytvořit uzel pro danou operaci */
|
|
if (!(new_node = create_node(node, inner))) {
|
|
error_bad_alloc(parser);
|
|
node_free(node);
|
|
node_free(inner);
|
|
return NULL;
|
|
}
|
|
|
|
/* uzly postupně řetězit */
|
|
node = new_node;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/* Zpracuje n výrazů */
|
|
static int parse_n_expressions(struct parser *parser, struct expr_node **out_nodes, size_t n) {
|
|
size_t i;
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
struct expr_node *node;
|
|
if (!(node = parse_expression(parser)))
|
|
break;
|
|
|
|
out_nodes[i] = node;
|
|
|
|
/* akceptovat čárku jakožto oddělovač výrazů */
|
|
if (i < n - 1)
|
|
accept_token(parser, TOK_COMMA);
|
|
}
|
|
|
|
/* nebyly zpracovány všechny výrazy? */
|
|
if (i != n) {
|
|
/* uvolnit všechny doposud alokované uzly */
|
|
while (i) {
|
|
--i;
|
|
node_free(out_nodes[i]);
|
|
out_nodes[i] = NULL;
|
|
}
|
|
|
|
/* chyba */
|
|
return 0;
|
|
}
|
|
|
|
/* úspěch */
|
|
return 1;
|
|
}
|
|
|
|
int parser_parse_n(struct parser *parser, const char *str, const char *variable_name, struct expr_node **out_nodes, size_t n) {
|
|
/* inicializace chybového bufferu */
|
|
error_buffer_init(&parser->eb);
|
|
|
|
/* inicializace lexikálního analyzázoru */
|
|
lex_init(&parser->lexer, str, variable_name);
|
|
|
|
/* zpracování n tokenů */
|
|
if (!parse_n_expressions(parser, out_nodes, n)) {
|
|
return 0;
|
|
}
|
|
|
|
/* požadovat konec vstupu */
|
|
if (!token_is(parser, TOK_EOF)) {
|
|
size_t i;
|
|
error_expected_tokens(parser, 1, TOK_EOF);
|
|
|
|
/* uvolnit všechny uzly */
|
|
for (i = 0; i < n; ++i) {
|
|
node_free(out_nodes[i]);
|
|
out_nodes[i] = NULL;
|
|
}
|
|
|
|
/* chyba */
|
|
return 0;
|
|
}
|
|
|
|
/* úspěch */
|
|
return 1;
|
|
}
|
|
|
|
struct expr_node *parser_parse(struct parser *parser, const char *str, const char *variable_name) {
|
|
struct expr_node *out_node = NULL;
|
|
|
|
/* zpracování jednoho výrazu */
|
|
parser_parse_n(parser, str, variable_name, &out_node, 1);
|
|
|
|
return out_node;
|
|
}
|
|
|
|
enum error_code parser_get_error(const struct parser *parser) {
|
|
return error_get(&parser->eb);
|
|
}
|
|
|
|
const char *parser_get_error_text(const struct parser *parser) {
|
|
return error_get_text(&parser->eb);
|
|
} |