error codes

This commit is contained in:
zbyv 2024-11-28 14:49:19 +01:00
parent 88c476e052
commit a62531d893
8 changed files with 302 additions and 170 deletions

View File

@ -15,6 +15,7 @@ add_executable(Graph
"parser.c" "parser.c"
"tree.c" "tree.c"
"ps_graph.c" "ps_graph.c"
"error_buffer.c"
) )
# Optionally, you can set compiler warnings # Optionally, you can set compiler warnings

47
error_buffer.c Normal file
View File

@ -0,0 +1,47 @@
#include "error_buffer.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
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;
}

31
error_buffer.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef ERROR_CODE_H
#define ERROR_CODE_H
#include <stdlib.h>
#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 */

64
lex.c
View File

@ -1,32 +1,16 @@
#include <stdlib.h>
#include <stdio.h>
#include "lex.h" #include "lex.h"
struct lexer { #include <stdlib.h>
const char* start; #include <stdio.h>
const char* prev_p; #include <string.h>
const char* p;
struct token tok;
};
struct lexer *lex_create(const char *str) { void lex_init(struct lexer *lex, const char *str) {
struct lexer *lex = malloc(sizeof(struct lexer)); error_buffer_init(&lex->eb);
if (!lex)
return NULL;
lex->start = str; lex->start = str;
lex->prev_p = str; lex->prev_p = str;
lex->p = str; lex->p = str;
lex_next(lex); lex_next(lex);
return lex;
}
void lex_free(struct lexer *lex) {
free(lex);
} }
static int is_whitespace(char p) { static int is_whitespace(char p) {
@ -119,8 +103,9 @@ void lex_next(struct lexer *lex) {
if (try_number(lex)) return; if (try_number(lex)) return;
fprintf(stderr, "Lexer error - unrecognized sequence \"%s\"\n", lex->p); error_set(&lex->eb, ERR_INVALID_FUNCTION);
lex_print_position(lex); error_printf(&lex->eb, "Unrecognized sequence \"%s\"\n", lex->p);
lex_print_position(lex, &lex->eb);
lex->tok.type = TOK_ERROR; lex->tok.type = TOK_ERROR;
return; return;
@ -130,19 +115,34 @@ struct token *lex_token(struct lexer *lex) {
return &lex->tok; return &lex->tok;
} }
void lex_print_position(const struct lexer *lex) { void lex_print_position(const struct lexer *lex, struct error_buffer *eb) {
int i; size_t pos = lex->prev_p - lex->start;
int pos = lex->prev_p - lex->start; size_t i;
size_t input_len = strlen(lex->start);
fprintf(stderr, "At character %d\n", pos); error_printf(eb, "At character %d\n", pos);
fprintf(stderr, " %s\n", lex->start); error_printf(eb, " %s\n", lex->start);
fprintf(stderr, " "); error_printf(eb, " ");
for (i = 0; i < pos; ++i)
fprintf(stderr, " ");
fprintf(stderr, "^\n----------------------------------------------------\n"); 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 #ifdef LEX_DEBUG

23
lex.h
View File

@ -1,6 +1,8 @@
#ifndef LEX_H #ifndef LEX_H
#define LEX_H #define LEX_H
#include "error_buffer.h"
#define LEX_DEBUG #define LEX_DEBUG
enum token_type { enum token_type {
@ -43,19 +45,26 @@ struct token {
} val; } 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); void lex_init(struct lexer *lex, const char *str);
extern void lex_free(struct lexer *lex);
extern void lex_next(struct lexer *lex); void lex_next(struct lexer *lex);
extern struct token *lex_token(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 #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_DEBUG */
#endif /* LEX_H */ #endif /* LEX_H */

48
main.c
View File

@ -6,40 +6,40 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
struct lexer *lex; struct parser parser;
struct expr_node *node; struct expr_node *node;
FILE *file;
struct graph_range graph;
if (argc < 2) { if (argc < 2) {
printf("Usage: %s <expression>\n", argv[0]); printf("Usage: %s <expression>\n", argv[0]);
return 1; return 1;
} }
lex = lex_create(argv[1]); parser_init(&parser);
node = parser_parse(&parser, argv[1]);
node = parse_expression(lex); if (!node) {
lex_free(lex); fprintf(stderr, "%s", parser_get_error_text(&parser));
return parser_get_error(&parser);
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);
} }
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; return 0;
} }

244
parser.c
View File

@ -2,81 +2,101 @@
#include <stdio.h> #include <stdio.h>
#include "parser.h" #include "parser.h"
static int token_is(struct lexer *lex, enum token_type type) { static struct token *get_token(struct parser *parser) {
return lex_token(lex)->type == type; return lex_token(&parser->lexer);
} }
static int accept(struct lexer *lex, enum token_type type) { static int token_is(struct parser *parser, enum token_type type) {
if (token_is(lex, type)) { return get_token(parser)->type == type;
lex_next(lex); }
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 1;
} }
return 0; return 0;
} }
static double token_num(struct lexer *lex) { static void error_bad_alloc(struct parser *parser) {
return lex_token(lex)->val.num; error_set(&parser->eb, ERR_BAD_ALLOC);
error_printf(&parser->eb, "Out of memory\n");
} }
static enum math_fn token_fn(struct lexer *lex) { static void error_expected_one_of(struct parser *parser, const int expected[]) {
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[] = { static const char* token_name[] = {
"end of expression", "end of expression",
"lexer error", "lexer error",
"constant", "constant",
"+", "+",
"-", "-",
"*", "*",
"/", "/",
"^", "^",
"x", "x",
"function name", "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 (got == TOK_ERROR) {
if (separate) error_set(&parser->eb, lex_get_error(&parser->lexer));
fprintf(stderr, ", "); error_printf(&parser->eb, "Lexer error - %s", lex_get_error_text(&parser->lexer));
else return;
separate = 1;
fprintf(stderr, "'%s'", token_name[*expected]);
} }
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 }; static int expected_arr[] = { -1, -1 };
expected_arr[0] = expected; 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; struct expr_node* node;
if (!accept(lex, TOK_LEFT_PAREN)) { if (!accept_token(parser, TOK_LEFT_PAREN)) {
error_expected_single(lex, TOK_LEFT_PAREN, lex_token(lex)->type); error_expected_single(parser, TOK_LEFT_PAREN);
return NULL; return NULL;
} }
if (!(node = parse_subexpression(lex))) if (!(node = parse_subexpression(parser)))
return NULL; return NULL;
if (!accept(lex, TOK_RIGHT_PAREN)) { if (!accept_token(parser, TOK_RIGHT_PAREN)) {
error_expected_single(lex, TOK_RIGHT_PAREN, lex_token(lex)->type); error_expected_single(parser, TOK_RIGHT_PAREN);
node_free(node); node_free(node);
return NULL; return NULL;
} }
@ -84,60 +104,72 @@ static struct expr_node* parse_bracketed(struct lexer* lex) {
return node; 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; struct expr_node *node, *inner;
if (token_is(lex, TOK_NUMBER)) { if (token_is(parser, TOK_NUMBER)) {
double val = token_num(lex); double val = token_num(parser);
lex_next(lex); next_token(parser);
return node_create_const(val); if (!(node = node_create_const(val))) {
} error_bad_alloc(parser);
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 NULL;
if (!(node = node_create_fn(fn, inner))) {
node_free(inner);
} }
return node; return node;
} }
if (token_is(lex, TOK_LEFT_PAREN)) { if (accept_token(parser, TOK_X)) {
return parse_bracketed(lex); 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 }; 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; 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; struct expr_node* node, * new_node, * inner;
if (!(node = parse_base(lex))) if (!(node = parse_base(parser)))
return NULL; return NULL;
if (accept(lex, TOK_POWER)) { if (accept_token(parser, TOK_POWER)) {
if (!(inner = parse_unary(lex))) { if (!(inner = parse_unary(parser))) {
node_free(node); node_free(node);
return NULL; return NULL;
} }
if (!(new_node = node_create_pow(node, inner))) { if (!(new_node = node_create_pow(node, inner))) {
error_bad_alloc(parser);
node_free(node); node_free(node);
node_free(inner); node_free(inner);
return NULL; return NULL;
@ -149,14 +181,15 @@ static struct expr_node* parse_factor(struct lexer* lex) {
return node; return node;
} }
static struct expr_node* parse_unary(struct lexer *lex) { static struct expr_node* parse_unary(struct parser *parser) {
if (accept(lex, TOK_MINUS)) { if (accept_token(parser, TOK_MINUS)) {
struct expr_node *node, *inner; struct expr_node *node, *inner;
if (!(inner = parse_factor(lex))) if (!(inner = parse_factor(parser)))
return NULL; return NULL;
if (!(node = node_create_neg(inner))) { if (!(node = node_create_neg(inner))) {
error_bad_alloc(parser);
node_free(inner); node_free(inner);
return NULL; return NULL;
} }
@ -164,32 +197,33 @@ static struct expr_node* parse_unary(struct lexer *lex) {
return node; return node;
} }
accept(lex, TOK_PLUS); accept_token(parser, TOK_PLUS);
return parse_factor(lex); 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; struct expr_node *node, *new_node, *inner;
if (!(node = parse_unary(lex))) if (!(node = parse_unary(parser)))
return NULL; return NULL;
while (1) { while (1) {
struct expr_node *(*create_node)(struct expr_node *left, struct expr_node *right); 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; create_node = node_create_mult;
else if (accept(lex, TOK_DIVIDE)) else if (accept_token(parser, TOK_DIVIDE))
create_node = node_create_div; create_node = node_create_div;
else else
break; break;
if (!(inner = parse_unary(lex))) { if (!(inner = parse_unary(parser))) {
node_free(node); node_free(node);
return NULL; return NULL;
} }
if (!(new_node = create_node(node, inner))) { if (!(new_node = create_node(node, inner))) {
error_bad_alloc(parser);
node_free(node); node_free(node);
node_free(inner); node_free(inner);
return NULL; return NULL;
@ -201,47 +235,29 @@ static struct expr_node *parse_term(struct lexer *lex) {
return node; 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; struct expr_node *node, *new_node, *inner;
/* if (!(node = parse_term(parser)))
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; return NULL;
while (1) { while (1) {
struct expr_node *(*create_node)(struct expr_node *left, struct expr_node *right); 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; create_node = node_create_add;
else if (accept(lex, TOK_MINUS)) else if (accept_token(parser, TOK_MINUS))
create_node = node_create_sub; create_node = node_create_sub;
else else
break; break;
if (!(inner = parse_term(lex))) { if (!(inner = parse_term(parser))) {
node_free(node); node_free(node);
return NULL; return NULL;
} }
if (!(new_node = create_node(node, inner))) { if (!(new_node = create_node(node, inner))) {
error_bad_alloc(parser);
node_free(node); node_free(node);
node_free(inner); node_free(inner);
return NULL; return NULL;
@ -253,17 +269,35 @@ struct expr_node *parse_subexpression(struct lexer *lex) {
return node; return node;
} }
struct expr_node *parse_expression(struct lexer *lex) { static struct expr_node *parse_expression(struct parser *parser) {
struct expr_node *node; struct expr_node *node;
if (!(node = parse_subexpression(lex))) if (!(node = parse_subexpression(parser)))
return NULL; return NULL;
if (!token_is(lex, TOK_EOF)) { if (!token_is(parser, TOK_EOF)) {
error_expected_single(lex, TOK_EOF, lex_token(lex)->type); error_expected_single(parser, TOK_EOF);
node_free(node); node_free(node);
return NULL; return NULL;
} }
return node; 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);
}

View File

@ -2,7 +2,17 @@
#define PARSER_H #define PARSER_H
#include "tree.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 */ #endif /* PARSER_H */