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

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

short find_param1( t_Param1List *List, char *Str );
short find_value2( t_strList    *List, char *Str );
short find_part(  t_StructList  *List, char *Str );

void  zerstoren_param( char *Str, char *Dir, char **Str1 );
void  zerstoren_word( char *Str, char *Imp, char **Str1 );
char  tst_const( t_Word *W, long i_str );

t_Grammar  Grammar ;         // все данные, относящиеся к грамматике
t_Lexer    Lexer ;           // Лексер, который разбирает lang.txt
FILE      *File_Error=NULL ; // Файл, в который пишутся ошибки lang.txt
char       Read_Error=0 ;    // Есть ли в lang.txt ошибки

/****************************************************************************/
//             прочесть все из файла и построить все индексы
//    File - имя файла lang.txt с путем
/****************************************************************************/

char t_Grammar :: make_all( char *File )
{
try
{
   del( );
   Read_Error=0 ;
   
   File_Error=Fopen("mercury.err","w");
   read( File );
   make_index( );

   for( short i1=0 ; i1<Format1.j ; i1++ )
      Format1[i1].make_part( this ) ;

   Fclose( File_Error );
   // ----------- определить какая часть речи - числительное ------
   i_Number=0 ;
   for( short i=0 ; i<From.Part.j ; i++ )
      if( 0==strcmp( From.Part[i].Name,"числительное" ) )
      {  i_Number=i ; break ;  }

   return Read_Error ; // если тут 0, то все в порядке
}
catch( int E )
{
   if( File_Error!=NULL ) 
   {   fprintf( File_Error,"\n Файл %s не прочитан",File );
       error_add( "t_Grammar :: make_all( " );
       error_add( File );
       error_add( " )\n" );
   }
   Fclose( File_Error );
   Read_Error=-1 ;
   return -1 ;
}
}
/***************************************************************************/

void t_Grammar :: del( void )
{
   From.del() ;
   To.del() ;
   Format1.del() ;
   File1.del() ;
   Trans.del() ;
}
/***************************************************************************/
//              прочесть из файла то, что можно прочесть                    
//    File - имя файла lang.txt с путем
/***************************************************************************/

void t_Grammar :: read( char *File )
{
   char    *Mass, f_version=0 ;
   long     i,L ;
   FILE    *fr ;

try
{  fr=Fopen( File,"r" );
   L=FileLength( fr );
   Mass=(char *)Calloc( L,1 );
   Fread( Mass,L,1,fr );
   Fclose(fr);

   Lexer.clr_breaker(  );
   Lexer.set_breaker( (uchar *)".,;:#$^=+-*/(){}<>[]\"\\." );
   Lexer.init( Mass,L );
   Lexer.make_words();

   From.To=0 ;
   To.To=1 ;

   for( i=0 ; i<Lexer.n_word() ; i++ )
   {
      Ifstr( Lexer.Word[i],"@Версия")
      {   if( 0!=strcmp(Lexer.Word[i+1],"00_00_00") )
          {  fprintf( File_Error,"\n Не та версия lang.txt"); throw(-1);  }
	  f_version=1 ;
      }
      Ifstr( Lexer.Word[i],"@Атомы_источника" )
	 i=From.read( &Lexer,i );
      Ifstr( Lexer.Word[i],"@Атомы_приемника" )
	 i=To.read( &Lexer,i );
      Ifstr( Lexer.Word[i],"@Словари_перевода" )
	 i=read_slowo1( i );
      Ifstr( Lexer.Word[i],"@Переводы" )
	 i=read_trans( i );
   }
   Free( Mass );
   
   if( f_version==0 )
   {  fprintf( File_Error,"\n Отсутствует версия lang.txt"); throw(-1);  }
}
catch( int E )
{
   throw( E );
}
}
/***************************************************************************/
//                      прочесть словари переводов
// Begin - слово, с которого в lang.txt начинается описание словарей перевода
/***************************************************************************/

long t_Grammar :: read_slowo1( long Begin )
{  long i,i1,z,End,End1 ;
   t_Format1 Form,*Form1 ;
   t_File    File2 ;

   End=Lexer.find_paar( Begin,"{","}" );
   for( i=Begin ; i<End ; i++ )
   {  Ifstr( Lexer.Word[i],"@Формат_перевод" )
      {  Format1.add( Form );
	 Form1=Format1.list+Format1.j-1 ;
	 i=read_format1( i,Form1 );
      }
      Ifstr( Lexer.Word[i],"@Файлы_переводов" )
      {
	  File2.i_part=0 ;
	  z=find_format1( Lexer.Word[i+1] );
	  File2.i_format=z ;
	  File2.FileName.j=0 ;

	  End1=Lexer.find_paar( i+2,"{","}" );
	  for( i1=i+3 ; i1<End1 ; i1++ )
	  {  char *a ;
	     Ifstr( Lexer.Word[i1],"," ) continue ;
	     a=(char *)Calloc( strlen(Lexer.Word[i1])+1,1 ); // Memory Leak
	     strcpy( a, Lexer.Word[i1] );
	     File2.FileName.add( a );
	  }
	  File1.add( File2 );
      }
   }
   return End ;
}
/**************************************************************************/
//           прочесть запись типа @Формат_перевода { ... }
//  Begin  - слово, с которого начинсется
//  Format - заполняемая структура
/**************************************************************************/

long t_Grammar :: read_format1( long Begin, t_Format1 *Format )
{  long i,i1,End,End1 ;
   t_PartDsk PartDsk ;

   strcpy( Format->Name, Lexer.Word[Begin+1] );

   Ifstr( Lexer.Word[Begin+2],"{" )
   {  End = Lexer.find_paar( Begin,"{","}" );
      if( End<0 ) {  fprintf( File_Error,"\n Ошибка непарности скобок"); throw(-1);  }
   }
   else {  fprintf( File_Error,"\n Ошибка формата"); throw(-1);  }

   for( i=Begin+3 ; i<End ; i++ )
   {
      Ifstr( Lexer.Word[i],"@Псевдоним" )
      {  // ------------- строка переименование ------------
	 t_Rename Ren ;
	 strcpy( Ren.Reduce, Lexer.Word[i+1] ) ;
	 strcpy( Ren.Full  , Lexer.Word[i+2] ) ;
	 Format->Rename.add( Ren );
	 i+=2 ;
	 continue ;
      }
      Ifstr( Lexer.Word[i],"@Части_речи_источника" )
      {  End1 = Lexer.find_paar( i,"{","}" );
	 for( i1=i+2 ; i1<End1 ; i1+=3 )
	 {  
	    strncpy( PartDsk.Tag ,Lexer.Word[i1],2 ) ;
	    strcpy(  PartDsk.Name,Lexer.Word[i1+1] );
	    if( Lexer.Word[i1+2][0]!=';' )
	    {  fprintf( File_Error,"\n Ошибка формата"); throw(-1);  }
	    Format->SouPart.add( PartDsk );
	 }
	 i=End1 ;
      }
      Ifstr( Lexer.Word[i],"@Части_речи_приемника" )
      {  End1 = Lexer.find_paar( i,"{","}" );
	 for( i1=i+2 ; i1<End1 ; i1+=3 )
	 {  
	    strncpy( PartDsk.Tag ,Lexer.Word[i1],2) ;
	    strcpy(  PartDsk.Name,Lexer.Word[i1+1] );
	    if( Lexer.Word[i1+2][0]!=';' )
	    {  fprintf( File_Error,"\n Ошибка формата"); throw(-1);  }
	    Format->DstPart.add( PartDsk );
	 }
      }
   }
   return End1 ;
}
/***************************************************************************/
//                      прочесть массив переводов
//   Begin  - слово, с которого начинсется
/***************************************************************************/

long t_Grammar :: read_trans( long Begin )
{  long i,i1,End ;

   End=Lexer.find_paar( Begin,"{","}" );
   for( i=Begin ; i<End ; i++ )
   {  Ifstr( Lexer.Word[i],"@Перевод" )
	 i=read_trans1( i );
   }
   copy_words();
   make_index_struct() ;
   for( i1=0 ; i1<Trans.j ; i1++ )
      Trans[i1].make_order( ) ;

   return i ;
}
/***************************************************************************/
//   скопировать описание частей речи в массив переводов t_Grammar->Trans
/***************************************************************************/
void t_Grammar :: copy_words( void )
{  short i,i1,i2,j ;
   char  *m1,*m2 ;
   t_Trans  T,*TT ;
   t_TransList Trans1 ;

   // ----------- найти "незадействованные" структуры --------
   m1=(char *)Calloc( From.Part.j,sizeof(char) );
   m2=(char *)Calloc( To.Part.j,sizeof(char) );
   for( i=0 ; i<Trans.j ; i++ )
   {  i1=find_part( &From.Part, Trans[i].From.Name );
      if( 0<=i1 )
      {   if( m1[i1]!=0 )
	  {   fprintf( File_Error,"\n Многократный перевод атома %ld",
		       Trans[i].From.i_str );
	       Read_Error=-1 ;
	  }
	  m1[i1]=1 ;
      }
      i2=find_part( &To.Part, Trans[i].To.Name );
      if( 0<=i2 )
      {   if( m2[i2]!=0 )
	  {   fprintf( File_Error,"\n Многократный перевод атома %ld",
		       Trans[i].From.i_str );
	       Read_Error=-1 ;
	  }
	  m2[i2]=1 ;
      }
   }
   // ----------- внести их в массив Trans1 -------------------
   for( i=0 ; i<From.Part.j ; i++ )
      if( m1[i]==0 )
      {  Trans1.add( T );
	 TT=Trans1.list+Trans1.j-1 ;
	 TT->From =From.Part[i] ;
	 //TT->From.type=TSTRUCT1 ;
      }
   for( i=j=0 ; i<To.Part.j ; i++ )
      if( m2[i]==0 )
      {  if( Trans1.j<=j )
	     Trans1.add( T );
	 TT=Trans1.list+j ;
	 TT->To=To.Part[i] ;
	 //TT->To.type=TSTRUCT1 ;
	 j++ ;
      }

   for( i=0 ; i<Trans.j ; i++ )
   {  i1=find_part( &From.Part, Trans[i].From.Name );
      i2=find_part( &To.Part  , Trans[i].To.Name );
      if( 0<=i1 && 0<=i2 )
      {  // ----- внести в массив Trans1 задействованные слова ------
	 Trans1.add( T );
	 TT=Trans1.list+Trans1.j-1 ;
	 TT->From=From.Part[i1] ;
	 TT->To  =To.Part[i2] ;
      }
      if( i1<0 && i2<0 )
	 // ------- внести в массив Trans1 все остальное ---
	 Trans1.add( Trans[i] );
   }
   Trans.del();
   Trans=Trans1 ;
   Trans1.del();
   Free(m1); Free(m2);
}
/***************************************************************************/
//                чтение одной записи типа @Перевод
//   Begin  - слово, с которого начинсется
/***************************************************************************/

long t_Grammar :: read_trans1( long Begin )
{  t_Trans TT,*T ;
   long  i,end ;
   char *pStr ;
   char  f ;

   Trans.add(TT) ;
   T=Trans.list+Trans.j-1 ;

   end=Lexer.find_paar( Begin+1,"{","}" );
   for( i=Begin+1,f=0 ; i<end ; i++ )
   {  pStr=Lexer.Word[i] ;
      if( 0==strcmp(pStr,"@Выбор") || 
          0==strcmp(pStr,"@Выбор1") ||
          0==strcmp(pStr,"@Выбор2") ||
          0==strcmp(pStr,"@Структура") ||
	  0==strcmp(pStr,"@Структура1") ||
	  0==strcmp(pStr,"@Структура2") ||
	  0==strcmp(pStr,"@Множество") ||
	  0==strcmp(pStr,"@Беспорядок") ||
	  0==strcmp(pStr,"@Беспорядок1") ||
	  0==strcmp(pStr,"@Беспорядок2") )
      {  if( f==0 ) {  i=T->From.read( i,&From ); f++ ;  }
	 if( f==1 ) {  i=T->To.read  ( i,&To );   f++ ;  }
      }
      Ifstr( Lexer.Word[i],"@Таблица" )
	 i=read_table( i+1,T );
   }
   T->make_order( );
   if( T->From.type!=T->To.type )
   {   fprintf( File_Error,"\n Выбор и структура в одном переводе %ld",
       	       Lexer.Str[Begin] );   
       Read_Error=-1 ;
   }

   return end ;
}
/***************************************************************************/
//                чтение одной записи типа @Таблица
//   Begin  - слово, с которого начинсется
//   TT     - заполняемая пара
/***************************************************************************/

long t_Grammar :: read_table( long Begin, t_Trans *TT )
{  long     i,j,i_param,End ;
   short    z ;
   t_2Index I ;
   char     f,f1,*pStr ;
   t_Table *T,T1 ;

   TT->Table.add( T1 );
   T=TT->Table.list+TT->Table.j-1 ;
   End=Lexer.find_paar( Begin,"(",")" );
   // ------------------- трансляция заголовка таблицы ----------------
   for( f=f1=0,i=Begin+1 ; i<End ; i++ )
   {   pStr=Lexer.Word[i] ;
       Ifstr( pStr,"," ) {  f1=0 ; continue ;  }
       Ifstr( pStr,"=" ) {  f=1 ; f1=0 ; continue ;  }
       if( f1==0 )
       {  f1++ ;
	  if( 0==strcmp("@Выбор",pStr) ) {  i_param=-1 ; goto M_Found ;  }
	  if( f==0 ) i_param=find_param( &From.Param,pStr );
	      else   i_param=find_param( &To.Param  ,pStr );
       }
       else
       {
M_Found:  f1++ ;
	  if( f==0 ) // --- найти параметр с таким именем в структуре источника--
	  {   I=TT->From.find_param2(pStr) ;
	      I.i_param=i_param ;
	      strcpy( I.Name,pStr );
	      T->In.add( I );
	      if( I.i1<0 ) Lexer.error( i );
	  }
	  else       // --- найти параметр с таким именем в структуре приемника--
	  {   I=TT->To.find_param2(pStr) ;
	      I.i_param=i_param ;
	      strcpy( I.Name,pStr );
	      T->Out.add( I );
	      if( I.i1<0 ) Lexer.error( i );
	  }
       }
   }
   T->Size=T->In.j+T->Out.j ;
   if( T->In.j==0 || T->Out.j==0 )
   {  fprintf( File_Error,"\n Заголовок таблицы - плохой строка %ld",
	       Lexer.Str[i] );
      Read_Error=-1 ;
      return End ;
   }
   // ------------------- трансляция тела таблицы ----------------
   t_Param *P ;

   Begin=End+1 ;
   End=Lexer.find_paar( Begin,"{","}" );
   j=0 ;
   for( i=Begin+1 ; i<End ; i++ )
   {  pStr=Lexer.Word[i] ;
      Ifstr( pStr,";" ) {  j=0 ; continue ;  }
      Ifstr( pStr,"=" ) {  continue ;  }
      if( j<T->In.j ) // ---- значения до знака равно ---------
      {  i_param=T->In[j].i_param ;
	 if( i_param<0 ) goto M_Select ;
	 P=&From.Param[i_param] ;
      }
      else            // ---- значения после знака равно ---------
      {  i_param=T->Out[j-T->In.j].i_param ;
	 if( i_param<0 ) goto M_Select ;
	 P=&To.Param[i_param] ;
      }

      z=find_value( &P->Value,pStr );
      T->Value.add( z );
      j++ ;
      continue ;
      // ----------- обработка параметра @Выбор --------
      M_Select :
      z=atoi(pStr);
      T->Value.add( z );
      j++ ;
   }
   return End ;
}
/***************************************************************************/
//        приведение в порядок ссылок на структуры по их именам
/***************************************************************************/

void t_Grammar :: make_index_struct( void )
{  t_Trans *T ;
   t_Word  *W ;
   long     i,i1,z ;
   char     F_Error=0 ;

   // ------ цикл по трансляционным парам -------------------
   for( i=0 ; i<Trans.j ; i++ )
   {  T=Trans.list+i ;
      make_index_param0( i );
      // ------ обработка структуры источника ---------------
      for( i1=0 ; i1<T->From.Word.j ; i1++ )
      {  W=T->From.Word.list+i1 ;

         if( tst_const( W,T->From.i_str ) ) continue ;
	 z=find_struct( FROM, W->Name );
	 if( z<0 )
	 {  fprintf( File_Error,"\n Не могу найти структуру \n Строка %ld %s",
		  T->From.i_str,W->Name );
	    F_Error=1 ; continue ;
	 }
	 W->i_struct=z ;
	 W->type    =Trans[z].From.type ;
	 make_index_param( FROM,i,i1 );
      }
      // ------ обработка структуры приемника ---------------
      for( i1=0 ; i1<T->To.Word.j ; i1++ )
      {  W=T->To.Word.list+i1 ;
      
         if( tst_const( W,T->From.i_str ) ) continue ;
	 z=find_struct( TO, W->Name );
	 if( z<0 )
	 {  fprintf( File_Error,"\n Не могу найти структуру \n Строка %ld %s",
		     T->To.i_str,W->Name );
	    F_Error=1 ; continue ;
	 }
	 W->i_struct=z ;
	 W->type    =Trans[z].To.type ;
	 make_index_param( TO,i,i1 );
      }
   }

   if( F_Error==1 )
       throw(-1) ;
}
/***************************************************************************/
//   приведение в порядок ссылок на параметры слов по именам параметров
//   i_trans - индекс трансляционной пары
/***************************************************************************/

void t_Grammar :: make_index_param0( long i_trans )
{  short i,i1 ;
   t_Param1List *P ;

   P=&Trans[i_trans].From.Param ;
   for( i=0 ; i<P->j ; i++ )
   {  i1=P->list[i].param ;
      P->list[i].value=find_value( &From.Param[i1].Value,P->list[i].Name );
   }
   P=&Trans[i_trans].To.Param ;
   for( i=0 ; i<P->j ; i++ )
   {  i1=P->list[i].param ;
      P->list[i].value=find_value( &To.Param[i1].Value,P->list[i].Name );
   }

}
/***************************************************************************/
//   приведение в порядок ссылок на параметры слов по именам параметров
//   Half - источник или приемник
//   i_trans - индекс трансляционной пары (он же индекс структуры)
//   i_word  - индекс подструктуры
/***************************************************************************/

void t_Grammar :: make_index_param( e_Half Half, long i_trans, long i_word )
{
   long      i,i1,i2,z,i_struct ;
   char      f ;
   t_Param1List  *p;
   t_Struct      *S;
   t_Word        *W ;
   t_Lang        *Lang ;
   t_Form        *F ;
   t_Format      *FF ;

   if( Half==FROM ) S=&Trans[i_trans].From ;
       else         S=&Trans[i_trans].To ;
   // --------- проверка на соответствие числа параметров -----------
   if( Half==FROM )
   {  W = &Trans[i_trans].From.Word[i_word] ;
      i_struct=W->i_struct ;
      p = &Trans[i_struct].From.Param ;
   }
   else
   {  W = &Trans[i_trans].To.Word[i_word] ;
      i_struct=W->i_struct ;
      p = &Trans[i_struct].To.Param ;
   }
   if( W->Param.j!=p->j )
   {  // --------------- Если не соответствует - печать об ошибке
      fprintf( File_Error,"\n Не соответствие числа параметров \n Строка %ld %s->%s",
		    S->i_str,S->Name, W->Name );
      Read_Error=-1 ;
   }
   else
   {  // -------- а если все в порядке - проставить номера параметров
      for( i=0 ; i<W->Param.j ; i++ )
      {  W->Param[i].param=i1=p->list[i].param ;
         if( W->Param[i].Name[0]=='%' )
	 {   if( Half==FROM ) z=find_value( &From.Param[i1].Value,W->Param[i].Name+1 );
	         else         z=find_value( &  To.Param[i1].Value,W->Param[i].Name+1 );
	     if( z<0 )
	     {
		 fprintf( File_Error,"\n Неизвесное значение параметра %s \n Строка %ld %s->%s",
			       W->Param[i].Name,S->i_str,S->Name, W->Name );
		 Read_Error=-1 ;
	     }
	     W->Param[i].value=z ;
         }
	 else
	     W->Param[i].value=-1 ;
      }
      // ----------- проверка на допустимые комбинации параметров ----
      if( W->Param.j==0 || W->type!=TWORD ) return ;
      if( Half==FROM ) Lang=&From ; else Lang=&To ;
      // ----------- проверка, что такую проверку надо проводить ----
      for( i=0,f=0 ; i<Lang->Part[W->i_struct].Param.j ; i++ )
         if( Lang->Part[W->i_struct].Param[i].Dir==0 )
	     f=1 ;
      if( f==0 ) return ;

      for( i=0 ; i<Lang->File.j ; i++ )
      {  if( Lang->File[i].i_part!=W->i_struct ) continue ;
	 FF=&Lang->Format[ Lang->File[i].i_format ] ;
	 for( i1=0 ; i1<FF->Record.j ; i1++ )
	 {
	    F= &FF->Record[i1] ;
	    for( i2=0 ; i2<W->Param.j ; i2++ )
	    {  if( 0<=W->Param[i2].value && 0<=F->value[i2] &&
		      W->Param[i2].value!=F->value[i2] ) goto M_No;
	    }
	    return ; // нужная комбинация найдена
	    M_No:;
	 }
      }
      fprintf( File_Error,"\n невозможная комбинация параметров \n Строка %ld %s->%s",
		    S->i_str,S->Name, W->Name );
      Read_Error=-1 ;
   }
}
/***************************************************************************/
//                установка индексов слов, структур, и т.д.
/***************************************************************************/

void t_Grammar :: make_index( void )
{  short    i,i1 ;
   t_Struct *S,*S1 ;

   for( i=0 ; i<Trans.j ; i++ )
   {  // ----- проверка на присутствие конструкций с одинаковыми именами ----
      for( i1=0 ; i1<i ; i1++ )
      {  S =&Trans[i].From ; S1=&Trans[i1].From ;
         if( S->type==TNULL || S->type==TNULL ) continue ;
         if( 0==strcmp( S->Name,S1->Name ) )
         {   fprintf( File_Error,"\n Конструкция %s описана два раза\n Строки %ld и %ld",
		    S->Name, S->i_str,S1->i_str );
             Read_Error=-1 ;
         }
         S =&Trans[i].To ; S1=&Trans[i1].To ;
         if( 0==strcmp( S->Name,S1->Name ) )
         {   fprintf( File_Error,"\n Конструкция %s описана два раза\n Строки %ld и %ld",
		    S->Name, S->i_str,S1->i_str );
             Read_Error=-1 ;
         }
      }
      // ------ собственно расстановка индексов -------------------
      S=&Trans[i].From ;
      for( i1=0 ; i1<S->Word.j ; i1++ )
	 index_word( &S->Word[i1], FROM );
      S=&Trans[i].To ;
      for( i1=0 ; i1<S->Word.j ; i1++ )
	 index_word( &S->Word[i1], TO );
      Trans[i].make_index_table( );
      Trans[i].From.trans_relation( );
      Trans[i].To.trans_relation( );
      Trans[i].make_order();
      Trans[i].From.tst_relation( );
      Trans[i].To.tst_relation( );
   }
}
/***************************************************************************/
//                 проставить индексы структур словам
/***************************************************************************/

void t_Grammar :: index_word( t_Word *W, e_Half Half )
{
   if( W->type!=TWORD && W->type!=TCONST && W->type!=TCONST1 && W->type!=TWORD0 )
   {   W->i_struct = find_struct( Half, W->Name );
       W->type     = Trans[W->i_struct].From.type ;
   }
}
/**************************************************************************/
//                 узнать номер структуры по ее имени
/**************************************************************************/

short t_Grammar :: find_struct( e_Half Half, char *Name )
{
   if( Half==FROM )
   {   for( short i=0 ; i<Trans.j ; i++ )
          if(  0==strcmp( Trans.list[i].From.Name,Name) ) return i ;
   }
   else
   {   for( short i=0 ; i<Trans.j ; i++ )
          if(  0==strcmp( Trans.list[i].To.Name,Name) ) return i ;
   }
   return -1 ;
}
/**************************************************************************/
//                 узнать номер формата перевода по его имени
/**************************************************************************/

short t_Grammar :: find_format1( char *Name )
{
   for( short i=0 ; i<Format1.j ; i++ )
      if( 0==strcmp( Format1[i].Name,Name ) ) return i ;
   return -1 ;
}
/**************************************************************************/
t_Trans& t_Grammar :: operator []( long i )
{  if( i<0 || Trans.j<=i )
   {  printf("\n Error index grammar");
      error_set("Error index grammar!!!");
      throw(-1);  
   }
   return Trans.list[i];  
}
/**************************************************************************/

short  t_Grammar :: n_trans( void )
{  return Trans.j ;  }
/**************************************************************************/

short  t_Grammar :: main_struct( void )
{  return Trans.j-1 ;  }
/**************************************************************************/

short  t_Grammar :: i_number( void )
{  return i_Number ;  }
/**************************************************************************/
t_Lang& t_Grammar :: from( void )
{  return From ;  }
/**************************************************************************/
t_Lang& t_Grammar :: to( void )
{  return To ;  }
/**************************************************************************/
t_Format1List& t_Grammar :: format1( void )
{  return Format1 ;  }
/**************************************************************************/
t_FileList& t_Grammar :: file1( void )
{  return File1 ;  }
/***************************************************************************/
//            создание таблицы передачи параметров для t_Trans
/***************************************************************************/

void t_Trans :: make_index_table( void )
{  short    i,i1 ;
   t_Table *T ;
   t_2Index I ;

   for( i=0 ; i<Table.j ; i++ )
   {  T=&Table[i] ;
      for( i1=0 ; i1<T->In.j ; i1++ )
      {  I=From.find_param2(T->In[i1].Name) ;
	 T->In[i1].i1=I.i1 ;
	 T->In[i1].i2=I.i2 ;
      }
      for( i1=0 ; i1<T->Out.j ; i1++ )
      {  I=To.find_param2(T->Out[i1].Name) ;
	 T->Out[i1].i1=I.i1 ;
	 T->Out[i1].i2=I.i2 ;
      }
   }
}
/***************************************************************************/
//     задание соответствия между составляющими источника и приемника
/***************************************************************************/

void t_Trans :: make_order( void )
{
   short     is1,is2,n_relation ;
   long      i,i1 ;

   for( i=0 ; i<To.Word.j ; i++ )
      To.Word[i].use=0 ;

   is1=-1 ;
   Relation1.j=Relation2.j=0 ;
   for( i=0 ; i<From.Word.j ; i++ )
	Relation1.add( is1 );
   for( i=0 ; i<To.Word.j ; i++ )
	Relation2.add( is1 );

   // --------------- формирование Relation1 -----------------------
   for( i=0 ; i<From.Word.j ; i++ )
   {
      if( From.Word[i].order<0 )
      {   // -------------- неявное задание порядка --------------
	  is1=From.Word[i].i_struct ;
	  n_relation=0 ;
	  for( i1=0 ; i1<To.Word.j ; i1++ )
	  {  if( 0<=To.Word[i1].order || To.Word[i1].use!=0 ) continue ;
	     is2=To.Word[i1].i_struct ;
	     if( is1==is2 )
	     {   Relation1[i] =i1 ;
		 Relation2[i1]=i ;
		 To.Word[i1].use=1 ;
		 n_relation++ ;
		 break ;
	     }
	  }
	  if( To.Word.j<n_relation )
	  {  fprintf( File_Error,"\n ошибка соответствия структур %s %s",
		     From.Name,To.Name );
	     Read_Error=-1 ;
	     throw(-1);
	  }
      }
      else
      {   // -------------- явное задание порядка --------------
	  for( i1=0 ; i1<To.Word.j ; i1++ )
	  {  if( To.Word[i1].order<0 ) continue ;	     
	     if( From.Word[i].order==To.Word[i1].order )
	     {   if( From.Word[i].i_struct!=To.Word[i1].i_struct )
		 {  fprintf( File_Error,"\n %s ошибка соответствия структур2",From.Name );
		    Read_Error=-1 ;
		    throw(-1);
		 }
		 Relation1[i]=i1;
		 Relation2[i1]=i;
	     }
	  }
      }
   }
   // ----- если это выбор, проверить его варианты на соответствие -----
   if( From.type==TSELECT || From.type==TSELECT2 )
   {
      if( From.Word.j!=To.Word.j )
      {  fprintf( File_Error,"\n %s : несоответствие числа вариантов выбора",From.Name );
	 Read_Error=-1 ;
      }      
      for( i=0 ; i<From.Word.j ; i++ )
         if( From.Word[i].i_struct!=To.Word[i].i_struct &&
	     0<=From.Word[i].i_struct && 0<=To.Word[i].i_struct )
	 {  fprintf( File_Error,"\n %s->%s : несоответствие вариантов выбора",
	             From.Name,From.Word[i].Name );
	    Read_Error=-1 ;
	 }
   }
}
/***************************************************************************/
//              прочесть запись типа @Структура @Выбор
//    Begin  - слово, с которого начинсется
//    Lang   - язык, к которому относится эта структура
/***************************************************************************/

long t_Struct :: read( long Begin, t_Lang *Lang )
{
   t_Word   W ;
   char     *pStr ;
   long     i,i1,end,End ;

   End=Lexer.n_Word ;

   for( i=Begin ; i<End ; i++ )
   {
      pStr=Lexer.Word[i] ;
      if( 0==strcmp(pStr,"@Часть_речи") ||
          0==strcmp(pStr,"@Структура") ||
	  0==strcmp(pStr,"@Структура1") ||
	  0==strcmp(pStr,"@Структура2") ||
	  0==strcmp(pStr,"@Выбор") ||
	  0==strcmp(pStr,"@Выбор1") ||
	  0==strcmp(pStr,"@Выбор2") ||
	  0==strcmp(pStr,"@Множество") ||
	  0==strcmp(pStr,"@Беспорядок") ||
	  0==strcmp(pStr,"@Беспорядок1") ||
	  0==strcmp(pStr,"@Беспорядок2") )
      {
         if( 40<=strlen(Lexer.word(i+1)) )
	 {  fprintf( File_Error,"\n Слишком длинное имя структуры %s",Lexer.word(i+1) );
	       throw(-1);
	 }

	 strcpy( Name,Lexer.word(i+1) );
	 
	 Ifstr( pStr,"@Часть_речи" ) type=TWORD ; 
	 Ifstr( pStr,"@Структура"  ) type=TSTRUCT ;
	 Ifstr( pStr,"@Структура1" ) type=TSTRUCT1 ;
	 Ifstr( pStr,"@Структура2" ) type=TSTRUCT2 ;
	 Ifstr( pStr,"@Выбор"      ) type=TSELECT ;
	 Ifstr( pStr,"@Выбор1"     ) type=TSELECT1 ;
	 Ifstr( pStr,"@Выбор2"     ) type=TSELECT2 ;
	 Ifstr( pStr,"@Множество"  ) type=TENUM ;
	 Ifstr( pStr,"@Беспорядок" ) type=TUNORDER ;
	 Ifstr( pStr,"@Беспорядок1") type=TUNORDER1 ;
	 Ifstr( pStr,"@Беспорядок2") type=TUNORDER2 ;

	 i_str=Lexer.Str[i+1] ;

	 // -------------- трансляция параметров ----------------- //
	 i=trans_param( i, Lang );

	 if( type != TWORD && 0!=strcmp( Lexer.Word[i],"=" ) )
	 {  fprintf( File_Error,"\n В строке %s нет знака равно",Name );
	    throw(-1);
	 }
	 // ----------- трансляция составляющих ----------------
	 end=Lexer.find_word( i,";" );
	 for( i1=i+1 ; i1<end ; i1++ )
	    i=i1=trans_word1( i1 );

	 return i+1 ;
      }
   }
   return i ; //End ;
}
/***************************************************************************/
//        трансляция составляющих структуры или варианта выбора
//    Begin  - слово, с которого начинсется
/***************************************************************************/

long t_Struct :: trans_word1( long Begin )
{  long    i ;
   t_Word  W ;
   char    use,*pStr ;

   for( i=Begin ; i<Lexer.n_word() ; i++ )
   {
      Ifstr( Lexer.Word[i],";" ) {  return i+1 ;  }

      zerstoren_word( Lexer.Word[i], &use, &pStr );
      strcpy( W.Name,pStr );
      W.meaning_use=use ;
      i=trans_order( i,&W );
      Word.add( W );
      return trans_word( i );
   }
   return Lexer.n_word();
}
/***************************************************************************/
//   Трансляция вот таких фенечек   @Структура = часть<1> часть<2>
//   Begin  - слово, с которого начинсется            ^^^      ^^^
//   Word1  - часть структуры, которой проставляется order
/***************************************************************************/
long t_Struct :: trans_order( long Begin, t_Word *Word1 )
{  long i=Begin ;

   Ifstr( Lexer.Word[i+1],"<" )
   {  Ifstr( Lexer.Word[i+3],">" )
	   Word1->order=atoi( Lexer.Word[i+2] );
      else Lexer.error(i);
      i+=3 ;
   }
   Ifstr( Lexer.Word[i+1],"[" )
   {  Ifstr( Lexer.Word[i+3],"]" )
	 strcpy( Word1->literal, Lexer.Word[i+2] );
      else
      {  fprintf( File_Error,"\n В строке %ld пустая константа",Lexer.Str[i+2] );
         Read_Error=-1 ;
      }
      i+=3 ;
   }
   return i ;
}
/***************************************************************************/
//                     трансляция параметров структуры
//    Begin  - слово, с которого начинсется
//    Lang   - язык, к которому относится эта структура
/***************************************************************************/

long t_Struct :: trans_param( long Begin, t_Lang *Lang )
{  t_Param1 Param1 ;
   long  i,z,End ;
   char *pStr ;

   Ifstr( Lexer.word(Begin+2),"(" )
   {  // -------------- если у структуры есть параметры -----------
      End=Lexer.find_paar( Begin+2,"(",")" );
      for( i=Begin+3 ; i<End ; i++ )
      {  char d ;

	 Ifstr( Lexer.Word[i],"," ) continue ;
	 z=find_param( &Lang->Param,Lexer.Word[i] );
	 if( z<0 ) continue ;
	 Param1.param=z ;
	 pStr=Lexer.Word[i+1] ;
	 zerstoren_param( Lexer.Word[i+1], &d, &pStr );
	 strcpy( Param1.Name,pStr );
	 Param1.Dir=d ;
	 Param.add( Param1 ); i++ ;
      }
      return End+1 ;
   }
   else
   {  // --------------- и если параметров нет -----------------
      return Begin+2 ;
   }
}
/***************************************************************************/
//     трансляция параметров части структуры
//     Begin  - слово, с которого начинсется
/***************************************************************************/

long t_Struct :: trans_word( long Begin )
{
   t_Param1  Param1 ;
   t_Word   *W=&Word[Word.j-1] ;
   long      i,End ;
   char      Dir,*Str ;

   Ifstr( Lexer.Word[Begin+1],"(" )
	   End=Lexer.find_paar( Begin+1,"(",")" );
      else End=Begin ;

   for( i=Begin+2 ; i<End ; i++ )
   {
      Ifstr( Lexer.Word[i],"," ) continue ;
      zerstoren_param( Lexer.Word[i],&Dir,&Str );

      Param1.param=-1 ;
      Param1.Dir=Dir ;
      strcpy( Param1.Name,Str );
      Param1.value=-1 ;

      W->Param.add( Param1 );
   }
   return End ;
}
/**************************************************************************/
//     сформировать описание передачи параметров внутри конструкции
//     одного языка (Relation)
/**************************************************************************/

void t_Struct :: trans_relation( void )
{  t_Param1   *Param1 ;
   t_Relation *Index,I ;
   short      *gruppe ;
   long        i,i1,j,N ;

   if( type==TWORD ) return ;
   N=Param.j ;
   for( i=0 ; i<Word.j ; i++ )
      N+=Word[i].Param.j ;

   Param1=(t_Param1   *)Calloc( N,sizeof(t_Param1  ) );
   Index =(t_Relation *)Calloc( N,sizeof(t_Relation) );
   gruppe=(short      *)Calloc( N,sizeof(short) );

   // ----------- инициация массивов структуры -------------
   for( i=j=0 ; i<Param.j ; i++ )
   {  if( 0<=Param[i].value ) continue ;
      Param1[j]=Param[i] ;
      Index[j].s1=Index[i].s2=0 ;
      Index[j].p1=Index[i].p2=i ;
      gruppe[j]=j ;
      j++ ;
   }
   // ----------- инициация массивов составляющих -------------
   for( i=0 ; i<Word.j ; i++ )
   {  for( i1=0 ; i1<Word[i].Param.j ; i1++ )
      {  if( 0<=Word[i].Param[i1].value ) continue ;
	 Param1[j]=Word[i].Param[i1] ;
	 Index[j].s1=Index[j].s2=i+1 ;
	 Index[j].p1=Index[j].p2=i1 ;
	 gruppe[j]=j ;
	 j++ ;
      }
   }
   N=j ;
   // ----------- заполнение массивов Relation ----------------
   for( i=0 ; i<N ; i++ )
   {
      for( i1=i ; i1<N ; i1++ )
	 if( 0==strcmp(Param1[i].Name,Param1[i1].Name) )
	 {   gruppe[i1]=i ;
	     if( Param1[i].Dir==1 && Param1[i1].Dir==0 )
	     {   I.s1=Index[i].s1 ; I.s2=Index[i1].s1 ;
		 I.p1=Index[i].p1 ; I.p2=Index[i1].p1 ;
		 Relation.add( I );
	     }
	     if( Param1[i].Dir==0 && Param1[i1].Dir==1 )
	     {   I.s1=Index[i1].s1 ; I.s2=Index[i].s1 ;
		 I.p1=Index[i1].p1 ; I.p2=Index[i].p1 ;
		 Relation.add( I );
	     }
	 }
   }
   Free( Param1 ); Free( Index ); Free( gruppe );

}
/**************************************************************************/
//     найти в структуре положение ( индекс слова и индекс параметра ) 
//     параметра источника с именем Str
/**************************************************************************/

t_2Index t_Struct :: find_param2( char *Str )
{  t_2Index      r ;
   t_Param1List *P ;
   short         i,i1 ;

   if( 0==strcmp("@Выбор",Str) ) {  r.i1=0 ; r.i2=-1 ; return r ; }
   P=&Param ;
   // ------- поиск в заголовке структуры -------------
   for( i=0 ; i<P->j ; i++ )
   {  if( P->list[i].Dir==0 && type==TSTRUCT ) continue ;
      if( 0==strcmp(P->list[i].Name,Str) )
      {  r.i1=0 ; r.i2=i ; return r ;  }
   }
   // ------- поиск в составляющих структуры ----------
   for( i1=0 ; i1<Word.j ; i1++ )
   {  P=&Word[i1].Param ;
      for( i=0 ; i<P->j ; i++ )
      {  if( P->list[i].Dir==0 ) continue ;
	 if( 0==strcmp(P->list[i].Name,Str) )
	 {  r.i1=i1+1 ; r.i2=i ; return r ;  }
      }
   }
   fprintf( File_Error,"\n %ld В структуре не могу найти параметр \"%s\"",i_str,Str );
   Read_Error=-1 ;
   r.i1=-1 ; r.i2=-1 ; return r ;
}
/**************************************************************************/
//     проверка параметров на соответствие типов при прямой передаче
/**************************************************************************/

void t_Struct :: tst_relation( void )
{  long  i ;
   t_Relation   I ;
   t_Param1List *P1,*P2 ;

   for( i=0 ; i<Relation.j ; i++ )
   {  I=Relation[i] ;
      if( I.s1==0 ) P1=&Param ; 
          else      P1=&Word[I.s1-1].Param ;
      if( I.s2==0 ) P2=&Param ;
          else      P2=&Word[I.s2-1].Param ;
      if( P1->list[I.p1].param!=P2->list[I.p2].param )
      {   fprintf( File_Error,"\n Прямая передача значений между разнородными параметрами");  
          fprintf( File_Error,"\n Строка = %ld  структура = %s  параметр = %s", 
	                      i_str, Name, P1->list[I.p1].Name ) ;
          Read_Error=-1 ;
      }
   }
}
/***************************************************************************/
// прочесть запись типа @Атомы_источника{ ... } или @Атомы_приемника{ ... }
//     Lexer - Лексер, который содержит lang.txt
//     Begin - слово, с которого начинается
/***************************************************************************/

long t_Lang :: read( t_Lexer *_Lexer, long Begin )
{
   long     i,i1,End,End1 ;
   t_Value  Value1 ;
   t_Param  Param1 ;
   t_Struct Part1 ;
   t_Format Form,*Form1 ;
   t_File   File1 ;
   short    z ;

try
{
   Lexer=_Lexer ;
   Ifstr( Lexer->Word[Begin+1],"{" )
   {  End = Lexer->find_paar( Begin,"{","}" );
      if( End<0 ){  fprintf(File_Error,"\n Ошибка непарности скобок"); throw(-1);  }
   }
   else {  fprintf(File_Error,"\n Ошибка формата"); throw(-1);  }

   for( i=Begin+1 ; i<End ; i++ )
   {
       Ifstr( Lexer->Word[i],"@Параметр" )
       {   strcpy( Param1.Name,Lexer->Word[i+1]) ;
	   Param.add( Param1 );
	   t_Param *P=&Param[Param.j-1] ;
	   End1=Lexer->find_paar( i+2,"{","}" );
	   for( i1=i+3 ; i1<End1 ; i1++ )
	   {  Ifstr( Lexer->Word[i1],"," ) continue ;
	      strcpy( Value1.Name,Lexer->Word[i1] );
	      P->Value.add( Value1 );
	   }
       }
       if( 0==strcmp( Lexer->Word[i],"@Часть_речи" ) ||
           0==strcmp( Lexer->Word[i],"@Структура" ) ||
	   0==strcmp( Lexer->Word[i],"@Структура1" ) ||
	   0==strcmp( Lexer->Word[i],"@Структура2" ) ||
	   0==strcmp( Lexer->Word[i],"@Множество" ) ||
	   0==strcmp( Lexer->Word[i],"@Беспорядок" ) ||
	   0==strcmp( Lexer->Word[i],"@Беспорядок1" ) ||
	   0==strcmp( Lexer->Word[i],"@Беспорядок2" ) )
       {
	   Part.add( Part1 );
	   Part[Part.j-1].read( i,this );
       }
       Ifstr( Lexer->Word[i],"@Формат" )
       {  Format.add( Form );
	  Form1=&Format[Format.j-1] ;
	  read_format( i, Form1 );
       }
       Ifstr( Lexer->Word[i],"@Файлы" )
       {
	   z=find_part( &Part,Lexer->Word[i+1] );
	   File1.i_part=z ;
	   z=find_format( &Format,Lexer->Word[i+2] );
	   File1.i_format=z ;
	   File1.FileName.j=0 ;

	   End1=Lexer->find_paar( i+3,"{","}" );
	   for( i1=i+4 ; i1<End1 ; i1++ )
	   {  char *a ;
	      Ifstr( Lexer->Word[i1],"," ) continue ;
	      a=(char *)Calloc( strlen(Lexer->Word[i1])+1,1 ); // Memory Leak
	      strcpy( a,Lexer->Word[i1] );
	      File1.FileName.add( a );
	   }
	   File.add( File1 );
       }
   }
   return End ;
}
catch( int E )
{
   throw( E );
}
}
/**************************************************************************/
//              прочесть запись типа @Формат { ... }
//     Begin - слово, с которого начинается
//     Format1 - то, что надо заполнить
/**************************************************************************/

void t_Lang :: read_format( long Begin, t_Format *Format1 )
{
   long   i,i1,s,z,z1,z2 ;
   long   End ;
   t_Struct *P ;
   t_Form    Form[10] ;

   for( i=0 ; i<10 ; i++ ) Form[i].init() ;

   z=find_part( &Part,Lexer->Word[Begin+1] );
   if( z<0 ) {  fprintf( File_Error,"\n Ошибка поиска части речи" ); throw(-1);  }
   Format1->i_part=z ;
   P=&Part[z] ;
   strcpy( Format1->Name, Lexer->Word[Begin+2] );

   Ifstr( Lexer->Word[Begin+3],"{" )
   {  End = Lexer->find_paar( Begin,"{","}" );
      if( End<0 ) {  fprintf( File_Error,"\n Ошибка непарности скобок"); throw(-1);  }
   }
   else {  fprintf( File_Error,"\n Ошибка формата"); throw(-1);  }

   s=0 ;
   for( i=Begin+3 ; i<End ; i++ )
   {
      Ifstr( Lexer->Word[i],"{" ) {  Form[s+1]=Form[s] ; s++ ; continue ;  }
      Ifstr( Lexer->Word[i],"}" ) {  s-- ; continue ;  }
      Ifstr( Lexer->Word[i],"@Слово" )
      {  
	 Format1->Record.add( Form[s] );
	 continue ;
      }

      for( i1=0 ; i1<P->Param.j ; i1++ )
	 if( 0==strcmp(P->Param[i1].Name,Lexer->Word[i]) )
	 {  z1=i1 ; z=P->Param[i1].param ; goto M_Ok ; }
      fprintf( File_Error,"\n Часть речи (%s) не имеет параметра(%s)",
	     P->Name,Lexer->Word[i] );
      Read_Error=-1 ;
      M_Ok:;

      Ifstr( Lexer->Word[i+1],"=" )
      {  // -------------- найти значение параметра -------------
	 z2=find_value( &Param[z].Value,Lexer->Word[i+2] );
	 if( z2<0 )
	 {  fprintf( File_Error,"\n Параметр(%s) не имеет значения(%s)",
		    Param[z].Name,Lexer->Word[i+2] );
	    throw(-1);
	 }
	 Form[s].value[z1]=z2 ;
	 i+=2 ;
      }
   }
}
/***************************************************************************/
//        сделать индексы сруктур в списке переименований структур
/***************************************************************************/

void t_Format1 :: make_part( t_Grammar *Grammar )
{  short i,z ;

   for( i=0 ; i<SouPart.j ; i++ )
   {  z=Grammar->find_struct( FROM, SouPart[i].Name );
      if( z<0 ) 
      {  fprintf( File_Error,"\n @Словари_перевода :: не могу найти часть речи %s",
                         SouPart[i].Name );
         Read_Error=-1 ;
      }
      SouPart[i].i_part = z ;
   }
   for( i=0 ; i<DstPart.j ; i++ )
   {  z=Grammar->find_struct( TO, DstPart[i].Name );
      if( z<0 )
      {  fprintf( File_Error,"\n @Словари_перевода :: не могу найти часть речи %s",
                         DstPart[i].Name );   
         Read_Error=-1 ;
      }
      DstPart[i].i_part = z ;
   }
}
/***************************************************************************/
//             найти индекс структуры по ее псевдониму
//    fTo - 0-источник или 1-приемник
//    Tag - псевдоним
/***************************************************************************/

short t_Format1 :: find_struct( char fTo, char *Tag  )
{  short i ;

   if( Tag[0]=='@' && Tag[1]=='0' )
       return -1 ; // если это константа

   if( fTo==0 )
   {   for( i=0 ; i<SouPart.j ; i++ )
          if( 0==strncmp(Tag,SouPart.list[i].Tag,2) )
	      return SouPart.list[i].i_part ;
   }
   else
   {   for( i=0 ; i<DstPart.j ; i++ )
          if( 0==strncmp(Tag,DstPart.list[i].Tag,2) )
	      return DstPart.list[i].i_part ;
   }
   return -10 ; // структура не найдена
}
/**************************************************************************/
//            дать псевдоним структуры по ее индексу
//    fTo      - 0-источник или 1-приемник
//    i_struct - индекс структуры
/**************************************************************************/
char 
* t_Format1 ::get_tag( char fTo, short i_struct )
{  static char Str[3] ;
   short i ;

   strcpy( Str,"@1" );
   if( fTo==0 )
   {   for( i=0 ; i<SouPart.j ; i++ )
          if( SouPart.list[i].i_part==i_struct )
	  {  strncpy( Str,SouPart.list[i].Tag,2 ); break ; }
   }
   else
   {   for( i=0 ; i<DstPart.j ; i++ )
          if( DstPart.list[i].i_part==i_struct )
	  {  strncpy( Str,DstPart.list[i].Tag,2 ); break ; }
   }
   return Str ;
}
/**************************************************************************/
//            дать имя структуры по ее индексу
//    fTo      - 0-источник или 1-приемник
//    i_struct - индекс структуры
/**************************************************************************/
char 
* t_Format1 ::get_name( char fTo, short i_struct )
{  short i ;

   if( fTo==0 )
   {   for( i=0 ; i<SouPart.j ; i++ )
          if( SouPart.list[i].i_part==i_struct )
	     return SouPart.list[i].Name ;
   }
   else
   {   for( i=0 ; i<DstPart.j ; i++ )
          if( DstPart.list[i].i_part==i_struct )
	     return DstPart.list[i].Name ;
   }
   return "@0" ;
}
/**************************************************************************/

void t_Lang :: del( void )
{
   Param.del( );
   Part.del( );
   Format.del( );
   File.del( );
}
/***************************************************************************/
//    проверка на то, что часть структуры является "жесткой константой"
//    W     - проверяемая часть структуры (Слово)
//    i_str - индекс строки файла lang.txt, в которой это "Слово" записано
/***************************************************************************/
char tst_const( t_Word *W, long i_str )
{
   Ifstr( "@0",W->Name )
   {   W->i_struct=-1 ;
       W->type    =TCONST ;

       if( W->literal[0]==0 )
       {   fprintf( File_Error,"\n У константы нет значения \n Строка %ld %s",
		     i_str,W->Name );
	   throw(-1);
       }
       if( 0<W->Param.j ) goto M_ErrParam ;
       return 1 ;
   }
   Ifstr( "@1",W->Name )
   {   W->i_struct=-1 ;
       W->type    =TCONST1 ;
       if( 0<W->Param.j ) goto M_ErrParam ;
       return 1 ;
   }
   Ifstr( "@00",W->Name )
   {   W->i_struct=-2 ;
       W->type    =TWORD0 ;
       if( 0<W->Param.j ) goto M_ErrParam ;
       return 1 ;
   }
   return 0 ;

M_ErrParam:
   fprintf( File_Error,"\n У константы какие-то параметры \n Строка %ld %s",
	     i_str,W->Name );
   throw(-1);
}
/**************************************************************************/
short find_param( t_ParamList  *List, char *Str )
{
   for( short i=0 ; i<List->j ; i++ )
      if( 0==strcmp(List->list[i].Name,Str) ) return i ;
   return -1 ;
}
/**************************************************************************/
short find_part(  t_StructList   *List, char *Str )
{
   for( short i=0 ; i<List->j ; i++ )
      if( 0==strcmp(List->list[i].Name,Str) ) return i ;
   return -1 ;
}
/**************************************************************************/
short find_format(t_FormatList *List, char *Str )
{
   for( short i=0 ; i<List->j ; i++ )
      if( 0==strcmp(List->list[i].Name,Str) ) return i ;
   return -1 ;
}
/**************************************************************************/
short find_value( t_ValueList  *List, char *Str )
{
   if( 0==strcmp( "@0",Str ) ) return -1 ;
   for( short i=0 ; i<List->j ; i++ )
      if( 0==strcmp(List->list[i].Name,Str) ) return i ;
   return -1 ;

}
/***************************************************************************/
t_Form :: t_Form( void )
{
   for( short i=9 ; 0<=i ; i-- ) value[i]=-1 ;
}
/***************************************************************************/

void t_Form :: init(void)
{
   for( short i=9 ; 0<=i ; i-- ) value[i]=-1 ;
}
/***************************************************************************/

void t_Format1 :: init( void )
{
   Name[0]=0 ;
   SouPart.init();
   DstPart.init();
}
/***************************************************************************/

void t_Format1 :: del( void )
{
   SouPart.del();
   DstPart.del();

}
/***************************************************************************/
t_Param ::  t_Param( void ){  init(); 
}
t_Param :: ~t_Param( void ){  del();  }

void t_Param :: init( void )
{  Name[0]=0 ;
   Value.init();
}

void t_Param :: del( void )
{  Value.del();  
}
/***************************************************************************/
t_Format ::  t_Format( void ){  init(); 
}
t_Format :: ~t_Format( void ){  del();  }

void t_Format :: init( void )
{
   Name[0]=0 ;
   i_part =0 ;
   Record.init() ;
}

void t_Format :: del( void )
{
   Record.del() ;

}
/***************************************************************************/
t_File ::  t_File( void ){  init(); 
}
t_File :: ~t_File( void ){  del();  }

void t_File :: init( void )
{  i_part  =0 ;
   i_format=0 ;
   FileName.init();
}

void t_File :: del( void )
{  // по идее надо освобождать и строки по этим адресам
   FileName.del();
}
/**************************************************************************/

void t_Table :: init( void )
{  Size=0 ;
   In.init();
   Out.init();
   Value.init();
}
/**************************************************************************/

void t_Table :: del( void )
{  In.del();
   Out.del();
   Value.del();
}
/**************************************************************************/

void t_Table :: operator = ( t_Table &T )
{  Size =T.Size ;
   In   =T.In ;
   Out  =T.Out ;
   Value=T.Value ;

}
/**************************************************************************/
t_Word :: t_Word( void )
{
   init( );
}
/**************************************************************************/

void t_Word :: init( void )
{
   literal[0] = 0 ;
   type       = TWORD ;
   Param.init();
   order      =-1 ;
   i_struct   =-1 ;
   meaning_use= 0 ;
}
/**************************************************************************/

void t_Word :: del( void )
{
   Param.del();
}
/**************************************************************************/

void t_Word :: operator = ( t_Word &W )
{
   strcpy( literal,W.literal ) ;
   strcpy( Name ,W.Name ) ;
   type        = W.type ;
   Param       = W.Param ;
   order       = W.order ;
   i_struct    = W.i_struct ;
   use         = W.use ;
   meaning_use = W.meaning_use ;

}
/**************************************************************************/
t_Struct :: t_Struct( void )
{
   init( );
}
/**************************************************************************/

void t_Struct :: init( void )
{
   type    =TNULL ;
   Name[0] =0 ;
   i_str   =-1 ;
   Word.init();
   Param.init();
   Relation.init();
}
/**************************************************************************/

void t_Struct :: del( void )
{
   Word.del();
   Param.del();
   Relation.del();
}
/**************************************************************************/

void t_Struct :: operator = ( t_Struct &S )
{
   strcpy( Name,S.Name );
   type    = S.type;
   i_str   = S.i_str;
   Param   = S.Param;
   Word    = S.Word;
   Relation= S.Relation;

}
/**************************************************************************/
t_Trans :: t_Trans( void )
{  init( );  }
/**************************************************************************/

void t_Trans :: init( void )
{
   From.init();
   To.init();
   Relation1.init();
   Relation2.init();
   Param1.init();
   Param2.init();
   Table.init();
}
/**************************************************************************/

void t_Trans :: del( void )
{
   From.del();
   To.del();
   Relation1.del();
   Relation2.del();
   Param1.del();
   Param2.del();
   Table.del();
}
/**************************************************************************/

void t_Trans :: operator = ( t_Trans &SS )
{  short     i ;
   t_Struct *F,*T ;

   F =&SS.From ;
   T =&SS.To ;

   From.Param=F->Param ;
   To.Param  =T->Param ;
   // ------------ копирование слов источника -----------
   for( i=0 ; i<F->Word.j ; i++ )
      From.Word.add( F->Word[i] );

   // ------------ копирование слов приемника -----------
   for( i=0 ; i<T->Word.j ; i++ )
      To.Word.add( T->Word[i] );

   // ------------ копирование параметров и таблиц ------
   Relation1 = SS.Relation1 ;
   Relation2 = SS.Relation2 ;
   Param1    = SS.Param1 ;
   Param2    = SS.Param2 ;
   Table     = SS.Table ;
   From.type = F->type ;
   From.i_str= F->i_str ;
   To.type   = T->type ;
   To.i_str  = T->i_str ;
   strcpy( From.Name,F->Name );
   strcpy( To.Name,  T->Name );
}

/**************************************************************************/
short find_param1( t_Param1List *List, char *Str )
{
   for( short i=0 ; i<List->j ; i++ )
      if( 0==strcmp(List->list[i].Name,Str) ) return i ;
   return -1 ;
}
/**************************************************************************/
short find_value2( t_strList  *List, char *Str )
{
   if( 0==strcmp( "@0",Str ) ) return -1 ;
   for( short i=0 ; i<List->j ; i++ )
      if( 0==strcmp(List->list[i],Str) ) return i ;
   return -1 ;
}
/**************************************************************************/
void zerstoren_param( char *Str, char *Dir, char **Str1 )
{
   if( Str[0]=='&' ) { *Dir=1 ; *Str1=Str+1 ; }
       else          { *Dir=0 ; *Str1=Str ; }
}
/**************************************************************************/
void zerstoren_word( char *Str, char *use, char **Str1 )
{
   if( Str[0]=='!' ) { *use=1 ; *Str1=Str+1 ; }
       else          { *use=0 ; *Str1=Str ; }
}
/**************************************************************************/
DEFINE_LIST_TYPE ( t_Trans,   t_TransList )
DEFINE_LIST_TYPE ( t_Table,   t_TableList )
DEFINE_LIST_BTYPE( t_Param1,  t_Param1List )
DEFINE_LIST_BTYPE( t_2Index,  t_2IndexList )
DEFINE_LIST_TYPE ( t_Word,    t_WordList )
DEFINE_LIST_TYPE ( t_Struct,  t_StructList )
DEFINE_LIST_BTYPE( t_Relation,t_RelationList )
DEFINE_LIST_BTYPE( t_PartDsk, t_PartDskList )
DEFINE_LIST_TYPE ( t_Format1, t_Format1List )
DEFINE_LIST_BTYPE( short,     t_shortList )
DEFINE_LIST_BTYPE( long,      t_longList )
DEFINE_LIST_BTYPE( t_Value,   t_ValueList )
DEFINE_LIST_TYPE ( t_Param,   t_ParamList )
DEFINE_LIST_TYPE ( t_Format,  t_FormatList )
DEFINE_LIST_BTYPE( char *,    t_strList )
DEFINE_LIST_TYPE ( t_File,    t_FileList )
DEFINE_LIST_BTYPE( t_Rename,  t_RenameList )
DEFINE_LIST_BTYPE( t_Form,    t_FormList )