/***************************************************************************/ // "Меркурий"-"Правда" - open source переводчик // распространяется в соответсвии с лицензией GNU v 2.0 // // главная программа перевода // Анисимов Д.В. сегодня /***************************************************************************/ # include <string.h> # include <stdlib.h> # include <unistd.h> # include <mylib.h> # include <slowo2.h> # include <slowo3.h> # include <grammar.h> # include <core.h> t_Slowo3 Macro ; // словарь английских сокращений (препроцессор) t_Slowo3 Micro ; // словарь русских сокращений (постпроцессор) t_Slowo3 DicConst ; // словарь английских constant t_Slowo3 Perevod ; // словарь переводов t_Slowo2 *SlowoF, // грамматические словари языка-оригинала *SlowoT ; // грамматические словари языка-перевода short *i_FormatT ; // соответствие часть речи -> SlowoT short *i_FormatF ; // соответствие часть речи -> SlowoF t_Core Core ; static char f_data_read=0 ; // данные уже были прочитаны void make_dic_const( void ); short find_enum_select( e_Half H, short up_struct, long i_slowo ); char compare_param( t_Param1List *Param, t_Form *Form ); void word_source( short i_struct, char *Word, char *Source, e_Half H ); char is_number( char *Str ); t_Tree *part_of_struct( t_TreeList &Tree, long i_tree, short i_word ); static void print_tree( t_TreeList &Node, char *FileName ); static void make_token( char *Sou, char *Dst ); /***************************************************************************/ char *filename( char *Path, char *File ) { static char Str[200] ; Strcpy( Str,Path,200 ); if( Str[strlen(Str)-1]!='/' ) Strcat( Str,"/",200 ); Strcat( Str,File,200 ); return Str ; } /***************************************************************************/ // прочесть все данные /***************************************************************************/ char read_grammar( char *Dir ) { t_File *F ; long i,N ; char *Path=".."; char Path1[200] ; char r ; try { if( Dir[0]!=0 ) Path=Dir ; r=Grammar.make_all( filename( Path,"grammar/lang.txt" ) ); if( r<0 ) return r ; File_Error=Fopen("mercury.err","w+"); Macro.read( filename( Path,"dicts/en_macro" ), &(Grammar.format1()[0]) ); Micro.read( filename( Path,"dicts/en_macro" ), &(Grammar.format1()[0]) ); make_dic_const( ); Strcpy( Path1,Path,200 ); if( Path1[strlen(Path1)-1]!='/' ) Strcat( Path1,"/",200 ); Strcat( Path1,"dicts",200 ); // ---------------- прочитать словари источника -------------------- t_Lang &From=Grammar.from(); N=From.File.j ; SlowoF =(t_Slowo2 *)Calloc( N,sizeof(t_Slowo2) ); i_FormatF=(short *)Calloc( From.Part.j,sizeof(t_Slowo2) ); for( i=0 ; i<From.Part.j ; i++ ) i_FormatF[i]=-1 ; for( i=0 ; i<N ; i++ ) { F=&From.File[i] ; SlowoF[i].read( filename( Path1,F->FileName[0] ), &From, &From.Format[F->i_format] ); SlowoF[i].freverce(); i_FormatF[F->i_part]=i ; } // ---------------- прочитать словари приемника -------------------- t_Lang &To=Grammar.to(); N=To.File.j ; SlowoT =(t_Slowo2 *)Calloc( N,sizeof(t_Slowo2) ); i_FormatT=(short *)Calloc( To.Part.j,sizeof(t_Slowo2) ); for( i=0 ; i<To.Part.j ; i++ ) i_FormatT[i]=-1 ; for( i=0 ; i<N ; i++ ) { F=&To.File[i] ; SlowoT[i].read( filename( Path1,F->FileName[0]), &To, &To.Format[F->i_format] ); SlowoT[i].freverce(); i_FormatT[F->i_part]=i ; } // -------------- прочитать словари перевода --------------- Perevod.read( filename( Path1,"" ), &Grammar ); /* strcpy( Filename,Dir ); strcat( Filename,"../dicts/base_enru.bin" ); r=Perevod.read_bin( Filename ); if( r<0 ) { Perevod.read( &Grammar ); Perevod.write_bin( Filename ); } */ Fclose( File_Error ); if( Read_Error==0 ) { unlink("mercury.err") ; f_data_read=1 ; } return Read_Error ; // если тут 0, то все в порядке } catch( int E ) { Read_Error=-1 ; Fclose( File_Error ); return -1 ; } } /***************************************************************************/ // перепрочесть все данные /***************************************************************************/ char reread_grammar( char *Dir ) { char r ; char *Path=".."; char Str[300] ; if( Dir[0]!=0 ) Path=Dir ; # ifndef __WIN__ sprintf( Str,"g++ -E -o %s/grammar/lang.txt -I%s/grammar %s/grammar/lang.cpp", Path,Path,Path ); system( Str ); # endif if( 0==f_data_read ) return read_grammar( Dir ); r=Grammar.make_all( filename( Path,"grammar/lang.txt" ) ) ; if( r<0 ) return r ; set_formats( ); return 0 ; } /***************************************************************************/ // сделать словарь для констант, встречаемых в lang.txt /***************************************************************************/ void make_dic_const( void ) { t_Struct *S ; long i,i1,L ; char *Mass,Str[100] ; for( i=L=0 ; i<Grammar.n_trans() ; i++ ) { S=&Grammar[i].From ; for( i1=0 ; i1<S->Word.j ; i1++ ) if( S->Word[i1].type==TCONST ) L+=strlen( S->Word[i1].literal )+10 ; } Mass=(char *)Calloc( L+1,sizeof(char) ); for( i=L=0 ; i<Grammar.n_trans() ; i++ ) { S=&Grammar[i].From ; for( i1=0 ; i1<S->Word.j ; i1++ ) if( S->Word[i1].type==TCONST ) { sprintf( Str,"\n@0[%s]=@0[]",S->Word[i1].literal ); strcpy( Mass+L,Str ); L+=strlen( Str ); } } DicConst.make( Mass, &(Grammar.format1()[0]) ); Free( Mass ); } /***************************************************************************/ // проставить словарям ссылки на форматы, // порушенные при повторном чтении lang.txt /***************************************************************************/ void set_formats( void ) { short i ; t_File *F ; t_Lang &From = Grammar.from(); t_Lang &To = Grammar.to(); for( i=0 ; i<From.File.j ; i++ ) { F=&From.File[i] ; SlowoF[i].set_lf( &From, &From.Format[F->i_format] ); } for( i=0 ; i<To.File.j ; i++ ) { F=&To.File[i] ; SlowoT[i].set_lf( &To, &To.Format[F->i_format] ); } } /***************************************************************************/ t_Core :: t_Core( ) { n_struct =0 ; n_word =0 ; Variants =NULL ; Meaning =(char *)Calloc( l_Meaning=5000,1 ); j_Meaning=0 ; rWord.init(); Result=E_NULL ; } /***************************************************************************/ t_Core :: ~t_Core( ) { long i,N ; N=(long)(n_struct)*(long)(n_word+1) ; for( i=0 ; i<N ; i++ ) Variants[i].Variant.del(); Free( Variants ); Free( Meaning ); rWord.del(); } /***************************************************************************/ // конструктор // _n_struct - число шаблонов в t_Grammar // _n_word - число слов в переводимой фразе /***************************************************************************/ void t_Core :: init( short _n_struct, short _n_word ) { long i,i1,N ; t_Variants *VV ; N=(long)(n_struct)*(long)(n_word+1) ; for( i=0 ; i<N ; i++ ) Variants[i].Variant.del(); Free(Variants); n_struct=_n_struct ; n_word =_n_word ; N=(long)(n_struct)*(long)(n_word+1) ; Variants=(t_Variants *)Calloc( N,sizeof(t_Variants) ); for( i=0 ; i<n_struct ; i++ ) { for( i1=0 ; i1<n_word ; i1++ ) { VV=variants( i1,i ); VV->i_struct=i ; VV->i_word =i1 ; } } rWord.j=0 ; } /***************************************************************************/ // главная программа перевода // Sou - строка источника // Dst - строка приемника (должна быть захвачена до вызова) /***************************************************************************/ void t_Core :: translate( char *_Sou, char *Dst ) { long i,i_best,nn,r,r1,n_Antwort ; t_rStruct *pV ; t_Word Word ; t_Form Form0 ; try { Result=E_NULL ; Sou=_Sou ; if( 0==strncmp(Sou,"\\##",3) ) { // ----- фраза не нуждается в переводе -------- no_brakets( Sou,Dst ); Strcpy( Antwort.str(),Dst,LFRASA ); Strcpy( Sou1,Dst,LFRASA ); Result=E_NO ; return ; } for( i=0 ; i<LFRASA ; i++ ) Sou0[i]=Sou1[i]=0 ; Antwort.del(); r =make_from1( Sou ); r1=make_from2( ); if( r!=0 || r1!=0 || From.j==0 ) goto M_Simple ; universe( 0, i_main_struct ); n_Antwort=Variants[0+i_main_struct].Variant.j ; if( n_Antwort==0 ) goto M_Simple ; // -------- определить есть ли "полные" варианты --------- for( f_Full=0,i=0 ; i<n_Antwort ; i++ ) { pV=variant( 0,i_main_struct,i ); if( pV->i_last_word==From.j ) { f_Full=1 ; break ; } } // -------- найти лучший вариант ------------------------- for( i_best=nn=i=0 ; i<n_Antwort ; i++ ) { pV=variant( 0,i_main_struct,i ); if( f_Full==1 && pV->i_last_word<From.j ) continue ; if( nn<pV->i_last_word ) { nn=pV->i_last_word ; i_best=i ; } } Dst[0]=0 ; Antwort.make( 0, i_main_struct, i_best, Form0 ) ; Strcpy( Dst,Antwort.str(),LFRASA ); if( f_Full ) Result=E_OK ; else Result=E_FIG ; return ; M_Simple: strcpy( Antwort.str(),"#фигня# " ); Antwort.translate_simple( 0 ); strcpy( Dst,Antwort.str() ); Result=E_FIGNA ; } catch( int E ) { strcpy( Dst,"!!! ошибка !!!."); Result=E_ERROR ; } } /************************************************************************/ // вытянуть фразу из фигурных скобочек // ( надо использовать в make_from1 ) /************************************************************************/ void t_Core :: no_brakets( char *Str, char *Str1 ) { long i,i1,L ; L=strlen( Str ); for( i=0 ; i<L ; i++ ) if( Str[i]=='{' ) break ; strcpy( Str1,Str+i+1 ); for( i1=L-i-1 ; 0<=i1 ; i1-- ) if( Str1[i1]=='}' ) { Str1[i1]=0 ; break ; } } /***************************************************************************/ // разбиение фразы на слова // Source - переводимая фраза /***************************************************************************/ char t_Core :: make_from1( char *Source ) { long i,j,f,L ; char c,c1 ; t_Item W ; e_TagType t ; char sPart[100],Str[100],stmp[2]=" " ; From.j=0 ; L=strlen( Source ); if( LFRASA<L ) return 1 ; if( 0==strncmp(Source,"\\@@",3) ) no_brakets( Source,Sou1 ); else strcpy( Sou1,Source ); // ------- отделить точку от последнего слова ------------ i=strlen( Sou1 ) ; Sign='.' ; for( ; 0<i ; i-- ) { c=Sou1[i] ; if( c=='}' || c=='.' || c=='!' || c=='?' ) break ; } if( c=='.' || c=='!' || c=='?' ) { Sign=Sou1[i] ; i++ ; Sou1[i+1]=0 ; Sou1[i]=Sou1[i-1] ; Sou1[i-1]=' ' ; } // ---- вот тут надо разворачивать сокращения ------ for( i=f=j=0 ; i<L ; i++ ) { c=Sou1[i] ; if( 0==strncmp( Sou1+i,"\\@~",3 ) ) f=1 ; if( 0==strncmp( Sou1+i,"\\@=",3 ) ) f=1 ; if( 0==strncmp( Sou1+i,"\\#<",3 ) ) f=1 ; if( 0==strncmp( Sou1+i,"\\#>",3 ) ) f=1 ; if( 0==strncmp( Sou1+i,"\\#" ,2 ) ) f=1 ; if( f==1 ) { stmp[0]=c ; strcat( Sou0,stmp ); } else { if( c==' ' || c=='\t' || c=='\n' ) { if( 0<j ) { Str[j]=0 ; j=0 ; strcat( Sou0, Macro.translate_word_s( Str,-1 ) ); strcat( Sou0," " ); } } else { if( j<98 ) Str[j++]=c ; } } if( c=='}' ) { f=0 ; stmp[0]=' ' ; strcat( Sou0,stmp ); } } Str[j]=0 ; strcat( Sou0, Macro.translate_word_s( Str,-1 ) ); strcpy( Sou1,Sou0 ); // ------- проверить на корректность тегов --------- L=strlen( Sou1 ); for( i=f=0 ; i<L ; i++ ) { c=Sou1[i] ; f+=(c=='{') ; f-=(c=='}') ; if( f==0 && (c=='\t' || c=='\n') ) Sou1[i]=' ' ; if( f==0 && (c=='.' || c=='!' || c=='?' || c==',' || c=='(' || c==')' || c==';' || c==':' ) ) Sou1[i]=' ' ; } if( f!=0 ) return 1 ; // ------ сделать массив From --------------------- c1=' ' ; t=P_FRASA ; for( i=0 ; i<L ; i++ ) { f=0 ; if( 0==strncmp( Sou1+i,"\\@~",3 ) ){ f=1 ; t=P_STRUCT ; } if( 0==strncmp( Sou1+i,"\\@=",3 ) ){ f=1 ; t=P_CONST ; } if( 0==strncmp( Sou1+i,"\\#<",3 ) ){ f=1 ; t=P_TAG_LEFT ; } if( 0==strncmp( Sou1+i,"\\#>",3 ) ){ f=1 ; t=P_TAG_RIGHT ; } if( f==1 ) { Sou1[i]=0 ; i+=2 ; if( t==P_STRUCT || t==P_CONST ) { make_token( Sou1+i+1,sPart ); W.i_struct=Grammar.find_struct( FROM,sPart ); } continue ; } c=Sou1[i] ; W.type=t ; if( t==P_FRASA ) { if( c1==' ' && c!=' ' ) { W.Str=Sou0+i ; W.Str1=Sou1+i ; W.z_str=i ; From.add( W ); } } if( t==P_CONST || t==P_STRUCT ) { if( c=='{' ) { W.Str=Sou0+i+1 ; W.Str1=Sou1+i+1 ; W.z_str=i+1 ; From.add( W ); } } if( t==P_VERB ) { if( c=='{' ) { W.Str=Sou0+i+1 ; W.Str1=Sou1+i+1 ; W.z_str=i+1 ; From.add( W ); } } if( t==P_TAG_LEFT || t==P_TAG_RIGHT ) { if( c=='{' ) { W.Str=Sou0+i+1 ; W.Str1=Sou1+i+1 ; W.z_str=i+1 ; if( t==P_TAG_LEFT ) W.i_word = From.j ; else W.i_word = From.j-1 ; Tag.add( W ); } } if( c==' ' && t==P_FRASA ) Sou0[i]=0 ; if( c=='}' ) { t=P_FRASA ; Sou0[i]=Sou1[i]=0 ; W.i_struct=-1 ; } c1=c ; } return 0 ; } /************************************************************************/ // заполнене главной таблицы атомарными элементами /************************************************************************/ char t_Core :: make_from2( void ) { long i,i1,i2,i3,i4,i_word,N,N1 ; short i_part ; char *Str,*Str1 ; t_Lexer Lexer ; long Ant1[20] ; short part[20] ; t_Form Form[20] ; t_longList Ant2 ; t_Variants *VV=NULL ; init( Grammar.n_trans(), From.j ); // ----- определить для каждого слова какой частью речи, оно может быть ----- for( i_word=0 ; i_word<From.j ; i_word++ ) { e_TagType t=From[i_word].type ; if( t==P_STRUCT || t==P_CONST || t==P_VERB ) { // ------- спец слова ---------------------------- short i_struct=From[i_word].i_struct ; t_Struct *SS=&Grammar[i_struct].From ; if( SS->type==TENUM ) { for( i=0 ; i<SS->Word.j ; i++ ) add_from( i_word, SS->Word[i].i_struct, t_Form(), -1, -1 ); } else add_from( i_word, i_struct, t_Form(), -1, -1 ); From[i_word].exist=1 ; continue ; } Str=From[i_word].Str ; if( is_number(Str) ) { // -------- проверить, что это числительное ------- add_from( i_word, Grammar.i_number(), t_Form(), -1, -1 ); continue ; } // ----------- найти в словарях форм ----------------- for( i1=0 ; i1<Grammar.from().File.j ; i1++ ) { i_part=SlowoF[i1].Format->i_part ; N=SlowoF[i1].quest( Str, Ant1, Form ); for( i2=0 ; i2<N ; i2++ ) { Str1=SlowoF[i1].normal( Ant1[i2] ); Perevod.find( Str1,i_part,&Ant2 ); if( Ant2.j<=0 ) continue ; for( i3=0 ; i3<Ant2.j ; i3++ ) { t_Form FormPP=Perevod.word_param( Ant2[i3],-1,0 ); t_Param1List *Param =&Grammar[i_part].From.Param ; for( i4=0 ; i4<Param->j ; i4++ ) if( Param->list[i4].Dir==0 ) FormPP.value[i4]=Form[i2].value[i4] ; N1=Perevod.get_n_perevod( Ant2[i3] ); add_from( i_word, i_part, FormPP, Ant2[i3], N1 ); } From[i_word].exist=1 ; } } // ---------- найти в главном словаре ----------------- N=Perevod.part( Str, part ); for( i2=0 ; i2<N ; i2++ ) { t_Form FormPP ; Perevod.find( Str, part[i2], &Ant2 ); if( Ant2.j<=0 ) continue ; for( i3=0 ; i3<Ant2.j ; i3++ ) { VV=variants( i_word,part[i2] ); for( i4=0 ; i4<VV->Variant.j ; i4++ ) if( Ant2[i3]==VV->Variant[i4].i_slowo ) goto Now_Exist ; FormPP =Perevod.word_param( Ant2[i3],-1,0 ) ; N1=Perevod.get_n_perevod( Ant2[i3] ); add_from( i_word, part[i2], FormPP, Ant2[i3], N1 ); Now_Exist : From[i_word].exist=1 ; } } // ---------- найти в словаре constant ----------------- DicConst.find( Str, -1, &Ant2 ); if( 0<Ant2.j ) From[i_word].exist=1 ; } // ------ проверить на дикое количество неизвестных слов ----- for( i=N=0 ; i<From.j ; i++ ) if( From[i].exist==0 ) N++ ; if( 6<N || From.j/2<N ) return 1 ; return 0 ; } /**************************************************************************/ // добавить вариант трансляции слова // i_word - индекс слова в фразе // i_struct - часть речи // Form - форма и грамматические параметры слова // i_slowo - индекс слова в словаре переводов // i_slowo1 - номер перевода /**************************************************************************/ void t_Core :: add_from( short i_word, long i_struct, t_Form Form, long i_slowo, short n_slowo ) { t_Variants *VV ; t_rStruct S ; t_rWord W ; VV=variants( i_word, i_struct ) ; S.type = Grammar[i_struct].From.type ; S.i_word = i_word ; S.i_last_word = i_word+1 ; S.i_struct = i_struct ; S.r_word = rWord.j ; S.Form = Form ; S.i_slowo = i_slowo ; S.i_slowo1 = 0 ; S.i_meaning = -1 ; VV->Variant.add(S); W.type = Grammar[i_struct].From.type ; W.i_struct = i_struct ; W.i_variant = VV->Variant.j-1 ; W.i_word = i_word ; W.i_last_word = i_word+1 ; W.index = 0 ; W.i_slowo = i_slowo ; W.i_slowo1 = 0 ; W.n_slowo = n_slowo ; rWord.add( W ); if( 0<=i_slowo ) set_meaning( &VV->Variant[VV->Variant.j-1], Perevod.word_src1(i_slowo) ); } /**************************************************************************/ // разбиение фразы на составные части (рекурсивная) // /**************************************************************************/ void t_Core :: universe( short i_word, long i_struct ) { t_Variants *VV0,*VV1 ; t_rStruct V1,*pV ; t_Tree N,*pN1 ; t_rWord R,*pR ; t_Struct *SS ; t_Word *W ; e_Type t ; long i,i1,z,i1_struct ; char q ; SS=&Grammar[i_struct].From ; if( n_word<i_word ) return ; VV0=variants( i_word,i_struct ) ; if( VV0->absend==1 ) return ; // если такую структуру нельзя построить if( 0<VV0->Variant.j ) return ; // если уже построена if( SS->type==TSTRUCT1 || SS->type==TSTRUCT2 || SS->type==TUNORDER1 || SS->type==TUNORDER2 ) { // ---- структура из словаря ----- Perevod.s_universe( i_word, i_struct ); return ; } if( SS->type==TSTRUCT || SS->type==TUNORDER ) { t_TreeList Node ; make_node( Node, i_word, i_struct ); // ---- собирание вариантов ---------------- for( i=0 ; i<Node.j ; i++ ) { if( Node[i].down!=(-10) ) continue ; V1.i_word =i_word ; V1.i_last_word=Node[i].i_last_word ; V1.i_struct =i_struct ; V1.r_word =rWord.j ; V1.i_slowo =-1 ; VV0->Variant.add(V1); for( i1=0 ; i1<SS->Word.j ; i1++ ) rWord.add(R); z=i ; for( i1=SS->Word.j-1 ; 0<=i1 ; i1-- ) { pN1=&Node[z] ; pR =&rWord[V1.r_word+pN1->index] ; pR->type =pN1->type ; pR->i_word =pN1->i_word ; pR->i_last_word=pN1->i_last_word ; pR->i_struct =pN1->i_struct ; pR->i_variant =pN1->i_variant ; pR->index =pN1->index ; pR->i_slowo =pN1->i_slowo ; pR->i_slowo1 =pN1->i_slowo1 ; pR->n_slowo =pN1->n_slowo ; z=Node[z].up ; } // ------ сформировать meaning ---------- { char Str[200]="" ; for( i1=0 ; i1<SS->Word.j ; i1++ ) { if( 0!=SS->Word[i1].meaning_use ) { if( Str[0]!=0 ) strcat( Str," " ); strcat( Str,get_meaning( variant(rWord[V1.r_word+i1]) ) ); } } set_meaning( &VV0->Variant[VV0->Variant.j-1], Str ); } real_param_up( &VV0->Variant[VV0->Variant.j-1] ); } if( VV0->Variant.j==0 ) VV0->absend=1 ; } if( IF_SELECT( SS->type ) ) { for( i=0 ; i<SS->Word.j ; i++ ) { // ------- цикл по составляющим выбора --------- t =SS->Word[i].type ; i1_struct=SS->Word[i].i_struct ; if( t==TCONST || t==TWORD0 ) { if( -1==(q=atom( i_word,SS->Word[i] )) ) continue ; if( SS->type==TSELECT2 && 1==select2_exist( i_word, i_struct, i_word+q ) ) continue ; V1.i_word = i_word ; V1.i_last_word= i_word+q ; V1.i_struct = i_struct ; V1.r_word = rWord.j ; VV0->Variant.add(V1); R.i_struct = i1_struct ; R.i_variant = VV0->Variant.j-1 ; R.i_word = i_word ; R.i_last_word = i_word+q ; R.index = i ; rWord.add( R ); continue ; } if( t==TWORD || t==TCONST1 ) { if( -1==atom( i_word,SS->Word[i] ) ) continue ; } else { universe( i_word, i1_struct ); } VV1=variants( i_word,i1_struct ) ; for( i1=0 ; i1<VV1->Variant.j ; i1++ ) { // ---- цикл по вариантам каждой составляющей ----- W =&SS->Word[i] ; pV=&VV1->Variant[i1] ; if( 0!=compare_param( &W->Param, &pV->Form ) ) continue ; if( SS->type==TSELECT2 && 1==select2_exist( i_word, i_struct, VV1->Variant[i1].i_last_word ) ) continue ; V1 =VV1->Variant[i1] ; V1.i_struct =i_struct ; V1.r_word =rWord.j ; V1.i_meaning =-1 ; VV0->Variant.add(V1); R.type =VV1->Variant[i1].type ; R.i_struct =SS->Word[i].i_struct ; R.i_variant =i1 ; R.i_word =V1.i_word ; R.i_last_word=V1.i_last_word ; R.index =i ; R.i_slowo =V1.i_slowo ; R.i_slowo1 =V1.i_slowo1 ; rWord.add( R ); if( 0!=SS->Word[i].meaning_use ) { char *Str ; Str=get_meaning( variant(rWord[V1.r_word]) ); // Free memory reading !!! set_meaning( &VV0->Variant[VV0->Variant.j-1], Str ); } real_param_up( &VV0->Variant[VV0->Variant.j-1] ); } } // ---- исключение "просто слов" если у нас есть "устойчивое выражение" /* не всегда так можно безнаказанно делать, иногда теряются нужные варианты char f=0 ; long j,n_word ; for( i=0 ; i<VV0->Variant.j ; i++ ) { t=rWord[VV0->Variant[i].r_word].type ; n_word=VV0->Variant[i].i_last_word-VV0->Variant[i].i_word ; if( (t==TSTRUCT1 || t==TSTRUCT2 || t==TSELECT1) && 1<n_word ) { f=1 ; break ; } } if( f==1 ) { for( i=j=0 ; i<VV0->Variant.j ; i++ ) { t=rWord[VV0->Variant[i].r_word].type ; n_word=VV0->Variant[i].i_last_word-VV0->Variant[i].i_word ; if( (t==TSTRUCT1 || t==TSTRUCT2 || t==TSELECT1) && 1<n_word ) { VV0->Variant[j++]=VV0->Variant[i] ; } } VV0->Variant.j=j ; } */ if( VV0->Variant.j==0 ) VV0->absend=1 ; } } /***************************************************************************/ // построение дерева вариантов // Node - дерево вариантов перевода фразы // Node[i].select используется как счетчик уровня вершины /***************************************************************************/ void t_Core :: make_node( t_TreeList &Node, short i_word, long i_struct ) { t_Variants *VV1 ; t_rStruct *pV ; t_Tree N,*pN ; t_Struct *SS ; t_Word *W ; e_Type t ; char *use=NULL ; long i,i1,i2,z,index,i1_word,i1_struct ; SS=&Grammar[i_struct].From ; Node.j=0 ; N.i_struct =i_struct ; N.i_last_word=i_word ; N.select =0 ; Node.add(N); if( SS->type==TUNORDER ) use=(char *)Calloc( SS->Word.j, sizeof(char) ); for( i=0 ; i<Node.j ; i++ ) { if( 256000<Node.j ) { print_tree( Node, "NodeError.txt" ); throw(-1); } pN=&Node[i] ; if( pN->select==SS->Word.j ) { pN->down=-10 ; continue ; } i1_word=pN->i_last_word ; if( n_word<i1_word ) continue ; if( SS->type==TUNORDER ) { // ----------- заполнить used ----------------- for( i2=0 ; i2<SS->Word.j ; i2++ ) use[i2]=0 ; z=i ; while( z!=0 ) { use[Node[z].index]=1 ; z=Node[z].up ; } } for( i2=0 ; i2<SS->Word.j ; i2++ ) { if( SS->type==TSTRUCT && i2!=pN->index+1 ) continue ; if( SS->type==TUNORDER && use[i2]!=0 ) continue ; index=i2 ; // ----------- основной цикл ----------------- t=SS->Word[index].type ; i1_struct=SS->Word[index].i_struct ; N.type = t ; N.up = i ; N.i_word = i1_word ; N.index = index ; N.i_struct = i1_struct ; N.select = pN->select+1 ; if( t==TWORD0 ) { N.i_variant = 0 ; N.i_last_word= i1_word ; Node.add(N); break ; } if( t==TCONST || t==TCONST1 ) { if( -1==atom( i1_word,SS->Word[index] ) ) continue ; N.i_variant = 0 ; N.i_last_word= i1_word+1 ; Node.add(N); break ; } if( t==TWORD ) { if( -1==atom( i1_word,SS->Word[index] ) ) continue ; } else { universe( i1_word, i1_struct ); } VV1=variants( i1_word,i1_struct ) ; for( i1=0 ; i1<VV1->Variant.j ; i1++ ) { W =&SS->Word[index] ; pV=&VV1->Variant[i1] ; if( 0!=compare_param( &W->Param, &pV->Form ) ) continue ; if( W->literal[0]!=0 ) // сравнить литералы { char *Str=Core.get_meaning( pV ) ; if( 0!=Strcmp( W->literal,Str) ) continue ; } N.type = Grammar[N.i_struct].From.type ; N.i_variant = i1 ; N.i_last_word= pV->i_last_word ; N.i_slowo = pV->i_slowo ; N.i_slowo1 = pV->i_slowo1 ; Node.add(N); } } } Free(use); } /***************************************************************************/ // попробовать подходит ли атомарный элемент фразы // return -1 - не подходит, 0 - пустой выбор, 1 - подходит /***************************************************************************/ char t_Core :: atom( short i_word, t_Word &Word ) { // ---------------- если это пустой выбор -------- if( Word.type==TWORD0 ) return 0 ; if( From.j<=i_word ) return -1 ; if( Word.type==TCONST ) { // ---------------- если это константное слово ---------- if( 0==Strcmp( From[i_word].Str,Word.literal ) ) return 1 ; return -1 ; } if( Word.type==TWORD ) { // ---------------- если это слово ---------- t_Variants *VV=variants( i_word,Word.i_struct ) ; if( VV->absend==1 ) return -1 ; if( 0<VV->Variant.j ) return 1 ; if( From[i_word].exist==0 ) { // ----слово отсутствует в словаре - сделать вид, что оно подходит -- add_from( i_word, Word.i_struct, t_Form(), -1, -1 ); return 1 ; } if( Word.literal[0]!=0 ) { // ---- если это литерал, найти начальную форму слова и // ---- проверить на совпадение---- char Str1[100] ; word_source( Word.i_struct, From[i_word].Str, Str1, FROM ); if( 0==Strcmp(Str1,Word.literal ) ) return 1 ; else return -1 ; } } return -1 ; } /***************************************************************************/ // сравнить требуемые параметры слова с фактическими /***************************************************************************/ char t_Core :: Compare_Param( t_rStruct *V, t_Word *Word ) { if( Word->type==TWORD && 0!=compare_param( &Word->Param, &V->Form ) ) return 1 ; return 0 ; } /***************************************************************************/ char t_Core :: select2_exist( short i_word, short i_struct, short i_last_word ) { long i ; t_Variants *VV=variants( i_word,i_struct ) ; for( i=0 ; i<VV->Variant.j ; i++ ) if( VV->Variant[i].i_last_word==i_last_word ) return 1 ; return 0 ; } /***************************************************************************/ // передать параметры вверх на один шаг при построении universe // V - конструкция, для которой определяются параметры на основе ее сыновей /***************************************************************************/ void t_Core :: real_param_up( t_rStruct *V ) { long i,ii ; t_rStruct *V1,*V2 ; t_Struct *SS ; t_RelationList1 RR ; t_Relation R ; if( V->i_struct<0 ) return ; SS=&Grammar[V->i_struct].From ; if( SS->type==TWORD0 || SS->type==TCONST ) return ; if( SS->type==TSTRUCT2 ) RR=Perevod.get_relation( V->i_slowo, -1 ); else RR=Grammar[V->i_struct].From.Relation ; if( IF_STRUCT( SS->type ) ) { for( i=0 ; i<RR.j ; i++ ) { R=RR.list[i] ; if( R.s1==0 ) V1= V ; else V1=variant( rWord[V->r_word+R.s1-1] ) ; if( R.s2==0 ) V2= V ; else V2=variant( rWord[V->r_word+R.s2-1] ) ; V2->Form.value[R.p2] = V1->Form.value[R.p1] ; } } if( IF_SELECT( SS->type ) ) { ii=rWord[V->r_word].index+1 ; for( i=0 ; i<RR.j ; i++ ) { R=RR.list[i] ; if( R.s1!=ii ) continue ; if( R.s1==0 ) V1=V ; else V1=variant( rWord[V->r_word] ) ; if( R.s2==0 ) V2=V ; else V2=variant( rWord[V->r_word] ) ; V2->Form.value[R.p2] = V1->Form.value[R.p1] ; } } } /**************************************************************************/ // первая попавшаяся часть речи, которой может быть это слово /**************************************************************************/ long t_Core :: struct_of_word( short i_word ) { long i ; e_Type t ; t_Variants *VV ; for( i=0 ; i<Core.n_struct ; i++ ) { t=Grammar[i].From.type ; if( t!=TWORD && t!=TSTRUCT1 && t!=TSTRUCT2 ) continue ; VV=Core.variants( i_word, i ); if( 0<VV->Variant.j ) return i ; } return -1 ; } /***************************************************************************/ // дать варианты перевода слова i_word как структуры i_struct /***************************************************************************/ t_Variants * t_Core :: variants( short i_word, long i_struct ) { if( i_word<0 || n_word<i_word || i_struct<0 ) { printf("\n t_Core :: Variants := Error index !!!"); exit(-1) ; } return &Variants[ n_struct*i_word+i_struct ] ; } /***************************************************************************/ // дать один вариант перевода /***************************************************************************/ t_rStruct * t_Core :: variant( short i_word, long i_struct, long i_variant ) { if( i_word<0 || n_word<i_word || i_struct<0 ) { printf("\n t_Core :: variant := Error index !!!"); exit(-1) ; } if( Variants[ n_struct*i_word+i_struct ].Variant.j<=i_variant ) { printf("\n t_Core :: variant := Error i_variant !!!"); exit(-1) ; } return &Variants[ n_struct*i_word+i_struct ].Variant[i_variant] ; } /***************************************************************************/ // дать один вариант перевода /***************************************************************************/ t_rStruct * t_Core :: variant( t_rWord R ) { if( R.i_word<0 || n_word<R.i_word || R.i_struct<0 ) { printf("\n t_Core :: variant := Error index !!!"); exit(-1) ; } if( Variants[ n_struct*R.i_word+R.i_struct ].Variant.j<=R.i_variant ) { printf("\n t_Core :: variant := Error i_variant !!!"); exit(-1) ; } return &Variants[ n_struct*R.i_word+R.i_struct ].Variant[R.i_variant] ; } /***************************************************************************/ // установить смысл варианту перевода /***************************************************************************/ void t_Core :: set_meaning( t_rStruct *V, char *Str ) { long L,LL ; if( 0<=V->i_meaning ) { printf("\n t_Core :: meaning != NULL !!!"); exit(-1) ; } L=strlen(Str); if( L==0 ) return ; if( l_Meaning<=j_Meaning+L+1 ) { LL=l_Meaning+max(l_Meaning>>2,L+1) ; Meaning=(char *)Realloc( Meaning,LL ); l_Meaning=LL ; } V->i_meaning=j_Meaning ; strcpy( Meaning+j_Meaning, Str ); j_Meaning+=L+1 ; } /***************************************************************************/ // прочесть смысл варианта перевода /***************************************************************************/ char * t_Core :: get_meaning( t_rStruct *V ) { static char *s="" ; static char s1[1000] ; if( V->i_meaning<0 ) return s ; Strcpy( s1,Meaning+V->i_meaning,1000 ); return s1 ; } /***************************************************************************/ t_Antwort & t_Core :: antwort( ) { return Antwort ; } /***************************************************************************/ long t_Core :: n_antwort( void ) { return Variants[0+i_main_struct].Variant.j ; } /***************************************************************************/ char t_Core :: sign( void ) { return Sign ; } /***************************************************************************/ char t_Core :: f_full( void ) { return f_Full ; } /***************************************************************************/ t_ItemList & t_Core :: from( void ) { return From ; } /***************************************************************************/ t_ItemList & t_Core :: tag( void ) { return Tag ; } /***************************************************************************/ t_rWord & t_Core :: rword( long i ) { return rWord[i] ; } /***************************************************************************/ short t_Core :: fn_word( void ) { return n_word ; } /***************************************************************************/ e_Result t_Core :: result( void ) { return Result ; } /***************************************************************************/ char * t_Core :: sou( void ) { return Sou ; } /***************************************************************************/ // сделать вариант ответа // i - индекс варианта ответа /***************************************************************************/ void t_Antwort :: make( short i_word, short i_struct, long i_variant, t_Form Form ) { short L ; t_rStruct *pV ; Str[0]=0 ; Tree1.j=Tree2.j=aWord.j=0 ; pV=Core.variant( i_word ,i_struct, i_variant ); make_sou( i_word, i_struct, i_variant ); make_dst(); make_to( 0 ); if( 0<Tree2.j ) Tree2[0].Form=Form ; param_from(); param_transmit(); param_to( ); if( pV->i_last_word < Core.from().j ) strcpy( Str,"#фиг# " ); insert_tag(); print_antwort( 0,1 ); post_proc( ); if( i_struct==i_main_struct && pV->i_last_word < Core.from().j ) { strcat( Str,"## " ); translate_simple( pV->i_last_word ); } L=strlen(Str); if( 0<L ) Str[L-1]=Core.sign() ; else { Str[0]=Core.sign() ; Str[1]=0 ; } } /***************************************************************************/ // построение дерева разбора (Tree1) // i_Variant - индекс варианта ответа /***************************************************************************/ void t_Antwort :: make_sou( short i_word, short i_struct, long i_variant ) { long i,i1 ; e_Type t ; t_Tree T,*pT ; t_Struct *SS ; t_rStruct *pS ; t_sStruct *sS ; t_rWord W ; pS = Core.variant( i_word, i_struct, i_variant ) ; W = Core.rword( pS->r_word ) ; // -------- внести в дерево первый элемент --------------- T.type = Grammar[i_struct].From.type ; T.i_word = i_word ; T.i_last_word = Core.from().j ; T.i_struct = i_struct ; T.i_variant = i_variant ; T.select = W.index ; T.i_slowo = W.i_slowo ; Tree1.j=0 ; Tree1.add(T); // -------- внести все последующие ----------------------- for( i=0 ; i<Tree1.j ; i++ ) { pT=&Tree1[i] ; pT->down=Tree1.j ; t=pT->type ; if( t==TWORD || t==TCONST || t==TCONST1 || t==TWORD0 ) continue ; pS=Core.variant( pT->i_word, pT->i_struct, pT->i_variant ) ; SS=&Grammar[pT->i_struct].From ; if( IF_STRUCT( t ) || t==TUNORDER || t==TUNORDER1 ) { if( t==TSTRUCT || t==TSTRUCT1 || t==TUNORDER || t==TUNORDER1 ) { // ------ нормальная структура --------- pT->i_slowo = pS->i_slowo ; Tree1[i].n_down =SS->Word.j ; for( i1=0 ; i1<SS->Word.j ; i1++ ) { set_tree( &T, pS, i1 ); T.up = i ; Tree1.add(T); } } if( t==TSTRUCT2 ) { // ------ структура из словаря ------ sS=Perevod.get_from( pS->i_slowo ); pT->i_slowo = pS->i_slowo ; pT->n_down = sS->n_Word ; for( i1=0 ; i1<sS->n_Word ; i1++ ) { set_tree( &T, pS, i1 ); T.up = i ; Tree1.add(T); } } } if( IF_SELECT( t ) ) { Tree1[i].n_down = 1 ; set_tree( &T, pS, 0 ); T.up = i ; Tree1[i].select =Core.rword( pS->r_word ).index ; Tree1.add(T); } } } /**************************************************************************/ // присвоить должные значения полям t_Tree, нужные для make_sou() // T - элемент дерева, который присваивается // pS - структура, которая соответствует элементу Tree1[T->up] // i - номер каким сыном является T по отношению к Tree1[T->up] /**************************************************************************/ void t_Antwort :: set_tree( t_Tree *T, t_rStruct *pS, long i ) { t_rWord W = Core.rword( pS->r_word+i ) ; t_Struct *SS = &Grammar[pS->i_struct].From ; if( SS->type==TSTRUCT || SS->type==TSTRUCT1 ) T->type = SS->Word[i].type ; if( SS->type==TUNORDER || SS->type==TUNORDER1 ) T->type = W.type ; if( SS->type==TSELECT || SS->type==TSELECT1 || SS->type==TSELECT2 ) T->type = SS->Word[W.index].type ; if( SS->type==TSTRUCT2 ) T->type = W.type ; if( SS->type==TWORD ) { printf("\n Error"); throw(-1); } T->down =-1 ; T->n_down = 0 ; T->i_word = W.i_word ; T->i_last_word = W.i_last_word ; T->i_struct = W.i_struct ; T->i_variant = W.i_variant ; T->Form = pS->Form ; T->link =-1 ; T->select =-1 ; T->i_slowo = W.i_slowo ; T->i_slowo1 = W.i_slowo1 ; T->n_slowo = W.n_slowo ; } /**************************************************************************/ // Построение дерева приемников по дереву источников // /**************************************************************************/ void t_Antwort :: make_dst( void ) { long i,i1,i2,is ; t_Trans *Tr ; t_Tree TT,*T2 ; t_sStruct *S1,*S2 ; e_Type t ; Tree2.j=0 ; TT.i_struct=is=Tree1[0].i_struct ; if( 0<=is && (Grammar[is].From.type==TSTRUCT1 || Grammar[is].From.type==TSTRUCT2 ) ) { S2=Perevod.get_to( Tree1[0].i_slowo,Tree1[0].i_slowo1 ); TT.i_struct=S2->i_struct ; } TT.up=-1 ; TT.type=Tree1[0].type ; TT.down=1 ; TT.n_down=0 ; TT.select=0 ; TT.i_word=0 ; TT.link =0 ; TT.Form.init(); Tree2.add( TT ); Tree1[0].link=0 ; for( i=0 ; i<Tree2.j ; i++ ) { T2=&Tree2[i] ; t=T2->type ; if( t==TWORD0 || t==TWORD || t==TCONST || t==TCONST1 ) continue ; Tr=&Grammar[ T2->i_struct ] ; T2->down =Tree2.j ; if( t==TSTRUCT2 || t==TSTRUCT1 ) { i2=Tree1[T2->link].i_slowo ; S1=Perevod.get_from( i2 ); S2=Perevod.get_to( i2,Tree1[T2->link].i_slowo1 ); T2->n_down =S2->n_Word ; T2->i_slowo =i2 ; T2->i_slowo1 =Tree1[T2->link].i_slowo1 ; T2->i_variant=Tree1[T2->link].i_variant ; for( i2=0 ; i2<S2->n_Word ; i2++ ) make_dst2( i, i2, S1, S2 ); } if( t==TSTRUCT || t==TUNORDER ) { T2->n_down =Tr->To.Word.j ; if( 0<=T2->link ) { T2->i_slowo =Tree1[T2->link].i_slowo ; T2->i_slowo1 =Tree1[T2->link].i_slowo1 ; T2->i_variant=Tree1[T2->link].i_variant ; } for( i2=0 ; i2<Tr->To.Word.j ; i2++ ) make_dst1( i, i2, Tr ); } if( t==TSELECT || t==TSELECT2 ) { T2->n_down =1 ; if( 0<=T2->link ) { T2->i_slowo =Tree1[T2->link].i_slowo ; T2->i_slowo1 =Tree1[T2->link].i_slowo1 ; T2->i_variant=Tree1[T2->link].i_variant ; } make_dst1( i, Tree1[T2->link].select, Tr ); } if( t==TSELECT1 ) { i1=T2->i_struct ; i2=Tree1[T2->link].i_slowo ; T2->n_down =1 ; T2->i_slowo =i2 ; T2->i_slowo1 =Tree1[T2->link].i_slowo1 ; T2->i_variant=Tree1[T2->link].i_variant ; T2->select=find_enum_select( TO, i1, i2 ); make_dst1( i, T2->select, Tr ); } } } /**************************************************************************/ // добавление одного элемента в дерево приемников // up - индекс родителя, к которому добавляется новый потомок // Tr - шаблон, соответствующий Tree2[up] // i2 - индекс слова в структуре-приемнике /**************************************************************************/ void t_Antwort :: make_dst1( long up, long i2, t_Trans *Tr ) { t_Tree TT,*pT ; t_Struct *S2 ; t_sStruct *sS ; long i_link,i3 ; e_Type type ; S2=&Tr->To ; type=S2->Word[i2].type ; TT.i_struct=S2->Word[i2].i_struct ; TT.up=up ; i_link=Tree2[up].link ; // ------ проставить i_link -------------- TT.link=-1 ; if( (Tree2[up].type==TSTRUCT || Tree2[up].type==TUNORDER ) && 0<=Tr->Relation2[i2] ) TT.link=Tree1[i_link].down+Tr->Relation2[i2] ; if( Tree2[up].type==TSTRUCT1 ) { sS=Perevod.get_to( Tree2[up].i_slowo ); //if( sS->Word[i2].str[0]==0 ) // ----- слово не константа if( 0<=sS->Word[i2].i_struct ) { pT=&Tree1[Tree2[up].link] ; for( i3=0 ; i3<pT->n_down ; i3++ ) if( Tree1[pT->down+i3].i_struct==TT.i_struct ) TT.link=pT->down+i3 ; } } if( IF_SELECT( Tree2[up].type ) ) TT.link=Tree1[i_link].down ; if( 0<=TT.link ) Tree1[TT.link].link=Tree2.j ; // ------ проставить все остальное --------------------------- if( type==TCONST || type==TCONST1 || type==TWORD0 ) { TT.type =type ; TT.select=0 ; } else { TT.type =Grammar[TT.i_struct].To.type ; if( 0<=TT.link ) { TT.select =Tree1[TT.link].select ; TT.i_slowo =Tree1[TT.link].i_slowo ; TT.i_slowo1=Tree1[TT.link].i_slowo1 ; } } TT.down=0 ; TT.n_down=0 ; TT.i_word=-1 ; TT.index=i2 ; // ------ прописать параметры -------------- for( i3=0 ; i3<S2->Word[i2].Param.j ; i3++ ) TT.Form.value[i3]=S2->Word[i2].Param[i3].value ; Tree2.add( TT ); } /**************************************************************************/ // добавление одного элемента в дерево приемников // если родитель - произвольная структура (TSTRUCT2) // up - индекс родителя, к которому добавляется новый потомок // i2 - индекс слова в структуре-приемнике // S1 - структура в языке оригинала // S2 - структура в языке перевода /**************************************************************************/ void t_Antwort :: make_dst2( long up, long i2, t_sStruct *S1, t_sStruct *S2 ) { t_Tree TT ; long z,i3 ; TT.up=up ; TT.i_struct=S2->Word[i2].i_struct ; if( TT.i_struct<0 ) { TT.type=TCONST ; TT.link=-1 ; } else { TT.type=Grammar[TT.i_struct].To.type ; for( i3=0,z=-1 ; i3<S1->n_Word ; i3++ ) if( S1->Word[i3].i_struct==S2->Word[i2].i_struct && S1->Word[i3].order ==S2->Word[i2].order ) { z=i3 ; break ; } if( z<0 ) TT.link=-1 ; else TT.link= Tree1[Tree2[up].link].down+z ; } if( 0<=TT.link ) { Tree1[TT.link].link=Tree2.j ; TT.select =Tree1[TT.link].select ; TT.i_slowo =Tree1[TT.link].i_slowo ; TT.i_slowo1=Tree1[TT.link].i_slowo1 ; } TT.down =0 ; TT.n_down=0 ; TT.i_word=-1 ; TT.index =i2 ; TT.Form =S2->Word[i2].Param ; Tree2.add( TT ); } /***************************************************************************/ // задание строковых значений дереву приемников /***************************************************************************/ void t_Antwort :: make_to( long i_tree ) { long i ; t_Tree *T,*T1 ; t_Struct *SS ; t_sStruct *S ; char *Str2,Str1[100] ; T=&Tree2[i_tree] ; if( T->type==TWORD0 ) return ; if( 0<T->i_struct ) SS=&Grammar[T->i_struct].To ; if( T->type==TWORD ) { if( T->link<0 ) return ; if( T->Str1[0]!=0 ) return ; T1=&Tree1[T->link] ; word_source( T1->i_struct, Core.from()[T1->i_word].Str, Str1, FROM ); Str2=Perevod.translate_word_i( Str1, T1->i_slowo, T1->i_slowo1 ); if( Str2!=NULL ) Strcpy( T->Str1, Str2, LWORD ); else Strcpy( T->Str1, Str1, LWORD ); } if( T->type==TCONST || T->type==TCONST1 ) { t_Struct *S1=&Grammar[Tree2[T->up].i_struct].To ; Strcpy( T->Str1, S1->Word[T->index].literal, LWORD ); } if( IF_SELECT( T->type ) ) { if( SS->Word[T->select].literal[0]!=0 ) Strcpy( Tree2[T->down].Str1, SS->Word[T->select].literal, LWORD ); if( SS->Word[T->select].meaning_use!=0 && T->Str1[0]!=0 ) Strcpy( Tree2[T->down].Str1, T->Str1, LWORD ); make_to( T->down ); } if( IF_STRUCT( T->type ) || IF_UNORDER( T->type ) ) { if( T->type==TSTRUCT || T->type==TUNORDER ) { for( i=0 ; i<T->n_down ; i++ ) { T1=&Tree2[T->down+i] ; if( SS->Word[i].literal[0]!=0 ) Strcpy( T1->Str1, SS->Word[i].literal, LWORD ); if( SS->Word[i].meaning_use!=0 && T->Str1[0]!=0 ) Strcpy( T1->Str1, T->Str1, LWORD ); make_to( T->down+i ); } } else { // ---- структура из словаря -------- S=Perevod.get_to( T->i_slowo,T->i_slowo1 ); for( i=0 ; i<S->n_Word; i++ ) { T1=&Tree2[T->down+i] ; if( T1->type==TWORD ) { if( S->Word[i].str[0]==0 ) { make_to( T->down+i ); } else { word_source( S->Word[i].i_struct, S->Word[i].str, Str1, FROM ); Strcpy( T1->Str1, Str1, LWORD ); } } if( T1->type==TCONST || T1->type==TCONST1 ) Strcpy( T1->Str1, S->Word[i].str, LWORD ); if( IF_CONSTR( T1->type ) ) { if( S->Word[i].str[0]!=0 ) Strcpy( T1->Str1, S->Word[i].str, LWORD ); make_to( T->down+i ); } } } } } /***************************************************************************/ // Пословный перевод, если разбор не удался // Begin - на каком слове надорвался штатный алгоритм /***************************************************************************/ char * t_Antwort :: translate_simple( short Begin ) { short i_word,i_slowar,i_struct,N,z_begin ; t_Slowo2 *Slowo ; t_Form Form1[20] ; char *Str0,*Str1 ; long Ant1[20] ; t_ItemList &From=Core.from(); i_slowar=i_struct=-1 ; z_begin=strlen( Str ); if( Begin<0 ) Begin=0 ; for( i_word=Begin ; i_word<From.j ; i_word++ ) { if( From[i_word].exist ) { i_struct=Core.struct_of_word( i_word ) ; if( 0<=i_struct ) i_slowar=i_FormatF[i_struct] ; } if( 0<=i_slowar ) { Slowo=&SlowoF[ i_slowar ]; N=Slowo->quest( From[i_word].Str, Ant1, Form1 ); } else N=0 ; if( 0<N ) Str1=Slowo->normal(Ant1[0]) ; else Str1=From[i_word].Str ; Str0=Perevod.translate_word_s( Str1, i_struct ); strcat( Str,Str0 ); strcat( Str," " ); } strcat( Str,"." ); return Str+z_begin ; } /***************************************************************************/ /* вычислить параметры структур на основании сыновей (в источнике) */ /***************************************************************************/ void t_Antwort :: param_from( void ) { long i,i1 ; t_Tree *F,*F1,*F2 ; t_rStruct *V ; t_RelationList1 RR ; t_Relation R ; for( i=Tree1.j-1 ; 0<=i ; i-- ) { F=&Tree1[i] ; if( F->type==TWORD0 || F->type==TCONST || F->type==TCONST1 ) continue ; if( F->type==TSTRUCT2 ) RR=Perevod.get_relation( F->i_slowo, -1 ); else { if( F->i_struct<0 || i_main_struct<F->i_struct ) printf("\n ABR !!!"); RR=Grammar[F->i_struct].From.Relation ; } if( F->type==TWORD ) { // -------- по хорошему это надо через Grammar делать ---- V=Core.variant( F->i_word,F->i_struct,F->i_variant ); F->Form=V->Form ; continue ; } for( i1=0 ; i1<RR.j ; i1++ ) { R=RR.list[i1] ; if( IF_SELECT( F->type ) && (R.s1-1)!=F->select ) continue ; F1=part_of_struct( Tree1, i, R.s1 ); F2=part_of_struct( Tree1, i, R.s2 ); F2->Form.value[R.p2] = F1->Form.value[R.p1] ; } } } /**************************************************************************/ // Передача параметров источник - приемник // /**************************************************************************/ void t_Antwort :: param_transmit( void ) { short I,i,i1,i2,i3 ; t_Tree *Dst,*Sou,*T1 ; t_Trans *Trans ; t_Table *TT ; for( I=0 ; I<Tree2.j ; I++ ) { Dst=&Tree2[I] ; if( Dst->link<0 ) continue ; Sou=&Tree1[Dst->link] ; if( Dst->type==TCONST || Dst->type==TCONST1 ) continue ; if( Dst->type==TWORD0 || Sou->type==TWORD0 ) continue ; Trans=&Grammar[ Dst->i_struct ] ; for( i=0 ; i<Trans->Table.j ; i++ ) { TT=&Trans->Table[i] ; for( i1=0 ; i1<TT->Value.j ; i1+=TT->Size ) { // --------- цикл по строчкам в таблице -------------- for( i2=0 ; i2<TT->In.j ; i2++ ) { // ---------- найти строчку, соответствующую вычисленным // ---------- значениям параметров ------------ i3=TT->In[i2].i1 ; if( TT->In[i2].i2<0 ) // ------- когда параметр - строка @Выбор'а { if( (Sou->select+1)!=TT->Value[i1+i2] ) goto M_Next ; } else { T1=part_of_struct( Tree1, Dst->link, i3 ); if( T1->Form.value[TT->In[i2].i2]!=TT->Value[i1+i2] && 0<=TT->Value[i1+i2] ) goto M_Next ; } } for( i2=0 ; i2<TT->Out.j ; i2++ ) { // ---------- записать параметры в приемник i3=TT->Out[i2].i1 ; T1=part_of_struct( Tree2, I, i3 ); T1->Form.value[TT->Out[i2].i2]=TT->Value[i1+TT->In.j+i2] ; } M_Next: ; } } } } /***************************************************************************/ // Передача параметров в приемнике // /***************************************************************************/ void t_Antwort :: param_to( void ) { long i,i1,i2 ; short v ; t_Tree *T,*T1,*T2 ; t_Struct *SS ; t_sStruct *sS ; t_RelationList1 RR ; t_Relation R ; t_Form Form ; for( i=Tree2.j-1 ; 0<=i ; i-- ) { T=&Tree2[i] ; if( T->type==TSTRUCT1 || T->type==TSTRUCT2 ) T->Form=Perevod.struct_param( T->i_slowo, T->i_slowo1 ); } for( i=Tree2.j-1 ; 0<=i ; i-- ) { // ------------- проход снизу вверх ------------------ T=&Tree2[i] ; if( T->i_struct<0 ) continue ; SS=&Grammar[T->i_struct].To ; if( T->type==TSTRUCT2 ) RR=Perevod.get_relation( T->i_slowo, T->i_slowo1 ); else RR=SS->Relation ; // ------------- вычисление постоянных параметров ---- if( T->type==TWORD ) { if( 0<=T->link ) { // ----- up - нормальная структура ------- Form=Perevod.word_param( T->i_slowo, T->i_slowo1 ,0 ); } else { // ----- up - TSTRUCT1 или TSTRUCT2 ------ t_Tree *T_up=&Tree2[T->up] ; Form=Perevod.word_param( T_up->i_slowo, T_up->i_slowo1 , T->index ); } for( i1=0 ; i1<SS->Param.j ; i1++ ) if( SS->Param[i1].Dir==1 ) T->Form.value[i1]=Form.value[i1] ; } // ------------- передача параметров наверх ---------- for( i1=0 ; i1<RR.j ; i1++ ) { R=RR.list[i1] ; if( R.s2!=0 ) continue ; if( SS->Param[R.p2].Dir!=0 ) continue ; // ---- лишнее условие ? if( IF_SELECT( T->type ) && (R.s1-1)!=T->select ) continue ; T1=part_of_struct( Tree2, i, R.s1 ); T2=part_of_struct( Tree2, i, R.s2 ); T2->Form.value[R.p2] = T1->Form.value[R.p1] ; } } for( i=0 ; i<Tree2.j ; i++ ) { // ------------- проход сверху вниз ---------------- T=&Tree2[i] ; if( T->i_struct<0 ) continue ; SS=&Grammar[T->i_struct].To ; if( T->type==TSTRUCT2 ) RR=Perevod.get_relation( T->i_slowo, T->i_slowo1 ); else RR=SS->Relation ; for( i1=0 ; i1<RR.j ; i1++ ) { R=RR.list[i1] ; if( R.s2==0 ) continue ; if( R.s1==0 ) { // ------- передача параметров от вышестоящей структуры ------- if( SS->Param[R.p1].Dir==0 ) continue ; if( IF_SELECT( T->type ) && (R.s2-1)!=T->select ) continue ; T2=part_of_struct( Tree2, i, R.s2 ); T2->Form.value[R.p2] = T->Form.value[R.p1] ; } else { // ------- передача параметров от соседних структур ------- T1=part_of_struct( Tree2, i, R.s1 ); T2=part_of_struct( Tree2, i, R.s2 ); T2->Form.value[R.p2] = T1->Form.value[R.p1] ; } } // -------- задание константных параметров ---------- if( IF_SELECT( T->type ) ) { // ---------- для выборов ------------ i1=T->select ; for( i2=0 ; i2<SS->Word[i1].Param.j ; i2++ ) { v=SS->Word[i1].Param[i2].value ; if( 0<=v ) { T2=&Tree2[T->down] ; T2->Form.value[i2]=v ; } } } if( T->type==TSTRUCT || T->type==TSTRUCT1 ) { // --------- и для структур ---------- if( T->type==TSTRUCT1 ) sS=Perevod.get_to( T->i_slowo ); for( i1=0 ; i1<SS->Word.j ; i1++ ) { for( i2=0 ; i2<SS->Word[i1].Param.j ; i2++ ) { v=-1 ; if( T->type==TSTRUCT1 ) { if( SS->Word[i1].Param[i2].Dir==1 ) v=sS->Word[i1].Param.value[i2] ; } else v=SS->Word[i1].Param[i2].value ; if( 0<=v ) { T2=&Tree2[T->down+i1] ; T2->Form.value[i2]=v ; } } } } } } /***************************************************************************/ // выдать адрес части(слова) структуры // Tree - дерево // Tree[i_tree] - та самая структура // i_word - индекс части (если i_word==0 возвращается // сама Tree[i_tree]) /***************************************************************************/ t_Tree *part_of_struct( t_TreeList &Tree, long i_tree, short i_word ) { t_Tree *T=&Tree[i_tree] ; if( i_word==0 ) return T ; else { if( IF_SELECT( T->type ) ) return &Tree[T->down] ; else return &Tree[T->down+i_word-1] ; } } /***************************************************************************/ // развешать теги (как сопли) на дерево приемника /***************************************************************************/ void t_Antwort :: insert_tag() { long i,i1,i_word ; e_TagType t ; t_Tree *T ; for( i=0 ; i<Core.tag().j ; i++ ) { t=Core.tag()[i].type ; i_word=Core.tag()[i].i_word ; if( t==P_TAG_LEFT ) { for( i1=0 ; i<Tree2.j ; i1++ ) { T=&Tree2[i1] ; if( IF_WORD(T->type) && 0<=T->link && i_word<=Tree1[T->link].i_word ) { T->left_tag =i ; break ; } } } if( t==P_TAG_RIGHT ) { for( i1=Tree2.j-1 ; 0<=i1 ; i1-- ) { T=&Tree2[i1] ; if( IF_WORD(T->type) && 0<=T->link && Tree1[T->link].i_word<=i_word ) { T->right_tag =i ; break ; } } } } } /***************************************************************************/ // напечатать ответ (рекурсивная) // /***************************************************************************/ # define F_LEFT_TAG if( 0<=T->left_tag ) strcat( Str,Core.tag()[T->left_tag].Str ); # define F_RIGHT_TAG if( 0<=T->right_tag ) strcat( Str,Core.tag()[T->right_tag].Str ); void t_Antwort :: print_antwort( long i_tree, char fword ) { t_Tree *T ; t_Slowo2 *Slowo ; short i ; static short sp=0 ; sp++ ; if( 80<sp ) { printf("\n Стек исчерпался"); exit(-1); } T=&Tree2[i_tree] ; if( T->type==TCONST || T->type==TCONST1 ) { F_LEFT_TAG strcpy( T->Str,T->Str1 ); Strcat( Str,T->Str,LFRASA ); Strcat( Str," ",LFRASA ); add_word( *T,fword ); F_RIGHT_TAG } if( T->type==TWORD ) { F_LEFT_TAG if( 0<=i_FormatT[T->i_struct] ) { Slowo=&SlowoT[ i_FormatT[T->i_struct] ]; Strcpy( T->Str, Slowo->form( T->Str1,&T->Form),LWORD ); } else { strcpy( T->Str, T->Str1 ); } Strcat( Str,T->Str,LFRASA ); Strcat( Str," ",LFRASA ); add_word( *T,fword ); F_RIGHT_TAG } // ---------- заполнить и оттранслировать сыновей -------- if( IF_STRUCT( T->type ) || IF_UNORDER( T->type ) ) { // ---- возможно, что тут еще надо теги вставлять for( i=0 ; i<T->n_down ; i++ ) print_antwort( T->down+i,fword ); if( T->type==TSTRUCT1 || T->type==TSTRUCT2 ) if( 0==Perevod.is_atom(T->i_slowo) ) { F_LEFT_TAG add_word( *T,fword ); F_RIGHT_TAG } } if( IF_SELECT( T->type ) ) { short z_str =strlen( Str ); short z_word=aWord.j ; print_antwort( T->down,fword && (T->type!=TSELECT2 ) ); if( T->type==TSELECT2 && fword ) { add_word( *T,1 ); Strcpy( aWord[z_word].Str,Str+z_str,LWORD ); } } sp-- ; } # undef F_LEFT_TAG # undef F_RIGHT_TAG /***************************************************************************/ void t_Antwort :: add_word( t_Tree &T, char fword ) { t_aWord W,W1 ; t_Tree *T_up ; if( 0<=T.up ) T_up=&Tree2[T.up] ; else return ; if( (T_up->type==TSTRUCT1 || T_up->type==TSTRUCT2) && 0==Perevod.is_atom(T_up->i_slowo) ) return ; if( fword==0 ) return ; W.meaning=W1.meaning=-1 ; if( 0<T.link ) { W.i_word = Tree1[T.link].i_word ; W.i_last_word = Tree1[T.link].i_last_word ; } else { W.i_word = -1 ; W.i_last_word = -1 ; } W.i_struct = T.i_struct ; W.i_slowo = T.i_slowo ; if( 0<=T.i_slowo ) W.n_slowo = Perevod.get_n_perevod( T.i_slowo ); else W.n_slowo = 1 ; W.Form = T.Form ; W.Str[0] = 0 ; if( IF_WORD( T.type ) ) strcpy( W.Str,T.Str1 ); W1.i_word =W.i_word ; W1.i_last_word=W.i_last_word ; // ----- внесение слова, и прикрепленных к нему тегов ---- if( 0<=T.left_tag ) { Strcpy( W1.Str,Core.tag()[T.left_tag].Str,LWORD ); aWord.add( W1 ); } aWord.add( W ); if( 0<=T.right_tag ) { Strcpy( W1.Str,Core.tag()[T.right_tag].Str,LWORD ); aWord.add( W1 ); } } /***************************************************************************/ void t_Antwort :: post_proc( void ) { long i,i1,i2,j ; t_sStruct *S ; t_longList Ant ; char c,Str1[LFRASA] ; c=' ' ; for( i=j=0 ; i<LFRASA && Str[i]!=0 ; i++ ) { if( !(Str[i]!=' ' && c==' ' ) ) goto M_Normal ; Micro.find( Str+i,-1,&Ant ); if( Ant.j<=0 ) goto M_Normal ; // ------ внести новые слова --------------- S=Micro.get_to( Ant[0],0 ); for( i1=0 ; i1<S->n_Word ; i1++ ) { for( i2=0 ; i2<LFRASA && S->Word[i1].str[i2]!=0 ; i2++ ) Str1[j++]=S->Word[i1].str[i2] ; Str1[j++]=' ' ; } // ------ убрать старые слова --------------- S=Micro.get_from( Ant[0] ); i2=0 ; for( ; i<LFRASA && Str[i]!=0 ; i++ ) { if( Str[i]!=' ' && c==' ' ) i2++ ; if( S->n_Word<i2 ) break ; c=Str[i] ; } // возможно здесь i увеличится лишний раз continue ; M_Normal: Str1[j++]=c=Str[i] ; } Str1[j]=0 ; Strcpy( Str,Str1,LFRASA ); } /***************************************************************************/ char * t_Antwort :: str( void ) { return Str ; } /***************************************************************************/ t_aWordList * t_Antwort :: aword( void ) { return &aWord ; } /***************************************************************************/ t_TreeList & t_Antwort :: tree1( void ) { return Tree1 ; } /***************************************************************************/ t_TreeList & t_Antwort :: tree2( void ) { return Tree2 ; } /***************************************************************************/ // найти начальную форму слова // i_struct - часть речи // Word - слово // Source - начальная форма слова /***************************************************************************/ void word_source( short i_struct, char *Word, char *Source, e_Half H ) { t_Slowo2 *Slowo ; long Ant1[20] ; t_Form Form1[20] ; short i_slowar,N ; i_slowar=-1 ; if( H==FROM ) { if( 0<=i_struct ) i_slowar=i_FormatF[i_struct] ; if( 0<=i_slowar ) { Slowo=&SlowoF[ i_slowar ]; N=Slowo->quest( Word, Ant1, Form1 ); if( 0<N ) { strcpy( Source,Slowo->normal(Ant1[0]) ); return ; } } } else { if( 0<=i_struct ) i_slowar=i_FormatT[i_struct] ; if( 0<=i_slowar ) { Slowo=&SlowoT[ i_slowar ]; N=Slowo->quest( Word, Ant1, Form1 ); if( 0<N ) { strcpy( Source,Slowo->normal(Ant1[0]) ); return ; } } } strcpy( Source,Word ); } /**************************************************************************/ // найти в конструкции типа TSELECT1 выбор соответствующий строке словаря // up_struct - номер структуры // i_slowo - номер строки словаря /**************************************************************************/ short find_enum_select( e_Half H, short up_struct, long i_slowo ) { t_Struct *S0 ; t_sStruct *S1 ; short i ; if( H==FROM ) { S0=&Grammar[up_struct].From ; S1=Perevod.get_from( i_slowo ); } else { S0=&Grammar[up_struct].To ; S1=Perevod.get_to( i_slowo ); } for( i=0 ; i<S0->Word.j ; i++ ) if( S0->Word[i].i_struct==S1->i_struct ) return i ; return -1 ; } /**************************************************************************/ // проверить, что данная строка является числом /**************************************************************************/ char is_number( char *Str ) { for( short i=0 ; i<99 && Str[i]!=0 ; i++ ) if( Str[i]<'0' || '9'<Str[i] ) return 0 ; return 1 ; } /**************************************************************************/ // сравнить параметры // Param - что должно быть согласно lang.txt // Form - что есть фактически /**************************************************************************/ char compare_param( t_Param1List *Param, t_Form *Form ) { short i ; for( i=0 ; i<Param->j ; i++ ) { if( Param->list[i].value==-1 ) continue ; if( Form->value[i]==-1 ) continue ; if( Param->list[i].value!=Form->value[i] ) return -1 ; } return 0 ; } /**************************************************************************/ t_Antwort :: t_Antwort( void ) { Str[0]=0 ; } /**************************************************************************/ void t_Antwort :: del( void ) { Tree1.del(); Tree2.del(); aWord.del(); } /***************************************************************************/ t_rWord :: t_rWord( ) { type = TNULL ; i_word =-1 ; i_last_word =-1 ; i_struct =-10; i_variant =-1 ; index =-1 ; i_slowo =-1 ; i_slowo1 = 0 ; n_slowo = 0 ; } /***************************************************************************/ t_rStruct :: t_rStruct( void ) { type = TNULL ; i_word =-1 ; i_last_word =-1 ; i_struct =-10; r_word =-1 ; i_slowo =-1 ; i_meaning =-1 ; Form.init() ; } /***************************************************************************/ t_Tree :: t_Tree( void ) { init( ); } t_Tree :: ~t_Tree( void ) { del( ); } /***************************************************************************/ void t_Tree :: init( void ) { type = TSTRUCT ; up =-1 ; down =-1 ; n_down = 0 ; i_word = 0 ; i_last_word=-1 ; i_struct=0 ; select =-1 ; link =-1 ; index =-1 ; i_slowo =-1 ; i_slowo1= 0 ; left_tag=-1 ; right_tag=-1 ; Form.init(); Str[0]=Str1[0]=0 ; } void t_Tree :: del( void ) { ; } /***************************************************************************/ static void p_type( char *Str, e_Type type ) { char *s1 ; switch( type ) { case TNULL : s1="TNULL" ; break ; case TCONST : s1="TCONST" ; break ; case TCONST1 : s1="TCONST1" ; break ; case TWORD : s1="TWORD" ; break ; case TWORD0 : s1="TWORD1" ; break ; case TSTRUCT : s1="TSTRUCT" ; break ; case TSTRUCT1 : s1="TSTRUCT1" ; break ; case TSTRUCT2 : s1="TSTRUCT2" ; break ; case TSELECT : s1="TSELECT" ; break ; case TSELECT1 : s1="TSELECT1" ; break ; case TSELECT2 : s1="TSELECT2" ; break ; } strcpy( Str,s1 ); } /***************************************************************************/ // вывести дерево вариантов в Файл (для отладки) /***************************************************************************/ void print_tree( t_TreeList &Node, char *FileName ) { long i ; char s2[20] ; FILE *fw ; fw=fopen( FileName,"wb" ); fprintf( fw, "\n i type - up down n_down - iw i_last Name i_var - select link index i_slowo"); for( i=0 ; i<Node.j ; i++ ) { p_type( s2,Node[i].type ); fprintf( fw, "\n %2ld %8s - %2ld %4ld %4ld - %2d %2d %12s %2ld - %4d %4ld %4d %4ld", i, s2, Node[i].up, Node[i].down, Node[i].n_down, Node[i].i_word, Node[i].i_last_word, Grammar[Node[i].i_struct].From.Name, Node[i].i_variant, Node[i].select, Node[i].link, Node[i].index, Node[i].i_slowo ); } fclose( fw ); } /************************************************************************/ void make_token( char *Sou, char *Dst ) { long i,j ; for( i=0 ; Sou[i]==' ' ; i++ ) ; for( j=0 ; Sou[i]!=0 && Sou[i]!=' ' ; i++ ) Dst[j++]=Sou[i] ; Dst[j]=0 ; } /************************************************************************/ DEFINE_LIST_BTYPE( t_aWord,t_aWordList ) DEFINE_LIST_BTYPE( t_rWord,t_rWordList ) DEFINE_LIST_BTYPE( t_rStruct,t_rStructList ) DEFINE_LIST_BTYPE( t_Item, t_ItemList ) DEFINE_LIST_TYPE ( t_Tree, t_TreeList )