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