rege_dfa.c

Go to the documentation of this file.
00001 /*
00002  * DFA routines
00003  * This file is #included by regexec.c.
00004  *
00005  * Copyright (c) 1998, 1999 Henry Spencer.  All rights reserved.
00006  *
00007  * Development of this software was funded, in part, by Cray Research Inc.,
00008  * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
00009  * Corporation, none of whom are responsible for the results.  The author
00010  * thanks all of them.
00011  *
00012  * Redistribution and use in source and binary forms -- with or without
00013  * modification -- are permitted for any purpose, provided that
00014  * redistributions in source form retain this entire copyright notice and
00015  * indicate the origin and nature of any modifications.
00016  *
00017  * I'd appreciate being given credit for this package in the documentation
00018  * of software which uses it, but that is not a requirement.
00019  *
00020  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
00021  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
00022  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
00023  * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00024  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00025  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
00026  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00027  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00028  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00029  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  *
00031  */
00032 
00033 /*
00034  - longest - longest-preferred matching engine
00035  ^ static chr *longest(struct vars *, struct dfa *, chr *, chr *, int *);
00036  */
00037 static chr *                    /* endpoint, or NULL */
00038 longest(
00039     struct vars *v,             /* used only for debug and exec flags */
00040     struct dfa *d,
00041     chr *start,                 /* where the match should start */
00042     chr *stop,                  /* match must end at or before here */
00043     int *hitstopp)              /* record whether hit v->stop, if non-NULL */
00044 {
00045     chr *cp;
00046     chr *realstop = (stop == v->stop) ? stop : stop + 1;
00047     color co;
00048     struct sset *css;
00049     struct sset *ss;
00050     chr *post;
00051     int i;
00052     struct colormap *cm = d->cm;
00053 
00054     /*
00055      * Initialize.
00056      */
00057 
00058     css = initialize(v, d, start);
00059     cp = start;
00060     if (hitstopp != NULL) {
00061         *hitstopp = 0;
00062     }
00063 
00064     /*
00065      * Startup.
00066      */
00067 
00068     FDEBUG(("+++ startup +++\n"));
00069     if (cp == v->start) {
00070         co = d->cnfa->bos[(v->eflags&REG_NOTBOL) ? 0 : 1];
00071         FDEBUG(("color %ld\n", (long)co));
00072     } else {
00073         co = GETCOLOR(cm, *(cp - 1));
00074         FDEBUG(("char %c, color %ld\n", (char)*(cp-1), (long)co));
00075     }
00076     css = miss(v, d, css, co, cp, start);
00077     if (css == NULL) {
00078         return NULL;
00079     }
00080     css->lastseen = cp;
00081 
00082     /*
00083      * Main loop.
00084      */
00085 
00086     if (v->eflags&REG_FTRACE) {
00087         while (cp < realstop) {
00088             FDEBUG(("+++ at c%d +++\n", css - d->ssets));
00089             co = GETCOLOR(cm, *cp);
00090             FDEBUG(("char %c, color %ld\n", (char)*cp, (long)co));
00091             ss = css->outs[co];
00092             if (ss == NULL) {
00093                 ss = miss(v, d, css, co, cp+1, start);
00094                 if (ss == NULL) {
00095                     break;      /* NOTE BREAK OUT */
00096                 }
00097             }
00098             cp++;
00099             ss->lastseen = cp;
00100             css = ss;
00101         }
00102     } else {
00103         while (cp < realstop) {
00104             co = GETCOLOR(cm, *cp);
00105             ss = css->outs[co];
00106             if (ss == NULL) {
00107                 ss = miss(v, d, css, co, cp+1, start);
00108                 if (ss == NULL) {
00109                     break;      /* NOTE BREAK OUT */
00110                 }
00111             }
00112             cp++;
00113             ss->lastseen = cp;
00114             css = ss;
00115         }
00116     }
00117 
00118     /*
00119      * Shutdown.
00120      */
00121 
00122     FDEBUG(("+++ shutdown at c%d +++\n", css - d->ssets));
00123     if (cp == v->stop && stop == v->stop) {
00124         if (hitstopp != NULL) {
00125             *hitstopp = 1;
00126         }
00127         co = d->cnfa->eos[(v->eflags&REG_NOTEOL) ? 0 : 1];
00128         FDEBUG(("color %ld\n", (long)co));
00129         ss = miss(v, d, css, co, cp, start);
00130 
00131         /*
00132          * Special case: match ended at eol?
00133          */
00134 
00135         if (ss != NULL && (ss->flags&POSTSTATE)) {
00136             return cp;
00137         } else if (ss != NULL) {
00138             ss->lastseen = cp;  /* to be tidy */
00139         }
00140     }
00141 
00142     /*
00143      * Find last match, if any.
00144      */
00145 
00146     post = d->lastpost;
00147     for (ss = d->ssets, i = d->nssused; i > 0; ss++, i--) {
00148         if ((ss->flags&POSTSTATE) && (post != ss->lastseen) &&
00149                 (post == NULL || post < ss->lastseen)) {
00150             post = ss->lastseen;
00151         }
00152     }
00153     if (post != NULL) {         /* found one */
00154         return post - 1;
00155     }
00156 
00157     return NULL;
00158 }
00159 
00160 /*
00161  - shortest - shortest-preferred matching engine
00162  ^ static chr *shortest(struct vars *, struct dfa *, chr *, chr *, chr *,
00163  ^      chr **, int *);
00164  */
00165 static chr *                    /* endpoint, or NULL */
00166 shortest(
00167     struct vars *v,
00168     struct dfa *d,
00169     chr *start,                 /* where the match should start */
00170     chr *min,                   /* match must end at or after here */
00171     chr *max,                   /* match must end at or before here */
00172     chr **coldp,                /* store coldstart pointer here, if nonNULL */
00173     int *hitstopp)              /* record whether hit v->stop, if non-NULL */
00174 {
00175     chr *cp;
00176     chr *realmin = (min == v->stop) ? min : min + 1;
00177     chr *realmax = (max == v->stop) ? max : max + 1;
00178     color co;
00179     struct sset *css;
00180     struct sset *ss;
00181     struct colormap *cm = d->cm;
00182 
00183     /*
00184      * Initialize.
00185      */
00186 
00187     css = initialize(v, d, start);
00188     cp = start;
00189     if (hitstopp != NULL) {
00190         *hitstopp = 0;
00191     }
00192 
00193     /*
00194      * Startup.
00195      */
00196 
00197     FDEBUG(("--- startup ---\n"));
00198     if (cp == v->start) {
00199         co = d->cnfa->bos[(v->eflags&REG_NOTBOL) ? 0 : 1];
00200         FDEBUG(("color %ld\n", (long)co));
00201     } else {
00202         co = GETCOLOR(cm, *(cp - 1));
00203         FDEBUG(("char %c, color %ld\n", (char)*(cp-1), (long)co));
00204     }
00205     css = miss(v, d, css, co, cp, start);
00206     if (css == NULL) {
00207         return NULL;
00208     }
00209     css->lastseen = cp;
00210     ss = css;
00211 
00212     /*
00213      * Main loop.
00214      */
00215 
00216     if (v->eflags&REG_FTRACE) {
00217         while (cp < realmax) {
00218             FDEBUG(("--- at c%d ---\n", css - d->ssets));
00219             co = GETCOLOR(cm, *cp);
00220             FDEBUG(("char %c, color %ld\n", (char)*cp, (long)co));
00221             ss = css->outs[co];
00222             if (ss == NULL) {
00223                 ss = miss(v, d, css, co, cp+1, start);
00224                 if (ss == NULL) {
00225                     break;      /* NOTE BREAK OUT */
00226                 }
00227             }
00228             cp++;
00229             ss->lastseen = cp;
00230             css = ss;
00231             if ((ss->flags&POSTSTATE) && cp >= realmin) {
00232                 break;          /* NOTE BREAK OUT */
00233             }
00234         }
00235     } else {
00236         while (cp < realmax) {
00237             co = GETCOLOR(cm, *cp);
00238             ss = css->outs[co];
00239             if (ss == NULL) {
00240                 ss = miss(v, d, css, co, cp+1, start);
00241                 if (ss == NULL) {
00242                     break;      /* NOTE BREAK OUT */
00243                 }
00244             }
00245             cp++;
00246             ss->lastseen = cp;
00247             css = ss;
00248             if ((ss->flags&POSTSTATE) && cp >= realmin) {
00249                 break;          /* NOTE BREAK OUT */
00250             }
00251         }
00252     }
00253 
00254     if (ss == NULL) {
00255         return NULL;
00256     }
00257 
00258     if (coldp != NULL) {        /* report last no-progress state set, if any */
00259         *coldp = lastcold(v, d);
00260     }
00261 
00262     if ((ss->flags&POSTSTATE) && cp > min) {
00263         assert(cp >= realmin);
00264         cp--;
00265     } else if (cp == v->stop && max == v->stop) {
00266         co = d->cnfa->eos[(v->eflags&REG_NOTEOL) ? 0 : 1];
00267         FDEBUG(("color %ld\n", (long)co));
00268         ss = miss(v, d, css, co, cp, start);
00269 
00270         /*
00271          * Match might have ended at eol.
00272          */
00273 
00274         if ((ss == NULL || !(ss->flags&POSTSTATE)) && hitstopp != NULL) {
00275             *hitstopp = 1;
00276         }
00277     }
00278 
00279     if (ss == NULL || !(ss->flags&POSTSTATE)) {
00280         return NULL;
00281     }
00282 
00283     return cp;
00284 }
00285 
00286 /*
00287  - lastcold - determine last point at which no progress had been made
00288  ^ static chr *lastcold(struct vars *, struct dfa *);
00289  */
00290 static chr *                    /* endpoint, or NULL */
00291 lastcold(
00292     struct vars *v,
00293     struct dfa *d)
00294 {
00295     struct sset *ss;
00296     chr *nopr;
00297     int i;
00298 
00299     nopr = d->lastnopr;
00300     if (nopr == NULL) {
00301         nopr = v->start;
00302     }
00303     for (ss = d->ssets, i = d->nssused; i > 0; ss++, i--) {
00304         if ((ss->flags&NOPROGRESS) && nopr < ss->lastseen) {
00305             nopr = ss->lastseen;
00306         }
00307     }
00308     return nopr;
00309 }
00310 
00311 /*
00312  - newdfa - set up a fresh DFA
00313  ^ static struct dfa *newdfa(struct vars *, struct cnfa *,
00314  ^      struct colormap *, struct smalldfa *);
00315  */
00316 static struct dfa *
00317 newdfa(
00318     struct vars *v,
00319     struct cnfa *cnfa,
00320     struct colormap *cm,
00321     struct smalldfa *small)     /* preallocated space, may be NULL */
00322 {
00323     struct dfa *d;
00324     size_t nss = cnfa->nstates * 2;
00325     int wordsper = (cnfa->nstates + UBITS - 1) / UBITS;
00326     struct smalldfa *smallwas = small;
00327 
00328     assert(cnfa != NULL && cnfa->nstates != 0);
00329 
00330     if (nss <= FEWSTATES && cnfa->ncolors <= FEWCOLORS) {
00331         assert(wordsper == 1);
00332         if (small == NULL) {
00333             small = (struct smalldfa *) MALLOC(sizeof(struct smalldfa));
00334             if (small == NULL) {
00335                 ERR(REG_ESPACE);
00336                 return NULL;
00337             }
00338         }
00339         d = &small->dfa;
00340         d->ssets = small->ssets;
00341         d->statesarea = small->statesarea;
00342         d->work = &d->statesarea[nss];
00343         d->outsarea = small->outsarea;
00344         d->incarea = small->incarea;
00345         d->cptsmalloced = 0;
00346         d->mallocarea = (smallwas == NULL) ? (char *)small : NULL;
00347     } else {
00348         d = (struct dfa *)MALLOC(sizeof(struct dfa));
00349         if (d == NULL) {
00350             ERR(REG_ESPACE);
00351             return NULL;
00352         }
00353         d->ssets = (struct sset *)MALLOC(nss * sizeof(struct sset));
00354         d->statesarea = (unsigned *)
00355                 MALLOC((nss+WORK) * wordsper * sizeof(unsigned));
00356         d->work = &d->statesarea[nss * wordsper];
00357         d->outsarea = (struct sset **)
00358                 MALLOC(nss * cnfa->ncolors * sizeof(struct sset *));
00359         d->incarea = (struct arcp *)
00360                 MALLOC(nss * cnfa->ncolors * sizeof(struct arcp));
00361         d->cptsmalloced = 1;
00362         d->mallocarea = (char *)d;
00363         if (d->ssets == NULL || d->statesarea == NULL ||
00364                 d->outsarea == NULL || d->incarea == NULL) {
00365             freedfa(d);
00366             ERR(REG_ESPACE);
00367             return NULL;
00368         }
00369     }
00370 
00371     d->nssets = (v->eflags&REG_SMALL) ? 7 : nss;
00372     d->nssused = 0;
00373     d->nstates = cnfa->nstates;
00374     d->ncolors = cnfa->ncolors;
00375     d->wordsper = wordsper;
00376     d->cnfa = cnfa;
00377     d->cm = cm;
00378     d->lastpost = NULL;
00379     d->lastnopr = NULL;
00380     d->search = d->ssets;
00381 
00382     /*
00383      * Initialization of sset fields is done as needed.
00384      */
00385 
00386     return d;
00387 }
00388 
00389 /*
00390  - freedfa - free a DFA
00391  ^ static VOID freedfa(struct dfa *);
00392  */
00393 static void
00394 freedfa(
00395     struct dfa *d)
00396 {
00397     if (d->cptsmalloced) {
00398         if (d->ssets != NULL) {
00399             FREE(d->ssets);
00400         }
00401         if (d->statesarea != NULL) {
00402             FREE(d->statesarea);
00403         }
00404         if (d->outsarea != NULL) {
00405             FREE(d->outsarea);
00406         }
00407         if (d->incarea != NULL) {
00408             FREE(d->incarea);
00409         }
00410     }
00411 
00412     if (d->mallocarea != NULL) {
00413         FREE(d->mallocarea);
00414     }
00415 }
00416 
00417 /*
00418  - hash - construct a hash code for a bitvector
00419  * There are probably better ways, but they're more expensive.
00420  ^ static unsigned hash(unsigned *, int);
00421  */
00422 static unsigned
00423 hash(
00424     unsigned *uv,
00425     int n)
00426 {
00427     int i;
00428     unsigned h;
00429 
00430     h = 0;
00431     for (i = 0; i < n; i++) {
00432         h ^= uv[i];
00433     }
00434     return h;
00435 }
00436 
00437 /*
00438  - initialize - hand-craft a cache entry for startup, otherwise get ready
00439  ^ static struct sset *initialize(struct vars *, struct dfa *, chr *);
00440  */
00441 static struct sset *
00442 initialize(
00443     struct vars *v,             /* used only for debug flags */
00444     struct dfa *d,
00445     chr *start)
00446 {
00447     struct sset *ss;
00448     int i;
00449 
00450     /*
00451      * Is previous one still there?
00452      */
00453 
00454     if (d->nssused > 0 && (d->ssets[0].flags&STARTER)) {
00455         ss = &d->ssets[0];
00456     } else {                    /* no, must (re)build it */
00457         ss = getvacant(v, d, start, start);
00458         for (i = 0; i < d->wordsper; i++) {
00459             ss->states[i] = 0;
00460         }
00461         BSET(ss->states, d->cnfa->pre);
00462         ss->hash = HASH(ss->states, d->wordsper);
00463         assert(d->cnfa->pre != d->cnfa->post);
00464         ss->flags = STARTER|LOCKED|NOPROGRESS;
00465 
00466         /*
00467          * lastseen dealt with below
00468          */
00469     }
00470 
00471     for (i = 0; i < d->nssused; i++) {
00472         d->ssets[i].lastseen = NULL;
00473     }
00474     ss->lastseen = start;       /* maybe untrue, but harmless */
00475     d->lastpost = NULL;
00476     d->lastnopr = NULL;
00477     return ss;
00478 }
00479 
00480 /*
00481  - miss - handle a cache miss
00482  ^ static struct sset *miss(struct vars *, struct dfa *, struct sset *,
00483  ^      pcolor, chr *, chr *);
00484  */
00485 static struct sset *            /* NULL if goes to empty set */
00486 miss(
00487     struct vars *v,             /* used only for debug flags */
00488     struct dfa *d,
00489     struct sset *css,
00490     pcolor co,
00491     chr *cp,                    /* next chr */
00492     chr *start)                 /* where the attempt got started */
00493 {
00494     struct cnfa *cnfa = d->cnfa;
00495     int i;
00496     unsigned h;
00497     struct carc *ca;
00498     struct sset *p;
00499     int ispost;
00500     int noprogress;
00501     int gotstate;
00502     int dolacons;
00503     int sawlacons;
00504 
00505     /*
00506      * For convenience, we can be called even if it might not be a miss.
00507      */
00508 
00509     if (css->outs[co] != NULL) {
00510         FDEBUG(("hit\n"));
00511         return css->outs[co];
00512     }
00513     FDEBUG(("miss\n"));
00514 
00515     /*
00516      * First, what set of states would we end up in?
00517      */
00518 
00519     for (i = 0; i < d->wordsper; i++) {
00520         d->work[i] = 0;
00521     }
00522     ispost = 0;
00523     noprogress = 1;
00524     gotstate = 0;
00525     for (i = 0; i < d->nstates; i++) {
00526         if (ISBSET(css->states, i)) {
00527             for (ca = cnfa->states[i]+1; ca->co != COLORLESS; ca++) {
00528                 if (ca->co == co) {
00529                     BSET(d->work, ca->to);
00530                     gotstate = 1;
00531                     if (ca->to == cnfa->post) {
00532                         ispost = 1;
00533                     }
00534                     if (!cnfa->states[ca->to]->co) {
00535                         noprogress = 0;
00536                     }
00537                     FDEBUG(("%d -> %d\n", i, ca->to));
00538                 }
00539             }
00540         }
00541     }
00542     dolacons = (gotstate) ? (cnfa->flags&HASLACONS) : 0;
00543     sawlacons = 0;
00544     while (dolacons) {          /* transitive closure */
00545         dolacons = 0;
00546         for (i = 0; i < d->nstates; i++) {
00547             if (ISBSET(d->work, i)) {
00548                 for (ca = cnfa->states[i]+1; ca->co != COLORLESS; ca++) {
00549                     if (ca->co <= cnfa->ncolors) {
00550                         continue; /* NOTE CONTINUE */
00551                     }
00552                     sawlacons = 1;
00553                     if (ISBSET(d->work, ca->to)) {
00554                         continue; /* NOTE CONTINUE */
00555                     }
00556                     if (!lacon(v, cnfa, cp, ca->co)) {
00557                         continue; /* NOTE CONTINUE */
00558                     }
00559                     BSET(d->work, ca->to);
00560                     dolacons = 1;
00561                     if (ca->to == cnfa->post) {
00562                         ispost = 1;
00563                     }
00564                     if (!cnfa->states[ca->to]->co) {
00565                         noprogress = 0;
00566                     }
00567                     FDEBUG(("%d :> %d\n", i, ca->to));
00568                 }
00569             }
00570         }
00571     }
00572     if (!gotstate) {
00573         return NULL;
00574     }
00575     h = HASH(d->work, d->wordsper);
00576 
00577     /*
00578      * Next, is that in the cache?
00579      */
00580 
00581     for (p = d->ssets, i = d->nssused; i > 0; p++, i--) {
00582          if (HIT(h, d->work, p, d->wordsper)) {
00583              FDEBUG(("cached c%d\n", p - d->ssets));
00584              break;                     /* NOTE BREAK OUT */
00585          }
00586     }
00587     if (i == 0) {               /* nope, need a new cache entry */
00588         p = getvacant(v, d, cp, start);
00589         assert(p != css);
00590         for (i = 0; i < d->wordsper; i++) {
00591             p->states[i] = d->work[i];
00592         }
00593         p->hash = h;
00594         p->flags = (ispost) ? POSTSTATE : 0;
00595         if (noprogress) {
00596             p->flags |= NOPROGRESS;
00597         }
00598 
00599         /*
00600          * lastseen to be dealt with by caller
00601          */
00602     }
00603 
00604     if (!sawlacons) {           /* lookahead conds. always cache miss */
00605         FDEBUG(("c%d[%d]->c%d\n", css - d->ssets, co, p - d->ssets));
00606         css->outs[co] = p;
00607         css->inchain[co] = p->ins;
00608         p->ins.ss = css;
00609         p->ins.co = (color)co;
00610     }
00611     return p;
00612 }
00613 
00614 /*
00615  - lacon - lookahead-constraint checker for miss()
00616  ^ static int lacon(struct vars *, struct cnfa *, chr *, pcolor);
00617  */
00618 static int                      /* predicate:  constraint satisfied? */
00619 lacon(
00620     struct vars *v,
00621     struct cnfa *pcnfa,         /* parent cnfa */
00622     chr *cp,
00623     pcolor co)                  /* "color" of the lookahead constraint */
00624 {
00625     int n;
00626     struct subre *sub;
00627     struct dfa *d;
00628     struct smalldfa sd;
00629     chr *end;
00630 
00631     n = co - pcnfa->ncolors;
00632     assert(n < v->g->nlacons && v->g->lacons != NULL);
00633     FDEBUG(("=== testing lacon %d\n", n));
00634     sub = &v->g->lacons[n];
00635     d = newdfa(v, &sub->cnfa, &v->g->cmap, &sd);
00636     if (d == NULL) {
00637         ERR(REG_ESPACE);
00638         return 0;
00639     }
00640     end = longest(v, d, cp, v->stop, (int *)NULL);
00641     freedfa(d);
00642     FDEBUG(("=== lacon %d match %d\n", n, (end != NULL)));
00643     return (sub->subno) ? (end != NULL) : (end == NULL);
00644 }
00645 
00646 /*
00647  - getvacant - get a vacant state set
00648  * This routine clears out the inarcs and outarcs, but does not otherwise
00649  * clear the innards of the state set -- that's up to the caller.
00650  ^ static struct sset *getvacant(struct vars *, struct dfa *, chr *, chr *);
00651  */
00652 static struct sset *
00653 getvacant(
00654     struct vars *v,             /* used only for debug flags */
00655     struct dfa *d,
00656     chr *cp,
00657     chr *start)
00658 {
00659     int i;
00660     struct sset *ss;
00661     struct sset *p;
00662     struct arcp ap;
00663     struct arcp lastap = {NULL, 0}; /* silence gcc 4 warning */
00664     color co;
00665 
00666     ss = pickss(v, d, cp, start);
00667     assert(!(ss->flags&LOCKED));
00668 
00669     /*
00670      * Clear out its inarcs, including self-referential ones.
00671      */
00672 
00673     ap = ss->ins;
00674     while ((p = ap.ss) != NULL) {
00675         co = ap.co;
00676         FDEBUG(("zapping c%d's %ld outarc\n", p - d->ssets, (long)co));
00677         p->outs[co] = NULL;
00678         ap = p->inchain[co];
00679         p->inchain[co].ss = NULL; /* paranoia */
00680     }
00681     ss->ins.ss = NULL;
00682 
00683     /*
00684      * Take it off the inarc chains of the ssets reached by its outarcs.
00685      */
00686 
00687     for (i = 0; i < d->ncolors; i++) {
00688         p = ss->outs[i];
00689         assert(p != ss);        /* not self-referential */
00690         if (p == NULL) {
00691             continue;           /* NOTE CONTINUE */
00692         }
00693         FDEBUG(("del outarc %d from c%d's in chn\n", i, p - d->ssets));
00694         if (p->ins.ss == ss && p->ins.co == i) {
00695             p->ins = ss->inchain[i];
00696         } else {
00697             assert(p->ins.ss != NULL);
00698             for (ap = p->ins; ap.ss != NULL &&
00699                     !(ap.ss == ss && ap.co == i);
00700                     ap = ap.ss->inchain[ap.co]) {
00701                 lastap = ap;
00702             }
00703             assert(ap.ss != NULL);
00704             lastap.ss->inchain[lastap.co] = ss->inchain[i];
00705         }
00706         ss->outs[i] = NULL;
00707         ss->inchain[i].ss = NULL;
00708     }
00709 
00710     /*
00711      * If ss was a success state, may need to remember location.
00712      */
00713 
00714     if ((ss->flags&POSTSTATE) && ss->lastseen != d->lastpost &&
00715             (d->lastpost == NULL || d->lastpost < ss->lastseen)) {
00716         d->lastpost = ss->lastseen;
00717     }
00718 
00719     /*
00720      * Likewise for a no-progress state.
00721      */
00722 
00723     if ((ss->flags&NOPROGRESS) && ss->lastseen != d->lastnopr &&
00724             (d->lastnopr == NULL || d->lastnopr < ss->lastseen)) {
00725         d->lastnopr = ss->lastseen;
00726     }
00727 
00728     return ss;
00729 }
00730 
00731 /*
00732  - pickss - pick the next stateset to be used
00733  ^ static struct sset *pickss(struct vars *, struct dfa *, chr *, chr *);
00734  */
00735 static struct sset *
00736 pickss(
00737     struct vars *v,             /* used only for debug flags */
00738     struct dfa *d,
00739     chr *cp,
00740     chr *start)
00741 {
00742     int i;
00743     struct sset *ss;
00744     struct sset *end;
00745     chr *ancient;
00746 
00747     /*
00748      * Shortcut for cases where cache isn't full.
00749      */
00750 
00751     if (d->nssused < d->nssets) {
00752         i = d->nssused;
00753         d->nssused++;
00754         ss = &d->ssets[i];
00755         FDEBUG(("new c%d\n", i));
00756 
00757         /*
00758          * Set up innards.
00759          */
00760 
00761         ss->states = &d->statesarea[i * d->wordsper];
00762         ss->flags = 0;
00763         ss->ins.ss = NULL;
00764         ss->ins.co = WHITE;     /* give it some value */
00765         ss->outs = &d->outsarea[i * d->ncolors];
00766         ss->inchain = &d->incarea[i * d->ncolors];
00767         for (i = 0; i < d->ncolors; i++) {
00768             ss->outs[i] = NULL;
00769             ss->inchain[i].ss = NULL;
00770         }
00771         return ss;
00772     }
00773 
00774     /*
00775      * Look for oldest, or old enough anyway.
00776      */
00777 
00778     if (cp - start > d->nssets*2/3) {   /* oldest 33% are expendable */
00779         ancient = cp - d->nssets*2/3;
00780     } else {
00781         ancient = start;
00782     }
00783     for (ss = d->search, end = &d->ssets[d->nssets]; ss < end; ss++) {
00784         if ((ss->lastseen == NULL || ss->lastseen < ancient)
00785                 && !(ss->flags&LOCKED)) {
00786             d->search = ss + 1;
00787             FDEBUG(("replacing c%d\n", ss - d->ssets));
00788             return ss;
00789         }
00790     }
00791     for (ss = d->ssets, end = d->search; ss < end; ss++) {
00792         if ((ss->lastseen == NULL || ss->lastseen < ancient)
00793                 && !(ss->flags&LOCKED)) {
00794             d->search = ss + 1;
00795             FDEBUG(("replacing c%d\n", ss - d->ssets));
00796             return ss;
00797         }
00798     }
00799 
00800     /*
00801      * Nobody's old enough?!? -- something's really wrong.
00802      */
00803 
00804     FDEBUG(("can't find victim to replace!\n"));
00805     assert(NOTREACHED);
00806     ERR(REG_ASSERT);
00807     return d->ssets;
00808 }
00809 
00810 /*
00811  * Local Variables:
00812  * mode: c
00813  * c-basic-offset: 4
00814  * fill-column: 78
00815  * End:
00816  */



Generated on Wed Mar 12 12:18:10 2008 by  doxygen 1.5.1