home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume19 / flex2 / part05 < prev    next >
Text File  |  1989-06-21  |  51KB  |  1,945 lines

  1. Subject:  v19i059:  Flex, a fast LEX replacement, Part05/07
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Vern Paxson <vern@csam.lbl.gov>
  7. Posting-number: Volume 19, Issue 59
  8. Archive-name: flex2/part05
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 5 (of 7)."
  17. # Contents:  flex/dfa.c flex/tblcmp.c
  18. # Wrapped by rsalz@prune.bbn.com on Thu Jun 22 19:01:49 1989
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'flex/dfa.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'flex/dfa.c'\"
  22. else
  23. echo shar: Extracting \"'flex/dfa.c'\" \(22852 characters\)
  24. sed "s/^X//" >'flex/dfa.c' <<'END_OF_FILE'
  25. X/* dfa - DFA construction routines */
  26. X
  27. X/*
  28. X * Copyright (c) 1989 The Regents of the University of California.
  29. X * All rights reserved.
  30. X *
  31. X * This code is derived from software contributed to Berkeley by
  32. X * Vern Paxson.
  33. X * 
  34. X * The United States Government has rights in this work pursuant to
  35. X * contract no. DE-AC03-76SF00098 between the United States Department of
  36. X * Energy and the University of California.
  37. X *
  38. X * Redistribution and use in source and binary forms are permitted
  39. X * provided that the above copyright notice and this paragraph are
  40. X * duplicated in all such forms and that any documentation,
  41. X * advertising materials, and other materials related to such
  42. X * distribution and use acknowledge that the software was developed
  43. X * by the University of California, Berkeley.  The name of the
  44. X * University may not be used to endorse or promote products derived
  45. X * from this software without specific prior written permission.
  46. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  47. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  48. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  49. X */
  50. X
  51. X#ifndef lint
  52. X
  53. Xstatic char copyright[] =
  54. X    "@(#) Copyright (c) 1989 The Regents of the University of California.\n";
  55. Xstatic char CR_continuation[] = "@(#) All rights reserved.\n";
  56. X
  57. Xstatic char rcsid[] =
  58. X    "@(#) $Header: dfa.c,v 2.0 89/06/20 15:49:30 vern Locked $ (LBL)";
  59. X
  60. X#endif
  61. X
  62. X#include "flexdef.h"
  63. X
  64. X
  65. X/* check_for_backtracking - check a DFA state for backtracking
  66. X *
  67. X * synopsis
  68. X *     int ds, state[numecs];
  69. X *     check_for_backtracking( ds, state );
  70. X *
  71. X * ds is the number of the state to check and state[] is its out-transitions,
  72. X * indexed by equivalence class, and state_rules[] is the set of rules
  73. X * associated with this state
  74. X */
  75. X
  76. Xcheck_for_backtracking( ds, state )
  77. Xint ds;
  78. Xint state[];
  79. X
  80. X    {
  81. X    if ( (reject && ! dfaacc[ds].dfaacc_set) || ! dfaacc[ds].dfaacc_state )
  82. X    { /* state is non-accepting */
  83. X    ++num_backtracking;
  84. X
  85. X    if ( backtrack_report )
  86. X        {
  87. X        fprintf( backtrack_file, "State #%d is non-accepting -\n", ds );
  88. X
  89. X        /* identify the state */
  90. X        dump_associated_rules( backtrack_file, ds );
  91. X
  92. X        /* now identify it further using the out- and jam-transitions */
  93. X        dump_transitions( backtrack_file, state );
  94. X
  95. X        putc( '\n', backtrack_file );
  96. X        }
  97. X    }
  98. X    }
  99. X
  100. X
  101. X/* check_trailing_context - check to see if NFA state set constitutes
  102. X *                          "dangerous" trailing context
  103. X *
  104. X * synopsis
  105. X *    int nfa_states[num_states+1], num_states;
  106. X *    int accset[nacc+1], nacc;
  107. X *    int check_trailing_context();
  108. X *    true/false = check_trailing_context( nfa_states, num_states,
  109. X *                                         accset, nacc );
  110. X *
  111. X * NOTES
  112. X *    Trailing context is "dangerous" if both the head and the trailing
  113. X *  part are of variable size \and/ there's a DFA state which contains
  114. X *  both an accepting state for the head part of the rule and NFA states
  115. X *  which occur after the beginning of the trailing context.
  116. X *  When such a rule is matched, it's impossible to tell if having been
  117. X *  in the DFA state indicates the beginning of the trailing context
  118. X *  or further-along scanning of the pattern.  In these cases, a warning
  119. X *  message is issued.
  120. X *
  121. X *    nfa_states[1 .. num_states] is the list of NFA states in the DFA.
  122. X *    accset[1 .. nacc] is the list of accepting numbers for the DFA state.
  123. X */
  124. X
  125. Xint check_trailing_context( nfa_states, num_states, accset, nacc )
  126. Xint *nfa_states, num_states;
  127. Xint *accset;
  128. Xregister int nacc;
  129. X
  130. X    {
  131. X    register int i, j;
  132. X
  133. X    for ( i = 1; i <= num_states; ++i )
  134. X    {
  135. X    int ns = nfa_states[i];
  136. X    register int type = state_type[ns];
  137. X    register int ar = assoc_rule[ns];
  138. X
  139. X    if ( type == STATE_NORMAL || rule_type[ar] != RULE_VARIABLE )
  140. X        { /* do nothing */
  141. X        }
  142. X
  143. X    else if ( type == STATE_TRAILING_CONTEXT )
  144. X        {
  145. X        /* potential trouble.  Scan set of accepting numbers for
  146. X         * the one marking the end of the "head".  We assume that
  147. X         * this looping will be fairly cheap since it's rare that
  148. X         * an accepting number set is large.
  149. X         */
  150. X        for ( j = 1; j <= nacc; ++j )
  151. X        if ( accset[j] & YY_TRAILING_HEAD_MASK )
  152. X            {
  153. X            fprintf( stderr,
  154. X             "flex: Dangerous trailing context in rule at line %d\n",
  155. X                 rule_linenum[ar] );
  156. X            return;
  157. X            }
  158. X        }
  159. X    }
  160. X    }
  161. X
  162. X
  163. X/* dump_associated_rules - list the rules associated with a DFA state
  164. X *
  165. X * synopisis
  166. X *     int ds;
  167. X *     FILE *file;
  168. X *     dump_associated_rules( file, ds );
  169. X *
  170. X * goes through the set of NFA states associated with the DFA and
  171. X * extracts the first MAX_ASSOC_RULES unique rules, sorts them,
  172. X * and writes a report to the given file
  173. X */
  174. X
  175. Xdump_associated_rules( file, ds )
  176. XFILE *file;
  177. Xint ds;
  178. X
  179. X    {
  180. X    register int i, j;
  181. X    register int num_associated_rules = 0;
  182. X    int rule_set[MAX_ASSOC_RULES + 1];
  183. X    int *dset = dss[ds];
  184. X    int size = dfasiz[ds];
  185. X    
  186. X    for ( i = 1; i <= size; ++i )
  187. X    {
  188. X    register rule_num = rule_linenum[assoc_rule[dset[i]]];
  189. X
  190. X    for ( j = 1; j <= num_associated_rules; ++j )
  191. X        if ( rule_num == rule_set[j] )
  192. X        break;
  193. X
  194. X    if ( j > num_associated_rules )
  195. X        { /* new rule */
  196. X        if ( num_associated_rules < MAX_ASSOC_RULES )
  197. X        rule_set[++num_associated_rules] = rule_num;
  198. X        }
  199. X    }
  200. X
  201. X    bubble( rule_set, num_associated_rules );
  202. X
  203. X    fprintf( file, " associated rules:" );
  204. X
  205. X    for ( i = 1; i <= num_associated_rules; ++i )
  206. X    {
  207. X    if ( i % 8 == 1 )
  208. X        putc( '\n', file );
  209. X    
  210. X    fprintf( file, "\t%d", rule_set[i] );
  211. X    }
  212. X    
  213. X    putc( '\n', file );
  214. X    }
  215. X
  216. X
  217. X/* dump_transitions - list the transitions associated with a DFA state
  218. X *
  219. X * synopisis
  220. X *     int state[numecs];
  221. X *     FILE *file;
  222. X *     dump_transitions( file, state );
  223. X *
  224. X * goes through the set of out-transitions and lists them in human-readable
  225. X * form (i.e., not as equivalence classes); also lists jam transitions
  226. X * (i.e., all those which are not out-transitions, plus EOF).  The dump
  227. X * is done to the given file.
  228. X */
  229. X
  230. Xdump_transitions( file, state )
  231. XFILE *file;
  232. Xint state[];
  233. X
  234. X    {
  235. X    register int i, ec;
  236. X    int out_char_set[CSIZE + 1];
  237. X
  238. X    for ( i = 1; i <= CSIZE; ++i )
  239. X    {
  240. X    ec = ecgroup[i];
  241. X
  242. X    if ( ec < 0 )
  243. X        ec = -ec;
  244. X
  245. X    out_char_set[i] = state[ec];
  246. X    }
  247. X    
  248. X    fprintf( file, " out-transitions: " );
  249. X
  250. X    list_character_set( file, out_char_set );
  251. X
  252. X    /* now invert the members of the set to get the jam transitions */
  253. X    for ( i = 1; i <= CSIZE; ++i )
  254. X    out_char_set[i] = ! out_char_set[i];
  255. X
  256. X    fprintf( file, "\n jam-transitions: EOF " );
  257. X
  258. X    list_character_set( file, out_char_set );
  259. X
  260. X    putc( '\n', file );
  261. X    }
  262. X
  263. X
  264. X/* epsclosure - construct the epsilon closure of a set of ndfa states
  265. X *
  266. X * synopsis
  267. X *    int t[current_max_dfa_size], numstates, accset[num_rules + 1], nacc;
  268. X *    int hashval;
  269. X *    int *epsclosure();
  270. X *    t = epsclosure( t, &numstates, accset, &nacc, &hashval );
  271. X *
  272. X * NOTES
  273. X *    the epsilon closure is the set of all states reachable by an arbitrary
  274. X *  number of epsilon transitions which themselves do not have epsilon
  275. X *  transitions going out, unioned with the set of states which have non-null
  276. X *  accepting numbers.  t is an array of size numstates of nfa state numbers.
  277. X *  Upon return, t holds the epsilon closure and numstates is updated.  accset
  278. X *  holds a list of the accepting numbers, and the size of accset is given
  279. X *  by nacc.  t may be subjected to reallocation if it is not large enough
  280. X *  to hold the epsilon closure.
  281. X *
  282. X *    hashval is the hash value for the dfa corresponding to the state set
  283. X */
  284. X
  285. Xint *epsclosure( t, ns_addr, accset, nacc_addr, hv_addr )
  286. Xint *t, *ns_addr, accset[], *nacc_addr, *hv_addr;
  287. X
  288. X    {
  289. X    register int stkpos, ns, tsp;
  290. X    int numstates = *ns_addr, nacc, hashval, transsym, nfaccnum;
  291. X    int stkend, nstate;
  292. X    static int did_stk_init = false, *stk; 
  293. X
  294. X#define MARK_STATE(state) \
  295. X    trans1[state] = trans1[state] - MARKER_DIFFERENCE;
  296. X
  297. X#define IS_MARKED(state) (trans1[state] < 0)
  298. X
  299. X#define UNMARK_STATE(state) \
  300. X    trans1[state] = trans1[state] + MARKER_DIFFERENCE;
  301. X
  302. X#define CHECK_ACCEPT(state) \
  303. X    { \
  304. X    nfaccnum = accptnum[state]; \
  305. X    if ( nfaccnum != NIL ) \
  306. X        accset[++nacc] = nfaccnum; \
  307. X    }
  308. X
  309. X#define DO_REALLOCATION \
  310. X    { \
  311. X    current_max_dfa_size += MAX_DFA_SIZE_INCREMENT; \
  312. X    ++num_reallocs; \
  313. X    t = reallocate_integer_array( t, current_max_dfa_size ); \
  314. X    stk = reallocate_integer_array( stk, current_max_dfa_size ); \
  315. X    } \
  316. X
  317. X#define PUT_ON_STACK(state) \
  318. X    { \
  319. X    if ( ++stkend >= current_max_dfa_size ) \
  320. X        DO_REALLOCATION \
  321. X    stk[stkend] = state; \
  322. X    MARK_STATE(state) \
  323. X    }
  324. X
  325. X#define ADD_STATE(state) \
  326. X    { \
  327. X    if ( ++numstates >= current_max_dfa_size ) \
  328. X        DO_REALLOCATION \
  329. X    t[numstates] = state; \
  330. X    hashval = hashval + state; \
  331. X    }
  332. X
  333. X#define STACK_STATE(state) \
  334. X    { \
  335. X    PUT_ON_STACK(state) \
  336. X    CHECK_ACCEPT(state) \
  337. X    if ( nfaccnum != NIL || transchar[state] != SYM_EPSILON ) \
  338. X        ADD_STATE(state) \
  339. X    }
  340. X
  341. X    if ( ! did_stk_init )
  342. X    {
  343. X    stk = allocate_integer_array( current_max_dfa_size );
  344. X    did_stk_init = true;
  345. X    }
  346. X
  347. X    nacc = stkend = hashval = 0;
  348. X
  349. X    for ( nstate = 1; nstate <= numstates; ++nstate )
  350. X    {
  351. X    ns = t[nstate];
  352. X
  353. X    /* the state could be marked if we've already pushed it onto
  354. X     * the stack
  355. X     */
  356. X    if ( ! IS_MARKED(ns) )
  357. X        PUT_ON_STACK(ns)
  358. X
  359. X    CHECK_ACCEPT(ns)
  360. X    hashval = hashval + ns;
  361. X    }
  362. X
  363. X    for ( stkpos = 1; stkpos <= stkend; ++stkpos )
  364. X    {
  365. X    ns = stk[stkpos];
  366. X    transsym = transchar[ns];
  367. X
  368. X    if ( transsym == SYM_EPSILON )
  369. X        {
  370. X        tsp = trans1[ns] + MARKER_DIFFERENCE;
  371. X
  372. X        if ( tsp != NO_TRANSITION )
  373. X        {
  374. X        if ( ! IS_MARKED(tsp) )
  375. X            STACK_STATE(tsp)
  376. X
  377. X        tsp = trans2[ns];
  378. X
  379. X        if ( tsp != NO_TRANSITION )
  380. X            if ( ! IS_MARKED(tsp) )
  381. X            STACK_STATE(tsp)
  382. X        }
  383. X        }
  384. X    }
  385. X
  386. X    /* clear out "visit" markers */
  387. X
  388. X    for ( stkpos = 1; stkpos <= stkend; ++stkpos )
  389. X    {
  390. X    if ( IS_MARKED(stk[stkpos]) )
  391. X        {
  392. X        UNMARK_STATE(stk[stkpos])
  393. X        }
  394. X    else
  395. X        flexfatal( "consistency check failed in epsclosure()" );
  396. X    }
  397. X
  398. X    *ns_addr = numstates;
  399. X    *hv_addr = hashval;
  400. X    *nacc_addr = nacc;
  401. X
  402. X    return ( t );
  403. X    }
  404. X
  405. X
  406. X/* increase_max_dfas - increase the maximum number of DFAs */
  407. X
  408. Xincrease_max_dfas()
  409. X
  410. X    {
  411. X    current_max_dfas += MAX_DFAS_INCREMENT;
  412. X
  413. X    ++num_reallocs;
  414. X
  415. X    base = reallocate_integer_array( base, current_max_dfas );
  416. X    def = reallocate_integer_array( def, current_max_dfas );
  417. X    dfasiz = reallocate_integer_array( dfasiz, current_max_dfas );
  418. X    accsiz = reallocate_integer_array( accsiz, current_max_dfas );
  419. X    dhash = reallocate_integer_array( dhash, current_max_dfas );
  420. X    dss = reallocate_int_ptr_array( dss, current_max_dfas );
  421. X    dfaacc = reallocate_dfaacc_union( dfaacc, current_max_dfas );
  422. X    }
  423. X
  424. X
  425. X/* ntod - convert an ndfa to a dfa
  426. X *
  427. X * synopsis
  428. X *    ntod();
  429. X *
  430. X *  creates the dfa corresponding to the ndfa we've constructed.  the
  431. X *  dfa starts out in state #1.
  432. X */
  433. Xntod()
  434. X
  435. X    {
  436. X    int *accset, ds, nacc, newds;
  437. X    int duplist[CSIZE + 1], sym, hashval, numstates, dsize;
  438. X    int targfreq[CSIZE + 1], targstate[CSIZE + 1], state[CSIZE + 1];
  439. X    int *nset, *dset;
  440. X    int targptr, totaltrans, i, comstate, comfreq, targ;
  441. X    int *epsclosure(), snstods(), symlist[CSIZE + 1];
  442. X    int num_start_states;
  443. X    int todo_head, todo_next;
  444. X
  445. X    /* this is so find_table_space(...) will know where to start looking in
  446. X     * chk/nxt for unused records for space to put in the state
  447. X     */
  448. X    if ( fullspd )
  449. X    firstfree = 0;
  450. X
  451. X    accset = allocate_integer_array( num_rules + 1 );
  452. X    nset = allocate_integer_array( current_max_dfa_size );
  453. X
  454. X    /* the "todo" queue is represented by the head, which is the DFA
  455. X     * state currently being processed, and the "next", which is the
  456. X     * next DFA state number available (not in use).  We depend on the
  457. X     * fact that snstods() returns DFA's \in increasing order/, and thus
  458. X     * need only know the bounds of the dfas to be processed.
  459. X     */
  460. X    todo_head = todo_next = 0;
  461. X
  462. X    for ( i = 0; i <= CSIZE; ++i )
  463. X    {
  464. X    duplist[i] = NIL;
  465. X    symlist[i] = false;
  466. X    }
  467. X
  468. X    for ( i = 0; i <= num_rules; ++i )
  469. X    accset[i] = NIL;
  470. X
  471. X    if ( trace )
  472. X    {
  473. X    dumpnfa( scset[1] );
  474. X    fputs( "\n\nDFA Dump:\n\n", stderr );
  475. X    }
  476. X
  477. X    inittbl();
  478. X
  479. X    if ( fullspd )
  480. X    {
  481. X    for ( i = 0; i <= numecs; ++i )
  482. X        state[i] = 0;
  483. X    place_state( state, 0, 0 );
  484. X    }
  485. X
  486. X    if ( fulltbl )
  487. X    {
  488. X    /* declare it "short" because it's a real long-shot that that
  489. X     * won't be large enough
  490. X     */
  491. X    printf( "static short int %s[][%d] =\n    {\n", NEXTARRAY,
  492. X        numecs + 1 ); /* '}' so vi doesn't get too confused */
  493. X
  494. X    /* generate 0 entries for state #0 */
  495. X    for ( i = 0; i <= numecs; ++i )
  496. X        mk2data( 0 );
  497. X
  498. X    /* force ',' and dataflush() next call to mk2data */
  499. X    datapos = NUMDATAITEMS;
  500. X
  501. X    /* force extra blank line next dataflush() */
  502. X    dataline = NUMDATALINES;
  503. X    }
  504. X
  505. X    /* create the first states */
  506. X
  507. X    num_start_states = lastsc * 2;
  508. X
  509. X    for ( i = 1; i <= num_start_states; ++i )
  510. X    {
  511. X    numstates = 1;
  512. X
  513. X    /* for each start condition, make one state for the case when
  514. X     * we're at the beginning of the line (the '%' operator) and
  515. X     * one for the case when we're not
  516. X     */
  517. X    if ( i % 2 == 1 )
  518. X        nset[numstates] = scset[(i / 2) + 1];
  519. X    else
  520. X        nset[numstates] = mkbranch( scbol[i / 2], scset[i / 2] );
  521. X
  522. X    nset = epsclosure( nset, &numstates, accset, &nacc, &hashval );
  523. X
  524. X    if ( snstods( nset, numstates, accset, nacc, hashval, &ds ) )
  525. X        {
  526. X        numas += nacc;
  527. X        totnst += numstates;
  528. X        ++todo_next;
  529. X
  530. X        if ( variable_trailing_context_rules && nacc > 0 )
  531. X        check_trailing_context( nset, numstates, accset, nacc );
  532. X        }
  533. X    }
  534. X
  535. X    if ( ! fullspd )
  536. X    {
  537. X    if ( ! snstods( nset, 0, accset, 0, 0, &end_of_buffer_state ) )
  538. X        flexfatal( "could not create unique end-of-buffer state" );
  539. X
  540. X    ++numas;
  541. X    ++num_start_states;
  542. X    ++todo_next;
  543. X    }
  544. X
  545. X    while ( todo_head < todo_next )
  546. X    {
  547. X    targptr = 0;
  548. X    totaltrans = 0;
  549. X
  550. X    for ( i = 1; i <= numecs; ++i )
  551. X        state[i] = 0;
  552. X
  553. X    ds = ++todo_head;
  554. X
  555. X    dset = dss[ds];
  556. X    dsize = dfasiz[ds];
  557. X
  558. X    if ( trace )
  559. X        fprintf( stderr, "state # %d:\n", ds );
  560. X
  561. X    sympartition( dset, dsize, symlist, duplist );
  562. X
  563. X    for ( sym = 1; sym <= numecs; ++sym )
  564. X        {
  565. X        if ( symlist[sym] )
  566. X        {
  567. X        symlist[sym] = 0;
  568. X
  569. X        if ( duplist[sym] == NIL )
  570. X            { /* symbol has unique out-transitions */
  571. X            numstates = symfollowset( dset, dsize, sym, nset );
  572. X            nset = epsclosure( nset, &numstates, accset,
  573. X                       &nacc, &hashval );
  574. X
  575. X            if ( snstods( nset, numstates, accset,
  576. X                  nacc, hashval, &newds ) )
  577. X            {
  578. X            totnst = totnst + numstates;
  579. X            ++todo_next;
  580. X            numas += nacc;
  581. X
  582. X            if ( variable_trailing_context_rules && nacc > 0 )
  583. X                check_trailing_context( nset, numstates,
  584. X                accset, nacc );
  585. X            }
  586. X
  587. X            state[sym] = newds;
  588. X
  589. X            if ( trace )
  590. X            fprintf( stderr, "\t%d\t%d\n", sym, newds );
  591. X
  592. X            targfreq[++targptr] = 1;
  593. X            targstate[targptr] = newds;
  594. X            ++numuniq;
  595. X            }
  596. X
  597. X        else
  598. X            {
  599. X            /* sym's equivalence class has the same transitions
  600. X             * as duplist(sym)'s equivalence class
  601. X             */
  602. X            targ = state[duplist[sym]];
  603. X            state[sym] = targ;
  604. X
  605. X            if ( trace )
  606. X            fprintf( stderr, "\t%d\t%d\n", sym, targ );
  607. X
  608. X            /* update frequency count for destination state */
  609. X
  610. X            i = 0;
  611. X            while ( targstate[++i] != targ )
  612. X            ;
  613. X
  614. X            ++targfreq[i];
  615. X            ++numdup;
  616. X            }
  617. X
  618. X        ++totaltrans;
  619. X        duplist[sym] = NIL;
  620. X        }
  621. X        }
  622. X
  623. X    numsnpairs = numsnpairs + totaltrans;
  624. X
  625. X    if ( caseins && ! useecs )
  626. X        {
  627. X        register int j;
  628. X
  629. X        for ( i = 'A', j = 'a'; i <= 'Z'; ++i, ++j )
  630. X        state[i] = state[j];
  631. X        }
  632. X
  633. X    if ( ds > num_start_states )
  634. X        check_for_backtracking( ds, state );
  635. X
  636. X    if ( fulltbl )
  637. X        {
  638. X        /* supply array's 0-element */
  639. X        if ( ds == end_of_buffer_state )
  640. X        mk2data( -end_of_buffer_state );
  641. X        else
  642. X        mk2data( end_of_buffer_state );
  643. X
  644. X        for ( i = 1; i <= numecs; ++i )
  645. X        /* jams are marked by negative of state number */
  646. X        mk2data( state[i] ? state[i] : -ds );
  647. X
  648. X        /* force ',' and dataflush() next call to mk2data */
  649. X        datapos = NUMDATAITEMS;
  650. X
  651. X        /* force extra blank line next dataflush() */
  652. X        dataline = NUMDATALINES;
  653. X        }
  654. X
  655. X        else if ( fullspd )
  656. X        place_state( state, ds, totaltrans );
  657. X
  658. X    else if ( ds == end_of_buffer_state )
  659. X        /* special case this state to make sure it does what it's
  660. X         * supposed to, i.e., jam on end-of-buffer
  661. X         */
  662. X        stack1( ds, 0, 0, JAMSTATE );
  663. X
  664. X    else /* normal, compressed state */
  665. X        {
  666. X        /* determine which destination state is the most common, and
  667. X         * how many transitions to it there are
  668. X         */
  669. X
  670. X        comfreq = 0;
  671. X        comstate = 0;
  672. X
  673. X        for ( i = 1; i <= targptr; ++i )
  674. X        if ( targfreq[i] > comfreq )
  675. X            {
  676. X            comfreq = targfreq[i];
  677. X            comstate = targstate[i];
  678. X            }
  679. X
  680. X        bldtbl( state, ds, totaltrans, comstate, comfreq );
  681. X        }
  682. X    }
  683. X
  684. X    if ( fulltbl )
  685. X    dataend();
  686. X
  687. X    else if ( ! fullspd )
  688. X    {
  689. X    cmptmps();  /* create compressed template entries */
  690. X
  691. X    /* create tables for all the states with only one out-transition */
  692. X    while ( onesp > 0 )
  693. X        {
  694. X        mk1tbl( onestate[onesp], onesym[onesp], onenext[onesp],
  695. X            onedef[onesp] );
  696. X        --onesp;
  697. X        }
  698. X
  699. X    mkdeftbl();
  700. X    }
  701. X    }
  702. X
  703. X
  704. X/* snstods - converts a set of ndfa states into a dfa state
  705. X *
  706. X * synopsis
  707. X *    int sns[numstates], numstates, newds, accset[num_rules + 1], nacc, hashval;
  708. X *    int snstods();
  709. X *    is_new_state = snstods( sns, numstates, accset, nacc, hashval, &newds );
  710. X *
  711. X * on return, the dfa state number is in newds.
  712. X */
  713. X
  714. Xint snstods( sns, numstates, accset, nacc, hashval, newds_addr )
  715. Xint sns[], numstates, accset[], nacc, hashval, *newds_addr;
  716. X
  717. X    {
  718. X    int didsort = 0;
  719. X    register int i, j;
  720. X    int newds, *oldsns;
  721. X    char *malloc();
  722. X
  723. X    for ( i = 1; i <= lastdfa; ++i )
  724. X    if ( hashval == dhash[i] )
  725. X        {
  726. X        if ( numstates == dfasiz[i] )
  727. X        {
  728. X        oldsns = dss[i];
  729. X
  730. X        if ( ! didsort )
  731. X            {
  732. X            /* we sort the states in sns so we can compare it to
  733. X             * oldsns quickly.  we use bubble because there probably
  734. X             * aren't very many states
  735. X             */
  736. X            bubble( sns, numstates );
  737. X            didsort = 1;
  738. X            }
  739. X
  740. X        for ( j = 1; j <= numstates; ++j )
  741. X            if ( sns[j] != oldsns[j] )
  742. X            break;
  743. X
  744. X        if ( j > numstates )
  745. X            {
  746. X            ++dfaeql;
  747. X            *newds_addr = i;
  748. X            return ( 0 );
  749. X            }
  750. X
  751. X        ++hshcol;
  752. X        }
  753. X
  754. X        else
  755. X        ++hshsave;
  756. X        }
  757. X
  758. X    /* make a new dfa */
  759. X
  760. X    if ( ++lastdfa >= current_max_dfas )
  761. X    increase_max_dfas();
  762. X
  763. X    newds = lastdfa;
  764. X
  765. X    dss[newds] = (int *) malloc( (unsigned) ((numstates + 1) * sizeof( int )) );
  766. X
  767. X    if ( ! dss[newds] )
  768. X    flexfatal( "dynamic memory failure in snstods()" );
  769. X
  770. X    /* if we haven't already sorted the states in sns, we do so now, so that
  771. X     * future comparisons with it can be made quickly
  772. X     */
  773. X
  774. X    if ( ! didsort )
  775. X    bubble( sns, numstates );
  776. X
  777. X    for ( i = 1; i <= numstates; ++i )
  778. X    dss[newds][i] = sns[i];
  779. X
  780. X    dfasiz[newds] = numstates;
  781. X    dhash[newds] = hashval;
  782. X
  783. X    if ( nacc == 0 )
  784. X    {
  785. X    if ( reject )
  786. X        dfaacc[newds].dfaacc_set = (int *) 0;
  787. X    else
  788. X        dfaacc[newds].dfaacc_state = 0;
  789. X
  790. X    accsiz[newds] = 0;
  791. X    }
  792. X
  793. X    else if ( reject )
  794. X    {
  795. X    /* we sort the accepting set in increasing order so the disambiguating
  796. X     * rule that the first rule listed is considered match in the event of
  797. X     * ties will work.  We use a bubble sort since the list is probably
  798. X     * quite small.
  799. X     */
  800. X
  801. X    bubble( accset, nacc );
  802. X
  803. X    dfaacc[newds].dfaacc_set =
  804. X        (int *) malloc( (unsigned) ((nacc + 1) * sizeof( int )) );
  805. X
  806. X    if ( ! dfaacc[newds].dfaacc_set )
  807. X        flexfatal( "dynamic memory failure in snstods()" );
  808. X
  809. X    /* save the accepting set for later */
  810. X    for ( i = 1; i <= nacc; ++i )
  811. X        dfaacc[newds].dfaacc_set[i] = accset[i];
  812. X
  813. X    accsiz[newds] = nacc;
  814. X    }
  815. X
  816. X    else
  817. X    { /* find lowest numbered rule so the disambiguating rule will work */
  818. X    j = num_rules + 1;
  819. X
  820. X    for ( i = 1; i <= nacc; ++i )
  821. X        if ( accset[i] < j )
  822. X        j = accset[i];
  823. X
  824. X    dfaacc[newds].dfaacc_state = j;
  825. X    }
  826. X
  827. X    *newds_addr = newds;
  828. X
  829. X    return ( 1 );
  830. X    }
  831. X
  832. X
  833. X/* symfollowset - follow the symbol transitions one step
  834. X *
  835. X * synopsis
  836. X *    int ds[current_max_dfa_size], dsize, transsym;
  837. X *    int nset[current_max_dfa_size], numstates;
  838. X *    numstates = symfollowset( ds, dsize, transsym, nset );
  839. X */
  840. X
  841. Xint symfollowset( ds, dsize, transsym, nset )
  842. Xint ds[], dsize, transsym, nset[];
  843. X
  844. X    {
  845. X    int ns, tsp, sym, i, j, lenccl, ch, numstates;
  846. X    int ccllist;
  847. X
  848. X    numstates = 0;
  849. X
  850. X    for ( i = 1; i <= dsize; ++i )
  851. X    { /* for each nfa state ns in the state set of ds */
  852. X    ns = ds[i];
  853. X    sym = transchar[ns];
  854. X    tsp = trans1[ns];
  855. X
  856. X    if ( sym < 0 )
  857. X        { /* it's a character class */
  858. X        sym = -sym;
  859. X        ccllist = cclmap[sym];
  860. X        lenccl = ccllen[sym];
  861. X
  862. X        if ( cclng[sym] )
  863. X        {
  864. X        for ( j = 0; j < lenccl; ++j )
  865. X            { /* loop through negated character class */
  866. X            ch = ccltbl[ccllist + j];
  867. X
  868. X            if ( ch > transsym )
  869. X            break;    /* transsym isn't in negated ccl */
  870. X
  871. X            else if ( ch == transsym )
  872. X            /* next 2 */ goto bottom;
  873. X            }
  874. X
  875. X        /* didn't find transsym in ccl */
  876. X        nset[++numstates] = tsp;
  877. X        }
  878. X
  879. X        else
  880. X        for ( j = 0; j < lenccl; ++j )
  881. X            {
  882. X            ch = ccltbl[ccllist + j];
  883. X
  884. X            if ( ch > transsym )
  885. X            break;
  886. X
  887. X            else if ( ch == transsym )
  888. X            {
  889. X            nset[++numstates] = tsp;
  890. X            break;
  891. X            }
  892. X            }
  893. X        }
  894. X
  895. X    else if ( sym >= 'A' && sym <= 'Z' && caseins )
  896. X        flexfatal( "consistency check failed in symfollowset" );
  897. X
  898. X    else if ( sym == SYM_EPSILON )
  899. X        { /* do nothing */
  900. X        }
  901. X
  902. X    else if ( ecgroup[sym] == transsym )
  903. X        nset[++numstates] = tsp;
  904. X
  905. Xbottom:
  906. X    ;
  907. X    }
  908. X
  909. X    return ( numstates );
  910. X    }
  911. X
  912. X
  913. X/* sympartition - partition characters with same out-transitions
  914. X *
  915. X * synopsis
  916. X *    integer ds[current_max_dfa_size], numstates, duplist[numecs];
  917. X *    symlist[numecs];
  918. X *    sympartition( ds, numstates, symlist, duplist );
  919. X */
  920. X
  921. Xsympartition( ds, numstates, symlist, duplist )
  922. Xint ds[], numstates, duplist[];
  923. Xint symlist[];
  924. X
  925. X    {
  926. X    int tch, i, j, k, ns, dupfwd[CSIZE + 1], lenccl, cclp, ich;
  927. X
  928. X    /* partitioning is done by creating equivalence classes for those
  929. X     * characters which have out-transitions from the given state.  Thus
  930. X     * we are really creating equivalence classes of equivalence classes.
  931. X     */
  932. X
  933. X    for ( i = 1; i <= numecs; ++i )
  934. X    { /* initialize equivalence class list */
  935. X    duplist[i] = i - 1;
  936. X    dupfwd[i] = i + 1;
  937. X    }
  938. X
  939. X    duplist[1] = NIL;
  940. X    dupfwd[numecs] = NIL;
  941. X
  942. X    for ( i = 1; i <= numstates; ++i )
  943. X    {
  944. X    ns = ds[i];
  945. X    tch = transchar[ns];
  946. X
  947. X    if ( tch != SYM_EPSILON )
  948. X        {
  949. X        if ( tch < -lastccl || tch > CSIZE )
  950. X        flexfatal( "bad transition character detected in sympartition()" );
  951. X
  952. X        if ( tch > 0 )
  953. X        { /* character transition */
  954. X        mkechar( ecgroup[tch], dupfwd, duplist );
  955. X        symlist[ecgroup[tch]] = 1;
  956. X        }
  957. X
  958. X        else
  959. X        { /* character class */
  960. X        tch = -tch;
  961. X
  962. X        lenccl = ccllen[tch];
  963. X        cclp = cclmap[tch];
  964. X        mkeccl( ccltbl + cclp, lenccl, dupfwd, duplist, numecs );
  965. X
  966. X        if ( cclng[tch] )
  967. X            {
  968. X            j = 0;
  969. X
  970. X            for ( k = 0; k < lenccl; ++k )
  971. X            {
  972. X            ich = ccltbl[cclp + k];
  973. X
  974. X            for ( ++j; j < ich; ++j )
  975. X                symlist[j] = 1;
  976. X            }
  977. X
  978. X            for ( ++j; j <= numecs; ++j )
  979. X            symlist[j] = 1;
  980. X            }
  981. X
  982. X        else
  983. X            for ( k = 0; k < lenccl; ++k )
  984. X            {
  985. X            ich = ccltbl[cclp + k];
  986. X            symlist[ich] = 1;
  987. X            }
  988. X        }
  989. X        }
  990. X    }
  991. X    }
  992. END_OF_FILE
  993. if test 22852 -ne `wc -c <'flex/dfa.c'`; then
  994.     echo shar: \"'flex/dfa.c'\" unpacked with wrong size!
  995. fi
  996. # end of 'flex/dfa.c'
  997. fi
  998. if test -f 'flex/tblcmp.c' -a "${1}" != "-c" ; then 
  999.   echo shar: Will not clobber existing file \"'flex/tblcmp.c'\"
  1000. else
  1001. echo shar: Extracting \"'flex/tblcmp.c'\" \(24794 characters\)
  1002. sed "s/^X//" >'flex/tblcmp.c' <<'END_OF_FILE'
  1003. X/* tblcmp - table compression routines */
  1004. X
  1005. X/*
  1006. X * Copyright (c) 1989 The Regents of the University of California.
  1007. X * All rights reserved.
  1008. X *
  1009. X * This code is derived from software contributed to Berkeley by
  1010. X * Vern Paxson.
  1011. X * 
  1012. X * The United States Government has rights in this work pursuant to
  1013. X * contract no. DE-AC03-76SF00098 between the United States Department of
  1014. X * Energy and the University of California.
  1015. X *
  1016. X * Redistribution and use in source and binary forms are permitted
  1017. X * provided that the above copyright notice and this paragraph are
  1018. X * duplicated in all such forms and that any documentation,
  1019. X * advertising materials, and other materials related to such
  1020. X * distribution and use acknowledge that the software was developed
  1021. X * by the University of California, Berkeley.  The name of the
  1022. X * University may not be used to endorse or promote products derived
  1023. X * from this software without specific prior written permission.
  1024. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  1025. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  1026. X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  1027. X */
  1028. X
  1029. X#ifndef lint
  1030. X
  1031. Xstatic char copyright[] =
  1032. X    "@(#) Copyright (c) 1989 The Regents of the University of California.\n";
  1033. Xstatic char CR_continuation[] = "@(#) All rights reserved.\n";
  1034. X
  1035. Xstatic char rcsid[] =
  1036. X    "@(#) $Header: tblcmp.c,v 2.0 89/06/20 15:50:21 vern Locked $ (LBL)";
  1037. X
  1038. X#endif
  1039. X
  1040. X#include "flexdef.h"
  1041. X
  1042. X/* bldtbl - build table entries for dfa state
  1043. X *
  1044. X * synopsis
  1045. X *   int state[numecs], statenum, totaltrans, comstate, comfreq;
  1046. X *   bldtbl( state, statenum, totaltrans, comstate, comfreq );
  1047. X *
  1048. X * State is the statenum'th dfa state.  It is indexed by equivalence class and
  1049. X * gives the number of the state to enter for a given equivalence class.
  1050. X * totaltrans is the total number of transitions out of the state.  Comstate
  1051. X * is that state which is the destination of the most transitions out of State.
  1052. X * Comfreq is how many transitions there are out of State to Comstate.
  1053. X *
  1054. X * A note on terminology:
  1055. X *    "protos" are transition tables which have a high probability of
  1056. X * either being redundant (a state processed later will have an identical
  1057. X * transition table) or nearly redundant (a state processed later will have
  1058. X * many of the same out-transitions).  A "most recently used" queue of
  1059. X * protos is kept around with the hope that most states will find a proto
  1060. X * which is similar enough to be usable, and therefore compacting the
  1061. X * output tables.
  1062. X *    "templates" are a special type of proto.  If a transition table is
  1063. X * homogeneous or nearly homogeneous (all transitions go to the same
  1064. X * destination) then the odds are good that future states will also go
  1065. X * to the same destination state on basically the same character set.
  1066. X * These homogeneous states are so common when dealing with large rule
  1067. X * sets that they merit special attention.  If the transition table were
  1068. X * simply made into a proto, then (typically) each subsequent, similar
  1069. X * state will differ from the proto for two out-transitions.  One of these
  1070. X * out-transitions will be that character on which the proto does not go
  1071. X * to the common destination, and one will be that character on which the
  1072. X * state does not go to the common destination.  Templates, on the other
  1073. X * hand, go to the common state on EVERY transition character, and therefore
  1074. X * cost only one difference.
  1075. X */
  1076. X
  1077. Xbldtbl( state, statenum, totaltrans, comstate, comfreq )
  1078. Xint state[], statenum, totaltrans, comstate, comfreq;
  1079. X
  1080. X    {
  1081. X    int extptr, extrct[2][CSIZE + 1];
  1082. X    int mindiff, minprot, i, d;
  1083. X    int checkcom;
  1084. X
  1085. X    /* If extptr is 0 then the first array of extrct holds the result of the
  1086. X     * "best difference" to date, which is those transitions which occur in
  1087. X     * "state" but not in the proto which, to date, has the fewest differences
  1088. X     * between itself and "state".  If extptr is 1 then the second array of
  1089. X     * extrct hold the best difference.  The two arrays are toggled
  1090. X     * between so that the best difference to date can be kept around and
  1091. X     * also a difference just created by checking against a candidate "best"
  1092. X     * proto.
  1093. X     */
  1094. X
  1095. X    extptr = 0;
  1096. X
  1097. X    /* if the state has too few out-transitions, don't bother trying to
  1098. X     * compact its tables
  1099. X     */
  1100. X
  1101. X    if ( (totaltrans * 100) < (numecs * PROTO_SIZE_PERCENTAGE) )
  1102. X    mkentry( state, numecs, statenum, JAMSTATE, totaltrans );
  1103. X
  1104. X    else
  1105. X    {
  1106. X    /* checkcom is true if we should only check "state" against
  1107. X     * protos which have the same "comstate" value
  1108. X     */
  1109. X
  1110. X    checkcom = comfreq * 100 > totaltrans * CHECK_COM_PERCENTAGE;
  1111. X
  1112. X    minprot = firstprot;
  1113. X    mindiff = totaltrans;
  1114. X
  1115. X    if ( checkcom )
  1116. X        {
  1117. X        /* find first proto which has the same "comstate" */
  1118. X        for ( i = firstprot; i != NIL; i = protnext[i] )
  1119. X        if ( protcomst[i] == comstate )
  1120. X            {
  1121. X            minprot = i;
  1122. X            mindiff = tbldiff( state, minprot, extrct[extptr] );
  1123. X            break;
  1124. X            }
  1125. X        }
  1126. X
  1127. X    else
  1128. X        {
  1129. X        /* since we've decided that the most common destination out
  1130. X         * of "state" does not occur with a high enough frequency,
  1131. X         * we set the "comstate" to zero, assuring that if this state
  1132. X         * is entered into the proto list, it will not be considered
  1133. X         * a template.
  1134. X         */
  1135. X        comstate = 0;
  1136. X
  1137. X        if ( firstprot != NIL )
  1138. X        {
  1139. X        minprot = firstprot;
  1140. X        mindiff = tbldiff( state, minprot, extrct[extptr] );
  1141. X        }
  1142. X        }
  1143. X
  1144. X    /* we now have the first interesting proto in "minprot".  If
  1145. X     * it matches within the tolerances set for the first proto,
  1146. X     * we don't want to bother scanning the rest of the proto list
  1147. X     * to see if we have any other reasonable matches.
  1148. X     */
  1149. X
  1150. X    if ( mindiff * 100 > totaltrans * FIRST_MATCH_DIFF_PERCENTAGE )
  1151. X        { /* not a good enough match.  Scan the rest of the protos */
  1152. X        for ( i = minprot; i != NIL; i = protnext[i] )
  1153. X        {
  1154. X        d = tbldiff( state, i, extrct[1 - extptr] );
  1155. X        if ( d < mindiff )
  1156. X            {
  1157. X            extptr = 1 - extptr;
  1158. X            mindiff = d;
  1159. X            minprot = i;
  1160. X            }
  1161. X        }
  1162. X        }
  1163. X
  1164. X    /* check if the proto we've decided on as our best bet is close
  1165. X     * enough to the state we want to match to be usable
  1166. X     */
  1167. X
  1168. X    if ( mindiff * 100 > totaltrans * ACCEPTABLE_DIFF_PERCENTAGE )
  1169. X        {
  1170. X        /* no good.  If the state is homogeneous enough, we make a
  1171. X         * template out of it.  Otherwise, we make a proto.
  1172. X         */
  1173. X
  1174. X        if ( comfreq * 100 >= totaltrans * TEMPLATE_SAME_PERCENTAGE )
  1175. X        mktemplate( state, statenum, comstate );
  1176. X
  1177. X        else
  1178. X        {
  1179. X        mkprot( state, statenum, comstate );
  1180. X        mkentry( state, numecs, statenum, JAMSTATE, totaltrans );
  1181. X        }
  1182. X        }
  1183. X
  1184. X    else
  1185. X        { /* use the proto */
  1186. X        mkentry( extrct[extptr], numecs, statenum,
  1187. X             prottbl[minprot], mindiff );
  1188. X
  1189. X        /* if this state was sufficiently different from the proto
  1190. X         * we built it from, make it, too, a proto
  1191. X         */
  1192. X
  1193. X        if ( mindiff * 100 >= totaltrans * NEW_PROTO_DIFF_PERCENTAGE )
  1194. X        mkprot( state, statenum, comstate );
  1195. X
  1196. X        /* since mkprot added a new proto to the proto queue, it's possible
  1197. X         * that "minprot" is no longer on the proto queue (if it happened
  1198. X         * to have been the last entry, it would have been bumped off).
  1199. X         * If it's not there, then the new proto took its physical place
  1200. X         * (though logically the new proto is at the beginning of the
  1201. X         * queue), so in that case the following call will do nothing.
  1202. X         */
  1203. X
  1204. X        mv2front( minprot );
  1205. X        }
  1206. X    }
  1207. X    }
  1208. X
  1209. X
  1210. X/* cmptmps - compress template table entries
  1211. X *
  1212. X * synopsis
  1213. X *    cmptmps();
  1214. X *
  1215. X *  template tables are compressed by using the 'template equivalence
  1216. X *  classes', which are collections of transition character equivalence
  1217. X *  classes which always appear together in templates - really meta-equivalence
  1218. X *  classes.  until this point, the tables for templates have been stored
  1219. X *  up at the top end of the nxt array; they will now be compressed and have
  1220. X *  table entries made for them.
  1221. X */
  1222. X
  1223. Xcmptmps()
  1224. X
  1225. X    {
  1226. X    int tmpstorage[CSIZE + 1];
  1227. X    register int *tmp = tmpstorage, i, j;
  1228. X    int totaltrans, trans;
  1229. X
  1230. X    peakpairs = numtemps * numecs + tblend;
  1231. X
  1232. X    if ( usemecs )
  1233. X    {
  1234. X    /* create equivalence classes base on data gathered on template
  1235. X     * transitions
  1236. X     */
  1237. X
  1238. X    nummecs = cre8ecs( tecfwd, tecbck, numecs );
  1239. X    }
  1240. X    
  1241. X    else
  1242. X    nummecs = numecs;
  1243. X
  1244. X    if ( lastdfa + numtemps + 1 >= current_max_dfas )
  1245. X    increase_max_dfas();
  1246. X
  1247. X    /* loop through each template */
  1248. X
  1249. X    for ( i = 1; i <= numtemps; ++i )
  1250. X    {
  1251. X    totaltrans = 0;    /* number of non-jam transitions out of this template */
  1252. X
  1253. X    for ( j = 1; j <= numecs; ++j )
  1254. X        {
  1255. X        trans = tnxt[numecs * i + j];
  1256. X
  1257. X        if ( usemecs )
  1258. X        {
  1259. X        /* the absolute value of tecbck is the meta-equivalence class
  1260. X         * of a given equivalence class, as set up by cre8ecs
  1261. X         */
  1262. X        if ( tecbck[j] > 0 )
  1263. X            {
  1264. X            tmp[tecbck[j]] = trans;
  1265. X
  1266. X            if ( trans > 0 )
  1267. X            ++totaltrans;
  1268. X            }
  1269. X        }
  1270. X
  1271. X        else
  1272. X        {
  1273. X        tmp[j] = trans;
  1274. X
  1275. X        if ( trans > 0 )
  1276. X            ++totaltrans;
  1277. X        }
  1278. X        }
  1279. X
  1280. X    /* it is assumed (in a rather subtle way) in the skeleton that
  1281. X     * if we're using meta-equivalence classes, the def[] entry for
  1282. X     * all templates is the jam template, i.e., templates never default
  1283. X     * to other non-jam table entries (e.g., another template)
  1284. X     */
  1285. X
  1286. X    /* leave room for the jam-state after the last real state */
  1287. X    mkentry( tmp, nummecs, lastdfa + i + 1, JAMSTATE, totaltrans );
  1288. X    }
  1289. X    }
  1290. X
  1291. X
  1292. X
  1293. X/* expand_nxt_chk - expand the next check arrays */
  1294. X
  1295. Xexpand_nxt_chk()
  1296. X
  1297. X    {
  1298. X    register int old_max = current_max_xpairs;
  1299. X
  1300. X    current_max_xpairs += MAX_XPAIRS_INCREMENT;
  1301. X
  1302. X    ++num_reallocs;
  1303. X
  1304. X    nxt = reallocate_integer_array( nxt, current_max_xpairs );
  1305. X    chk = reallocate_integer_array( chk, current_max_xpairs );
  1306. X
  1307. X    bzero( (char *) (chk + old_max),
  1308. X       MAX_XPAIRS_INCREMENT * sizeof( int ) / sizeof( char ) );
  1309. X    }
  1310. X
  1311. X
  1312. X/* find_table_space - finds a space in the table for a state to be placed
  1313. X *
  1314. X * synopsis
  1315. X *     int *state, numtrans, block_start;
  1316. X *     int find_table_space();
  1317. X *
  1318. X *     block_start = find_table_space( state, numtrans );
  1319. X *
  1320. X * State is the state to be added to the full speed transition table.
  1321. X * Numtrans is the number of out-transitions for the state.
  1322. X *
  1323. X * find_table_space() returns the position of the start of the first block (in
  1324. X * chk) able to accommodate the state
  1325. X *
  1326. X * In determining if a state will or will not fit, find_table_space() must take
  1327. X * into account the fact that an end-of-buffer state will be added at [0],
  1328. X * and an action number will be added in [-1].
  1329. X */
  1330. X
  1331. Xint find_table_space( state, numtrans )
  1332. Xint *state, numtrans;
  1333. X    
  1334. X    {
  1335. X    /* firstfree is the position of the first possible occurrence of two
  1336. X     * consecutive unused records in the chk and nxt arrays
  1337. X     */
  1338. X    register int i;
  1339. X    register int *state_ptr, *chk_ptr;
  1340. X    register int *ptr_to_last_entry_in_state;
  1341. X
  1342. X    /* if there are too many out-transitions, put the state at the end of
  1343. X     * nxt and chk
  1344. X     */
  1345. X    if ( numtrans > MAX_XTIONS_FULL_INTERIOR_FIT )
  1346. X    {
  1347. X    /* if table is empty, return the first available spot in chk/nxt,
  1348. X     * which should be 1
  1349. X     */
  1350. X    if ( tblend < 2 )
  1351. X        return ( 1 );
  1352. X
  1353. X    i = tblend - numecs;    /* start searching for table space near the
  1354. X                 * end of chk/nxt arrays
  1355. X                 */
  1356. X    }
  1357. X
  1358. X    else
  1359. X    i = firstfree;        /* start searching for table space from the
  1360. X                 * beginning (skipping only the elements
  1361. X                 * which will definitely not hold the new
  1362. X                 * state)
  1363. X                 */
  1364. X
  1365. X    while ( 1 )        /* loops until a space is found */
  1366. X    {
  1367. X    if ( i + numecs > current_max_xpairs )
  1368. X        expand_nxt_chk();
  1369. X
  1370. X    /* loops until space for end-of-buffer and action number are found */
  1371. X    while ( 1 )
  1372. X        {
  1373. X        if ( chk[i - 1] == 0 )    /* check for action number space */
  1374. X        {
  1375. X        if ( chk[i] == 0 )    /* check for end-of-buffer space */
  1376. X            break;
  1377. X
  1378. X        else
  1379. X            i += 2;    /* since i != 0, there is no use checking to
  1380. X                 * see if (++i) - 1 == 0, because that's the
  1381. X                 * same as i == 0, so we skip a space
  1382. X                 */
  1383. X        }
  1384. X
  1385. X        else
  1386. X        ++i;
  1387. X
  1388. X        if ( i + numecs > current_max_xpairs )
  1389. X        expand_nxt_chk();
  1390. X        }
  1391. X
  1392. X    /* if we started search from the beginning, store the new firstfree for
  1393. X     * the next call of find_table_space()
  1394. X     */
  1395. X    if ( numtrans <= MAX_XTIONS_FULL_INTERIOR_FIT )
  1396. X        firstfree = i + 1;
  1397. X
  1398. X    /* check to see if all elements in chk (and therefore nxt) that are
  1399. X     * needed for the new state have not yet been taken
  1400. X     */
  1401. X
  1402. X    state_ptr = &state[1];
  1403. X    ptr_to_last_entry_in_state = &chk[i + numecs + 1];
  1404. X
  1405. X    for ( chk_ptr = &chk[i + 1]; chk_ptr != ptr_to_last_entry_in_state;
  1406. X          ++chk_ptr )
  1407. X        if ( *(state_ptr++) != 0 && *chk_ptr != 0 )
  1408. X        break;
  1409. X
  1410. X    if ( chk_ptr == ptr_to_last_entry_in_state )
  1411. X        return ( i );
  1412. X
  1413. X    else
  1414. X        ++i;
  1415. X    }
  1416. X    }
  1417. X
  1418. X
  1419. X/* inittbl - initialize transition tables
  1420. X *
  1421. X * synopsis
  1422. X *   inittbl();
  1423. X *
  1424. X * Initializes "firstfree" to be one beyond the end of the table.  Initializes
  1425. X * all "chk" entries to be zero.  Note that templates are built in their
  1426. X * own tbase/tdef tables.  They are shifted down to be contiguous
  1427. X * with the non-template entries during table generation.
  1428. X */
  1429. Xinittbl()
  1430. X
  1431. X    {
  1432. X    register int i;
  1433. X
  1434. X    bzero( (char *) chk, current_max_xpairs * sizeof( int ) / sizeof( char ) );
  1435. X
  1436. X    tblend = 0;
  1437. X    firstfree = tblend + 1;
  1438. X    numtemps = 0;
  1439. X
  1440. X    if ( usemecs )
  1441. X    {
  1442. X    /* set up doubly-linked meta-equivalence classes
  1443. X     * these are sets of equivalence classes which all have identical
  1444. X     * transitions out of TEMPLATES
  1445. X     */
  1446. X
  1447. X    tecbck[1] = NIL;
  1448. X
  1449. X    for ( i = 2; i <= numecs; ++i )
  1450. X        {
  1451. X        tecbck[i] = i - 1;
  1452. X        tecfwd[i - 1] = i;
  1453. X        }
  1454. X
  1455. X    tecfwd[numecs] = NIL;
  1456. X    }
  1457. X    }
  1458. X
  1459. X
  1460. X/* mkdeftbl - make the default, "jam" table entries
  1461. X *
  1462. X * synopsis
  1463. X *   mkdeftbl();
  1464. X */
  1465. X
  1466. Xmkdeftbl()
  1467. X
  1468. X    {
  1469. X    int i;
  1470. X
  1471. X    jamstate = lastdfa + 1;
  1472. X
  1473. X    ++tblend; /* room for transition on end-of-buffer character */
  1474. X
  1475. X    if ( tblend + numecs > current_max_xpairs )
  1476. X    expand_nxt_chk();
  1477. X
  1478. X    /* add in default end-of-buffer transition */
  1479. X    nxt[tblend] = end_of_buffer_state;
  1480. X    chk[tblend] = jamstate;
  1481. X
  1482. X    for ( i = 1; i <= numecs; ++i )
  1483. X    {
  1484. X    nxt[tblend + i] = 0;
  1485. X    chk[tblend + i] = jamstate;
  1486. X    }
  1487. X
  1488. X    jambase = tblend;
  1489. X
  1490. X    base[jamstate] = jambase;
  1491. X    def[jamstate] = 0;
  1492. X
  1493. X    tblend += numecs;
  1494. X    ++numtemps;
  1495. X    }
  1496. X
  1497. X
  1498. X/* mkentry - create base/def and nxt/chk entries for transition array
  1499. X *
  1500. X * synopsis
  1501. X *   int state[numchars + 1], numchars, statenum, deflink, totaltrans;
  1502. X *   mkentry( state, numchars, statenum, deflink, totaltrans );
  1503. X *
  1504. X * "state" is a transition array "numchars" characters in size, "statenum"
  1505. X * is the offset to be used into the base/def tables, and "deflink" is the
  1506. X * entry to put in the "def" table entry.  If "deflink" is equal to
  1507. X * "JAMSTATE", then no attempt will be made to fit zero entries of "state"
  1508. X * (i.e., jam entries) into the table.  It is assumed that by linking to
  1509. X * "JAMSTATE" they will be taken care of.  In any case, entries in "state"
  1510. X * marking transitions to "SAME_TRANS" are treated as though they will be
  1511. X * taken care of by whereever "deflink" points.  "totaltrans" is the total
  1512. X * number of transitions out of the state.  If it is below a certain threshold,
  1513. X * the tables are searched for an interior spot that will accommodate the
  1514. X * state array.
  1515. X */
  1516. X
  1517. Xmkentry( state, numchars, statenum, deflink, totaltrans )
  1518. Xregister int *state;
  1519. Xint numchars, statenum, deflink, totaltrans;
  1520. X
  1521. X    {
  1522. X    register int minec, maxec, i, baseaddr;
  1523. X    int tblbase, tbllast;
  1524. X
  1525. X    if ( totaltrans == 0 )
  1526. X    { /* there are no out-transitions */
  1527. X    if ( deflink == JAMSTATE )
  1528. X        base[statenum] = JAMSTATE;
  1529. X    else
  1530. X        base[statenum] = 0;
  1531. X
  1532. X    def[statenum] = deflink;
  1533. X    return;
  1534. X    }
  1535. X
  1536. X    for ( minec = 1; minec <= numchars; ++minec )
  1537. X    {
  1538. X    if ( state[minec] != SAME_TRANS )
  1539. X        if ( state[minec] != 0 || deflink != JAMSTATE )
  1540. X        break;
  1541. X    }
  1542. X
  1543. X    if ( totaltrans == 1 )
  1544. X    {
  1545. X    /* there's only one out-transition.  Save it for later to fill
  1546. X     * in holes in the tables.
  1547. X     */
  1548. X    stack1( statenum, minec, state[minec], deflink );
  1549. X    return;
  1550. X    }
  1551. X
  1552. X    for ( maxec = numchars; maxec > 0; --maxec )
  1553. X    {
  1554. X    if ( state[maxec] != SAME_TRANS )
  1555. X        if ( state[maxec] != 0 || deflink != JAMSTATE )
  1556. X        break;
  1557. X    }
  1558. X
  1559. X    /* Whether we try to fit the state table in the middle of the table
  1560. X     * entries we have already generated, or if we just take the state
  1561. X     * table at the end of the nxt/chk tables, we must make sure that we
  1562. X     * have a valid base address (i.e., non-negative).  Note that not only are
  1563. X     * negative base addresses dangerous at run-time (because indexing the
  1564. X     * next array with one and a low-valued character might generate an
  1565. X     * array-out-of-bounds error message), but at compile-time negative
  1566. X     * base addresses denote TEMPLATES.
  1567. X     */
  1568. X
  1569. X    /* find the first transition of state that we need to worry about. */
  1570. X    if ( totaltrans * 100 <= numchars * INTERIOR_FIT_PERCENTAGE )
  1571. X    { /* attempt to squeeze it into the middle of the tabls */
  1572. X    baseaddr = firstfree;
  1573. X
  1574. X    while ( baseaddr < minec )
  1575. X        {
  1576. X        /* using baseaddr would result in a negative base address below
  1577. X         * find the next free slot
  1578. X         */
  1579. X        for ( ++baseaddr; chk[baseaddr] != 0; ++baseaddr )
  1580. X        ;
  1581. X        }
  1582. X
  1583. X    if ( baseaddr + maxec - minec >= current_max_xpairs )
  1584. X        expand_nxt_chk();
  1585. X
  1586. X    for ( i = minec; i <= maxec; ++i )
  1587. X        if ( state[i] != SAME_TRANS )
  1588. X        if ( state[i] != 0 || deflink != JAMSTATE )
  1589. X            if ( chk[baseaddr + i - minec] != 0 )
  1590. X            { /* baseaddr unsuitable - find another */
  1591. X            for ( ++baseaddr;
  1592. X                  baseaddr < current_max_xpairs &&
  1593. X                  chk[baseaddr] != 0;
  1594. X                  ++baseaddr )
  1595. X                ;
  1596. X
  1597. X            if ( baseaddr + maxec - minec >= current_max_xpairs )
  1598. X                expand_nxt_chk();
  1599. X
  1600. X            /* reset the loop counter so we'll start all
  1601. X             * over again next time it's incremented
  1602. X             */
  1603. X
  1604. X            i = minec - 1;
  1605. X            }
  1606. X    }
  1607. X
  1608. X    else
  1609. X    {
  1610. X    /* ensure that the base address we eventually generate is
  1611. X     * non-negative
  1612. X     */
  1613. X    baseaddr = max( tblend + 1, minec );
  1614. X    }
  1615. X
  1616. X    tblbase = baseaddr - minec;
  1617. X    tbllast = tblbase + maxec;
  1618. X
  1619. X    if ( tbllast >= current_max_xpairs )
  1620. X    expand_nxt_chk();
  1621. X
  1622. X    base[statenum] = tblbase;
  1623. X    def[statenum] = deflink;
  1624. X
  1625. X    for ( i = minec; i <= maxec; ++i )
  1626. X    if ( state[i] != SAME_TRANS )
  1627. X        if ( state[i] != 0 || deflink != JAMSTATE )
  1628. X        {
  1629. X        nxt[tblbase + i] = state[i];
  1630. X        chk[tblbase + i] = statenum;
  1631. X        }
  1632. X
  1633. X    if ( baseaddr == firstfree )
  1634. X    /* find next free slot in tables */
  1635. X    for ( ++firstfree; chk[firstfree] != 0; ++firstfree )
  1636. X        ;
  1637. X
  1638. X    tblend = max( tblend, tbllast );
  1639. X    }
  1640. X
  1641. X
  1642. X/* mk1tbl - create table entries for a state (or state fragment) which
  1643. X *            has only one out-transition
  1644. X *
  1645. X * synopsis
  1646. X *   int state, sym, onenxt, onedef;
  1647. X *   mk1tbl( state, sym, onenxt, onedef );
  1648. X */
  1649. X
  1650. Xmk1tbl( state, sym, onenxt, onedef )
  1651. Xint state, sym, onenxt, onedef;
  1652. X
  1653. X    {
  1654. X    if ( firstfree < sym )
  1655. X    firstfree = sym;
  1656. X
  1657. X    while ( chk[firstfree] != 0 )
  1658. X    if ( ++firstfree >= current_max_xpairs )
  1659. X        expand_nxt_chk();
  1660. X
  1661. X    base[state] = firstfree - sym;
  1662. X    def[state] = onedef;
  1663. X    chk[firstfree] = state;
  1664. X    nxt[firstfree] = onenxt;
  1665. X
  1666. X    if ( firstfree > tblend )
  1667. X    {
  1668. X    tblend = firstfree++;
  1669. X
  1670. X    if ( firstfree >= current_max_xpairs )
  1671. X        expand_nxt_chk();
  1672. X    }
  1673. X    }
  1674. X
  1675. X
  1676. X/* mkprot - create new proto entry
  1677. X *
  1678. X * synopsis
  1679. X *   int state[], statenum, comstate;
  1680. X *   mkprot( state, statenum, comstate );
  1681. X */
  1682. X
  1683. Xmkprot( state, statenum, comstate )
  1684. Xint state[], statenum, comstate;
  1685. X
  1686. X    {
  1687. X    int i, slot, tblbase;
  1688. X
  1689. X    if ( ++numprots >= MSP || numecs * numprots >= PROT_SAVE_SIZE )
  1690. X    {
  1691. X    /* gotta make room for the new proto by dropping last entry in
  1692. X     * the queue
  1693. X     */
  1694. X    slot = lastprot;
  1695. X    lastprot = protprev[lastprot];
  1696. X    protnext[lastprot] = NIL;
  1697. X    }
  1698. X
  1699. X    else
  1700. X    slot = numprots;
  1701. X
  1702. X    protnext[slot] = firstprot;
  1703. X
  1704. X    if ( firstprot != NIL )
  1705. X    protprev[firstprot] = slot;
  1706. X
  1707. X    firstprot = slot;
  1708. X    prottbl[slot] = statenum;
  1709. X    protcomst[slot] = comstate;
  1710. X
  1711. X    /* copy state into save area so it can be compared with rapidly */
  1712. X    tblbase = numecs * (slot - 1);
  1713. X
  1714. X    for ( i = 1; i <= numecs; ++i )
  1715. X    protsave[tblbase + i] = state[i];
  1716. X    }
  1717. X
  1718. X
  1719. X/* mktemplate - create a template entry based on a state, and connect the state
  1720. X *              to it
  1721. X *
  1722. X * synopsis
  1723. X *   int state[], statenum, comstate, totaltrans;
  1724. X *   mktemplate( state, statenum, comstate, totaltrans );
  1725. X */
  1726. X
  1727. Xmktemplate( state, statenum, comstate )
  1728. Xint state[], statenum, comstate;
  1729. X
  1730. X    {
  1731. X    int i, numdiff, tmpbase, tmp[CSIZE + 1];
  1732. X    char transset[CSIZE + 1];
  1733. X    int tsptr;
  1734. X
  1735. X    ++numtemps;
  1736. X
  1737. X    tsptr = 0;
  1738. X
  1739. X    /* calculate where we will temporarily store the transition table
  1740. X     * of the template in the tnxt[] array.  The final transition table
  1741. X     * gets created by cmptmps()
  1742. X     */
  1743. X
  1744. X    tmpbase = numtemps * numecs;
  1745. X
  1746. X    if ( tmpbase + numecs >= current_max_template_xpairs )
  1747. X    {
  1748. X    current_max_template_xpairs += MAX_TEMPLATE_XPAIRS_INCREMENT;
  1749. X
  1750. X    ++num_reallocs;
  1751. X
  1752. X    tnxt = reallocate_integer_array( tnxt, current_max_template_xpairs );
  1753. X    }
  1754. X
  1755. X    for ( i = 1; i <= numecs; ++i )
  1756. X    if ( state[i] == 0 )
  1757. X        tnxt[tmpbase + i] = 0;
  1758. X    else
  1759. X        {
  1760. X        transset[tsptr++] = i;
  1761. X        tnxt[tmpbase + i] = comstate;
  1762. X        }
  1763. X
  1764. X    if ( usemecs )
  1765. X    mkeccl( transset, tsptr, tecfwd, tecbck, numecs );
  1766. X
  1767. X    mkprot( tnxt + tmpbase, -numtemps, comstate );
  1768. X
  1769. X    /* we rely on the fact that mkprot adds things to the beginning
  1770. X     * of the proto queue
  1771. X     */
  1772. X
  1773. X    numdiff = tbldiff( state, firstprot, tmp );
  1774. X    mkentry( tmp, numecs, statenum, -numtemps, numdiff );
  1775. X    }
  1776. X
  1777. X
  1778. X/* mv2front - move proto queue element to front of queue
  1779. X *
  1780. X * synopsis
  1781. X *   int qelm;
  1782. X *   mv2front( qelm );
  1783. X */
  1784. X
  1785. Xmv2front( qelm )
  1786. Xint qelm;
  1787. X
  1788. X    {
  1789. X    if ( firstprot != qelm )
  1790. X    {
  1791. X    if ( qelm == lastprot )
  1792. X        lastprot = protprev[lastprot];
  1793. X
  1794. X    protnext[protprev[qelm]] = protnext[qelm];
  1795. X
  1796. X    if ( protnext[qelm] != NIL )
  1797. X        protprev[protnext[qelm]] = protprev[qelm];
  1798. X
  1799. X    protprev[qelm] = NIL;
  1800. X    protnext[qelm] = firstprot;
  1801. X    protprev[firstprot] = qelm;
  1802. X    firstprot = qelm;
  1803. X    }
  1804. X    }
  1805. X
  1806. X
  1807. X/* place_state - place a state into full speed transition table
  1808. X *
  1809. X * synopsis
  1810. X *     int *state, statenum, transnum;
  1811. X *     place_state( state, statenum, transnum );
  1812. X *
  1813. X * State is the statenum'th state.  It is indexed by equivalence class and
  1814. X * gives the number of the state to enter for a given equivalence class.
  1815. X * Transnum is the number of out-transitions for the state.
  1816. X */
  1817. X
  1818. Xplace_state( state, statenum, transnum )
  1819. Xint *state, statenum, transnum;
  1820. X
  1821. X    {
  1822. X    register int i;
  1823. X    register int *state_ptr;
  1824. X    int position = find_table_space( state, transnum );
  1825. X
  1826. X    /* base is the table of start positions */
  1827. X    base[statenum] = position;
  1828. X
  1829. X    /* put in action number marker; this non-zero number makes sure that
  1830. X     * find_table_space() knows that this position in chk/nxt is taken
  1831. X     * and should not be used for another accepting number in another state
  1832. X     */
  1833. X    chk[position - 1] = 1;
  1834. X
  1835. X    /* put in end-of-buffer marker; this is for the same purposes as above */
  1836. X    chk[position] = 1;
  1837. X
  1838. X    /* place the state into chk and nxt */
  1839. X    state_ptr = &state[1];
  1840. X
  1841. X    for ( i = 1; i <= numecs; ++i, ++state_ptr )
  1842. X    if ( *state_ptr != 0 )
  1843. X        {
  1844. X        chk[position + i] = i;
  1845. X        nxt[position + i] = *state_ptr;
  1846. X        }
  1847. X
  1848. X    if ( position + numecs > tblend )
  1849. X    tblend = position + numecs;
  1850. X    }
  1851. X
  1852. X
  1853. X/* stack1 - save states with only one out-transition to be processed later
  1854. X *
  1855. X * synopsis
  1856. X *   int statenum, sym, nextstate, deflink;
  1857. X *   stack1( statenum, sym, nextstate, deflink );
  1858. X *
  1859. X * if there's room for another state one the "one-transition" stack, the
  1860. X * state is pushed onto it, to be processed later by mk1tbl.  If there's
  1861. X * no room, we process the sucker right now.
  1862. X */
  1863. X
  1864. Xstack1( statenum, sym, nextstate, deflink )
  1865. Xint statenum, sym, nextstate, deflink;
  1866. X
  1867. X    {
  1868. X    if ( onesp >= ONE_STACK_SIZE - 1 )
  1869. X    mk1tbl( statenum, sym, nextstate, deflink );
  1870. X
  1871. X    else
  1872. X    {
  1873. X    ++onesp;
  1874. X    onestate[onesp] = statenum;
  1875. X    onesym[onesp] = sym;
  1876. X    onenext[onesp] = nextstate;
  1877. X    onedef[onesp] = deflink;
  1878. X    }
  1879. X    }
  1880. X
  1881. X
  1882. X/* tbldiff - compute differences between two state tables
  1883. X *
  1884. X * synopsis
  1885. X *   int state[], pr, ext[];
  1886. X *   int tbldiff, numdifferences;
  1887. X *   numdifferences = tbldiff( state, pr, ext )
  1888. X *
  1889. X * "state" is the state array which is to be extracted from the pr'th
  1890. X * proto.  "pr" is both the number of the proto we are extracting from
  1891. X * and an index into the save area where we can find the proto's complete
  1892. X * state table.  Each entry in "state" which differs from the corresponding
  1893. X * entry of "pr" will appear in "ext".
  1894. X * Entries which are the same in both "state" and "pr" will be marked
  1895. X * as transitions to "SAME_TRANS" in "ext".  The total number of differences
  1896. X * between "state" and "pr" is returned as function value.  Note that this
  1897. X * number is "numecs" minus the number of "SAME_TRANS" entries in "ext".
  1898. X */
  1899. X
  1900. Xint tbldiff( state, pr, ext )
  1901. Xint state[], pr, ext[];
  1902. X
  1903. X    {
  1904. X    register int i, *sp = state, *ep = ext, *protp;
  1905. X    register int numdiff = 0;
  1906. X
  1907. X    protp = &protsave[numecs * (pr - 1)];
  1908. X
  1909. X    for ( i = numecs; i > 0; --i )
  1910. X    {
  1911. X    if ( *++protp == *++sp )
  1912. X        *++ep = SAME_TRANS;
  1913. X    else
  1914. X        {
  1915. X        *++ep = *sp;
  1916. X        ++numdiff;
  1917. X        }
  1918. X    }
  1919. X
  1920. X    return ( numdiff );
  1921. X    }
  1922. END_OF_FILE
  1923. if test 24794 -ne `wc -c <'flex/tblcmp.c'`; then
  1924.     echo shar: \"'flex/tblcmp.c'\" unpacked with wrong size!
  1925. fi
  1926. # end of 'flex/tblcmp.c'
  1927. fi
  1928. echo shar: End of archive 5 \(of 7\).
  1929. cp /dev/null ark5isdone
  1930. MISSING=""
  1931. for I in 1 2 3 4 5 6 7 ; do
  1932.     if test ! -f ark${I}isdone ; then
  1933.     MISSING="${MISSING} ${I}"
  1934.     fi
  1935. done
  1936. if test "${MISSING}" = "" ; then
  1937.     echo You have unpacked all 7 archives.
  1938.     rm -f ark[1-9]isdone
  1939. else
  1940.     echo You still need to unpack the following archives:
  1941.     echo "        " ${MISSING}
  1942. fi
  1943. ##  End of shell archive.
  1944. exit 0
  1945.