diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2021-01-15 12:40:19 -0800 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2021-01-15 12:40:19 -0800 |
| commit | ce1868d707b0f0338a93057d017252c98e50e15d (patch) | |
| tree | 8ded2ca165610361d9ea21f7402db4a9fa6dd39c | |
| parent | 26fed0ec2848b023131df8c4fb967c360e0382a4 (diff) | |
Added support for `bp -p 'foo: "xx"; baz; baz: foo'`
| -rw-r--r-- | README.md | 3 | ||||
| -rw-r--r-- | bp.1 | 11 | ||||
| -rw-r--r-- | bp.c | 41 | ||||
| -rw-r--r-- | compiler.c | 21 | ||||
| -rw-r--r-- | compiler.h | 4 |
5 files changed, 43 insertions, 37 deletions
@@ -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 <name>:<def>` define a grammar rule -* `-D` `--define-string <name>:<def>` define a grammar rule (string-pattern) * `-p` `--pattern <pat>` provide a pattern (equivalent to `bp '\(<pat>)'`) * `-P` `--pattern-string <pat>` provide a string pattern (equivalent to `bp '<pat>'`, but may be useful if `'<pat>'` begins with a '-') * `-r` `--replace <replacement>` 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 @@ -14,8 +14,6 @@ bp \- Bruce's Parsing Expression Grammar tool [\fI-I\fR|\fI--inplace\fR] [\fI-p\fR|\fI--pattern\fR \fI<pattern>\fR] [\fI-P\fR|\fI--pattern-string\fR \fI<string-pattern>\fR] -[\fI-d\fR|\fI--define\fR \fI<name>\fR:\fI<pattern>\fR] -[\fI-D\fR|\fI--define-string\fR \fI<name>\fR:\fI<string-pattern>\fR] [\fI-r\fR|\fI--replace\fR \fI<replacement>\fR] [\fI-g\fR|\fI--grammar\fR \fI<grammar file>\fR] [\fI-c\fR|\fI--conntext\fR \fI<N>\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<name>\fR:\fI<pattern>\fR -Define a grammar rule using a bp pattern. - -.B \-D\fR, \fB--define-string \fI<name>\fR:\fI<string-pattern>\fR -Define a grammar rule using a bp string pattern. - .B \-r\fR, \fB--replace \fI<replacement>\fR Replace all occurrences of the main pattern with the given string. @@ -188,6 +180,9 @@ Will match only if \fI<pat1>\fR matches and \fI<pat2>\fR doesn't match the text Will match only if \fI<pat1>\fR and \fI<pat2>\fR don't both match and have the exact same length. Pronounced \fI<pat1>\fB-assuming-it-doesn't-equal-\fI<pat2>\fR +.B \fI<name>\fB:\fI<pat>\fR +\fBDefine-\fI<name>\fB-to-mean-\fI<pat>\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). @@ -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 <name>:<def> define a grammar rule\n" - " -D --define-string <name>:<def> define a grammar rule (string-pattern)\n" " -p --pattern <pat> provide a pattern (equivalent to bp '\\(<pat>)')\n" " -P --pattern-string <pat> provide a string pattern (may be useful if '<pat>' begins with a '-')\n" " -r --replace <replacement> 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, "<pattern argument>", 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, "<pattern argument>", flag); vm_op_t *p = bp_stringpattern(arg_file, arg_file->contents); @@ -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 @@ -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 |
