Add allocation error handling to the parser
This commit is contained in:
parent
846f560979
commit
5d5042fdec
104
ell.c
104
ell.c
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue