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