dic_search.c

Go to the documentation of this file.
00001 /* Eliot                                                                     */
00002 /* Copyright (C) 1999  Antoine Fraboulet                                     */
00003 /*                                                                           */
00004 /* This file is part of Eliot.                                               */
00005 /*                                                                           */
00006 /* Eliot is free software; you can redistribute it and/or modify             */
00007 /* it under the terms of the GNU General Public License as published by      */
00008 /* the Free Software Foundation; either version 2 of the License, or         */
00009 /* (at your option) any later version.                                       */
00010 /*                                                                           */
00011 /* Eliot is distributed in the hope that it will be useful,                  */
00012 /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
00013 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
00014 /* GNU General Public License for more details.                              */
00015 /*                                                                           */
00016 /* You should have received a copy of the GNU General Public License         */
00017 /* along with this program; if not, write to the Free Software               */
00018 /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00019 
00020 /**
00021  *  \file   dic_search.c
00022  *  \brief  Dictionary lookup functions
00023  *  \author Antoine Fraboulet
00024  *  \date   2002
00025  */
00026 
00027 #include <ctype.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 
00031 #include "dic_internals.h"
00032 #include "dic.h"
00033 #include "regexp.h"
00034 #include "dic_search.h"
00035 #include "libdic_a-er.h" /* generated by bison */
00036 #include "scanner.h"     /* generated by flex  */
00037 #include "automaton.h"
00038 
00039 /*
00040  * shut down the compiler
00041  */
00042 static int yy_init_globals (yyscan_t yyscanner )
00043 {
00044   yy_init_globals(yyscanner);
00045   return 0;
00046 }
00047 
00048 /**
00049  * Dic_seel_edgeptr
00050  * walk the dictionary until the end of the word
00051  * @param dic : dictionnary
00052  * @param s : current pointer to letters
00053  * @param eptr : current edge in the dawg
00054  */
00055 static Dawg_edge*
00056 Dic_seek_edgeptr(const Dictionary dic, const char* s, Dawg_edge *eptr)
00057 {
00058   if (*s)
00059     {
00060       Dawg_edge *p = dic->dawg + eptr->ptr;
00061       do {
00062         if (p->chr == (unsigned)(*s & DIC_CHAR_MASK))
00063           return Dic_seek_edgeptr (dic,s + 1, p);
00064       } while (!(*p++).last);
00065       return dic->dawg;
00066     }
00067   else
00068     return eptr;
00069 }
00070 
00071 
00072 /**
00073  * Dic_search_word : direct application of Dic_seek_edgeptr
00074  * @param dic : dictionary
00075  * @param word : word to lookup
00076  * @result 0 not a valid word, 1 ok
00077  */
00078 
00079 int
00080 Dic_search_word(const Dictionary dic, const char* word)
00081 {
00082   Dawg_edge *e;
00083   e = Dic_seek_edgeptr(dic,word,dic->dawg + dic->root);
00084   return e->term;
00085 }
00086 
00087 
00088 /**
00089  * global variables for Dic_search_word_by_len :
00090  *
00091  * a pointer to the structure is passed as a parameter
00092  * so that all the search_* variables appear to the functions
00093  * as global but the code remains re-entrant.
00094  * Should be better to change the algorithm ...
00095  */
00096 
00097 struct params_7plus1_t {
00098  Dictionary search_dic;
00099  int search_len;
00100  int search_wordlistlen;
00101  int search_wordlistlenmax;
00102  char search_wordtst[DIC_WORD_MAX];
00103  char search_letters[DIC_LETTERS];
00104  char (*search_wordlist)[RES_7PL1_MAX][DIC_WORD_MAX];
00105 };
00106 
00107 static void
00108 Dic_search_word_by_len(struct params_7plus1_t *params, int i, Dawg_edge *edgeptr)
00109 {
00110   /* depth first search in the dictionary */
00111   do {
00112     /* we use a static array and not a real list so we have to stop if
00113      * the array is full */
00114     if (params->search_wordlistlen >= params->search_wordlistlenmax)
00115       break;
00116 
00117     /* the test is false only when reach the end-node */
00118     if (edgeptr->chr)
00119       {
00120 
00121         /* is the letter available in search_letters */
00122         if (params->search_letters[edgeptr->chr])
00123           {
00124             params->search_wordtst[i] = edgeptr->chr + 'A' - 1;
00125             params->search_letters[edgeptr->chr] --;
00126             if (i == params->search_len)
00127               {
00128                 if ((edgeptr->term)
00129                   /* && (params->search_wordlistlen < params->search_wordlistlenmax) */)
00130                   strcpy((*params->search_wordlist)[params->search_wordlistlen++],params->search_wordtst);
00131               }
00132             else /* if (params->search_wordlistlen < params->search_wordlistlenmax) */
00133               {
00134                 Dic_search_word_by_len(params,i + 1, params->search_dic->dawg + edgeptr->ptr);
00135               }
00136             params->search_letters[edgeptr->chr] ++;
00137             params->search_wordtst[i] = '\0';
00138           }
00139 
00140         /* the letter is of course available if we have a joker available */
00141         if (params->search_letters[0])
00142           {
00143             params->search_wordtst[i] = edgeptr->chr + 'a' - 1;
00144             params->search_letters[0] --;
00145             if (i == params->search_len)
00146               {
00147                 if ((edgeptr->term)
00148                      /* && (params->search_wordlistlen < params->search_wordlistlenmax) */)
00149                   strcpy((*(params->search_wordlist))[params->search_wordlistlen++],params->search_wordtst);
00150               }
00151             else /* if (params->search_wordlistlen < params->search_wordlistlenmax) */
00152               {
00153                 Dic_search_word_by_len(params,i + 1,params->search_dic->dawg + edgeptr->ptr);
00154               }
00155             params->search_letters[0] ++;
00156             params->search_wordtst[i] = '\0';
00157           }
00158       }
00159   } while (! (*edgeptr++).last);
00160 }
00161 
00162 void
00163 Dic_search_7pl1(const Dictionary dic, const char* rack,
00164                 char buff[DIC_LETTERS][RES_7PL1_MAX][DIC_WORD_MAX],
00165                 int joker)
00166 {
00167   int i,j,wordlen;
00168   const char* r = rack;
00169   struct params_7plus1_t params;
00170   Dawg_edge *root_edge;
00171 
00172   for(i=0; i < DIC_LETTERS; i++)
00173     for(j=0; j < RES_7PL1_MAX; j++)
00174       buff[i][j][0] = '\0';
00175 
00176   for(i=0; i<DIC_LETTERS; i++)
00177     params.search_letters[i] = 0;
00178 
00179   if (dic == NULL || rack == NULL)
00180     return;
00181 
00182   /*
00183    * the letters are verified and changed to the dic internal
00184    * representation (*r & DIC_CHAR_MASK)
00185    */
00186   for(wordlen=0; wordlen < DIC_WORD_MAX && *r; r++)
00187     {
00188       if (isalpha(*r))
00189         {
00190           params.search_letters[(int)*r & DIC_CHAR_MASK]++;
00191           wordlen++;
00192         }
00193       else if (*r == '?')
00194         {
00195           if (joker)
00196             {
00197               params.search_letters[0]++;
00198               wordlen++;
00199             }
00200           else
00201             {
00202               strncpy(buff[0][0],"** joker **",DIC_WORD_MAX);
00203               return;
00204             }
00205         }
00206     }
00207 
00208   if (wordlen < 1)
00209     return;
00210 
00211   root_edge = dic->dawg + (dic->dawg[dic->root].ptr);
00212 
00213   params.search_dic = dic;
00214   params.search_wordlistlenmax = RES_7PL1_MAX;
00215 
00216   /* search for all the words that can be done with the letters */
00217   params.search_len = wordlen - 1;
00218   params.search_wordtst[wordlen]='\0';
00219   params.search_wordlist = & buff[0];
00220   params.search_wordlistlen = 0;
00221   Dic_search_word_by_len(&params,0,root_edge);
00222 
00223   /* search for all the words that can be done with the letters +1 */
00224   params.search_len = wordlen;
00225   params.search_wordtst[wordlen + 1]='\0';
00226   for(i='a'; i <= 'z'; i++)
00227     {
00228       params.search_letters[i & DIC_CHAR_MASK]++;
00229 
00230       params.search_wordlist = & buff[i & DIC_CHAR_MASK];
00231       params.search_wordlistlen = 0;
00232       Dic_search_word_by_len(&params,0,root_edge);
00233 
00234       params.search_letters[i & DIC_CHAR_MASK]--;
00235     }
00236 }
00237 
00238 /****************************************/
00239 /****************************************/
00240 
00241 void
00242 Dic_search_Racc(const Dictionary dic, const char* word,
00243                 char wordlist[RES_RACC_MAX][DIC_WORD_MAX])
00244 {
00245   /* search_racc will try to add a letter in front and at the end of a word */
00246 
00247   int i,wordlistlen;
00248   Dawg_edge *edge;
00249   char wordtst[DIC_WORD_MAX];
00250 
00251   for(i=0; i < RES_RACC_MAX; i++)
00252     wordlist[i][0] = 0;
00253 
00254   if (dic == NULL || wordlist == NULL)
00255     return;
00256 
00257   /* let's try for the front */
00258   wordlistlen = 0;
00259   strcpy(wordtst+1,word);
00260   for(i='a'; i <= 'z'; i++)
00261     {
00262       wordtst[0] = i;
00263       if (Dic_search_word(dic,wordtst) && wordlistlen < RES_RACC_MAX)
00264         strcpy(wordlist[wordlistlen++],wordtst);
00265     }
00266 
00267   /* add a letter at the end */
00268   for(i=0; word[i]; i++)
00269     wordtst[i] = word[i];
00270 
00271   wordtst[i  ] = '\0';
00272   wordtst[i+1] = '\0';
00273 
00274   edge = Dic_seek_edgeptr(dic,word,dic->dawg + dic->root);
00275 
00276   /* points to what the next letter can be */
00277   edge = dic->dawg + edge->ptr;
00278 
00279   if (edge != dic->dawg)
00280     {
00281       do {
00282           if (edge->term && wordlistlen < RES_RACC_MAX)
00283             {
00284               wordtst[i] = edge->chr + 'a' - 1;
00285               strcpy(wordlist[wordlistlen++],wordtst);
00286             }
00287       } while (!(*edge++).last);
00288     }
00289 }
00290 
00291 /****************************************/
00292 /****************************************/
00293 
00294 
00295 void
00296 Dic_search_Benj(const Dictionary dic, const char* word,
00297                 char wordlist[RES_BENJ_MAX][DIC_WORD_MAX])
00298 {
00299   int i,wordlistlen;
00300   char wordtst[DIC_WORD_MAX];
00301   Dawg_edge *edge0,*edge1,*edge2,*edgetst;
00302 
00303   for(i=0; i < RES_BENJ_MAX; i++)
00304     wordlist[i][0] = 0;
00305 
00306   if (dic == NULL || word == NULL)
00307     return;
00308 
00309   wordlistlen = 0;
00310 
00311   strcpy(wordtst+3,word);
00312   edge0 = dic->dawg + (dic->dawg[dic->root].ptr);
00313   do {
00314     wordtst[0] = edge0->chr + 'a' - 1;
00315     edge1 = dic->dawg + edge0->ptr;
00316     do {
00317       wordtst[1] = edge1->chr + 'a' - 1;
00318       edge2  = dic->dawg + edge1->ptr;
00319       do {
00320         wordtst[2] = edge2->chr + 'a' - 1;
00321         edgetst = Dic_seek_edgeptr(dic,word,edge2);
00322         if (edgetst->term && wordlistlen < RES_BENJ_MAX)
00323           strcpy(wordlist[wordlistlen++],wordtst);
00324       } while (!(*edge2++).last);
00325     } while (!(*edge1++).last);
00326   } while (!(*edge0++).last);
00327 }
00328 
00329 
00330 /****************************************/
00331 /****************************************/
00332 
00333 struct params_cross_t {
00334  Dictionary dic;
00335  int wordlen;
00336  int wordlistlen;
00337  int wordlistlenmax;
00338  char mask[DIC_WORD_MAX];
00339 };
00340 
00341 
00342 void
00343 Dic_search_cross_rec(struct params_cross_t *params,
00344                      char wordlist[RES_CROS_MAX][DIC_WORD_MAX],
00345                      Dawg_edge *edgeptr)
00346 {
00347   Dawg_edge *current = params->dic->dawg + edgeptr->ptr;
00348 
00349   if (params->mask[params->wordlen] == '\0' && edgeptr->term)
00350     {
00351       if (params->wordlistlen < params->wordlistlenmax)
00352         strcpy(wordlist[params->wordlistlen++],params->mask);
00353     }
00354   else if (params->mask[params->wordlen] == '.')
00355     {
00356       do
00357         {
00358           params->mask[params->wordlen] = current->chr + 'a' - 1;
00359           params->wordlen ++;
00360           Dic_search_cross_rec(params,wordlist,current);
00361           params->wordlen --;
00362           params->mask[params->wordlen] = '.';
00363         }
00364       while (!(*current++).last);
00365     }
00366   else
00367     {
00368       do
00369         {
00370           if (current->chr == (unsigned int)(params->mask[params->wordlen] & DIC_CHAR_MASK))
00371             {
00372               params->wordlen ++;
00373               Dic_search_cross_rec(params,wordlist,current);
00374               params->wordlen --;
00375               break;
00376             }
00377         }
00378       while (!(*current++).last);
00379     }
00380 }
00381 
00382 
00383 
00384 void
00385 Dic_search_Cros(const Dictionary dic, const char* mask,
00386                 char wordlist[RES_CROS_MAX][DIC_WORD_MAX])
00387 {
00388   int  i;
00389   struct params_cross_t params;
00390 
00391   for(i=0; i < RES_CROS_MAX; i++)
00392     wordlist[i][0] = 0;
00393 
00394   if (dic == NULL || mask == NULL)
00395     return;
00396 
00397   for(i=0; i < DIC_WORD_MAX && mask[i]; i++)
00398     {
00399       if (isalpha(mask[i]))
00400         params.mask[i] = (mask[i] & DIC_CHAR_MASK) + 'A' - 1;
00401       else
00402         params.mask[i] = '.';
00403     }
00404   params.mask[i] = '\0';
00405 
00406   params.dic            = dic;
00407   params.wordlen        = 0;
00408   params.wordlistlen    = 0;
00409   params.wordlistlenmax = RES_CROS_MAX;
00410   Dic_search_cross_rec(&params, wordlist, dic->dawg + dic->root);
00411 }
00412 
00413 /****************************************/
00414 /****************************************/
00415 
00416 struct params_regexp_t {
00417   Dictionary dic;
00418   int minlength;
00419   int maxlength;
00420   automaton automaton;
00421   struct search_RegE_list_t *charlist;
00422   char word[DIC_WORD_MAX];
00423   int  wordlen;
00424   int  wordlistlen;
00425   int  wordlistlenmax;
00426 };
00427 
00428 void
00429 Dic_search_regexp_rec(struct params_regexp_t *params,
00430                       int state,
00431                       Dawg_edge *edgeptr,
00432                       char wordlist[RES_REGE_MAX][DIC_WORD_MAX])
00433 {
00434   int next_state;
00435   Dawg_edge *current;
00436   /* if we have a valid word we store it */
00437   if (automaton_get_accept(params->automaton,state) && edgeptr->term)
00438     {
00439       int l = strlen(params->word);
00440       if (params->wordlistlen < params->wordlistlenmax &&
00441           params->minlength <= l                        &&
00442           params->maxlength >= l)
00443         {
00444           strcpy(wordlist[params->wordlistlen++],params->word);
00445         }
00446     }
00447   /* we now drive the search by exploring the dictionary */
00448   current = params->dic->dawg + edgeptr->ptr;
00449   do {
00450     /* the current letter is current->chr */
00451     next_state = automaton_get_next_state(params->automaton,state,current->chr);
00452     /* 1 : the letter appears in the automaton as is */
00453     if (next_state)
00454       {
00455         params->word[params->wordlen] = current->chr + 'a' - 1;
00456         params->wordlen ++;
00457         Dic_search_regexp_rec(params,next_state,current,wordlist);
00458         params->wordlen --;
00459         params->word[params->wordlen] = '\0';
00460       }
00461   } while (!(*current++).last);
00462 }
00463 
00464 
00465     /**
00466      * function prototype for parser generated by bison
00467      */
00468 int  regexpparse(yyscan_t scanner, NODE** root,
00469                  struct search_RegE_list_t *list,
00470                  struct regexp_error_report_t *err);
00471 
00472 void
00473 Dic_search_RegE(const Dictionary dic, const char* re,
00474                 char wordlist[RES_REGE_MAX][DIC_WORD_MAX],
00475                 struct search_RegE_list_t *list)
00476 {
00477   int i,p,n,value;
00478   int ptl[REGEXP_MAX+1];
00479   int PS [REGEXP_MAX+1];
00480   NODE* root;
00481   yyscan_t scanner;
00482   YY_BUFFER_STATE buf;
00483   automaton a;
00484   char stringbuf[250];
00485   struct params_regexp_t params;
00486   struct regexp_error_report_t report;
00487 
00488   /* init */
00489   for(i=0; i < RES_REGE_MAX; i++)
00490     wordlist[i][0] = 0;
00491 
00492   if (dic == NULL || re == NULL)
00493     return;
00494 
00495   /* (expr)# */
00496   sprintf(stringbuf,"(%s)#",re);
00497   for(i=0; i < REGEXP_MAX; i++)
00498     {
00499       PS[i] = 0;
00500       ptl[i] = 0;
00501     }
00502 
00503   report.pos1 = 0;
00504   report.pos2 = 0;
00505   report.msg[0] = '\0';
00506 
00507   /* parsing */
00508   regexplex_init( &scanner );
00509   buf   = regexp_scan_string( stringbuf, scanner );
00510   root  = NULL;
00511   value = regexpparse( scanner , &root, list, &report);
00512   regexp_delete_buffer(buf,scanner);
00513   regexplex_destroy( scanner );
00514 
00515   if (value)
00516     {
00517 #ifdef DEBUG_FLEX_IS_BROKEN
00518       fprintf(stderr,"parser error at pos %d - %d : %s\n",
00519               report.pos1, report.pos2, report.msg);
00520 #endif
00521       regexp_delete_tree(root);
00522       return ;
00523     }
00524 
00525   n = 1;
00526   p = 1;
00527   regexp_parcours(root, &p, &n, ptl);
00528   PS [0] = p - 1;
00529   ptl[0] = p - 1;
00530 
00531   regexp_possuivante(root,PS);
00532 
00533   if ((a = automaton_build(root->PP,ptl,PS,list)) != NULL)
00534     {
00535       params.dic            = dic;
00536       params.minlength      = list->minlength;
00537       params.maxlength      = list->maxlength;
00538       params.automaton      = a;
00539       params.charlist       = list;
00540       memset(params.word,'\0',sizeof(params.word));
00541       params.wordlen        = 0;
00542       params.wordlistlen    = 0;
00543       params.wordlistlenmax = RES_REGE_MAX;
00544       Dic_search_regexp_rec(&params, automaton_get_init(a), dic->dawg + dic->root, wordlist);
00545 
00546       automaton_delete(a);
00547     }
00548   regexp_delete_tree(root);
00549 }
00550 
00551 /****************************************/
00552 /****************************************/
00553 

Generated on Thu Dec 29 02:01:14 2005 for Eliot by  doxygen 1.4.5