rege_dfa.cGo 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®_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®_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®_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®_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®_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®_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®_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 1.5.1 |