#include "lex.h" #include #include #include void lex_init(struct lexer *lex, const char *str) { error_buffer_init(&lex->eb); lex->start = str; lex->prev_p = str; lex->p = str; lex_next(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; error_set(&lex->eb, ERR_INVALID_FUNCTION); error_printf(&lex->eb, "Unrecognized sequence \"%s\"\n", lex->p); lex_print_position(lex, &lex->eb); lex->tok.type = TOK_ERROR; return; } struct token *lex_token(struct lexer *lex) { return &lex->tok; } void lex_print_position(const struct lexer *lex, struct error_buffer *eb) { size_t pos = lex->prev_p - lex->start; size_t i; size_t input_len = strlen(lex->start); error_printf(eb, "At character %d\n", pos); error_printf(eb, " %s\n", lex->start); error_printf(eb, " "); for (i = 0; i < input_len; ++i) { char c = '_'; if (i == pos) c = '^'; error_printf(eb, "%c", c); } error_printf(eb, "\n"); /* error_printf(eb, "\n----------------------------------------------------\n"); */ } enum error_code lex_get_error(const struct lexer *lex) { return error_get(&lex->eb); } const char *lex_get_error_text(const struct lexer *lex) { return error_get_text(&lex->eb); } #ifdef LEX_DEBUG void lex_debug_print_token(const 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" }; printf("%-20s ", token_str[tok->type]); if (tok->type == TOK_NUMBER) printf("%.2f\n", tok->val.num); else if (tok->type == TOK_FUNCTION) { 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("%s\n", fn_str[tok->val.fn]); } else printf("\n"); } #endif /* LEX_DEBUG */