//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1991 - 2000.
//
//  File:       State.cxx
//
//  Contents:   Finite automata state classes
//
//  Classes:
//
//  History:    01-21-92  KyleP     Created
//
//--------------------------------------------------------------------------

#include <pch.cxx>
#pragma hdrstop

#include <state.hxx>

#include "stateset.hxx"

//+-------------------------------------------------------------------------
//
//  Member:     CNFAState::CNFAState, public
//
//  Synopsis:   Copy constructor
//
//  Arguments:  [src] -- Source
//
//  History:    13-Jul-95 KyleP     Created
//
//--------------------------------------------------------------------------

CNFAState::CNFAState( CNFAState const & src )
        : CFAState( src ),
          _pmoveRest( 0 ),
          _cmoveRest( src._cmoveRest ),
          _cMove( src._cMove )
{
    if ( _cmoveRest > 0 )
    {
        _pmoveRest = new CMove [_cmoveRest];
        RtlCopyMemory( _pmoveRest, src._pmoveRest, _cmoveRest * sizeof(_pmoveRest[0]) );
    }

    RtlCopyMemory( _moveFirst, src._moveFirst, sizeof(_moveFirst) );
}

//+-------------------------------------------------------------------------
//
//  Member:     CNFAState::Init, public
//
//  Synopsis:   Copy initializer
//
//  Arguments:  [src] -- Source
//
//  History:    15-Jul-96 KyleP     Created
//
//--------------------------------------------------------------------------

void CNFAState::Init( CNFAState & src )
{
    CFAState::Init( src.StateNumber() );

    if ( src.IsFinal() )
        MakeFinal();

    _cMove = src._cMove;
    RtlCopyMemory( _moveFirst, src._moveFirst, sizeof(_moveFirst) );

    _cmoveRest = src._cmoveRest;
    _pmoveRest = src._pmoveRest;

    src._cMove = 0;
    src._cmoveRest = 0;
    src._pmoveRest = 0;
}

//+-------------------------------------------------------------------------
//
//  Member:     CNFAState::operator =, public
//
//  Synopsis:   Assignment operator
//
//  Arguments:  [src] -- Source
//
//  History:    13-Jul-95 KyleP     Created
//
//--------------------------------------------------------------------------

inline void * operator new( size_t, CNFAState * pthis )
{
    return pthis;
}

#if _MSC_VER >= 1200
inline void operator delete( void * p, CNFAState * pthis ) {}
#endif

CNFAState & CNFAState::operator =( CNFAState const & src )
{
    CNFAState::~CNFAState();

    new (this) CNFAState( src );

    return *this;
}

//+-------------------------------------------------------------------------
//
//  Member:     CNFAState::AddTransition, public
//
//  Synopsis:   Add new state transition.
//
//  Arguments:  [symbol]   -- On this symbol to...
//              [StateNum] --   this state.
//
//  History:    20-Jan-92 KyleP     Created
//
//--------------------------------------------------------------------------

void CNFAState::AddTransition( UINT symbol, UINT StateNum )
{
    //
    // First look for an exact match.  If this transition exists
    // then don't add it again.
    //

    for ( int i = CNFAState_cFirst-1; i >= 0; i--)
    {
        if ( _moveFirst[i]._symbol == symbol &&
             _moveFirst[i]._iState == StateNum )
        {
            return;
        }
    }

    if ( _cMove > CNFAState_cFirst )
    {
        for ( int i = _cMove - CNFAState_cFirst - 1; i >= 0; i--)
        {
            if ( _pmoveRest[i]._symbol == symbol &&
                 _pmoveRest[i]._iState == StateNum )
            {
                return;
            }
        }
    }

    //
    // New transition.  Add it.
    //

    if ( _cMove < CNFAState_cFirst )
    {
        //
        // Fits in the first (object based) set of moves.
        //

        _moveFirst[_cMove] = CMove( symbol, StateNum );
    }
    else
    {
        //
        // Overflow set of moves.
        //

        if ( _cMove - CNFAState_cFirst >= _cmoveRest )
        {
            vqDebugOut(( DEB_ITRACE,
                         "Growing NFA State transition array.\n" ));
            CMove * oldpmoveRest = _pmoveRest;
            UINT    oldcmoveRest = _cmoveRest;

            _cmoveRest = (_cmoveRest == 0) ? 2 : _cmoveRest + 5;

            _pmoveRest = (CMove *) new char [ _cmoveRest * sizeof( CMove ) ];

            memcpy( _pmoveRest, oldpmoveRest, oldcmoveRest * sizeof( CMove ) );
            delete oldpmoveRest;
        }

        _pmoveRest[_cMove - CNFAState_cFirst] = CMove( symbol, StateNum );
    }

    ++_cMove;
}

//+-------------------------------------------------------------------------
//
//  Member:     CNFAState::RemoveTransition, public
//
//  Synopsis:   Removes a transition.
//
//  Arguments:  [symbol]   -- On this symbol to...
//              [StateNum] --   this state.
//
//  History:    20-Jan-92 KyleP     Created
//
//--------------------------------------------------------------------------

void CNFAState::RemoveTransition( UINT symbol, UINT StateNum )
{
    //
    // Find the transition
    //

    for ( int i = CNFAState_cFirst-1; i >= 0; i--)
    {
        if ( _moveFirst[i]._symbol == symbol &&
             _moveFirst[i]._iState == StateNum )
        {
            //
            // Move the last transition to this place.
            //

            if ( _cMove > CNFAState_cFirst )
            {
                _moveFirst[i] = _pmoveRest[_cMove - CNFAState_cFirst - 1];
            }
            else
            {
                _moveFirst[i] = _moveFirst[ _cMove - 1 ];
            }

            _cMove--;

            return;
        }
    }

    if ( _cMove > CNFAState_cFirst )
    {
        for ( int i = _cMove - CNFAState_cFirst - 1; i >= 0; i--)
        {
            if ( _pmoveRest[i]._symbol == symbol &&
                 _pmoveRest[i]._iState == StateNum )
            {
                _pmoveRest[i] = _pmoveRest[ _cMove - CNFAState_cFirst - 1 ];

                _cMove--;

                return;
            }
        }
    }
}

//+-------------------------------------------------------------------------
//
//  Member:     CNFAState::Move, public
//
//  Effects:    Adds to [ss] the set of states that can be reached from
//              this state on [symbol].
//
//  Arguments:  [ss]     -- Output state set.
//              [symbol] -- Input symbol.
//
//  History:    20-Jan-92 KyleP     Created
//
//--------------------------------------------------------------------------

void CNFAState::Move( CStateSet & ss, UINT symbol )
{
    for ( int i = (_cMove <= CNFAState_cFirst) ? _cMove-1 : CNFAState_cFirst-1;
            i >= 0;
            i--)
    {
        if ( _moveFirst[i]._symbol == symbol ||
             ( _moveFirst[i]._symbol == symAny &&
               symbol != symEpsilon ))
        {
            ss.Add( _moveFirst[i]._iState );
        }
    }

    for ( i = _cMove - CNFAState_cFirst - 1; i >= 0; i-- )
    {
        if ( _pmoveRest[i]._symbol == symbol ||
             ( _pmoveRest[i]._symbol == symAny &&
               symbol != symEpsilon &&
               symbol != symDot ))
        {
            ss.Add( _pmoveRest[i]._iState );
        }
    }
}

//
// Debug methods
//

#if (CIDBG == 1)

void CFAState::Display()
{
    vqDebugOut(( DEB_REGEX,
                 "State: %u, Final = %c", _iState, _fFinal ? 'T' : 'F' ));
}

void CNFAState::Display()
{
    CFAState::Display();
    vqDebugOut(( DEB_REGEX | DEB_NOCOMPNAME, " -- %u transitions\n", _cMove ));

    for ( int i = (_cMove <= CNFAState_cFirst) ? _cMove-1 : CNFAState_cFirst-1;
            i >= 0;
            i--)
    {
        if ( _moveFirst[i]._symbol == symEpsilon)
        {
            vqDebugOut(( DEB_REGEX | DEB_NOCOMPNAME, "\tEpsilon " ));
        }
        else if ( _moveFirst[i]._symbol == symAny )
        {
            vqDebugOut(( DEB_REGEX | DEB_NOCOMPNAME, "\tAny " ));
        }
        else
        {
            vqDebugOut(( DEB_REGEX | DEB_NOCOMPNAME,
                         "\t%u ", _moveFirst[i]._symbol ));
        }

        vqDebugOut(( DEB_REGEX | DEB_NOCOMPNAME,
                     "--> %u\n", _moveFirst[i]._iState ));
    }

    for ( i = _cMove - CNFAState_cFirst - 1; i >= 0; i-- )
    {
        if ( _pmoveRest[i]._symbol == symEpsilon)
        {
            vqDebugOut(( DEB_REGEX | DEB_NOCOMPNAME, "\tEpsilon " ));
        }
        else if ( _pmoveRest[i]._symbol == symAny )
        {
            vqDebugOut(( DEB_REGEX | DEB_NOCOMPNAME, "\tAny " ));
        }
        else
        {
            vqDebugOut(( DEB_REGEX | DEB_NOCOMPNAME,
                         "\t%u ", _pmoveRest[i]._symbol ));
        }

        vqDebugOut(( DEB_REGEX | DEB_NOCOMPNAME,
                     "--> %u\n", _pmoveRest[i]._iState ));
    }
}

#endif // (CIDBG == 1)
