1 /* $OpenBSD: tblcmp.c,v 1.6 2003/06/04 17:34:44 millert Exp $ */
2
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 *
16 * Redistribution and use in source and binary forms, with or without
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.
34 */
35
36 /* $Header: /cvs/src/usr.bin/lex/tblcmp.c,v 1.6 2003/06/04 17:34:44 millert Exp $ */
37
38 #include "flexdef.h"
39
40
41 /* declarations for functions that have forward references */
42
43 void mkentry PROTO((int*, int, int, int, int));
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
bldtbl(state,statenum,totaltrans,comstate,comfreq)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
cmptmps()235 void cmptmps()
236 {
237 int tmpstorage[CSIZE + 1];
238 int *tmp = tmpstorage, i, j;
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
expand_nxt_chk()308 void expand_nxt_chk()
309 {
310 int old_max = current_max_xpairs;
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
find_table_space(state,numtrans)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 */
349 int i;
350 int *state_ptr, *chk_ptr;
351 int *ptr_to_last_entry_in_state;
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 */
inittbl()442 void inittbl()
443 {
444 int i;
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
mkdeftbl()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
mkentry(state,numchars,statenum,deflink,totaltrans)524 void mkentry( state, numchars, statenum, deflink, totaltrans )
525 int *state;
526 int numchars, statenum, deflink, totaltrans;
527 {
528 int minec, maxec, i, baseaddr;
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
mk1tbl(state,sym,onenxt,onedef)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
mkprot(state,statenum,comstate)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
mktemplate(state,statenum,comstate)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
mv2front(qelm)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
place_state(state,statenum,transnum)799 void place_state( state, statenum, transnum )
800 int *state, statenum, transnum;
801 {
802 int i;
803 int *state_ptr;
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
stack1(statenum,sym,nextstate,deflink)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
tbldiff(state,pr,ext)874 int tbldiff( state, pr, ext )
875 int state[], pr, ext[];
876 {
877 int i, *sp = state, *ep = ext, *protp;
878 int numdiff = 0;
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 }
895