Some error handling
This commit is contained in:
parent
2477d9869c
commit
67e538e774
17
bpeg.c
17
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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) % (__`/__)
|
||||
|
5
types.h
5
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;
|
||||
|
16
vm.c
16
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)) {
|
||||
|
Loading…
Reference in New Issue
Block a user