From a62531d893db40b501a78fc0a3a0d0596903ba3c Mon Sep 17 00:00:00 2001 From: zbyv Date: Thu, 28 Nov 2024 14:49:19 +0100 Subject: [PATCH] error codes --- CMakeLists.txt | 1 + error_buffer.c | 47 ++++++++++ error_buffer.h | 31 +++++++ lex.c | 66 ++++++------- lex.h | 23 +++-- main.c | 48 +++++----- parser.c | 244 ++++++++++++++++++++++++++++--------------------- parser.h | 12 ++- 8 files changed, 302 insertions(+), 170 deletions(-) create mode 100644 error_buffer.c create mode 100644 error_buffer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e8a3fe..a42558a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ add_executable(Graph "parser.c" "tree.c" "ps_graph.c" + "error_buffer.c" ) # Optionally, you can set compiler warnings diff --git a/error_buffer.c b/error_buffer.c new file mode 100644 index 0000000..bb87692 --- /dev/null +++ b/error_buffer.c @@ -0,0 +1,47 @@ +#include "error_buffer.h" +#include +#include +#include + +void error_buffer_init(struct error_buffer *eb) { + eb->err = ERR_NO_ERR; + eb->text_len = 0; + eb->text[0] = 0; + /* memset(eb->text, 0xAA, MAX_ERROR_MESSAGE_LENGTH); */ +} + +void error_set(struct error_buffer *eb, enum error_code err) { + eb->err = err; +} + +enum error_code error_get(const struct error_buffer *eb) { + return eb->err; +} + +void error_printf(struct error_buffer *eb, const char *format, ...) { + va_list args; + int space = MAX_ERROR_MESSAGE_LENGTH - eb->text_len; + int write_size; + + if (space == 0) + return; + + va_start(args, format); + write_size = vsnprintf(eb->text + eb->text_len, MAX_ERROR_MESSAGE_LENGTH - eb->text_len, format, args); + va_end(args); + + if (write_size < 0) + return; + + if (write_size < space) { + eb->text_len += write_size; + } else { + 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; +} \ No newline at end of file diff --git a/error_buffer.h b/error_buffer.h new file mode 100644 index 0000000..64d7d4c --- /dev/null +++ b/error_buffer.h @@ -0,0 +1,31 @@ +#ifndef ERROR_CODE_H +#define ERROR_CODE_H + +#include + +#define MAX_ERROR_MESSAGE_LENGTH 512 + +enum error_code { + ERR_NO_ERR = 0, + ERR_INVALID_ARGS = 1, + ERR_INVALID_FUNCTION = 2, + ERR_INVALID_FILENAME = 3, + ERR_INVALID_LIMITS = 4, + ERR_BAD_ALLOC = 5 +}; + +struct error_buffer { + enum error_code err; + char text[MAX_ERROR_MESSAGE_LENGTH]; + size_t text_len; +}; + +void error_buffer_init(struct error_buffer *eb); + +void error_set(struct error_buffer *eb, enum error_code err); +void error_printf(struct error_buffer *eb, const char *format, ...); + +enum error_code error_get(const struct error_buffer *eb); +const char *error_get_text(const struct error_buffer *eb); + +#endif /* ERROR_CODE_H */ \ No newline at end of file diff --git a/lex.c b/lex.c index 7283047..13d0e34 100644 --- a/lex.c +++ b/lex.c @@ -1,32 +1,16 @@ -#include -#include - #include "lex.h" -struct lexer { - const char* start; - const char* prev_p; - const char* p; - struct token tok; -}; +#include +#include +#include -struct lexer *lex_create(const char *str) { - struct lexer *lex = malloc(sizeof(struct lexer)); - - if (!lex) - return NULL; +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); - - return lex; -} - -void lex_free(struct lexer *lex) { - free(lex); } static int is_whitespace(char p) { @@ -119,8 +103,9 @@ void lex_next(struct lexer *lex) { if (try_number(lex)) return; - fprintf(stderr, "Lexer error - unrecognized sequence \"%s\"\n", lex->p); - lex_print_position(lex); + 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; @@ -130,19 +115,34 @@ struct token *lex_token(struct lexer *lex) { return &lex->tok; } -void lex_print_position(const 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, " "); +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); - fprintf(stderr, "^\n----------------------------------------------------\n"); + 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 diff --git a/lex.h b/lex.h index 503660c..948fec1 100644 --- a/lex.h +++ b/lex.h @@ -1,6 +1,8 @@ #ifndef LEX_H #define LEX_H +#include "error_buffer.h" + #define LEX_DEBUG enum token_type { @@ -43,19 +45,26 @@ struct token { } val; }; -struct lexer; +struct lexer { + const char *start; + const char *prev_p; + const char *p; + struct token tok; + struct error_buffer eb; +}; -extern struct lexer *lex_create(const char *str); -extern void lex_free(struct lexer *lex); +void lex_init(struct lexer *lex, const char *str); -extern void lex_next(struct lexer *lex); -extern struct token *lex_token(struct lexer *lex); +void lex_next(struct lexer *lex); +struct token *lex_token(struct lexer *lex); -extern void lex_print_position(const struct lexer *lex); +void lex_print_position(const struct lexer *lex, struct error_buffer *eb); +enum error_code lex_get_error(const struct lexer *lex); +const char *lex_get_error_text(const struct lexer *lex); #ifdef LEX_DEBUG -extern void lex_debug_print_token(const struct token *tok); +void lex_debug_print_token(const struct token *tok); #endif /* LEX_DEBUG */ #endif /* LEX_H */ \ No newline at end of file diff --git a/main.c b/main.c index c46f9d4..bf4b747 100644 --- a/main.c +++ b/main.c @@ -6,40 +6,40 @@ int main(int argc, char *argv[]) { - struct lexer *lex; + struct parser parser; struct expr_node *node; + FILE *file; + struct graph_range graph; if (argc < 2) { printf("Usage: %s \n", argv[0]); return 1; } - lex = lex_create(argv[1]); + parser_init(&parser); + node = parser_parse(&parser, argv[1]); - node = parse_expression(lex); - lex_free(lex); - - if (node) { - FILE *file; - struct graph_range graph; - - graph.xmin = -20.0; - graph.xmax = 20.0; - graph.ymin = -20.0; - graph.ymax = 20.0; - graph.step = 0.01; - - file = fopen("out.ps", "w"); - ps_export_graph(file, node, &graph); - fclose(file); - - file = fopen("graph.dot", "w"); - node_debug_print_gv(node, file); - fclose(file); - - node_free(node); + if (!node) { + fprintf(stderr, "%s", parser_get_error_text(&parser)); + return parser_get_error(&parser); } + graph.xmin = -20.0; + graph.xmax = 20.0; + graph.ymin = -20.0; + graph.ymax = 20.0; + graph.step = 0.01; + + file = fopen("out.ps", "w"); + ps_export_graph(file, node, &graph); + fclose(file); + + file = fopen("graph.dot", "w"); + node_debug_print_gv(node, file); + fclose(file); + + node_free(node); + return 0; } \ No newline at end of file diff --git a/parser.c b/parser.c index 5c457ce..9019ed0 100644 --- a/parser.c +++ b/parser.c @@ -2,81 +2,101 @@ #include #include "parser.h" -static int token_is(struct lexer *lex, enum token_type type) { - return lex_token(lex)->type == type; +static struct token *get_token(struct parser *parser) { + return lex_token(&parser->lexer); } -static int accept(struct lexer *lex, enum token_type type) { - if (token_is(lex, type)) { - lex_next(lex); +static int token_is(struct parser *parser, enum token_type type) { + return get_token(parser)->type == type; +} + +static double token_num(struct parser *parser) { + return get_token(parser)->val.num; +} + +static enum math_fn token_fn(struct parser *parser) { + return get_token(parser)->val.fn; +} + +static void next_token(struct parser *parser) { + lex_next(&parser->lexer); +} + +static int accept_token(struct parser *parser, enum token_type type) { + if (token_is(parser, type)) { + next_token(parser); return 1; } return 0; } -static double token_num(struct lexer *lex) { - return lex_token(lex)->val.num; +static void error_bad_alloc(struct parser *parser) { + error_set(&parser->eb, ERR_BAD_ALLOC); + error_printf(&parser->eb, "Out of memory\n"); } -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 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", - "(", - ")" + "-", + "*", + "/", + "^", + "x", + "function name", + "(", + ")" }; - int separate = 0; + size_t i; - fprintf(stderr, "Syntax error - expected "); + enum token_type got = get_token(parser)->type; - for (; *expected >= 0; ++expected) { - if (separate) - fprintf(stderr, ", "); - else - separate = 1; - - fprintf(stderr, "'%s'", token_name[*expected]); + if (got == TOK_ERROR) { + error_set(&parser->eb, lex_get_error(&parser->lexer)); + error_printf(&parser->eb, "Lexer error - %s", lex_get_error_text(&parser->lexer)); + return; } - fprintf(stderr, " - but got '%s'\n", token_name[got]); + error_set(&parser->eb, ERR_INVALID_FUNCTION); + error_printf(&parser->eb, "Syntax error - expected "); - lex_print_position(lex); + for (i = 0; expected[i] >= 0; ++i) { + if (i > 0) + error_printf(&parser->eb, ", "); + + error_printf(&parser->eb, "'%s'", token_name[expected[i]]); + } + + error_printf(&parser->eb, " - but got '%s'\n", token_name[got]); + + lex_print_position(&parser->lexer, &parser->eb); } -static void error_expected_single(struct lexer* lex, enum token_type expected, enum token_type got) { +static void error_expected_single(struct parser *parser, enum token_type expected) { static int expected_arr[] = { -1, -1 }; expected_arr[0] = expected; - error_expected_one_of(lex, expected_arr, got); + error_expected_one_of(parser, expected_arr); } -struct expr_node* parse_subexpression(struct lexer* lex); +static struct expr_node* parse_subexpression(struct parser *parser); -static struct expr_node* parse_bracketed(struct lexer* lex) { +static struct expr_node* parse_bracketed(struct parser *parser) { struct expr_node* node; - if (!accept(lex, TOK_LEFT_PAREN)) { - error_expected_single(lex, TOK_LEFT_PAREN, lex_token(lex)->type); + if (!accept_token(parser, TOK_LEFT_PAREN)) { + error_expected_single(parser, TOK_LEFT_PAREN); return NULL; } - if (!(node = parse_subexpression(lex))) + if (!(node = parse_subexpression(parser))) return NULL; - if (!accept(lex, TOK_RIGHT_PAREN)) { - error_expected_single(lex, TOK_RIGHT_PAREN, lex_token(lex)->type); + if (!accept_token(parser, TOK_RIGHT_PAREN)) { + error_expected_single(parser, TOK_RIGHT_PAREN); node_free(node); return NULL; } @@ -84,60 +104,72 @@ static struct expr_node* parse_bracketed(struct lexer* lex) { return node; } -static struct expr_node *parse_base(struct lexer *lex) { +static struct expr_node *parse_base(struct parser *parser) { struct expr_node *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))) + 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; - - if (!(node = node_create_fn(fn, inner))) { - node_free(inner); } return node; } - if (token_is(lex, TOK_LEFT_PAREN)) { - return parse_bracketed(lex); + if (accept_token(parser, TOK_X)) { + if (!(node = node_create_x())) { + error_bad_alloc(parser); + return NULL; + } + return node; + } + + if (token_is(parser, TOK_FUNCTION)) { + enum math_fn fn = token_fn(parser); + next_token(parser); + + if (!(inner = parse_bracketed(parser))) + return NULL; + + if (!(node = node_create_fn(fn, inner))) { + node_free(inner); + error_bad_alloc(parser); + return NULL; + } + + return node; + } + + if (token_is(parser, TOK_LEFT_PAREN)) { + return parse_bracketed(parser); } { static const int expected[] = { TOK_NUMBER, TOK_X, TOK_FUNCTION, TOK_LEFT_PAREN, -1 }; - error_expected_one_of(lex, expected, lex_token(lex)->type); + error_expected_one_of(parser, expected); } return NULL; } -static struct expr_node* parse_unary(struct lexer* lex); +static struct expr_node *parse_unary(struct parser *parser); -static struct expr_node* parse_factor(struct lexer* lex) { +static struct expr_node *parse_factor(struct parser *parser) { struct expr_node* node, * new_node, * inner; - if (!(node = parse_base(lex))) + if (!(node = parse_base(parser))) return NULL; - if (accept(lex, TOK_POWER)) { - if (!(inner = parse_unary(lex))) { + if (accept_token(parser, TOK_POWER)) { + if (!(inner = parse_unary(parser))) { node_free(node); return NULL; } if (!(new_node = node_create_pow(node, inner))) { + error_bad_alloc(parser); node_free(node); node_free(inner); return NULL; @@ -149,14 +181,15 @@ static struct expr_node* parse_factor(struct lexer* lex) { return node; } -static struct expr_node* parse_unary(struct lexer *lex) { - if (accept(lex, TOK_MINUS)) { +static struct expr_node* parse_unary(struct parser *parser) { + if (accept_token(parser, TOK_MINUS)) { struct expr_node *node, *inner; - if (!(inner = parse_factor(lex))) + if (!(inner = parse_factor(parser))) return NULL; if (!(node = node_create_neg(inner))) { + error_bad_alloc(parser); node_free(inner); return NULL; } @@ -164,32 +197,33 @@ static struct expr_node* parse_unary(struct lexer *lex) { return node; } - accept(lex, TOK_PLUS); - return parse_factor(lex); + accept_token(parser, TOK_PLUS); + return parse_factor(parser); } -static struct expr_node *parse_term(struct lexer *lex) { +static struct expr_node *parse_term(struct parser *parser) { struct expr_node *node, *new_node, *inner; - if (!(node = parse_unary(lex))) + if (!(node = parse_unary(parser))) return NULL; while (1) { struct expr_node *(*create_node)(struct expr_node *left, struct expr_node *right); - if (accept(lex, TOK_MULTIPLY)) + if (accept_token(parser, TOK_MULTIPLY)) create_node = node_create_mult; - else if (accept(lex, TOK_DIVIDE)) + else if (accept_token(parser, TOK_DIVIDE)) create_node = node_create_div; else break; - if (!(inner = parse_unary(lex))) { + if (!(inner = parse_unary(parser))) { node_free(node); return NULL; } if (!(new_node = create_node(node, inner))) { + error_bad_alloc(parser); node_free(node); node_free(inner); return NULL; @@ -201,47 +235,29 @@ static struct expr_node *parse_term(struct lexer *lex) { return node; } -struct expr_node *parse_subexpression(struct lexer *lex) { +static struct expr_node *parse_subexpression(struct parser *parser) { 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))) + if (!(node = parse_term(parser))) return NULL; while (1) { struct expr_node *(*create_node)(struct expr_node *left, struct expr_node *right); - if (accept(lex, TOK_PLUS)) + if (accept_token(parser, TOK_PLUS)) create_node = node_create_add; - else if (accept(lex, TOK_MINUS)) + else if (accept_token(parser, TOK_MINUS)) create_node = node_create_sub; else break; - if (!(inner = parse_term(lex))) { + if (!(inner = parse_term(parser))) { node_free(node); return NULL; } if (!(new_node = create_node(node, inner))) { + error_bad_alloc(parser); node_free(node); node_free(inner); return NULL; @@ -253,17 +269,35 @@ struct expr_node *parse_subexpression(struct lexer *lex) { return node; } -struct expr_node *parse_expression(struct lexer *lex) { +static struct expr_node *parse_expression(struct parser *parser) { struct expr_node *node; - if (!(node = parse_subexpression(lex))) + if (!(node = parse_subexpression(parser))) return NULL; - if (!token_is(lex, TOK_EOF)) { - error_expected_single(lex, TOK_EOF, lex_token(lex)->type); + if (!token_is(parser, TOK_EOF)) { + error_expected_single(parser, TOK_EOF); node_free(node); return NULL; } return node; +} + +void parser_init(struct parser *parser) { + error_buffer_init(&parser->eb); +} + +struct expr_node *parser_parse(struct parser *parser, const char *str) { + lex_init(&parser->lexer, str); + return parse_expression(parser); + +} + +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); } \ No newline at end of file diff --git a/parser.h b/parser.h index f070592..e7fdb4c 100644 --- a/parser.h +++ b/parser.h @@ -2,7 +2,17 @@ #define PARSER_H #include "tree.h" +#include "lex.h" -extern struct expr_node *parse_expression(struct lexer *lex); +struct parser { + struct lexer lexer; + struct error_buffer eb; +}; + +void parser_init(struct parser *parser); +struct expr_node *parser_parse(struct parser *parser, const char *str); + +enum error_code parser_get_error(const struct parser *parser); +const char *parser_get_error_text(const struct parser *parser); #endif /* PARSER_H */ \ No newline at end of file