Attachment "sync-with-postgres.patch" to
ticket [187d7f499b]
added by
tgl
2015-09-19 16:59:08.
diff -pcdr tcl8.6.4.withqbr/generic/regc_color.c tcl8.6.4/generic/regc_color.c
*** tcl8.6.4.withqbr/generic/regc_color.c Thu Feb 26 11:57:28 2015
--- tcl8.6.4/generic/regc_color.c Fri Sep 18 15:10:57 2015
*************** dumpcolors(
*** 777,794 ****
}
/*
! * It's hard to do this more efficiently.
*/
! for (c=CHR_MIN ; c<CHR_MAX ; c++) {
if (GETCOLOR(cm, c) == co) {
dumpchr(c, f);
}
}
- assert(c == CHR_MAX);
- if (GETCOLOR(cm, c) == co) {
- dumpchr(c, f);
- }
fprintf(f, "\n");
}
}
--- 777,795 ----
}
/*
! * Unfortunately, it's hard to do this next bit more efficiently.
! *
! * Spencer's original coding has the loop iterating from CHR_MIN
! * to CHR_MAX, but that's utterly unusable for 32-bit chr, or
! * even 16-bit. For debugging purposes it seems fine to print
! * only chr codes up to 1000 or so.
*/
! for (c=CHR_MIN ; c<1000 ; c++) {
if (GETCOLOR(cm, c) == co) {
dumpchr(c, f);
}
}
fprintf(f, "\n");
}
}
diff -pcdr tcl8.6.4.withqbr/generic/regc_cvec.c tcl8.6.4/generic/regc_cvec.c
*** tcl8.6.4.withqbr/generic/regc_cvec.c Thu Feb 26 11:57:28 2015
--- tcl8.6.4/generic/regc_cvec.c Fri Sep 18 15:46:49 2015
*************** addchr(
*** 81,86 ****
--- 81,87 ----
struct cvec *cv, /* character vector */
pchr c) /* character to add */
{
+ assert(cv->nchrs < cv->chrspace);
cv->chrs[cv->nchrs++] = (chr)c;
}
diff -pcdr tcl8.6.4.withqbr/generic/regc_lex.c tcl8.6.4/generic/regc_lex.c
*** tcl8.6.4.withqbr/generic/regc_lex.c Thu Feb 26 11:57:28 2015
--- tcl8.6.4/generic/regc_lex.c Fri Sep 18 14:24:03 2015
*************** newline(void)
*** 1139,1162 ****
}
/*
- - ch - return the chr sequence for regc_locale.c's fake collating element ch
- * This helps confine use of CHR to this source file. Beware that the caller
- * knows how long the sequence is.
- ^ #ifdef REG_DEBUG
- ^ static const chr *ch(NOPARMS);
- ^ #endif
- */
- #ifdef REG_DEBUG
- static const chr *
- ch(void)
- {
- static const chr chstr[] = { CHR('c'), CHR('h'), CHR('\0') };
-
- return chstr;
- }
- #endif
-
- /*
- chrnamed - return the chr known by a given (chr string) name
* The code is a bit clumsy, but this routine gets only such specialized
* use that it hardly matters.
--- 1139,1144 ----
diff -pcdr tcl8.6.4.withqbr/generic/regc_nfa.c tcl8.6.4/generic/regc_nfa.c
*** tcl8.6.4.withqbr/generic/regc_nfa.c Thu Feb 26 11:57:28 2015
--- tcl8.6.4/generic/regc_nfa.c Fri Sep 18 16:18:49 2015
*************** newnfa(
*** 49,54 ****
--- 49,55 ----
nfa = (struct nfa *) MALLOC(sizeof(struct nfa));
if (nfa == NULL) {
+ ERR(REG_ESPACE);
return NULL;
}
*************** compact(
*** 1651,1663 ****
narcs = 0;
for (s = nfa->states; s != NULL; s = s->next) {
nstates++;
! narcs += 1 + s->nouts + 1;
! /* 1 as a fake for flags, nouts for arcs, 1 as endmarker */
}
cnfa->states = (struct carc **) MALLOC(nstates * sizeof(struct carc *));
cnfa->arcs = (struct carc *) MALLOC(narcs * sizeof(struct carc));
! if (cnfa->states == NULL || cnfa->arcs == NULL) {
if (cnfa->states != NULL) {
FREE(cnfa->states);
}
--- 1652,1667 ----
narcs = 0;
for (s = nfa->states; s != NULL; s = s->next) {
nstates++;
! narcs += s->nouts + 1; /* need one extra for endmarker */
}
+ cnfa->stflags = (char *) MALLOC(nstates * sizeof(char));
cnfa->states = (struct carc **) MALLOC(nstates * sizeof(struct carc *));
cnfa->arcs = (struct carc *) MALLOC(narcs * sizeof(struct carc));
! if (cnfa->stflags == NULL || cnfa->states == NULL || cnfa->arcs == NULL) {
! if (cnfa->stflags != NULL) {
! FREE(cnfa->stflags);
! }
if (cnfa->states != NULL) {
FREE(cnfa->states);
}
*************** compact(
*** 1680,1688 ****
ca = cnfa->arcs;
for (s = nfa->states; s != NULL; s = s->next) {
assert((size_t) s->no < nstates);
cnfa->states[s->no] = ca;
- ca->co = 0; /* clear and skip flags "arc" */
- ca++;
first = ca;
for (a = s->outs; a != NULL; a = a->outchain) {
switch (a->type) {
--- 1684,1691 ----
ca = cnfa->arcs;
for (s = nfa->states; s != NULL; s = s->next) {
assert((size_t) s->no < nstates);
+ cnfa->stflags[s->no] = 0;
cnfa->states[s->no] = ca;
first = ca;
for (a = s->outs; a != NULL; a = a->outchain) {
switch (a->type) {
*************** compact(
*** 1716,1724 ****
*/
for (a = nfa->pre->outs; a != NULL; a = a->outchain) {
! cnfa->states[a->to->no]->co = 1;
}
! cnfa->states[nfa->pre->no]->co = 1;
}
/*
--- 1719,1727 ----
*/
for (a = nfa->pre->outs; a != NULL; a = a->outchain) {
! cnfa->stflags[a->to->no] = CNFA_NOPROGRESS;
}
! cnfa->stflags[nfa->pre->no] = CNFA_NOPROGRESS;
}
/*
*************** freecnfa(
*** 1762,1767 ****
--- 1765,1771 ----
{
assert(cnfa->nstates != 0); /* not empty already */
cnfa->nstates = 0;
+ FREE(cnfa->stflags);
FREE(cnfa->states);
FREE(cnfa->arcs);
}
*************** dumpcnfa(
*** 1984,1990 ****
}
fprintf(f, "\n");
for (st = 0; st < cnfa->nstates; st++) {
! dumpcstate(st, cnfa->states[st], cnfa, f);
}
fflush(f);
#endif
--- 1988,1994 ----
}
fprintf(f, "\n");
for (st = 0; st < cnfa->nstates; st++) {
! dumpcstate(st, cnfa, f);
}
fflush(f);
#endif
*************** dumpcnfa(
*** 1997,2021 ****
/*
- dumpcstate - dump a compacted-NFA state in human-readable form
! ^ static void dumpcstate(int, struct carc *, struct cnfa *, FILE *);
*/
static void
dumpcstate(
int st,
- struct carc *ca,
struct cnfa *cnfa,
FILE *f)
{
! int i;
int pos;
! fprintf(f, "%d%s", st, (ca[0].co) ? ":" : ".");
pos = 1;
! for (i = 1; ca[i].co != COLORLESS; i++) {
! if (ca[i].co < cnfa->ncolors) {
! fprintf(f, "\t[%ld]->%d", (long) ca[i].co, ca[i].to);
} else {
! fprintf(f, "\t:%ld:->%d", (long) ca[i].co-cnfa->ncolors,ca[i].to);
}
if (pos == 5) {
fprintf(f, "\n");
--- 2001,2024 ----
/*
- dumpcstate - dump a compacted-NFA state in human-readable form
! ^ static void dumpcstate(int, struct cnfa *, FILE *);
*/
static void
dumpcstate(
int st,
struct cnfa *cnfa,
FILE *f)
{
! struct carc *ca;
int pos;
! fprintf(f, "%d%s", st, (cnfa->stflags[st] & CNFA_NOPROGRESS) ? ":" : ".");
pos = 1;
! for (ca = cnfa->states[st]; ca->co != COLORLESS; ca++) {
! if (ca->co < cnfa->ncolors) {
! fprintf(f, "\t[%ld]->%d", (long) ca->co, ca->to);
} else {
! fprintf(f, "\t:%ld:->%d", (long) (ca->co - cnfa->ncolors), ca->to);
}
if (pos == 5) {
fprintf(f, "\n");
*************** dumpcstate(
*** 2024,2030 ****
pos++;
}
}
! if (i == 1 || pos != 1) {
fprintf(f, "\n");
}
fflush(f);
--- 2027,2033 ----
pos++;
}
}
! if (ca == cnfa->states[st] || pos != 1) {
fprintf(f, "\n");
}
fflush(f);
diff -pcdr tcl8.6.4.withqbr/generic/regcomp.c tcl8.6.4/generic/regcomp.c
*** tcl8.6.4.withqbr/generic/regcomp.c Fri Sep 18 12:16:30 2015
--- tcl8.6.4/generic/regcomp.c Fri Sep 18 16:20:14 2015
*************** static int lexdigits(struct vars *, int,
*** 83,91 ****
static int brenext(struct vars *, pchr);
static void skip(struct vars *);
static chr newline(NOPARMS);
- #ifdef REG_DEBUG
- static const chr *ch(NOPARMS);
- #endif
static chr chrnamed(struct vars *, const chr *, const chr *, pchr);
/* === regc_color.c === */
static void initcm(struct vars *, struct colormap *);
--- 83,88 ----
*************** static void dumparc(struct arc *, struct
*** 165,171 ****
#endif
static void dumpcnfa(struct cnfa *, FILE *);
#ifdef REG_DEBUG
! static void dumpcstate(int, struct carc *, struct cnfa *, FILE *);
#endif
/* === regc_cvec.c === */
static struct cvec *clearcvec(struct cvec *);
--- 162,168 ----
#endif
static void dumpcnfa(struct cnfa *, FILE *);
#ifdef REG_DEBUG
! static void dumpcstate(int, struct cnfa *, FILE *);
#endif
/* === regc_cvec.c === */
static struct cvec *clearcvec(struct cvec *);
*************** struct vars {
*** 210,216 ****
struct subre *tree; /* subexpression tree */
struct subre *treechain; /* all tree nodes allocated */
struct subre *treefree; /* any free tree nodes */
! int ntree; /* number of tree nodes */
struct cvec *cv; /* interface cvec */
struct cvec *cv2; /* utility cvec */
struct subre *lacons; /* lookahead-constraint vector */
--- 207,213 ----
struct subre *tree; /* subexpression tree */
struct subre *treechain; /* all tree nodes allocated */
struct subre *treefree; /* any free tree nodes */
! int ntree; /* number of tree nodes, plus one */
struct cvec *cv; /* interface cvec */
struct cvec *cv2; /* utility cvec */
struct subre *lacons; /* lookahead-constraint vector */
*************** struct vars {
*** 223,235 ****
#define EAT(t) (SEE(t) && next(v)) /* if next is this, swallow it */
#define VISERR(vv) ((vv)->err != 0)/* have we seen an error yet? */
#define ISERR() VISERR(v)
! #define VERR(vv,e) \
! ((vv)->nexttype = EOS, ((vv)->err) ? (vv)->err : ((vv)->err = (e)))
#define ERR(e) VERR(v, e) /* record an error */
#define NOERR() {if (ISERR()) return;} /* if error seen, return */
#define NOERRN() {if (ISERR()) return NULL;} /* NOERR with retval */
#define NOERRZ() {if (ISERR()) return 0;} /* NOERR with retval */
! #define INSIST(c, e) ((c) ? 0 : ERR(e)) /* if condition false, error */
#define NOTE(b) (v->re->re_info |= (b)) /* note visible condition */
#define EMPTYARC(x, y) newarc(v->nfa, EMPTY, 0, x, y)
--- 220,232 ----
#define EAT(t) (SEE(t) && next(v)) /* if next is this, swallow it */
#define VISERR(vv) ((vv)->err != 0)/* have we seen an error yet? */
#define ISERR() VISERR(v)
! #define VERR(vv,e) ((vv)->nexttype = EOS, \
! (vv)->err = ((vv)->err ? (vv)->err : (e)))
#define ERR(e) VERR(v, e) /* record an error */
#define NOERR() {if (ISERR()) return;} /* if error seen, return */
#define NOERRN() {if (ISERR()) return NULL;} /* NOERR with retval */
#define NOERRZ() {if (ISERR()) return 0;} /* NOERR with retval */
! #define INSIST(c, e) do { if (!(c)) ERR(e); } while (0) /* error if c false */
#define NOTE(b) (v->re->re_info |= (b)) /* note visible condition */
#define EMPTYARC(x, y) newarc(v->nfa, EMPTY, 0, x, y)
*************** struct vars {
*** 258,269 ****
((a)->type == PLAIN || (a)->type == AHEAD || (a)->type == BEHIND)
/* static function list */
! static struct fns functions = {
rfree, /* regfree insides */
};
/*
- compile - compile regular expression
^ int compile(regex_t *, const chr *, size_t, int);
*/
int
--- 255,268 ----
((a)->type == PLAIN || (a)->type == AHEAD || (a)->type == BEHIND)
/* static function list */
! static const struct fns functions = {
rfree, /* regfree insides */
};
/*
- compile - compile regular expression
+ * Note: on failure, no resources remain allocated, so regfree()
+ * need not be applied to re.
^ int compile(regex_t *, const chr *, size_t, int);
*/
int
*************** parseqatom(
*** 982,987 ****
--- 981,987 ----
NOERR();
assert(v->nextvalue > 0);
atom = subre(v, 'b', BACKR, lp, rp);
+ NOERR();
subno = v->nextvalue;
atom->subno = subno;
EMPTYARC(lp, rp); /* temporarily, so there's something */
*************** parseqatom(
*** 1133,1138 ****
--- 1133,1139 ----
*/
t = subre(v, '.', COMBINE(qprefer, atom->flags), lp, rp);
+ NOERR();
t->left = atom;
atomp = &t->left;
*************** parseqatom(
*** 1146,1151 ****
--- 1147,1153 ----
assert(top->op == '=' && top->left == NULL && top->right == NULL);
top->left = subre(v, '=', top->flags, top->begin, lp);
+ NOERR();
top->op = '.';
top->right = t;
*************** freesrnode(
*** 1783,1789 ****
}
sr->flags = 0;
! if (v != NULL) {
sr->left = v->treefree;
v->treefree = sr;
} else {
--- 1785,1792 ----
}
sr->flags = 0;
! if (v != NULL && v->treechain != NULL) {
! /* we're still parsing, maybe we can reuse the subre */
sr->left = v->treefree;
v->treefree = sr;
} else {
*************** numst(
*** 1836,1841 ****
--- 1839,1857 ----
/*
- markst - mark tree nodes as INUSE
+ * Note: this is a great deal more subtle than it looks. During initial
+ * parsing of a regex, all subres are linked into the treechain list;
+ * discarded ones are also linked into the treefree list for possible reuse.
+ * After we are done creating all subres required for a regex, we run markst()
+ * then cleanst(), which results in discarding all subres not reachable from
+ * v->tree. We then clear v->treechain, indicating that subres must be found
+ * by descending from v->tree. This changes the behavior of freesubre(): it
+ * will henceforth FREE() unwanted subres rather than sticking them into the
+ * treefree list. (Doing that any earlier would result in dangling links in
+ * the treechain list.) This all means that freev() will clean up correctly
+ * if invoked before or after markst()+cleanst(); but it would not work if
+ * called partway through this state conversion, so we mustn't error out
+ * in or between these two functions.
^ static void markst(struct subre *);
*/
static void
*************** newlacon(
*** 1942,1965 ****
struct state *end,
int pos)
{
- struct subre *sub;
int n;
if (v->nlacons == 0) {
- v->lacons = (struct subre *) MALLOC(2 * sizeof(struct subre));
n = 1; /* skip 0th */
! v->nlacons = 2;
} else {
! v->lacons = (struct subre *) REALLOC(v->lacons,
! (v->nlacons+1)*sizeof(struct subre));
! n = v->nlacons++;
}
! if (v->lacons == NULL) {
ERR(REG_ESPACE);
return 0;
}
sub = &v->lacons[n];
sub->begin = begin;
sub->end = end;
--- 1958,1983 ----
struct state *end,
int pos)
{
int n;
+ struct subre *newlacons;
+ struct subre *sub;
if (v->nlacons == 0) {
n = 1; /* skip 0th */
! newlacons = (struct subre *) MALLOC(2 * sizeof(struct subre));
} else {
! n = v->nlacons;
! newlacons = (struct subre *) REALLOC(v->lacons,
! (n + 1) * sizeof(struct subre));
}
! if (newlacons == NULL) {
ERR(REG_ESPACE);
return 0;
}
+ v->lacons = newlacons;
+ v->nlacons = n + 1;
sub = &v->lacons[n];
sub->begin = begin;
sub->end = end;
*************** rfree(
*** 2007,2024 ****
g = (struct guts *) re->re_guts;
re->re_guts = NULL;
re->re_fns = NULL;
! g->magic = 0;
! freecm(&g->cmap);
! if (g->tree != NULL) {
! freesubre(NULL, g->tree);
! }
! if (g->lacons != NULL) {
! freelacons(g->lacons, g->nlacons);
! }
! if (!NULLCNFA(g->search)) {
! freecnfa(&g->search);
}
- FREE(g);
}
/*
--- 2025,2044 ----
g = (struct guts *) re->re_guts;
re->re_guts = NULL;
re->re_fns = NULL;
! if (g != NULL) {
! g->magic = 0;
! freecm(&g->cmap);
! if (g->tree != NULL) {
! freesubre(NULL, g->tree);
! }
! if (g->lacons != NULL) {
! freelacons(g->lacons, g->nlacons);
! }
! if (!NULLCNFA(g->search)) {
! freecnfa(&g->search);
! }
! FREE(g);
}
}
/*
*************** dump(
*** 2050,2056 ****
fprintf(f, "\n\n\n========= DUMP ==========\n");
fprintf(f, "nsub %d, info 0%lo, csize %d, ntree %d\n",
! re->re_nsub, re->re_info, re->re_csize, g->ntree);
dumpcolors(&g->cmap, f);
if (!NULLCNFA(g->search)) {
--- 2070,2076 ----
fprintf(f, "\n\n\n========= DUMP ==========\n");
fprintf(f, "nsub %d, info 0%lo, csize %d, ntree %d\n",
! (int) re->re_nsub, re->re_info, re->re_csize, g->ntree);
dumpcolors(&g->cmap, f);
if (!NULLCNFA(g->search)) {
diff -pcdr tcl8.6.4.withqbr/generic/rege_dfa.c tcl8.6.4/generic/rege_dfa.c
*** tcl8.6.4.withqbr/generic/rege_dfa.c Thu Feb 26 11:57:28 2015
--- tcl8.6.4/generic/rege_dfa.c Fri Sep 18 14:41:04 2015
*************** longest(
*** 84,90 ****
if (v->eflags®_FTRACE) {
while (cp < realstop) {
! FDEBUG(("+++ at c%d +++\n", css - d->ssets));
co = GETCOLOR(cm, *cp);
FDEBUG(("char %c, color %ld\n", (char)*cp, (long)co));
ss = css->outs[co];
--- 84,90 ----
if (v->eflags®_FTRACE) {
while (cp < realstop) {
! FDEBUG(("+++ at c%d +++\n", (int) (css - d->ssets)));
co = GETCOLOR(cm, *cp);
FDEBUG(("char %c, color %ld\n", (char)*cp, (long)co));
ss = css->outs[co];
*************** longest(
*** 118,124 ****
* Shutdown.
*/
! FDEBUG(("+++ shutdown at c%d +++\n", css - d->ssets));
if (cp == v->stop && stop == v->stop) {
if (hitstopp != NULL) {
*hitstopp = 1;
--- 118,124 ----
* Shutdown.
*/
! FDEBUG(("+++ shutdown at c%d +++\n", (int) (css - d->ssets)));
if (cp == v->stop && stop == v->stop) {
if (hitstopp != NULL) {
*hitstopp = 1;
*************** shortest(
*** 213,219 ****
if (v->eflags®_FTRACE) {
while (cp < realmax) {
! FDEBUG(("--- at c%d ---\n", css - d->ssets));
co = GETCOLOR(cm, *cp);
FDEBUG(("char %c, color %ld\n", (char)*cp, (long)co));
ss = css->outs[co];
--- 213,219 ----
if (v->eflags®_FTRACE) {
while (cp < realmax) {
! FDEBUG(("--- at c%d ---\n", (int) (css - d->ssets)));
co = GETCOLOR(cm, *cp);
FDEBUG(("char %c, color %ld\n", (char)*cp, (long)co));
ss = css->outs[co];
*************** miss(
*** 516,529 ****
gotState = 0;
for (i = 0; i < d->nstates; i++) {
if (ISBSET(css->states, i)) {
! for (ca = cnfa->states[i]+1; ca->co != COLORLESS; ca++) {
if (ca->co == co) {
BSET(d->work, ca->to);
gotState = 1;
if (ca->to == cnfa->post) {
isPost = 1;
}
! if (!cnfa->states[ca->to]->co) {
noProgress = 0;
}
FDEBUG(("%d -> %d\n", i, ca->to));
--- 516,529 ----
gotState = 0;
for (i = 0; i < d->nstates; i++) {
if (ISBSET(css->states, i)) {
! for (ca = cnfa->states[i]; ca->co != COLORLESS; ca++) {
if (ca->co == co) {
BSET(d->work, ca->to);
gotState = 1;
if (ca->to == cnfa->post) {
isPost = 1;
}
! if (!(cnfa->stflags[ca->to] & CNFA_NOPROGRESS)) {
noProgress = 0;
}
FDEBUG(("%d -> %d\n", i, ca->to));
*************** miss(
*** 537,544 ****
doLAConstraints = 0;
for (i = 0; i < d->nstates; i++) {
if (ISBSET(d->work, i)) {
! for (ca = cnfa->states[i]+1; ca->co != COLORLESS; ca++) {
! if (ca->co <= cnfa->ncolors) {
continue; /* NOTE CONTINUE */
}
sawLAConstraints = 1;
--- 537,544 ----
doLAConstraints = 0;
for (i = 0; i < d->nstates; i++) {
if (ISBSET(d->work, i)) {
! for (ca = cnfa->states[i]; ca->co != COLORLESS; ca++) {
! if (ca->co < cnfa->ncolors) {
continue; /* NOTE CONTINUE */
}
sawLAConstraints = 1;
*************** miss(
*** 553,559 ****
if (ca->to == cnfa->post) {
isPost = 1;
}
! if (!cnfa->states[ca->to]->co) {
noProgress = 0;
}
FDEBUG(("%d :> %d\n", i, ca->to));
--- 553,559 ----
if (ca->to == cnfa->post) {
isPost = 1;
}
! if (!(cnfa->stflags[ca->to] & CNFA_NOPROGRESS)) {
noProgress = 0;
}
FDEBUG(("%d :> %d\n", i, ca->to));
*************** miss(
*** 572,578 ****
for (p = d->ssets, i = d->nssused; i > 0; p++, i--) {
if (HIT(h, d->work, p, d->wordsper)) {
! FDEBUG(("cached c%d\n", p - d->ssets));
break; /* NOTE BREAK OUT */
}
}
--- 572,578 ----
for (p = d->ssets, i = d->nssused; i > 0; p++, i--) {
if (HIT(h, d->work, p, d->wordsper)) {
! FDEBUG(("cached c%d\n", (int) (p - d->ssets)));
break; /* NOTE BREAK OUT */
}
}
*************** miss(
*** 594,600 ****
}
if (!sawLAConstraints) { /* lookahead conds. always cache miss */
! FDEBUG(("c%d[%d]->c%d\n", css - d->ssets, co, p - d->ssets));
css->outs[co] = p;
css->inchain[co] = p->ins;
p->ins.ss = css;
--- 594,601 ----
}
if (!sawLAConstraints) { /* lookahead conds. always cache miss */
! FDEBUG(("c%d[%d]->c%d\n",
! (int) (css - d->ssets), co, (int) (p - d->ssets)));
css->outs[co] = p;
css->inchain[co] = p->ins;
p->ins.ss = css;
*************** getVacantSS(
*** 663,669 ****
ap = ss->ins;
while ((p = ap.ss) != NULL) {
co = ap.co;
! FDEBUG(("zapping c%d's %ld outarc\n", p - d->ssets, (long)co));
p->outs[co] = NULL;
ap = p->inchain[co];
p->inchain[co].ss = NULL; /* paranoia */
--- 664,670 ----
ap = ss->ins;
while ((p = ap.ss) != NULL) {
co = ap.co;
! FDEBUG(("zapping c%d's %ld outarc\n", (int) (p - d->ssets), (long)co));
p->outs[co] = NULL;
ap = p->inchain[co];
p->inchain[co].ss = NULL; /* paranoia */
*************** getVacantSS(
*** 680,686 ****
if (p == NULL) {
continue; /* NOTE CONTINUE */
}
! FDEBUG(("del outarc %d from c%d's in chn\n", i, p - d->ssets));
if (p->ins.ss == ss && p->ins.co == i) {
p->ins = ss->inchain[i];
} else {
--- 681,687 ----
if (p == NULL) {
continue; /* NOTE CONTINUE */
}
! FDEBUG(("del outarc %d from c%d's in chn\n", i, (int) (p - d->ssets)));
if (p->ins.ss == ss && p->ins.co == i) {
p->ins = ss->inchain[i];
} else {
*************** pickNextSS(
*** 772,778 ****
if ((ss->lastseen == NULL || ss->lastseen < ancient)
&& !(ss->flags&LOCKED)) {
d->search = ss + 1;
! FDEBUG(("replacing c%d\n", ss - d->ssets));
return ss;
}
}
--- 773,779 ----
if ((ss->lastseen == NULL || ss->lastseen < ancient)
&& !(ss->flags&LOCKED)) {
d->search = ss + 1;
! FDEBUG(("replacing c%d\n", (int) (ss - d->ssets)));
return ss;
}
}
*************** pickNextSS(
*** 780,786 ****
if ((ss->lastseen == NULL || ss->lastseen < ancient)
&& !(ss->flags&LOCKED)) {
d->search = ss + 1;
! FDEBUG(("replacing c%d\n", ss - d->ssets));
return ss;
}
}
--- 781,787 ----
if ((ss->lastseen == NULL || ss->lastseen < ancient)
&& !(ss->flags&LOCKED)) {
d->search = ss + 1;
! FDEBUG(("replacing c%d\n", (int) (ss - d->ssets)));
return ss;
}
}
diff -pcdr tcl8.6.4.withqbr/generic/regerror.c tcl8.6.4/generic/regerror.c
*** tcl8.6.4.withqbr/generic/regerror.c Thu Feb 26 11:57:28 2015
--- tcl8.6.4/generic/regerror.c Fri Sep 18 14:18:44 2015
*************** static const char unk[] = "*** unknown r
*** 41,47 ****
* Struct to map among codes, code names, and explanations.
*/
! static struct rerr {
int code;
const char *name;
const char *explain;
--- 41,47 ----
* Struct to map among codes, code names, and explanations.
*/
! static const struct rerr {
int code;
const char *name;
const char *explain;
*************** regerror(
*** 62,68 ****
char *errbuf, /* Result buffer (unless errbuf_size==0) */
size_t errbuf_size) /* Available space in errbuf, can be 0 */
{
! struct rerr *r;
const char *msg;
char convbuf[sizeof(unk)+50]; /* 50 = plenty for int */
size_t len;
--- 62,68 ----
char *errbuf, /* Result buffer (unless errbuf_size==0) */
size_t errbuf_size) /* Available space in errbuf, can be 0 */
{
! const struct rerr *r;
const char *msg;
char convbuf[sizeof(unk)+50]; /* 50 = plenty for int */
size_t len;
diff -pcdr tcl8.6.4.withqbr/generic/regexec.c tcl8.6.4/generic/regexec.c
*** tcl8.6.4.withqbr/generic/regexec.c Fri Sep 18 12:24:14 2015
--- tcl8.6.4/generic/regexec.c Fri Sep 18 17:46:15 2015
*************** struct vars {
*** 107,118 ****
chr *start; /* start of string */
chr *stop; /* just past end of string */
int err; /* error code if any (0 none) */
struct smalldfa dfa1;
struct smalldfa dfa2;
};
#define VISERR(vv) ((vv)->err != 0) /* have we seen an error yet? */
#define ISERR() VISERR(v)
! #define VERR(vv,e) (((vv)->err) ? (vv)->err : ((vv)->err = (e)))
#define ERR(e) VERR(v, e) /* record an error */
#define NOERR() {if (ISERR()) return v->err;} /* if error seen, return it */
#define OFF(p) ((p) - v->start)
--- 107,119 ----
chr *start; /* start of string */
chr *stop; /* just past end of string */
int err; /* error code if any (0 none) */
+ struct dfa **subdfas; /* per-subre DFAs */
struct smalldfa dfa1;
struct smalldfa dfa2;
};
#define VISERR(vv) ((vv)->err != 0) /* have we seen an error yet? */
#define ISERR() VISERR(v)
! #define VERR(vv,e) ((vv)->err = ((vv)->err ? (vv)->err : (e)))
#define ERR(e) VERR(v, e) /* record an error */
#define NOERR() {if (ISERR()) return v->err;} /* if error seen, return it */
#define OFF(p) ((p) - v->start)
*************** struct vars {
*** 125,130 ****
--- 126,132 ----
/* automatically gathered by fwd; do not hand-edit */
/* === regexec.c === */
int exec(regex_t *, const chr *, size_t, rm_detail_t *, size_t, regmatch_t [], int);
+ static struct dfa *getsubdfa(struct vars *, struct subre *);
static int simpleFind(struct vars *const, struct cnfa *const, struct colormap *const);
static int complicatedFind(struct vars *const, struct cnfa *const, struct colormap *const);
static int complicatedFindLoop(struct vars *const, struct cnfa *const, struct colormap *const, struct dfa *const, struct dfa *const, chr **const);
*************** exec(
*** 171,178 ****
--- 173,183 ----
AllocVars(v);
int st, backref;
size_t n;
+ size_t i;
#define LOCALMAT 20
regmatch_t mat[LOCALMAT];
+ #define LOCALDFAS 40
+ struct dfa *subdfas[LOCALDFAS];
/*
* Sanity checks.
*************** exec(
*** 230,235 ****
--- 235,254 ----
v->start = (chr *)string;
v->stop = (chr *)string + len;
v->err = 0;
+ assert(v->g->ntree >= 0);
+ n = (size_t) v->g->ntree;
+ if (n <= LOCALDFAS)
+ v->subdfas = subdfas;
+ else
+ v->subdfas = (struct dfa **) MALLOC(n * sizeof(struct dfa *));
+ if (v->subdfas == NULL) {
+ if (v->pmatch != pmatch && v->pmatch != mat)
+ FREE(v->pmatch);
+ FreeVars(v);
+ return REG_ESPACE;
+ }
+ for (i = 0; i < n; i++)
+ v->subdfas[i] = NULL;
/*
* Do it.
*************** exec(
*** 259,269 ****
--- 278,312 ----
if (v->pmatch != pmatch && v->pmatch != mat) {
FREE(v->pmatch);
}
+ n = (size_t) v->g->ntree;
+ for (i = 0; i < n; i++) {
+ if (v->subdfas[i] != NULL)
+ freeDFA(v->subdfas[i]);
+ }
+ if (v->subdfas != subdfas)
+ FREE(v->subdfas);
FreeVars(v);
return st;
}
/*
+ - getsubdfa - create or re-fetch the DFA for a subre node
+ * We only need to create the DFA once per overall regex execution.
+ * The DFA will be freed by the cleanup step in exec().
+ */
+ static struct dfa *
+ getsubdfa(struct vars * v,
+ struct subre * t)
+ {
+ if (v->subdfas[t->id] == NULL) {
+ v->subdfas[t->id] = newDFA(v, &t->cnfa, &v->g->cmap, DOMALLOC);
+ if (ISERR())
+ return NULL;
+ }
+ return v->subdfas[t->id];
+ }
+
+ /*
- simpleFind - find a match for the main NFA (no-complications case)
^ static int simpleFind(struct vars *, struct cnfa *, struct colormap *);
*/
*************** simpleFind(
*** 327,333 ****
} else {
end = longest(v, d, begin, v->stop, &hitend);
}
! NOERR();
if (hitend && cold == NULL) {
cold = begin;
}
--- 370,379 ----
} else {
end = longest(v, d, begin, v->stop, &hitend);
}
! if (ISERR()) {
! freeDFA(d);
! return v->err;
! }
if (hitend && cold == NULL) {
cold = begin;
}
*************** complicatedFindLoop(
*** 470,475 ****
--- 516,522 ----
}
if (er != REG_NOMATCH) {
ERR(er);
+ *coldp = cold;
return er;
}
if ((shorter) ? end == estop : end == begin) {
*************** cdissect(
*** 636,642 ****
}
/*
! - ccondissect - concatenation subexpression matches (with complications)
^ static int ccondissect(struct vars *, struct subre *, chr *, chr *);
*/
static int /* regexec return code */
--- 683,689 ----
}
/*
! - ccondissect - dissect match for concatenation node
^ static int ccondissect(struct vars *, struct subre *, chr *, chr *);
*/
static int /* regexec return code */
*************** ccondissect(
*** 654,668 ****
assert(t->right != NULL && t->right->cnfa.nstates > 0);
assert(!(t->left->flags & SHORTER));
! d = newDFA(v, &t->left->cnfa, &v->g->cmap, DOMALLOC);
! if (ISERR()) {
! return v->err;
! }
! d2 = newDFA(v, &t->right->cnfa, &v->g->cmap, DOMALLOC);
! if (ISERR()) {
! freeDFA(d);
! return v->err;
! }
MDEBUG(("cConcat %d\n", t->id));
/*
--- 701,711 ----
assert(t->right != NULL && t->right->cnfa.nstates > 0);
assert(!(t->left->flags & SHORTER));
! d = getsubdfa(v, t->left);
! NOERR();
! d2 = getsubdfa(v, t->right);
! NOERR();
!
MDEBUG(("cConcat %d\n", t->id));
/*
*************** ccondissect(
*** 670,677 ****
*/
mid = longest(v, d, begin, end, (int *) NULL);
if (mid == NULL) {
- freeDFA(d);
- freeDFA(d2);
return REG_NOMATCH;
}
MDEBUG(("tentative midpoint %ld\n", LOFF(mid)));
--- 713,718 ----
*************** ccondissect(
*** 696,709 ****
*/
MDEBUG(("successful\n"));
- freeDFA(d);
- freeDFA(d2);
return REG_OKAY;
}
}
if (er != REG_NOMATCH) {
- freeDFA(d);
- freeDFA(d2);
return er;
}
}
--- 737,746 ----
*************** ccondissect(
*** 718,725 ****
*/
MDEBUG(("%d no midpoint\n", t->id));
- freeDFA(d);
- freeDFA(d2);
return REG_NOMATCH;
}
mid = longest(v, d, begin, mid-1, NULL);
--- 755,760 ----
*************** ccondissect(
*** 729,736 ****
*/
MDEBUG(("%d failed midpoint\n", t->id));
- freeDFA(d);
- freeDFA(d2);
return REG_NOMATCH;
}
MDEBUG(("%d: new midpoint %ld\n", t->id, LOFF(mid)));
--- 764,769 ----
*************** crevcondissect(
*** 758,772 ****
assert(t->right != NULL && t->right->cnfa.nstates > 0);
assert(t->left->flags&SHORTER);
! d = newDFA(v, &t->left->cnfa, &v->g->cmap, DOMALLOC);
! if (ISERR()) {
! return v->err;
! }
! d2 = newDFA(v, &t->right->cnfa, &v->g->cmap, DOMALLOC);
! if (ISERR()) {
! freeDFA(d);
! return v->err;
! }
MDEBUG(("crevcon %d\n", t->id));
/*
--- 791,801 ----
assert(t->right != NULL && t->right->cnfa.nstates > 0);
assert(t->left->flags&SHORTER);
! d = getsubdfa(v, t->left);
! NOERR();
! d2 = getsubdfa(v, t->right);
! NOERR();
!
MDEBUG(("crevcon %d\n", t->id));
/*
*************** crevcondissect(
*** 775,782 ****
mid = shortest(v, d, begin, begin, end, (chr **) NULL, (int *) NULL);
if (mid == NULL) {
- freeDFA(d);
- freeDFA(d2);
return REG_NOMATCH;
}
MDEBUG(("tentative midpoint %ld\n", LOFF(mid)));
--- 804,809 ----
*************** crevcondissect(
*** 801,814 ****
*/
MDEBUG(("successful\n"));
- freeDFA(d);
- freeDFA(d2);
return REG_OKAY;
}
}
if (er != REG_NOMATCH) {
- freeDFA(d);
- freeDFA(d2);
return er;
}
}
--- 828,837 ----
*************** crevcondissect(
*** 823,830 ****
*/
MDEBUG(("%d no midpoint\n", t->id));
- freeDFA(d);
- freeDFA(d2);
return REG_NOMATCH;
}
mid = shortest(v, d, begin, mid+1, end, NULL, NULL);
--- 846,851 ----
*************** crevcondissect(
*** 834,841 ****
*/
MDEBUG(("%d failed midpoint\n", t->id));
- freeDFA(d);
- freeDFA(d2);
return REG_NOMATCH;
}
MDEBUG(("%d: new midpoint %ld\n", t->id, LOFF(mid)));
--- 855,860 ----
*************** caltdissect(
*** 943,959 ****
MDEBUG(("calt n%d\n", t->id));
! d = newDFA(v, &t->left->cnfa, &v->g->cmap, DOMALLOC);
NOERR();
if (longest(v, d, begin, end, (int *) NULL) == end) {
- freeDFA(d);
MDEBUG(("calt matched\n"));
er = cdissect(v, t->left, begin, end);
if (er != REG_NOMATCH) {
return er;
}
}
- freeDFA(d);
t = t->right;
}
--- 962,976 ----
MDEBUG(("calt n%d\n", t->id));
! d = getsubdfa(v, t->left);
NOERR();
if (longest(v, d, begin, end, (int *) NULL) == end) {
MDEBUG(("calt matched\n"));
er = cdissect(v, t->left, begin, end);
if (er != REG_NOMATCH) {
return er;
}
}
t = t->right;
}
*************** citerdissect(struct vars * v,
*** 1017,1023 ****
return REG_ESPACE;
endpts[0] = begin;
! d = newDFA(v, &t->left->cnfa, &v->g->cmap, DOMALLOC);
if (ISERR()) {
FREE(endpts);
return v->err;
--- 1034,1040 ----
return REG_ESPACE;
endpts[0] = begin;
! d = getsubdfa(v, t->left);
if (ISERR()) {
FREE(endpts);
return v->err;
*************** citerdissect(struct vars * v,
*** 1094,1100 ****
if (er == REG_NOMATCH)
break;
/* oops, something failed */
- freeDFA(d);
FREE(endpts);
return er;
}
--- 1111,1116 ----
*************** citerdissect(struct vars * v,
*** 1102,1108 ****
if (i > k) {
/* satisfaction */
MDEBUG(("%d successful\n", t->id));
- freeDFA(d);
FREE(endpts);
return REG_OKAY;
}
--- 1118,1123 ----
*************** citerdissect(struct vars * v,
*** 1132,1138 ****
/* all possibilities exhausted */
MDEBUG(("%d failed\n", t->id));
- freeDFA(d);
FREE(endpts);
return REG_NOMATCH;
}
--- 1147,1152 ----
*************** creviterdissect(struct vars * v,
*** 1193,1199 ****
return REG_ESPACE;
endpts[0] = begin;
! d = newDFA(v, &t->left->cnfa, &v->g->cmap, DOMALLOC);
if (ISERR()) {
FREE(endpts);
return v->err;
--- 1207,1213 ----
return REG_ESPACE;
endpts[0] = begin;
! d = getsubdfa(v, t->left);
if (ISERR()) {
FREE(endpts);
return v->err;
*************** creviterdissect(struct vars * v,
*** 1276,1282 ****
if (er == REG_NOMATCH)
break;
/* oops, something failed */
- freeDFA(d);
FREE(endpts);
return er;
}
--- 1290,1295 ----
*************** creviterdissect(struct vars * v,
*** 1284,1290 ****
if (i > k) {
/* satisfaction */
MDEBUG(("%d successful\n", t->id));
- freeDFA(d);
FREE(endpts);
return REG_OKAY;
}
--- 1297,1302 ----
*************** creviterdissect(struct vars * v,
*** 1308,1314 ****
/* all possibilities exhausted */
MDEBUG(("%d failed\n", t->id));
- freeDFA(d);
FREE(endpts);
return REG_NOMATCH;
}
--- 1320,1325 ----
diff -pcdr tcl8.6.4.withqbr/generic/regguts.h tcl8.6.4/generic/regguts.h
*** tcl8.6.4.withqbr/generic/regguts.h Thu Sep 17 18:52:18 2015
--- tcl8.6.4/generic/regguts.h Fri Sep 18 14:49:53 2015
*************** struct colordesc {
*** 186,192 ****
union tree *block; /* block of solid color, if any */
};
! /* the color map itself */
struct colormap {
int magic;
#define CMMAGIC 0x876
--- 186,199 ----
union tree *block; /* block of solid color, if any */
};
! /*
! * The color map itself
! *
! * Much of the data in the colormap struct is only used at compile time.
! * However, the bulk of the space usage is in the "tree" structure, so it's
! * not clear that there's much point in converting the rest to a more compact
! * form when compilation is finished.
! */
struct colormap {
int magic;
#define CMMAGIC 0x876
*************** struct cvec {
*** 242,256 ****
struct state;
struct arc {
! int type;
! #define ARCFREE '\0'
color co;
struct state *from; /* where it's from (and contained within) */
struct state *to; /* where it's to */
! struct arc *outchain; /* *from's outs chain or free chain */
#define freechain outchain
! struct arc *inchain; /* *to's ins chain */
! struct arc *colorchain; /* color's arc chain */
struct arc *colorchainRev; /* back-link in color's arc chain */
};
--- 249,262 ----
struct state;
struct arc {
! int type; /* 0 if free, else an NFA arc type code */
color co;
struct state *from; /* where it's from (and contained within) */
struct state *to; /* where it's to */
! struct arc *outchain; /* link in *from's outs chain or free chain */
#define freechain outchain
! struct arc *inchain; /* link in *to's ins chain */
! struct arc *colorchain; /* link in color's arc chain */
struct arc *colorchainRev; /* back-link in color's arc chain */
};
*************** struct nfa {
*** 297,307 ****
/*
* definitions for compacted NFA
*/
struct carc {
color co; /* COLORLESS is list terminator */
! int to; /* state number */
};
struct cnfa {
--- 303,324 ----
/*
* definitions for compacted NFA
+ *
+ * The main space savings in a compacted NFA is from making the arcs as small
+ * as possible. We store only the transition color and next-state number for
+ * each arc. The list of out arcs for each state is an array beginning at
+ * cnfa.states[statenumber], and terminated by a dummy carc struct with
+ * co == COLORLESS.
+ *
+ * The non-dummy carc structs are of two types: plain arcs and LACON arcs.
+ * Plain arcs just store the transition color number as "co". LACON arcs
+ * store the lookahead constraint number plus cnfa.ncolors as "co". LACON
+ * arcs can be distinguished from plain by testing for co >= cnfa.ncolors.
*/
struct carc {
color co; /* COLORLESS is list terminator */
! int to; /* next-state number */
};
struct cnfa {
*************** struct cnfa {
*** 313,319 ****
--- 330,339 ----
int post; /* teardown state number */
color bos[2]; /* colors, if any, assigned to BOS and BOL */
color eos[2]; /* colors, if any, assigned to EOS and EOL */
+ char *stflags; /* vector of per-state flags bytes */
+ #define CNFA_NOPROGRESS 01 /* flag bit for a no-progress state */
struct carc **states; /* vector of pointers to outarc lists */
+ /* states[n] are pointers into a single malloc'd array of arcs */
struct carc *arcs; /* the area for the lists */
};
#define ZAPCNFA(cnfa) ((cnfa).nstates = 0)
*************** struct subre {
*** 366,372 ****
#define PREF(f) ((f)&NOPROP)
#define PREF2(f1, f2) ((PREF(f1) != 0) ? PREF(f1) : PREF(f2))
#define COMBINE(f1, f2) (UP((f1)|(f2)) | PREF2(f1, f2))
! short id; /* ID of subre (1..ntree) */
int subno; /* subexpression number (for 'b' and '(') */
short min; /* min repetitions for iteration or backref */
short max; /* max repetitions for iteration or backref */
--- 386,392 ----
#define PREF(f) ((f)&NOPROP)
#define PREF2(f1, f2) ((PREF(f1) != 0) ? PREF(f1) : PREF(f2))
#define COMBINE(f1, f2) (UP((f1)|(f2)) | PREF2(f1, f2))
! short id; /* ID of subre (1..ntree-1) */
int subno; /* subexpression number (for 'b' and '(') */
short min; /* min repetitions for iteration or backref */
short max; /* max repetitions for iteration or backref */
*************** struct guts {
*** 399,405 ****
size_t nsub; /* copy of re_nsub */
struct subre *tree;
struct cnfa search; /* for fast preliminary search */
! int ntree;
struct colormap cmap;
int FUNCPTR(compare, (const chr *, const chr *, size_t));
struct subre *lacons; /* lookahead-constraint vector */
--- 419,425 ----
size_t nsub; /* copy of re_nsub */
struct subre *tree;
struct cnfa search; /* for fast preliminary search */
! int ntree; /* number of subre's, plus one */
struct colormap cmap;
int FUNCPTR(compare, (const chr *, const chr *, size_t));
struct subre *lacons; /* lookahead-constraint vector */