⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 minimize.c

📁 compiler
💻 C
字号:
/*@A (C) 1992 Allen I. Holub                                                */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tools/debug.h>
#include <tools/set.h>
#include <tools/hash.h>
#include <tools/compiler.h>
#include "dfa.h"
#include "globals.h"	/* externs for Verbose */

/* MINIMIZE.C:	Make a minimal DFA by eliminating equivalent states.  */

PRIVATE SET  *Groups [ DFA_MAX ];  /* Groups of equivalent states in Dtran */
PRIVATE int  Numgroups;	           /* Number of groups in Groups     	   */
PRIVATE int  Ingroup [ DFA_MAX ];  /* the Inverse of Group		   */

/*----------------------------------------------------------------------
 * Prototypes for subroutines in this file:
 */

PRIVATE void 	fix_dtran	P(( ROW*[],          ACCEPT**		));
PRIVATE void  	init_groups	P(( int,             ACCEPT* 		));
PUBLIC	int 	min_dfa		P(( char *(*)(void), ROW*[],  ACCEPT**	));
PRIVATE void 	minimize	P(( int,             ROW*[],  ACCEPT**	));
PRIVATE void	pgroups		P(( int	       				));

#ifdef DEBUG
  PRIVATE void	setp		P(( SET*				));
#endif
/*----------------------------------------------------------------------*/

PUBLIC	int min_dfa( ifunct, dfap, acceptp )
char    *( *ifunct  )P((void));
ROW     *( dfap[]   );
ACCEPT  *( *acceptp );
{
    /* Make a minimal DFA, eliminating equivalent states. Return the number of
     * states in the minimized machine. *sstatep = the new start state.
     */

    int	 nstates;		/* Number of DFA states	  	*/

    memset( Groups,  0, sizeof(Groups)  );
    memset( Ingroup, 0, sizeof(Ingroup) );
    Numgroups = 0;

    nstates = dfa( ifunct,  dfap, acceptp );
    minimize     ( nstates, dfap, acceptp );

    return Numgroups;
}

PRIVATE  void  init_groups( nstates, accept )
int	nstates;
ACCEPT	*accept;
{
    SET	 **last ;
    int	 i, j ;

    last      = & Groups[0] ;
    Numgroups = 0;

    for( i = 0; i < nstates ; i++ )
    {
	for( j = i;  --j >= 0 ;)
	{
	    /* Check to see if a group already exists that has the same
	     * accepting string as the current state. If so, add the current
	     * state to the already existing group and skip past the code that
	     * would create a new group. Note that since all nonaccepting states
	     * have NULL accept strings, this loop puts all of these together
	     * into a single group. Also note that the test in the for loop
	     * always fails for group 0, which can't be an accepting state.
	     */

	    if( accept[i].string == accept[j].string )
	    {
		ADD( Groups[ Ingroup[j] ], i );
		Ingroup[i] = Ingroup[j];
		goto match;
	    }
	}

	/* Create a new group and put the current state into it. Note that ADD()
	 * has side effects, so "last" can't be incremented in the ADD
	 * invocation.
	 */

	*last = newset();
	ADD( *last, i );
	Ingroup[i] = Numgroups++;
	++last;

match:;	/* Group already exists, keep going */
    }

    if( Verbose > 1 )
    {
	printf  ( "Initial groupings:\n" );
	pgroups ( nstates );
    }
}

/*----------------------------------------------------------------------*/

PRIVATE void minimize( nstates, dfap, acceptp )
int	 nstates;		/* number of states in dtran[]		*/
ROW	 *( dfap[]   );		/* DFA transition table to compress	*/
ACCEPT	 *( *acceptp );		/* Set of accept states			*/
{
    int  old_numgroups;	/* Used to see if we did anything in this pass. */
    int  c;		/* Current character.                           */
    SET  **current;	/* Current group being processed.		*/
    SET  **new ;	/* New partition being created.			*/
    int  first;		/* State # of first element of current group.	*/
    int  next;		/* State # of next element of current group.	*/
    int  goto_first;	/* target of transition from first[c].		*/
    int  goto_next;	/* other target of transition from first[c].	*/

    ROW    *dtran  = *dfap;
    ACCEPT *accept = *acceptp;

    init_groups( nstates, accept );
    do
    {
	old_numgroups = Numgroups;
	for( current = &Groups[0]; current < &Groups[Numgroups]; ++current )
	{
	    if( num_ele( *current ) <= 1 )
		continue;

	    new  = &Groups[ Numgroups ];
	    *new = newset();

	    next_member( NULL );
	    first = next_member( *current );

	    while( (next = next_member(*current))  >= 0 )
	    {
		for( c = MAX_CHARS; --c >= 0 ;)
		{
		    goto_first = dtran[ first ][ c ];
		    goto_next  = dtran[ next  ][ c ];

		    if( goto_first != goto_next
			&&(    goto_first == F
			    || goto_next  == F
			    || Ingroup[goto_first] != Ingroup[goto_next]
			  )
		      )
		    {
			REMOVE( *current, next );     /* Move the state to  */
			ADD   ( *new,     next );     /* the new partition  */
			Ingroup[ next ] = Numgroups ;
			break;
		    }
		}
	    }

	    if( IS_EMPTY( *new ) )
		delset( *new );
	    else
		++Numgroups;
	}

    } while( old_numgroups != Numgroups );

    if( Verbose > 1 )
    {
    	printf("\nStates grouped as follows after minimization:\n");
	pgroups( nstates );
    }

    fix_dtran( dfap, acceptp );
}

/*----------------------------------------------------------------------*/

PRIVATE	void fix_dtran( dfap, acceptp )
ROW	*( dfap[]  );
ACCEPT	*( *acceptp );
{
    /*    Reduce the size of the dtran, using the group set made by  minimize().
     * Return the state number of the start state. The original dtran and accept
     * arrays are destroyed and replaced with the smaller versions.
     *    Consider the first element of each group (current) to be a
     * "representative" state. Copy that state to the new transition table,
     * modifying all the transitions in the representative state so that they'll
     * go to the group within which the old state is found.
     */

    SET	   **current   ;
    ROW	   *newdtran   ;
    ACCEPT *newaccept  ;
    int	   state       ;
    int	   i	       ;
    int    *src, *dest ;
    ROW	   *dtran  = *dfap;
    ACCEPT *accept = *acceptp;
    SET    **end   = &Groups[Numgroups];

    newdtran  = (ROW    *) calloc( Numgroups, sizeof(ROW   ) );
    newaccept = (ACCEPT *) calloc( Numgroups, sizeof(ACCEPT) );

    if( !newdtran || !newaccept )
	ferr("Out of memory!!!");

    next_member( NULL );
    for( current = Groups; current < end; ++current )
    {
	dest  = &newdtran[ current-Groups ][ 0 ];
	state = next_member(*current) ;		     /* All groups have at */
	src   = & dtran[ state ][ 0 ];		     /* least one element. */

	newaccept[ current-Groups ]=accept[state];   /* Struct. assignment */

	for( i = MAX_CHARS; --i >= 0 ; src++, dest++ )
	    *dest = (*src == F) ? F : Ingroup[ *src ];
    }

    free( *dfap    );
    free( *acceptp );
    *dfap    = newdtran  ;
    *acceptp = newaccept ;
}
PRIVATE void pgroups( nstates )
int	nstates ;
{
    /* Print all the groups used for minimization.  */

    SET	**current;
    SET **end = &Groups[Numgroups];
    for( current = Groups; current < end; ++current )
    {
	printf( "\tgroup %ld: {", (long)(current - Groups) );
#if (0 ANSI(+1))
	pset( *current, (int (*)(void*,char*,int))fprintf, (void*)stdout );
#else
  	pset( *current, fprintf, (void*) stdout );
#endif
	printf( "}\n" );
    }
    printf("\n");
    while( --nstates >= 0 )
	printf("\tstate %2d is in group %2d\n", nstates, Ingroup[nstates] );
}

   /*----------------------------------------------------------------------*/
#ifdef DEBUG
   /* The following function is not called. It's here so that it can be
    * called from the debugger if you like.
    */

   PRIVATE void setp( set )
   SET	*set;
   {
       pset( set, fprintf, stdout );
       putchar('\n');
   }
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -