Simplified grammars using intrusive linked lists instead of dynamic

arrays
This commit is contained in:
Bruce Hill 2021-01-10 00:12:09 -08:00
parent aa91728a08
commit 9d1f51c483
6 changed files with 80 additions and 52 deletions

2
bp.c
View File

@ -133,7 +133,7 @@ int main(int argc, char *argv[])
char path[PATH_MAX] = {0};
const char *rule = "find-all";
grammar_t *g = new_grammar();
grammar_t *g = new(grammar_t);
// Load builtins:
if (access("/etc/xdg/bp/builtins.bp", R_OK) != -1)

View File

@ -10,24 +10,18 @@
#include "grammar.h"
#include "utils.h"
grammar_t *new_grammar(void)
{
grammar_t *g = new(grammar_t);
g->definitions = xcalloc(sizeof(def_t), (g->defcapacity = 128));
return g;
}
/*
* Add a definition to the grammar
*/
void add_def(grammar_t *g, file_t *f, const char *src, const char *name, vm_op_t *op)
{
if (g->defcount >= g->defcapacity) {
g->definitions = xrealloc(g->definitions, sizeof(&g->definitions[0])*(g->defcapacity += 32));
}
int i = g->defcount;
g->definitions[i].file = f;
g->definitions[i].source = src;
g->definitions[i].name = name;
g->definitions[i].op = op;
++g->defcount;
def_t *def = new(def_t);
def->next = g->firstdef;
def->file = f;
def->source = src;
def->name = name;
def->op = op;
g->firstdef = def;
}
/*
@ -65,39 +59,44 @@ vm_op_t *load_grammar(grammar_t *g, file_t *f)
return ret;
}
/*
* Look up a backreference or grammar definition by name
*/
vm_op_t *lookup(grammar_t *g, const char *name)
{
// Search backwards so newer backrefs/defs take precedence
for (int i = (int)g->backrefcount-1; i >= 0; i--) {
if (streq(g->backrefs[i].name, name)) {
return g->backrefs[i].op;
}
for (backref_t *b = g->firstbackref; b; b = b->next) {
if (streq(b->name, name))
return b->op;
}
for (int i = g->defcount-1; i >= 0; i--) {
if (streq(g->definitions[i].name, name)) {
return g->definitions[i].op;
}
for (def_t *d = g->firstdef; d; d = d->next) {
if (streq(d->name, name))
return d->op;
}
return NULL;
}
/*
* Push a backreference onto the backreference stack
*/
void push_backref(grammar_t *g, const char *name, match_t *capture)
{
if (g->backrefcount >= g->backrefcapacity) {
g->backrefs = xrealloc(g->backrefs, sizeof(g->backrefs[0])*(g->backrefcapacity += 32));
}
size_t i = g->backrefcount++;
g->backrefs[i].name = name;
g->backrefs[i].capture = capture;
backref_t *backref = new(backref_t);
backref->name = name;
backref->capture = capture;
vm_op_t *op = new(vm_op_t);
op->op = VM_BACKREF;
op->start = capture->start;
op->end = capture->end;
op->len = -1; // TODO: maybe calculate this?
op->len = -1; // TODO: maybe calculate this? (nontrivial because of replacements)
op->args.backref = capture;
g->backrefs[i].op = op;
backref->op = op;
backref->next = g->firstbackref;
g->firstbackref = backref;
}
/*
* Push all the backreferences contained in a match onto the backreference stack
*/
size_t push_backrefs(grammar_t *g, match_t *m)
{
if (m->op->op == VM_REF) return 0;
@ -111,14 +110,17 @@ size_t push_backrefs(grammar_t *g, match_t *m)
return count;
}
/*
* Pop a number of backreferences off the backreference stack
*/
void pop_backrefs(grammar_t *g, size_t count)
{
check(count <= g->backrefcount, "Attempt to pop %ld backrefs when there are only %ld", count, g->backrefcount);
for ( ; count > 0; count--) {
//free(g->backrefs[i].op); // TODO: memory leak problem??
int i = (int)g->backrefcount - 1;
memset(&g->backrefs[i], 0, sizeof(g->backrefs[i]));
--g->backrefcount;
backref_t *b = g->firstbackref;
g->firstbackref = b->next;
check(b, "Attempt to pop %ld more backrefs than there are", count);
xfree((void**)&b->op);
xfree((void**)&b);
}
}

View File

@ -7,7 +7,6 @@
#include "file_loader.h"
#include "types.h"
grammar_t *new_grammar(void);
__attribute__((nonnull(1,3,4,5)))
void add_def(grammar_t *g, file_t *f, const char *src, const char *name, vm_op_t *op);
__attribute__((nonnull))

31
types.h
View File

@ -88,24 +88,33 @@ typedef struct match_s {
vm_op_t *op;
} match_t;
typedef struct {
/*
* Pattern matching rule definition
*/
typedef struct def_s {
const char *name;
const char *source;
file_t *file;
vm_op_t *op;
struct def_s *next;
} def_t;
typedef struct {
size_t defcount, defcapacity;
def_t *definitions;
/*
* Backreference (look up previous capture by name)
*/
typedef struct backref_s {
const char *name;
match_t *capture;
vm_op_t *op;
struct backref_s *next;
} backref_t;
size_t backrefcount, backrefcapacity;
struct {
const char *name;
match_t *capture;
vm_op_t *op;
} *backrefs;
/*
* Grammar (a collection of definitions)
*/
typedef struct {
def_t *firstdef;
backref_t *firstbackref;
} grammar_t;
#endif

17
utils.c
View File

@ -3,6 +3,7 @@
*/
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include "utils.h"
@ -186,6 +187,9 @@ size_t unescape_string(char *dest, const char *src, size_t bufsize)
#undef PUT
}
/*
* Fail and exit if a memory value is NULL
*/
void *memcheck(void *p)
{
if (p == NULL) {
@ -195,7 +199,9 @@ void *memcheck(void *p)
return p;
}
/*
* Case-insensitive memory comparison
*/
int memicmp(const void *v1, const void *v2, size_t n)
{
int result = 0;
@ -205,4 +211,13 @@ int memicmp(const void *v1, const void *v2, size_t n)
return result;
}
/*
* Free memory, but also set the pointer to NULL for safety
*/
void xfree(void **p)
{
free(*p);
p = NULL;
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1

View File

@ -31,7 +31,10 @@ int matchstr(const char **str, const char *target);
__attribute__((nonnull))
size_t unescape_string(char *dest, const char *src, size_t bufsize);
void *memcheck(void *p);
__attribute__((nonnull))
int memicmp(const void *s1, const void *s2, size_t n);
__attribute__((nonnull))
void xfree(void **p);
#endif
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1