[BACK]Return to tblcmp.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / lex

Annotation of src/usr.bin/lex/tblcmp.c, Revision 1.5

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