aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2020-09-17 00:29:11 -0700
committerBruce Hill <bruce@bruce-hill.com>2020-09-17 00:29:11 -0700
commit67e538e774b37749c53c553b941736a281e6ac8f (patch)
treecc02c6622c831b2cb2dad7e3128e9a9e3dbb3ded
parent2477d9869c295cbaa1e948fc6e40190aa7149295 (diff)
Some error handling
-rw-r--r--bpeg.c17
-rw-r--r--file_loader.c8
-rw-r--r--grammars/bpeg.bpeg24
-rw-r--r--types.h5
-rw-r--r--vm.c16
5 files changed, 52 insertions, 18 deletions
diff --git a/bpeg.c b/bpeg.c
index 55c2e98..1c934ab 100644
--- a/bpeg.c
+++ b/bpeg.c
@@ -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) % (__`/__)
diff --git a/types.h b/types.h
index 1a19e86..2a1cc2a 100644
--- a/types.h
+++ b/types.h
@@ -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;
diff --git a/vm.c b/vm.c
index 40efb30..c7bf517 100644
--- a/vm.c
+++ b/vm.c
@@ -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)) {