diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2020-09-17 00:29:11 -0700 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2020-09-17 00:29:11 -0700 |
| commit | 67e538e774b37749c53c553b941736a281e6ac8f (patch) | |
| tree | cc02c6622c831b2cb2dad7e3128e9a9e3dbb3ded | |
| parent | 2477d9869c295cbaa1e948fc6e40190aa7149295 (diff) | |
Some error handling
| -rw-r--r-- | bpeg.c | 17 | ||||
| -rw-r--r-- | file_loader.c | 8 | ||||
| -rw-r--r-- | grammars/bpeg.bpeg | 24 | ||||
| -rw-r--r-- | types.h | 5 | ||||
| -rw-r--r-- | vm.c | 16 |
5 files changed, 52 insertions, 18 deletions
@@ -49,11 +49,28 @@ static char *getflag(const char *flag, char *argv[], int *i) return NULL; } +static int print_errors(file_t *f, match_t *m) +{ + int ret = 0; + if (m->op->op == VM_CAPTURE && m->value.name && streq(m->value.name, "!")) { + printf("\033[31;1m"); + print_match(f, m); + printf("\033[0m\n"); + fprint_line(stdout, f, m->start, m->end, ""); + return 1; + } + if (m->child) ret += print_errors(f, m->child); + if (m->nextsibling) ret += print_errors(f, m->nextsibling); + return ret; +} + static int run_match(grammar_t *g, const char *filename, vm_op_t *pattern, unsigned int flags) { file_t *f = load_file(filename); check(f, "Could not open file: %s", filename); match_t *m = match(g, f, f->contents, pattern, flags); + if (m && print_errors(f, m) > 0) + _exit(1); if (m != NULL && m->end > m->start + 1) { print_match(f, m); destroy_file(&f); diff --git a/file_loader.c b/file_loader.c index 1bc3d20..7533b91 100644 --- a/file_loader.c +++ b/file_loader.c @@ -101,9 +101,15 @@ void fprint_line(FILE *dest, file_t *f, const char *start, const char *end, cons f->filename, linenum, charnum, msg); const char *eol = linenum == f->nlines ? strchr(line, '\0') : strchr(line, '\n'); if (end == NULL || end > eol) end = eol; - fprintf(dest, "\033[2m% 5ld |\033[0m %.*s\033[31;4;1m%.*s\033[0m%.*s\n", + fprintf(dest, "\033[2m% 5ld |\033[0m %.*s\033[41;30m%.*s\033[0m%.*s\n", linenum, (int)charnum - 1, line, (int)(end - &line[charnum-1]), &line[charnum-1], (int)(eol - end), end); + fprintf(dest, " "); + const char *p = line - 1; + for (; p < start; ++p) fputc(' ', dest); + if (start == end) ++end; + for (; p < end; ++p) fputc('^', dest); + fputc('\n', dest); } diff --git a/grammars/bpeg.bpeg b/grammars/bpeg.bpeg index 21e689e..5570ecb 100644 --- a/grammars/bpeg.bpeg +++ b/grammars/bpeg.bpeg @@ -1,7 +1,9 @@ # This is a file defining the BPEG grammar using BPEG syntax -Grammar: __ 0+(Def 0-1(__`;))%__ __ -Def: @[name]id __ `: __ @[definition]extended-pat +Grammar: __ 0+(Def 0-1(__`;))%__ __ ($$ / @[!]{... => "Could not parse this code"}) +Def: @[name]id __ `: __ (@[definition]extended-pat + / $$ @[!]{=>"No definition for rule"} + / @[!]{...>(`;/id__`:/$) => "Invalid definition: @0"}) # This is used for command line arguments: String-pattern: 0+(`\ pat 0-1`; / .) @@ -9,14 +11,20 @@ String-pattern: 0+(`\ pat 0-1`; / .) pat: suffixed-pat / simple-pat simple-pat: Upto-and / Dot / String / Char-range / Char / Escape-range / Escape / No / Nodent / Repeat / After / Before / Capture / Replace / Ref / parens -suffixed-pat: Eq-pat + +suffixed-pat: Eq-pat / simple-pat ( + @[!]{`* => "'*' is not a BPEG operator. Use 0+<pat> instead of <pat>*"} + / @[!]{`+ => "'+' is not a BPEG operator. Use 1+<pat> instead of <pat>+"} + / @[!]{`? => "'?' is not a BPEG operator. Use 0-1<pat> or 1-<pat> instead of <pat>?"} + / @[!]{`= => "'=' is not valid here. Perhaps you meant '==' or ':'"} +) Eq-pat: @[first]simple-pat "==" @[second]pat Dot: `. !`. String: ( - `" @[s]0+(Escape / !`"$.) `" - / `' @[s]0+(Escape / !`'$.) `' + `" @[s]0+(Escape / !`".) (`" / @[!]{=> "Expected closing quote here"}) + / `' @[s]0+(Escape / !`'.) (`' / @[!]{=> "Expected closing quote here"}) ) Char-range: `` @[low]. `- @[high]. Char: `` @[s]. @@ -37,13 +45,13 @@ Repeat: ( ) _ @[repeat-pat]pat 0-1( __ `% __ @[sep]pat) After: `< _ pat Before: `> _ pat -Capture: `@ 0-1(_ `[ @[capture-name](...>`]) `]) _ @[capture]pat +Capture: `@ 0-1(_ `[ @[capture-name](...>(`]/$$)) (`] / @[!]{=>"Expected closing bracket here"})) _ @[capture]pat Replace: `{ __ ( 0-1(@[replace-pat]extended-pat __) "=>" 0-1(__ @[replacement]String) - ) __ `} + ) __ (`} / @[!]{=> "Expected closing brace here"}) Ref: @[name]id !>(__`:) -parens: `( __ extended-pat __ `) +parens: `( __ extended-pat (__ `) / @[!]{=> "Expected closing parenthesis here"}) Chain: 2+@pat % (__) Otherwise: 2+@(Chain/pat) % (__`/__) @@ -76,7 +76,10 @@ typedef struct vm_op_s { typedef struct match_s { // Where the match starts and ends (end is after the last character) const char *start, *end; - const char *name_or_replacement; + union { + const char *name; + const char *replacement; + } value; struct match_s *child, *nextsibling; vm_op_t *op; } match_t; @@ -56,9 +56,9 @@ static size_t push_backrefs(grammar_t *g, match_t *m) if (m == NULL) return 0; if (m->op->op == VM_REF) return 0; size_t count = 0; - if (m->op->op == VM_CAPTURE && m->name_or_replacement) { + if (m->op->op == VM_CAPTURE && m->value.name) { ++count; - push_backref(g, m->name_or_replacement, m->child); + push_backref(g, m->value.name, m->child); } if (m->child) count += push_backrefs(g, m->child); if (m->nextsibling) count += push_backrefs(g, m->nextsibling); @@ -228,7 +228,7 @@ static match_t *_match(grammar_t *g, file_t *f, const char *str, vm_op_t *op, un m->op = op; m->child = p; if (op->args.capture.name) - m->name_or_replacement = op->args.capture.name; + m->value.name = op->args.capture.name; return m; } case VM_OTHERWISE: { @@ -286,7 +286,7 @@ static match_t *_match(grammar_t *g, file_t *f, const char *str, vm_op_t *op, un } else { m->end = m->start; } - m->name_or_replacement = op->args.replace.replacement; + m->value.replacement = op->args.replace.replacement; return m; } case VM_REF: { @@ -325,7 +325,7 @@ static match_t *_match(grammar_t *g, file_t *f, const char *str, vm_op_t *op, un m->end = best->end; m->op = op; m->child = best; - m->name_or_replacement = op->args.s; + m->value.name = op->args.s; return m; } case VM_BACKREF: { @@ -490,7 +490,7 @@ static match_t *get_capture_n(match_t *m, int *n) */ static match_t *get_capture_named(match_t *m, const char *name) { - if (m->op->op == VM_CAPTURE && m->name_or_replacement && streq(m->name_or_replacement, name)) + if (m->op->op == VM_CAPTURE && m->value.name && streq(m->value.name, name)) return m; for (match_t *c = m->child; c; c = c->nextsibling) { match_t *cap = get_capture_named(c, name); @@ -523,7 +523,7 @@ static match_t *get_cap(match_t *m, const char **r) void print_match(file_t *f, match_t *m) { if (m->op->op == VM_REPLACE) { - for (const char *r = m->name_or_replacement; *r; ) { + for (const char *r = m->value.replacement; *r; ) { if (*r == '\\') { ++r; fputc(unescapechar(r, &r), stdout); @@ -585,7 +585,7 @@ static match_t *match_backref(const char *str, vm_op_t *op, match_t *cap, unsign match_t **dest = &ret->child; if (cap->op->op == VM_REPLACE) { - for (const char *r = cap->name_or_replacement; *r; ) { + for (const char *r = cap->value.replacement; *r; ) { if (*r == '\\') { ++r; if (*(str++) != unescapechar(r, &r)) { |
