From ce1868d707b0f0338a93057d017252c98e50e15d Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 15 Jan 2021 12:40:19 -0800 Subject: Added support for `bp -p 'foo: "xx"; baz; baz: foo'` --- README.md | 3 +-- bp.1 | 11 +++-------- bp.c | 41 +++++++++++++++-------------------------- compiler.c | 21 +++++++++++++++++++++ compiler.h | 4 +++- 5 files changed, 43 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index f90b62d..650fb53 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,6 @@ It's written in pure C with no dependencies. * `-e` `--explain` print an explanation of the matches * `-j` `--json` print matches as JSON objects * `-l` `--list-files` print only filenames containing matches -* `-d` `--define :` define a grammar rule -* `-D` `--define-string :` define a grammar rule (string-pattern) * `-p` `--pattern ` provide a pattern (equivalent to `bp '\()'`) * `-P` `--pattern-string ` provide a string pattern (equivalent to `bp ''`, but may be useful if `''` begins with a '-') * `-r` `--replace ` replace the input pattern with the given replacement @@ -63,6 +61,7 @@ Pattern | Meaning `(pat1 @keep=pat2) => "@keep"` | Match `pat1` followed by `pat2` and replace it with the text of `pat2` `pat1==pat2` | `pat1`, assuming `pat2` also matches with the same length `pat1!=pat2` | `pat1`, unless `pat2` also matches with the same length +`name:pat2` | `name` is defined to mean `pat` `#( block comment )#` | A block comment `# line comment` | A line comment diff --git a/bp.1 b/bp.1 index 2c48799..5b220ad 100644 --- a/bp.1 +++ b/bp.1 @@ -14,8 +14,6 @@ bp \- Bruce's Parsing Expression Grammar tool [\fI-I\fR|\fI--inplace\fR] [\fI-p\fR|\fI--pattern\fR \fI\fR] [\fI-P\fR|\fI--pattern-string\fR \fI\fR] -[\fI-d\fR|\fI--define\fR \fI\fR:\fI\fR] -[\fI-D\fR|\fI--define-string\fR \fI\fR:\fI\fR] [\fI-r\fR|\fI--replace\fR \fI\fR] [\fI-g\fR|\fI--grammar\fR \fI\fR] [\fI-c\fR|\fI--conntext\fR \fI\fR] @@ -42,12 +40,6 @@ Perform pattern matching case-insensitively. .B \-I\fR, \fB--inplace Perform filtering or replacement in-place (i.e. overwrite files with new content). -.B \-d\fR, \fB--define \fI\fR:\fI\fR -Define a grammar rule using a bp pattern. - -.B \-D\fR, \fB--define-string \fI\fR:\fI\fR -Define a grammar rule using a bp string pattern. - .B \-r\fR, \fB--replace \fI\fR Replace all occurrences of the main pattern with the given string. @@ -188,6 +180,9 @@ Will match only if \fI\fR matches and \fI\fR doesn't match the text Will match only if \fI\fR and \fI\fR don't both match and have the exact same length. Pronounced \fI\fB-assuming-it-doesn't-equal-\fI\fR +.B \fI\fB:\fI\fR +\fBDefine-\fI\fB-to-mean-\fI\fR (pattern definition) + .B | This pattern matches the indentation at the beginning of a line that has the same indentation as the line before (or zero indentation on the first line). diff --git a/bp.c b/bp.c index 5f5158c..0b0590f 100644 --- a/bp.c +++ b/bp.c @@ -31,8 +31,6 @@ static const char *usage = ( " -I --inplace modify a file in-place\n" " -i --ignore-case preform matching case-insensitively\n" " -l --list-files list filenames only\n" - " -d --define : define a grammar rule\n" - " -D --define-string : define a grammar rule (string-pattern)\n" " -p --pattern provide a pattern (equivalent to bp '\\()')\n" " -P --pattern-string provide a string pattern (may be useful if '' begins with a '-')\n" " -r --replace replace the input pattern with the given replacement\n" @@ -311,33 +309,24 @@ int main(int argc, char *argv[]) f = load_file(&loaded_files, "/etc/xdg/bp/%s.bp", flag); check(f != NULL, "Couldn't find grammar: %s", flag); defs = load_grammar(defs, f); // Keep in memory for debug output - } else if (FLAG("--define") || FLAG("-d")) { - char *def = flag; - char *eq = strchr(def, ':'); - check(eq, "Rule definitions must include an ':'\n\n%s", usage); - *eq = '\0'; - char *src = ++eq; - file_t *def_file = spoof_file(&loaded_files, def, src); - vm_op_t *pat = bp_pattern(def_file, def_file->contents); - check(pat, "Failed to compile pattern: %s", flag); - defs = with_def(defs, def_file, strlen(def), def, pat); - } else if (FLAG("--define-string") || FLAG("-D")) { - char *def = flag; - char *eq = strchr(def, ':'); - check(eq, "Rule definitions must include an ':'\n\n%s", usage); - *eq = '\0'; - char *src = ++eq; - file_t *def_file = spoof_file(&loaded_files, def, src); - vm_op_t *pat = bp_stringpattern(def_file, def_file->contents); - check(pat, "Failed to compile pattern: %s", src); - defs = with_def(defs, def_file, strlen(def), def, pat); } else if (FLAG("--pattern") || FLAG("-p")) { check(npatterns == 0, "Cannot define multiple patterns"); file_t *arg_file = spoof_file(&loaded_files, "", flag); - vm_op_t *p = bp_pattern(arg_file, arg_file->contents); - check(p, "Pattern failed to compile: %s", flag); - defs = with_def(defs, arg_file, strlen("pattern"), "pattern", p); - ++npatterns; + for (const char *str = arg_file->contents; str < arg_file->end; ) { + def_t *d = bp_definition(arg_file, str); + if (d) { + d->next = defs; + defs = d; + str = d->op->end; + } else { + vm_op_t *p = bp_pattern(arg_file, str); + check(p, "Pattern failed to compile: %s", flag); + defs = with_def(defs, arg_file, strlen("pattern"), "pattern", p); + ++npatterns; + str = p->end; + } + str = strchr(str, ';') ? strchr(str, ';') + 1 : str; + } } else if (FLAG("--pattern-string") || FLAG("-P")) { file_t *arg_file = spoof_file(&loaded_files, "", flag); vm_op_t *p = bp_stringpattern(arg_file, arg_file->contents); diff --git a/compiler.c b/compiler.c index 951462a..8e782cc 100644 --- a/compiler.c +++ b/compiler.c @@ -593,4 +593,25 @@ vm_op_t *bp_pattern(file_t *f, const char *str) return op; } +// +// Match a definition (id__`:__pattern) +// +def_t *bp_definition(file_t *f, const char *str) +{ + const char *name = after_spaces(str); + str = after_name(name); + if (!str) return NULL; + size_t namelen = (size_t)(str - name); + if (!matchchar(&str, ':')) return NULL; + vm_op_t *pat = bp_pattern(f, str); + if (!pat) return NULL; + matchchar(&pat->end, ';'); // TODO: verify this is safe to mutate + def_t *def = new(def_t); + def->file = f; + def->namelen = namelen; + def->name = name; + def->op = pat; + return def; +} + // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1 diff --git a/compiler.h b/compiler.h index 3b61c17..76e7734 100644 --- a/compiler.h +++ b/compiler.h @@ -15,8 +15,10 @@ __attribute__((nonnull(1,2))) vm_op_t *bp_stringpattern(file_t *f, const char *str); __attribute__((nonnull(1,2))) vm_op_t *bp_replacement(file_t *f, vm_op_t *pat, const char *replacement); -__attribute__((nonnull(1,2))) +__attribute__((nonnull)) vm_op_t *bp_pattern(file_t *f, const char *str); +__attribute__((nonnull)) +def_t *bp_definition(file_t *f, const char *str); #endif // vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1 -- cgit v1.2.3