/***************************************************************************/
//              "Меркурий"-"Правда" - open source переводчик
//          распространяется в соответсвии с лицензией GNU v 2.0
//
//              Класс, разбивающий текстовый файл на слова
//       Анисимов Д.В.                                    сегодня
/***************************************************************************/
# include <string.h>
# include "mylib.h"
# include "lexer.h"

# define Ifstr( a,b ) if( 0==strcmp(a,b) 
)

/***************************************************************************/
t_Lexer ::  t_Lexer( void )
{
   Mass   = NULL ;
   Mass1  = NULL ;
   Word   = NULL ;
   Str    = NULL ;
   l_Mass = 0 ;
   n_Word = 0 ;
   clr_breaker( );

}
/***************************************************************************/
t_Lexer :: ~t_Lexer( void )
{
   Free( Mass );
   Free( Mass1 );
   Free( Word );
   Free( Str );
}
/***************************************************************************/
//          установить какие символы являются разделителями слов
/***************************************************************************/
//    set_breaker( ".,;:#$%^=+-*/(){}<>[]\"\\" );
void t_Lexer :: set_breaker( unsigned char *Breaker )
{
   for( short i=0 ; i<256 && Breaker[i]!=0 ; i++ )
      Type[Breaker[i]]=1 ;
}
/***************************************************************************/
//         установить дефолтные символы, разделители слов
/***************************************************************************/

void t_Lexer :: clr_breaker( void )
{
   for( short i=0 ; i<256 ; i++ )
      Type[i]=0 ;
   Type[' '] =2 ;Type['\t']=2;
   Type['\n']=3 ;Type['\r']=3 ;
}
/***************************************************************************/
//        задать массив, который будет разбираться на слова
/***************************************************************************/

void t_Lexer :: init( char *_Mass, long _L )
{
   Free( Mass ); Free( Mass1 ); Free( Word ); Free( Str );

   Mass=(char *)Calloc(_L,sizeof(char));
   Str =(long *)Calloc( max(3,_L/2) ,sizeof(long)); 
   // число слов надо посчитать более корректно
   l_Mass=_L ;
   memcpy( Mass,_Mass,l_Mass );
   remark( );
}
/***************************************************************************/

void t_Lexer :: init1( char *_Mass, long _L )
{
   Free( Mass ); Free( Mass1 ); Free( Word ); Free( Str );

   Mass=(char *)Calloc(_L,sizeof(char));
   Str =(long *)Calloc( max(3,_L/2) ,sizeof(long)); 
   // число слов надо посчитать более корректно
   l_Mass=_L ;
   memcpy( Mass,_Mass,l_Mass );
   remark1( );
}
/***************************************************************************/
//                          удалить коментарии
/***************************************************************************/

void t_Lexer :: remark( void )
{  long i,j,N ;
   char  c1,c2=' ' ;
   register char f,c ;

   N=l_Mass-1 ;
   f=0 ;
   for( i=j=0 ; i<N ; i++ )
   {  c=Mass[i] ; 
      if( f==0 )
      {
         f=( c=='#' );
	 if( c=='/' )
	 {   c1=Mass[i+1] ;
	     if( c1=='/' ) f=1 ;
	     if( c1=='*' ) f=2 ;
	 }
      }
      if( f==0 ) continue ;
          else   Mass[i]=' ' ;
      if( c=='\n' && f==1 ) f=0 ;
      if( f==2 && c2=='*' && c=='/' ) f=0 ;      
      c2=c ;
   }
}
/***************************************************************************/
//                          удалить коментарии
/***************************************************************************/

void t_Lexer :: remark1( void )
{  long i,j,N ;
   char  c1,c2=' ' ;
   register char f,c ;

   N=l_Mass-1 ;
   f=0 ;
   for( i=j=0 ; i<N ; i++ )
   {  c=Mass[i] ; 
      if( f==0 )
      {
	 if( c=='/' )
	 {   c1=Mass[i+1] ;
	     if( c1=='/' ) f=1 ;
	     if( c1=='*' ) f=2 ;
	 }
      }
      if( f==0 ) continue ;
          else   Mass[i]=' ' ;
      if( c=='\n' && f==1 ) f=0 ;
      if( f==2 && c2=='*' && c=='/' ) f=0 ;      
      c2=c ;
   }
}
/***************************************************************************/
//                     создать из текста массив слов
/***************************************************************************/

void t_Lexer :: make_words( void )
{
   long i,j,j_Word,n,j_Str=0 ;
   register char t,c ;

   Mass1=(char  *)Calloc( 2*l_Mass,sizeof(char) );

   for( i=j=n=0 ; i<l_Mass ; i++ )
   {  c=Mass[i] ;
      
      if( 0<=c )
      {  t=Type[c] ;
	 
	 if( t==1 ) // ------ если разделитель ----------
	 {
	    if( 0<j && Mass1[j-1]!=0 )
	    {   Mass1[j++]=0 ; Str[n]=j_Str ; n++ ;  }
	    Mass1[j++]=c ;
	    Mass1[j++]=0 ;
	    Str[n]=j_Str ; /* ABW1 */
	    n++ ;
	    continue ;
	 }

	 if( t==2 || t==3 ) // ------ если новая строка ----------
	 {  if( Mass[i]=='\n' ) j_Str++ ;
	    if( 0<j && Mass1[j-1]!=0 )
	    {   Mass1[j++]=0 ; Str[n]=j_Str ; n++ ;  }
	    continue ;
	 }
      }
      Mass1[j++]=c ;
   }
   n_Word=n ;
   Word =(char **)Calloc( n_Word+1,sizeof(char *));

   Word[0]=Mass1 ;
   for( i=j_Word=0 ; i<j ; i++ )
   {
      if( 0==Mass1[i] )
      {
	 Word[++j_Word]=Mass1+i+1 ;
      }
   }
}
/* ---------------------------------------------------------------------- */
char
* t_Lexer :: word( long i )
{  return Word[i] ;  }
/* ---------------------------------------------------------------------- */

long t_Lexer :: n_word( void )
{  return n_Word ;  }
/* ---------------------------------------------------------------------- */

long t_Lexer :: str( long i )
{  return Str[i] ;  }
/**************************************************************************/
//    найти закрывающую скобку для соответствующей открывающей
//    Begin - с какого слова начинать искать
//    Open  - что мы считаем открывающей скобкой
//    Close - что мы считаем закрывающей скобкой
/**************************************************************************/

long t_Lexer :: find_paar( long Begin, char *Open, char *Close )
{  long i,s=-1 ;

   for( i=Begin ; i<n_Word ; i++ )
      if( 0==strcmp(Word[i],Open) )  {  s=0 ; break ;  }
   if( s<0 ) return Begin ;
   for( ; i<n_Word ; i++ )
   {  Ifstr( Word[i],Open ) s++ ;
      Ifstr( Word[i],Close) s-- ;
      if( s==0 ) return i ;
   }
   return -1 ;
}
/**************************************************************************/
//    найти в тексте нужное слово
//    Begin - с какого слова начинать искать
//    W     - что за слово мы ищем
/**************************************************************************/

long t_Lexer :: find_word( long Begin, char *W )
{
   for( long i=Begin ; i<n_Word ; i++ )
      if( 0==strcmp(Word[i],W) )  return i ;
   return -1 ;
}
/* ---------------------------------------------------------------------- */

void t_Lexer :: error( long i )
{  printf("\n Строка %ld неизвестное слово %s",Str[i],Word[i] );
   throw( -1 );
}