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