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