Few more things
[apertium.git] / lttoolbox / lttoolbox / FSTProcessor.C
blobe9d37e846114db97ec4096c068d0e6c35519ad92
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 <lttoolbox/FSTProcessor.H>
20 #include <lttoolbox/Compression.H>
21 #include <lttoolbox/MyStdio.H>
23 #include <iostream>
25 using namespace std;
27 FSTProcessor::FSTProcessor()
29   // escaped_chars chars
30   escaped_chars.insert(static_cast<unsigned short>('['));
31   escaped_chars.insert(static_cast<unsigned short>(']'));
32   escaped_chars.insert(static_cast<unsigned short>('^'));
33   escaped_chars.insert(static_cast<unsigned short>('$'));
34   escaped_chars.insert(static_cast<unsigned short>('/'));
35   escaped_chars.insert(static_cast<unsigned short>('\\'));
36   escaped_chars.insert(static_cast<unsigned short>('@'));
37   escaped_chars.insert(static_cast<unsigned short>('<'));
38   escaped_chars.insert(static_cast<unsigned short>('>'));
41 FSTProcessor::~FSTProcessor()
45 void
46 FSTProcessor::streamError()
48   cerr << "Error: Malformed input stream." << endl;
49   exit(EXIT_FAILURE);
52 unsigned short
53 FSTProcessor::readEscaped(FILE *input)
55   if(feof(input))
56   {
57     streamError();
58   }
60   unsigned short val = static_cast<unsigned short>(fgetc_unlocked(input));
62   if(feof(input) || escaped_chars.find(val) == escaped_chars.end())
63   {
64     streamError();
65   }
66   
67   return val;
70 string 
71 FSTProcessor::readFullBlock(FILE *input, char const delim1, char const delim2)
73   string result = "";
74   result += delim1;
75   char c = delim1;
77   while(!feof(input) && c != delim2)
78   {
79     c = static_cast<char>(fgetc_unlocked(input));
80     result += c;
81     if(c != '\\')
82     {
83       continue;
84     }
85     else
86     {
87       result += static_cast<char>(readEscaped(input));
88     }
89   }   
91   if(c != delim2)
92   {
93     streamError();
94   }
96   return result;
99 unsigned short
100 FSTProcessor::readAnalysis(FILE *input)
102   if(!input_buffer.isEmpty())
103   {
104     return input_buffer.next();
105   }
107   unsigned short val = static_cast<unsigned short>(fgetc_unlocked(input));
108   if(feof(input))
109   {
110     return 0;
111   }
113   if(escaped_chars.find(val) != escaped_chars.end())
114   {
115     switch(val)
116     {
117       case '<':
118         val = static_cast<unsigned short>(alphabet(readFullBlock(input, '<', '>')));
119         input_buffer.add(val);
120         return val;
122       case '[':
123         blankqueue.push(readFullBlock(input, '[', ']'));
124         input_buffer.add(' ');
125         return static_cast<unsigned short>(' ');
126         
127       case '\\':
128         val = static_cast<unsigned short>(fgetc_unlocked(input));
129         if(escaped_chars.find(val) == escaped_chars.end())
130         {
131           streamError();
132         }
133         input_buffer.add(val);
134         return val;
136       default:
137         streamError();
138     }                   
139   }
141   input_buffer.add(val);
142   return val;
145 unsigned short
146 FSTProcessor::readPostgeneration(FILE *input)
148   if(!input_buffer.isEmpty())
149   {
150     return input_buffer.next();
151   }
153   unsigned short val = static_cast<unsigned short>(fgetc_unlocked(input));
154   if(feof(input))
155   {
156     return 0;
157   }
159   switch(val)
160   {
161     case '<':
162       val = static_cast<unsigned short>(alphabet(readFullBlock(input, '<', '>')));
163       input_buffer.add(val);
164       return val;
166     case '[':
167       blankqueue.push(readFullBlock(input, '[', ']'));
168       input_buffer.add(' ');
169       return static_cast<unsigned short>(' ');
170         
171     case '\\':
172       val = static_cast<unsigned short>(fgetc_unlocked(input));
173       if(escaped_chars.find(val) == escaped_chars.end())
174       {
175         streamError();
176       }
177       input_buffer.add(val);
178       return val;
180     default:
181       input_buffer.add(val);
182       return val;
183   }
189 void
190 FSTProcessor::skipUntil(FILE *input, FILE *output, int const character)
192   while(true)
193   {
194     int val = fgetc_unlocked(input);
195     if(feof(input))
196     {
197       return;
198     }
200     if(val == '\\')
201     {
202       val = fgetc_unlocked(input);
203       if(feof(input))
204       {
205         return;
206       }
207       fputc_unlocked('\\', output);
208       fputc_unlocked(val, output);
209     }
210     else if(val == character)
211     {
212       return;
213     }
214     else
215     {
216       fputc_unlocked(val, output);
217     }
218   }
221 unsigned short
222 FSTProcessor::readGeneration(FILE *input, FILE *output)
224   int val = fgetc_unlocked(input);
226   if(feof(input))
227   {
228     return 0xffff;
229   }
230   
231   if(outOfWord)
232   {
233     if(val == '^')
234     {
235       val = fgetc_unlocked(input);
236       if(feof(input))
237       {
238         return 0xffff;
239       }
240     }
241     else if(val == '\\')
242     {
243       fputc_unlocked(val,output);
244       val = fgetc_unlocked(input);
245       if(feof(input))
246       {
247         return 0xffff;
248       }
249       fputc_unlocked(val,output);
250       skipUntil(input,output, '^');
251       val = fgetc_unlocked(input);
252       if(feof(input))
253       {
254         return 0xffff;
255       }
256     }
257     else
258     {
259       fputc_unlocked(val, output);
260       skipUntil(input, output, '^');
261       val = fgetc_unlocked(input);
262       if(feof(input))
263       {
264         return 0xffff;
265       }
266     }
267     outOfWord = false;
268   }
270   if(val == '\\')
271   {
272     val = fgetc_unlocked(input);
273     return static_cast<unsigned short>(val);
274   }
275   else if(val == '$')
276   {
277     outOfWord = true;
278     return static_cast<unsigned short>('$');
279   }
280   else if(val == '<')
281   {
282     string cad = "";
283     cad += char(val);
284     while((val = fgetc_unlocked(input)) != '>')
285     {
286       if(feof(input))
287       {
288         streamError();
289       }
290       cad += char(val);
291     }
292     cad += char(val);
294     return alphabet(cad);
295   }
296   else if(val == '[')
297   {
298     fputs_unlocked(readFullBlock(input, '[', ']').c_str(), output);
299     return readGeneration(input, output);
300   }
301   else
302   {
303     return static_cast<unsigned short>(val);
304   }
306   return 0xffff;
309 void
310 FSTProcessor::flushBlanks(FILE *output)
311 {  
312   for(unsigned int i = blankqueue.size(); i > 0; i--)
313   {
314     fputs_unlocked(blankqueue.front().c_str(), output);
315     blankqueue.pop();
316   }
319 void
320 FSTProcessor::calcInitial()
322   for(map<string, TransExe, Ltstr>::iterator it = transducers.begin(),
323                                              limit = transducers.end();
324       it != limit; it++)
325   {
326     root.addTransition(0, 0, it->second.getInitial());
327   }
329   initial_state.init(&root);
332 bool
333 FSTProcessor::endsWith(string const &a, string const &b)
335   if(a.size() < b.size())
336   {
337     return false;
338   }
339   else
340   {
341     return a.substr(a.size()-b.size()) == b;
342   }
345 void
346 FSTProcessor::classifyFinals()
348   for(map<string, TransExe, Ltstr>::iterator it = transducers.begin(),
349                                              limit = transducers.end();
350       it != limit; it++)
351   {
352     if(endsWith(it->first, "@inconditional"))
353     {
354       inconditional.insert(it->second.getFinals().begin(),
355                            it->second.getFinals().end());
356     }
357     else if(endsWith(it->first, "@standard"))
358     {
359       standard.insert(it->second.getFinals().begin(),
360                       it->second.getFinals().end());
361     }
362     else if(endsWith(it->first, "@postblank"))
363     {
364       postblank.insert(it->second.getFinals().begin(),
365                        it->second.getFinals().end());
366     }
367     else
368     {
369       cerr << "Error: Unsupported transducer type for '";
370       cerr << it->first << "'." << endl;
371       exit(EXIT_FAILURE);
372     }
373   }
376 void
377 FSTProcessor::writeEscaped(string const &str, FILE *output)
379   for(unsigned int i = 0, limit = str.size(); i < limit; i++)
380   {
381     if(escaped_chars.find(str[i]) != escaped_chars.end())
382     {
383       fputc_unlocked('\\', output);
384     }
385     fputc_unlocked(str[i], output);
386   } 
390 void
391 FSTProcessor::printWord(string const &sf, string const &lf, FILE *output)
393   fputc_unlocked('^', output);
394   writeEscaped(sf, output);
395   fwrite_unlocked(lf.c_str(), lf.size(), sizeof(char), output);
396   fputc_unlocked('$', output);
399 void
400 FSTProcessor::printUnknownWord(string const &sf, FILE *output)
402   fputc_unlocked('^', output);
403   writeEscaped(sf, output);
404   fputc_unlocked('/', output);
405   fputc_unlocked('*', output);
406   writeEscaped(sf, output);
407   fputc_unlocked('$', output);  
410 unsigned int
411 FSTProcessor::lastBlank(string const &str)
413   for(int i = static_cast<int>(str.size())-1; i >= 0; i--)
414   {
415     if(alphabetic_chars.find(str[i]) == alphabetic_chars.end())
416     {
417       return static_cast<unsigned int>(i);
418     }
419   }
421   return 0;
424 void
425 FSTProcessor::printSpace(unsigned short const val, FILE *output)
427   if(blankqueue.size() > 0)
428   {
429     flushBlanks(output);
430   }
431   else
432   {
433     fputc_unlocked(val, output);
434   }
437 bool
438 FSTProcessor::isEscaped(unsigned short const c) const
440   return escaped_chars.find(c) != escaped_chars.end();
443 bool
444 FSTProcessor::isAlphabetic(unsigned short const c) const
446   return alphabetic_chars.find(c) != alphabetic_chars.end();
449 void
450 FSTProcessor::load(FILE *input)
452   int len = Compression::multibyte_read(input);
454   while(len > 0)
455   {
456     alphabetic_chars.insert(static_cast<unsigned short>(fgetc_unlocked(input)));
457     len--;
458   }  
459   
460   alphabet.read(input);
462   len = Compression::multibyte_read(input);
464   while(len > 0)
465   {
466     int len2 = Compression::multibyte_read(input);
467     string name = "";
468     while(len2 > 0)
469     {
470       name += static_cast<char>(fgetc_unlocked(input));
471       len2--;
472     }
473     transducers[name].read(input, alphabet.size());
474     len--;
475   } 
479 void
480 FSTProcessor::initAnalysis()
482   calcInitial();
483   classifyFinals();
484   all_finals = standard;
485   all_finals.insert(inconditional.begin(), inconditional.end());
486   all_finals.insert(postblank.begin(), postblank.end());
489 void
490 FSTProcessor::initGeneration()
492   calcInitial();  
493   for(map<string, TransExe, Ltstr>::iterator it = transducers.begin(),
494                                              limit = transducers.end();
495       it != limit; it++)
496   {
497     all_finals.insert(it->second.getFinals().begin(),
498                       it->second.getFinals().end());
499   }
502 void
503 FSTProcessor::initPostgeneration()
505   initGeneration();
508 void
509 FSTProcessor::initBiltrans()
511   initGeneration();
514 void
515 FSTProcessor::analysis(FILE *input, FILE *output)
517   bool last_incond = false;
518   bool last_postblank = false;
519   State current_state = initial_state;
520   string lf = "";
521   string sf = "";
522   int last = 0;
524   while(unsigned short val = readAnalysis(input))
525   {
526     // test for final states
527     if(current_state.isFinal(all_finals))
528     {
529       if(current_state.isFinal(inconditional))
530       {
531         bool firstupper = isupper(sf[0]);
532         bool uppercase = firstupper && isupper(sf[sf.size()-1]);
534         lf = current_state.filterFinals(all_finals, alphabet,
535                                         escaped_chars,
536                                         uppercase, firstupper);
537         last_incond = true;
538         last = input_buffer.getPos();
539       }
540       else if(current_state.isFinal(postblank))
541       {
542         bool firstupper = isupper(sf[0]);
543         bool uppercase = firstupper && isupper(sf[sf.size()-1]);
545         lf = current_state.filterFinals(all_finals, alphabet,
546                                         escaped_chars,
547                                         uppercase, firstupper);
548         last_postblank = true;
549         last = input_buffer.getPos();      
550       }
551       else if(!isAlphabetic(val))
552       {
553         bool firstupper = isupper(sf[0]);
554         bool uppercase = firstupper && isupper(sf[sf.size()-1]);
556         lf = current_state.filterFinals(all_finals, alphabet, 
557                                         escaped_chars, 
558                                         uppercase, firstupper);
559         last_postblank = false;
560         last_incond = false;
561         last = input_buffer.getPos();
562       }
563     }
564     else if(sf == "" && isspace(val)) 
565     {
566       lf = "/*";
567       lf.append(sf);
568       last_postblank = false;
569       last_incond = false;
570       last = input_buffer.getPos();
571     }
573     if(!isupper(val))
574     {
575       current_state.step(val);
576     }
577     else
578     {
579       current_state.step(val, tolower(val));
580     }
581       
582     if(current_state.size() != 0)
583     {
584       alphabet.getSymbol(sf, val);
585     }
586     else
587     {
588       if(!isAlphabetic(val) && sf == "")
589       {
590         if(isspace(val))
591         {
592           printSpace(val, output);
593         }
594         else
595         {
596           if(isEscaped(val))
597           {
598             fputc_unlocked('\\', output);
599           }
600           fputc_unlocked(val, output);
601         }
602       }
603       else if(last_incond)
604       {
605         printWord(sf.substr(0, sf.size()-input_buffer.diffPrevPos(last)),
606                   lf, output);
607         input_buffer.setPos(last);
608         input_buffer.back(1);
609       }
610       else if(last_postblank)
611       {
612         printWord(sf.substr(0, sf.size()-input_buffer.diffPrevPos(last)),
613                   lf, output);
614         fputc_unlocked(' ', output);
615         input_buffer.setPos(last);
616         input_buffer.back(1);
617       }
618       else if(isAlphabetic(val) && 
619               ((sf.size()-input_buffer.diffPrevPos(last)) > lastBlank(sf) || 
620                lf == ""))
621       {
622         do
623         {
624           alphabet.getSymbol(sf, val);
625         }         
626         while((val = readAnalysis(input)) && isAlphabetic(val));
628         unsigned int limit = sf.find(' ');
629         unsigned int size = sf.size();
630         limit = (limit == static_cast<unsigned 
631 int>(string::npos)?size:limit);
632         input_buffer.back(1+(size-limit));
633         printUnknownWord(sf.substr(0, limit), output);
634       }
635       else if(lf == "")
636       {
637         unsigned int limit = sf.find(' ');
638         unsigned int size = sf.size();
639         limit = (limit == static_cast<unsigned 
640 int>(string::npos)?size:limit);
641         input_buffer.back(1+(size-limit));
642         printUnknownWord(sf.substr(0, limit), output);
643       }
644       else
645       {
646         printWord(sf.substr(0, sf.size()-input_buffer.diffPrevPos(last)), 
647                   lf, output);
648         input_buffer.setPos(last);
649         input_buffer.back(1);
650       }
651         
652       current_state = initial_state;
653       lf = "";
654       sf = "";
655       last_incond = false;
656       last_postblank = false;
657     }
658   }
659   
660   // print remaining blanks
661   flushBlanks(output);
664 void
665 FSTProcessor::generation(FILE *input, FILE *output, GenerationMode mode)
667   State current_state = initial_state;
668   string sf = "";
670   outOfWord = false;
672   skipUntil(input, output, '^');
673   unsigned short val;
674   while((val = readGeneration(input, output)) != 0xffff)
675   {
676     if(val == '$')
677     {
678       if(sf[0] == '*')
679       {
680         if(mode != gm_clean)
681         {
682           writeEscaped(sf, output);
683         }
684         else
685         {
686           writeEscaped(sf.substr(1), output);
687         }
688       }
689       else if(sf[0] == '@')
690       {
691         if(mode == gm_all)
692         {
693           writeEscaped(sf, output);
694         }
695         else if(mode == gm_clean)
696         {
697           writeEscaped(removeTags(sf.substr(1)), output);
698         }
699         else if(mode == gm_unknown)
700         {
701           writeEscaped(removeTags(sf), output);
702         }
703       }
704       else if(current_state.isFinal(all_finals))
705       {
706         bool uppercase = sf.size() > 1 && isupper(sf[1]);
707         bool firstupper= isupper(sf[0]);
709         fputs_unlocked(current_state.filterFinals(all_finals, alphabet,
710                                                   escaped_chars,
711                                                   uppercase, firstupper).substr(1).c_str(),
712                                                   output);
713       }
714       else
715       {
716         if(mode == gm_all)
717         {
718           fputc_unlocked('#', output);
719           writeEscaped(sf, output);
720         }
721         else if(mode == gm_clean)
722         {
723           writeEscaped(removeTags(sf), output);
724         }
725         else if(mode == gm_unknown)
726         {
727           fputc_unlocked('#', output);
728           writeEscaped(removeTags(sf), output);
729         }
730       }
731   
732       current_state = initial_state;
733       sf = "";
734     }
735     else if(isspace(val) && sf.size() == 0)
736     {
737       // do nothing
738     }
739     else if(sf.size() > 0 && sf[0] == '*')
740     {
741       alphabet.getSymbol(sf, val);
742     }
743     else
744     {
745       alphabet.getSymbol(sf,val);
746       if(current_state.size() > 0)
747       {
748         if(val < 256 && isupper(val))
749         {
750           current_state.step(val, tolower(val));
751         }
752         else
753         {
754           current_state.step(val);
755         }
756       }
757     }
758   }
761 void
762 FSTProcessor::postgeneration(FILE *input, FILE *output)
764   bool skip_mode = true;
765   State current_state = initial_state;
766   string lf = "";
767   string sf = "";
768   int last = 0;
770   while(unsigned short val = readPostgeneration(input))
771   {
772     if(val == '~')
773     {
774       skip_mode = false;
775     }
777     if(skip_mode)
778     {
779       if(isspace(val))
780       {
781         printSpace(val, output);
782       }
783       else
784       {
785         if(isEscaped(val))
786         {
787           fputc_unlocked('\\', output);
788         }
789         fputc_unlocked(val, output);
790       }
791     }
792     else      
793     {
794       // test for final states
795       if(current_state.isFinal(all_finals))
796       {
797         bool firstupper = isupper(sf[1]);
798         bool uppercase = sf.size() > 1 && firstupper && isupper(sf[2]);
799         lf = current_state.filterFinals(all_finals, alphabet,
800                                         escaped_chars,
801                                         uppercase, firstupper, 0);
803         // case of the beggining of the next word
804                 
805         string mybuf = "";                              
806         for(unsigned int i = sf.size()-1; i >= 0; i--)
807         {
808           if(!isalpha(sf[i]))
809           {
810             break;
811           }
812           else
813           {
814             mybuf = sf[i] + mybuf;
815           }
816         }
817         
818         if(mybuf.size() > 0)
819         {
820           bool myfirstupper = isupper(mybuf[0]);
821           bool myuppercase = mybuf.size() > 1 && isupper(mybuf[1]);
822         
823           for(unsigned int i = lf.size()-1; i >= 0; i--)
824           {
825             if(!isalpha(lf[i]))
826             {
827               if(myfirstupper && i != lf.size()-1)
828               {
829                 lf[i+1] = toupper(lf[i+1]);
830               }
831               else
832               {
833                 lf[i+1] = tolower(lf[i+1]);
834               }
835               break;
836             }
837             else
838             {
839               if(myuppercase)
840               {
841                 lf[i] = toupper(lf[i]);
842               }
843               else
844               {
845                 lf[i] = tolower(lf[i]);
846               }
847             }
848           }
849         }
850         
851         last = input_buffer.getPos();
852       }
854       if(!isupper(val))
855       {
856         current_state.step(val);
857       }
858       else
859       {
860         current_state.step(val, tolower(val));
861       }
862       
863       if(current_state.size() != 0)
864       {
865         alphabet.getSymbol(sf, val);
866       }
867       else
868       { 
869         if(lf == "")
870         {
871           unsigned int mark = sf.size();
872           for(unsigned int i = 1, limit = sf.size(); i < limit; i++)
873           {
874             if(sf[i] == '~')
875             { 
876               mark = i;
877               break;
878             }
879           }
880           fputs_unlocked(sf.substr(1, mark-1).c_str(), output);
881           if(mark == sf.size())
882           {
883             input_buffer.back(1);
884           }
885           else
886           {
887             input_buffer.back(sf.size()-mark);
888           }
889         }
890         else
891         {
892           fputs_unlocked(lf.substr(1,lf.size()-3).c_str(), output);
893           input_buffer.setPos(last);
894           input_buffer.back(2);
895           val = lf[lf.size()-2];
896           if(isspace(val))
897           {
898             printSpace(val, output);
899           }
900           else
901           {
902             if(isEscaped(val))
903             {
904               fputc_unlocked('\\', output);
905             }
906             fputc_unlocked(val, output);
907           }       
908         }
910         current_state = initial_state;
911         lf = "";
912         sf = "";
913         skip_mode = true;
914       }
915     }
916   }
917   
918   // print remaining blanks
919   flushBlanks(output);  
922 string
923 FSTProcessor::biltrans(string const &input_word, bool with_delim)
925   State current_state = initial_state;
926   string result="";
927   unsigned int start_point = 1;
928   unsigned int end_point = input_word.size()-2;
929   string queue = "";
930   
931   if(with_delim == false)
932   {
933     start_point = 0;
934     end_point = input_word.size()-1;
935   }
937   if(input_word[start_point] == '*')
938   {
939     return input_word;
940   }
941   
942   bool firstupper = isupper(input_word[start_point]);
943   bool uppercase = firstupper && isupper(input_word[start_point+1]);
945   for(unsigned int i = start_point; i <= end_point; i++)
946   {
947     unsigned short val;
948     string symbol ="";
950     if(input_word[i] == '\\')
951     {
952       i++;
953       val = static_cast<unsigned short>((unsigned char) input_word[i]);
954     }
955     else if(input_word[i] == '<')
956     {
957       symbol = '<';
958       for(unsigned int j = i + 1; j <= end_point; j++)
959       {
960         symbol += input_word[j];
961         if(input_word[j] == '>')
962         {
963           i = j;
964           break;
965         }
966       }
967       val = alphabet(symbol);
968     }
969     else
970     {
971       val = static_cast<unsigned short>((unsigned char) input_word[i]);
972     }
973     if(current_state.size() != 0)
974     {
975       if(val < 256 && isupper(val))
976       {
977         current_state.step(val, tolower(val));
978       }
979       else
980       {
981         current_state.step(val);
982       }
983     }
984     if(current_state.isFinal(all_finals))
985     {
986       result = current_state.filterFinals(all_finals, alphabet,
987                                          escaped_chars,
988                                          uppercase, firstupper, 0);
989       if(with_delim)
990       {      
991         result[0] = '^';
992       }
993       else
994       {
995         result = result.substr(1);
996       }
997     }
998     
999     if(current_state.size() == 0)
1000     { 
1001       if(symbol != "")
1002       {
1003         queue.append(symbol);
1004       }
1005       else
1006       {
1007         // word is not present
1008         if(with_delim)
1009         {
1010           result = "^@" + input_word.substr(1);  
1011         }
1012         else
1013         {
1014           result = "@" + input_word;
1015         }
1016         return result;  
1017       }      
1018     }
1019   }
1021   // attach unmatched queue automatically
1023   if(queue != "")
1024   {
1025     string result_with_queue = "";    
1026     bool multiple_translation = false;
1027     for(unsigned int i = 0, limit = result.size(); i != limit; i++)
1028     {
1029       switch(result[i])
1030       {
1031         case '\\':
1032           result_with_queue += '\\';
1033           i++;
1034           break;
1035      
1036         case '/':
1037           result_with_queue.append(queue);
1038           multiple_translation = true;
1039           break;
1040     
1041         default:
1042           break;
1043       }
1044       result_with_queue += result[i];
1045     }
1046     result_with_queue.append(queue);
1048     if(with_delim)
1049     {
1050       result_with_queue += '$';
1051  //     if(multiple_translation)
1052  //     {
1053  //       result_with_queue[0] = '@';
1054  //       result = "^" + result_with_queue;
1055  //       return result;
1056  //     }
1057  //     else
1058  //     {
1059         return result_with_queue;
1060  //     }
1061     }
1062  //   if(multiple_translation)
1063  //   {
1064  //     return  "@"+result_with_queue;
1065  //   }
1066  //   else
1067  //   {
1068       return result_with_queue;
1069  //   }
1070   }
1071   else
1072   {
1073     if(with_delim)
1074     {
1075       result += '$';
1076     }
1077     return result;
1078   }
1081 pair<string, int>
1082 FSTProcessor::biltransWithQueue(string const &input_word, bool with_delim)
1084   State current_state = initial_state;
1085   string result="";
1086   unsigned int start_point = 1;
1087   unsigned int end_point = input_word.size()-2;
1088   string queue = "";
1089   
1090   if(with_delim == false)
1091   {
1092     start_point = 0;
1093     end_point = input_word.size()-1;
1094   }
1096   if(input_word[start_point] == '*')
1097   {
1098     return pair<string, int>(input_word, 0);
1099   }
1100   
1101   bool firstupper = isupper(input_word[start_point]);
1102   bool uppercase = firstupper && isupper(input_word[start_point+1]);
1104   for(unsigned int i = start_point; i <= end_point; i++)
1105   {
1106     unsigned short val;
1107     string symbol ="";
1109     if(input_word[i] == '\\')
1110     {
1111       i++;
1112       val = static_cast<unsigned short>((unsigned char) input_word[i]);
1113     }
1114     else if(input_word[i] == '<')
1115     {
1116       symbol = '<';
1117       for(unsigned int j = i + 1; j <= end_point; j++)
1118       {
1119         symbol += input_word[j];
1120         if(input_word[j] == '>')
1121         {
1122           i = j;
1123           break;
1124         }
1125       }
1126       val = alphabet(symbol);
1127     }
1128     else
1129     {
1130       val = static_cast<unsigned short>((unsigned char) input_word[i]);
1131     }
1132     if(current_state.size() != 0)
1133     {
1134       if(val < 256 && isupper(val))
1135       {
1136         current_state.step(val, tolower(val));
1137       }
1138       else
1139       {
1140         current_state.step(val);
1141       }
1142     }
1143     if(current_state.isFinal(all_finals))
1144     {
1145       result = current_state.filterFinals(all_finals, alphabet,
1146                                          escaped_chars,
1147                                          uppercase, firstupper, 0);
1148       if(with_delim)
1149       {      
1150         result[0] = '^';
1151       }
1152       else
1153       {
1154         result = result.substr(1);
1155       }
1156     }
1157     
1158     if(current_state.size() == 0)
1159     { 
1160       if(symbol != "")
1161       {
1162         queue.append(symbol);
1163       }
1164       else
1165       {
1166         // word is not present
1167         if(with_delim)
1168         {
1169           result = "^@" + input_word.substr(1);  
1170         }
1171         else
1172         {
1173           result = "@" + input_word;
1174         }
1175         return pair<string, int>(result, 0);  
1176       }      
1177     }
1178   }
1180   // attach unmatched queue automatically
1182   if(queue != "")
1183   {
1184     string result_with_queue = "";    
1185     bool multiple_translation = false;
1186     for(unsigned int i = 0, limit = result.size(); i != limit; i++)
1187     {
1188       switch(result[i])
1189       {
1190         case '\\':
1191           result_with_queue += '\\';
1192           i++;
1193           break;
1194      
1195         case '/':
1196           result_with_queue.append(queue);
1197           multiple_translation = true;
1198           break;
1199     
1200         default:
1201           break;
1202       }
1203       result_with_queue += result[i];
1204     }
1205     result_with_queue.append(queue);
1207     if(with_delim)
1208     {
1209       result_with_queue += '$';
1210     }
1211     return pair<string, int>(result_with_queue, queue.size());
1212   }
1213   else
1214   {
1215     if(with_delim)
1216     {
1217       result += '$';
1218     }
1219     return pair<string, int>(result, 0);
1220   }
1223 string
1224 FSTProcessor::biltransWithoutQueue(string const &input_word, bool with_delim)
1226   State current_state = initial_state;
1227   string result="";
1228   unsigned int start_point = 1;
1229   unsigned int end_point = input_word.size()-2;
1230   
1231   if(with_delim == false)
1232   {
1233     start_point = 0;
1234     end_point = input_word.size()-1;
1235   }
1237   if(input_word[start_point] == '*')
1238   {
1239     return input_word;
1240   }
1241   
1242   bool firstupper = isupper(input_word[start_point]);
1243   bool uppercase = firstupper && isupper(input_word[start_point+1]);
1245   for(unsigned int i = start_point; i <= end_point; i++)
1246   {
1247     unsigned short val;
1248     string symbol ="";
1250     if(input_word[i] == '\\')
1251     {
1252       i++;
1253       val = static_cast<unsigned short>((unsigned char) input_word[i]);
1254     }
1255     else if(input_word[i] == '<')
1256     {
1257       symbol = '<';
1258       for(unsigned int j = i + 1; j <= end_point; j++)
1259       {
1260         symbol += input_word[j];
1261         if(input_word[j] == '>')
1262         {
1263           i = j;
1264           break;
1265         }
1266       }
1267       val = alphabet(symbol);
1268     }
1269     else
1270     {
1271       val = static_cast<unsigned short>((unsigned char) input_word[i]);
1272     }
1273     if(current_state.size() != 0)
1274     {
1275       if(val < 256 && isupper(val))
1276       {
1277         current_state.step(val, tolower(val));
1278       }
1279       else
1280       {
1281         current_state.step(val);
1282       }
1283     }
1284     if(current_state.isFinal(all_finals))
1285     {
1286       result = current_state.filterFinals(all_finals, alphabet,
1287                                          escaped_chars,
1288                                          uppercase, firstupper, 0);
1289       if(with_delim)
1290       {      
1291         result[0] = '^';
1292       }
1293       else
1294       {
1295         result = result.substr(1);
1296       }
1297     }
1298     
1299     if(current_state.size() == 0)
1300     { 
1301       if(symbol == "")
1302       {
1303         // word is not present
1304         if(with_delim)
1305         {
1306           result = "^@" + input_word.substr(1);  
1307         }
1308         else
1309         {
1310           result = "@" + input_word;
1311         }
1312         return result;  
1313       }      
1314     }
1315   }
1317   if(with_delim)
1318   {
1319     result += '$';
1320   }
1321   return result;
1325 bool
1326 FSTProcessor::valid() const
1328   return !initial_state.isFinal(all_finals);
1331 unsigned short
1332 FSTProcessor::readSAO(FILE *input)
1334   if(!input_buffer.isEmpty())
1335   {
1336     return input_buffer.next();
1337   }
1339   unsigned short val = static_cast<unsigned short>(fgetc_unlocked(input));
1340   if(feof(input))
1341   {
1342     return 0;
1343   }
1345   if(escaped_chars.find(val) != escaped_chars.end())
1346   {
1347     if(val == '<')
1348     {
1349       string str = readFullBlock(input, '<', '>');
1350       if(str.substr(0, 9) == "<![CDATA[")
1351       {
1352         while(str.substr(str.size()-3) != "]]>")
1353         {
1354           str.append(readFullBlock(input, '<', '>').substr(1));
1355         }
1356         blankqueue.push(str);
1357         input_buffer.add(' ');
1358         return static_cast<unsigned short>(' ');
1359       }
1360       else
1361       {
1362         streamError();
1363       }
1364     }
1365     else if (val == '\\') {
1366       val = static_cast<unsigned short>(fgetc_unlocked(input));
1367       if(isEscaped(val))
1368       {
1369         input_buffer.add(val);
1370         return val;
1371       }
1372       else
1373         streamError();
1374     }
1375     else
1376     {
1377       streamError();
1378     }                   
1379   }
1381   input_buffer.add(val);
1382   return val;
1385 void
1386 FSTProcessor::printSAOWord(string const &lf, FILE *output)
1388   for(unsigned int i = 1, limit = lf.size(); i != limit; i++)
1389   {
1390     if(lf[i] == '/')
1391     {
1392       break;
1393     }
1394     fputc_unlocked(lf[i], output);
1395   }
1398 void
1399 FSTProcessor::SAO(FILE *input, FILE *output)
1401   bool last_incond = false;
1402   bool last_postblank = false;
1403   State current_state = initial_state;
1404   string lf = "";
1405   string sf = "";
1406   int last = 0;
1408   escaped_chars.clear();
1409   escaped_chars.insert(static_cast<unsigned short>('\\'));
1410   escaped_chars.insert(static_cast<unsigned short>('<'));
1411   escaped_chars.insert(static_cast<unsigned short>('>'));
1413   while(unsigned short val = readSAO(input))
1414   {
1415     // test for final states
1416     if(current_state.isFinal(all_finals))
1417     {
1418       if(current_state.isFinal(inconditional))
1419       {
1420         bool firstupper = isupper(sf[0]);
1421         bool uppercase = firstupper && isupper(sf[sf.size()-1]);
1423         lf = current_state.filterFinalsSAO(all_finals, alphabet,
1424                                         escaped_chars,
1425                                         uppercase, firstupper);
1426         last_incond = true;
1427         last = input_buffer.getPos();
1428       }
1429       else if(current_state.isFinal(postblank))
1430       {
1431         bool firstupper = isupper(sf[0]);
1432         bool uppercase = firstupper && isupper(sf[sf.size()-1]);
1434         lf = current_state.filterFinalsSAO(all_finals, alphabet,
1435                                         escaped_chars,
1436                                         uppercase, firstupper);
1437         last_postblank = true;
1438         last = input_buffer.getPos();      
1439       }
1440       else if(!isAlphabetic(val))
1441       {
1442         bool firstupper = isupper(sf[0]);
1443         bool uppercase = firstupper && isupper(sf[sf.size()-1]);
1445         lf = current_state.filterFinalsSAO(all_finals, alphabet, 
1446                                         escaped_chars, 
1447                                         uppercase, firstupper);
1448         last_postblank = false;
1449         last_incond = false;
1450         last = input_buffer.getPos();
1451       }
1452     }
1453     else if(sf == "" && isspace(val)) // "hay incidencias" problem
1454     {
1455       lf = "/*";
1456       lf.append(sf);
1457       last_postblank = false;
1458       last_incond = false;
1459       last = input_buffer.getPos();
1460     }
1462     if(!isupper(val))
1463     {
1464       current_state.step(val);
1465     }
1466     else
1467     {
1468       current_state.step(val, tolower(val));
1469     }
1470       
1471     if(current_state.size() != 0)
1472     {
1473       alphabet.getSymbol(sf, val);
1474     }
1475     else
1476     {
1477       if(!isAlphabetic(val) && sf == "")
1478       {
1479         if(isspace(val))
1480         {
1481           printSpace(val, output);
1482         }
1483         else
1484         {
1485           if(isEscaped(val))
1486           {
1487             fputc_unlocked('\\', output);
1488           }
1489           fputc_unlocked(val, output);
1490         }
1491       }
1492       else if(last_incond)
1493       {
1494         printSAOWord(lf, output);
1495         input_buffer.setPos(last);
1496         input_buffer.back(1);
1497       }
1498       else if(last_postblank)
1499       {
1500         printSAOWord(lf, output);
1501         fputc_unlocked(' ', output);
1502         input_buffer.setPos(last);
1503         input_buffer.back(1);
1504       }
1505       else if(isAlphabetic(val) && 
1506               ((sf.size()-input_buffer.diffPrevPos(last)) > lastBlank(sf) || 
1507                lf == ""))
1508       {
1509         do
1510         {
1511           alphabet.getSymbol(sf, val);
1512         }         
1513         while((val = readSAO(input)) && isAlphabetic(val));
1515         unsigned int limit = sf.find(' ');
1516         unsigned int size = sf.size();
1517         limit = (limit == static_cast<unsigned 
1518 int>(string::npos)?size:limit);
1519         input_buffer.back(1+(size-limit));
1520         fwrite_unlocked("<d>", 3, sizeof(char), output);
1521         fwrite_unlocked(sf.c_str(), limit, sizeof(char), output);
1522         fwrite_unlocked("</d>", 4, sizeof(char), output);
1523       }
1524       else if(lf == "")
1525       {
1527         unsigned int limit = sf.find(' ');
1528         unsigned int size = sf.size();
1529         limit = (limit == static_cast<unsigned 
1530 int>(string::npos)?size:limit);
1531         input_buffer.back(1+(size-limit));
1532         fwrite_unlocked("<d>", 3, sizeof(char), output);
1533         fwrite_unlocked(sf.c_str(), limit, sizeof(char), output);
1534         fwrite_unlocked("</d>", 4, sizeof(char), output);
1535       }
1536       else
1537       {
1538         printSAOWord(lf, output);
1539         input_buffer.setPos(last);
1540         input_buffer.back(1);
1541       }
1542         
1543       current_state = initial_state;
1544       lf = "";
1545       sf = "";
1546       last_incond = false;
1547       last_postblank = false;
1548     }
1549   }
1550   
1551   // print remaining blanks
1552   flushBlanks(output);
1555 string
1556 FSTProcessor::removeTags(string const &str)
1558   for(unsigned int i = 0; i < str.size(); i++)
1559   {
1560     if(str[i] == '<' && i >=1 && str[i-1] != '\\')
1561     {
1562       return str.substr(0, i);
1563     }
1564   }
1565   
1566   return str;