diff options
author | Vadim Zhukov <zhuk@cvs.openbsd.org> | 2015-07-24 06:36:43 +0000 |
---|---|---|
committer | Vadim Zhukov <zhuk@cvs.openbsd.org> | 2015-07-24 06:36:43 +0000 |
commit | 2a710a650614a5fab6280e39b41b1f9d3c525135 (patch) | |
tree | a9f855b17e326cc4341a3caccda76434dd68cdd4 | |
parent | c589667a02683377f081c4939c7172d434e376aa (diff) |
Further improve syntax error reporting in doas:
- teach parser to recover after error, allowing to report many errors
instead of the first one only;
- fix remaining error printouts without exact position.
Some ideas were taken from diff sent by dlg@ earlier, thanks!
okay tedu@, dlg@
-rw-r--r-- | usr.bin/doas/doas.c | 4 | ||||
-rw-r--r-- | usr.bin/doas/doas.h | 3 | ||||
-rw-r--r-- | usr.bin/doas/parse.y | 56 |
3 files changed, 36 insertions, 27 deletions
diff --git a/usr.bin/doas/doas.c b/usr.bin/doas/doas.c index 399171ec360..f34e3da8b97 100644 --- a/usr.bin/doas/doas.c +++ b/usr.bin/doas/doas.c @@ -1,4 +1,4 @@ -/* $OpenBSD: doas.c,v 1.20 2015/07/22 16:35:03 zhuk Exp $ */ +/* $OpenBSD: doas.c,v 1.21 2015/07/24 06:36:42 zhuk Exp $ */ /* * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org> * @@ -173,6 +173,8 @@ parseconfig(const char *filename) yyparse(); fclose(yyfp); + if (parse_errors) + exit(1); } static int diff --git a/usr.bin/doas/doas.h b/usr.bin/doas/doas.h index 5eef18e80c6..1b7f37515ac 100644 --- a/usr.bin/doas/doas.h +++ b/usr.bin/doas/doas.h @@ -1,4 +1,4 @@ -/* $OpenBSD: doas.h,v 1.3 2015/07/21 11:04:06 zhuk Exp $ */ +/* $OpenBSD: doas.h,v 1.4 2015/07/24 06:36:42 zhuk Exp $ */ struct rule { int action; @@ -12,6 +12,7 @@ struct rule { extern struct rule **rules; extern int nrules, maxrules; +extern int parse_errors; size_t arraylen(const char **); diff --git a/usr.bin/doas/parse.y b/usr.bin/doas/parse.y index 6f50f0344d4..0003aec2865 100644 --- a/usr.bin/doas/parse.y +++ b/usr.bin/doas/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.9 2015/07/22 20:15:24 zhuk Exp $ */ +/* $OpenBSD: parse.y,v 1.10 2015/07/24 06:36:42 zhuk Exp $ */ /* * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org> * @@ -38,6 +38,8 @@ typedef struct { }; const char *str; }; + int lineno; + int colno; } yystype; #define YYSTYPE yystype @@ -45,6 +47,7 @@ FILE *yyfp; struct rule **rules; int nrules, maxrules; +int parse_errors = 0; void yyerror(const char *, ...); int yylex(void); @@ -61,6 +64,7 @@ int yyparse(void); grammar: /* empty */ | grammar '\n' | grammar rule '\n' + | error '\n' ; rule: action ident target cmd { @@ -100,9 +104,10 @@ options: /* none */ $$.options = $1.options | $2.options; $$.envlist = $1.envlist; if ($2.envlist) { - if ($$.envlist) - errx(1, "can't have two keepenv sections"); - else + if ($$.envlist) { + yyerror("can't have two keepenv sections"); + YYERROR; + } else $$.envlist = $2.envlist; } } ; @@ -171,7 +176,10 @@ yyerror(const char *fmt, ...) va_list va; va_start(va, fmt); - verrx(1, fmt, va); + vfprintf(stderr, fmt, va); + va_end(va); + fprintf(stderr, " at line %d\n", yylval.lineno + 1); + parse_errors++; } struct keyword { @@ -190,10 +198,8 @@ struct keyword { int yylex(void) { - static int colno = 1, lineno = 1; - char buf[1024], *ebuf, *p, *str; - int i, c, quotes = 0, escape = 0, qpos = 0, nonkw = 0; + int i, c, quotes = 0, escape = 0, qpos = -1, nonkw = 0; p = buf; ebuf = buf + sizeof(buf); @@ -201,13 +207,13 @@ yylex(void) repeat: /* skip whitespace first */ for (c = getc(yyfp); c == ' ' || c == '\t'; c = getc(yyfp)) - colno++; + yylval.colno++; /* check for special one-character constructions */ switch (c) { case '\n': - colno = 1; - lineno++; + yylval.colno = 0; + yylval.lineno++; /* FALLTHROUGH */ case '{': case '}': @@ -217,19 +223,18 @@ repeat: while ((c = getc(yyfp)) != '\n') if (c == EOF) return 0; - colno = 1; - lineno++; + yylval.colno = 0; + yylval.lineno++; return c; case EOF: return 0; } /* parsing next word */ - for (;; c = getc(yyfp), colno++) { + for (;; c = getc(yyfp), yylval.colno++) { switch (c) { case '\0': - yyerror("unallowed character NUL at " - "line %d, column %d", lineno, colno); + yyerror("unallowed character NUL in column %d", yylval.colno + 1); escape = 0; continue; case '\\': @@ -239,8 +244,8 @@ repeat: break; case '\n': if (quotes) - yyerror("unterminated quotes at line %d, column %d", - lineno, qpos); + yyerror("unterminated quotes in column %d", + qpos + 1); if (escape) { nonkw = 1; escape = 0; @@ -249,11 +254,12 @@ repeat: goto eow; case EOF: if (escape) - yyerror("unterminated escape at line %d, column %d", - lineno, colno - 1); + yyerror("unterminated escape in column %d", + yylval.colno); if (quotes) - yyerror("unterminated quotes at line %d, column %d", - lineno, qpos); + yyerror("unterminated quotes in column %d", + qpos + 1); + goto eow; /* FALLTHROUGH */ case '{': case '}': @@ -268,14 +274,14 @@ repeat: quotes = !quotes; if (quotes) { nonkw = 1; - qpos = colno; + qpos = yylval.colno; } continue; } } *p++ = c; if (p == ebuf) - yyerror("too long line %d", lineno); + yyerror("too long line"); escape = 0; } @@ -290,7 +296,7 @@ eow: */ if (c == EOF) return 0; - else if (!qpos) /* accept, e.g., empty args: cmd foo args "" */ + else if (qpos == -1) /* accept, e.g., empty args: cmd foo args "" */ goto repeat; } if (!nonkw) { |