From ad46d49574ea8ada67d8644c70817502c8591305 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Wed, 26 Oct 2011 13:23:38 -0400 Subject: Parse error handling improvements. * parser.l (prepared_error_message): New static variable. (yyerror): Emit and clear prepared error message. (yyerrprepf): New static function. (yybadtoken): Function moved into parser.y. (grammar): For irrecoverable lexical errors, stash error message with yyerrprepf and return the special error token ERRTOK to generate a syntax error. I could find no other interface to the parser to make it cleanly exit. * parser.y (ERRTOK): New terminal symbol, does not appear anywhere in the grammar. (spec): Bail after 8 errors, recover to nearest newline, and use yyerrok to clear error situation. (YYEOF): Provided by Bison, conditionally defined for other yacc-s. (yybadtoken): Function moved from parser.l. Checks for the next token being YYEMPTY or YYEOF, and also handles ERRTOK. * stream.c (vformat_to_string): New function. (format): If stream is nil, format to string and return it. * stream.h (vformat_to_string): Declared. --- parser.y | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) (limited to 'parser.y') diff --git a/parser.y b/parser.y index 004211aa..1437e982 100644 --- a/parser.y +++ b/parser.y @@ -63,6 +63,7 @@ static val parsed_spec; %token AND OR END COLLECT %token UNTIL COLL OUTPUT REPEAT REP SINGLE FIRST LAST EMPTY DEFINE %token TRY CATCH FINALLY +%token ERRTOK %token NUMBER @@ -99,8 +100,12 @@ static val parsed_spec; spec : clauses { parsed_spec = $1; } | /* empty */ { parsed_spec = nil; } - | error { parsed_spec = nil; + | error '\n' { parsed_spec = nil; + if (errors >= 8) + YYABORT; + yyerrok; yybadtoken(yychar, nil); } + ; clauses : clause { $$ = cons($1, nil); } @@ -778,3 +783,69 @@ val get_spec(void) { return parsed_spec; } + +#ifndef YYEOF +#define YYEOF YYEMPTY +#endif + +void yybadtoken(int tok, val context) +{ + val problem = nil; + + switch (tok) { + case ERRTOK: + return; + case SPACE: problem = lit("space"); break; + case TEXT: problem = lit("text"); break; + case IDENT: problem = lit("identifier"); break; + case KEYWORD: problem = lit("keyword"); break; + case METAVAR: problem = lit("metavar"); break; + case ALL: problem = lit("\"all\""); break; + case SOME: problem = lit("\"some\""); break; + case NONE: problem = lit("\"none\""); break; + case MAYBE: problem = lit("\"maybe\""); break; + case CASES: problem = lit("\"cases\""); break; + case CHOOSE: problem = lit("\"choose\""); break; + case AND: problem = lit("\"and\""); break; + case OR: problem = lit("\"or\""); break; + case END: problem = lit("\"end\""); break; + case COLLECT: problem = lit("\"collect\""); break; + case UNTIL: problem = lit("\"until\""); break; + case COLL: problem = lit("\"coll\""); break; + case OUTPUT: problem = lit("\"output\""); break; + case REPEAT: problem = lit("\"repeat\""); break; + case REP: problem = lit("\"rep\""); break; + case SINGLE: problem = lit("\"single\""); break; + case FIRST: problem = lit("\"first\""); break; + case LAST: problem = lit("\"last\""); break; + case EMPTY: problem = lit("\"empty\""); break; + case DEFINE: problem = lit("\"define\""); break; + case TRY: problem = lit("\"try\""); break; + case CATCH: problem = lit("\"catch\""); break; + case FINALLY: problem = lit("\"finally\""); break; + case NUMBER: problem = lit("\"number\""); break; + case REGCHAR: problem = lit("regular expression character"); break; + case LITCHAR: problem = lit("string literal character"); break; + case METAPAR: problem = lit("@("); break; + } + + if (problem != 0) + if (context) + yyerrorf(lit("misplaced ~a in ~a"), problem, context, nao); + else + yyerrorf(lit("unexpected ~a"), problem, nao); + else + if (context) + if (tok == YYEOF || tok == YYEMPTY) + yyerrorf(lit("unterminated ~a"), context, nao); + else + yyerrorf(lit("misplaced ~s in ~a"), chr(tok), context, nao); + else + if (tok == YYEOF) + yyerrorf(lit("unexpected end of input"), nao); + else if (tok == YYEMPTY) + return; + else + yyerrorf(lit("unexpected ~s"), chr(tok), nao); +} + -- cgit v1.2.3