summaryrefslogtreecommitdiffstats
path: root/parser.y
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2011-10-26 13:23:38 -0400
committerKaz Kylheku <kaz@kylheku.com>2011-10-26 13:23:38 -0400
commitad46d49574ea8ada67d8644c70817502c8591305 (patch)
treefc069f9eefe2edda87733f24937cc4103d7d414d /parser.y
parentdabff9ab6f89a1ec36461022a811c1f10cd09f17 (diff)
downloadtxr-ad46d49574ea8ada67d8644c70817502c8591305.tar.gz
txr-ad46d49574ea8ada67d8644c70817502c8591305.tar.bz2
txr-ad46d49574ea8ada67d8644c70817502c8591305.zip
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.
Diffstat (limited to 'parser.y')
-rw-r--r--parser.y73
1 files changed, 72 insertions, 1 deletions
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 <lexeme> AND OR END COLLECT
%token <lexeme> UNTIL COLL OUTPUT REPEAT REP SINGLE FIRST LAST EMPTY DEFINE
%token <lexeme> TRY CATCH FINALLY
+%token <lexeme> ERRTOK
%token <num> 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);
+}
+