///////////////////////////////////////////////////////////////////////////////
//                                                         
// Worm.cc
// -------
// Dragon scanner generator interface defintion
//                                               
// Design and Implementation by Bjoern Lemke               
//                                                         
// (C)opyright 2000-2007 Bjoern Lemke
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; see the file COPYING.  If not, write to
// the Free Software Foundation, 59 Temple Place - Suite 330,
// Boston, MA 02111-1307, USA.
//
// IMPLEMENTATION MODULE
//
// Class: Worm
// 
// Description: regular expression analysis, optimization and generation of FSM
//
///////////////////////////////////////////////////////////////////////////////

// BASE INCLUDES
#include <lfc/Exception.h>

// DRAGON INCLUDES
#include "Worm.h"
#include "FSM.h"

Worm::Worm(const Chain& regExp, const Chain&  token)
{
    _stateTable.Insert(FSMState(0, START));
    _nextState = 1;    


    _transTable.Insert(FSMTransition(0, _nextState, EPSILON));

    // _nextState++;
    _reg = regExp;
    _i=0;

    int finalState, startState;

    while (_i < _reg.length())
    {
	startState = _nextState;

	_stateTable.Insert(FSMState(startState, NONE));
           
	_nextState++;
	
	finalState = _nextState;

	_stateTable.Insert(FSMState(finalState, NONE));
	
	_nextState++;
	
	parseRegElement(startState, finalState);
	
	_transTable.Insert(FSMTransition(finalState, _nextState, EPSILON));
    }
	
    _stateTable.Insert(FSMState(_nextState, FINAL, token));

    _nextState++;

}

Worm::~Worm()
{
}


void Worm::makeOptimalDEA()
{
  
    FSM f(&_stateTable, &_transTable);
    
    // this optimization works

    // f.epsilonFree(); 
    // f.determinate();

    // the following produces a minimal DEA
    // but actually treats token values 
    // not correctly

    // prrintFsm();

    f.epsilonFree();
   
    f.invert();

    f.determinate();

    f.invert();

    f.determinate();
    
    // f.printFsm();
}


void Worm::parseRegElement(int startState, int endState)
{
	
    char c = _reg[_i];
    
    switch (c)
    {
	
    case '*': 
    {

	_transTable.Insert(FSMTransition(startState, endState, EPSILON));

	int newStartState = _nextState;

	_stateTable.Insert(FSMState(newStartState, NONE));

	_transTable.Insert(FSMTransition(startState, newStartState, EPSILON));
	
	_nextState++;

	int newEndState = _nextState;
 
	_stateTable.Insert(FSMState(newEndState, NONE));
	_transTable.Insert(FSMTransition(newEndState, newStartState, EPSILON));
	_transTable.Insert(FSMTransition(newEndState, endState, EPSILON));
	
	_nextState++; 
	
	_i++;
	
	parseRegElement(newStartState, newEndState);
	
	break;
    }
    
    case '[':
		
    {
	_i++;
	
	while ( _reg[_i] != ']' && _i < _reg.length() )
	{ 
	    int newStartState = _nextState;
	    _nextState++;
	    int newEndState = _nextState;
	    _nextState++;
	    
	    _stateTable.Insert(FSMState(newStartState, NONE));
	    _stateTable.Insert(FSMState(newEndState, NONE));
	    
	    _transTable.Insert(FSMTransition(startState, newStartState, EPSILON));
	    _transTable.Insert(FSMTransition(newEndState, endState, EPSILON));
	    
	    parseRegElement(newStartState, newEndState);

	}
	if  ( _reg[_i] != ']' )
	{
	    throw Exception(EXLOC, "Unterminated [ ... ] expression");
	}
	
	_i++;
	
	break;
	
    }
    
    case '\'':
	
    {
	
	int prevState = startState;

	_i++;

	while ( _reg[_i] != '\'')
	{ 	
	    _stateTable.Insert(FSMState(_nextState, NONE));	
	    _transTable.Insert(FSMTransition(prevState, _nextState, _reg[_i]));
	    prevState = _nextState;
	    _nextState++;
	    _i++;
	}
	_transTable.Insert(FSMTransition(prevState, endState, EPSILON));
	
	_i++;

	break;

    }
    case '-':
      
    {

	char c1 = _reg[_i-1];
	char c2 = _reg[_i+1];
	
	c1++;

	while ( c1 <= c2 )
	{ 
	    _transTable.Insert(FSMTransition(startState, endState, c1));
	    c1++;
	}
	_i=_i+2;
	break;

    }


    case '(':
		
    {

	_i++;
	
	int newStartState1 = _nextState;

	while ( _reg[_i] != '|' && _i < _reg.length() )
	{ 

	    int newStartState = _nextState;

	    _nextState++;
	    	    
	    _stateTable.Insert(FSMState(newStartState, NONE));
	   
	    int newFinalState = _nextState;

	    _stateTable.Insert(FSMState(newFinalState, NONE));
	    
	    _nextState++;
	    
	    parseRegElement(newStartState, newFinalState);
	    
	    _transTable.Insert(FSMTransition(newFinalState, _nextState, EPSILON));
	}
	
	int newFinalState1 = _nextState;
	
	_i++;

	_stateTable.Insert(FSMState(newFinalState1, NONE));
	_transTable.Insert(FSMTransition(startState, newStartState1, EPSILON));
	_transTable.Insert(FSMTransition(newFinalState1, endState, EPSILON));

	
	bool isEnded=false;

	do {

	    _nextState++;
	    
	    int newStartState2 = _nextState;
	    	    
	    while (  _reg[_i] != ')' && _reg[_i] != '|'  && _i < _reg.length() )
	    { 
		
		int newStartState = _nextState;
		
		_stateTable.Insert(FSMState(newStartState, NONE));
		
		_nextState++;
		
		int newFinalState = _nextState;
		
		_stateTable.Insert(FSMState(newFinalState, NONE));
		
		_nextState++;
		
		parseRegElement(newStartState, newFinalState);
		
		_transTable.Insert(FSMTransition(newFinalState, _nextState, EPSILON));
	    }
	    
	    int newFinalState2 = _nextState;	
	    
	    _nextState++;
	    
	    if ( _reg[_i] == ')' || _i >= _reg.length() )
		isEnded = true;
	    
	    _i++; 
	    	    
	    _transTable.Insert(FSMTransition(startState, newStartState2, EPSILON));
	    
	    
	    _stateTable.Insert(FSMState(newFinalState2, NONE));
	    
	    
	    _transTable.Insert(FSMTransition(newFinalState2, endState, EPSILON));

	} while  ( ! isEnded );
	
	
	break;
	
    }
    
    default:

    {
	_transTable.Insert(FSMTransition(startState, endState, c));
	
	_i++;
	
	break;
	
    }
    }
}
    

void Worm::printTables()
{

    cout << "StateTable: " << endl;

    FSMState* pE = _stateTable.First();
    while (pE)
    {
      cout << pE->Num() << " " << pE->Type() << " " << pE->Token() << endl;
      pE = _stateTable.Next();
    }

    cout << "TransTable: " << endl;

    FSMTransition* pT = _transTable.First();
    while (pT)
    {
	cout << pT->Source() << " " << pT->Target() << " " << pT->Sign() <<  endl;
	pT = _transTable.Next();
    }
    
}

TreeT<FSMState>& Worm::getStateTable()
{
    return _stateTable;
}

TreeT<FSMTransition>& Worm::getTransitionTable()
{
    return _transTable;
}
