/* *forwarddeclarations,upheresoforwarddatatypesetc.aredefinedearly
*/ /* === regcomp.c === */ staticvoid moresubs(struct vars *v, int wanted); staticint freev(struct vars *v, int err); staticvoid makesearch(struct vars *v, struct nfa *nfa); staticstruct subre *parse(struct vars *v, int stopper, int type, struct state *init, struct state *final); staticstruct subre *parsebranch(struct vars *v, int stopper, int type, struct state *left, struct state *right, int partial); staticstruct subre *parseqatom(struct vars *v, int stopper, int type, struct state *lp, struct state *rp, struct subre *top); staticvoid nonword(struct vars *v, int dir, struct state *lp, struct state *rp); staticvoid word(struct vars *v, int dir, struct state *lp, struct state *rp); staticvoid charclass(struct vars *v, enum char_classes cls, struct state *lp, struct state *rp); staticvoid charclasscomplement(struct vars *v, enum char_classes cls, struct state *lp, struct state *rp); staticint scannum(struct vars *v); staticvoid repeat(struct vars *v, struct state *lp, struct state *rp, int m, int n); staticvoid bracket(struct vars *v, struct state *lp, struct state *rp); staticvoid cbracket(struct vars *v, struct state *lp, struct state *rp); staticvoid brackpart(struct vars *v, struct state *lp, struct state *rp, bool *have_cclassc); staticconst chr *scanplain(struct vars *v); staticvoid onechr(struct vars *v, chr c, struct state *lp, struct state *rp); staticvoid optimizebracket(struct vars *v, struct state *lp, struct state *rp); staticvoid wordchrs(struct vars *v); staticvoid processlacon(struct vars *v, struct state *begin, struct state *end, int latype, struct state *lp, struct state *rp); staticstruct subre *subre(struct vars *v, int op, int flags, struct state *begin, struct state *end); staticvoid freesubre(struct vars *v, struct subre *sr); staticvoid freesubreandsiblings(struct vars *v, struct subre *sr); staticvoid freesrnode(struct vars *v, struct subre *sr); staticvoid removecaptures(struct vars *v, struct subre *t); staticint numst(struct subre *t, int start); staticvoid markst(struct subre *t); staticvoid cleanst(struct vars *v); staticlong nfatree(struct vars *v, struct subre *t, FILE *f); staticlong nfanode(struct vars *v, struct subre *t, int converttosearch, FILE *f); staticint newlacon(struct vars *v, struct state *begin, struct state *end, int latype); staticvoid freelacons(struct subre *subs, int n); staticvoid rfree(regex_t *re); staticint rstacktoodeep(void);
#ifdef REG_DEBUG staticvoid dump(regex_t *re, FILE *f); staticvoid dumpst(struct subre *t, FILE *f, int nfapresent); staticvoid stdump(struct subre *t, FILE *f, int nfapresent); staticconstchar *stid(struct subre *t, char *buf, size_t bufsize); #endif /* === regc_lex.c === */ staticvoid lexstart(struct vars *v); staticvoid prefixes(struct vars *v); staticint next(struct vars *v); staticint lexescape(struct vars *v); static chr lexdigits(struct vars *v, int base, int minlen, int maxlen); staticint brenext(struct vars *v, chr c); staticvoid skip(struct vars *v); static chr newline(void); static chr chrnamed(struct vars *v, const chr *startp, const chr *endp,
chr lastresort);
/* === regc_color.c === */ staticvoid initcm(struct vars *v, struct colormap *cm); staticvoid freecm(struct colormap *cm); static color maxcolor(struct colormap *cm); static color newcolor(struct colormap *cm); staticvoid freecolor(struct colormap *cm, color co); static color pseudocolor(struct colormap *cm); static color subcolor(struct colormap *cm, chr c); static color subcolorhi(struct colormap *cm, color *pco); static color newsub(struct colormap *cm, color co); staticint newhicolorrow(struct colormap *cm, int oldrow); staticvoid newhicolorcols(struct colormap *cm); staticvoid subcolorcvec(struct vars *v, struct cvec *cv, struct state *lp, struct state *rp); staticvoid subcoloronechr(struct vars *v, chr ch, struct state *lp, struct state *rp, color *lastsubcolor); staticvoid subcoloronerange(struct vars *v, chr from, chr to, struct state *lp, struct state *rp,
color *lastsubcolor); staticvoid subcoloronerow(struct vars *v, int rownum, struct state *lp, struct state *rp, color *lastsubcolor); staticvoid okcolors(struct nfa *nfa, struct colormap *cm); staticvoid colorchain(struct colormap *cm, struct arc *a); staticvoid uncolorchain(struct colormap *cm, struct arc *a); staticvoid rainbow(struct nfa *nfa, struct colormap *cm, int type, color but, struct state *from, struct state *to); staticvoid colorcomplement(struct nfa *nfa, struct colormap *cm, int type, struct state *of, struct state *from, struct state *to);
#ifdef REG_DEBUG staticvoid dumpcolors(struct colormap *cm, FILE *f); staticvoid dumpchr(chr c, FILE *f); #endif /* === regc_nfa.c === */ staticstruct nfa *newnfa(struct vars *v, struct colormap *cm, struct nfa *parent); staticvoid freenfa(struct nfa *nfa); staticstruct state *newstate(struct nfa *nfa); staticstruct state *newfstate(struct nfa *nfa, int flag); staticvoid dropstate(struct nfa *nfa, struct state *s); staticvoid freestate(struct nfa *nfa, struct state *s); staticvoid newarc(struct nfa *nfa, int t, color co, struct state *from, struct state *to); staticvoid createarc(struct nfa *nfa, int t, color co, struct state *from, struct state *to); staticstruct arc *allocarc(struct nfa *nfa); staticvoid freearc(struct nfa *nfa, struct arc *victim); staticvoid changearcsource(struct arc *a, struct state *newfrom); staticvoid changearctarget(struct arc *a, struct state *newto); staticint hasnonemptyout(struct state *s); staticstruct arc *findarc(struct state *s, int type, color co); staticvoid cparc(struct nfa *nfa, struct arc *oa, struct state *from, struct state *to); staticvoid sortins(struct nfa *nfa, struct state *s); staticint sortins_cmp(constvoid *a, constvoid *b); staticvoid sortouts(struct nfa *nfa, struct state *s); staticint sortouts_cmp(constvoid *a, constvoid *b); staticvoid moveins(struct nfa *nfa, struct state *oldState, struct state *newState); staticvoid copyins(struct nfa *nfa, struct state *oldState, struct state *newState); staticvoid mergeins(struct nfa *nfa, struct state *s, struct arc **arcarray, int arccount); staticvoid moveouts(struct nfa *nfa, struct state *oldState, struct state *newState); staticvoid copyouts(struct nfa *nfa, struct state *oldState, struct state *newState); staticvoid cloneouts(struct nfa *nfa, struct state *old, struct state *from, struct state *to, int type); staticvoid delsub(struct nfa *nfa, struct state *lp, struct state *rp); staticvoid deltraverse(struct nfa *nfa, struct state *leftend, struct state *s); staticvoid dupnfa(struct nfa *nfa, struct state *start, struct state *stop, struct state *from, struct state *to); staticvoid duptraverse(struct nfa *nfa, struct state *s, struct state *stmp); staticvoid removeconstraints(struct nfa *nfa, struct state *start, struct state *stop); staticvoid removetraverse(struct nfa *nfa, struct state *s); staticvoid cleartraverse(struct nfa *nfa, struct state *s); staticstruct state *single_color_transition(struct state *s1, struct state *s2); staticvoid specialcolors(struct nfa *nfa); staticlong optimize(struct nfa *nfa, FILE *f); staticvoid pullback(struct nfa *nfa, FILE *f); staticint pull(struct nfa *nfa, struct arc *con, struct state **intermediates); staticvoid pushfwd(struct nfa *nfa, FILE *f); staticint push(struct nfa *nfa, struct arc *con, struct state **intermediates);
#define INCOMPATIBLE 1/* destroys arc */ #define SATISFIED 2/* constraint satisfied */ #define COMPATIBLE 3/* compatible but not satisfied yet */ #define REPLACEARC 4/* replace arc's color with constraint color */ staticint combine(struct nfa *nfa, struct arc *con, struct arc *a); staticvoid fixempties(struct nfa *nfa, FILE *f); staticstruct state *emptyreachable(struct nfa *nfa, struct state *s, struct state *lastfound, struct arc **inarcsorig); staticint isconstraintarc(struct arc *a); staticint hasconstraintout(struct state *s); staticvoid fixconstraintloops(struct nfa *nfa, FILE *f); staticint findconstraintloop(struct nfa *nfa, struct state *s); staticvoid breakconstraintloop(struct nfa *nfa, struct state *sinitial); staticvoid clonesuccessorstates(struct nfa *nfa, struct state *ssource, struct state *sclone, struct state *spredecessor, struct arc *refarc, char *curdonemap, char *outerdonemap, int nstates); staticvoid removecantmatch(struct nfa *nfa); staticvoid cleanup(struct nfa *nfa); staticvoid markreachable(struct nfa *nfa, struct state *s, struct state *okay, struct state *mark); staticvoid markcanreach(struct nfa *nfa, struct state *s, struct state *okay, struct state *mark); staticlong analyze(struct nfa *nfa); staticvoid checkmatchall(struct nfa *nfa); staticbool checkmatchall_recurse(struct nfa *nfa, struct state *s, bool **haspaths); staticbool check_out_colors_match(struct state *s, color co1, color co2); staticbool check_in_colors_match(struct state *s, color co1, color co2); staticvoid compact(struct nfa *nfa, struct cnfa *cnfa); staticvoid carcsort(struct carc *first, size_t n); staticint carc_cmp(constvoid *a, constvoid *b); staticvoid freecnfa(struct cnfa *cnfa); staticvoid dumpnfa(struct nfa *nfa, FILE *f);
/* === regc_locale.c === */ static chr element(struct vars *v, const chr *startp, const chr *endp); staticstruct cvec *range(struct vars *v, chr a, chr b, int cases); staticint before(chr x, chr y); staticstruct cvec *eclass(struct vars *v, chr c, int cases); staticenum char_classes lookupcclass(struct vars *v, const chr *startp, const chr *endp); staticstruct cvec *cclasscvec(struct vars *v, enum char_classes cclasscode, int cases); staticint cclass_column_index(struct colormap *cm, chr c); staticstruct cvec *allcases(struct vars *v, chr c); staticint cmp(const chr *x, const chr *y, size_t len); staticint casecmp(const chr *x, const chr *y, size_t len);
/* internal variables, bundled for easy passing around */ struct vars
{
regex_t *re; const chr *now; /* scan pointer into string */ const chr *stop; /* end of string */ int err; /* error code (0 if none) */ int cflags; /* copy of compile flags */ int lasttype; /* type of previous token */ int nexttype; /* type of next token */
chr nextvalue; /* value (if any) of next token */ int lexcon; /* lexical context type (see regc_lex.c) */ int nsubexp; /* subexpression count */ struct subre **subs; /* subRE pointer vector */
size_t nsubs; /* length of vector */ struct subre *sub10[10]; /* initial vector, enough for most */ struct nfa *nfa; /* the NFA */ struct colormap *cm; /* character color map */
color nlcolor; /* color of newline */ struct state *wordchrs; /* state in nfa holding word-char outarcs */ 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; /* lookaround-constraint vector */ int nlacons; /* size of lacons[]; note that only slots
* numbered 1 .. nlacons-1 are used */
size_t spaceused; /* approx. space used for compilation */
};
/* parsing macros; most know that `v' is the struct vars pointer */ #define NEXT() (next(v)) /* advance by one token */ #define SEE(t) (v->nexttype == (t)) /* is next token this? */ #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()) return0;} /* 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)
/* token type codes, some also used as NFA arc types */ #define EMPTY 'n'/* no token present */ #define EOS 'e'/* end of string */ #define PLAIN 'p'/* ordinary character */ #define DIGIT 'd'/* digit (in bound) */ #define BACKREF 'b'/* back reference */ #define COLLEL 'I'/* start of [. */ #define ECLASS 'E'/* start of [= */ #define CCLASS 'C'/* start of [: */ #define END 'X'/* end of [. [= [: */ #define CCLASSS 's'/* char class shorthand escape */ #define CCLASSC 'c'/* complement char class shorthand escape */ #define RANGE 'R'/* - within [] which might be range delim. */ #define LACON 'L'/* lookaround constraint subRE */ #define AHEAD 'a'/* color-lookahead arc */ #define BEHIND 'r'/* color-lookbehind arc */ #define WBDRY 'w'/* word boundary constraint */ #define NWBDRY 'W'/* non-word-boundary constraint */ #define CANTMATCH 'x'/* arc that cannot match anything */ #define SBEGIN 'A'/* beginning of string (even if not BOL) */ #define SEND 'Z'/* end of string (even if not EOL) */
/* is an arc colored, and hence should belong to a color chain? */ /* the test on "co" eliminates RAINBOW arcs, which we don't bother to chain */ #define COLORED(a) \
((a)->co >= 0 && \
((a)->type == PLAIN || (a)->type == AHEAD || (a)->type == BEHIND))
/* static function list */ staticconststruct fns functions = {
rfree, /* regfree insides */
rstacktoodeep /* check for stack getting dangerously deep */
};
/* *pg_regcomp-compileregularexpression * *Note:onfailure,noresourcesremainallocated,sopg_regfree() *neednotbeappliedtore.
*/ int
pg_regcomp(regex_t *re, const chr *string,
size_t len, int flags,
Oid collation)
{ struct vars var; struct vars *v = &var; struct guts *g; int i;
size_t j;
/* Prepend .* to pattern if it's a lookbehind LACON */
nfanode(v, lasub, !LATYPE_IS_AHEAD(lasub->latype), debug);
}
CNOERR(); if (v->tree->flags & SHORTER)
NOTE(REG_USHORTEST);
/* build compacted NFAs for tree, lacons, fast search */ #ifdef REG_DEBUG if (debug != NULL)
fprintf(debug, "\n\n\n========= SEARCH ==========\n"); #endif /* can sacrifice main NFA now, so use it as work area */
(DISCARD) optimize(v->nfa, debug);
CNOERR();
makesearch(v, v->nfa);
CNOERR();
compact(v->nfa, &g->search);
CNOERR();
/* n is bounded by the number of states, so no chance of overflow here */ if (v->subs == v->sub10)
{
p = (struct subre **) MALLOC(n * sizeof(struct subre *)); if (p != NULL)
memcpy(VS(p), VS(v->subs),
v->nsubs * sizeof(struct subre *));
} else
p = (struct subre **) REALLOC(v->subs, n * sizeof(struct subre *)); if (p == NULL)
{
ERR(REG_ESPACE); return;
}
v->subs = p; for (p = &v->subs[v->nsubs]; v->nsubs < n; p++, v->nsubs++)
*p = NULL;
assert(v->nsubs == n);
assert((size_t) wanted < v->nsubs);
}
/* *freev-freevarsstruct'ssubstructureswherenecessary * *Optionallydoeserror-numbersetting,andalwaysreturnserrorcode *(ifany),tomakeerror-handlingcodeterser.
*/ staticint
freev(struct vars *v, int err)
{ if (v->re != NULL)
rfree(v->re); if (v->subs != v->sub10)
FREE(v->subs); if (v->nfa != NULL)
freenfa(v->nfa); if (v->tree != NULL)
freesubre(v, v->tree); if (v->treechain != NULL)
cleanst(v); if (v->cv != NULL)
freecvec(v->cv); if (v->cv2 != NULL)
freecvec(v->cv2); if (v->lacons != NULL)
freelacons(v->lacons, v->nlacons);
ERR(err); /* nop if err==0 */
return v->err;
}
/* *makesearch-turnanNFAintoasearchNFA(implicitprependof.*?) *NFAmusthavebeenoptimize()dalready.
*/ staticvoid
makesearch(struct vars *v, struct nfa *nfa)
{ struct arc *a; struct arc *b; struct state *pre = nfa->pre; struct state *s; struct state *s2; struct state *slist;
/* no loops are needed if it's anchored */ for (a = pre->outs; a != NULL; a = a->outchain)
{
assert(a->type == PLAIN); if (a->co != nfa->bos[0] && a->co != nfa->bos[1]) break;
} if (a != NULL)
{ /* add implicit .* in front */
rainbow(nfa, v->cm, PLAIN, COLORLESS, pre, pre);
/* and ^* and \A* too -- not always necessary, but harmless */
newarc(nfa, PLAIN, nfa->bos[0], pre, pre);
newarc(nfa, PLAIN, nfa->bos[1], pre, pre);
/* first, make a list of the states reachable from pre and elsewhere */
slist = NULL; for (a = pre->outs; a != NULL; a = a->outchain)
{
s = a->to; for (b = s->ins; b != NULL; b = b->inchain)
{ if (b->from != pre) break;
}
/* do the splits */ for (s = slist; s != NULL; s = s2)
{
s2 = newstate(nfa);
NOERR();
copyouts(nfa, s, s2);
NOERR(); for (a = s->ins; a != NULL; a = b)
{
b = a->inchain; if (a->from != pre)
{
cparc(nfa, a, a->from, s2);
freearc(nfa, a);
}
}
s2 = (s->tmp != s) ? s->tmp : NULL;
s->tmp = NULL; /* clean up while we're at it */
}
}
/* *parse-parseanRE * *Thisisactuallyjustthetoplevel,whichparsesabunchofbranches *tiedtogetherwith'|'.Ifthere'smorethanone,theyappearinthe *treeasthechildrenofa'|'subre.
*/ staticstruct subre *
parse(struct vars *v, int stopper, /* EOS or ')' */ int type, /* LACON (lookaround subRE) or PLAIN */ struct state *init, /* initial state */ struct state *final) /* final state */
{ struct subre *branches; /* top level */ struct subre *lastbranch; /* latest branch */
assert(stopper == ')' || stopper == EOS);
branches = subre(v, '|', LONGER, init, final);
NOERRN();
lastbranch = NULL; do
{ /* a branch */ struct subre *branch; struct state *left; /* scaffolding for branch */ struct state *right;
if (!SEE(stopper))
{
assert(stopper == ')' && SEE(EOS));
ERR(REG_EPAREN);
}
/* optimize out simple cases */ if (lastbranch == branches->child)
{ /* only one branch */
assert(lastbranch->sibling == NULL);
freesrnode(v, branches);
branches = lastbranch;
} elseif (!MESSY(branches->flags))
{ /* no interesting innards */
freesubreandsiblings(v, branches->child);
branches->child = NULL;
branches->op = '=';
}
return branches;
}
/* *parsebranch-parseonebranchofanRE * *Thismostlymanagesconcatenation,workingcloselywithparseqatom(). *Concatenatedthingsarebundledupasmuchaspossible,withseparate *'.'nodesintroducedonlywhennecessaryduetosubstructure.
*/ staticstruct subre *
parsebranch(struct vars *v, int stopper, /* EOS or ')' */ int type, /* LACON (lookaround subRE) or PLAIN */ struct state *left, /* leftmost state */ struct state *right, /* rightmost state */ int partial) /* is this only part of a branch? */
{ struct state *lp; /* left end of current construct */ int seencontent; /* is there anything in this branch yet? */ struct subre *t;
lp = left;
seencontent = 0;
t = subre(v, '=', 0, left, right); /* op '=' is tentative */
NOERRN(); while (!SEE('|') && !SEE(stopper) && !SEE(EOS))
{ if (seencontent)
{ /* implicit concat operator */
lp = newstate(v->nfa);
NOERRN();
moveins(v->nfa, right, lp);
}
seencontent = 1;
/* NB, recursion in parseqatom() may swallow rest of branch */
t = parseqatom(v, stopper, type, lp, right, t);
NOERRN();
}
if (!seencontent)
{ /* empty branch */ if (!partial)
NOTE(REG_UUNSPEC);
assert(lp == left);
EMPTYARC(left, right);
}
return t;
}
/* *parseqatom-parseonequantifiedatomorconstraintofanRE * *Thebookkeepingneartheendcooperatesverycloselywithparsebranch(); *inparticular,itcontainsarecursionthatcaninvolveparsingtherest *ofthebranch,makingthisfunction'snamesomewhatinaccurate. * *Usually,thereturnvalueisjust"top",butinsomecaseswherewe *haveparsedtherestofthebranch,wemaydeem"top"redundantand *freeit,returningsomechildsubreinstead.
*/ staticstruct subre *
parseqatom(struct vars *v, int stopper, /* EOS or ')' */ int type, /* LACON (lookaround subRE) or PLAIN */ struct state *lp, /* left state to hang it on */ struct state *rp, /* right state to hang it on */ struct subre *top) /* subtree top */
{ struct state *s; /* temporaries for new states */ struct state *s2;
#define ARCV(t, val) newarc(v->nfa, t, val, lp, rp) int m,
n; struct subre *atom; /* atom's subtree */ struct subre *t; int cap; /* capturing parens? */ int latype; /* lookaround constraint type */ int subno; /* capturing-parens or backref number */ int atomtype; int qprefer; /* quantifier short/long preference */ int f; struct subre **atomp; /* where the pointer to atom is */
/* initial bookkeeping */
atom = NULL;
assert(lp->nouts == 0); /* must string new code */
assert(rp->nins == 0); /* between lp and rp */
subno = 0; /* just to shut lint up */
/* an atom or constraint... */
atomtype = v->nexttype; switch (atomtype)
{ /* first, constraints, which end by returning */ case'^':
ARCV('^', 1); if (v->cflags & REG_NLANCH)
ARCV(BEHIND, v->nlcolor);
NEXT(); return top; break; case'$':
ARCV('$', 1); if (v->cflags & REG_NLANCH)
ARCV(AHEAD, v->nlcolor);
NEXT(); return top; break; case SBEGIN:
ARCV('^', 1); /* BOL */
ARCV('^', 0); /* or BOS */
NEXT(); return top; break; case SEND:
ARCV('$', 1); /* EOL */
ARCV('$', 0); /* or EOS */
NEXT(); return top; break; case'<':
wordchrs(v);
s = newstate(v->nfa);
NOERRN();
nonword(v, BEHIND, lp, s);
word(v, AHEAD, s, rp);
NEXT(); return top; break; case'>':
wordchrs(v);
s = newstate(v->nfa);
NOERRN();
word(v, BEHIND, lp, s);
nonword(v, AHEAD, s, rp);
NEXT(); return top; break; case WBDRY:
wordchrs(v);
s = newstate(v->nfa);
NOERRN();
nonword(v, BEHIND, lp, s);
word(v, AHEAD, s, rp);
s = newstate(v->nfa);
NOERRN();
word(v, BEHIND, lp, s);
nonword(v, AHEAD, s, rp);
NEXT(); return top; break; case NWBDRY:
wordchrs(v);
s = newstate(v->nfa);
NOERRN();
word(v, BEHIND, lp, s);
word(v, AHEAD, s, rp);
s = newstate(v->nfa);
NOERRN();
nonword(v, BEHIND, lp, s);
nonword(v, AHEAD, s, rp);
NEXT(); return top; break; case LACON: /* lookaround constraint */
latype = v->nextvalue;
NEXT();
s = newstate(v->nfa);
s2 = newstate(v->nfa);
NOERRN();
t = parse(v, ')', LACON, s, s2);
freesubre(v, t); /* internal structure irrelevant */
NOERRN();
assert(SEE(')'));
NEXT();
processlacon(v, s, s2, latype, lp, rp); return top; break; /* then errors, to get them out of the way */ case'*': case'+': case'?': case'{':
ERR(REG_BADRPT); return top; break; default:
ERR(REG_ASSERT); return top; break; /* then plain characters, and minor variants on that theme */ case')': /* unbalanced paren */ if ((v->cflags & REG_ADVANCED) != REG_EXTENDED)
{
ERR(REG_EPAREN); return top;
} /* legal in EREs due to specification botch */
NOTE(REG_UPBOTCH); /* fall through into case PLAIN */ /* FALLTHROUGH */ case PLAIN:
onechr(v, v->nextvalue, lp, rp);
okcolors(v->nfa, v->cm);
NOERRN();
NEXT(); break; case'[': if (v->nextvalue == 1)
bracket(v, lp, rp); else
cbracket(v, lp, rp);
assert(SEE(']') || ISERR());
NEXT(); break; case CCLASSS:
charclass(v, (enum char_classes) v->nextvalue, lp, rp);
okcolors(v->nfa, v->cm);
NEXT(); break; case CCLASSC:
charclasscomplement(v, (enum char_classes) v->nextvalue, lp, rp); /* charclasscomplement() did okcolors() internally */
NEXT(); break; case'.':
rainbow(v->nfa, v->cm, PLAIN,
(v->cflags & REG_NLSTOP) ? v->nlcolor : COLORLESS,
lp, rp);
NEXT(); break; /* and finally the ugly stuff */ case'(': /* value flags as capturing or non */
cap = (type == LACON) ? 0 : v->nextvalue; if (cap)
{
v->nsubexp++;
subno = v->nsubexp; if ((size_t) subno >= v->nsubs)
moresubs(v, subno);
} else
atomtype = PLAIN; /* something that's not '(' */
NEXT();
/* *Makeseparateendpointstatestokeepthissub-NFAdistinct *fromwhatsurroundsit.Weneedtobesurethatwhenwe *duplicatethesub-NFAforabackref,wegettheright *states/arcsandnoothers.Inparticular,lettingabackref *duplicatethesub-NFAfromlptorpwouldbequitewrong, *becausewemayaddquantificationsuperstructurearoundthis *atombelow.(Perhapswecouldskiptheextrastatesfor *non-capturingparens,butitseemsnotworththetrouble.)
*/
s = newstate(v->nfa);
s2 = newstate(v->nfa);
NOERRN(); /* We may not need these arcs, but keep things connected for now */
EMPTYARC(lp, s);
EMPTYARC(s2, rp);
NOERRN();
atom = parse(v, ')', type, s, s2);
assert(SEE(')') || ISERR());
NEXT();
NOERRN(); if (cap)
{ if (atom->capno == 0)
{ /* normal case: just mark the atom as capturing */
atom->flags |= CAP;
atom->capno = subno;
} else
{ /* generate no-op wrapper node to handle "((x))" */
t = subre(v, '(', atom->flags | CAP, s, s2);
NOERRN();
t->capno = subno;
t->child = atom;
atom = t;
}
assert(v->subs[subno] == NULL);
v->subs[subno] = atom;
} /* postpone everything else pending possible {0} */ break; case BACKREF: /* the Feature From The Black Lagoon */
INSIST(type != LACON, REG_ESUBREG);
subno = v->nextvalue;
assert(subno > 0);
INSIST(subno < v->nsubs, REG_ESUBREG);
NOERRN();
INSIST(v->subs[subno] != NULL, REG_ESUBREG);
NOERRN();
atom = subre(v, 'b', BACKR, lp, rp);
NOERRN();
atom->backno = subno;
v->subs[subno]->flags |= BRUSE;
EMPTYARC(lp, rp); /* temporarily, so there's something */
NEXT(); break;
}
/* ...and an atom may be followed by a quantifier */ switch (v->nexttype)
{ case'*':
m = 0;
n = DUPINF;
qprefer = (v->nextvalue) ? LONGER : SHORTER;
NEXT(); break; case'+':
m = 1;
n = DUPINF;
qprefer = (v->nextvalue) ? LONGER : SHORTER;
NEXT(); break; case'?':
m = 0;
n = 1;
qprefer = (v->nextvalue) ? LONGER : SHORTER;
NEXT(); break; case'{':
NEXT();
m = scannum(v); if (EAT(','))
{ if (SEE(DIGIT))
n = scannum(v); else
n = DUPINF; if (m > n)
{
ERR(REG_BADBR); return top;
} /* {m,n} exercises preference, even if it's {m,m} */
qprefer = (v->nextvalue) ? LONGER : SHORTER;
} else
{
n = m; /* {m} passes operand's preference through */
qprefer = 0;
} if (!SEE('}'))
{ /* catches errors too */
ERR(REG_BADBR); return top;
}
NEXT(); break; default: /* no quantifier */
m = n = 1;
qprefer = 0; break;
}
/* annoying special case: {0} or {0,0} cancels everything */ if (m == 0 && n == 0)
{ /* *Ifwehadcapturingsubexpression(s)withintheatom,wedon'twant *todestroythem,becauseit'slegal(ifuseless)toback-refthem *later.Hence,justunlinktheatomfromlp/rpandthenignoreit.
*/ if (atom != NULL && (atom->flags & CAP))
{
delsub(v->nfa, lp, atom->begin);
delsub(v->nfa, atom->end, rp);
} else
{ /* Otherwise, we can clean up any subre infrastructure we made */ if (atom != NULL)
freesubre(v, atom);
delsub(v->nfa, lp, rp);
}
EMPTYARC(lp, rp); return top;
}
/* if not a messy case, avoid hard part */
assert(!MESSY(top->flags));
f = top->flags | qprefer | ((atom != NULL) ? atom->flags : 0); if (atomtype != '(' && atomtype != BACKREF && !MESSY(UP(f)))
{ if (!(m == 1 && n == 1))
repeat(v, lp, rp, m, n); if (atom != NULL)
freesubre(v, atom);
top->flags = f; return top;
}
/* if it's a backref, now is the time to replicate the subNFA */ if (atomtype == BACKREF)
{
assert(atom->begin->nouts == 1); /* just the EMPTY */
delsub(v->nfa, atom->begin, atom->end);
assert(v->subs[subno] != NULL);
/* The backref node's NFA should not enforce any constraints */
removeconstraints(v->nfa, atom->begin, atom->end);
NOERRN();
}
/* *It'squantifiertime.Iftheatomisjustabackref,we'llletitdeal *withquantifiersinternally.
*/ if (atomtype == BACKREF)
{ /* special case: backrefs have internal quantifiers */
EMPTYARC(s, atom->begin); /* empty prefix */ /* just stuff everything into atom */
repeat(v, atom->begin, atom->end, m, n);
atom->min = (short) m;
atom->max = (short) n;
atom->flags |= COMBINE(qprefer, atom->flags); /* rest of branch can be strung starting from atom->end */
s2 = atom->end;
} elseif (m == 1 && n == 1 &&
(qprefer == 0 ||
(atom->flags & (LONGER | SHORTER | MIXED)) == 0 ||
qprefer == (atom->flags & (LONGER | SHORTER | MIXED))))
{ /* no/vacuous quantifier: done */
EMPTYARC(s, atom->begin); /* empty prefix */ /* rest of branch can be strung starting from atom->end */
s2 = atom->end;
} elseif (!(atom->flags & (CAP | BACKR)))
{ /* *Ifthere'snocapturesnorbackrefsintheatombeingrepeated,we *don'treallycarewherethesubmatchesoftheiterationare,sowe *don'tneedaniterationnode.MakeaplainDFAnodeinstead.
*/
EMPTYARC(s, atom->begin); /* empty prefix */
repeat(v, atom->begin, atom->end, m, n);
f = COMBINE(qprefer, atom->flags);
t = subre(v, '=', f, atom->begin, atom->end);
NOERRN();
freesubre(v, atom);
*atomp = t; /* rest of branch can be strung starting from t->end */
s2 = t->end;
} elseif (m > 0 && !(atom->flags & BACKR))
{ /* *Ifthere'snobackrefsinvolved,wecanturnx{m,n}into *x{m-1,n-1}x,withcapturingparensinonlythesecondx.Thisis *validbecauseweonlycareaboutcapturingmatchesfromthefinal *iterationofthequantifier.It'sawinbecausewecanimplement *thebackref-freeleftsideasaplainDFAnode,sincewedon't *reallycarewhereitssubmatchesare.
*/
dupnfa(v->nfa, atom->begin, atom->end, s, atom->begin);
assert(m >= 1 && m != DUPINF && n >= 1);
repeat(v, s, atom->begin, m - 1, (n == DUPINF) ? n : n - 1);
f = COMBINE(qprefer, atom->flags);
t = subre(v, '.', f, s, atom->end); /* prefix and atom */
NOERRN();
t->child = subre(v, '=', PREF(f), s, atom->begin);
NOERRN();
t->child->sibling = atom;
*atomp = t; /* rest of branch can be strung starting from atom->end */
s2 = atom->end;
} else
{ /* general case: need an iteration node */
s2 = newstate(v->nfa);
NOERRN();
moveouts(v->nfa, atom->end, s2);
NOERRN();
dupnfa(v->nfa, atom->begin, atom->end, s, s2);
repeat(v, s, s2, m, n);
f = COMBINE(qprefer, atom->flags);
t = subre(v, '*', f, s, s2);
NOERRN();
t->min = (short) m;
t->max = (short) n;
t->child = atom;
*atomp = t; /* rest of branch is to be strung from iteration's end state */
}
/* and finally, look after that postponed recursion */
t = top->child->sibling; if (!(SEE('|') || SEE(stopper) || SEE(EOS)))
{ /* parse all the rest of the branch, and insert in t->child->sibling */
t->child->sibling = parsebranch(v, stopper, type, s2, rp, 1);
NOERRN();
assert(SEE('|') || SEE(stopper) || SEE(EOS));
/* here's the promised update of the flags */
t->flags |= COMBINE(t->flags, t->child->sibling->flags);
top->flags |= COMBINE(top->flags, t->flags);
/* neither t nor top could be directly marked for capture as yet */
assert(t->capno == 0);
assert(top->capno == 0);
/* *Again,itcouldbethattop->childisvacuous(ifthemessyatom *wasinfacttheonlythinginthebranch).Inthatcaseweneedno *concatenationatall;justreplacetopwithtop->child->sibling.
*/
assert(top->child->op == '='); if (top->child->begin == top->child->end)
{
assert(!MESSY(top->child->flags));
t = top->child->sibling;
top->child->sibling = NULL;
freesubre(v, top);
top = t;
}
}
return top;
}
/* *nonword-generatearcsfornon-word-characteraheadorbehind
*/ staticvoid
nonword(struct vars *v, int dir, /* AHEAD or BEHIND */ struct state *lp, struct state *rp)
{ int anchor = (dir == AHEAD) ? '$' : '^';
assert(dir == AHEAD || dir == BEHIND);
newarc(v->nfa, anchor, 1, lp, rp);
newarc(v->nfa, anchor, 0, lp, rp);
colorcomplement(v->nfa, v->cm, dir, v->wordchrs, lp, rp); /* (no need for special attention to \n) */
}
/* *word-generatearcsforwordcharacteraheadorbehind
*/ staticvoid
word(struct vars *v, int dir, /* AHEAD or BEHIND */ struct state *lp, struct state *rp)
{
assert(dir == AHEAD || dir == BEHIND);
cloneouts(v->nfa, v->wordchrs, lp, rp, dir); /* (no need for special attention to \n) */
}
/* *charclass-generatearcsforacharacterclass * *Thisisusedforbothatoms(\wandsiblingescapes)andforelements *ofbracketexpressions.Thecallerisresponsibleforcallingokcolors() *attheendofprocessingtheatomorbracket.
*/ staticvoid
charclass(struct vars *v, enum char_classes cls, struct state *lp, struct state *rp)
{ struct cvec *cv;
/* obtain possibly-cached cvec for char class */
NOTE(REG_ULOCALE);
cv = cclasscvec(v, cls, (v->cflags & REG_ICASE));
NOERR();
/* build the arcs; this may cause color splitting */
subcolorcvec(v, cv, lp, rp);
}
/* *charclasscomplement-generatearcsforacomplementedcharacterclass * *Thisisusedforbothatoms(\Wandsiblingescapes)andforelements *ofbracketexpressions.Inbracketexpressions,itisthecaller's *responsibilitythattherenotbeanyopensubcolorswhenthisiscalled.
*/ staticvoid
charclasscomplement(struct vars *v, enum char_classes cls, struct state *lp, struct state *rp)
{ struct state *cstate; struct cvec *cv;
/* make dummy state to hang temporary arcs on */
cstate = newstate(v->nfa);
NOERR();
/* obtain possibly-cached cvec for char class */
NOTE(REG_ULOCALE);
cv = cclasscvec(v, cls, (v->cflags & REG_ICASE));
NOERR();
/* build arcs for char class; this may cause color splitting */
subcolorcvec(v, cv, cstate, cstate);
NOERR();
/* clean up any subcolors in the arc set */
okcolors(v->nfa, v->cm);
NOERR();
/* now build output arcs for the complement of the char class */
colorcomplement(v->nfa, v->cm, PLAIN, cstate, lp, rp);
NOERR();
/* clean up dummy state */
dropstate(v->nfa, cstate);
}
/* *scannum-scananumber
*/ staticint/* value, <= DUPMAX */
scannum(struct vars *v)
{ int n = 0;
while (SEE(DIGIT) && n < DUPMAX)
{
n = n * 10 + v->nextvalue;
NEXT();
} if (SEE(DIGIT) || n > DUPMAX)
{
ERR(REG_BADBR); return0;
} return n;
}
/* *repeat-replicatesubNFAforquantifiers * *Thesub-NFAstrungfromlptorpismodifiedtorepresentmton *repetitionsofitsinitialcontents. * *Theduplicationsequencesusedherearechosencarefullysothatany *pointersstartingoutpointingintothesubexpressionenduppointinginto *thelastoccurrence.(Notethatitmaynotbestrungbetweenthesame *leftandrightendstates,however!)Thisusedtobeimportantforthe *subREtree,althoughtheimportantbitsarenowhandledbythein-line *codeinparse(),andwhenthisiscalled,itdoesn'tmatteranymore.
*/ staticvoid
repeat(struct vars *v, struct state *lp, struct state *rp, int m, int n)
{ #define SOME 2 #define INF 3 #define PAIR(x, y) ((x)*4 + (y)) #define REDUCE(x) ( ((x) == DUPINF) ? INF : (((x) > 1) ? SOME : (x)) ) constint rm = REDUCE(m); constint rn = REDUCE(n); struct state *s; struct state *s2;
switch (PAIR(rm, rn))
{ case PAIR(0, 0): /* empty string */
delsub(v->nfa, lp, rp);
EMPTYARC(lp, rp); break; case PAIR(0, 1): /* do as x| */
EMPTYARC(lp, rp); break; case PAIR(0, SOME): /* do as x{1,n}| */
repeat(v, lp, rp, 1, n);
NOERR();
EMPTYARC(lp, rp); break; case PAIR(0, INF): /* loop x around */
s = newstate(v->nfa);
NOERR();
moveouts(v->nfa, lp, s);
moveins(v->nfa, rp, s);
EMPTYARC(lp, s);
EMPTYARC(s, rp); break; case PAIR(1, 1): /* no action required */ break; case PAIR(1, SOME): /* do as x{0,n-1}x = (x{1,n-1}|)x */
s = newstate(v->nfa);
NOERR();
moveouts(v->nfa, lp, s);
dupnfa(v->nfa, s, rp, lp, s);
NOERR();
repeat(v, lp, s, 1, n - 1);
NOERR();
EMPTYARC(lp, s); break; case PAIR(1, INF): /* add loopback arc */
s = newstate(v->nfa);
s2 = newstate(v->nfa);
NOERR();
moveouts(v->nfa, lp, s);
moveins(v->nfa, rp, s2);
EMPTYARC(lp, s);
EMPTYARC(s2, rp);
EMPTYARC(s2, s); break; case PAIR(SOME, SOME): /* do as x{m-1,n-1}x */
s = newstate(v->nfa);
NOERR();
moveouts(v->nfa, lp, s);
dupnfa(v->nfa, s, rp, lp, s);
NOERR();
repeat(v, lp, s, m - 1, n - 1); break; case PAIR(SOME, INF): /* do as x{m-1,}x */
s = newstate(v->nfa);
NOERR();
moveouts(v->nfa, lp, s);
dupnfa(v->nfa, s, rp, lp, s);
NOERR();
repeat(v, lp, s, m - 1, n); break; default:
ERR(REG_ASSERT); break;
}
}
/* *bracket-handlenon-complementedbracketexpression * *Alsocalledfromcbracketforcomplementedbracketexpressions.
*/ staticvoid
bracket(struct vars *v, struct state *lp, struct state *rp)
{ /* *Wecan'tprocesscomplementedcharclasses(e.g.\W)immediatelywhile *scanningthebracketexpression,elsecolorbookkeepinggetsconfused. *Instead,rememberwhetherwesawanyinhave_cclassc[],andprocess *themattheend.
*/ bool have_cclassc[NUM_CCLASSES]; bool any_cclassc; int i;
/* close up open subcolors from the positive bracket elements */
okcolors(v->nfa, v->cm);
NOERR();
/* now handle any complemented elements */
any_cclassc = false; for (i = 0; i < NUM_CCLASSES; i++)
{ if (have_cclassc[i])
{
charclasscomplement(v, (enum char_classes) i, lp, rp);
NOERR();
any_cclassc = true;
}
}
/* *cbracket-handlecomplementedbracketexpression * *Wedoitbycallingbracket()withdummyendpoints,andthencomplementing *theresult.Thealternativewouldbetoinvokerainbow(),andthendelete *arcsastheb.e.isseen...butthatgetsmessy,andisreallyquite *infeasiblenowthatrainbow()justputsoutoneRAINBOWarc.
*/ staticvoid
cbracket(struct vars *v, struct state *lp, struct state *rp)
{ struct state *left = newstate(v->nfa); struct state *right = newstate(v->nfa);
NOERR();
bracket(v, left, right);
/* in NLSTOP mode, ensure newline is not part of the result set */ if (v->cflags & REG_NLSTOP)
newarc(v->nfa, PLAIN, v->nlcolor, left, right);
NOERR();
assert(lp->nouts == 0); /* all outarcs will be ours */
/* *scanplain-scanPLAINcontentsof[.etc. * *Certainbitsoftrickeryinregc_lex.cknowthatthiscodedoesnottry *tolookpastthefinalbracketofthe[.etc.
*/ staticconst chr * /* just after end of sequence */
scanplain(struct vars *v)
{ const chr *endp;
/* build the arcs; this may cause color splitting */
subcolorcvec(v, cv, cstate, cstate);
NOERR();
/* close new open subcolors to ensure the cache entry is self-contained */
okcolors(v->nfa, v->cm);
NOERR();
/* success! save the cache pointer */
v->wordchrs = cstate;
}
/* *processlacon-generatetheNFArepresentationofaLACON * *Inthegeneralcasethisisjustnewlacon()+newarc(),butsomecases *canbeoptimized.
*/ staticvoid
processlacon(struct vars *v, struct state *begin, /* start of parsed LACON sub-re */ struct state *end, /* end of parsed LACON sub-re */ int latype, struct state *lp, /* left state to hang it on */ struct state *rp) /* right state to hang it on */
{ struct state *s1; int n;
/* *CheckforlookaroundREconsistingofasingleplaincolorarc(orset *ofarcs);thiswouldtypicallybeasimplechrorabracketexpression.
*/
s1 = single_color_transition(begin, end); switch (latype)
{ case LATYPE_AHEAD_POS: /* If lookahead RE is just colorset C, convert to AHEAD(C) */ if (s1 != NULL)
{
cloneouts(v->nfa, s1, lp, rp, AHEAD); return;
} break; case LATYPE_AHEAD_NEG: /* If lookahead RE is just colorset C, convert to AHEAD(^C)|$ */ if (s1 != NULL)
{
colorcomplement(v->nfa, v->cm, AHEAD, s1, lp, rp);
newarc(v->nfa, '$', 1, lp, rp);
newarc(v->nfa, '$', 0, lp, rp); return;
} break; case LATYPE_BEHIND_POS: /* If lookbehind RE is just colorset C, convert to BEHIND(C) */ if (s1 != NULL)
{
cloneouts(v->nfa, s1, lp, rp, BEHIND); return;
} break; case LATYPE_BEHIND_NEG: /* If lookbehind RE is just colorset C, convert to BEHIND(^C)|^ */ if (s1 != NULL)
{
colorcomplement(v->nfa, v->cm, BEHIND, s1, lp, rp);
newarc(v->nfa, '^', 1, lp, rp);
newarc(v->nfa, '^', 0, lp, rp); return;
} break; default:
assert(NOTREACHED);
}
/* General case: we need a LACON subre and arc */
n = newlacon(v, begin, end, latype);
newarc(v->nfa, LACON, n, lp, rp);
}
/* *subre-allocateasubre
*/ staticstruct subre *
subre(struct vars *v, int op, int flags, struct state *begin, struct state *end)
{ struct subre *ret = v->treefree;
/* *freesubre-freeasubREsubtree * *Thisfreeschildnode(s)ofthegivensubREtoo, *butnotitssiblings.
*/ staticvoid
freesubre(struct vars *v, /* might be NULL */ struct subre *sr)
{ if (sr == NULL) return;
if (sr->child != NULL)
freesubreandsiblings(v, sr->child);
freesrnode(v, sr);
}
/* *freesubreandsiblings-freeasubREsubtree * *Thisfreeschildnode(s)ofthegivensubREtoo, *aswellasanyfollowingsiblings.
*/ staticvoid
freesubreandsiblings(struct vars *v, /* might be NULL */ struct subre *sr)
{ while (sr != NULL)
{ struct subre *next = sr->sibling;
freesubre(v, sr);
sr = next;
}
}
/* *freesrnode-freeonenodeinasubREsubtree
*/ staticvoid
freesrnode(struct vars *v, /* might be NULL */ struct subre *sr)
{ if (sr == NULL) return;
if (!NULLCNFA(sr->cnfa))
freecnfa(&sr->cnfa);
sr->flags = 0; /* in particular, not INUSE */
sr->child = sr->sibling = NULL;
sr->begin = sr->end = NULL;
if (v != NULL && v->treechain != NULL)
{ /* we're still parsing, maybe we can reuse the subre */
sr->child = v->treefree;
v->treefree = sr;
} else
FREE(sr);
}
/* Now recurse to children */ for (t2 = t->child; t2 != NULL; t2 = t2->sibling)
{
removecaptures(v, t2); /* Propagate child CAP flag back up, if it's still set */ if (t2->flags & CAP)
t->flags |= CAP;
}
/* *numst-numbertreenodes(assigning"id"indexes)
*/ staticint/* next number */
numst(struct subre *t, int start) /* starting point for subtree numbers */
{ int i; struct subre *t2;
assert(t != NULL);
i = start;
t->id = i++; for (t2 = t->child; t2 != NULL; t2 = t2->sibling)
i = numst(t2, i); return i;
}
for (t = v->treechain; t != NULL; t = next)
{
next = t->chain; if (!(t->flags & INUSE))
FREE(t);
}
v->treechain = NULL;
v->treefree = NULL; /* just on general principles */
}
/* *nfatree-turnasubREsubtreeintoatreeofcompactedNFAs
*/ staticlong/* optimize results from top node */
nfatree(struct vars *v, struct subre *t,
FILE *f) /* for debug output */
{ struct subre *t2;
/* *nfanode-dooneNFAfornfatreeorlacons * *Ifconverttosearchistrue,applymakesearch()totheNFA.
*/ staticlong/* optimize results */
nfanode(struct vars *v, struct subre *t, int converttosearch,
FILE *f) /* for debug output */
{ struct nfa *nfa; long ret = 0;
assert(t->begin != NULL);
#ifdef REG_DEBUG if (f != NULL)
{ char idbuf[50];
fprintf(f, "\n\n\n========= TREE NODE %s ==========\n",
stid(t, idbuf, sizeof(idbuf)));
} #endif
nfa = newnfa(v, v->cm, v->nfa);
NOERRZ();
dupnfa(nfa, t->begin, t->end, nfa->init, nfa->final);
nfa->flags = v->nfa->flags; if (!ISERR())
specialcolors(nfa); if (!ISERR())
ret = optimize(nfa, f); if (converttosearch && !ISERR())
makesearch(v, nfa); if (!ISERR())
compact(nfa, &t->cnfa);
freenfa(nfa); return ret;
}
/* *newlacon-allocatealookaround-constraintsubRE
*/ staticint/* lacon number */
newlacon(struct vars *v, struct state *begin, struct state *end, int latype)
{ 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; /* better use REALLOC_ARRAY here, as struct subre is big */
newlacons = REALLOC_ARRAY(v->lacons, struct subre, n + 1);
} if (newlacons == NULL)
{
ERR(REG_ESPACE); return0;
}
v->lacons = newlacons;
v->nlacons = n + 1;
sub = &v->lacons[n];
sub->begin = begin;
sub->end = end;
sub->latype = latype;
ZAPCNFA(sub->cnfa); return n;
}
/* *freelacons-freelookaround-constraintsubREvector
*/ staticvoid
freelacons(struct subre *subs, int n)
{ struct subre *sub; int i;
assert(n > 0); for (sub = subs + 1, i = n - 1; i > 0; sub++, i--) /* no 0th */ if (!NULLCNFA(sub->cnfa))
freecnfa(&sub->cnfa);
FREE(subs);
}
/* *dumpst-dumpasubREtree
*/ staticvoid
dumpst(struct subre *t,
FILE *f, int nfapresent) /* is the original NFA still around? */
{ if (t == NULL)
fprintf(f, "null tree\n"); else
stdump(t, f, nfapresent);
fflush(f);
}
/* *stdump-recursivegutsofdumpst
*/ staticvoid
stdump(struct subre *t,
FILE *f, int nfapresent) /* is the original NFA still around? */
{ char idbuf[50]; struct subre *t2;
fprintf(f, "%s. `%c'", stid(t, idbuf, sizeof(idbuf)), t->op); if (t->flags & LONGER)
fprintf(f, " longest"); if (t->flags & SHORTER)
fprintf(f, " shortest"); if (t->flags & MIXED)
fprintf(f, " hasmixed"); if (t->flags & CAP)
fprintf(f, " hascapture"); if (t->flags & BACKR)
fprintf(f, " hasbackref"); if (t->flags & BRUSE)
fprintf(f, " isreferenced"); if (!(t->flags & INUSE))
fprintf(f, " UNUSED"); if (t->latype != (char) -1)
fprintf(f, " latype(%d)", t->latype); if (t->capno != 0)
fprintf(f, " capture(%d)", t->capno); if (t->backno != 0)
fprintf(f, " backref(%d)", t->backno); if (t->min != 1 || t->max != 1)
{
fprintf(f, " {%d,", t->min); if (t->max != DUPINF)
fprintf(f, "%d", t->max);
fprintf(f, "}");
} if (nfapresent)
fprintf(f, " %ld-%ld", (long) t->begin->no, (long) t->end->no); if (t->child != NULL)
fprintf(f, " C:%s", stid(t->child, idbuf, sizeof(idbuf))); /* printing second child isn't necessary, but it is often helpful */ if (t->child != NULL && t->child->sibling != NULL)
fprintf(f, " C2:%s", stid(t->child->sibling, idbuf, sizeof(idbuf))); if (t->sibling != NULL)
fprintf(f, " S:%s", stid(t->sibling, idbuf, sizeof(idbuf))); if (!NULLCNFA(t->cnfa))
{
fprintf(f, "\n");
dumpcnfa(&t->cnfa, f);
}
fprintf(f, "\n"); for (t2 = t->child; t2 != NULL; t2 = t2->sibling)
stdump(t2, f, nfapresent);
}
/* *stid-identifyasubtreenodefordumping
*/ staticconstchar * /* points to buf or constant string */
stid(struct subre *t, char *buf,
size_t bufsize)
{ /* big enough for hex int or decimal t->id? */ if (bufsize < sizeof(void *) * 2 + 3 || bufsize < sizeof(t->id) * 3 + 1) return"unable"; if (t->id != 0)
sprintf(buf, "%d", t->id); else
sprintf(buf, "%p", t); return buf;
} #endif/* REG_DEBUG */
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.