/*******************************************************************/ // "Меркурий"-"Правда" - open source переводчик // распространяется в соответсвии с лицензией GNU v 2.0 // // Последовательный выбор вариантов перевода // Анисимов Д.В. сегодня /*******************************************************************/ # include <string.h> # include <mylib.h> # include <video.h> # include <s_defkey.h> # include <color.h> # include <core.h> # include <slowo2.h> # include <window.h> # include <edit2.h> # include <path.h> extern t_Slowo2 *SlowoT ; extern short *i_FormatT ; void word_source( short i_struct, char *Word, char *Source, e_Half H ); void Window_help( void *Void ); void figna( char *str ); # define no_trans(r) (E_NULL==(r) || E_NO==(r) || E_FIGNA==(r) || E_ERROR==(r) ) /************************************************************************/ // заменить в строке '\n' и '\t' на ' ' (для форматирования) /************************************************************************/ void remove_wk( char *Str ) { for( long i=0 ; Str[i]!=0 ; i++ ) if( Str[i]=='\n' || Str[i]=='\t' ) Str[i]=' ' ; } /************************************************************************/ long t_pVariant :: word_to_aword( long i_word ) { long i ; for( i=0 ; i<aWord.j ; i++ ) if( i_word<=aWord[i].i_word ) break ; return i ; } /************************************************************************/ t_Path :: t_Path( void ) : t_Win() { strcpy( Name,"Ручной перевод" ); Up =NULL ; Variant=NULL ; Tree =NULL ; aWord =NULL ; n_Tree =0 ; n_Variant=0 ; Antwort[0]=StrUp[0]=0 ; z_Tree=i_down=0 ; } /************************************************************************/ t_Path :: t_Path( t_Path *Up1, long z_Tree1 ) { strcpy( Name,Up1->Name ); x1=Up1->x1 ; x2=Up1->x2 ; size_x=Up1->size_x ; y1=Up1->y1 ; y2=Up1->y2 ; size_y=Up1->size_y ; Up=Up1 ; Variant=NULL ; Tree =NULL ; aWord =NULL ; n_Tree =0 ; n_Variant=0 ; Antwort[0]=StrUp[0]=0 ; Up1->print1( StrUp,z_Tree1 ); z_Tree=i_down=0 ; } /************************************************************************/ t_Path :: ~t_Path() { del(); } /************************************************************************/ void t_Path :: del() { for( long i=0 ; i<n_Tree ; i++ ) if( Tree[i].Down!=NULL ) { delete(Tree[i].Down); Tree[i].Down=NULL ; } Free(aWord); Free(Variant); Free(Tree); n_Tree =0 ; n_Variant=0 ; } /***************************************************************************/ // рисовалка /***************************************************************************/ void t_Path :: paint( ) { long i,j,j1,n,z,z1,Begin,n_Down ; short yy ; char f,f1 ; e_Result r ; t_pTree *T ; char Str[LFRASA] ; try { // ------ нарисовать рамки -------------------------- t_Win :: paint(); s_rame2_F( y1, x1, y2, x2, 0x07 ); s_rame2_F( y1, x1, y1+4, x2, 0x07 ); s_rame2_F( y1, x1, y1+2, x2, 0x07 ); s_text_yxf( y1 , x1+3, 0x0a, "Оригинал" ); s_text_yxf( y1+2, x1+3, 0x0a, "Перевод" ); s_text_yxf( y1+4, x1+3, 0x0a, "Варианты продолжения" ); s_goto_xy( y1+1,x1+1 ); T=&Tree[z_Tree] ; // ------ нарисовать оригинал ----------------------- { short z1,z2,halb=size_x/2 ; z1=sou_length1( ); z2=z1+x1+2 ; r=Core.result(); if( r==E_NULL || r==E_ERROR ) Strcpy( Str,"",LFRASA ) ; else Strcpy( Str,Core.sou(),LFRASA ) ; if( size_x-5<z1+halb ) { strcpy( Str,Str+z1-(size_x-5-halb) ); z2=x1+2+size_x-5-halb ; } Str[size_x-5]=0 ; remove_wk( Str ); s_text_yxf( y1+1, x1+2, 0x07, Str ); uchar t[2]={ 0x3d ,0 }; s_color_yxt( y1+1, z2+6, t,"0" ); } // ------ нарисовать перевод ----------------------- if( no_trans(r) ) Strcpy( Str,Core.antwort().str(),LFRASA ); else print1( Str,z_Tree ); n=strlen( Str ); if( size_x-4<n ) Begin=n-size_x+4 ; else Begin=0 ; remove_wk( Str ); s_text_yxf( y1+3, x1+2, 0x07, Str+Begin ); if( no_trans(r) ) return ; // ------ нарисовать варианты перевода -------------- n_Down=0 ; for( i=0 ; i<T->n_down ; i++ ) if( 0<Tree[T->down+i].n_slowo ) n_Down+=Tree[T->down+i].n_slowo ; z=size_y-6 ; Begin=0 ; if( i_down<Begin ) Begin=i_down ; if( Begin+z<i_down ) Begin=i_down-z ; long L ; for( i=j=j1=n=0 ; i<n_Down ; i++ ) { j++ ; if( Tree[T->down+j1].n_slowo<j ) { j1++ ; j=1 ; } if( Begin+z<i ) break ; if( i<Begin ) continue ; if( i==i_down ) { f=0x60 ; f1=0x70 ; } else { f=0x0e ; f1=0x07 ; } Strcpy( Str,emptystr(size_x-3),LFRASA ); yy=y1+5+i-Begin ; s_text_yxf( yy, x1+2, f1, Str ); print2( Str, z_Tree, j1, j-1 ); Str[size_x-3]=0 ; remove_wk( Str ); s_text_yxf( yy, x1+2, f, Str ); z1=strlen( Str ); L=print3( Str, z_Tree, j1, j-1 ); Str[size_x-4-z1]=0 ; remove_wk( Str ); s_text_yxf( yy, x1+3+z1, f1, Str ); if( L<size_x-4-z1 ) Str[L]=0 ; s_text_yxf( yy, x1+3+z1, 0x0a, Str ); } } catch( int E ) { error_add( "t_Path :: paint( )\n" ); throw(E); } } /************************************************************************/ // переведенный кусок источника // (надо же как сложно сделать такое простое действие) /************************************************************************/ long t_Path :: sou_length1( ) { long i,z1,z2 ; if( n_Variant<=0 ) return 0 ; t_pTree *T=&Tree[z_Tree] ; t_pVariant *V=&Variant[T->first] ; if( V->aWord.j<=0 ) { if( Up!=NULL ) return Up->sou_length1( ); return 0 ; } t_aWord *W=&V->aWord[0] ; if( T->i_last_aword< V->aWord.j ) { if( 0<T->i_last_aword ) { for( i=T->i_last_aword-1 ; 0<=i ; i-- ) { W=&V->aWord[i] ; if( 0<=W->i_last_word ) break ; } z1=sou_length( W->i_last_word ); } else { for( i=T->i_last_aword ; 0<=i ; i-- ) { W=&V->aWord[i] ; if( 0<=W->i_last_word ) break ; } z1=sou_length( W->i_word ); } } else { for( i=V->aWord.j-1 ; 0<=i ; i-- ) { W=&V->aWord[i] ; if( 0<=W->i_last_word ) break ; } z1=sou_length( W->i_last_word ); } return z1 ; } /***************************************************************************/ long t_Path :: sou_length( long i_word ) { short i,L ; if( i_word<0 ) return 0 ; if( Core.fn_word()<=i_word ) return strlen( Core.sou() ); return Core.from()[i_word].z_str ; } /***************************************************************************/ // нарисовать фразу (уже переведенный кусок) /***************************************************************************/ # define add_ws(Str) if( ' '!=Str[strlen(Str)-1] ) Strcat( Str," ",LFRASA ); void t_Path :: print1( char *Str1, long i_Node ) { long i,i1,j,z,i_slowo1 ; t_pTree *T ; long index[100] ; try { z=i_Node ; j=0 ; while( 1 ) { index[j++]=z ; z=Tree[z].up ; if( z<0 ) break ; } Str1[0]=0 ; if( StrUp[0]!=0 ) { strcat( Str1,StrUp ); add_ws( Str1 ); } for( i=j-1 ; 0<=i ; i-- ) { T=&Tree[index[i]] ; for( i1=T->i_aword ; i1<T->i_last_aword ; i1++ ) { if( Variant[T->first].aWord.j<=i1 ) return ; if( T->i_aword<i1 ) i_slowo1=0 ; else i_slowo1=T->i_slowo1 ; Strcat( Str1, print_serv( &Variant[T->first].aWord[i1], i_slowo1 ),LFRASA ); add_ws( Str1 ); } } } catch( int E ) { char EStr[200] ; sprintf( EStr,"t_Path :: print1( Str1,%d )\n",i_Node ); error_add( EStr ); throw(E); } } /***************************************************************************/ // нарисовать ближайший шаг /***************************************************************************/ void t_Path :: print2( char *Str1, long i_Node, long i_down1, long i_slowo1 ) { long i ; t_pTree *T ; try { T=&Tree[Tree[i_Node].down+i_down1] ; Str1[0]=0 ; for( i=T->i_aword ; i<T->i_last_aword ; i++ ) { if( Variant[T->first].aWord.j<=i ) return ; if( T->i_aword<i ) i_slowo1=0 ; Strcat( Str1, print_serv( &Variant[T->first].aWord[i], i_slowo1 ),LFRASA ); Strcat( Str1," ",LFRASA ); } } catch( int E ) { char EStr[200] ; sprintf( EStr,"t_Path :: print2( Str1,%d,%d,%d )\n",i_Node, i_down1, i_slowo1 ); error_add( EStr ); throw(E); } } /***************************************************************************/ // нарисовать дальнейшие шаги /***************************************************************************/ # ifdef NEW long t_Path :: print3( char *Str1, long i_Node, long i_down1, long i_slowo1 ) { long i,i1,z ; long f,L,L1 ; t_pVariant *V ; t_pTree *T ; try { Str1[0]=0 ; f=0 ; L=0 ; z=Tree[i_Node].down+i_down1 ; if( Tree[z].n_down<=0 ) goto M_Ende ; // if( Tree[z].fselect2==1 ) f=1 ; z=Tree[z].down ; while( 1 ) { T=&Tree[z] ; V=&Variant[T->first] ; for( i=T->i_aword ; i<T->i_last_aword ; i++ ) { if( i==V->aWord.j ) break ; Strcat( Str1, print_serv( &V->aWord[i], 0 ),LFRASA ); Strcat( Str1," ",LFRASA ); // if( 1<V->aWord[i].n_slowo ) f=1 ; // if( f==0 ) L=strlen( Str1 ); // if( T->fselect2==1 ) f=1 ; } // if( 1<T->n_down ) f=1 ; if( T->ende==1 ) break ; z=Tree[z].down ; } M_Ende: if( Up!=NULL ) { char Str2[LFRASA] ; split_final( Tree[i_Node].down+i_down1,&i,&i1 ); // zz_Tree индекс этого дерева в вышестоящем дереве L1=Up->print3( Str2, Up->z_Tree ,i, 0 ); Strcat( Str1,Str2,LFRASA ); // if( f==0 ) L+=L1 ; } return L ; } catch( int E ) { char EStr[200] ; sprintf( EStr,"t_Path :: print2( Str1,%d,%d,%d )\n",i_Node, i_down1, i_slowo1 ); error_add( EStr ); throw(E); } } # endif /************************************************************************/ //# ifdef OLD long t_Path :: print3( char *Str1, long i_Node, long i_down1, long i_slowo1 ) { long i,i1 ; t_pVariant *V ; t_pTree *T ; try { T=&Tree[Tree[i_Node].down+i_down1] ; V=&Variant[T->first] ; Str1[0]=0 ; for( i=T->i_last_aword ; i<V->aWord.j ; i++ ) { Strcat( Str1, print_serv( &V->aWord[i], 0 ),LFRASA ); Strcat( Str1," ",LFRASA ); } if( Up!=NULL ) { char Str2[LFRASA] ; split_final( Tree[i_Node].down+i_down1,&i,&i1 ); // zz_Tree индекс этого дерева в вышестоящем дереве Up->print3( Str2, Up->z_Tree ,i, 0 ); Strcat( Str1,Str2,LFRASA ); } return 0 ; } catch( int E ) { char EStr[200] ; sprintf( EStr,"t_Path :: print2( Str1,%d,%d,%d )\n",i_Node, i_down1, i_slowo1 ); error_add( EStr ); throw(E); } } //# endif /***************************************************************************/ char * t_Path :: print_serv( t_aWord *W, short i_slowo1 ) { t_Slowo2 *Slowo2 ; t_sStruct *S ; short i,is ; char *Str ; static char Str2[LFRASA] ; static char Str3[LFRASA] ; try { if( W->i_struct<0 ) // ---- если это константа -------- if( W->meaning<0 ) return W->Str ; else return Meaning.get( W->meaning ) ; else { if( W->n_slowo<=1 ) i_slowo1=0 ; if( W->i_slowo<0 || W->n_slowo<=0 ) { // ----- какой-то загадочный случай (убрать смелости не хватило) ----- if( W->meaning<0 ) Str=W->Str ; else Str=Meaning.get( W->meaning ) ; is=i_FormatT[W->i_struct] ; if( 0<=is ) { word_source( W->i_struct, Str, Str2, TO ); Slowo2=&SlowoT[ is ]; return Slowo2->form( Str2, &W->Form ); } else return Str ; } else { // ----- слово или структура ------------------- t_Form Form[10] ; t_Struct *SS ; t_sWord *W1 ; t_RelationList1 RR ; t_Relation R ; S=Perevod.get_to( W->i_slowo, i_slowo1 ); // ----- вычисление параметров ----------------- SS=&Grammar[S->i_struct].To ; if( SS->type==TSTRUCT2 ) RR=Perevod.get_relation( W->i_slowo, i_slowo1 ); else RR=SS->Relation ; Form[0]=W->Form ; for( i=0 ; i<S->n_Word ;i++ ) Form[i+1]=S->Word[i].Param ; if( 0<=W->i_struct && Grammar[W->i_struct].To.type==TWORD ) Form[1]=Form[0] ; for( i=0 ; i<RR.j ; i++ ) { R=RR.list[i] ; Form[R.s2].value[R.p2]=Form[R.s1].value[R.p1] ; } // ----- сложение составляющих ----------------- Str3[0]=0 ; for( i=0 ; i<S->n_Word ;i++ ) { W1=&S->Word[i] ; Str=W1->str ; if( 0<=W1->i_struct ) is=i_FormatT[W1->i_struct] ; else is=-1 ; if( 0<i ) strcat( Str3," " ) ; if( 0<=is ) { word_source( W1->i_struct, Str, Str2, TO ); Slowo2=&SlowoT[ is ]; Strcat( Str3,Slowo2->form( Str2, &Form[i+1] ),LFRASA ); } else Strcat( Str3,Str,LFRASA ) ; } return Str3 ; } } } catch( int E ) { char EStr[200] ; sprintf( EStr,"t_Path :: print_serv( Str1,%d )\n", i_slowo1 ); error_add( EStr ); throw(E); } } /***************************************************************************/ // вызов окна ручного выбора перевода /***************************************************************************/ e_WinMsg t_Path :: loop( void ) { e_WinMsg r1 ; try { e_Result r=Core.result( ); del(); if( no_trans(r) ) { Strcpy( Antwort,Core.antwort().str(),LFRASA ); r1=universe() ; provokator( ); return r1 ; } else { Antwort[0]=0 ; make_variant1( ); make_tree( ); z_Tree=i_down=0 ; r1=universe( ); provokator( ); return r1 ; } } catch( int E ) { error_add( "t_Path :: ВНУТРЕННЯЯ ОШИБКА ПРОГРАММЫ" ); figna( error_get() ); return WM_ESC ; } } /***************************************************************************/ // формирование ответа // (ужасная повторяемость текста надо в if переделать) /***************************************************************************/ e_WinMsg t_Path :: universe( ) { short ZZ,key1,key2,Level ; long z1_Tree,i,i1,i2,n_Down ; char *s1,*s2 ; t_pTree *T,*T1 ; e_WinMsg r ; e_Result r1 ; char Sign[2]="."; char StrTree[60] ; try { Sign[0]=Core.sign(); // -------- определение уровня дерева (для отладки) ---------- t_Path *P=this ; for( Level=0 ; Level<100 ; Level++ ) { if( P->Up==NULL ) break ; P=P->Up ; } r1=Core.result(); if( !no_trans(r1) ) { if( Tree[z_Tree].ende==1 ) { // ---- дерево состоит из единственной вершины (вырожденный собиратель) if( z_Tree==0 ) { print1( Antwort, z_Tree ); if( Up==NULL ) strcat( Antwort, Sign ); return WM_OK ; } z_Tree=Tree[z_Tree].up ; } } while( 1 ) { if( !no_trans(r1) ) { T=&Tree[z_Tree] ; if( T->fselect2 ) { // ----- если попали в собиратель ---------- if( T->Down==NULL ) { T->Down=new t_Path( this, z_Tree ) ; T->Down->make_variant2( this,z_Tree ); T->Down->make_tree( ); } r=T->Down->universe( ); switch( r ) { case WM_OK: T->Down->split_final( T->Down->z_Tree,&i1, &i2 ); // в этом месте ошибка goto M_OK; case WM_PREV : goto M_PREV; case WM_ESC : return WM_ESC ; } continue ; } } paint( ); sprintf( StrTree," Level=%2d z_Tree =%4d i_down=%2d",Level,z_Tree,i_down ); s_text_yxf( y2,10,0xf0,StrTree ); s_getch( &key1,&key2 ) ; ZZ=s_shiftstatus(); if( (ZZ&(S_Ctrl_L|S_Ctrl_R))!=0 ) { if( key1==0 && key2==S_key_Left ) return WM_P_FRASA ; if( key1==0 && key2==S_key_Right ) return WM_N_FRASA ; continue ; } switch( key1 ) { case S_key_TabR : return WM_NEXT ; case 0: switch( key2 ) { case S_key_F1 : Window_help( (void *)"path.html") ; break ; // ------------ переход в другие окна ------------ case S_key_F2 : return WM_FIRST ; case S_key_F3 : return WM_SRC ; case S_key_F4 : return WM_DST ; case S_key_F5 : return WM_DEBUG ; case S_key_F6 : print_all( ); figna("отладочные деревья записаны"); break ; case S_key_F10: return WM_ESC ; case S_key_Left : if( no_trans(r1) ) return WM_P_FRASA ; break ; case S_key_Right: if( no_trans(r1) ) return WM_OK ; break ; } } if( no_trans(r1) ) continue ; T=&Tree[z_Tree] ; for( n_Down=i=0 ; i<T->n_down ; i++ ) if( 0<Tree[T->down+i].n_slowo ) n_Down+=Tree[T->down+i].n_slowo ; switch( key1 ) { case S_key_Esc : case S_key_Back : return WM_ESC ; case 0: switch( key2 ) { case S_key_Left : goto M_PREV ; case S_key_Right : split_down( z_Tree, i_down, &i1, &i2 ); goto M_OK; case S_key_Up : if( 0<i_down ) i_down-- ; break ; case S_key_Down : if( i_down<n_Down-1 ) i_down++ ; break ; } } continue ; M_OK: // ---- шаг вперед ------- z1_Tree=T->down+i1 ; T1=&Tree[z1_Tree] ; z_Tree=z1_Tree ; T1->i_slowo1=i2 ; if( T1->i_struct!=-2 && T->Down!=NULL ) { t_aWord *W=&Variant[T1->first].aWord[T1->i_aword] ; s1=W->Str ; s2=T->Down->Antwort+strlen( T->Down->StrUp ) ; if( LWORD<=strlen(s2) ) W->meaning=Meaning.set( s2 ) ; else Strcpy( s1,s2,LWORD ); } if( T1->ende==1 ) { print1( Antwort, z1_Tree ); if( Up==NULL ) { t_pVariant *V=&Variant[T1->first] ; short n_word=0,z ; for( z=V->aWord.j-1 ; 0<=z ; z-- ) if( 0<=V->aWord[z].i_last_word ) { n_word=V->aWord[z].i_last_word ; break ; } if( n_word<Core.fn_word() ) { t_Antwort A ; Strcat( Antwort, A.translate_simple( n_word ), LFRASA ); } short L=strlen(Antwort) ; if( ' '==Antwort[L-1] ) Antwort[L-1]=0 ; Strcat( Antwort, Sign, LFRASA ); } return WM_OK ; } i_down=0 ; continue ; M_PREV: // ---- шаг назад ------- if( 0<=T->up ) { i_down=merge_down( z_Tree,z_Tree-Tree[T->up].down )+T->i_slowo1 ; z_Tree=T->up ; M1: T1=&Tree[z_Tree] ; if( T1->fselect2!=0 && T1->Down->n_Tree<=1 && 0<=T1->up ) // ------ вырожденный собиратель ------- { z_Tree=T1->up ; goto M1 ; } } else { if( Up!=NULL ) return WM_PREV ; } continue ; } } catch( int E ) { error_add( "t_Path :: universe\n" ); throw(E); } } /************************************************************************/ // сосчитать число вариантов i_down сыновей /************************************************************************/ long t_Path :: merge_down( long i_Tree, long i_down1 ) { long i,n ; t_pTree *T ; try { T=&Tree[i_Tree] ; for( n=i=0 ; i<i_down1 ; i++ ) n=Tree[T->down+i].n_slowo ; return n ; } catch( int E ) { error_add( "t_Path :: merge_down\n" ); throw(E); } } /************************************************************************/ // расщепить индекс потомка на "старший" (индекс потомка) // и "младший" (индекс варианта потомка) /************************************************************************/ void t_Path :: split_down( long i_Tree, long i_down1, long *i1, long *i2 ) { long i,n,n_Down ; t_pTree *T ; try { T=&Tree[i_Tree] ; n_Down=0 ; for( i=0 ; i<T->n_down ; i++ ) { n=Tree[T->down+i].n_slowo ; if( i_down1<n_Down+n ) { *i1=i ; *i2=i_down1-n_Down ; return ; } n_Down+=n ; } *i1=-1 ; *i2=-1 ; } catch( int E ) { error_add( "t_Path :: split_down\n" ); throw(E); } } /************************************************************************/ void t_Path :: split_final( long i_Tree, long *i1, long *i2 ) { long z,up ; try { z=i_Tree ; while( 0<z ) { up=Tree[z].up ; if( up==0 ) break ; z=up ; } //*i1=Variant[Tree[z].first].i_down ; *i1=Variant[Tree[i_Tree].first].i_down ; *i2=Tree[z].i_slowo1 ; } catch( int E ) { error_add( "t_Path :: split_final\n" ); throw(E); } } /************************************************************************/ // сравнить два варианта перевода (для упорядочивания) /************************************************************************/ int varcmp( const void *_a , const void *_b ) { t_pVariant *a,*b ; long i,i1 ; char f=0 ; try { a=(t_pVariant *)_a ; b=(t_pVariant *)_b ; if( a->aWord.j != b->aWord.j ) { f=1 ; goto M_End ; } for( i=0 ; i<a->aWord.j ; i++ ) { if( a->aWord[i].i_struct != b->aWord[i].i_struct ) { f=1 ; break ; } if( a->aWord[i].i_slowo != b->aWord[i].i_slowo ) { f=1 ; break ; } if( a->aWord[i].i_struct<0 && 0!=Strcmp( a->aWord[i].Str, b->aWord[i].Str ) ) { f=1 ; break ; } t_Form &F1 = a->aWord[i].Form ; t_Form &F2 = b->aWord[i].Form ; for( i1=0 ; i1<10 ; i1++ ) if( F1.value[i1]!=F2.value[i1] ) { f=1 ; break ; } } M_End : if( f==1 ) return a->index - b->index ; else return 0 ; } catch( int E ) { error_add( "t_Path :: varcmp\n" ); throw(E); } } /************************************************************************/ // сравнить два варианта слова (для упорядочивания) /************************************************************************/ int awordcmp( const void *_a , const void *_b ) { t_aWord *a,*b ; a=(t_aWord *)_a ; b=(t_aWord *)_b ; if( a->i_struct != b->i_struct ) return a->i_struct - b->i_struct ; if( a->i_slowo != b->i_slowo ) return a->i_slowo - b->i_slowo ; if( a->i_word != b->i_word ) // только что вставил return a->i_word - b->i_word ; if( a->i_last_word != b->i_last_word ) // только что вставил return a->i_last_word - b->i_last_word ; if( a->i_struct<0 ) return Strcmp( a->Str, b->Str ); t_Form &F1 = a->Form ; t_Form &F2 = b->Form ; for( short i1=0 ; i1<10 ; i1++ ) if( F1.value[i1]!=F2.value[i1] ) { return F1.value[i1]-F2.value[i1] ; } return 0 ; } /************************************************************************/ t_aWord get_word( t_pVariant &V, short i_aword ) { if( i_aword<V.aWord.j ) return V.aWord[i_aword] ; else { t_aWord W ; W.i_word = 0 ; W.i_last_word= 0 ; W.i_struct =-2 ; W.i_slowo = 0 ; W.n_slowo = 0 ; W.Str[0] = 0 ; W.meaning =-1 ; return W ; } } /************************************************************************/ // сделать дерево вариантов перевода /************************************************************************/ void t_Path :: make_tree( void ) { long i,i1,j ; t_pTree T1,*T ; t_aWord W,W1 ; try { if( 0==Core.fn_word() ) { n_Variant=0 ; n_Tree =0 ; return ; } Free(Tree); if( n_Variant==0 ) { n_Tree=0 ; return ; } Tree=(t_pTree *)Calloc( 1+Core.from().j*n_Variant,sizeof(t_pTree) ); // -------- внести первую вершину ------------------ T1.up =-1 ; T1.down = 1 ; T1.n_down = 0 ; T1.first= 0 ; T1.last = n_Variant ; T1.ende = 0 ; T1.i_struct = i_main_struct ; T1.i_aword =-1 ; T1.i_last_aword =0 ; T1.i_slowo1 =0 ; T1.n_slowo =0 ; T1.Down =NULL ; Tree[0]=T1 ; // -------- внести последующие вершины ------------- char f_split,f_exist ; short i_aword ; for( i=0,j=1 ; i<j ; i++ ) { T=&Tree[i] ; // ----- выяснить есть ли "разветвления" на этой ветке ------ if( T->last-T->first<=1 ) { for( i1=T->i_aword+1 ; i1<Variant[T->first].aWord.j ; i1++ ) { W = get_word( Variant[T->first], i1 ); if( 1<W.n_slowo ) goto M_Need ; if( 0<=W.i_struct && Grammar[W.i_struct].From.type==TSELECT2 ) goto M_Need ; } T->ende=1 ; T->i_last_aword=100 ; continue ; M_Need : ; } T->down=j ; // ---- пройти вдоль ветки, и сделать в нужном слове разветвление ---- for( i_aword=T->i_aword+1 ; i_aword<100 ; i_aword++ ) { f_split=f_exist=0 ; // ---- делать ли разветвление в слове i_word ---- if( 0<=T->i_struct && Grammar[T->i_struct].From.type==TSELECT2 ) f_split=1 ; W = get_word( Variant[T->first], i_aword ); for( i1=T->first ; i1<T->last ; i1++ ) { W1 = get_word( Variant[i1], i_aword ); if( i_aword<Variant[i1].aWord.j ) f_exist=1 ; if( 0!=awordcmp( &W,&W1 ) ) { f_split=1 ; break ; } if( 1<W1.n_slowo ) { f_split=1 ; break ; } if( 0<=W1.i_struct && Grammar[W1.i_struct].From.type==TSELECT2 ) { f_split=1 ; break ; } } if( f_exist==0 ) break ; if( f_split==0 ) continue ; // ---- если делать, то какие варианты в какие ветки попадают ---- W.i_struct=-2 ; for( i1=T->first ; i1<T->last ; i1++ ) { W1 = get_word( Variant[i1], i_aword ); if( 0!=awordcmp( &W,&W1 ) || W.i_struct==-2 ) { if( T->first<i1 ) Tree[j-1].last=i1 ; T1.up = i ; T1.n_down = 0 ; T1.first = i1 ; T1.last = n_Variant ; T1.ende = 0 ; T1.i_struct= W1.i_struct ; T1.i_aword = i_aword ; T1.i_slowo1= 0 ; T1.n_slowo = W1.n_slowo ; Tree[j++]=T1 ; W=W1 ; } } if( f_split==1 ) { T->i_last_aword=i_aword ; Tree[j-1].last=T->last ; } if( f_split==1 ) break ; } T->n_down=j-T->down ; } if( 1+Core.from().j*n_Variant<j ) { error_set("t_Path :: make_tree Ошибка памяти при заполнении Tree\n"); throw(-1); } n_Tree=j ; Tree=(t_pTree *)Realloc( Tree,n_Tree*sizeof(t_pTree) ); // Memory Leak Tree[0].i_aword=0 ; // ---- проставить n_slowo и fselect2 ------- for( i=0 ; i<n_Tree ; i++ ) { if( Tree[i].n_slowo<=0 ) Tree[i].n_slowo=1 ; Tree[i].fselect2=0 ; if( 0<=Tree[i].i_struct && Grammar[Tree[i].i_struct].From.type==TSELECT2 && 0<=Tree[i].up ) Tree[Tree[i].up].fselect2=1 ; } // print_tree( "Tree0" ); } catch( int E ) { error_add( "t_Path :: make_tree\n" ); throw(E); } } /************************************************************************/ // подсчет сыновей для "пред-собирателя" /************************************************************************/ long t_Path :: n_variant_calc( t_Path *Up1, long z_Tree1 ) { long i,i1,n ; short i_struct ; t_Struct *SS ; t_pTree *T,*T1 ; t_Variants *VV ; try { T=&Up1->Tree[z_Tree1] ; for( i=n=0 ; i<T->n_down ; i++ ) { T1=&Up1->Tree[T->down+i] ; i_struct=T1->i_struct ; if( 0<=i_struct ) SS=&Grammar[i_struct].From ; if( i_struct<0 || SS->type!=TSELECT2 ) n++ ; else { for( i1=0 ; i1<SS->Word.j ; i1++ ) { //t_aWord *W=&Up1->Variant[T->first].aWord[T->i_last_aword] ; t_aWord *W=&Up1->Variant[T1->first].aWord[T1->i_aword] ; if( W->i_word<0 || SS->Word[i1].i_struct<0 ) n++ ; else { VV=Core.variants( W->i_word,SS->Word[i1].i_struct ); n+=VV->Variant.j ; } } } } return n ; } catch( int E ) { char EStr[200] ; sprintf( EStr,"t_Path :: n_variant_calc( Up1,%d )\n", z_Tree ); error_add( EStr ); throw(E); } } /************************************************************************/ // сделать массив вариантов для последующего построения дерева /************************************************************************/ void t_Path :: make_variant1( void ) { long i,j ; t_Variants *VV ; t_Form Form0 ; try { VV=Core.variants( 0, i_main_struct ); Free( Variant ); Variant=(t_pVariant *)Calloc( VV->Variant.j,sizeof(t_pVariant) ); for( i=j=0 ; i<VV->Variant.j ; i++ ) { if( Core.f_full() && VV->Variant[i].i_last_word<Core.fn_word()) continue ; Core.antwort().make( 0,i_main_struct,i,Form0 ); Variant[j].index =i ; Variant[j].i_down=i ; Variant[j].aWord =*Core.antwort().aword() ; Core.antwort().del(); if( VV->Variant.j<=j ) { error_set("t_Path :: make_variant Ошибка памяти при заполнении Variant\n"); throw(-1); } j++ ; } n_Variant=j ; sort_variant(); } catch( int E ) { error_add( "t_Path :: make_variant1\n" ); throw(E); } } /************************************************************************/ // сделать массив вариантов для последующего построения дерева /************************************************************************/ void t_Path :: make_variant2( t_Path *Up1, long z_Tree1 ) { long i,i1,i2,i3,j,n,i_struct,i_last_word ; t_Variants *VV ; t_Struct *SS ; t_pTree *T,*T1 ; t_aWord *W ; t_RelationList1 RR ; t_Relation R ; try { n_Variant=n_variant_calc( Up1,z_Tree1 ); Free( Variant ); Variant=(t_pVariant *)Calloc( n_Variant,sizeof(t_pVariant) ); // Memory Leak T=&Up1->Tree[z_Tree1] ; for( j=i=n=0 ; i<T->n_down ; i++ ) { T1=&Up1->Tree[T->down+i] ; i_struct=T1->i_struct ; if( 0<=i_struct ) SS=&Grammar[i_struct].From ; if( 0<=i_struct && SS->type==TSELECT2 ) { RR=Grammar[i_struct].To.Relation ; W=&Up1->Variant[T1->first].aWord[T1->i_aword] ; i_last_word=W->i_last_word ; for( i1=0 ; i1<SS->Word.j ; i1++ ) { if( SS->Word[i1].type==TWORD0 ) { Variant[j].index=j ; // i Variant[j].i_down=i ; //Variant[j].aWord = ; j++ ; } else { VV=Core.variants( W->i_word,SS->Word[i1].i_struct ); for( i2=0 ; i2<VV->Variant.j ; i2++ ) { if( VV->Variant[i2].i_last_word!=i_last_word ) continue ; t_Antwort A ; // ---- госссподи, что я делаю, какой позор! ------- // ---- вычисляю параметры потомка, подменяя функции ядра ---- t_Form Form ; Form.init(); for( i3=0 ; i3<RR.j ; i3++ ) { R=RR.list[i3] ; if( R.s1!=0 ) continue ; if((R.s2-1)!=i1 ) continue ; Form.value[R.p2] = W->Form.value[R.p1] ; } A.make( W->i_word, SS->Word[i1].i_struct, i2, Form ); if( n_Variant<=j ) { error_set("t_Path :: make_variant2 Ошибка памяти при заполнении Variant\n"); throw(-1); } Variant[j].index=j ; // i Variant[j].i_down=i ; Variant[j].aWord =*A.aword() ; A.del(); j++ ; } } } } else { if( n_Variant<=j ) { error_set("t_Path :: make_variant2 Ошибка памяти при заполнении Variant\n"); throw(-1); } Variant[j].index =j ; Variant[j].i_down=i ; // ну а вообще-то как отображать такой "вариант с пустым словом"??? if( T1->i_struct!=-2 ) Variant[j].aWord.add( Up1->Variant[T1->first].aWord[T1->i_aword] ); j++ ; } } n_Variant=j ; sort_variant(); } catch( int E ) { char EStr[200] ; sprintf( EStr,"t_Path :: make_variant2( Up1,%d )\n", z_Tree1 ); error_add( EStr ); throw(E); } } /************************************************************************/ // сортировка вариантов в удобном для человека порядке /************************************************************************/ void t_Path :: sort_variant() { long i,i1,j,i_word,max_Word,End,m_Variant ; t_pVariant **Var1,**Var2,**Var3,*zVar ; t_aWord W1,W2 ; // ------ Сделать массив ссылок на варианты ----------------- m_Variant=n_Variant ; Var1=(t_pVariant **)Calloc( n_Variant,sizeof(t_pVariant *) ); Var2=(t_pVariant **)Calloc( n_Variant,sizeof(t_pVariant *) ); for( i=0 ; i<n_Variant ; i++ ) Var1[i]=&Variant[i] ; // ------ Уничтожить одинаковые стоящие рядом варианты ------ for( i=j=1 ; i<n_Variant ; i++ ) if( 0!=varcmp( Var1[j-1],Var1[i] ) ) { Var1[j++]=Var1[i] ; } if( 0<n_Variant ) n_Variant=j ; for( i=max_Word=0 ; i<n_Variant ; i++ ) if( max_Word<Var1[i]->aWord.j ) max_Word=Var1[i]->aWord.j ; // ------ Цикл по номеру слова в варианте ------------------- for( i_word=0 ; i_word<max_Word ; i_word++ ) { // ---- Цикл по номеру варианта ---------------------- for( i=j=0 ; i<n_Variant ; i++ ) { // ----- Если вариант выбран - continue ----- if( Var1[i]==NULL ) continue ; // ----- Переписать вариант во второй массив вариантов и // ----- Установить на него стрелку zVar=Var1[i] ; Var2[j++]=Var1[i] ; Var1[i]=NULL ; // ----- Установить предел индекса End по неравенству предыдущего слова if( i_word==0 ) End=n_Variant ; else { W1=get_word( *zVar,i_word-1 ); for( End=i+1 ; End<n_Variant ; End++ ) { if( Var1[End]==NULL ) continue ; W2=get_word( *(Var1[End]),i_word-1 ); if( 0!=awordcmp( &W1,&W2 ) ) break ; } } // ----- Еще цикл по номеру варианта i1=i+1 ; i1<End for( i1=i+1 ; i1<End ; i1++ ) { if( Var1[i1]==NULL ) continue ; // -- Если вариант тождественен варианту на стрелке - переписать в другой массив W1=get_word( *zVar,i_word ); W2=get_word( *(Var1[i1]),i_word ); if( 0==awordcmp( &W1,&W2 ) ) { Var2[j++]=Var1[i1] ; Var1[i1]=NULL ; } } } if( n_Variant<j ) printf("Аааа!!! Ошибка!!!!\n"); // ----- Поменять первый и второй массивы ссылок ------ Var3=Var1 ; Var1=Var2 ; Var2=Var3 ; } // ------ Уничтожить одинаковые стоящие рядом варианты ------ for( i=j=1 ; i<n_Variant ; i++ ) if( 0!=varcmp( Var1[j-1],Var1[i] ) ) { Var1[j++]=Var1[i] ; } if( 0<n_Variant ) n_Variant=j ; // ------ Переписать массив вариантов ------------------------ t_pVariant *Variant1 ; long n_aWord ; for( i=n_aWord=0 ; i<n_Variant ; i++ ) n_aWord+=Var1[i]->aWord.j ; Variant1=(t_pVariant *)Calloc( n_Variant,sizeof(t_pVariant) ); aWord =(t_aWord *)Calloc( n_aWord ,sizeof(t_aWord) ); for( i=j=0 ; i<n_Variant ; i++ ) { Variant1[i].index =Var1[i]->index ; Variant1[i].i_down=Var1[i]->i_down ; Variant1[i].aWord.list=aWord+j ; Variant1[i].aWord.j=Var1[i]->aWord.j ; for( i1=0 ; i1<Var1[i]->aWord.j ; i1++ ) aWord[j++]=Var1[i]->aWord[i1] ; } for( i=0 ; i<m_Variant ; i++ ) Variant[i].aWord.del(); Free( Var1 ); Free( Var2 ); Free(Variant) ; Variant=Variant1 ; } /************************************************************************/ // печать вариантов (для отладки) /************************************************************************/ void t_Path :: print_variant( char *File ) { long i,i1,j ; FILE *fw ; t_aWord W ; fw=Fopen( File,"w"); for( i=0 ; i<n_Variant ; i++ ) { fprintf( fw,"\n %3d i_down=%4d",i,Variant[i].i_down ); for( i1=0 ; i1<Variant[i].aWord.j ; i1++ ) { W=Variant[i].aWord[i1] ; fprintf( fw,", %d %s ",W.n_slowo, W.Str ); for( j=0 ; j<10 ; j++ ) fprintf( fw,"%c",'0'+W.Form.value[j] ); } } Fclose(fw); } /************************************************************************/ // печать дерева (для отладки) /************************************************************************/ void t_Path :: print_tree( char *Name1 ) { long i ; t_pTree *T ; FILE *fw=Fopen( Name1,"w"); char *s1 ; fprintf( fw,"\n i up down n_down | first last | i_word i_word n_slowo ende select |" ); for( i=0 ; i<n_Tree ; i++ ) { T=&Tree[i] ; s1="" ; if( 0<=T->i_aword && T->i_aword<Variant[T->first].aWord.j ) s1=Variant[T->first].aWord[T->i_aword].Str ; fprintf( fw,"\n %5ld %5ld %5ld %5ld | %5ld %5ld | %5d %5d %5d %5d %d | %s",i, T->up, T->down, T->n_down, T->first, T->last, T->i_aword, T->i_last_aword, T->n_slowo, T->ende, T->fselect2, s1 ); } Fclose(fw); } /************************************************************************/ void t_Path :: print_all( ) { t_Path *P=this ; short i,n ; char Str[100] ; for( i=0 ; i<100 ; i++ ) { if( P->Up==NULL ) break ; P=P->Up ; } n=i ; P=this ; for( i=0 ; i<100 ; i++ ) { sprintf( Str,"Var%d",n-i ); P->print_variant( Str ); sprintf( Str,"Tree%d",n-i ); P->print_tree( Str ); if( P->Up==NULL ) break ; P=P->Up ; } } /************************************************************************/ t_Meaning :: t_Meaning() { Meaning =(char *)Calloc( l_Meaning=5000,1 ); j_Meaning=0 ; } /************************************************************************/ t_Meaning :: ~t_Meaning() { Free(Meaning); } /************************************************************************/ long t_Meaning :: set( char *Str ) { long z,L,LL ; L=strlen(Str); if( L==0 ) return -1 ; if( l_Meaning<=j_Meaning+L+1 ) { LL=l_Meaning+max(l_Meaning>>2,L+1) ; Meaning=(char *)Realloc( Meaning,LL ); l_Meaning=LL ; } z=j_Meaning ; strcpy( Meaning+j_Meaning, Str ); j_Meaning+=L+1 ; return z ; } /************************************************************************/ char * t_Meaning :: get( long z ) { if( z<0 ) return "" ; return Meaning+z ; }