Add allocation error handling to the parser

This commit is contained in:
Přemysl Eric Janouch 2017-05-19 19:22:44 +02:00
parent 846f560979
commit 5d5042fdec
Signed by: p
GPG Key ID: B715679E3A361BE6
1 changed files with 60 additions and 44 deletions

104
ell.c
View File

@ -203,8 +203,10 @@ new_string (const char *s, ssize_t len) {
static struct item * static struct item *
new_list (struct item *head) { new_list (struct item *head) {
struct item *item = calloc (1, sizeof *item + 1); struct item *item = calloc (1, sizeof *item + 1);
if (!item) if (!item) {
item_free_list (head);
return NULL; return NULL;
}
item->type = ITEM_LIST; item->type = ITEM_LIST;
item->head = head; item->head = head;
@ -453,6 +455,7 @@ struct parser
char *error; ///< Tokenizer error char *error; ///< Tokenizer error
enum token token; ///< Current token in the lexer enum token token; ///< Current token in the lexer
bool replace_token; ///< Replace the token bool replace_token; ///< Replace the token
bool memory_failure; ///< Memory allocation failed
}; };
static void static void
@ -478,11 +481,13 @@ parser_peek (struct parser *self, jmp_buf out) {
const char *e = NULL; const char *e = NULL;
self->token = lexer_next (&self->lexer, &e); self->token = lexer_next (&self->lexer, &e);
if (e) { if (e) {
// TODO: check memory error self->memory_failure =
self->error = lexer_errorf (&self->lexer, "%s", e); !(self->error = lexer_errorf (&self->lexer, "%s", e));
longjmp (out, 1); longjmp (out, 1);
} }
// TODO: with T_STRING check for memory error within if (self->token == T_STRING
&& (self->memory_failure = self->lexer.string.memory_failure))
longjmp (out, 1);
self->replace_token = false; self->replace_token = false;
} }
return self->token; return self->token;
@ -498,10 +503,9 @@ parser_expect (struct parser *self, enum token token, jmp_buf out) {
if (parser_accept (self, token, out)) if (parser_accept (self, token, out))
return; return;
// TODO: check memory error self->memory_failure = !(self->error = lexer_errorf (&self->lexer,
self->error = lexer_errorf (&self->lexer, "unexpected `%s', expected `%s'", "unexpected `%s', expected `%s'",
token_name (self->token), token_name (self->token), token_name (token)));
token_name (token));
longjmp (out, 1); longjmp (out, 1);
} }
@ -515,24 +519,37 @@ parser_expect (struct parser *self, enum token token, jmp_buf out) {
#define EXPECT(token) parser_expect (self, token, err) #define EXPECT(token) parser_expect (self, token, err)
#define SKIP_NL() do {} while (ACCEPT (T_NEWLINE)) #define SKIP_NL() do {} while (ACCEPT (T_NEWLINE))
static struct item *
parser_check (struct parser *self, struct item *item, jmp_buf out) {
if (!item) {
self->memory_failure = true;
longjmp (out, 1);
}
return item;
}
// Beware that this jumps to the "out" buffer directly
#define CHECK(item) parser_check (self, (item), out)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static struct item *
parse_prefix_list (struct item *list, const char *name) {
struct item *prefix;
if (!(prefix = new_string (name, strlen (name)))) {
item_free_list (list);
return NULL;
}
prefix->next = list;
return new_list (prefix);
}
static struct item * parse_line (struct parser *self, jmp_buf out); static struct item * parse_line (struct parser *self, jmp_buf out);
static struct item *
parse_prefix_list (struct item *list, const char *name) {
// TODO: check memory error
struct item *prefix = new_string (name, strlen (name));
prefix->next = list;
// TODO: check memory error
return new_list (prefix);
}
static struct item * static struct item *
parse_item (struct parser *self, jmp_buf out) { parse_item (struct parser *self, jmp_buf out) {
struct item *volatile result = NULL, *volatile *tail = &result;
jmp_buf err; jmp_buf err;
struct item *volatile result = NULL, *volatile *tail = &result;
if (setjmp (err)) { if (setjmp (err)) {
item_free_list (result); item_free_list (result);
longjmp (out, 1); longjmp (out, 1);
@ -540,48 +557,43 @@ parse_item (struct parser *self, jmp_buf out) {
SKIP_NL (); SKIP_NL ();
if (ACCEPT (T_STRING)) if (ACCEPT (T_STRING))
// TODO: check memory error, also in "self->lexer.string" return CHECK (new_string
return new_string (self->lexer.string.s, self->lexer.string.len); (self->lexer.string.s, self->lexer.string.len));
if (ACCEPT (T_AT)) { if (ACCEPT (T_AT)) {
result = parse_item (self, out); result = parse_item (self, out);
return parse_prefix_list (result, "set"); return CHECK (parse_prefix_list (result, "set"));
} }
if (ACCEPT (T_LPAREN)) { if (ACCEPT (T_LPAREN)) {
while (!ACCEPT (T_RPAREN)) { while (!ACCEPT (T_RPAREN)) {
*tail = parse_item (self, err); tail = &(*tail = parse_item (self, err))->next;
tail = &(*tail)->next;
SKIP_NL (); SKIP_NL ();
} }
// TODO: check memory error return CHECK (new_list (result));
return new_list (result);
} }
if (ACCEPT (T_LBRACKET)) { if (ACCEPT (T_LBRACKET)) {
while (!ACCEPT (T_RBRACKET)) { while (!ACCEPT (T_RBRACKET)) {
*tail = parse_item (self, err); tail = &(*tail = parse_item (self, err))->next;
tail = &(*tail)->next;
SKIP_NL (); SKIP_NL ();
} }
return parse_prefix_list (result, "list"); return CHECK (parse_prefix_list (result, "list"));
} }
if (ACCEPT (T_LBRACE)) { if (ACCEPT (T_LBRACE)) {
while ((*tail = parse_line (self, err))) while ((*tail = parse_line (self, err)))
tail = &(*tail)->next; tail = &(*tail)->next;
EXPECT (T_RBRACE); EXPECT (T_RBRACE);
// TODO: check memory error result = CHECK (new_list (result));
return parse_prefix_list (new_list (result), "quote"); return CHECK (parse_prefix_list (result, "quote"));
} }
// TODO: check memory error self->memory_failure = !(self->error = lexer_errorf (&self->lexer,
self->error = lexer_errorf (&self->lexer, "unexpected `%s', expected a value", token_name (self->token)));
"unexpected `%s', expected a value", token_name (self->token));
longjmp (out, 1); longjmp (out, 1);
} }
static struct item * static struct item *
parse_line (struct parser *self, jmp_buf out) { parse_line (struct parser *self, jmp_buf out) {
struct item *volatile result = NULL, *volatile *tail = &result;
jmp_buf err; jmp_buf err;
struct item *volatile result = NULL, *volatile *tail = &result;
if (setjmp (err)) { if (setjmp (err)) {
item_free_list (result); item_free_list (result);
longjmp (out, 1); longjmp (out, 1);
@ -589,16 +601,13 @@ parse_line (struct parser *self, jmp_buf out) {
while (PEEK () != T_RBRACE && PEEK () != T_ABORT) { while (PEEK () != T_RBRACE && PEEK () != T_ABORT) {
if (!ACCEPT (T_NEWLINE)) { if (!ACCEPT (T_NEWLINE)) {
*tail = parse_item (self, err); tail = &(*tail = parse_item (self, err))->next;
tail = &(*tail)->next;
} else if (result) { } else if (result) {
// TODO: check memory error return CHECK (new_list (result));
return new_list (result);
} }
} }
if (result) if (result)
// TODO: check memory error return CHECK (new_list (result));
return new_list (result);
return NULL; return NULL;
} }
@ -608,19 +617,25 @@ parse_line (struct parser *self, jmp_buf out) {
#undef ACCEPT #undef ACCEPT
#undef EXPECT #undef EXPECT
#undef SKIP_NL #undef SKIP_NL
#undef CHECK
static struct item * static struct item *
parse (const char *s, size_t len, char **e) { parse (const char *s, size_t len, char **e) {
struct parser parser; struct parser parser;
parser_init (&parser, s, len); parser_init (&parser, s, len);
struct item *volatile result = NULL, *volatile *tail = &result;
jmp_buf err; jmp_buf err;
struct item *volatile result = NULL, *volatile *tail = &result;
if (setjmp (err)) { if (setjmp (err)) {
item_free_list (result); item_free_list (result);
*e = parser.error; *e = parser.error;
lexer_free (&parser.lexer); lexer_free (&parser.lexer);
// TODO: figure out how to handle this, since the return value
// may be null and we may not be able to allocate an error message
if (parser.memory_failure)
abort ();
return NULL; return NULL;
} }
@ -917,6 +932,7 @@ init_runtime_library_scripts (struct context *ctx) {
char *e = NULL; char *e = NULL;
struct item *body = parse (functions[i].definition, struct item *body = parse (functions[i].definition,
strlen (functions[i].definition), &e); strlen (functions[i].definition), &e);
// TODO: also handle memory allocation errors
if (e) { if (e) {
printf ("error parsing internal function `%s': %s\n", printf ("error parsing internal function `%s': %s\n",
functions[i].definition, e); functions[i].definition, e);