/***************************************************************************/
//              "Меркурий"-"Правда" - open source переводчик
//          распространяется в соответсвии с лицензией GNU v 2.0
//
//                 словарь переводов слов и словосочетаний
//       Анисимов Д.В.                                    сегодня
/***************************************************************************/

# include <stdio.h>
# include <malloc.h>
# include <string.h>
# include <stdlib.h>

# include <mylib.h>
# include <grammar.h>
# include <slowo3.h>
# include <core.h>
# include <factorial.cpp>

static t_Slowo3 *Slowo3 ;
char   Word0[100] ;
t_Factorial Factorial(5) ;

char *filename( char *Path, char *File );
short find_param1( t_Param1List *List, char *Str )
;

/***************************************************************************/
//                          инициировать нулями
/***************************************************************************/
t_Slowo3 :: t_Slowo3( void )
{
   FileName[0]=0 ;
   Format  =NULL ;

   Mass    =NULL ;
   Word    =NULL ;
   Struct  =NULL ;
   Record  =NULL ;
   Relation=NULL ;

   l_Mass  =0 ;
   l_Mass1 =0 ;
   n_Word  =0 ;
   n_Struct=0 ;
   n_Record=0 ;
   n_Tree  =0 ;
   n_Relation=0 ;
}
/***************************************************************************/
// 
/***************************************************************************/

void t_Slowo3 :: del( void )
{
   Free( Mass );
   Free( Word );
   Free( Struct );
   Free( Record );
   Free( Tree );
   Free( Relation );
}
/***************************************************************************/
//                     записать бинарный образ
/***************************************************************************/

void t_Slowo3 :: write_bin( char *File )
{  FILE *fw ;

   fw=Fopen( File,"wb" );
   
   Fwrite( &l_Mass    ,1,sizeof(long),fw );
   Fwrite( &n_Word    ,1,sizeof(long),fw );
   Fwrite( &n_Struct  ,1,sizeof(long),fw );
   Fwrite( &n_Record  ,1,sizeof(long),fw );
   Fwrite( &n_Tree    ,1,sizeof(long),fw );
   Fwrite( &n_Relation,1,sizeof(long),fw );

   Fwrite( Mass    ,l_Mass+1    ,sizeof(char)      ,fw );
   Fwrite( Word    ,n_Word+1    ,sizeof(t_sWord)   ,fw );
   Fwrite( Struct  ,n_Struct+1  ,sizeof(t_sStruct) ,fw );
   Fwrite( Record  ,n_Record+1  ,sizeof(t_sRecord) ,fw );
   Fwrite( Tree    ,n_Tree      ,sizeof(t_sTree)   ,fw );
   Fwrite( Relation,n_Relation+1,sizeof(t_Relation),fw );

   Fclose( fw );
}
/***************************************************************************/
//                     прочитать бинарный образ
/***************************************************************************/

char t_Slowo3 :: read_bin( char *File )
{  FILE *fr ;
   long  i ;
try
{
   fr=Fopen( File,"rb" );
   del( );
   
   Fread( &l_Mass    ,1,sizeof(long),fr );
   Fread( &n_Word    ,1,sizeof(long),fr );
   Fread( &n_Struct  ,1,sizeof(long),fr );
   Fread( &n_Record  ,1,sizeof(long),fr );
   Fread( &n_Tree    ,1,sizeof(long),fr );
   Fread( &n_Relation,1,sizeof(long),fr );

   Mass    =(uchar      *)Malloc( l_Mass+1    ,sizeof(uchar));
   Word    =(t_sWord    *)Malloc( n_Word+1    ,sizeof(t_sWord));
   Struct  =(t_sStruct  *)Malloc( n_Struct+1  ,sizeof(t_sStruct));
   Record  =(t_sRecord  *)Malloc( n_Record+1  ,sizeof(t_sRecord));
   Tree    =(t_sTree    *)Malloc( n_Tree      ,sizeof(t_sTree));
   Relation=(t_Relation *)Malloc( n_Relation+1,sizeof(t_Relation));

   Fread( Mass    ,l_Mass+1    ,sizeof(char)      ,fr );
   Fread( Word    ,n_Word+1    ,sizeof(t_sWord)   ,fr );
   Fread( Struct  ,n_Struct+1  ,sizeof(t_sStruct) ,fr );
   Fread( Record  ,n_Record+1  ,sizeof(t_sRecord) ,fr );
   Fread( Tree    ,n_Tree      ,sizeof(t_sTree)   ,fr );
   Fread( Relation,n_Relation+1,sizeof(t_Relation),fr );

   Fclose( fr );
   for( i=0 ; i<n_Struct ; i++ )
      Struct[i].Word=Word+Struct[i].sy_word ;

   for( i=0 ; i<n_Word ; i++ )
      Word[i].str=(char *)Mass+Word[i].sy ;

   l_Mass1=l_Mass ;
   return 0 ;
}
catch( ... )
{
   return -1 ;
}
}
/***************************************************************************/
//              прочитать из текстового формата все словари, 
//              и сделать из них единый словарь
/***************************************************************************/

void t_Slowo3 :: read( char *Dir, t_Grammar *Gr )
{
   long  i,i1,j,N,j_Slowo ;
   long  j_Word,j_Struct,j_Record,j_Relation ;
   t_File    *FF ;
   t_Slowo3  *Slowo3,*SS ;
   t_FileList &File1=Gr->file1() ;
   char   Filename[200] ;

   del( );

   Format=&(Gr->format1()[0]) ;

   for( N=i=0 ; i<File1.j ; i++ )
      N+=File1[i].FileName.j ;

   Slowo3=(t_Slowo3 *)Calloc( N,sizeof(t_Slowo3) );

   // ------ сосчитать потребную память --------------------------
   l_Mass=n_Word=n_Struct=n_Record=n_Relation=0 ;
   for( j_Slowo=i=0 ; i<File1.j ; i++ )
   {  FF=&File1[i] ;
      for( i1=0 ; i1<FF->FileName.j ; i1++ )
      {  SS=&Slowo3[j_Slowo] ;
	 SS->Format=&(Gr->format1()[FF->i_format]) ;
	 strcpy( Filename,Dir ); strcat( Filename,FF->FileName[i1] );
	 SS->read0( Filename );
	 SS->parse( );
	 l_Mass     += SS->l_Mass ;
	 n_Word     += SS->n_Word ;
	 n_Struct   += SS->n_Struct ;
	 n_Record   += SS->n_Record ;
	 n_Relation += SS->n_Relation ;
	 j_Slowo++ ;
      }
   }
   l_Mass1=l_Mass ;
   // ------ захватить память ------------------------------------
   Mass    =(uchar      *)Calloc( l_Mass+1    ,sizeof(uchar    ) );
   Word    =(t_sWord    *)Calloc( n_Word+1    ,sizeof(t_sWord  ) );
   Struct  =(t_sStruct  *)Calloc( n_Struct+1  ,sizeof(t_sStruct) );
   Record  =(t_sRecord  *)Calloc( n_Record+1  ,sizeof(t_sRecord) );
   Relation=(t_Relation *)Calloc( n_Relation+1,sizeof(t_Relation));

   // ------ переписать структуры и слова из всех словарей в один -
   j=j_Word=j_Struct=j_Record=j_Relation=0 ;
   for( i=0 ; i<N ; i++ )
   {  SS=&Slowo3[i] ;
      t_sRecord *R ;
      t_sStruct *S ;

      memcpy( Record+j_Record,SS->Record,SS->n_Record*sizeof(t_sRecord) );
      for( i1=0 ; i1<SS->n_Record ; i1++ )
      {  R=&Record[j_Record++] ;
         R->sy_struct+=j_Struct ;
	 R->i_dict=i ;
      }
      
      memcpy( Struct+j_Struct,SS->Struct,SS->n_Struct*sizeof(t_sStruct) );
      for( i1=0 ; i1<SS->n_Struct ; i1++ )
      {  S=&Struct[j_Struct++] ;
         S->sy_word   +=j_Word ;
	 S->i_relation+=j_Relation ;
      }

      memcpy( Word+j_Word,SS->Word,SS->n_Word*sizeof(t_sWord) );
      for( i1=0 ; i1<SS->n_Word ; i1++ )
	 Word[j_Word++].sy+=j ;

      for( i1=0 ; i1<SS->n_Relation ; i1++ )
         Relation[j_Relation++]=SS->Relation[i1] ;

      memcpy( Mass+j,SS->Mass,SS->l_Mass );
      j+=SS->l_Mass ;
   }
   // ----- освободить память от исходных словарей ----------------
   for( i=0 ; i<N ; i++ )
      Slowo3[i].del( );
   Free( Slowo3 );

   // ----- проставть конечные значения ---------------------------
   Struct[j_Struct].sy_word   =j_Word ;
   Struct[j_Struct].i_relation=j_Relation ;
   Record[j_Record].sy_struct =j_Struct ;

   // ----- проставть ссылки куда надо ----------------------------
   for( i=0 ; i<n_Struct ; i++ )
      Struct[i].Word=Word+Struct[i].sy_word ;

   for( i=0 ; i<n_Word ; i++ )
      Word[i].str=(char *)Mass+Word[i].sy ;

   split_unorder( );
   sort0( );
   make_tree( );
}
/***************************************************************************/
//             прочесть из файла и построить все структуры
/***************************************************************************/

void t_Slowo3 :: read( char *File, t_Format1 *_Format )
{
   Format = _Format ;

   read0( File );
   parse( );
   split_unorder( );
   sort0( );
   make_tree( );
}
/***************************************************************************/
//             прочесть из массива и построить все структуры
/***************************************************************************/

void t_Slowo3 :: make( char *_Mass, t_Format1 *_Format )
{
   Format = _Format ;

   make0( _Mass );
   parse( );
   sort0( );
   make_tree( );
}
/***************************************************************************/
//                     прочесть из файла
/***************************************************************************/

void t_Slowo3 :: read0( char *File )
{  FILE *fr ;

try
{
   fr=Fopen( File,"rb" );
   l_Mass=FileLength( fr );
   Mass  =(uchar *)Calloc( l_Mass+1,sizeof(uchar) );
   Fread( Mass,l_Mass,sizeof(uchar),fr );
   fclose(fr);
   l_Mass=remark( (char *)Mass, l_Mass );
}
catch( int E )
{  
   fprintf( File_Error,"\n Ребята, че-то я словарь %s не могу прочесть.",File );
   if( E==Err_Fopen ) fprintf( File_Error,"\n А он вообще-то есть?" );
   throw( E );
}
}
/***************************************************************************/
//                     прочесть из массива
/***************************************************************************/

void t_Slowo3 :: make0( char *_Mass )
{
   l_Mass=strlen( _Mass );
   Mass  =(uchar *)Calloc( l_Mass+1,1 );
   for( long i=0 ; i<l_Mass ; i++ )
      Mass[i]=_Mass[i] ;
   l_Mass=remark( (char *)Mass, l_Mass );
}
/***************************************************************************/
//                     построить все структуры
/***************************************************************************/

void t_Slowo3 :: parse( void )
{  long  i,i1,i2,j,j1 ;

   char  c,Reg[100],Msg[200]="" ;
   char  fformat,  // признак, что разбирается сложная структура
         fstr,     // признак, что разбирается заголовок структуры
         fdst;     // признак, что разбирается структура-приемник
   long  j_Word,j_Struct,j_Record,j_Relation ;
   t_sStruct *S ;
   t_sWord   *W ;

try
{
   // ------------ посчитать число слов и переводов -----------------
   for( i=0,fformat=1 ; i<l_Mass ; i++ )
   {  c=Mass[i] ;
      if( c=='[' || c=='~' )
      {   n_Word++ ;
	  n_Struct+=fformat ;
	  continue ;
      }
      if( c=='\n' ) {  n_Record++ ; fformat=1 ; }
      if( c==':'  ) {  n_Struct++ ; fformat=0 ; }
   }

   n_Record++ ;
   // ------------ захватить память --------------------------------
   Word    =(t_sWord    *)Calloc( n_Word+1  ,sizeof(t_sWord) );
   Struct  =(t_sStruct  *)Calloc( n_Struct+1,sizeof(t_sStruct) );
   Record  =(t_sRecord  *)Calloc( n_Record+1,sizeof(t_sRecord) );
   Relation=(t_Relation *)Calloc( 256000    ,sizeof(t_Relation) );

   for( i=0 ; i<n_Struct ; i++ )
      Struct[i].Param.init();
   for( i=0 ; i<n_Word ; i++ )
      Word[i].Param.init();

   // ---------- расставить ссылки и определить части речи ---------------
   j_Word    =0 ; W=Word ;
   j_Struct  =0 ; S=Struct ;
   j_Record  =0 ;
   j_Relation=0 ;

   char Type[256] ;
   for( i=0 ; i<256 ; i++ )
      Type[i]=0 ;
   Type['=']=Type[';']=Type[':']=Type['~']=1 ;
   Type['(']=Type[')']=Type['[']=Type[']']=Type['<']=Type['>']=1 ;

   for( i=-1 ; i<l_Mass ; i++ )
   {  if( i!=-1 && Mass[i]!='\n' ) continue ;

      Record[j_Record++].sy_struct=j_Struct ;
      fformat=fdst=fstr=0 ;
      // -------- сформировать строку сообщения ------------
      for( i1=i+1,j=0 ; i1<l_Mass && Mass[i1]!='\n' ; i1++ )
      {   if( 198<j ) break ;
          Msg[j++]=Mass[i1] ;
      }
      Msg[j]=0 ;
      // -------- определить, является ли строка словом или структурой -------
      for( i1=i+1 ; i1<l_Mass && Mass[i1]!='[' ; i1++ )
      	 if( Mass[i1]==':' ) {  fformat=fstr=1 ; break ;  }

      // -------- разбор строки ----------------------------
      for( i1=i+1,j=0 ; i1<l_Mass && Mass[i1]!='\n' ; i1++ )
      {
	 c=Mass[i1] ;
	 if( j<98 ) Reg[j++]=c ;
	 if( c<0 || Type[c]==0 ) continue ;

	 if( c=='=' )
	 {  fdst=1 ;
	    fstr=fformat ;
	    j=0 ;
	 }
	 if( c==';' )
	 {  fstr=fformat ;
	    j=0 ;
	    continue ;
	 }

	 if( fstr==1 )
	 {   // -------- если разбирается заголовок структуры --------
	     if( c==':' || c=='(')
	     {   short i_str ;

		 if( Mass[i1-1]!=')' )
		 {
		     Reg[j-1]=0 ;
		     for( j1=i2=0 ; i2<j ; i2++ )
		        if( Reg[i2]!=' ' ) Reg[j1++]=Reg[i2] ;
		     S->sy_word =j_Word ;
		     i_str=Format->find_struct( fdst,Reg );
		     if( i_str<=-10 )
        	     {   fprintf( File_Error,"\n Неизвестный тэг\"%s\"\n",Reg ); throw(-1);  }
		     S->i_struct=i_str ;
		     S->i_relation=j_Relation++ ;
		     S=Struct+(++j_Struct) ;
		 }
		 if( c==':' ) fstr=0 ;
		 j=0 ;
	     }
	     if( c==')' )
	     {  Reg[j-1]=0 ;
		t_sStruct *S1=&Struct[j_Struct-1] ;
        	make_relation1( fdst, S1, Reg );
		j=0 ;
	     }
	 }
	 else
	 {   // -------- если разбирается тело структуры --------
	     if( c=='[' || c=='~' )
	     {   short i_str ;

		 Reg[j-1]=0 ;
		 for( j1=i2=0 ; i2<j ; i2++ )
		    if( Reg[i2]!=' ' ) Reg[j1++]=Reg[i2] ;
		 i_str=Format->find_struct( fdst,Reg );
		 if( i_str<=-10 )
        	 {   fprintf( File_Error,"\n Неизвестный тэг\"%s\"\n",Reg ); throw(-1);  }
        	 W->i_struct=i_str ;
		 j=0 ;

		 if( c=='[' )
		 {  if( fformat==0 )
		    {   S->sy_word =j_Word ;
			S->i_struct=W->i_struct ;
			S->i_relation=j_Relation++ ;
			S=Struct+(++j_Struct) ;
		    }
		    W->sy=i1+1 ;
		 }
		 else
		 {
		    Mass[i1]=0 ;
		    W->sy=i1 ;
		    W=Word+(++j_Word) ;
		 }
		 continue ;
	     }
	     if( c==']' )
	     {  Mass[i1]=0 ;
		W=Word+(++j_Word) ;
		j=0 ;
		continue ;
	     }
	     if( c=='(' || c=='<' )
		j=0 ;
	     if( c=='>' ) 
	     {  Reg[j-1]=0 ; Word[j_Word-1].order=atoi(Reg); j=0 ; }
	     if( c==')' )
	     {  Reg[j-1]=0 ;
		t_sStruct *S1=&Struct[j_Struct-1] ;
		short      iw=j_Word-S1->sy_word-1 ;
		make_relation2( fdst, S1, iw, Reg, j_Relation );
		j=0 ;
	     }
	 }
      }
   }   
   // ----- проставть конечные значения --------------
   Struct[j_Struct].sy_word   =j_Word ;
   Struct[j_Struct].i_relation=j_Relation ;
   Record[j_Record].sy_struct =j_Struct ;

   // ----- проставть ссылки Struct[].Word -----------
   for( i=0 ; i<n_Struct ; i++ )
   {  Struct[i].Word=Word+Struct[i].sy_word ;
      Struct[i].n_Word=Struct[i+1].sy_word-Struct[i].sy_word ;
      Relation[Struct[i].i_relation].s1=Struct[i+1].i_relation-Struct[i].i_relation-1 ;
   }

   // ----- проставть Record[].n_struct --------------
   for( i=0 ; i<n_Record ; i++ )
      Record[i].n_struct=Record[i+1].sy_struct-Record[i].sy_struct ;

   // ------ проверить TSTRUCT1 ----------------------
{
   char f_error=0 ;
   for( i=0 ; i<n_Record ; i++ )
   {  t_Struct *S0 ;
      for( i1=0 ; i1<Record[i].n_struct ; i1++ )
      {  S=&Struct[Record[i].sy_struct+i1] ;
         if( S->i_struct<0 ) continue ;
         if( i1==0 ) S0=&Grammar[S->i_struct].From ;
	     else    S0=&Grammar[S->i_struct].To ;
         if( S0->type!=TSTRUCT1 ) continue ; // ABR
         if( S0->Word.j!=S->n_Word )
	 {   fprintf( File_Error,"\n Несоответствие числа слов в Структура1");
	     fprintf( File_Error,"\n строка %ld",i+1 );	     
	     f_error=1 ;
	 }
	 for( i2=0 ; i2<S0->Word.j ; i2++ )
	 {  if( S0->Word[i2].i_struct!=S->Word[i2].i_struct )
	    {   fprintf( File_Error,"\n Несоответствие типов слов в Структура1");
	        fprintf( File_Error,"\n строка %ld",i+1 );
		f_error=1 ;
	    }
	 }
      }
   }
   if( f_error==1 ) throw(-1);
}
   
   // ----- поджать массив Record --------------------
   for( i=j_Record=0 ; i<n_Record ; i++ )
      if( 0<Record[i].n_struct ) Record[j_Record++]=Record[i] ;
   n_Record=j_Record ;
   
   // ------ проставить ссылки Word[].str ------------
   for( i=0 ; i<n_Word ; i++ )
      Word[i].str=(char *)Mass+Word[i].sy ;

   // ------ исключить нулевые строки ----------------
   for( i=0 ; i<l_Mass ; i++ )
      if( Mass[i]=='\n' ) Mass[i]=0 ;     

   Relation=(t_Relation *)Realloc( Relation,j_Relation*sizeof(t_Relation) );
   n_Relation=j_Relation ;
}
catch( int E )
{
   fprintf( File_Error,"\nSlowo3::Строка=\"%s\"\n",Msg );
   Read_Error=-1 ;
   throw( E );
}
}
/***************************************************************************/
//           задать постоянные параметры заголовку структуры
//    fdst   - 0-источник 1-приемник
//    S      - заполняемая структура
//    Str    - строка, содержащая параметры, например "Родительный,Множественное"
/***************************************************************************/

void t_Slowo3 :: make_relation1( char fdst, t_sStruct *S, char *Str )
{
   short  i,j,j_param ;
   char   c,Str1[20] ;

   S->Param.init();
   for( i=j=j_param=0 ; i<100 ; i++ )
   {  c=Str[i] ;
      if( c==' ' ) continue ;
      if( c==0 || c==',' )
      {   Str1[j]=0 ; j=0 ;
          S->Param.value[j_param]=find_value1( S->i_struct, j_param, fdst, Str1 ) ;
	  j_param++ ;
      }
      if( c==0 ) break ;
      Str1[j++]=c ;
   }
}
/***************************************************************************/
//           сделать таблицу передачи параметров для структуры,
//           и задать постоянные параметры
//    fdst   - 0-источник 1-приемник
//    S      - заполняемая структура
//    i_word - индекс части структуры  t_sStruct->Word[i_word]
//    Str    - строка, содержащая параметры, например "Родительный,Множественное"
//    j_Relation - ссылка на первый свободный элемент в массиве Relation
/***************************************************************************/
void t_Slowo3 :: make_relation2( char fdst, t_sStruct *S, long i_word, 
                  char *Str, long &j_Relation )
{
   t_sWord      *W=Word+S->sy_word+i_word ;
   t_Param1List *pParam ;
   t_Relation    R ;
   short  i,i1,j,j_param,v ;
   char   c,Str1[20] ;

   if( i_word<0 )
   {  fprintf( File_Error,"\nmake_relation i_word<0 !!!\n"); throw(-1);  }

   W->Param.init();
   for( i=j=j_param=0 ; i<100 ; i++ )
   {  c=Str[i] ;
      if( c==' ' ) continue ;
      if( c==0 || c==',' )
      {   Str1[j]=0 ; j=0 ;

          v=find_value1( W->i_struct, j_param, fdst, Str1 ) ;

          if( 0<=v || 0==strcmp(Str1,"@0") )
	      W->Param.value[j_param]=v ;
	  else
	  {
             if( S->i_struct<0 )
	     {  fprintf( File_Error,"\nmake_relation1::S->i_struct<0"); throw(-1);  }

	     if( fdst==0 )
	              pParam=&Grammar[S->i_struct].From.Param ;
		 else pParam=&Grammar[S->i_struct].To.Param ;

	     i1=find_param1( pParam, Str1 );

	     if( i1<0 )
	     {  fprintf( File_Error,"\nmake_relation2::параметр структуры не найден"); throw(-1);  }

	     if( pParam->list[i1].Dir==1 )
	     {  // ----- передача параметров от структуры к ее части
	     	R.s1=0 ;
		R.p1=i1 ;
		R.s2=i_word+1 ;
		R.p2=j_param ;
	     }
	     else
	     {  // ----- передача параметров от части к структуре
	     	R.s2=0 ;
		R.p2=i1 ;
		R.s1=i_word+1 ;
		R.p1=j_param ;
	     }
	     Relation[j_Relation++]=R ;
	  }
	  j_param++ ;
      }
      if( c==0 ) break ;
      if( c==',' ) continue ;
      Str1[j++]=c ;
   }
}
/***************************************************************************/
//   найти значение грамматического параметра по имени значения 
//   i_struct - индекс части речи или структуры
//   i_param  - индекс параметра в этой структуре t_Struct->Param[i_struct]
//   fdst     - 0-источник 1-приемник
//   Str1     - значение параметра, например "Дательный"
/***************************************************************************/
short t_Slowo3 :: find_value1( short i_struct, short i_param, char fdst, char *Str1 )
{  short    v, i_rename ;
   t_Param1List *pParam ;
   t_ValueList  *value ;

   if( i_struct<0 )
   {  fprintf( File_Error,"\nmake_relation2::W->i_struct<0"); throw(-1);  }

   if( fdst==0 )
   {   pParam=&Grammar[i_struct].From.Param ;
       value =&Grammar.from().Param[pParam->list[i_param].param].Value ;
   }
   else
   {   pParam=&Grammar[i_struct].To.Param ;
       value =&Grammar.to().Param[pParam->list[i_param].param].Value ;
   }

   if( pParam->j<=i_param )
   {  fprintf( File_Error,"\nmake_relation2::pParam.j<=i_param"); throw(-1);  }

   i_rename=find_rename( Str1 );
   if( 0<=i_rename )
	    v=find_value( value, Format->Rename[i_rename].Full );
       else v=find_value( value, Str1 );
	      
   return v ;
}
/***************************************************************************/
//
/***************************************************************************/

short t_Slowo3 :: find_rename( char *Str )
{
   for( short i=0 ; i<Format->Rename.j ; i++ )
      if( 0==strcmp( Str,Format->Rename[i].Reduce ) ) return i ;
   return -1 ;
}
/***************************************************************************/
//               построить дерево поиска слов и выражений
/***************************************************************************/

void t_Slowo3 :: make_tree( void )
{
   long  i,i1,j ;
   short s,s1,n ;
   char  *Str,*Str1 ;
   t_sStruct *S,*S1 ;
   t_sTree   *T ;

   Tree=(t_sTree *)Calloc( 4*n_Word,sizeof(t_sTree) );

   Tree[0].up=-1 ;
   Tree[0].down=1 ;
   Tree[0].first =0 ;
   Tree[0].last  =n_Record ;
   Tree[0].rang  =-2 ;
   // ----------- первый уровень - по индексам структур --------
   Tree[1].first=0 ;
   Tree[1].rang =-1 ;
   s=Struct[Record[0].sy_struct].i_struct ;

   for( i=0,j=2 ; i<n_Record ; i++ )
   {  s1=Struct[Record[i].sy_struct].i_struct ;
      if( s1!=s )
      {   Tree[j-1].last = i-1 ;
	  Tree[j].first  = i ;
	  Tree[j].rang   =-1 ;
	  j++ ;
	  s=s1 ;
      }
   }
   Tree[j-1].last=n_Record ;
   Tree[0].n_down=j-1 ;
   // ----------- следующие уровни - по индексам слов --------
   for( i=1 ; i<j ; i++ )
   {  T=&Tree[i] ;
      n=T->rang+1 ;

      S=&Struct[Record[T->first].sy_struct] ;
      if( (T->last-T->first)<=1 && S->n_Word<=n )
      {
         T->down=-1 ;
	 T->n_down=0 ;
         continue ;
      }
      T->down=j ;
      S =&Struct[Record[T->first].sy_struct] ;
      S1=&Struct[Record[T->last ].sy_struct] ;
      if( S->n_Word<=n  ) s =-2 ; else s =S->Word[n].i_struct ;
      if( S1->n_Word<=n ) s1=-2 ; else s1=S1->Word[n].i_struct ;
      if( s!=s1 )
      {   // ---- структура с неодинаковыми сыновьями ----
          T->empty=2 ;
	  s=-10 ;
          for( i1=T->first ; i1<=T->last ; i1++ )
	  {  S=&Struct[Record[i1].sy_struct] ;
	     if( S->n_Word<=n ) s1=-2 ;
		 else           s1=S->Word[n].i_struct ;
	     if( s1!=s )
	     {   if( i1!=0 && s!=-10 ) Tree[j-1].last =i1-1 ;
		 Tree[j].up     =i ;
		 Tree[j].first  =i1 ;
		 Tree[j].rang   =n-1 ;
		 Tree[j].empty  =1 ;
		 s=s1 ;
		 j++ ;
	      }
	  }
	  Tree[j-1].last=T->last ;
	  T->n_down     =j-T->down ;
      }
      else
      {   // ---- структура с одинаковыми сыновьями ----
          Str="\7" ;
	  for( i1=T->first ; i1<=T->last ; i1++ )
	  {  S=&Struct[Record[i1].sy_struct] ;
	     if( S->n_Word<=n ) Str1="" ;
		 else           Str1=(char *)Mass+S->Word[n].sy ;
	     if( 0!=Strcmp( Str1,Str ) || S->n_Word==(n+1) )
	     {   if( i1!=T->first ) Tree[j-1].last =i1-1 ;
		 Tree[j].up     =i ;
		 Tree[j].first  =i1 ;
		 Tree[j].rang   =n ;
		 Str=Str1 ;
		 j++ ;
	     }
	  }
	  Tree[j-1].last=T->last ;
	  T->n_down     =j-T->down ;
       }
   }
   n_Tree=j ;
   Tree=(t_sTree *)Realloc( Tree,j*sizeof(t_sTree));
}
/***************************************************************************/
//             размножить все cтруктуры типа "беспорядок"
/***************************************************************************/

void t_Slowo3 :: split_unorder( void )
{  long i,i1,i2,f,ns,z,N ;
   long j_Record,  j_Struct,  j_Word,  j_Relation ;
   long n_Record1, n_Struct1, n_Word1, n_Relation1 ;
   e_Type     t ;
   t_sRecord *R ;
   t_sStruct *S ;
   
   n_Record1=n_Struct1=n_Word1=n_Relation1=0 ;

   for( f=i=0 ; i<n_Record ; i++ )
   {  S=&Struct[Record[i].sy_struct] ;
      if( S->i_struct<0 ) continue ;
      t=Grammar[S->i_struct].From.type ;
      if( t==TUNORDER1 || t==TUNORDER2 )
      {   N=Factorial.fak[S->n_Word]-1 ;
          n_Record1  +=N ;
	  n_Struct1  +=N*Record[i].n_struct ;
	  n_Word1    +=N*S->n_Word ;
	  n_Relation1+=N*(Relation[S->i_relation].s1+1) ;
      }
   }
   if( n_Record1==0 ) return ;

   long NN   =n_Record ;
   
   j_Record  =n_Record   ; n_Record  +=n_Record1 ;
   j_Struct  =n_Struct   ; n_Struct  +=n_Struct1 ;
   j_Word    =n_Word     ; n_Word    +=n_Word1 ;
   j_Relation=n_Relation ; n_Relation+=n_Relation1 ;
   Record  =(t_sRecord  *)Realloc( Record  ,(n_Record+1)* sizeof( t_sRecord  ) );
   Struct  =(t_sStruct  *)Realloc( Struct  ,(n_Struct+1)* sizeof( t_sStruct  ) );
   Word    =(t_sWord    *)Realloc( Word    ,n_Word      * sizeof( t_sWord    ) );
   Relation=(t_Relation *)Realloc( Relation,n_Relation  * sizeof( t_Relation ) );

   // ---- c Relation не понятно что делать

   for( f=i=0 ; i<NN ; i++ )
   {  R=&Record[i] ;
      S=&Struct[Record[i].sy_struct] ;
      if( S->i_struct<0 ) continue ;
      t=Grammar[S->i_struct].From.type ;
      if( t==TUNORDER1 || t==TUNORDER2 )
      {   N=Factorial.fak[S->n_Word] ;
          for( i1=1 ; i1<N ; i1++ )
	  {  Record[j_Record]=*R ;
	     Record[j_Record].sy_struct=j_Struct ;
	     Struct[j_Struct]=*S ;
	     Struct[j_Struct].sy_word=j_Word ;
	     for( i2=0 ; i2<S->n_Word ; i2++ )
	     {  z=Factorial.value[i1*Factorial.n+i2] ;
	        Word[j_Word++]=S->Word[z] ;
	     }
	     Relation[j_Relation++].s1=ns=Relation[S->i_relation].s1 ;
	     for( i2=0 ; i2<ns ; i2++ )
	     {  t_Relation R1=Relation[S->i_relation+i2+1] ;
	        Relation[j_Relation]   =R1 ;
	        Relation[j_Relation].s1=Factorial.use(i1,R1.s1) ;
		Relation[j_Relation].s2=Factorial.use(i1,R1.s2) ;
		j_Relation++ ;
	     }
	     j_Struct++ ;
	     for( i2=1 ; i2<R->n_struct ; i2++ )
	        Struct[j_Struct++]=S[i2] ;
	     j_Record++ ;
	  }
      }
      if( n_Record<j_Record || n_Struct<j_Struct || n_Word<j_Word || n_Relation<j_Relation )
      {   printf("\nВнутренняя ошибка в t_Slowo3 :: split_unorder\n"); 
          exit(-1);  
      }
   }
   // ----- проставть конечные значения ---------------------------
   Struct[j_Struct].sy_word   =j_Word ;
   Struct[j_Struct].i_relation=j_Relation ;
   Record[j_Record].sy_struct =j_Struct ;

   // ----- проставть ссылки куда надо ----------------------------
   for( i=0 ; i<n_Struct ; i++ )
      Struct[i].Word=Word+Struct[i].sy_word ;

   for( i=0 ; i<n_Word ; i++ )
      Word[i].str=(char *)Mass+Word[i].sy ;
}
/***************************************************************************/
//              функция упорядочивания структур (больше-меньше)
/***************************************************************************/
int funk0( const void *a, const void *b )
{  t_sStruct *S1,*S2 ;
   short f,iw,nw,is1,is2 ;

   S1=Slowo3->sstruct((*(t_sRecord **)a)->sy_struct) ;
   S2=Slowo3->sstruct((*(t_sRecord **)b)->sy_struct) ;

   if( S1->i_struct!=S2->i_struct ) return S1->i_struct-S2->i_struct ;

   nw=min( S1->n_Word,S2->n_Word ) ;
   for( iw=0 ; iw<nw ; iw++ )
   {
      is1=S1->Word[iw].i_struct ;
      is2=S2->Word[iw].i_struct ;
      if( is1 != is2 ) return is1-is2 ;
      f=Strcmp( S1->Word[iw].str,S2->Word[iw].str );
      if( f!=0 ) return f ;
   }
   if( S1->n_Word != S2->n_Word ) return S1->n_Word - S2->n_Word ;
   return (*(t_sRecord **)a)->i_dict - (*(t_sRecord **)b)->i_dict ;
}
/***************************************************************************/
//            Отсортировать структуры в должном порядке
/***************************************************************************/

void t_Slowo3 :: sort0( void )
{  long i ;
   t_sRecord *R, **RR ;
   
   Slowo3=this ;
   RR=(t_sRecord **)Malloc( n_Record,sizeof(t_sRecord *) );
   for( i=0 ; i<n_Record ; i++ )
      RR[i]=Record+i ;

   qsort( RR,n_Record,sizeof(t_sRecord *),funk0 );

   R =(t_sRecord *)Calloc( n_Record+1,sizeof(t_sRecord) );
   for( i=0 ; i<n_Record ; i++ )
      R[i]=*RR[i] ;
   Free( Record ); Free( RR );
   Record=R ;
}
/***************************************************************************/
//               Вставить новые выражения в словарь
/***************************************************************************/

void t_Slowo3 :: add_new( char *Dir, char *str )
{
   long   L ;
   FILE  *fw ;
   t_FileList &File1=Grammar.file1() ;
   char  *ff ;
   char   Str[200] ;

   if( 0!=strcmp(File1[0].FileName[File1[0].FileName.j-1],"base_new.tmp" ) )
   {   ff=(char *)Malloc( 20,sizeof(char) );
       strcpy( ff,"base_new.tmp" );
       File1[0].FileName.add( ff );
   }
   L=strlen( str );
   fw=Fopen( filename( Dir,"base_new.tmp" ),"w" );
   Fwrite( str,L,sizeof(char),fw );
   Fclose( fw );
   File_Error=Fopen("mercury.err","w+"); 
   read( Dir, &Grammar );
   Fclose( File_Error );
}
/***************************************************************************/
//          разбиение фразы на составные части (итерационная)
/***************************************************************************/

void t_Slowo3 :: s_universe( short i_word, short i_struct )
{
   long  i,i1,i2,j,z,N1,i_tree ;
   char *Str ;
   t_sTree    *T ;
   t_sStruct  *S ;
   t_sWord    *W ;
   t_Variants *VV ;
   t_rStruct   SS ;
   t_rWord     R,*pR ;
   t_Tree      N,*pN ;
   t_TreeList  Node ;

   if( n_Tree<=0 ) return ;
   if( Core.From.j<=i_word ) return ;
   i_tree=root_of_struct( i_struct );
   if( i_tree<0 ) return ;

   // ---- построение дерева вариантов ------
   N.link=i_tree ;
   N.i_last_word=i_word ;
   Node.add(N);

   for( i=0 ; i<Node.j ; i++ )
   {  i_tree=Node[i].link ;
      T=&Tree[i_tree] ;

      if( Node[i].type==TNULL ) continue ; //  прописать вариант

      if( T->empty==2 )
      {   // ---- случай с произвольными структурами и разными сыновьями ----
	  for( i1=0 ; i1<T->n_down ; i1++ )
	  {  z=T->down+i1 ;
	     N.type       = TSTRUCT ;
	     N.up         = i ;
	     N.i_word     = Node[i].i_last_word ;
	     N.i_last_word= Node[i].i_last_word ;
	     N.link       = z ;
	     N.i_struct   =-1 ;
	     N.i_variant  = 0 ;
	     N.index      = T->rang ; // T->rang+1 
	     N.i_slowo    =-1 ;
	     Node.add(N);
	  }
	  continue ;
      }

      // --------- транслировать дальше --------------
      S=Struct+Record[T->first].sy_struct ;
      W=&S->Word[T->rang+1] ;

      if( W->i_struct==-1 )
      {  // ------ слово является константой ---------
         if( Core.n_word<=Node[i].i_last_word )
	     Antwort.j=0 ;
	 else
	     find_bin( Core.From[Node[i].i_last_word].Str1, i_tree );
	 for( i1=0 ; i1<Antwort.j ; i1++ )
	 {  z=Antwort[i1] ;
	    S=Struct+Record[Tree[z].first].sy_struct ;
	    W=&S->Word[Tree[z].rang] ;
	    for( i2=j=1 ; W->str[i2]!=0 ; i2++ )
	       if( W->str[i2]==' ' && W->str[i2-1]!=' ' ) j++ ;
	    N.type       = TSTRUCT ; // формальность
	    N.up         = i ;
	    N.i_word     = Node[i].i_last_word ;
	    N.i_last_word= Node[i].i_last_word+j ;
	    N.link       = z ;
	    N.i_struct   =-1 ;
	    N.i_variant  = i1 ;
	    N.index      = T->rang+1 ;
	    N.i_slowo    =-1 ;
	    if( Tree[z].n_down<=0 )
		N.type=TNULL ;
	    Node.add(N);
	 }
      }
      else
      {  // ------ слово может иметь всякостные формы ------
         if( Core.From.j<=Node[i].i_last_word ) 
	     continue ;
	 Core.universe( Node[i].i_last_word,W->i_struct );
	 VV=Core.variants( Node[i].i_last_word,W->i_struct );
	 // ---- литерал таки задан --------
	 // ---- вот здесь херачится большое количество ненужных вариантов
	 // ---- (связанных с тем, что по-русски это слово 10-ю способами переводится)
	 //for( i1=0 ; i1<VV->Variant.j ; i1++ )
	 //if( 0<VV->Variant.j )
	 long NN ;
	 if( IF_WORD( Grammar[W->i_struct].From.type ) )
	          NN=min( 1,VV->Variant.j ) ;
	     else NN=VV->Variant.j ;
	 for( i1=0 ; i1<NN; i1++ )	 
	 {  // ------- цикл по вариантам -------------
	    Str=Core.get_meaning( &VV->Variant[i1] ) ; // смысл варианта
	    find_bin( Str, i_tree );
	    for( i2=0 ; i2<Antwort.j ; i2++ )
	    {  z=Antwort[i2] ;
	       N.type       = TSTRUCT ; // формальность
	       N.up         =i ;
	       N.i_word     =VV->Variant[i1].i_word ;
	       N.i_last_word=VV->Variant[i1].i_last_word ;
	       N.link       =z ;
	       N.i_struct   =W->i_struct ;
	       N.i_variant  =i1 ;
	       N.index      =T->rang+1 ;
	       N.i_slowo    =VV->Variant[i1].i_slowo ;
	       if( Tree[z].n_down<=0 )
		   N.type=TNULL ;
	       Node.add(N);
	    }
	 }
      }
   }
   // ---- собирание вариантов ----------------
   t_Struct *S1=&Grammar[i_struct].From ;
   VV=Core.variants( i_word, i_struct );
   for( i=0 ; i<Node.j ; i++ )
   {  if( Node[i].type!=TNULL ) continue ;
      // ----- заполнение заголовка структуры ---------
      T=&Tree[Node[i].link] ;
      SS.type       =S1->type ;
      SS.i_word     =i_word ;
      SS.i_last_word=Node[i].i_last_word ;
      SS.i_struct   =i_struct ;
      SS.r_word     =Core.rWord.j ;
      SS.i_slowo    =T->first ;
      SS.Form       =Struct[Record[T->first].sy_struct].Param ;
      N1=get_n_perevod( SS.i_slowo );

      if( 0==is_atom(SS.i_slowo) ) // к стати сюда же логично воткнуть проверку
          N1=min( 1,N1 );          // на IF_WORD а не там, где она сейчас стоит

      // ---- цикл по вариантам перевода этой структуры -----
      for( i1=0 ; i1<N1 ; i1++)
      {  
         SS.i_slowo1=i1 ;
         // ----- внесение, но не заполнение составляющих структуры ---
	 for( i2=0 ; i2<=T->rang ; i2++ )
	    Core.rWord.add(R);

         // ----- заполнение составляющих структуры -----------------------
	 // ----- (в порядке задом наперед от листа дерева к его корню) ---
	 z=i ;
	 while( 1 )
	 {  pN=&Node[z] ;
	    if( Tree[pN->link].empty!=1 )
	    {   pR =&Core.rWord[SS.r_word+Tree[pN->link].rang] ;
		if( pN->i_struct<0 )
	        	 pR->type =TCONST ;
                    else pR->type =Grammar[pN->i_struct].From.type ;
		pR->i_word     =pN->i_word ;
		pR->i_last_word=pN->i_last_word ;
		pR->i_struct   =pN->i_struct ;
		pR->i_variant  =pN->i_variant ;
		pR->index      =pN->index ;
		pR->i_slowo    =pN->i_slowo ;
		pR->i_slowo1   =0 ;           // не уверен
	    }
	    z=pN->up ;
	    if( z==0 ) break ;
	 }
	 VV->Variant.add(SS);
	 Core.real_param_up( &VV->Variant[VV->Variant.j-1] );
      }
   }
}
/**************************************************************************/
//                      одновариантный перевод слова
//   From     - переводимое слово
//   i_slowo  - строка записи в словаре t_Slowo3->Record[i_slowo]
//   i_slowo1 - вариант перевода
/**************************************************************************/
char 
* t_Slowo3 :: translate_word_i( char *From, long i_slowo, short i_slowo1 )
{
   strcpy( Word0,From );
   if( i_slowo<0 ) return Word0 ;
   
   t_sStruct *S=&Struct[Record[i_slowo].sy_struct+1+i_slowo1] ;

   Word0[0]=0 ;   
   for( short i=0 ; i<S->n_Word ; i++ )
   {  strcat( Word0,S->Word[i].str ); 
      if( i<S->n_Word-1 ) strcat( Word0," " );  
   }
   //strcpy( Word0,(char *)Mass+Struct[Record[i_slowo].sy_struct+1+i_slowo1].Word[0].sy );
   return Word0 ;
}
/**************************************************************************/
//                      одновариантный перевод слова
//   From     - переводимое слово
//   i_struct - часть речи, которой должно быть это слово
//   i_slowo1 - вариант перевода
/**************************************************************************/
char 
* t_Slowo3 :: translate_word_s( char *From, short i_struct, short i_slowo1 )
{
   t_longList Ant ;
   e_Type t ;
   long   a ;
   
   if( 0<=i_struct )
   {   t=Grammar[i_struct].To.type ;
       if( t==TSTRUCT1 || t==TSTRUCT2 )
       {   strcpy( Word0,"" );  return Word0 ;  }
   
       if( Grammar[i_struct].To.type!=TWORD )
           return NULL ; // признак неправильного вызова
   }
   strcpy( Word0,From );
   if( n_Tree<=0 ) return Word0 ;
   
   find( From, i_struct, &Ant );
   if( Antwort.j<=0 ) return Word0 ; //  такого слова нет в словаре

   a=Antwort[0] ;
   if( Record[a].n_struct<=i_slowo1+1 ) i_slowo1=0 ;
   strcpy( Word0,(char *)Mass+Struct[Record[a].sy_struct+1+i_slowo1].Word[0].sy );
   return Word0 ;
}
/***************************************************************************/
//     найти слово в дереве
//     From1  - искомое слово
//     i_struct - требуемая часть речи
//     *_a, *_b  диапазон номеров в t_sRecord встречается это слово
/***************************************************************************/

void t_Slowo3 :: find( char *From1, short i_struct, t_longList *Ant )
{
   long   i,zz ;

   Antwort.j=0 ;
   Ant->j=0 ;
   if( From1[0]==0 ) return ;
   if( n_Tree<=0 ) return ;
   
   zz=root_of_struct( i_struct );
   if( zz<0 ) return ;

   find_bin( From1, zz );
   
   for( i=0 ; i<Antwort.j ; i++ )
   {  Antwort[i]=Tree[Antwort[i]].first ;
      Ant->add( Antwort[i] );
   }
}
/***************************************************************************/
//     найти СТРУКТУРУ в дереве, начиная с определенной ветки
//     если не получилось, укоротить выражение, до тех пор пока не найдется
//     From1  - искомое слово
//     zz - ветка начала поиска
/***************************************************************************/

char t_Slowo3 :: find_bin( char *From1, long zz )
{
   long   i ;
   char   From2[100] ;

   Antwort.j=0 ;
   for( i=0 ; i<100 ; i++ )
   {  if( From1[i]==0 )
      {   From2[i]=0 ; find_bin1( From2, zz ); break ;  }
      if( From1[i]==' ' )
      {   From2[i]=0 ; 
          if( 0==find_bin1( From2, zz ) ) break ;
	  From2[i]=' ' ; 
      }
      From2[i]=From1[i] ;
   }
   if( Antwort.j<=0 ) return -1 ;
   return 0 ;
}
/***************************************************************************/
//     найти СТРУКТУРУ в дереве, начиная с определенной ветки
//     и без всяких хитростев сказать, есть оно в словаре или нет
//     From1  - искомое слово
//     i_tree - ветка начала поиска
/***************************************************************************/

char t_Slowo3 :: find_bin1( char *From1, long i_tree )
{
   long   a,b,b1,c,i,L,L1 ;
   char   f, *Str ;
   char   ff=0 ;     // факт наличия строки влючающей в себя Form1

   L=strlen(From1);
   a=Tree[i_tree].down ;
   b=b1=a+Tree[i_tree].n_down-1 ;
   while( 1 )
   {
      if( b-a<4 )
      {   for( i=a ; i<=b ; i++ )
	     if( 0==Strncmp( From1,word_src(i),L ) ) break ;
	  a=i ;
	  break ;
      }
      c=(a+b)/2 ;
      f=Strncmp( From1,word_src( c ),L );
      if( f<0 ) b=c ;
      if( f>0 ) a=c ;
      if( f==0 )
      {	  for( i=c ; a<i ; i-- )
	     if( 0!=Strncmp( From1,word_src(i),L) ) {  a=i+1 ; break ;  }	  
	  break ;
      }
   }
   for( i=a ; i<=b && i<=b1 ; i++ )
   {  Str=word_src(i);      
      f=Strncmp( From1,Str,L );
      if( 0>f ) break ;
      L1 =strlen(Str);      
      if( L==L1 ) Antwort.add(i) ;
          else    ff=1 ;
      if( 0==L && 0<L1 ) break ;
   }
   return ff ;
}
/***************************************************************************/
//    найти ветвь в дереве, с которой начинаются структуры типа i_struct
/***************************************************************************/

long t_Slowo3 :: root_of_struct( short i_struct )
{  long i ;

   for( i=0 ; i<Tree[0].n_down ; i++ )
      if( Struct[Record[Tree[1+i].first].sy_struct].i_struct==i_struct )
          return i+1 ;
   return -1 ;
}
/***************************************************************************/
//                какими частями речи является слово From
/***************************************************************************/

short t_Slowo3 :: part( char *From, short *i_Part )
{  short i,j ;
   t_sStruct *S ;
   t_longList Ant ;

   if( n_Tree<=0 ) return j ;
   for( i=j=0 ; i<Tree[0].n_down ; i++ )
   {
      S=Struct+Record[Tree[1+i].first].sy_struct ;
      if( S->i_struct<0 ) continue ;
      if( Grammar[S->i_struct].From.type!=TWORD ) continue ;
      find( From, S->i_struct,&Ant );
      if( 0<Ant.j )
          i_Part[j++]=S->i_struct ;
   }
   return j ;
}
/***************************************************************************/
//                постоянные параметры структуры i_slowo
/***************************************************************************/

t_Form t_Slowo3 :: struct_param( long i_slowo, long i_variant )
{
   t_Form     Form0 ;
   t_sStruct *S ;

   if( i_slowo<0 || n_Record<=i_slowo ) return Form0 ;
   if( i_variant==-1 )
            S=&Struct[Record[i_slowo].sy_struct] ;
       else S=&Struct[Record[i_slowo].sy_struct+1+i_variant] ;
   return S->Param ;
}
/***************************************************************************/
//                постоянные параметры слова i_slowo
/***************************************************************************/

t_Form t_Slowo3 :: word_param( long i_slowo, long i_variant, long i_word )
{
   t_Form     Form0 ;
   t_sStruct *S ;

   if( i_slowo<0 || n_Record<=i_slowo ) return Form0 ;
   if( i_variant<-1 || Record[i_slowo].n_struct<=i_variant-1 ) return Form0 ;
   if( i_variant==-1 )
            S=&Struct[Record[i_slowo].sy_struct] ;
       else S=&Struct[Record[i_slowo].sy_struct+1+i_variant] ;
   if( i_word<0 || S->n_Word<=i_word ) return Form0 ;
   return S->Word[i_word].Param ;
}
/***************************************************************************/
//
/***************************************************************************/
t_Format1 * t_Slowo3 :: format( void )
{
   return Format ;
}
/***************************************************************************/
//
/***************************************************************************/
t_sRecord * t_Slowo3 :: record( long i_record )
{
   return &Record[i_record] ;
}
/***************************************************************************/
//
/***************************************************************************/

long t_Slowo3 :: n_record( void )
{
   return n_Record ;
}
/***************************************************************************/
//        есть ли у данной конструкции неатомарные потомки
//        возвращает 1 если есть
/***************************************************************************/

char t_Slowo3 :: is_atom( long i_record )
{
   if( i_record<0 ) return 1 ;

   t_sStruct *S=&Struct[Record[i_record].sy_struct] ;

   for( long i=0 ; i<S->n_Word ; i++ )
   {  if( S->Word[i].i_struct<0 ) continue ;
      e_Type t=Grammar[S->Word[i].i_struct].From.type ;
      if( IF_CONSTR(t) ) return 1 ;
   }
   return 0 ;
}
/***************************************************************************/
//              элемент дерева переводов
/***************************************************************************/
t_sTree * t_Slowo3 :: tree( long i_tree )
{
   return &Tree[i_tree] ;
}
/***************************************************************************/
//
/***************************************************************************/
t_sStruct * t_Slowo3 :: sstruct( long i_struct )
{
   return &Struct[i_struct] ;
}
/***************************************************************************/
//              дать переводимую структуру
/***************************************************************************/
t_sStruct * t_Slowo3 :: get_from( long i_slowo )
{
   if( i_slowo<0 || n_Record<=i_slowo ) return NULL ;
   return &Struct[Record[i_slowo].sy_struct] ;
}
/***************************************************************************/
//               перевод структуры
//               i_slowo   - индекс переводимой строки
//               i_variant - вариант перевода
/***************************************************************************/
t_sStruct * t_Slowo3 :: get_to( long i_slowo, long i_variant )
{
   if( i_slowo<0 || n_Record<=i_slowo ) return NULL ;
   if( Record[i_slowo].n_struct<i_variant+1 ) i_variant=0 ;
   return &Struct[Record[i_slowo].sy_struct+1+i_variant] ;
}
/***************************************************************************/
//               передача параметров
//               i_slowo   - индекс переводимой строки
//               i_variant - вариант перевода (-1 - оригинал)
/***************************************************************************/

t_RelationList1 t_Slowo3 :: get_relation( long i_slowo, long i_variant )
{
   t_RelationList1  RL ;
   t_sStruct       *S ;

   if( i_slowo<0 || n_Record<=i_slowo ) return RL ;
   if( i_variant==-1 )
            S=&Struct[Record[i_slowo].sy_struct] ;
       else S=&Struct[Record[i_slowo].sy_struct+1+i_variant] ;
   RL.list  =Relation+S->i_relation+1 ;
   RL.j=Relation[S->i_relation].s1 ;
   return RL ;
}
/***************************************************************************/
//             дать число возможных переводов по индексу структуры
//             типа "голова" и "жопа"
/***************************************************************************/

short t_Slowo3 :: get_n_perevod( long i_slowo )
{
   return Record[i_slowo].n_struct-1 ; // ABR
}
/***************************************************************************/
//             дать слово по индексу дерева
/***************************************************************************/
char 
* t_Slowo3 :: word_src( long i_tree )
{
   if( i_tree<0 || n_Tree<=i_tree )
   {   printf("\n Error t_Slowo3 :: word_src") ; throw(-1) ;  }
   return (char *)Mass+Struct[Record[Tree[i_tree].first].sy_struct].Word[Tree[i_tree].rang].sy ;
}
/***************************************************************************/
//             дать слово по индексу структуры
/***************************************************************************/
char 
* t_Slowo3 :: word_src1( long i_slowo )
{
   return (char *)Mass+Struct[Record[i_slowo].sy_struct].Word[0].sy ;
}
/***************************************************************************/
//             напечатать строку словаря
/***************************************************************************/

void t_Slowo3 :: print_record( FILE *fw, long i_record )
{
   t_sRecord *R=&Record[i_record] ;
   t_sStruct *S ;
   long       i,j,is ;

   fprintf( fw,"\n" );
   S=&Struct[R->sy_struct];
   
   fprintf( fw,"%s:",Format->get_tag(0,S->i_struct) );
   print_param( fw,0,S->i_struct, S->Param );
   
   for( i=0 ; i<S->n_Word ; i++ )
   {  
      is=S->Word[i].i_struct ;
      if( is<0 ) fprintf( fw,"@0" ) ;
          else   fprintf( fw,"%s",Format->get_tag(0,is) );
      if( S->Word[i].str[0]==0 ) fprintf( fw,"~ ") ;
          else                   fprintf( fw,"[%s] ",S->Word[i].str ) ;
      print_param( fw,0,S->Word[i].i_struct, S->Word[i].Param );
   }
   fprintf( fw,"=" );
   for( j=1 ; j<R->n_struct ; j++ )
   {
      S=&Struct[R->sy_struct+j] ;
      if( 1<j ) fprintf( fw,";" );
      fprintf( fw,"%s:",Format->get_tag(1,S->i_struct) );
      print_param( fw,1,S->i_struct, S->Param );
      
      for( i=0 ; i<S->n_Word ; i++ )
      {  
	 is=S->Word[i].i_struct ;
	 if( is<0 ) fprintf( fw,"@0" );
             else   fprintf( fw,"%s",Format->get_tag(1,is) );
	 if( S->Word[i].str[0]==0 ) fprintf( fw,"~ " );
             else                   fprintf( fw,"[%s] ",S->Word[i].str );
         print_param( fw,1,S->Word[i].i_struct, S->Word[i].Param );
      }
   }  
}
/***************************************************************************/
//             напечатать параметры
/***************************************************************************/

void t_Slowo3 :: print_param( FILE *fw, char to, short i_struct, t_Form &Param )
{
   short  i,ip ;
   char  *s ;

   fprintf( fw,"(" );
   for( i=0 ; i<10 ; i++ )
   {  if( Param.value[i]<0 ) break ;
      if( to==0 )
      {   if( Grammar[i_struct].From.Param.j<=i ) break ;
          ip=Grammar[i_struct].From.Param[i].param ;
	  s =Grammar.from().Param[ip].Value[Param.value[i]].Name;
      }
      else
      {   if( Grammar[i_struct].To.Param.j<=i ) break ;
          ip=Grammar[i_struct].To.Param[i].param ;
	  s =Grammar.to().Param[ip].Value[Param.value[i]].Name;
      }
      if( 0<i ) fprintf( fw,"," );
      fprintf( fw,s );
   }
   fprintf( fw,")" );
}