init
This commit is contained in:
commit
704979f9bb
29
CMakeLists.txt
Normal file
29
CMakeLists.txt
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Minimum required CMake version
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
# Project name and version
|
||||||
|
project(Graph VERSION 1.0)
|
||||||
|
|
||||||
|
# Specify the C standard
|
||||||
|
set(CMAKE_C_STANDARD 90)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
|
# Add the executable target
|
||||||
|
add_executable(Graph
|
||||||
|
"main.c"
|
||||||
|
"lex.c"
|
||||||
|
"parser.c"
|
||||||
|
"tree.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Optionally, you can set compiler warnings
|
||||||
|
if (MSVC)
|
||||||
|
target_compile_options(Graph PRIVATE /W4)
|
||||||
|
else()
|
||||||
|
target_compile_options(Graph PRIVATE -Wall -Wextra -pedantic)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Optionally, set the output directory for the executable
|
||||||
|
# set_target_properties(Graph PROPERTIES
|
||||||
|
# RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||||
|
# )
|
||||||
191
lex.c
Normal file
191
lex.c
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "lex.h"
|
||||||
|
|
||||||
|
struct lexer {
|
||||||
|
const char* start;
|
||||||
|
const char* prev_p;
|
||||||
|
const char* p;
|
||||||
|
struct token tok;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lexer *lex_create(const char *str) {
|
||||||
|
struct lexer *lex = malloc(sizeof(struct lexer));
|
||||||
|
|
||||||
|
if (!lex)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
lex->start = str;
|
||||||
|
lex->prev_p = str;
|
||||||
|
lex->p = str;
|
||||||
|
|
||||||
|
lex_next(lex);
|
||||||
|
|
||||||
|
return lex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lex_free(struct lexer *lex) {
|
||||||
|
free(lex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_whitespace(char p) {
|
||||||
|
return p == ' ' || p == '\t' || p == '\n' || p == '\r';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void skip_whitespace(struct lexer *lex) {
|
||||||
|
while (is_whitespace(*lex->p))
|
||||||
|
++lex->p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int try_advance(struct lexer *lex, const char *str) {
|
||||||
|
const char *temp_p = lex->p;
|
||||||
|
while (1) {
|
||||||
|
if (!*str) {
|
||||||
|
lex->p = temp_p;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*str != *temp_p) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
++temp_p;
|
||||||
|
++str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int try_token(struct lexer *lex, const char *tok_str, enum token_type type) {
|
||||||
|
if (try_advance(lex, tok_str)) {
|
||||||
|
lex->tok.type = type;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int try_fn(struct lexer *lex, const char *tok_str, enum math_fn fn) {
|
||||||
|
if (try_advance(lex, tok_str)) {
|
||||||
|
lex->tok.type = TOK_FUNCTION;
|
||||||
|
lex->tok.val.fn = fn;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int try_number(struct lexer* lex) {
|
||||||
|
char *end;
|
||||||
|
double val;
|
||||||
|
val = strtod(lex->p, &end);
|
||||||
|
if (lex->p == end) return 0;
|
||||||
|
lex->tok.type = TOK_NUMBER;
|
||||||
|
lex->tok.val.num = val;
|
||||||
|
lex->p = end;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lex_next(struct lexer *lex) {
|
||||||
|
skip_whitespace(lex);
|
||||||
|
lex->prev_p = lex->p;
|
||||||
|
|
||||||
|
if (!*lex->p) {
|
||||||
|
lex->tok.type = TOK_EOF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (try_token(lex, "+", TOK_PLUS)) return;
|
||||||
|
if (try_token(lex, "-", TOK_MINUS)) return;
|
||||||
|
if (try_token(lex, "*", TOK_MULTIPLY)) return;
|
||||||
|
if (try_token(lex, "/", TOK_DIVIDE)) return;
|
||||||
|
if (try_token(lex, "^", TOK_POWER)) return;
|
||||||
|
|
||||||
|
if (try_token(lex, "x", TOK_X)) return;
|
||||||
|
|
||||||
|
if (try_token(lex, "(", TOK_LEFT_PAREN)) return;
|
||||||
|
if (try_token(lex, ")", TOK_RIGHT_PAREN)) return;
|
||||||
|
|
||||||
|
if (try_fn(lex, "abs", FN_ABS)) return;
|
||||||
|
if (try_fn(lex, "exp", FN_EXP)) return;
|
||||||
|
if (try_fn(lex, "ln", FN_LN)) 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_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;
|
||||||
|
|
||||||
|
fprintf(stderr, "Lexer error - unrecognized sequence \"%s\"\n", lex->p);
|
||||||
|
lex_print_position(lex);
|
||||||
|
|
||||||
|
lex->tok.type = TOK_ERROR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct token *lex_token(struct lexer *lex) {
|
||||||
|
return &lex->tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lex_print_position(struct lexer *lex) {
|
||||||
|
int i;
|
||||||
|
int pos = lex->prev_p - lex->start;
|
||||||
|
|
||||||
|
fprintf(stderr, "At character %d\n", pos);
|
||||||
|
fprintf(stderr, " %s\n", lex->start);
|
||||||
|
fprintf(stderr, " ");
|
||||||
|
for (i = 0; i < pos; ++i)
|
||||||
|
fprintf(stderr, " ");
|
||||||
|
|
||||||
|
fprintf(stderr, "^\n----------------------------------------------------\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LEX_DEBUG
|
||||||
|
|
||||||
|
void lex_debug_print_token(struct token *tok) {
|
||||||
|
static const char *token_str[] = {
|
||||||
|
"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"
|
||||||
|
};
|
||||||
|
|
||||||
|
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"
|
||||||
|
};
|
||||||
|
|
||||||
|
printf("%-20s ", token_str[tok->type]);
|
||||||
|
|
||||||
|
if (tok->type == TOK_NUMBER)
|
||||||
|
printf("%.2f\n", tok->val.num);
|
||||||
|
else if (tok->type == TOK_FUNCTION)
|
||||||
|
printf("%s\n", fn_str[tok->val.fn]);
|
||||||
|
else
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* LEX_DEBUG */
|
||||||
61
lex.h
Normal file
61
lex.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#ifndef LEX_H
|
||||||
|
#define LEX_H
|
||||||
|
|
||||||
|
#define LEX_DEBUG
|
||||||
|
|
||||||
|
enum token_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
|
||||||
|
};
|
||||||
|
|
||||||
|
enum math_fn {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
struct token {
|
||||||
|
enum token_type type;
|
||||||
|
union token_val {
|
||||||
|
double num;
|
||||||
|
enum math_fn fn;
|
||||||
|
} val;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lexer;
|
||||||
|
|
||||||
|
extern struct lexer *lex_create(const char *str);
|
||||||
|
extern void lex_free(struct lexer *lex);
|
||||||
|
|
||||||
|
extern void lex_next(struct lexer *lex);
|
||||||
|
extern struct token *lex_token(struct lexer *lex);
|
||||||
|
|
||||||
|
extern void lex_print_position(struct lexer *lex);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LEX_DEBUG
|
||||||
|
extern void lex_debug_print_token(struct token *tok);
|
||||||
|
#endif /* LEX_DEBUG */
|
||||||
|
|
||||||
|
#endif /* LEX_H */
|
||||||
38
main.c
Normal file
38
main.c
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "lex.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
struct lexer *lex;
|
||||||
|
struct expr_node *node;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("Usage: %s <expression>\n", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
//struct lexer *lex = lex_create("x* sin (x ^ 2) * 5.5e+2* cosh (x )");
|
||||||
|
//struct lexer *lex = lex_create("-1 + -2 - 3 + 4");
|
||||||
|
*/
|
||||||
|
lex = lex_create(argv[1]);
|
||||||
|
|
||||||
|
node = parse_expression(lex);
|
||||||
|
lex_free(lex);
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
double x;
|
||||||
|
node_debug_print(node);
|
||||||
|
printf("polygon(");
|
||||||
|
for (x = -10.0; x < 10.0; x += 0.1) {
|
||||||
|
printf("(%.2f,%.2f),", x, node_eval(node, x));
|
||||||
|
}
|
||||||
|
printf("(10, -1000),(-10,-1000))\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
node_free(node);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
263
parser.c
Normal file
263
parser.c
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
static int token_is(struct lexer *lex, enum token_type type) {
|
||||||
|
return lex_token(lex)->type == type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int accept(struct lexer *lex, enum token_type type) {
|
||||||
|
if (token_is(lex, type)) {
|
||||||
|
lex_next(lex);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double token_num(struct lexer *lex) {
|
||||||
|
return lex_token(lex)->val.num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum math_fn token_fn(struct lexer *lex) {
|
||||||
|
return lex_token(lex)->val.fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void error_expected_one_of(struct lexer *lex, const int expected[], enum token_type got) {
|
||||||
|
static const char* token_name[] = {
|
||||||
|
"end of expression",
|
||||||
|
"lexer error",
|
||||||
|
"constant",
|
||||||
|
"+",
|
||||||
|
"-",
|
||||||
|
"*",
|
||||||
|
"/",
|
||||||
|
"^",
|
||||||
|
"x",
|
||||||
|
"function name",
|
||||||
|
"(",
|
||||||
|
")"
|
||||||
|
};
|
||||||
|
|
||||||
|
int separate = 0;
|
||||||
|
|
||||||
|
fprintf(stderr, "Syntax error - expected ");
|
||||||
|
|
||||||
|
for (; *expected >= 0; ++expected) {
|
||||||
|
if (separate)
|
||||||
|
fprintf(stderr, ", ");
|
||||||
|
else
|
||||||
|
separate = 1;
|
||||||
|
|
||||||
|
fprintf(stderr, "'%s'", token_name[*expected]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, " - but got '%s'\n", token_name[got]);
|
||||||
|
|
||||||
|
lex_print_position(lex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void error_expected_single(struct lexer *lex, enum token_type expected, enum token_type got) {
|
||||||
|
static int expected_arr[] = { -1, -1 };
|
||||||
|
expected_arr[0] = expected;
|
||||||
|
error_expected_one_of(lex, expected_arr, got);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *parse_subexpression(struct lexer *lex);
|
||||||
|
|
||||||
|
static struct expr_node *parse_bracketed(struct lexer* lex) {
|
||||||
|
struct expr_node *node;
|
||||||
|
|
||||||
|
if (!accept(lex, TOK_LEFT_PAREN)) {
|
||||||
|
error_expected_single(lex, TOK_LEFT_PAREN, lex_token(lex)->type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(node = parse_subexpression(lex)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!accept(lex, TOK_RIGHT_PAREN)) {
|
||||||
|
error_expected_single(lex, TOK_RIGHT_PAREN, lex_token(lex)->type);
|
||||||
|
node_free(node);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct expr_node *parse_base(struct lexer *lex) {
|
||||||
|
struct expr_node *inner;
|
||||||
|
|
||||||
|
if (token_is(lex, TOK_NUMBER)) {
|
||||||
|
double val = token_num(lex);
|
||||||
|
lex_next(lex);
|
||||||
|
return node_create_const(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accept(lex, TOK_X)) {
|
||||||
|
return node_create_x();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token_is(lex, TOK_FUNCTION)) {
|
||||||
|
enum math_fn fn = token_fn(lex);
|
||||||
|
lex_next(lex);
|
||||||
|
|
||||||
|
if (!(inner = parse_bracketed(lex)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return node_create_fn(fn, inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token_is(lex, TOK_LEFT_PAREN)) {
|
||||||
|
return parse_bracketed(lex);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
static const int expected[] = { TOK_NUMBER, TOK_X, TOK_FUNCTION, TOK_LEFT_PAREN, -1 };
|
||||||
|
error_expected_one_of(lex, expected, lex_token(lex)->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct expr_node* parse_unary(struct lexer *lex) {
|
||||||
|
if (accept(lex, TOK_MINUS)) {
|
||||||
|
struct expr_node *node, *inner;
|
||||||
|
|
||||||
|
if (!(inner = parse_base(lex)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(node = node_create_neg(inner))) {
|
||||||
|
node_free(inner);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
accept(lex, TOK_PLUS);
|
||||||
|
return parse_base(lex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct expr_node *parse_factor(struct lexer *lex) {
|
||||||
|
struct expr_node *node, *new_node, *inner;
|
||||||
|
|
||||||
|
if (!(node = parse_unary(lex)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (accept(lex, TOK_POWER)) {
|
||||||
|
if (!(inner = parse_unary(lex))) {
|
||||||
|
node_free(node);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(new_node = node_create_pow(node, inner))) {
|
||||||
|
node_free(node);
|
||||||
|
node_free(inner);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = new_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct expr_node *parse_term(struct lexer *lex) {
|
||||||
|
struct expr_node *node, *new_node, *inner;
|
||||||
|
|
||||||
|
if (!(node = parse_factor(lex)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
struct expr_node *(*create_node)(struct expr_node *left, struct expr_node *right);
|
||||||
|
|
||||||
|
if (accept(lex, TOK_MULTIPLY))
|
||||||
|
create_node = node_create_mult;
|
||||||
|
else if (accept(lex, TOK_DIVIDE))
|
||||||
|
create_node = node_create_div;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!(inner = parse_factor(lex))) {
|
||||||
|
node_free(node);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(new_node = create_node(node, inner))) {
|
||||||
|
node_free(node);
|
||||||
|
node_free(inner);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = new_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *parse_subexpression(struct lexer *lex) {
|
||||||
|
struct expr_node *node, *new_node, *inner;
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (accept(lex, TOK_MINUS)) {
|
||||||
|
if (!(term = parse_term(lex)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(node = node_create_neg(term))) {
|
||||||
|
node_free(term);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
accept(lex, TOK_PLUS);
|
||||||
|
|
||||||
|
if (!(node = parse_term(lex)))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!(node = parse_term(lex)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
struct expr_node *(*create_node)(struct expr_node *left, struct expr_node *right);
|
||||||
|
|
||||||
|
if (accept(lex, TOK_PLUS))
|
||||||
|
create_node = node_create_add;
|
||||||
|
else if (accept(lex, TOK_MINUS))
|
||||||
|
create_node = node_create_sub;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!(inner = parse_term(lex))) {
|
||||||
|
node_free(node);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(new_node = create_node(node, inner))) {
|
||||||
|
node_free(node);
|
||||||
|
node_free(inner);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = new_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *parse_expression(struct lexer *lex) {
|
||||||
|
struct expr_node *node;
|
||||||
|
|
||||||
|
if (!(node = parse_subexpression(lex)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!token_is(lex, TOK_EOF)) {
|
||||||
|
error_expected_single(lex, TOK_EOF, lex_token(lex)->type);
|
||||||
|
node_free(node);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
8
parser.h
Normal file
8
parser.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef PARSER_H
|
||||||
|
#define PARSER_H
|
||||||
|
|
||||||
|
#include "tree.h"
|
||||||
|
|
||||||
|
extern struct expr_node *parse_expression(struct lexer *lex);
|
||||||
|
|
||||||
|
#endif /* PARSER_H */
|
||||||
232
tree.c
Normal file
232
tree.c
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "tree.h"
|
||||||
|
|
||||||
|
static struct expr_node *alloc_node(void) {
|
||||||
|
return malloc(sizeof(struct expr_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *node_create_const(double val) {
|
||||||
|
struct expr_node *node = alloc_node();
|
||||||
|
if (!node) return NULL;
|
||||||
|
node->type = EXPR_CONST;
|
||||||
|
node->vals.num = val;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *node_create_neg(struct expr_node *unop) {
|
||||||
|
struct expr_node *node = alloc_node();
|
||||||
|
if (!node) return NULL;
|
||||||
|
node->type = EXPR_NEG;
|
||||||
|
node->vals.unop = unop;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct expr_node *create_binary_node(enum expr_type type, struct expr_node *left, struct expr_node *right) {
|
||||||
|
struct expr_node *node = alloc_node();
|
||||||
|
if (!node) return NULL;
|
||||||
|
node->type = type;
|
||||||
|
node->vals.binop.left = left;
|
||||||
|
node->vals.binop.right = right;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *node_create_add(struct expr_node *left, struct expr_node *right) {
|
||||||
|
return create_binary_node(EXPR_ADD, left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *node_create_sub(struct expr_node *left, struct expr_node *right) {
|
||||||
|
return create_binary_node(EXPR_SUB, left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *node_create_mult(struct expr_node *left, struct expr_node *right) {
|
||||||
|
return create_binary_node(EXPR_MULT, left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *node_create_div(struct expr_node *left, struct expr_node *right) {
|
||||||
|
return create_binary_node(EXPR_DIV, left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *node_create_pow(struct expr_node *base, struct expr_node *power) {
|
||||||
|
return create_binary_node(EXPR_POW, base, power);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *node_create_x(void) {
|
||||||
|
struct expr_node *node = alloc_node();
|
||||||
|
if (!node) return NULL;
|
||||||
|
node->type = EXPR_X;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct expr_node *node_create_fn(enum math_fn fn, struct expr_node *arg) {
|
||||||
|
struct expr_node *node = alloc_node();
|
||||||
|
if (!node) return NULL;
|
||||||
|
node->type = EXPR_FN;
|
||||||
|
node->vals.fn.fn = fn;
|
||||||
|
node->vals.fn.arg = arg;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_free(struct expr_node *node) {
|
||||||
|
if (!node) return;
|
||||||
|
|
||||||
|
switch (node->type) {
|
||||||
|
case EXPR_ADD:
|
||||||
|
case EXPR_SUB:
|
||||||
|
case EXPR_MULT:
|
||||||
|
case EXPR_DIV:
|
||||||
|
case EXPR_POW:
|
||||||
|
node_free(node->vals.binop.left);
|
||||||
|
node_free(node->vals.binop.right);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_NEG:
|
||||||
|
node_free(node->vals.unop);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_FN:
|
||||||
|
node_free(node->vals.fn.arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debug_indent(int indent) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < indent; ++i)
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void debug_print(struct expr_node *node, 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("left:\n");*/
|
||||||
|
debug_print(node->vals.binop.left, 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 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"
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (node->type) {
|
||||||
|
case EXPR_ADD:
|
||||||
|
debug_print_binop(node, "ADD", indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_SUB:
|
||||||
|
debug_print_binop(node, "SUB", indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_MULT:
|
||||||
|
debug_print_binop(node, "MULT", indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_DIV:
|
||||||
|
debug_print_binop(node, "DIV", indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_POW:
|
||||||
|
debug_print_binop(node, "POW", indent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_NEG:
|
||||||
|
debug_indent(indent); printf("[NEG]\n");
|
||||||
|
/*debug_indent(indent); printf("unop:\n");*/
|
||||||
|
debug_print(node->vals.unop, indent + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_CONST:
|
||||||
|
debug_indent(indent); printf("[CONST] %.2f\n", node->vals.num);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_X:
|
||||||
|
debug_indent(indent); printf("[X]\n");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXPR_FN:
|
||||||
|
debug_indent(indent); printf("[FN] %s\n", fn_str[node->vals.fn.fn]);
|
||||||
|
/*debug_indent(indent); printf("arg:\n");*/
|
||||||
|
debug_print(node->vals.fn.arg, indent + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void node_debug_print(struct expr_node *node) {
|
||||||
|
debug_print(node, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double node_eval(struct expr_node *node, double x) {
|
||||||
|
switch (node->type) {
|
||||||
|
case EXPR_CONST:
|
||||||
|
return node->vals.num;
|
||||||
|
|
||||||
|
case EXPR_X:
|
||||||
|
return x;
|
||||||
|
|
||||||
|
case EXPR_NEG:
|
||||||
|
return -node_eval(node->vals.unop, x);
|
||||||
|
|
||||||
|
case EXPR_ADD:
|
||||||
|
return node_eval(node->vals.binop.left, x) + node_eval(node->vals.binop.right, x);
|
||||||
|
|
||||||
|
case EXPR_SUB:
|
||||||
|
return node_eval(node->vals.binop.left, x) - node_eval(node->vals.binop.right, x);
|
||||||
|
|
||||||
|
case EXPR_MULT:
|
||||||
|
return node_eval(node->vals.binop.left, x) * node_eval(node->vals.binop.right, x);
|
||||||
|
|
||||||
|
case EXPR_DIV:
|
||||||
|
return node_eval(node->vals.binop.left, x) / node_eval(node->vals.binop.right, x);
|
||||||
|
|
||||||
|
case EXPR_POW:
|
||||||
|
return pow(node_eval(node->vals.binop.left, x), node_eval(node->vals.binop.right, x));
|
||||||
|
|
||||||
|
case EXPR_FN:
|
||||||
|
{
|
||||||
|
double inner = node_eval(node->vals.fn.arg, x);
|
||||||
|
switch (node->vals.fn.fn) {
|
||||||
|
case FN_ABS: return fabs(inner);
|
||||||
|
case FN_EXP: return exp(inner);
|
||||||
|
case FN_LN: return log(inner);
|
||||||
|
case FN_LOG: return log10(inner);
|
||||||
|
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 0.0;
|
||||||
|
}
|
||||||
51
tree.h
Normal file
51
tree.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef TREE_H
|
||||||
|
#define TREE_H
|
||||||
|
|
||||||
|
#include "lex.h"
|
||||||
|
|
||||||
|
enum expr_type {
|
||||||
|
EXPR_CONST,
|
||||||
|
EXPR_NEG,
|
||||||
|
EXPR_ADD,
|
||||||
|
EXPR_SUB,
|
||||||
|
EXPR_MULT,
|
||||||
|
EXPR_DIV,
|
||||||
|
EXPR_POW,
|
||||||
|
EXPR_X,
|
||||||
|
EXPR_FN
|
||||||
|
};
|
||||||
|
|
||||||
|
struct expr_node {
|
||||||
|
enum expr_type type;
|
||||||
|
union expr_vals {
|
||||||
|
struct expr_binop_vals {
|
||||||
|
struct expr_node *left;
|
||||||
|
struct expr_node *right;
|
||||||
|
} binop;
|
||||||
|
struct expr_fn_vals {
|
||||||
|
enum math_fn fn;
|
||||||
|
struct expr_node *arg;
|
||||||
|
} fn;
|
||||||
|
struct expr_node *unop;
|
||||||
|
double num;
|
||||||
|
} vals;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct expr_node *node_create_const(double val);
|
||||||
|
extern struct expr_node *node_create_neg(struct expr_node *unop);
|
||||||
|
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);
|
||||||
|
extern struct expr_node *node_create_mult(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_x(void);
|
||||||
|
extern struct expr_node *node_create_fn(enum math_fn fn, struct expr_node *arg);
|
||||||
|
|
||||||
|
extern void node_debug_print(struct expr_node *node);
|
||||||
|
|
||||||
|
extern double node_eval(struct expr_node *node, double x);
|
||||||
|
|
||||||
|
extern void node_free(struct expr_node *node);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* TREE_H */
|
||||||
Loading…
x
Reference in New Issue
Block a user