Moving transfer tools
[apertium.git] / apertium-multiple-translations / apertium-multiple-translations / TransferMult.C
blob7e9d0a889568b6e6dd697630fb0c85d18af11cc5
1 /*
2  * Copyright (C) 2005 Universitat d'Alacant / Universidad de Alicante
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17  * 02111-1307, USA.
18  */
19 #include <apertium-multiple-translations/TransferMult.H>
20 #include <apertium/TRXReader.H>
21 #include <lttoolbox/Compression.H>
22 #include <lttoolbox/XMLParseUtil.H>
24 #include <cctype>
25 #include <iostream>
26 #include <stack>
28 using namespace std;
30 void
31 TransferMult::copy(TransferMult const &o)
35 void
36 TransferMult::destroy()
38   if(me)
39   {
40     delete me;
41     me = NULL;
42   }
45 TransferMult::TransferMult()
47   me = NULL;
48   isRule = false;
49   defaultAttrs = lu;
50   numwords = 0;
53 TransferMult::~TransferMult()
55   destroy();
58 TransferMult::TransferMult(TransferMult const &o)
60   copy(o);
63 TransferMult &
64 TransferMult::operator =(TransferMult const &o)
66   if(this != &o)
67   {
68     destroy();
69     copy(o);
70   }
71   return *this;
74 string
75 TransferMult::tolower(string const &str) const
77   string result = str;
78   for(unsigned int i = 0, limit = str.size(); i != limit; i++)
79   {
80     result[i] = ::tolower(result[i]);
81   }
83   return result;
87 void 
88 TransferMult::readData(FILE *in)
90   alphabet.read(in);
91   any_char = alphabet(TRXReader::ANY_CHAR);
92   any_tag = alphabet(TRXReader::ANY_TAG);
94   Transducer t;
95   t.read(in);
96   
97   map<int, int> finals;  
98   
99   // finals
100   for(int i = 0, limit = Compression::multibyte_read(in); i != limit; i++)
101   {
102     int key = Compression::multibyte_read(in);
103     finals[key] = Compression::multibyte_read(in);
104   }  
105   
106   me = new MatchExe(t, finals);
108   // attr_items
110   // fixed attr_items
111   attr_items["lem"] = "(([^<]|\"\\<\")+)";
112   attr_items["lemq"] = "(#[ _][^<]+)";
113   attr_items["lemh"] = "(([^<#]|\"\\<\"|\"\\#\")+)";
114   attr_items["whole"] = ".+";
115   attr_items["tags"] = "((<[^>]+>)+)";
116   
117   for(int i = 0, limit = Compression::multibyte_read(in); i != limit; i++)
118   {
119     int size_k = Compression::multibyte_read(in);
120     char cad_k[size_k+1];
121     fread(cad_k, sizeof(char), size_k, in);
122     cad_k[size_k] = 0;
123     
124     int size_v = Compression::multibyte_read(in);
125     char cad_v[size_v+1];
126     fread(cad_v, sizeof(char), size_v, in);
127     cad_v[size_v] = 0;
128     
129     attr_items[cad_k] = cad_v;
130   }
132   // variables
133   for(int i = 0, limit = Compression::multibyte_read(in); i != limit; i++)
134   {
135     int size_k = Compression::multibyte_read(in);
136     char cad_k[size_k+1];
137     fread(cad_k, sizeof(char), size_k, in);
138     cad_k[size_k] = 0;
139     
140     int size_v = Compression::multibyte_read(in);
141     char cad_v[size_v+1];
142     fread(cad_v, sizeof(char), size_v, in);
143     cad_v[size_v] = 0;
144     
145     variables[cad_k] = cad_v;
146   }
148   // macros
149   for(int i = 0, limit = Compression::multibyte_read(in); i != limit; i++)
150   {
151     int size_k = Compression::multibyte_read(in);
152     char cad_k[size_k+1];
153     fread(cad_k, sizeof(char), size_k, in);
154     cad_k[size_k] = 0;
155     
156     macros[cad_k] = Compression::multibyte_read(in);
157   }
160   // lists
161   for(int i = 0, limit = Compression::multibyte_read(in); i != limit; i++)
162   {
163     int size_k = Compression::multibyte_read(in);
164     char cad_k[size_k+1];
165     fread(cad_k, sizeof(char), size_k, in);
166     cad_k[size_k] = 0;
167     for(int j = 0, limit2 = Compression::multibyte_read(in); j != limit2; j++)
168     {
169       int size_v = Compression::multibyte_read(in);
170       char cad_v[size_v+1];
171       fread(cad_v, sizeof(char), size_v, in);
172       cad_v[size_v] = 0;
173       lists[cad_k].insert(cad_v);
174       listslow[cad_k].insert(tolower(cad_v));
175     }  
176   }
179 void
180 TransferMult::readBil(string const &fstfile)
182   FILE *in = fopen(fstfile.c_str(), "r");
183   if(!in)
184   {
185     cerr << "Error: Could not open file '" << fstfile << "'." << endl;
186     exit(EXIT_FAILURE);
187   }
188   fstp.load(in);
189   fstp.initBiltrans();
190   fclose(in);
193 void
194 TransferMult::read(string const &datafile, string const &fstfile)
196   // datafile
197   FILE *in = fopen(datafile.c_str(), "r");
198   if(!in)
199   {
200     cerr << "Error: Could not open file '" << datafile << "'." << endl;
201     exit(EXIT_FAILURE);
202   }
203   readData(in);
204   fclose(in);
205   
206   readBil(fstfile);
209 TransferToken &
210 TransferMult::readToken(FILE *in)
212   if(!input_buffer.isEmpty())
213   {
214     return input_buffer.next();
215   }
217   string content = "";
218   while(true)
219   {
220     int val = fgetc_unlocked(in);
221     if(feof(in))
222     {
223       return input_buffer.add(TransferToken(content, tt_eof));
224     }
225     if(val == '\\')
226     {  
227       content += '\\';
228       content += char(fgetc_unlocked(in));
229     }
230     else if(val == '[')
231     {
232       content += '[';
233       while(true)
234       {
235         int val2 = fgetc_unlocked(in);
236         if(val2 == '\\')
237         {
238           content += '\\';
239           content += char(fgetc_unlocked(in));
240         }
241         else if(val2 == ']')
242         {
243           content += ']';
244           break;
245         }
246         else
247         {
248           content += char(val2);
249         }
250       }
251     }
252     else if(val == '$')
253     {
254       return input_buffer.add(TransferToken(content, tt_word));
255     }
256     else if(val == '^')
257     {
258       return input_buffer.add(TransferToken(content, tt_blank));
259     }
260     else
261     {
262       content += char(val);
263     }
264   }
267 void
268 TransferMult::transfer(FILE *in, FILE *out)
270   int last = 0;
272   output = out;
273   ms.init(me->getInitial());
274   
275   while(true)
276   {
277     if(ms.size() == 0)
278     {
279       if(isRule)
280       {
281         applyRule();
282         isRule = false;
283         input_buffer.setPos(last);
284       }
285       else
286       {
287         if(tmpword.size() != 0)
288         {
289           pair<string, int> tr = fstp.biltransWithQueue(*tmpword[0], false);
290           if(tr.first.size() != 0)
291           {
292             vector<string> multiword = acceptions(tr.first);        
293             for(unsigned int i = 0, limit = multiword.size(); i != limit; i++)
294             {
295               if(i > 0)
296               {
297                 fputs_unlocked("[ | ]", output);
298               }
299               fputc_unlocked('^', output);
300               fputs_unlocked(multiword[i].c_str(), output);
301               fputc_unlocked('$', output);
302             }
303           }
304           tmpword.clear();
305           isRule = false;
306           input_buffer.setPos(last);
307           input_buffer.next();       
308           last = input_buffer.getPos();
309           ms.init(me->getInitial());
310         }
311         else if(tmpblank.size() != 0)
312         {
313           fputs_unlocked(tmpblank[0]->c_str(), output);
314           tmpblank.clear();
315           last = input_buffer.getPos();
316           ms.init(me->getInitial());
317         }
318       }
319     }
320     int val = ms.classifyFinals(me->getFinals());
321     if(val != -1)
322     {
323       isRule = true;
324       numwords = tmpword.size();
325       last = input_buffer.getPos();
326     }
328     TransferToken &current = readToken(in);
329    
330     switch(current.getType())
331     {
332       case tt_word:
333         applyWord(current.getContent());
334         tmpword.push_back(&current.getContent());
335         break;
337       case tt_blank:
338         ms.step(' ');
339         tmpblank.push_back(&current.getContent());
340         break;
342       case tt_eof:
343         if(tmpword.size() != 0)
344         {
345           tmpblank.push_back(&current.getContent());
346           ms.clear();
347         }
348         else
349         {
350           fputs_unlocked(current.getContent().c_str(), output);
351           return;
352         }
353         break;
355       default:
356         cerr << "Error: Unknown input token." << endl;
357         return;
358     }
359   }
362 bool
363 TransferMult::isDefaultWord(string const &str)
365   return str.find(" D<");
368 vector<string> 
369 TransferMult::acceptions(string const &str)
371   vector<string> result;
372   int low = 0;
373   
374   for(unsigned int i = 0, limit = str.size(); i != limit; i++)
375   {
376      if(str[i] == '\\')
377      {
378        i++;
379      }
380      else if(str[i] == '/')
381      {
382        string new_word = str.substr(low, i-low);
383       
384        if(result.size() > 1 && isDefaultWord(new_word))
385        {
386          result.push_back(result[0]);
387          result[0] = new_word;
388        }
389        else
390        {
391          result.push_back(new_word);
392        }
393        low = i + 1;
394      }
395   }
396   
397   string otherword = str.substr(low);
398   if(result.size() > 0 && isDefaultWord(otherword))
399   {
400     result.push_back(result[0]);
401     result[0] = otherword;
402   }
403   else
404   {
405     result.push_back(otherword);
406   }
407   
408   return result;
411 void 
412 TransferMult::writeMultiple(list<vector<string> >::iterator itwords,
413                             list<string>::iterator itblanks, 
414                             list<vector<string> >::const_iterator limitwords, 
415                             string acum , bool multiple)
417   if(itwords == limitwords)
418   {
419     if(multiple)
420     {
421       fputs_unlocked("[ | ]", output);
422     }      
423     fputs_unlocked(acum.c_str(), output);
424   }
425   else
426   {
427     vector<string> &refword = *itwords;
429     itwords++;
430   
431     if(itwords == limitwords)
432     {
433       for(unsigned int i = 0, limit = refword.size(); i != limit; i++)
434       {
435         writeMultiple(itwords, itblanks, limitwords, 
436                       acum + "^" + refword[i] + "$", multiple || (i > 0));
437       }
438     }
439     else
440     {
441       string &refblank = *itblanks;
442       itblanks++;
443       
444       for(unsigned int i = 0, limit = refword.size(); i != limit; i++)
445       {
446         writeMultiple(itwords, itblanks, limitwords, 
447                       acum + "^" + refword[i] + "$" + refblank, 
448                       multiple || (i > 0));
449       }
450     }
451   }
454 void
455 TransferMult::applyRule()
457   list<string> blanks;
458   list<vector<string> > words;  
460   words.push_back(acceptions(fstp.biltransWithQueue(*tmpword[0], false).first));
461   
462   for(unsigned int i = 1; i != numwords; i++)
463   {
464     blanks.push_back(*tmpblank[i-1]);    
465     pair<string, int> tr = fstp.biltransWithQueue(*tmpword[i], false);
466     words.push_back(acceptions(tr.first));
467   }
469   writeMultiple(words.begin(), blanks.begin(), words.end());
471   ms.init(me->getInitial());
472   
473   tmpblank.clear();
474   tmpword.clear();
475   numwords = 0;
478 void
479 TransferMult::applyWord(string const &word_str)
481   ms.step('^');
482   for(unsigned int i = 0, limit = word_str.size(); i < limit; i++)
483   {
484     switch(word_str[i])
485     {
486       case '\\':
487         i++;
488         ms.step(::tolower(word_str[i]), any_char);
489         break;
491       case '<':
492         for(unsigned int j = i+1; j != limit; j++)
493         {
494           if(word_str[j] == '>')
495           {
496             int symbol = alphabet(word_str.substr(i, j-i+1));
497             if(symbol)
498             {
499               ms.step(symbol, any_tag);
500             }
501             else
502             {
503               ms.step(any_tag);
504             }
505             i = j;
506             break;
507           }
508         }
509         break;
510         
511       default:
512         ms.step(::tolower(word_str[i]), any_char);
513         break;
514     }
515   }
516   ms.step('$');