Annotation of 43BSDReno/pgrm/lex/tblcmp.c, revision 1.1.1.1

1.1       root        1: /* tblcmp - table compression routines */
                      2: 
                      3: /*-
                      4:  * Copyright (c) 1990 The Regents of the University of California.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to Berkeley by
                      8:  * Vern Paxson.
                      9:  * 
                     10:  * The United States Government has rights in this work pursuant
                     11:  * to contract no. DE-AC03-76SF00098 between the United States
                     12:  * Department of Energy and the University of California.
                     13:  *
                     14:  * Redistribution and use in source and binary forms are permitted provided
                     15:  * that: (1) source distributions retain this entire copyright notice and
                     16:  * comment, and (2) distributions including binaries display the following
                     17:  * acknowledgement:  ``This product includes software developed by the
                     18:  * University of California, Berkeley and its contributors'' in the
                     19:  * documentation or other materials provided with the distribution and in
                     20:  * all advertising materials mentioning features or use of this software.
                     21:  * Neither the name of the University nor the names of its contributors may
                     22:  * be used to endorse or promote products derived from this software without
                     23:  * specific prior written permission.
                     24:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     25:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     26:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     27:  */
                     28: 
                     29: #ifndef lint
                     30: static char sccsid[] = "@(#)tblcmp.c   5.2 (Berkeley) 6/18/90";
                     31: #endif /* not lint */
                     32: 
                     33: #include "flexdef.h"
                     34: 
                     35: /* declarations for functions that have forward references */
                     36: 
                     37: void mkentry PROTO((register int*, int, int, int, int));
                     38: void mkprot PROTO((int[], int, int));
                     39: void mktemplate PROTO((int[], int, int));
                     40: void mv2front PROTO((int));
                     41: int tbldiff PROTO((int[], int, int[]));
                     42: 
                     43: 
                     44: /* bldtbl - build table entries for dfa state
                     45:  *
                     46:  * synopsis
                     47:  *   int state[numecs], statenum, totaltrans, comstate, comfreq;
                     48:  *   bldtbl( state, statenum, totaltrans, comstate, comfreq );
                     49:  *
                     50:  * State is the statenum'th dfa state.  It is indexed by equivalence class and
                     51:  * gives the number of the state to enter for a given equivalence class.
                     52:  * totaltrans is the total number of transitions out of the state.  Comstate
                     53:  * is that state which is the destination of the most transitions out of State.
                     54:  * Comfreq is how many transitions there are out of State to Comstate.
                     55:  *
                     56:  * A note on terminology:
                     57:  *    "protos" are transition tables which have a high probability of
                     58:  * either being redundant (a state processed later will have an identical
                     59:  * transition table) or nearly redundant (a state processed later will have
                     60:  * many of the same out-transitions).  A "most recently used" queue of
                     61:  * protos is kept around with the hope that most states will find a proto
                     62:  * which is similar enough to be usable, and therefore compacting the
                     63:  * output tables.
                     64:  *    "templates" are a special type of proto.  If a transition table is
                     65:  * homogeneous or nearly homogeneous (all transitions go to the same
                     66:  * destination) then the odds are good that future states will also go
                     67:  * to the same destination state on basically the same character set.
                     68:  * These homogeneous states are so common when dealing with large rule
                     69:  * sets that they merit special attention.  If the transition table were
                     70:  * simply made into a proto, then (typically) each subsequent, similar
                     71:  * state will differ from the proto for two out-transitions.  One of these
                     72:  * out-transitions will be that character on which the proto does not go
                     73:  * to the common destination, and one will be that character on which the
                     74:  * state does not go to the common destination.  Templates, on the other
                     75:  * hand, go to the common state on EVERY transition character, and therefore
                     76:  * cost only one difference.
                     77:  */
                     78: 
                     79: void bldtbl( state, statenum, totaltrans, comstate, comfreq )
                     80: int state[], statenum, totaltrans, comstate, comfreq;
                     81: 
                     82:     {
                     83:     int extptr, extrct[2][CSIZE + 1];
                     84:     int mindiff, minprot, i, d;
                     85:     int checkcom;
                     86: 
                     87:     /* If extptr is 0 then the first array of extrct holds the result of the
                     88:      * "best difference" to date, which is those transitions which occur in
                     89:      * "state" but not in the proto which, to date, has the fewest differences
                     90:      * between itself and "state".  If extptr is 1 then the second array of
                     91:      * extrct hold the best difference.  The two arrays are toggled
                     92:      * between so that the best difference to date can be kept around and
                     93:      * also a difference just created by checking against a candidate "best"
                     94:      * proto.
                     95:      */
                     96: 
                     97:     extptr = 0;
                     98: 
                     99:     /* if the state has too few out-transitions, don't bother trying to
                    100:      * compact its tables
                    101:      */
                    102: 
                    103:     if ( (totaltrans * 100) < (numecs * PROTO_SIZE_PERCENTAGE) )
                    104:        mkentry( state, numecs, statenum, JAMSTATE, totaltrans );
                    105: 
                    106:     else
                    107:        {
                    108:        /* checkcom is true if we should only check "state" against
                    109:         * protos which have the same "comstate" value
                    110:         */
                    111: 
                    112:        checkcom = comfreq * 100 > totaltrans * CHECK_COM_PERCENTAGE;
                    113: 
                    114:        minprot = firstprot;
                    115:        mindiff = totaltrans;
                    116: 
                    117:        if ( checkcom )
                    118:            {
                    119:            /* find first proto which has the same "comstate" */
                    120:            for ( i = firstprot; i != NIL; i = protnext[i] )
                    121:                if ( protcomst[i] == comstate )
                    122:                    {
                    123:                    minprot = i;
                    124:                    mindiff = tbldiff( state, minprot, extrct[extptr] );
                    125:                    break;
                    126:                    }
                    127:            }
                    128: 
                    129:        else
                    130:            {
                    131:            /* since we've decided that the most common destination out
                    132:             * of "state" does not occur with a high enough frequency,
                    133:             * we set the "comstate" to zero, assuring that if this state
                    134:             * is entered into the proto list, it will not be considered
                    135:             * a template.
                    136:             */
                    137:            comstate = 0;
                    138: 
                    139:            if ( firstprot != NIL )
                    140:                {
                    141:                minprot = firstprot;
                    142:                mindiff = tbldiff( state, minprot, extrct[extptr] );
                    143:                }
                    144:            }
                    145: 
                    146:        /* we now have the first interesting proto in "minprot".  If
                    147:         * it matches within the tolerances set for the first proto,
                    148:         * we don't want to bother scanning the rest of the proto list
                    149:         * to see if we have any other reasonable matches.
                    150:         */
                    151: 
                    152:        if ( mindiff * 100 > totaltrans * FIRST_MATCH_DIFF_PERCENTAGE )
                    153:            { /* not a good enough match.  Scan the rest of the protos */
                    154:            for ( i = minprot; i != NIL; i = protnext[i] )
                    155:                {
                    156:                d = tbldiff( state, i, extrct[1 - extptr] );
                    157:                if ( d < mindiff )
                    158:                    {
                    159:                    extptr = 1 - extptr;
                    160:                    mindiff = d;
                    161:                    minprot = i;
                    162:                    }
                    163:                }
                    164:            }
                    165: 
                    166:        /* check if the proto we've decided on as our best bet is close
                    167:         * enough to the state we want to match to be usable
                    168:         */
                    169: 
                    170:        if ( mindiff * 100 > totaltrans * ACCEPTABLE_DIFF_PERCENTAGE )
                    171:            {
                    172:            /* no good.  If the state is homogeneous enough, we make a
                    173:             * template out of it.  Otherwise, we make a proto.
                    174:             */
                    175: 
                    176:            if ( comfreq * 100 >= totaltrans * TEMPLATE_SAME_PERCENTAGE )
                    177:                mktemplate( state, statenum, comstate );
                    178: 
                    179:            else
                    180:                {
                    181:                mkprot( state, statenum, comstate );
                    182:                mkentry( state, numecs, statenum, JAMSTATE, totaltrans );
                    183:                }
                    184:            }
                    185: 
                    186:        else
                    187:            { /* use the proto */
                    188:            mkentry( extrct[extptr], numecs, statenum,
                    189:                     prottbl[minprot], mindiff );
                    190: 
                    191:            /* if this state was sufficiently different from the proto
                    192:             * we built it from, make it, too, a proto
                    193:             */
                    194: 
                    195:            if ( mindiff * 100 >= totaltrans * NEW_PROTO_DIFF_PERCENTAGE )
                    196:                mkprot( state, statenum, comstate );
                    197: 
                    198:            /* since mkprot added a new proto to the proto queue, it's possible
                    199:             * that "minprot" is no longer on the proto queue (if it happened
                    200:             * to have been the last entry, it would have been bumped off).
                    201:             * If it's not there, then the new proto took its physical place
                    202:             * (though logically the new proto is at the beginning of the
                    203:             * queue), so in that case the following call will do nothing.
                    204:             */
                    205: 
                    206:            mv2front( minprot );
                    207:            }
                    208:        }
                    209:     }
                    210: 
                    211: 
                    212: /* cmptmps - compress template table entries
                    213:  *
                    214:  * synopsis
                    215:  *    cmptmps();
                    216:  *
                    217:  *  template tables are compressed by using the 'template equivalence
                    218:  *  classes', which are collections of transition character equivalence
                    219:  *  classes which always appear together in templates - really meta-equivalence
                    220:  *  classes.  until this point, the tables for templates have been stored
                    221:  *  up at the top end of the nxt array; they will now be compressed and have
                    222:  *  table entries made for them.
                    223:  */
                    224: 
                    225: void cmptmps()
                    226: 
                    227:     {
                    228:     int tmpstorage[CSIZE + 1];
                    229:     register int *tmp = tmpstorage, i, j;
                    230:     int totaltrans, trans;
                    231: 
                    232:     peakpairs = numtemps * numecs + tblend;
                    233: 
                    234:     if ( usemecs )
                    235:        {
                    236:        /* create equivalence classes base on data gathered on template
                    237:         * transitions
                    238:         */
                    239: 
                    240:        nummecs = cre8ecs( tecfwd, tecbck, numecs );
                    241:        }
                    242:     
                    243:     else
                    244:        nummecs = numecs;
                    245: 
                    246:     if ( lastdfa + numtemps + 1 >= current_max_dfas )
                    247:        increase_max_dfas();
                    248: 
                    249:     /* loop through each template */
                    250: 
                    251:     for ( i = 1; i <= numtemps; ++i )
                    252:        {
                    253:        totaltrans = 0; /* number of non-jam transitions out of this template */
                    254: 
                    255:        for ( j = 1; j <= numecs; ++j )
                    256:            {
                    257:            trans = tnxt[numecs * i + j];
                    258: 
                    259:            if ( usemecs )
                    260:                {
                    261:                /* the absolute value of tecbck is the meta-equivalence class
                    262:                 * of a given equivalence class, as set up by cre8ecs
                    263:                 */
                    264:                if ( tecbck[j] > 0 )
                    265:                    {
                    266:                    tmp[tecbck[j]] = trans;
                    267: 
                    268:                    if ( trans > 0 )
                    269:                        ++totaltrans;
                    270:                    }
                    271:                }
                    272: 
                    273:            else
                    274:                {
                    275:                tmp[j] = trans;
                    276: 
                    277:                if ( trans > 0 )
                    278:                    ++totaltrans;
                    279:                }
                    280:            }
                    281: 
                    282:        /* it is assumed (in a rather subtle way) in the skeleton that
                    283:         * if we're using meta-equivalence classes, the def[] entry for
                    284:         * all templates is the jam template, i.e., templates never default
                    285:         * to other non-jam table entries (e.g., another template)
                    286:         */
                    287: 
                    288:        /* leave room for the jam-state after the last real state */
                    289:        mkentry( tmp, nummecs, lastdfa + i + 1, JAMSTATE, totaltrans );
                    290:        }
                    291:     }
                    292: 
                    293: 
                    294: 
                    295: /* expand_nxt_chk - expand the next check arrays */
                    296: 
                    297: void expand_nxt_chk()
                    298: 
                    299:     {
                    300:     register int old_max = current_max_xpairs;
                    301: 
                    302:     current_max_xpairs += MAX_XPAIRS_INCREMENT;
                    303: 
                    304:     ++num_reallocs;
                    305: 
                    306:     nxt = reallocate_integer_array( nxt, current_max_xpairs );
                    307:     chk = reallocate_integer_array( chk, current_max_xpairs );
                    308: 
                    309:     bzero( (char *) (chk + old_max),
                    310:           MAX_XPAIRS_INCREMENT * sizeof( int ) / sizeof( char ) );
                    311:     }
                    312: 
                    313: 
                    314: /* find_table_space - finds a space in the table for a state to be placed
                    315:  *
                    316:  * synopsis
                    317:  *     int *state, numtrans, block_start;
                    318:  *     int find_table_space();
                    319:  *
                    320:  *     block_start = find_table_space( state, numtrans );
                    321:  *
                    322:  * State is the state to be added to the full speed transition table.
                    323:  * Numtrans is the number of out-transitions for the state.
                    324:  *
                    325:  * find_table_space() returns the position of the start of the first block (in
                    326:  * chk) able to accommodate the state
                    327:  *
                    328:  * In determining if a state will or will not fit, find_table_space() must take
                    329:  * into account the fact that an end-of-buffer state will be added at [0],
                    330:  * and an action number will be added in [-1].
                    331:  */
                    332: 
                    333: int find_table_space( state, numtrans )
                    334: int *state, numtrans;
                    335:     
                    336:     {
                    337:     /* firstfree is the position of the first possible occurrence of two
                    338:      * consecutive unused records in the chk and nxt arrays
                    339:      */
                    340:     register int i;
                    341:     register int *state_ptr, *chk_ptr;
                    342:     register int *ptr_to_last_entry_in_state;
                    343: 
                    344:     /* if there are too many out-transitions, put the state at the end of
                    345:      * nxt and chk
                    346:      */
                    347:     if ( numtrans > MAX_XTIONS_FULL_INTERIOR_FIT )
                    348:        {
                    349:        /* if table is empty, return the first available spot in chk/nxt,
                    350:         * which should be 1
                    351:         */
                    352:        if ( tblend < 2 )
                    353:            return ( 1 );
                    354: 
                    355:        i = tblend - numecs;    /* start searching for table space near the
                    356:                                 * end of chk/nxt arrays
                    357:                                 */
                    358:        }
                    359: 
                    360:     else
                    361:        i = firstfree;          /* start searching for table space from the
                    362:                                 * beginning (skipping only the elements
                    363:                                 * which will definitely not hold the new
                    364:                                 * state)
                    365:                                 */
                    366: 
                    367:     while ( 1 )                /* loops until a space is found */
                    368:        {
                    369:        if ( i + numecs > current_max_xpairs )
                    370:            expand_nxt_chk();
                    371: 
                    372:        /* loops until space for end-of-buffer and action number are found */
                    373:        while ( 1 )
                    374:            {
                    375:            if ( chk[i - 1] == 0 )      /* check for action number space */
                    376:                {
                    377:                if ( chk[i] == 0 )      /* check for end-of-buffer space */
                    378:                    break;
                    379: 
                    380:                else
                    381:                    i += 2;     /* since i != 0, there is no use checking to
                    382:                                 * see if (++i) - 1 == 0, because that's the
                    383:                                 * same as i == 0, so we skip a space
                    384:                                 */
                    385:                }
                    386: 
                    387:            else
                    388:                ++i;
                    389: 
                    390:            if ( i + numecs > current_max_xpairs )
                    391:                expand_nxt_chk();
                    392:            }
                    393: 
                    394:        /* if we started search from the beginning, store the new firstfree for
                    395:         * the next call of find_table_space()
                    396:         */
                    397:        if ( numtrans <= MAX_XTIONS_FULL_INTERIOR_FIT )
                    398:            firstfree = i + 1;
                    399: 
                    400:        /* check to see if all elements in chk (and therefore nxt) that are
                    401:         * needed for the new state have not yet been taken
                    402:         */
                    403: 
                    404:        state_ptr = &state[1];
                    405:        ptr_to_last_entry_in_state = &chk[i + numecs + 1];
                    406: 
                    407:        for ( chk_ptr = &chk[i + 1]; chk_ptr != ptr_to_last_entry_in_state;
                    408:              ++chk_ptr )
                    409:            if ( *(state_ptr++) != 0 && *chk_ptr != 0 )
                    410:                break;
                    411: 
                    412:        if ( chk_ptr == ptr_to_last_entry_in_state )
                    413:            return ( i );
                    414: 
                    415:        else
                    416:            ++i;
                    417:        }
                    418:     }
                    419: 
                    420: 
                    421: /* inittbl - initialize transition tables
                    422:  *
                    423:  * synopsis
                    424:  *   inittbl();
                    425:  *
                    426:  * Initializes "firstfree" to be one beyond the end of the table.  Initializes
                    427:  * all "chk" entries to be zero.  Note that templates are built in their
                    428:  * own tbase/tdef tables.  They are shifted down to be contiguous
                    429:  * with the non-template entries during table generation.
                    430:  */
                    431: void inittbl()
                    432: 
                    433:     {
                    434:     register int i;
                    435: 
                    436:     bzero( (char *) chk, current_max_xpairs * sizeof( int ) / sizeof( char ) );
                    437: 
                    438:     tblend = 0;
                    439:     firstfree = tblend + 1;
                    440:     numtemps = 0;
                    441: 
                    442:     if ( usemecs )
                    443:        {
                    444:        /* set up doubly-linked meta-equivalence classes
                    445:         * these are sets of equivalence classes which all have identical
                    446:         * transitions out of TEMPLATES
                    447:         */
                    448: 
                    449:        tecbck[1] = NIL;
                    450: 
                    451:        for ( i = 2; i <= numecs; ++i )
                    452:            {
                    453:            tecbck[i] = i - 1;
                    454:            tecfwd[i - 1] = i;
                    455:            }
                    456: 
                    457:        tecfwd[numecs] = NIL;
                    458:        }
                    459:     }
                    460: 
                    461: 
                    462: /* mkdeftbl - make the default, "jam" table entries
                    463:  *
                    464:  * synopsis
                    465:  *   mkdeftbl();
                    466:  */
                    467: 
                    468: void mkdeftbl()
                    469: 
                    470:     {
                    471:     int i;
                    472: 
                    473:     jamstate = lastdfa + 1;
                    474: 
                    475:     ++tblend; /* room for transition on end-of-buffer character */
                    476: 
                    477:     if ( tblend + numecs > current_max_xpairs )
                    478:        expand_nxt_chk();
                    479: 
                    480:     /* add in default end-of-buffer transition */
                    481:     nxt[tblend] = end_of_buffer_state;
                    482:     chk[tblend] = jamstate;
                    483: 
                    484:     for ( i = 1; i <= numecs; ++i )
                    485:        {
                    486:        nxt[tblend + i] = 0;
                    487:        chk[tblend + i] = jamstate;
                    488:        }
                    489: 
                    490:     jambase = tblend;
                    491: 
                    492:     base[jamstate] = jambase;
                    493:     def[jamstate] = 0;
                    494: 
                    495:     tblend += numecs;
                    496:     ++numtemps;
                    497:     }
                    498: 
                    499: 
                    500: /* mkentry - create base/def and nxt/chk entries for transition array
                    501:  *
                    502:  * synopsis
                    503:  *   int state[numchars + 1], numchars, statenum, deflink, totaltrans;
                    504:  *   mkentry( state, numchars, statenum, deflink, totaltrans );
                    505:  *
                    506:  * "state" is a transition array "numchars" characters in size, "statenum"
                    507:  * is the offset to be used into the base/def tables, and "deflink" is the
                    508:  * entry to put in the "def" table entry.  If "deflink" is equal to
                    509:  * "JAMSTATE", then no attempt will be made to fit zero entries of "state"
                    510:  * (i.e., jam entries) into the table.  It is assumed that by linking to
                    511:  * "JAMSTATE" they will be taken care of.  In any case, entries in "state"
                    512:  * marking transitions to "SAME_TRANS" are treated as though they will be
                    513:  * taken care of by whereever "deflink" points.  "totaltrans" is the total
                    514:  * number of transitions out of the state.  If it is below a certain threshold,
                    515:  * the tables are searched for an interior spot that will accommodate the
                    516:  * state array.
                    517:  */
                    518: 
                    519: void mkentry( state, numchars, statenum, deflink, totaltrans )
                    520: register int *state;
                    521: int numchars, statenum, deflink, totaltrans;
                    522: 
                    523:     {
                    524:     register int minec, maxec, i, baseaddr;
                    525:     int tblbase, tbllast;
                    526: 
                    527:     if ( totaltrans == 0 )
                    528:        { /* there are no out-transitions */
                    529:        if ( deflink == JAMSTATE )
                    530:            base[statenum] = JAMSTATE;
                    531:        else
                    532:            base[statenum] = 0;
                    533: 
                    534:        def[statenum] = deflink;
                    535:        return;
                    536:        }
                    537: 
                    538:     for ( minec = 1; minec <= numchars; ++minec )
                    539:        {
                    540:        if ( state[minec] != SAME_TRANS )
                    541:            if ( state[minec] != 0 || deflink != JAMSTATE )
                    542:                break;
                    543:        }
                    544: 
                    545:     if ( totaltrans == 1 )
                    546:        {
                    547:        /* there's only one out-transition.  Save it for later to fill
                    548:         * in holes in the tables.
                    549:         */
                    550:        stack1( statenum, minec, state[minec], deflink );
                    551:        return;
                    552:        }
                    553: 
                    554:     for ( maxec = numchars; maxec > 0; --maxec )
                    555:        {
                    556:        if ( state[maxec] != SAME_TRANS )
                    557:            if ( state[maxec] != 0 || deflink != JAMSTATE )
                    558:                break;
                    559:        }
                    560: 
                    561:     /* Whether we try to fit the state table in the middle of the table
                    562:      * entries we have already generated, or if we just take the state
                    563:      * table at the end of the nxt/chk tables, we must make sure that we
                    564:      * have a valid base address (i.e., non-negative).  Note that not only are
                    565:      * negative base addresses dangerous at run-time (because indexing the
                    566:      * next array with one and a low-valued character might generate an
                    567:      * array-out-of-bounds error message), but at compile-time negative
                    568:      * base addresses denote TEMPLATES.
                    569:      */
                    570: 
                    571:     /* find the first transition of state that we need to worry about. */
                    572:     if ( totaltrans * 100 <= numchars * INTERIOR_FIT_PERCENTAGE )
                    573:        { /* attempt to squeeze it into the middle of the tabls */
                    574:        baseaddr = firstfree;
                    575: 
                    576:        while ( baseaddr < minec )
                    577:            {
                    578:            /* using baseaddr would result in a negative base address below
                    579:             * find the next free slot
                    580:             */
                    581:            for ( ++baseaddr; chk[baseaddr] != 0; ++baseaddr )
                    582:                ;
                    583:            }
                    584: 
                    585:        if ( baseaddr + maxec - minec >= current_max_xpairs )
                    586:            expand_nxt_chk();
                    587: 
                    588:        for ( i = minec; i <= maxec; ++i )
                    589:            if ( state[i] != SAME_TRANS )
                    590:                if ( state[i] != 0 || deflink != JAMSTATE )
                    591:                    if ( chk[baseaddr + i - minec] != 0 )
                    592:                        { /* baseaddr unsuitable - find another */
                    593:                        for ( ++baseaddr;
                    594:                              baseaddr < current_max_xpairs &&
                    595:                              chk[baseaddr] != 0;
                    596:                              ++baseaddr )
                    597:                            ;
                    598: 
                    599:                        if ( baseaddr + maxec - minec >= current_max_xpairs )
                    600:                            expand_nxt_chk();
                    601: 
                    602:                        /* reset the loop counter so we'll start all
                    603:                         * over again next time it's incremented
                    604:                         */
                    605: 
                    606:                        i = minec - 1;
                    607:                        }
                    608:        }
                    609: 
                    610:     else
                    611:        {
                    612:        /* ensure that the base address we eventually generate is
                    613:         * non-negative
                    614:         */
                    615:        baseaddr = max( tblend + 1, minec );
                    616:        }
                    617: 
                    618:     tblbase = baseaddr - minec;
                    619:     tbllast = tblbase + maxec;
                    620: 
                    621:     if ( tbllast >= current_max_xpairs )
                    622:        expand_nxt_chk();
                    623: 
                    624:     base[statenum] = tblbase;
                    625:     def[statenum] = deflink;
                    626: 
                    627:     for ( i = minec; i <= maxec; ++i )
                    628:        if ( state[i] != SAME_TRANS )
                    629:            if ( state[i] != 0 || deflink != JAMSTATE )
                    630:                {
                    631:                nxt[tblbase + i] = state[i];
                    632:                chk[tblbase + i] = statenum;
                    633:                }
                    634: 
                    635:     if ( baseaddr == firstfree )
                    636:        /* find next free slot in tables */
                    637:        for ( ++firstfree; chk[firstfree] != 0; ++firstfree )
                    638:            ;
                    639: 
                    640:     tblend = max( tblend, tbllast );
                    641:     }
                    642: 
                    643: 
                    644: /* mk1tbl - create table entries for a state (or state fragment) which
                    645:  *            has only one out-transition
                    646:  *
                    647:  * synopsis
                    648:  *   int state, sym, onenxt, onedef;
                    649:  *   mk1tbl( state, sym, onenxt, onedef );
                    650:  */
                    651: 
                    652: void mk1tbl( state, sym, onenxt, onedef )
                    653: int state, sym, onenxt, onedef;
                    654: 
                    655:     {
                    656:     if ( firstfree < sym )
                    657:        firstfree = sym;
                    658: 
                    659:     while ( chk[firstfree] != 0 )
                    660:        if ( ++firstfree >= current_max_xpairs )
                    661:            expand_nxt_chk();
                    662: 
                    663:     base[state] = firstfree - sym;
                    664:     def[state] = onedef;
                    665:     chk[firstfree] = state;
                    666:     nxt[firstfree] = onenxt;
                    667: 
                    668:     if ( firstfree > tblend )
                    669:        {
                    670:        tblend = firstfree++;
                    671: 
                    672:        if ( firstfree >= current_max_xpairs )
                    673:            expand_nxt_chk();
                    674:        }
                    675:     }
                    676: 
                    677: 
                    678: /* mkprot - create new proto entry
                    679:  *
                    680:  * synopsis
                    681:  *   int state[], statenum, comstate;
                    682:  *   mkprot( state, statenum, comstate );
                    683:  */
                    684: 
                    685: void mkprot( state, statenum, comstate )
                    686: int state[], statenum, comstate;
                    687: 
                    688:     {
                    689:     int i, slot, tblbase;
                    690: 
                    691:     if ( ++numprots >= MSP || numecs * numprots >= PROT_SAVE_SIZE )
                    692:        {
                    693:        /* gotta make room for the new proto by dropping last entry in
                    694:         * the queue
                    695:         */
                    696:        slot = lastprot;
                    697:        lastprot = protprev[lastprot];
                    698:        protnext[lastprot] = NIL;
                    699:        }
                    700: 
                    701:     else
                    702:        slot = numprots;
                    703: 
                    704:     protnext[slot] = firstprot;
                    705: 
                    706:     if ( firstprot != NIL )
                    707:        protprev[firstprot] = slot;
                    708: 
                    709:     firstprot = slot;
                    710:     prottbl[slot] = statenum;
                    711:     protcomst[slot] = comstate;
                    712: 
                    713:     /* copy state into save area so it can be compared with rapidly */
                    714:     tblbase = numecs * (slot - 1);
                    715: 
                    716:     for ( i = 1; i <= numecs; ++i )
                    717:        protsave[tblbase + i] = state[i];
                    718:     }
                    719: 
                    720: 
                    721: /* mktemplate - create a template entry based on a state, and connect the state
                    722:  *              to it
                    723:  *
                    724:  * synopsis
                    725:  *   int state[], statenum, comstate, totaltrans;
                    726:  *   mktemplate( state, statenum, comstate, totaltrans );
                    727:  */
                    728: 
                    729: void mktemplate( state, statenum, comstate )
                    730: int state[], statenum, comstate;
                    731: 
                    732:     {
                    733:     int i, numdiff, tmpbase, tmp[CSIZE + 1];
                    734:     Char transset[CSIZE + 1];
                    735:     int tsptr;
                    736: 
                    737:     ++numtemps;
                    738: 
                    739:     tsptr = 0;
                    740: 
                    741:     /* calculate where we will temporarily store the transition table
                    742:      * of the template in the tnxt[] array.  The final transition table
                    743:      * gets created by cmptmps()
                    744:      */
                    745: 
                    746:     tmpbase = numtemps * numecs;
                    747: 
                    748:     if ( tmpbase + numecs >= current_max_template_xpairs )
                    749:        {
                    750:        current_max_template_xpairs += MAX_TEMPLATE_XPAIRS_INCREMENT;
                    751: 
                    752:        ++num_reallocs;
                    753: 
                    754:        tnxt = reallocate_integer_array( tnxt, current_max_template_xpairs );
                    755:        }
                    756: 
                    757:     for ( i = 1; i <= numecs; ++i )
                    758:        if ( state[i] == 0 )
                    759:            tnxt[tmpbase + i] = 0;
                    760:        else
                    761:            {
                    762:            transset[tsptr++] = i;
                    763:            tnxt[tmpbase + i] = comstate;
                    764:            }
                    765: 
                    766:     if ( usemecs )
                    767:        mkeccl( transset, tsptr, tecfwd, tecbck, numecs, 0 );
                    768: 
                    769:     mkprot( tnxt + tmpbase, -numtemps, comstate );
                    770: 
                    771:     /* we rely on the fact that mkprot adds things to the beginning
                    772:      * of the proto queue
                    773:      */
                    774: 
                    775:     numdiff = tbldiff( state, firstprot, tmp );
                    776:     mkentry( tmp, numecs, statenum, -numtemps, numdiff );
                    777:     }
                    778: 
                    779: 
                    780: /* mv2front - move proto queue element to front of queue
                    781:  *
                    782:  * synopsis
                    783:  *   int qelm;
                    784:  *   mv2front( qelm );
                    785:  */
                    786: 
                    787: void mv2front( qelm )
                    788: int qelm;
                    789: 
                    790:     {
                    791:     if ( firstprot != qelm )
                    792:        {
                    793:        if ( qelm == lastprot )
                    794:            lastprot = protprev[lastprot];
                    795: 
                    796:        protnext[protprev[qelm]] = protnext[qelm];
                    797: 
                    798:        if ( protnext[qelm] != NIL )
                    799:            protprev[protnext[qelm]] = protprev[qelm];
                    800: 
                    801:        protprev[qelm] = NIL;
                    802:        protnext[qelm] = firstprot;
                    803:        protprev[firstprot] = qelm;
                    804:        firstprot = qelm;
                    805:        }
                    806:     }
                    807: 
                    808: 
                    809: /* place_state - place a state into full speed transition table
                    810:  *
                    811:  * synopsis
                    812:  *     int *state, statenum, transnum;
                    813:  *     place_state( state, statenum, transnum );
                    814:  *
                    815:  * State is the statenum'th state.  It is indexed by equivalence class and
                    816:  * gives the number of the state to enter for a given equivalence class.
                    817:  * Transnum is the number of out-transitions for the state.
                    818:  */
                    819: 
                    820: void place_state( state, statenum, transnum )
                    821: int *state, statenum, transnum;
                    822: 
                    823:     {
                    824:     register int i;
                    825:     register int *state_ptr;
                    826:     int position = find_table_space( state, transnum );
                    827: 
                    828:     /* base is the table of start positions */
                    829:     base[statenum] = position;
                    830: 
                    831:     /* put in action number marker; this non-zero number makes sure that
                    832:      * find_table_space() knows that this position in chk/nxt is taken
                    833:      * and should not be used for another accepting number in another state
                    834:      */
                    835:     chk[position - 1] = 1;
                    836: 
                    837:     /* put in end-of-buffer marker; this is for the same purposes as above */
                    838:     chk[position] = 1;
                    839: 
                    840:     /* place the state into chk and nxt */
                    841:     state_ptr = &state[1];
                    842: 
                    843:     for ( i = 1; i <= numecs; ++i, ++state_ptr )
                    844:        if ( *state_ptr != 0 )
                    845:            {
                    846:            chk[position + i] = i;
                    847:            nxt[position + i] = *state_ptr;
                    848:            }
                    849: 
                    850:     if ( position + numecs > tblend )
                    851:        tblend = position + numecs;
                    852:     }
                    853: 
                    854: 
                    855: /* stack1 - save states with only one out-transition to be processed later
                    856:  *
                    857:  * synopsis
                    858:  *   int statenum, sym, nextstate, deflink;
                    859:  *   stack1( statenum, sym, nextstate, deflink );
                    860:  *
                    861:  * if there's room for another state one the "one-transition" stack, the
                    862:  * state is pushed onto it, to be processed later by mk1tbl.  If there's
                    863:  * no room, we process the sucker right now.
                    864:  */
                    865: 
                    866: void stack1( statenum, sym, nextstate, deflink )
                    867: int statenum, sym, nextstate, deflink;
                    868: 
                    869:     {
                    870:     if ( onesp >= ONE_STACK_SIZE - 1 )
                    871:        mk1tbl( statenum, sym, nextstate, deflink );
                    872: 
                    873:     else
                    874:        {
                    875:        ++onesp;
                    876:        onestate[onesp] = statenum;
                    877:        onesym[onesp] = sym;
                    878:        onenext[onesp] = nextstate;
                    879:        onedef[onesp] = deflink;
                    880:        }
                    881:     }
                    882: 
                    883: 
                    884: /* tbldiff - compute differences between two state tables
                    885:  *
                    886:  * synopsis
                    887:  *   int state[], pr, ext[];
                    888:  *   int tbldiff, numdifferences;
                    889:  *   numdifferences = tbldiff( state, pr, ext )
                    890:  *
                    891:  * "state" is the state array which is to be extracted from the pr'th
                    892:  * proto.  "pr" is both the number of the proto we are extracting from
                    893:  * and an index into the save area where we can find the proto's complete
                    894:  * state table.  Each entry in "state" which differs from the corresponding
                    895:  * entry of "pr" will appear in "ext".
                    896:  * Entries which are the same in both "state" and "pr" will be marked
                    897:  * as transitions to "SAME_TRANS" in "ext".  The total number of differences
                    898:  * between "state" and "pr" is returned as function value.  Note that this
                    899:  * number is "numecs" minus the number of "SAME_TRANS" entries in "ext".
                    900:  */
                    901: 
                    902: int tbldiff( state, pr, ext )
                    903: int state[], pr, ext[];
                    904: 
                    905:     {
                    906:     register int i, *sp = state, *ep = ext, *protp;
                    907:     register int numdiff = 0;
                    908: 
                    909:     protp = &protsave[numecs * (pr - 1)];
                    910: 
                    911:     for ( i = numecs; i > 0; --i )
                    912:        {
                    913:        if ( *++protp == *++sp )
                    914:            *++ep = SAME_TRANS;
                    915:        else
                    916:            {
                    917:            *++ep = *sp;
                    918:            ++numdiff;
                    919:            }
                    920:        }
                    921: 
                    922:     return ( numdiff );
                    923:     }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.