From dcc75348c720acd6c2a0587bca34f7851e6c1283 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Sun, 6 Sep 2015 22:50:52 -0700 Subject: Reset flex scanner if exception thrown during read. We must tear down and rebuild the Flex scanner, otherwise it is left in a bad state causing it to abort. * parser.c (parser_cleanup): After destroying scanner, null out the pointer. (parser_reset): Destroy the Flex scanner, and instantiate a new one in its place. (lisp_parse): Set up an unwind catch which will reset the parser if it was aborted by an exception. * parser.h (parser_reset): Declared. --- parser.c | 23 ++++++++++++++++++++++- parser.h | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/parser.c b/parser.c index 035291f6..37255ae0 100644 --- a/parser.c +++ b/parser.c @@ -120,6 +120,16 @@ void parser_cleanup(parser_t *p) { if (p->scanner != 0) yylex_destroy(p->scanner); + p->scanner = 0; +} + +void parser_reset(parser_t *p) +{ + yyscan_t yyscan; + parser_cleanup(p); + yylex_init(&yyscan); + p->scanner = convert(scanner_t *, yyscan); + yyset_extra(p, p->scanner); } val parser(val stream, val lineno) @@ -279,6 +289,9 @@ val lisp_parse(val source_in, val error_stream, val error_return_val, val parser = ensure_parser(input_stream); val saved_dyn = dyn_env; parser_t *pi = get_parser_impl(parser); + volatile val parsed = nil; + + uw_simple_catch_begin; dyn_env = make_env(nil, nil, dyn_env); @@ -295,9 +308,17 @@ val lisp_parse(val source_in, val error_stream, val error_return_val, int gc = gc_state(0); parse(pi, if3(std_error != std_null, name, lit("")), prime_lisp); gc_state(gc); + parsed = t; + } + + uw_unwind { + dyn_env = saved_dyn; + if (!parsed) { + parser_reset(pi); + } } - dyn_env = saved_dyn; + uw_catch_end; if (pi->errors || pi->syntax_tree == nao) { if (missingp(error_return_val)) diff --git a/parser.h b/parser.h index bc6a3364..efbaa351 100644 --- a/parser.h +++ b/parser.h @@ -86,6 +86,7 @@ int parse(parser_t *parser, val name, enum prime_parser); val source_loc(val form); val source_loc_str(val form, val alt); val rlset(val form, val info); +void parser_reset(parser_t *); INLINE val rlcp(val to, val from) { return rlset(to, source_loc(from)); -- cgit v1.2.3