Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/generic/regc_nfa.c @ 35

Last change on this file since 35 was 25, checked in by landauf, 17 years ago

added tcl to libs

File size: 40.1 KB
Line 
1/*
2 * NFA utilities.
3 * This file is #included by regcomp.c.
4 *
5 * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
6 *
7 * Development of this software was funded, in part, by Cray Research Inc.,
8 * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
9 * Corporation, none of whom are responsible for the results. The author
10 * thanks all of them.
11 *
12 * Redistribution and use in source and binary forms -- with or without
13 * modification -- are permitted for any purpose, provided that
14 * redistributions in source form retain this entire copyright notice and
15 * indicate the origin and nature of any modifications.
16 *
17 * I'd appreciate being given credit for this package in the documentation of
18 * software which uses it, but that is not a requirement.
19 *
20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23 * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * One or two things that technically ought to be in here are actually in
32 * color.c, thanks to some incestuous relationships in the color chains.
33 */
34
35#define NISERR()        VISERR(nfa->v)
36#define NERR(e)         VERR(nfa->v, (e))
37
38/*
39 - newnfa - set up an NFA
40 ^ static struct nfa *newnfa(struct vars *, struct colormap *, struct nfa *);
41 */
42static struct nfa *             /* the NFA, or NULL */
43newnfa(
44    struct vars *v,
45    struct colormap *cm,
46    struct nfa *parent)         /* NULL if primary NFA */
47{
48    struct nfa *nfa;
49
50    nfa = (struct nfa *) MALLOC(sizeof(struct nfa));
51    if (nfa == NULL) {
52        return NULL;
53    }
54
55    nfa->states = NULL;
56    nfa->slast = NULL;
57    nfa->free = NULL;
58    nfa->nstates = 0;
59    nfa->cm = cm;
60    nfa->v = v;
61    nfa->size = 0;
62    nfa->bos[0] = nfa->bos[1] = COLORLESS;
63    nfa->eos[0] = nfa->eos[1] = COLORLESS;
64    nfa->parent = parent;       /* Precedes newfstate so parent is valid. */
65    nfa->post = newfstate(nfa, '@');    /* number 0 */
66    nfa->pre = newfstate(nfa, '>');     /* number 1 */
67
68    nfa->init = newstate(nfa);  /* May become invalid later. */
69    nfa->final = newstate(nfa);
70    if (ISERR()) {
71        freenfa(nfa);
72        return NULL;
73    }
74    rainbow(nfa, nfa->cm, PLAIN, COLORLESS, nfa->pre, nfa->init);
75    newarc(nfa, '^', 1, nfa->pre, nfa->init);
76    newarc(nfa, '^', 0, nfa->pre, nfa->init);
77    rainbow(nfa, nfa->cm, PLAIN, COLORLESS, nfa->final, nfa->post);
78    newarc(nfa, '$', 1, nfa->final, nfa->post);
79    newarc(nfa, '$', 0, nfa->final, nfa->post);
80
81    if (ISERR()) {
82        freenfa(nfa);
83        return NULL;
84    }
85    return nfa;
86}
87
88/*
89 - TooManyStates - checks if the max states exceeds the compile-time value
90 ^ static int TooManyStates(struct nfa *);
91 */
92static int
93TooManyStates(
94    struct nfa *nfa)
95{
96    struct nfa *parent = nfa->parent;
97    size_t sz = nfa->size;
98
99    while (parent != NULL) {
100        sz = parent->size;
101        parent = parent->parent;
102    }
103    if (sz > REG_MAX_STATES) {
104        return 1;
105    }
106    return 0;
107}
108
109/*
110 - IncrementSize - increases the tracked size of the NFA and its parents.
111 ^ static void IncrementSize(struct nfa *);
112 */
113static void
114IncrementSize(
115    struct nfa *nfa)
116{
117    struct nfa *parent = nfa->parent;
118
119    nfa->size++;
120    while (parent != NULL) {
121        parent->size++;
122        parent = parent->parent;
123    }
124}
125
126/*
127 - DecrementSize - increases the tracked size of the NFA and its parents.
128 ^ static void DecrementSize(struct nfa *);
129 */
130static void
131DecrementSize(
132    struct nfa *nfa)
133{
134    struct nfa *parent = nfa->parent;
135
136    nfa->size--;
137    while (parent != NULL) {
138        parent->size--;
139        parent = parent->parent;
140    }
141}
142
143/*
144 - freenfa - free an entire NFA
145 ^ static VOID freenfa(struct nfa *);
146 */
147static void
148freenfa(
149    struct nfa *nfa)
150{
151    struct state *s;
152
153    while ((s = nfa->states) != NULL) {
154        s->nins = s->nouts = 0; /* don't worry about arcs */
155        freestate(nfa, s);
156    }
157    while ((s = nfa->free) != NULL) {
158        nfa->free = s->next;
159        destroystate(nfa, s);
160    }
161
162    nfa->slast = NULL;
163    nfa->nstates = -1;
164    nfa->pre = NULL;
165    nfa->post = NULL;
166    FREE(nfa);
167}
168
169/*
170 - newstate - allocate an NFA state, with zero flag value
171 ^ static struct state *newstate(struct nfa *);
172 */
173static struct state *           /* NULL on error */
174newstate(
175    struct nfa *nfa)
176{
177    struct state *s;
178
179    if (TooManyStates(nfa)) {
180        /* XXX: add specific error for this */
181        NERR(REG_ETOOBIG);
182        return NULL;
183    }
184    if (nfa->free != NULL) {
185        s = nfa->free;
186        nfa->free = s->next;
187    } else {
188        s = (struct state *) MALLOC(sizeof(struct state));
189        if (s == NULL) {
190            NERR(REG_ESPACE);
191            return NULL;
192        }
193        s->oas.next = NULL;
194        s->free = NULL;
195        s->noas = 0;
196    }
197
198    assert(nfa->nstates >= 0);
199    s->no = nfa->nstates++;
200    s->flag = 0;
201    if (nfa->states == NULL) {
202        nfa->states = s;
203    }
204    s->nins = 0;
205    s->ins = NULL;
206    s->nouts = 0;
207    s->outs = NULL;
208    s->tmp = NULL;
209    s->next = NULL;
210    if (nfa->slast != NULL) {
211        assert(nfa->slast->next == NULL);
212        nfa->slast->next = s;
213    }
214    s->prev = nfa->slast;
215    nfa->slast = s;
216
217    /*
218     * Track the current size and the parent size.
219     */
220
221    IncrementSize(nfa);
222    return s;
223}
224
225/*
226 - newfstate - allocate an NFA state with a specified flag value
227 ^ static struct state *newfstate(struct nfa *, int flag);
228 */
229static struct state *           /* NULL on error */
230newfstate(
231    struct nfa *nfa,
232    int flag)
233{
234    struct state *s;
235
236    s = newstate(nfa);
237    if (s != NULL) {
238        s->flag = (char) flag;
239    }
240    return s;
241}
242
243/*
244 - dropstate - delete a state's inarcs and outarcs and free it
245 ^ static VOID dropstate(struct nfa *, struct state *);
246 */
247static void
248dropstate(
249    struct nfa *nfa,
250    struct state *s)
251{
252    struct arc *a;
253
254    while ((a = s->ins) != NULL) {
255        freearc(nfa, a);
256    }
257    while ((a = s->outs) != NULL) {
258        freearc(nfa, a);
259    }
260    freestate(nfa, s);
261}
262
263/*
264 - freestate - free a state, which has no in-arcs or out-arcs
265 ^ static VOID freestate(struct nfa *, struct state *);
266 */
267static void
268freestate(
269    struct nfa *nfa,
270    struct state *s)
271{
272    assert(s != NULL);
273    assert(s->nins == 0 && s->nouts == 0);
274
275    s->no = FREESTATE;
276    s->flag = 0;
277    if (s->next != NULL) {
278        s->next->prev = s->prev;
279    } else {
280        assert(s == nfa->slast);
281        nfa->slast = s->prev;
282    }
283    if (s->prev != NULL) {
284        s->prev->next = s->next;
285    } else {
286        assert(s == nfa->states);
287        nfa->states = s->next;
288    }
289    s->prev = NULL;
290    s->next = nfa->free;        /* don't delete it, put it on the free list */
291    nfa->free = s;
292    DecrementSize(nfa);
293}
294
295/*
296 - destroystate - really get rid of an already-freed state
297 ^ static VOID destroystate(struct nfa *, struct state *);
298 */
299static void
300destroystate(
301    struct nfa *nfa,
302    struct state *s)
303{
304    struct arcbatch *ab;
305    struct arcbatch *abnext;
306
307    assert(s->no == FREESTATE);
308    for (ab=s->oas.next ; ab!=NULL ; ab=abnext) {
309        abnext = ab->next;
310        FREE(ab);
311    }
312    s->ins = NULL;
313    s->outs = NULL;
314    s->next = NULL;
315    FREE(s);
316}
317
318/*
319 - newarc - set up a new arc within an NFA
320 ^ static VOID newarc(struct nfa *, int, pcolor, struct state *,
321 ^      struct state *);
322 */
323static void
324newarc(
325    struct nfa *nfa,
326    int t,
327    pcolor co,
328    struct state *from,
329    struct state *to)
330{
331    struct arc *a;
332
333    assert(from != NULL && to != NULL);
334
335    /*
336     * Check for duplicates.
337     */
338
339    for (a=from->outs ; a!=NULL ; a=a->outchain) {
340        if (a->to == to && a->co == co && a->type == t) {
341            return;
342        }
343    }
344
345    a = allocarc(nfa, from);
346    if (NISERR()) {
347        return;
348    }
349    assert(a != NULL);
350
351    a->type = t;
352    a->co = (color) co;
353    a->to = to;
354    a->from = from;
355
356    /*
357     * Put the new arc on the beginning, not the end, of the chains. Not only
358     * is this easier, it has the very useful side effect that deleting the
359     * most-recently-added arc is the cheapest case rather than the most
360     * expensive one.
361     */
362
363    a->inchain = to->ins;
364    to->ins = a;
365    a->outchain = from->outs;
366    from->outs = a;
367
368    from->nouts++;
369    to->nins++;
370
371    if (COLORED(a) && nfa->parent == NULL) {
372        colorchain(nfa->cm, a);
373    }
374}
375
376/*
377 - allocarc - allocate a new out-arc within a state
378 ^ static struct arc *allocarc(struct nfa *, struct state *);
379 */
380static struct arc *             /* NULL for failure */
381allocarc(
382    struct nfa *nfa,
383    struct state *s)
384{
385    struct arc *a;
386
387    /*
388     * Shortcut
389     */
390
391    if (s->free == NULL && s->noas < ABSIZE) {
392        a = &s->oas.a[s->noas];
393        s->noas++;
394        return a;
395    }
396
397    /*
398     * if none at hand, get more
399     */
400
401    if (s->free == NULL) {
402        struct arcbatch *newAb = (struct arcbatch *)
403                MALLOC(sizeof(struct arcbatch));
404        int i;
405
406        if (newAb == NULL) {
407            NERR(REG_ESPACE);
408            return NULL;
409        }
410        newAb->next = s->oas.next;
411        s->oas.next = newAb;
412
413        for (i=0 ; i<ABSIZE ; i++) {
414            newAb->a[i].type = 0;
415            newAb->a[i].freechain = &newAb->a[i+1];
416        }
417        newAb->a[ABSIZE-1].freechain = NULL;
418        s->free = &newAb->a[0];
419    }
420    assert(s->free != NULL);
421
422    a = s->free;
423    s->free = a->freechain;
424    return a;
425}
426
427/*
428 - freearc - free an arc
429 ^ static VOID freearc(struct nfa *, struct arc *);
430 */
431static void
432freearc(
433    struct nfa *nfa,
434    struct arc *victim)
435{
436    struct state *from = victim->from;
437    struct state *to = victim->to;
438    struct arc *a;
439
440    assert(victim->type != 0);
441
442    /*
443     * Take it off color chain if necessary.
444     */
445
446    if (COLORED(victim) && nfa->parent == NULL) {
447        uncolorchain(nfa->cm, victim);
448    }
449
450    /*
451     * Take it off source's out-chain.
452     */
453
454    assert(from != NULL);
455    assert(from->outs != NULL);
456    a = from->outs;
457    if (a == victim) {          /* simple case: first in chain */
458        from->outs = victim->outchain;
459    } else {
460        for (; a!=NULL && a->outchain!=victim ; a=a->outchain) {
461            continue;
462        }
463        assert(a != NULL);
464        a->outchain = victim->outchain;
465    }
466    from->nouts--;
467
468    /*
469     * Take it off target's in-chain.
470     */
471
472    assert(to != NULL);
473    assert(to->ins != NULL);
474    a = to->ins;
475    if (a == victim) {          /* simple case: first in chain */
476        to->ins = victim->inchain;
477    } else {
478        for (; a->inchain!=victim ; a=a->inchain) {
479            assert(a->inchain != NULL);
480            continue;
481        }
482        a->inchain = victim->inchain;
483    }
484    to->nins--;
485
486    /*
487     * Clean up and place on free list.
488     */
489
490    victim->type = 0;
491    victim->from = NULL;        /* precautions... */
492    victim->to = NULL;
493    victim->inchain = NULL;
494    victim->outchain = NULL;
495    victim->freechain = from->free;
496    from->free = victim;
497}
498
499/*
500 - findarc - find arc, if any, from given source with given type and color
501 * If there is more than one such arc, the result is random.
502 ^ static struct arc *findarc(struct state *, int, pcolor);
503 */
504static struct arc *
505findarc(
506    struct state *s,
507    int type,
508    pcolor co)
509{
510    struct arc *a;
511
512    for (a=s->outs ; a!=NULL ; a=a->outchain) {
513        if (a->type == type && a->co == co) {
514            return a;
515        }
516    }
517    return NULL;
518}
519
520/*
521 - cparc - allocate a new arc within an NFA, copying details from old one
522 ^ static VOID cparc(struct nfa *, struct arc *, struct state *,
523 ^      struct state *);
524 */
525static void
526cparc(
527    struct nfa *nfa,
528    struct arc *oa,
529    struct state *from,
530    struct state *to)
531{
532    newarc(nfa, oa->type, oa->co, from, to);
533}
534
535/*
536 - moveins - move all in arcs of a state to another state
537 * You might think this could be done better by just updating the
538 * existing arcs, and you would be right if it weren't for the desire
539 * for duplicate suppression, which makes it easier to just make new
540 * ones to exploit the suppression built into newarc.
541 ^ static VOID moveins(struct nfa *, struct state *, struct state *);
542 */
543static void
544moveins(
545    struct nfa *nfa,
546    struct state *oldState,
547    struct state *newState)
548{
549    struct arc *a;
550
551    assert(oldState != newState);
552
553    while ((a = oldState->ins) != NULL) {
554        cparc(nfa, a, a->from, newState);
555        freearc(nfa, a);
556    }
557    assert(oldState->nins == 0);
558    assert(oldState->ins == NULL);
559}
560
561/*
562 - copyins - copy all in arcs of a state to another state
563 ^ static VOID copyins(struct nfa *, struct state *, struct state *);
564 */
565static void
566copyins(
567    struct nfa *nfa,
568    struct state *oldState,
569    struct state *newState)
570{
571    struct arc *a;
572
573    assert(oldState != newState);
574
575    for (a=oldState->ins ; a!=NULL ; a=a->inchain) {
576        cparc(nfa, a, a->from, newState);
577    }
578}
579
580/*
581 - moveouts - move all out arcs of a state to another state
582 ^ static VOID moveouts(struct nfa *, struct state *, struct state *);
583 */
584static void
585moveouts(
586    struct nfa *nfa,
587    struct state *oldState,
588    struct state *newState)
589{
590    struct arc *a;
591
592    assert(oldState != newState);
593
594    while ((a = oldState->outs) != NULL) {
595        cparc(nfa, a, newState, a->to);
596        freearc(nfa, a);
597    }
598}
599
600/*
601 - copyouts - copy all out arcs of a state to another state
602 ^ static VOID copyouts(struct nfa *, struct state *, struct state *);
603 */
604static void
605copyouts(
606    struct nfa *nfa,
607    struct state *oldState,
608    struct state *newState)
609{
610    struct arc *a;
611
612    assert(oldState != newState);
613
614    for (a=oldState->outs ; a!=NULL ; a=a->outchain) {
615        cparc(nfa, a, newState, a->to);
616    }
617}
618
619/*
620 - cloneouts - copy out arcs of a state to another state pair, modifying type
621 ^ static VOID cloneouts(struct nfa *, struct state *, struct state *,
622 ^      struct state *, int);
623 */
624static void
625cloneouts(
626    struct nfa *nfa,
627    struct state *old,
628    struct state *from,
629    struct state *to,
630    int type)
631{
632    struct arc *a;
633
634    assert(old != from);
635
636    for (a=old->outs ; a!=NULL ; a=a->outchain) {
637        newarc(nfa, type, a->co, from, to);
638    }
639}
640
641/*
642 - delsub - delete a sub-NFA, updating subre pointers if necessary
643 * This uses a recursive traversal of the sub-NFA, marking already-seen
644 * states using their tmp pointer.
645 ^ static VOID delsub(struct nfa *, struct state *, struct state *);
646 */
647static void
648delsub(
649    struct nfa *nfa,
650    struct state *lp,           /* the sub-NFA goes from here... */
651    struct state *rp)           /* ...to here, *not* inclusive */
652{
653    assert(lp != rp);
654
655    rp->tmp = rp;               /* mark end */
656
657    deltraverse(nfa, lp, lp);
658    assert(lp->nouts == 0 && rp->nins == 0);    /* did the job */
659    assert(lp->no != FREESTATE && rp->no != FREESTATE); /* no more */
660
661    rp->tmp = NULL;             /* unmark end */
662    lp->tmp = NULL;             /* and begin, marked by deltraverse */
663}
664
665/*
666 - deltraverse - the recursive heart of delsub
667 * This routine's basic job is to destroy all out-arcs of the state.
668 ^ static VOID deltraverse(struct nfa *, struct state *, struct state *);
669 */
670static void
671deltraverse(
672    struct nfa *nfa,
673    struct state *leftend,
674    struct state *s)
675{
676    struct arc *a;
677    struct state *to;
678
679    if (s->nouts == 0) {
680        return;                 /* nothing to do */
681    }
682    if (s->tmp != NULL) {
683        return;                 /* already in progress */
684    }
685
686    s->tmp = s;                 /* mark as in progress */
687
688    while ((a = s->outs) != NULL) {
689        to = a->to;
690        deltraverse(nfa, leftend, to);
691        assert(to->nouts == 0 || to->tmp != NULL);
692        freearc(nfa, a);
693        if (to->nins == 0 && to->tmp == NULL) {
694            assert(to->nouts == 0);
695            freestate(nfa, to);
696        }
697    }
698
699    assert(s->no != FREESTATE); /* we're still here */
700    assert(s == leftend || s->nins != 0);       /* and still reachable */
701    assert(s->nouts == 0);      /* but have no outarcs */
702
703    s->tmp = NULL;              /* we're done here */
704}
705
706/*
707 - dupnfa - duplicate sub-NFA
708 * Another recursive traversal, this time using tmp to point to duplicates as
709 * well as mark already-seen states. (You knew there was a reason why it's a
710 * state pointer, didn't you? :-))
711 ^ static VOID dupnfa(struct nfa *, struct state *, struct state *,
712 ^      struct state *, struct state *);
713 */
714static void
715dupnfa(
716    struct nfa *nfa,
717    struct state *start,        /* duplicate of subNFA starting here */
718    struct state *stop,         /* and stopping here */
719    struct state *from,         /* stringing duplicate from here */
720    struct state *to)           /* to here */
721{
722    if (start == stop) {
723        newarc(nfa, EMPTY, 0, from, to);
724        return;
725    }
726
727    stop->tmp = to;
728    duptraverse(nfa, start, from);
729    /* done, except for clearing out the tmp pointers */
730
731    stop->tmp = NULL;
732    cleartraverse(nfa, start);
733}
734
735/*
736 - duptraverse - recursive heart of dupnfa
737 ^ static VOID duptraverse(struct nfa *, struct state *, struct state *);
738 */
739static void
740duptraverse(
741    struct nfa *nfa,
742    struct state *s,
743    struct state *stmp)         /* s's duplicate, or NULL */
744{
745    struct arc *a;
746
747    if (s->tmp != NULL) {
748        return;                 /* already done */
749    }
750
751    s->tmp = (stmp == NULL) ? newstate(nfa) : stmp;
752    if (s->tmp == NULL) {
753        assert(NISERR());
754        return;
755    }
756
757    for (a=s->outs ; a!=NULL && !NISERR() ; a=a->outchain) {
758        duptraverse(nfa, a->to, NULL);
759        if (NISERR()) {
760            break;
761        }
762        assert(a->to->tmp != NULL);
763        cparc(nfa, a, s->tmp, a->to->tmp);
764    }
765}
766
767/*
768 - cleartraverse - recursive cleanup for algorithms that leave tmp ptrs set
769 ^ static VOID cleartraverse(struct nfa *, struct state *);
770 */
771static void
772cleartraverse(
773    struct nfa *nfa,
774    struct state *s)
775{
776    struct arc *a;
777
778    if (s->tmp == NULL) {
779        return;
780    }
781    s->tmp = NULL;
782
783    for (a=s->outs ; a!=NULL ; a=a->outchain) {
784        cleartraverse(nfa, a->to);
785    }
786}
787
788/*
789 - specialcolors - fill in special colors for an NFA
790 ^ static VOID specialcolors(struct nfa *);
791 */
792static void
793specialcolors(
794    struct nfa *nfa)
795{
796    /*
797     * False colors for BOS, BOL, EOS, EOL
798     */
799
800    if (nfa->parent == NULL) {
801        nfa->bos[0] = pseudocolor(nfa->cm);
802        nfa->bos[1] = pseudocolor(nfa->cm);
803        nfa->eos[0] = pseudocolor(nfa->cm);
804        nfa->eos[1] = pseudocolor(nfa->cm);
805    } else {
806        assert(nfa->parent->bos[0] != COLORLESS);
807        nfa->bos[0] = nfa->parent->bos[0];
808        assert(nfa->parent->bos[1] != COLORLESS);
809        nfa->bos[1] = nfa->parent->bos[1];
810        assert(nfa->parent->eos[0] != COLORLESS);
811        nfa->eos[0] = nfa->parent->eos[0];
812        assert(nfa->parent->eos[1] != COLORLESS);
813        nfa->eos[1] = nfa->parent->eos[1];
814    }
815}
816
817/*
818 - optimize - optimize an NFA
819 ^ static long optimize(struct nfa *, FILE *);
820 */
821static long                     /* re_info bits */
822optimize(
823    struct nfa *nfa,
824    FILE *f)                    /* for debug output; NULL none */
825{
826    int verbose = (f != NULL) ? 1 : 0;
827
828    if (verbose) {
829        fprintf(f, "\ninitial cleanup:\n");
830    }
831    cleanup(nfa);               /* may simplify situation */
832    if (verbose) {
833        dumpnfa(nfa, f);
834    }
835    if (verbose) {
836        fprintf(f, "\nempties:\n");
837    }
838    fixempties(nfa, f);         /* get rid of EMPTY arcs */
839    if (verbose) {
840        fprintf(f, "\nconstraints:\n");
841    }
842    pullback(nfa, f);           /* pull back constraints backward */
843    pushfwd(nfa, f);            /* push fwd constraints forward */
844    if (verbose) {
845        fprintf(f, "\nfinal cleanup:\n");
846    }
847    cleanup(nfa);               /* final tidying */
848    return analyze(nfa);        /* and analysis */
849}
850
851/*
852 - pullback - pull back constraints backward to (with luck) eliminate them
853 ^ static VOID pullback(struct nfa *, FILE *);
854 */
855static void
856pullback(
857    struct nfa *nfa,
858    FILE *f)                    /* for debug output; NULL none */
859{
860    struct state *s;
861    struct state *nexts;
862    struct arc *a;
863    struct arc *nexta;
864    int progress;
865
866    /*
867     * Find and pull until there are no more.
868     */
869
870    do {
871        progress = 0;
872        for (s=nfa->states ; s!=NULL && !NISERR() ; s=nexts) {
873            nexts = s->next;
874            for (a=s->outs ; a!=NULL && !NISERR() ; a=nexta) {
875                nexta = a->outchain;
876                if (a->type == '^' || a->type == BEHIND) {
877                    if (pull(nfa, a)) {
878                        progress = 1;
879                    }
880                }
881                assert(nexta == NULL || s->no != FREESTATE);
882            }
883        }
884        if (progress && f != NULL) {
885            dumpnfa(nfa, f);
886        }
887    } while (progress && !NISERR());
888    if (NISERR()) {
889        return;
890    }
891
892    for (a=nfa->pre->outs ; a!=NULL ; a=nexta) {
893        nexta = a->outchain;
894        if (a->type == '^') {
895            assert(a->co == 0 || a->co == 1);
896            newarc(nfa, PLAIN, nfa->bos[a->co], a->from, a->to);
897            freearc(nfa, a);
898        }
899    }
900}
901
902/*
903 - pull - pull a back constraint backward past its source state
904 * A significant property of this function is that it deletes at most
905 * one state -- the constraint's from state -- and only if the constraint
906 * was that state's last outarc.
907 ^ static int pull(struct nfa *, struct arc *);
908 */
909static int                      /* 0 couldn't, 1 could */
910pull(
911    struct nfa *nfa,
912    struct arc *con)
913{
914    struct state *from = con->from;
915    struct state *to = con->to;
916    struct arc *a;
917    struct arc *nexta;
918    struct state *s;
919
920    if (from == to) {           /* circular constraint is pointless */
921        freearc(nfa, con);
922        return 1;
923    }
924    if (from->flag) {           /* can't pull back beyond start */
925        return 0;
926    }
927    if (from->nins == 0) {      /* unreachable */
928        freearc(nfa, con);
929        return 1;
930    }
931
932    /*
933     * DGP 2007-11-15: Cloning a state with a circular constraint on its list
934     * of outs can lead to trouble [Bug 1810038], so get rid of them first.
935     */
936
937    for (a = from->outs; a != NULL; a = nexta) {
938        nexta = a->outchain;
939        switch (a->type) {
940        case '^':
941        case '$':
942        case BEHIND:
943        case AHEAD:
944            if (from == a->to) {
945                freearc(nfa, a);
946            }
947            break;
948        }
949    }
950
951    /*
952     * First, clone from state if necessary to avoid other outarcs.
953     */
954
955    if (from->nouts > 1) {
956        s = newstate(nfa);
957        if (NISERR()) {
958            return 0;
959        }
960        assert(to != from);     /* con is not an inarc */
961        copyins(nfa, from, s);  /* duplicate inarcs */
962        cparc(nfa, con, s, to); /* move constraint arc */
963        freearc(nfa, con);
964        from = s;
965        con = from->outs;
966    }
967    assert(from->nouts == 1);
968
969    /*
970     * Propagate the constraint into the from state's inarcs.
971     */
972
973    for (a=from->ins ; a!=NULL ; a=nexta) {
974        nexta = a->inchain;
975        switch (combine(con, a)) {
976        case INCOMPATIBLE:      /* destroy the arc */
977            freearc(nfa, a);
978            break;
979        case SATISFIED:         /* no action needed */
980            break;
981        case COMPATIBLE:        /* swap the two arcs, more or less */
982            s = newstate(nfa);
983            if (NISERR()) {
984                return 0;
985            }
986            cparc(nfa, a, s, to);       /* anticipate move */
987            cparc(nfa, con, a->from, s);
988            if (NISERR()) {
989                return 0;
990            }
991            freearc(nfa, a);
992            break;
993        default:
994            assert(NOTREACHED);
995            break;
996        }
997    }
998
999    /*
1000     * Remaining inarcs, if any, incorporate the constraint.
1001     */
1002
1003    moveins(nfa, from, to);
1004    dropstate(nfa, from);       /* will free the constraint */
1005    return 1;
1006}
1007
1008/*
1009 - pushfwd - push forward constraints forward to (with luck) eliminate them
1010 ^ static VOID pushfwd(struct nfa *, FILE *);
1011 */
1012static void
1013pushfwd(
1014    struct nfa *nfa,
1015    FILE *f)                    /* for debug output; NULL none */
1016{
1017    struct state *s;
1018    struct state *nexts;
1019    struct arc *a;
1020    struct arc *nexta;
1021    int progress;
1022
1023    /*
1024     * Find and push until there are no more.
1025     */
1026
1027    do {
1028        progress = 0;
1029        for (s=nfa->states ; s!=NULL && !NISERR() ; s=nexts) {
1030            nexts = s->next;
1031            for (a = s->ins; a != NULL && !NISERR(); a = nexta) {
1032                nexta = a->inchain;
1033                if (a->type == '$' || a->type == AHEAD) {
1034                    if (push(nfa, a)) {
1035                        progress = 1;
1036                    }
1037                }
1038                assert(nexta == NULL || s->no != FREESTATE);
1039            }
1040        }
1041        if (progress && f != NULL) {
1042            dumpnfa(nfa, f);
1043        }
1044    } while (progress && !NISERR());
1045    if (NISERR()) {
1046        return;
1047    }
1048
1049    for (a = nfa->post->ins; a != NULL; a = nexta) {
1050        nexta = a->inchain;
1051        if (a->type == '$') {
1052            assert(a->co == 0 || a->co == 1);
1053            newarc(nfa, PLAIN, nfa->eos[a->co], a->from, a->to);
1054            freearc(nfa, a);
1055        }
1056    }
1057}
1058
1059/*
1060 - push - push a forward constraint forward past its destination state
1061 * A significant property of this function is that it deletes at most
1062 * one state -- the constraint's to state -- and only if the constraint
1063 * was that state's last inarc.
1064 ^ static int push(struct nfa *, struct arc *);
1065 */
1066static int                      /* 0 couldn't, 1 could */
1067push(
1068    struct nfa *nfa,
1069    struct arc *con)
1070{
1071    struct state *from = con->from;
1072    struct state *to = con->to;
1073    struct arc *a;
1074    struct arc *nexta;
1075    struct state *s;
1076
1077    if (to == from) {           /* circular constraint is pointless */
1078        freearc(nfa, con);
1079        return 1;
1080    }
1081    if (to->flag) {             /* can't push forward beyond end */
1082        return 0;
1083    }
1084    if (to->nouts == 0) {       /* dead end */
1085        freearc(nfa, con);
1086        return 1;
1087    }
1088
1089    /*
1090     * DGP 2007-11-15: Here we duplicate the same protections as appear
1091     * in pull() above to avoid troubles with cloning a state with a
1092     * circular constraint on its list of ins.  It is not clear whether
1093     * this is necessary, or is protecting against a "can't happen".
1094     * Any test case that actually leads to a freearc() call here would
1095     * be a welcome addition to the test suite.
1096     */
1097
1098    for (a = to->ins; a != NULL; a = nexta) {
1099        nexta = a->inchain;
1100        switch (a->type) {
1101        case '^':
1102        case '$':
1103        case BEHIND:
1104        case AHEAD:
1105            if (a->from == to) {
1106                freearc(nfa, a);
1107            }
1108            break;
1109        }
1110    }
1111    /*
1112     * First, clone to state if necessary to avoid other inarcs.
1113     */
1114
1115    if (to->nins > 1) {
1116        s = newstate(nfa);
1117        if (NISERR()) {
1118            return 0;
1119        }
1120        copyouts(nfa, to, s);   /* duplicate outarcs */
1121        cparc(nfa, con, from, s);       /* move constraint */
1122        freearc(nfa, con);
1123        to = s;
1124        con = to->ins;
1125    }
1126    assert(to->nins == 1);
1127
1128    /*
1129     * Propagate the constraint into the to state's outarcs.
1130     */
1131
1132    for (a = to->outs; a != NULL; a = nexta) {
1133        nexta = a->outchain;
1134        switch (combine(con, a)) {
1135        case INCOMPATIBLE:      /* destroy the arc */
1136            freearc(nfa, a);
1137            break;
1138        case SATISFIED:         /* no action needed */
1139            break;
1140        case COMPATIBLE:        /* swap the two arcs, more or less */
1141            s = newstate(nfa);
1142            if (NISERR()) {
1143                return 0;
1144            }
1145            cparc(nfa, con, s, a->to);  /* anticipate move */
1146            cparc(nfa, a, from, s);
1147            if (NISERR()) {
1148                return 0;
1149            }
1150            freearc(nfa, a);
1151            break;
1152        default:
1153            assert(NOTREACHED);
1154            break;
1155        }
1156    }
1157
1158    /*
1159     * Remaining outarcs, if any, incorporate the constraint.
1160     */
1161
1162    moveouts(nfa, to, from);
1163    dropstate(nfa, to);         /* will free the constraint */
1164    return 1;
1165}
1166
1167/*
1168 - combine - constraint lands on an arc, what happens?
1169 ^ #def INCOMPATIBLE    1       // destroys arc
1170 ^ #def SATISFIED       2       // constraint satisfied
1171 ^ #def COMPATIBLE      3       // compatible but not satisfied yet
1172 ^ static int combine(struct arc *, struct arc *);
1173 */
1174static int
1175combine(
1176    struct arc *con,
1177    struct arc *a)
1178{
1179#define CA(ct,at)       (((ct)<<CHAR_BIT) | (at))
1180
1181    switch (CA(con->type, a->type)) {
1182    case CA('^', PLAIN):        /* newlines are handled separately */
1183    case CA('$', PLAIN):
1184        return INCOMPATIBLE;
1185        break;
1186    case CA(AHEAD, PLAIN):      /* color constraints meet colors */
1187    case CA(BEHIND, PLAIN):
1188        if (con->co == a->co) {
1189            return SATISFIED;
1190        }
1191        return INCOMPATIBLE;
1192        break;
1193    case CA('^', '^'):          /* collision, similar constraints */
1194    case CA('$', '$'):
1195    case CA(AHEAD, AHEAD):
1196    case CA(BEHIND, BEHIND):
1197        if (con->co == a->co) { /* true duplication */
1198            return SATISFIED;
1199        }
1200        return INCOMPATIBLE;
1201        break;
1202    case CA('^', BEHIND):       /* collision, dissimilar constraints */
1203    case CA(BEHIND, '^'):
1204    case CA('$', AHEAD):
1205    case CA(AHEAD, '$'):
1206        return INCOMPATIBLE;
1207        break;
1208    case CA('^', '$'):          /* constraints passing each other */
1209    case CA('^', AHEAD):
1210    case CA(BEHIND, '$'):
1211    case CA(BEHIND, AHEAD):
1212    case CA('$', '^'):
1213    case CA('$', BEHIND):
1214    case CA(AHEAD, '^'):
1215    case CA(AHEAD, BEHIND):
1216    case CA('^', LACON):
1217    case CA(BEHIND, LACON):
1218    case CA('$', LACON):
1219    case CA(AHEAD, LACON):
1220        return COMPATIBLE;
1221        break;
1222    }
1223    assert(NOTREACHED);
1224    return INCOMPATIBLE;        /* for benefit of blind compilers */
1225}
1226
1227/*
1228 - fixempties - get rid of EMPTY arcs
1229 ^ static VOID fixempties(struct nfa *, FILE *);
1230 */
1231static void
1232fixempties(
1233    struct nfa *nfa,
1234    FILE *f)                    /* for debug output; NULL none */
1235{
1236    struct state *s;
1237    struct state *nexts;
1238    struct arc *a;
1239    struct arc *nexta;
1240    int progress;
1241
1242    /*
1243     * Find and eliminate empties until there are no more.
1244     */
1245
1246    do {
1247        progress = 0;
1248        for (s = nfa->states; s != NULL && !NISERR()
1249                && s->no != FREESTATE; s = nexts) {
1250            nexts = s->next;
1251            for (a = s->outs; a != NULL && !NISERR(); a = nexta) {
1252                nexta = a->outchain;
1253                if (a->type == EMPTY && unempty(nfa, a)) {
1254                    progress = 1;
1255                }
1256                assert(nexta == NULL || s->no != FREESTATE);
1257            }
1258        }
1259        if (progress && f != NULL) {
1260            dumpnfa(nfa, f);
1261        }
1262    } while (progress && !NISERR());
1263}
1264
1265/*
1266 - unempty - optimize out an EMPTY arc, if possible
1267 * Actually, as it stands this function always succeeds, but the return value
1268 * is kept with an eye on possible future changes.
1269 ^ static int unempty(struct nfa *, struct arc *);
1270 */
1271static int                      /* 0 couldn't, 1 could */
1272unempty(
1273    struct nfa *nfa,
1274    struct arc *a)
1275{
1276    struct state *from = a->from;
1277    struct state *to = a->to;
1278    int usefrom;                /* work on from, as opposed to to? */
1279
1280    assert(a->type == EMPTY);
1281    assert(from != nfa->pre && to != nfa->post);
1282
1283    if (from == to) {           /* vacuous loop */
1284        freearc(nfa, a);
1285        return 1;
1286    }
1287
1288    /*
1289     * Decide which end to work on.
1290     */
1291
1292    usefrom = 1;                /* default: attack from */
1293    if (from->nouts > to->nins) {
1294        usefrom = 0;
1295    } else if (from->nouts == to->nins) {
1296        /*
1297         * Decide on secondary issue: move/copy fewest arcs.
1298         */
1299
1300        if (from->nins > to->nouts) {
1301            usefrom = 0;
1302        }
1303    }
1304
1305    freearc(nfa, a);
1306    if (usefrom) {
1307        if (from->nouts == 0) {
1308            /*
1309             * Was the state's only outarc.
1310             */
1311
1312            moveins(nfa, from, to);
1313            freestate(nfa, from);
1314        } else {
1315            copyins(nfa, from, to);
1316        }
1317    } else {
1318        if (to->nins == 0) {
1319            /*
1320             * Was the state's only inarc.
1321             */
1322
1323            moveouts(nfa, to, from);
1324            freestate(nfa, to);
1325        } else {
1326            copyouts(nfa, to, from);
1327        }
1328    }
1329
1330    return 1;
1331}
1332
1333/*
1334 - cleanup - clean up NFA after optimizations
1335 ^ static VOID cleanup(struct nfa *);
1336 */
1337static void
1338cleanup(
1339    struct nfa *nfa)
1340{
1341    struct state *s;
1342    struct state *nexts;
1343    int n;
1344
1345    /*
1346     * Clear out unreachable or dead-end states. Use pre to mark reachable,
1347     * then post to mark can-reach-post.
1348     */
1349
1350    markreachable(nfa, nfa->pre, NULL, nfa->pre);
1351    markcanreach(nfa, nfa->post, nfa->pre, nfa->post);
1352    for (s = nfa->states; s != NULL; s = nexts) {
1353        nexts = s->next;
1354        if (s->tmp != nfa->post && !s->flag) {
1355            dropstate(nfa, s);
1356        }
1357    }
1358    assert(nfa->post->nins == 0 || nfa->post->tmp == nfa->post);
1359    cleartraverse(nfa, nfa->pre);
1360    assert(nfa->post->nins == 0 || nfa->post->tmp == NULL);
1361    /* the nins==0 (final unreachable) case will be caught later */
1362
1363    /*
1364     * Renumber surviving states.
1365     */
1366
1367    n = 0;
1368    for (s = nfa->states; s != NULL; s = s->next) {
1369        s->no = n++;
1370    }
1371    nfa->nstates = n;
1372}
1373
1374/*
1375 - markreachable - recursive marking of reachable states
1376 ^ static VOID markreachable(struct nfa *, struct state *, struct state *,
1377 ^      struct state *);
1378 */
1379static void
1380markreachable(
1381    struct nfa *nfa,
1382    struct state *s,
1383    struct state *okay,         /* consider only states with this mark */
1384    struct state *mark)         /* the value to mark with */
1385{
1386    struct arc *a;
1387
1388    if (s->tmp != okay) {
1389        return;
1390    }
1391    s->tmp = mark;
1392
1393    for (a = s->outs; a != NULL; a = a->outchain) {
1394        markreachable(nfa, a->to, okay, mark);
1395    }
1396}
1397
1398/*
1399 - markcanreach - recursive marking of states which can reach here
1400 ^ static VOID markcanreach(struct nfa *, struct state *, struct state *,
1401 ^      struct state *);
1402 */
1403static void
1404markcanreach(
1405    struct nfa *nfa,
1406    struct state *s,
1407    struct state *okay,         /* consider only states with this mark */
1408    struct state *mark)         /* the value to mark with */
1409{
1410    struct arc *a;
1411
1412    if (s->tmp != okay) {
1413        return;
1414    }
1415    s->tmp = mark;
1416
1417    for (a = s->ins; a != NULL; a = a->inchain) {
1418        markcanreach(nfa, a->from, okay, mark);
1419    }
1420}
1421
1422/*
1423 - analyze - ascertain potentially-useful facts about an optimized NFA
1424 ^ static long analyze(struct nfa *);
1425 */
1426static long                     /* re_info bits to be ORed in */
1427analyze(
1428    struct nfa *nfa)
1429{
1430    struct arc *a;
1431    struct arc *aa;
1432
1433    if (nfa->pre->outs == NULL) {
1434        return REG_UIMPOSSIBLE;
1435    }
1436    for (a = nfa->pre->outs; a != NULL; a = a->outchain) {
1437        for (aa = a->to->outs; aa != NULL; aa = aa->outchain) {
1438            if (aa->to == nfa->post) {
1439                return REG_UEMPTYMATCH;
1440            }
1441        }
1442    }
1443    return 0;
1444}
1445
1446/*
1447 - compact - compact an NFA
1448 ^ static VOID compact(struct nfa *, struct cnfa *);
1449 */
1450static void
1451compact(
1452    struct nfa *nfa,
1453    struct cnfa *cnfa)
1454{
1455    struct state *s;
1456    struct arc *a;
1457    size_t nstates;
1458    size_t narcs;
1459    struct carc *ca;
1460    struct carc *first;
1461
1462    assert(!NISERR());
1463
1464    nstates = 0;
1465    narcs = 0;
1466    for (s = nfa->states; s != NULL; s = s->next) {
1467        nstates++;
1468        narcs += 1 + s->nouts + 1;
1469        /* 1 as a fake for flags, nouts for arcs, 1 as endmarker */
1470    }
1471
1472    cnfa->states = (struct carc **) MALLOC(nstates * sizeof(struct carc *));
1473    cnfa->arcs = (struct carc *) MALLOC(narcs * sizeof(struct carc));
1474    if (cnfa->states == NULL || cnfa->arcs == NULL) {
1475        if (cnfa->states != NULL) {
1476            FREE(cnfa->states);
1477        }
1478        if (cnfa->arcs != NULL) {
1479            FREE(cnfa->arcs);
1480        }
1481        NERR(REG_ESPACE);
1482        return;
1483    }
1484    cnfa->nstates = nstates;
1485    cnfa->pre = nfa->pre->no;
1486    cnfa->post = nfa->post->no;
1487    cnfa->bos[0] = nfa->bos[0];
1488    cnfa->bos[1] = nfa->bos[1];
1489    cnfa->eos[0] = nfa->eos[0];
1490    cnfa->eos[1] = nfa->eos[1];
1491    cnfa->ncolors = maxcolor(nfa->cm) + 1;
1492    cnfa->flags = 0;
1493
1494    ca = cnfa->arcs;
1495    for (s = nfa->states; s != NULL; s = s->next) {
1496        assert((size_t) s->no < nstates);
1497        cnfa->states[s->no] = ca;
1498        ca->co = 0;             /* clear and skip flags "arc" */
1499        ca++;
1500        first = ca;
1501        for (a = s->outs; a != NULL; a = a->outchain) {
1502            switch (a->type) {
1503            case PLAIN:
1504                ca->co = a->co;
1505                ca->to = a->to->no;
1506                ca++;
1507                break;
1508            case LACON:
1509                assert(s->no != cnfa->pre);
1510                ca->co = (color) (cnfa->ncolors + a->co);
1511                ca->to = a->to->no;
1512                ca++;
1513                cnfa->flags |= HASLACONS;
1514                break;
1515            default:
1516                assert(NOTREACHED);
1517                break;
1518            }
1519        }
1520        carcsort(first, ca-1);
1521        ca->co = COLORLESS;
1522        ca->to = 0;
1523        ca++;
1524    }
1525    assert(ca == &cnfa->arcs[narcs]);
1526    assert(cnfa->nstates != 0);
1527
1528    /*
1529     * Mark no-progress states.
1530     */
1531
1532    for (a = nfa->pre->outs; a != NULL; a = a->outchain) {
1533        cnfa->states[a->to->no]->co = 1;
1534    }
1535    cnfa->states[nfa->pre->no]->co = 1;
1536}
1537
1538/*
1539 - carcsort - sort compacted-NFA arcs by color
1540 * Really dumb algorithm, but if the list is long enough for that to matter,
1541 * you're in real trouble anyway.
1542 ^ static VOID carcsort(struct carc *, struct carc *);
1543 */
1544static void
1545carcsort(
1546    struct carc *first,
1547    struct carc *last)
1548{
1549    struct carc *p;
1550    struct carc *q;
1551    struct carc tmp;
1552
1553    if (last - first <= 1) {
1554        return;
1555    }
1556
1557    for (p = first; p <= last; p++) {
1558        for (q = p; q <= last; q++) {
1559            if (p->co > q->co || (p->co == q->co && p->to > q->to)) {
1560                assert(p != q);
1561                tmp = *p;
1562                *p = *q;
1563                *q = tmp;
1564            }
1565        }
1566    }
1567}
1568
1569/*
1570 - freecnfa - free a compacted NFA
1571 ^ static VOID freecnfa(struct cnfa *);
1572 */
1573static void
1574freecnfa(
1575    struct cnfa *cnfa)
1576{
1577    assert(cnfa->nstates != 0); /* not empty already */
1578    cnfa->nstates = 0;
1579    FREE(cnfa->states);
1580    FREE(cnfa->arcs);
1581}
1582
1583/*
1584 - dumpnfa - dump an NFA in human-readable form
1585 ^ static VOID dumpnfa(struct nfa *, FILE *);
1586 */
1587static void
1588dumpnfa(
1589    struct nfa *nfa,
1590    FILE *f)
1591{
1592#ifdef REG_DEBUG
1593    struct state *s;
1594
1595    fprintf(f, "pre %d, post %d", nfa->pre->no, nfa->post->no);
1596    if (nfa->bos[0] != COLORLESS) {
1597        fprintf(f, ", bos [%ld]", (long) nfa->bos[0]);
1598    }
1599    if (nfa->bos[1] != COLORLESS) {
1600        fprintf(f, ", bol [%ld]", (long) nfa->bos[1]);
1601    }
1602    if (nfa->eos[0] != COLORLESS) {
1603        fprintf(f, ", eos [%ld]", (long) nfa->eos[0]);
1604    }
1605    if (nfa->eos[1] != COLORLESS) {
1606        fprintf(f, ", eol [%ld]", (long) nfa->eos[1]);
1607    }
1608    fprintf(f, "\n");
1609    for (s = nfa->states; s != NULL; s = s->next) {
1610        dumpstate(s, f);
1611    }
1612    if (nfa->parent == NULL) {
1613        dumpcolors(nfa->cm, f);
1614    }
1615    fflush(f);
1616#endif
1617}
1618
1619#ifdef REG_DEBUG                /* subordinates of dumpnfa */
1620/*
1621 ^ #ifdef REG_DEBUG
1622 */
1623
1624/*
1625 - dumpstate - dump an NFA state in human-readable form
1626 ^ static VOID dumpstate(struct state *, FILE *);
1627 */
1628static void
1629dumpstate(
1630    struct state *s,
1631    FILE *f)
1632{
1633    struct arc *a;
1634
1635    fprintf(f, "%d%s%c", s->no, (s->tmp != NULL) ? "T" : "",
1636            (s->flag) ? s->flag : '.');
1637    if (s->prev != NULL && s->prev->next != s) {
1638        fprintf(f, "\tstate chain bad\n");
1639    }
1640    if (s->nouts == 0) {
1641        fprintf(f, "\tno out arcs\n");
1642    } else {
1643        dumparcs(s, f);
1644    }
1645    fflush(f);
1646    for (a = s->ins; a != NULL; a = a->inchain) {
1647        if (a->to != s) {
1648            fprintf(f, "\tlink from %d to %d on %d's in-chain\n",
1649                    a->from->no, a->to->no, s->no);
1650        }
1651    }
1652}
1653
1654/*
1655 - dumparcs - dump out-arcs in human-readable form
1656 ^ static VOID dumparcs(struct state *, FILE *);
1657 */
1658static void
1659dumparcs(
1660    struct state *s,
1661    FILE *f)
1662{
1663    int pos;
1664
1665    assert(s->nouts > 0);
1666    /* printing arcs in reverse order is usually clearer */
1667    pos = dumprarcs(s->outs, s, f, 1);
1668    if (pos != 1) {
1669        fprintf(f, "\n");
1670    }
1671}
1672
1673/*
1674 - dumprarcs - dump remaining outarcs, recursively, in reverse order
1675 ^ static int dumprarcs(struct arc *, struct state *, FILE *, int);
1676 */
1677static int                      /* resulting print position */
1678dumprarcs(
1679    struct arc *a,
1680    struct state *s,
1681    FILE *f,
1682    int pos)                    /* initial print position */
1683{
1684    if (a->outchain != NULL) {
1685        pos = dumprarcs(a->outchain, s, f, pos);
1686    }
1687    dumparc(a, s, f);
1688    if (pos == 5) {
1689        fprintf(f, "\n");
1690        pos = 1;
1691    } else {
1692        pos++;
1693    }
1694    return pos;
1695}
1696
1697/*
1698 - dumparc - dump one outarc in readable form, including prefixing tab
1699 ^ static VOID dumparc(struct arc *, struct state *, FILE *);
1700 */
1701static void
1702dumparc(
1703    struct arc *a,
1704    struct state *s,
1705    FILE *f)
1706{
1707    struct arc *aa;
1708    struct arcbatch *ab;
1709
1710    fprintf(f, "\t");
1711    switch (a->type) {
1712    case PLAIN:
1713        fprintf(f, "[%ld]", (long) a->co);
1714        break;
1715    case AHEAD:
1716        fprintf(f, ">%ld>", (long) a->co);
1717        break;
1718    case BEHIND:
1719        fprintf(f, "<%ld<", (long) a->co);
1720        break;
1721    case LACON:
1722        fprintf(f, ":%ld:", (long) a->co);
1723        break;
1724    case '^':
1725    case '$':
1726        fprintf(f, "%c%d", a->type, (int) a->co);
1727        break;
1728    case EMPTY:
1729        break;
1730    default:
1731        fprintf(f, "0x%x/0%lo", a->type, (long) a->co);
1732        break;
1733    }
1734    if (a->from != s) {
1735        fprintf(f, "?%d?", a->from->no);
1736    }
1737    for (ab = &a->from->oas; ab != NULL; ab = ab->next) {
1738        for (aa = &ab->a[0]; aa < &ab->a[ABSIZE]; aa++) {
1739            if (aa == a) {
1740                break;          /* NOTE BREAK OUT */
1741            }
1742        }
1743        if (aa < &ab->a[ABSIZE]) {      /* propagate break */
1744            break;              /* NOTE BREAK OUT */
1745        }
1746    }
1747    if (ab == NULL) {
1748        fprintf(f, "?!?");      /* not in allocated space */
1749    }
1750    fprintf(f, "->");
1751    if (a->to == NULL) {
1752        fprintf(f, "NULL");
1753        return;
1754    }
1755    fprintf(f, "%d", a->to->no);
1756    for (aa = a->to->ins; aa != NULL; aa = aa->inchain) {
1757        if (aa == a) {
1758            break;              /* NOTE BREAK OUT */
1759        }
1760    }
1761    if (aa == NULL) {
1762        fprintf(f, "?!?");      /* missing from in-chain */
1763    }
1764}
1765
1766/*
1767 ^ #endif
1768 */
1769#endif                          /* ifdef REG_DEBUG */
1770
1771/*
1772 - dumpcnfa - dump a compacted NFA in human-readable form
1773 ^ static VOID dumpcnfa(struct cnfa *, FILE *);
1774 */
1775static void
1776dumpcnfa(
1777    struct cnfa *cnfa,
1778    FILE *f)
1779{
1780#ifdef REG_DEBUG
1781    int st;
1782
1783    fprintf(f, "pre %d, post %d", cnfa->pre, cnfa->post);
1784    if (cnfa->bos[0] != COLORLESS) {
1785        fprintf(f, ", bos [%ld]", (long) cnfa->bos[0]);
1786    }
1787    if (cnfa->bos[1] != COLORLESS) {
1788        fprintf(f, ", bol [%ld]", (long) cnfa->bos[1]);
1789    }
1790    if (cnfa->eos[0] != COLORLESS) {
1791        fprintf(f, ", eos [%ld]", (long) cnfa->eos[0]);
1792    }
1793    if (cnfa->eos[1] != COLORLESS) {
1794        fprintf(f, ", eol [%ld]", (long) cnfa->eos[1]);
1795    }
1796    if (cnfa->flags&HASLACONS) {
1797        fprintf(f, ", haslacons");
1798    }
1799    fprintf(f, "\n");
1800    for (st = 0; st < cnfa->nstates; st++) {
1801        dumpcstate(st, cnfa->states[st], cnfa, f);
1802    }
1803    fflush(f);
1804#endif
1805}
1806
1807#ifdef REG_DEBUG                /* subordinates of dumpcnfa */
1808/*
1809 ^ #ifdef REG_DEBUG
1810 */
1811
1812/*
1813 - dumpcstate - dump a compacted-NFA state in human-readable form
1814 ^ static VOID dumpcstate(int, struct carc *, struct cnfa *, FILE *);
1815 */
1816static void
1817dumpcstate(
1818    int st,
1819    struct carc *ca,
1820    struct cnfa *cnfa,
1821    FILE *f)
1822{
1823    int i;
1824    int pos;
1825
1826    fprintf(f, "%d%s", st, (ca[0].co) ? ":" : ".");
1827    pos = 1;
1828    for (i = 1; ca[i].co != COLORLESS; i++) {
1829        if (ca[i].co < cnfa->ncolors) {
1830            fprintf(f, "\t[%ld]->%d", (long) ca[i].co, ca[i].to);
1831        } else {
1832            fprintf(f, "\t:%ld:->%d", (long) ca[i].co-cnfa->ncolors,ca[i].to);
1833        }
1834        if (pos == 5) {
1835            fprintf(f, "\n");
1836            pos = 1;
1837        } else {
1838            pos++;
1839        }
1840    }
1841    if (i == 1 || pos != 1) {
1842        fprintf(f, "\n");
1843    }
1844    fflush(f);
1845}
1846
1847/*
1848 ^ #endif
1849 */
1850#endif                          /* ifdef REG_DEBUG */
1851
1852/*
1853 * Local Variables:
1854 * mode: c
1855 * c-basic-offset: 4
1856 * fill-column: 78
1857 * End:
1858 */
Note: See TracBrowser for help on using the repository browser.