fsa_mngr.c

Go to the documentation of this file.
00001 /******************************************************************************
00002  *                                S Y N T A X
00003  *-----------------------------------------------------------------------------
00004  *   Copyright (C) 1972-2008 INRIA (Institut National de Recherche en
00005  *   Informatique et Automatique)
00006  *-----------------------------------------------------------------------------
00007  *   URL: http://syntax.gforge.inria.fr
00008  *-----------------------------------------------------------------------------
00009  *   The source code of SYNTAX is distributed with two different licenses,
00010  *   depending on the files:
00011  *   - The recursive content of src/ and incl/ and the non-recursive content
00012  *     of SYNTAX's root directory are distributed under the CeCILL-C license
00013  *   - The recursive content of all other repertories is distributed under
00014  *     the CeCILL license
00015  *   All code produced by SYNTAX must be considered as being under the
00016  *   CeCILL-C license. Information about the CeCILL and CeCILL-C licenses
00017  *   can be found at, e.g., http://www.cecill.fr
00018  *****************************************************************************/
00019 
00020 
00021 
00022 #include "sxversion.h"
00023 #include "sxunix.h"
00024 
00025 char WHAT_SXDAG_MNGR[] = "@(#)SYNTAX - $Id: fsa_mngr.c 1743 2009-06-08 13:32:55Z sagot $" WHAT_DEBUG;
00026 
00027 static char ME [] = "fsa_mngr";
00028 
00029 #include "varstr.h"
00030 #include "XxY.h"
00031 #include "XxYxZ.h"
00032 #include "fsa.h"
00033 #include "sxstack.h"
00034 #include "XH.h"
00035 #include "sxdico.h"
00036 
00037 
00038 static SXINT     *old_state2max_path_lgth, *old_state2new_state /*, normalized_fsa_final_state */;
00039 static SXBA      state_set;
00040 static void      (*normalized_fsa_fill_trans)(SXINT , SXINT, SXINT);
00041 static void      (*normalized_fsa_forward_trans) (SXINT , void (*fill_old_state2max_path_lgth)(SXINT, SXINT, SXINT) );
00042 static SXBOOLEAN   normalized_is_cyclic;
00043 
00044 static void
00045 fill_old_state2max_path_lgth (SXINT prev_old_state, SXINT t, SXINT next_old_state)
00046 {
00047   SXINT old_prev_max_path_lgth, old_next_max_path_lgth;
00048 
00049   sxuse (t);
00050   if (SXBA_bit_is_reset_set (state_set, next_old_state)) {
00051     /* Pas de cycle sur next_old_state */
00052     old_prev_max_path_lgth = old_state2max_path_lgth [prev_old_state];
00053     old_next_max_path_lgth = old_state2max_path_lgth [next_old_state];
00054 
00055     if (old_next_max_path_lgth == 0 || old_next_max_path_lgth <= old_prev_max_path_lgth) {
00056       /* C'est la 1ere fois qu'on tombe sur next_old_state */
00057       /* On a deja atteint next_old_state par un autre chemin "normal" mais plus court... */
00058       old_state2max_path_lgth [next_old_state] = old_prev_max_path_lgth+1;
00059       (*normalized_fsa_forward_trans)(next_old_state, fill_old_state2max_path_lgth);
00060     }
00061     /*
00062       else
00063       rien
00064     */
00065 
00066     SXBA_0_bit (state_set, next_old_state);
00067   }
00068   else {
00069     /*
00070       Detection d'un cycle ds l'automate
00071       On ne touche pas a old_state2max_path_lgth [next_old_state]
00072     */
00073     normalized_is_cyclic = SXTRUE;
00074   }
00075 }
00076 
00077 
00078 #if EBUG
00079 static void
00080 check_old_state2max_path_lgth (SXINT prev_old_state, SXINT t, SXINT next_old_state)
00081 {
00082   sxuse (t);
00083   if (old_state2max_path_lgth [prev_old_state] >= old_state2max_path_lgth [next_old_state])
00084     sxtrap (ME, "check_old_state2max_path_lgth (erroneous path length)");
00085 }
00086 #endif /* EBUG */
00087 
00088 static int
00089 cmp_old_state (const void *p1, const void *p2)
00090 {  
00091   SXINT state1, state2, lgth1, lgth2;
00092 
00093   /* The actual arguments to this function are "pointers to SXINT", hence the following cast plus dereference */
00094   state1 = (SXINT) * (SXINT * const *) p1;
00095   state2 = (SXINT) * (SXINT * const *) p2;
00096 
00097   lgth1 = old_state2max_path_lgth [state1];
00098   lgth2 = old_state2max_path_lgth [state2];
00099 
00100   return (lgth1 < lgth2) ? -1 /* Le nouvel etat de state1 va etre inferieur au nouvel etat de state2 */
00101     : ((lgth1 > lgth2) ? 1 /* Le nouvel etat de state1 va etre superieur au nouvel etat de state2 */
00102        : ((state1 < state2) ? -1 : 1) /* Ici state1 et state2 se trouvent a la meme distance de init_state (sur des chemins differents) On conserve l'ordre initial */
00103        );
00104 }
00105 
00106 
00107 static SXINT prev_from_new_state;
00108 static SXBA  to_new_state_set, *to_new_state2t_set;
00109 static SXINT *to_new_state2t;
00110 
00111 /* On accumule les trans depuis prev_from_new_state pour pouvoir les sortir par q croissant */
00112 static void
00113 save_a_trans (SXINT t, SXINT q)
00114 {
00115   SXINT old_t;
00116   SXBA  t_set;
00117 
00118   if (SXBA_bit_is_reset_set (to_new_state_set, q)) {
00119     to_new_state2t [q] = t;
00120   }
00121   else {
00122     /* transition multiple vers le meme q, on les trie par t croissant */
00123     old_t = to_new_state2t [q];
00124     t_set = to_new_state2t_set [q];
00125 
00126     if (old_t) {
00127       to_new_state2t [q] = 0;
00128       SXBA_1_bit (t_set, old_t);
00129       
00130     }
00131 
00132     SXBA_1_bit (t_set, t);
00133   }
00134 }
00135 
00136 static void
00137 output_from_prev (void)
00138 {
00139   SXINT q, t;
00140   SXBA  t_set;
00141 
00142   q = -1;
00143 
00144   while ((q = sxba_scan_reset (to_new_state_set, q)) >= 0) {
00145     if ((t = to_new_state2t [q]))
00146       (*normalized_fsa_fill_trans) (prev_from_new_state, t, q);
00147     else {
00148       t_set = to_new_state2t_set [q];
00149       t = -1;
00150 
00151       while ((t = sxba_scan_reset (t_set, t)) >= 0)
00152     (*normalized_fsa_fill_trans) (prev_from_new_state, t, q);
00153     }
00154   }
00155 }
00156 
00157 
00158 static SXINT
00159 output_new_trans (SXINT from_old_state, SXINT t, SXINT to_old_state)
00160 {
00161   SXINT        from_new_state, to_new_state;
00162 
00163   from_new_state = old_state2new_state [from_old_state];
00164   to_new_state = old_state2new_state [to_old_state];
00165 
00166   /*  if (to_new_state == normalized_fsa_final_state)
00167       t = -1;*/
00168 
00169   if (prev_from_new_state == from_new_state) {
00170     /* On a deja trouve' une transition depuis from_new_state */
00171   }
00172   else {
00173     /* 1ere trans depuis from_old_state */
00174     if (prev_from_new_state) {
00175       /* On traite donc les transitions depuis prev_from_new_state */
00176       output_from_prev ();
00177     }
00178 
00179     prev_from_new_state = from_new_state;
00180   }
00181 
00182   save_a_trans (t, to_new_state);
00183 
00184   return 1;
00185 }
00186 
00187 
00188 /* Permet une renumerotation raisonnable des etats d'un FSA a partir de init_state>= 0
00189    En particulier pour un DAG si p ->t q, on a p < q
00190 */
00191 /* fsa_forward_trans est la fonction de l'appelant qui permet de parcourir le vieil FSA 
00192    fsa_fill_trans permet de construire le FSA renumerote' */
00193 /* (*fsa_forward_trans)(p, f)  appelle (*f)(p, t, q) pour tout p ->t q
00194    Pour les valeurs croissantes de p', fsa_normalize () appelle (*fsa_fill_trans)(p', t', q') pour toute transition p' ->t' q' renumerotee
00195 */
00196 void
00197 fsa_normalize (SXINT init_state, 
00198            SXINT final_state, 
00199            SXINT eof_ste,
00200            void (*fsa_forward_trans)(SXINT, void (*)(SXINT, SXINT, SXINT)), 
00201            void (*fsa_fill_trans)(SXINT, SXINT, SXINT)
00202 #ifdef ESSAI_INVERSE_MAPPING
00203            , SXINT *new_state2old_state
00204 #endif /* ESSAI_INVERSE_MAPPING */
00205            )
00206 {
00207   SXINT state, new_state;
00208   SXINT *to_be_sorted;
00209 
00210   normalized_fsa_forward_trans = fsa_forward_trans;
00211   normalized_fsa_fill_trans = fsa_fill_trans;
00212   /*  normalized_fsa_final_state = final_state;*/
00213 
00214   old_state2max_path_lgth = (SXINT*) sxcalloc (final_state+1, sizeof (SXINT));
00215   state_set = sxba_calloc (final_state+1);
00216 
00217   SXBA_1_bit (state_set, init_state);
00218   old_state2max_path_lgth [init_state] = 1; /* pour reserver 0 a non encore traite' */
00219 
00220   /* On calcule la longueur maximale des chemins qui conduisent depuis l'etat initial a chaque etat de l'automate ... */
00221   normalized_is_cyclic = SXFALSE;
00222   (*normalized_fsa_forward_trans)(init_state, fill_old_state2max_path_lgth);
00223 
00224   /* Attention, si l'automate en entree contient des cycles (c'est pas un DAG), l'algo precedent n'assure pas
00225      que l'etat final sera a` la distance max de l'etat initial, on y remedie */
00226   old_state2max_path_lgth [final_state] = final_state;
00227 
00228 #if EBUG
00229   /* petite verif */
00230   if (!normalized_is_cyclic)
00231     (*normalized_fsa_forward_trans)(init_state, check_old_state2max_path_lgth);
00232 #endif /* EBUG */
00233 
00234   /* ... On trie ces etats par ces longueurs ... */
00235   sxfree (state_set), state_set = NULL;
00236 
00237 #ifdef ESSAI_INVERSE_MAPPING
00238   if (new_state2old_state)
00239     to_be_sorted = new_state2old_state;
00240   else
00241     to_be_sorted = (SXINT*) sxalloc (final_state+1, sizeof (SXINT));
00242 #else /* ESSAI_INVERSE_MAPPING */
00243   to_be_sorted = (SXINT*) sxalloc (final_state+1, sizeof (SXINT));
00244 #endif /* ESSAI_INVERSE_MAPPING */
00245 
00246   for (state = 0; state <= final_state; state++)
00247     to_be_sorted [state] = state;
00248 
00249   /* Ici old_state2max_path_lgth est rempli, on va donc trier */
00250   /*
00251     NAME
00252     qsort - sorts an array
00253 
00254     SYNOPSIS
00255     #include <stdlib.h>
00256 
00257     void qsort(void *base, size_t nmemb, size_t size,
00258     int(*compar)(const void *, const void *));
00259 
00260     DESCRIPTION
00261     The  qsort()  function sorts an array with nmemb elements of size size.
00262     The base argument points to the start of the array.
00263 
00264     The contents of the array are sorted in ascending order according to  a
00265     comparison  function  pointed  to  by  compar, which is called with two
00266     arguments that point to the objects being compared.
00267 
00268     The comparison function must return an integer less than, equal to,  or
00269     greater  than  zero  if  the first argument is considered to be respec-
00270     tively less than, equal to, or greater than the second.  If two members
00271     compare as equal, their order in the sorted array is undefined.
00272 
00273     RETURN VALUE
00274     The qsort() function returns no value.
00275   */
00276 
00277   qsort(to_be_sorted+init_state, final_state-init_state+1, sizeof (SXINT), cmp_old_state);
00278 
00279   sxfree (old_state2max_path_lgth), old_state2max_path_lgth = NULL;
00280 
00281   /* Pour des questions d'ordre de sortie, on a besoin de la correspondance old_state -> new_state */
00282   old_state2new_state = (SXINT*) sxalloc (final_state+1, sizeof (SXINT));
00283 
00284   for (new_state = init_state; new_state <= final_state; new_state++) {
00285     state = to_be_sorted [new_state];
00286     old_state2new_state [state] = new_state;
00287   }
00288 
00289   /* ... et on sort l'automate "normalise' */
00290   /* par ordre croissant des etats d'origine de chaque transition (pour chaque p, on sort tous les p ->t q) */
00291   to_new_state_set = sxba_calloc (final_state+1);
00292   to_new_state2t = (SXINT *) sxalloc (final_state+1, sizeof (SXINT));
00293   to_new_state2t_set = sxbm_calloc (final_state+1, eof_ste+1);
00294 
00295   prev_from_new_state = 0;
00296 
00297   for (new_state = init_state; new_state < final_state; new_state++) {
00298     (*normalized_fsa_forward_trans)(to_be_sorted [new_state], (void (*)(SXINT, SXINT, SXINT))output_new_trans);
00299     /* nous utilisons un cast pour le pointeur de fonction 'output_new_trans' car son prototype
00300        ne correspond pas parfaitement a l'argument #2 de 'normalized_fsa_forward_trans' :
00301        il retourne 'SXINT' au lieu de 'void' */
00302   }
00303 
00304   /* ... Et les dernieres transitions */
00305   output_from_prev ();
00306 
00307   sxfree (to_new_state_set), to_new_state_set = NULL;
00308   sxfree (to_new_state2t), to_new_state2t = NULL;
00309   sxbm_free (to_new_state2t_set), to_new_state2t_set = NULL;
00310 
00311 #ifdef ESSAI_INVERSE_MAPPING
00312   if (new_state2old_state == NULL)
00313     sxfree (to_be_sorted), to_be_sorted = NULL;
00314 #else /* ESSAI_INVERSE_MAPPING */
00315   sxfree (to_be_sorted), to_be_sorted = NULL;
00316 #endif /* ESSAI_INVERSE_MAPPING */
00317 
00318   sxfree (old_state2new_state);
00319 }
00320 
00321 /* ******************************************* nfa2dfa ******************************************* */
00322 static SXINT        dfa_init_state, dfa_final_state;
00323 static SXBOOLEAN    (*nfa_empty_trans) (SXINT, SXBA);
00324 static SXINT        last_partition, dfa_state_nb;
00325 static SXINT        *nfa_ec_stack, *nfa_t_stack, *nfa_state_stack;
00326 static SXBA       nfa_wstate_set, t_set;
00327 static SXBA       *t2nfa_state_set;
00328 static XH_header  XH_dfa_states;
00329 
00330 
00331 static SXINT        *t2pos, *pos2state, *part_set_id2part;
00332 static XH_header  XH_trans_list_id, XH_t_trans, XH_part_set;
00333 static SXINT        *dfa_state2pred_nb;
00334 static XxY_header XxY_out_trans;
00335 static SXINT        *XxY_out_trans2next_state;
00336 static SXINT        **dfa_state2pred_stack;
00337 
00338 static struct state2attr {
00339   SXINT next_state, prev_state, part, init_part, trans_list_id, temp_id;
00340 } *state2attr;
00341 
00342 static struct part2attr {
00343   SXINT state, card, sub_card;
00344   SXINT *tbp_state_stack;
00345 } *part2attr;
00346 
00347 /* L'etat state change de partition et vient ds part */
00348 static void
00349 move (SXINT state, SXINT part)
00350 {
00351   SXINT               next_state, prev_state;
00352   struct state2attr *attr_ptr;
00353   struct part2attr  *old_part_ptr, *new_part_ptr;
00354 
00355   attr_ptr = state2attr+state;
00356   next_state = attr_ptr->next_state;
00357   prev_state = attr_ptr->prev_state;
00358   
00359   old_part_ptr = part2attr + attr_ptr->part;
00360 
00361   old_part_ptr->card--;
00362 
00363   if (prev_state == 0)
00364     old_part_ptr->state = next_state;
00365   else
00366     state2attr [prev_state].next_state = next_state;
00367 
00368   if (next_state)
00369     state2attr [next_state].prev_state = prev_state;
00370 
00371   new_part_ptr = part2attr + part;
00372   new_part_ptr->card++;
00373 
00374   next_state = new_part_ptr->state;
00375 
00376   new_part_ptr->state = state;
00377 
00378   attr_ptr->next_state = next_state;
00379   attr_ptr->prev_state = 0;
00380   state2attr [next_state].prev_state = state;
00381 
00382   attr_ptr->part = part;
00383 }
00384 
00385 
00386 /* On met l'etat state dans la partition part */
00387 static void
00388 init_set (SXINT state, SXINT part)
00389 {
00390   SXINT               old_state;
00391   struct state2attr *attr_ptr;
00392   struct part2attr  *part_ptr;
00393 
00394   part_ptr = part2attr + part;
00395   old_state = part_ptr->state;
00396   part_ptr->card++;
00397   part_ptr->state = state;
00398 
00399   attr_ptr = state2attr+state;
00400   attr_ptr->part = part;
00401   attr_ptr->next_state = old_state;
00402   attr_ptr->prev_state = 0;
00403 
00404   if (old_state)
00405     state2attr [old_state].prev_state = state;
00406 }
00407 
00408 
00409 /* On a un NFSA qui a des transitions vides */
00410 /* On passe en arg un ensembles d'etats, on complete cet ensemble avec les etats accessibles par transition vide
00411    l'ensemble des etats atteint par transition vide depuis l'etat p est donne' par (*empty_trans)(p, reached_set) */
00412 /* Retourne vrai ssi cur_state_set a change' */
00413 static SXBOOLEAN
00414 epsilon_closure (SXBA cur_state_set)
00415 {
00416   SXINT     state, next_state;
00417   SXBOOLEAN ret_val = SXFALSE;
00418 
00419   state = 0; /* et non nfa_init_state-1, car dans certains cas (DAG) on n'a pas la garantie qu'une transition i -t-> j vérifie i<j */
00420 
00421   while ((state = sxba_scan (cur_state_set, state)) >= 0)
00422     PUSH (nfa_ec_stack, state);
00423 
00424   while (!IS_EMPTY (nfa_ec_stack)) {
00425     state = POP (nfa_ec_stack);
00426 
00427     if ((*nfa_empty_trans)(state, nfa_wstate_set)) {
00428       /* wstate_set est non vide */
00429       next_state = 0; /* et non nfa_init_state-1, car dans certains cas (DAG) on n'a pas la garantie qu'une transition i -t-> j vérifie i<j */
00430 
00431       while ((next_state = sxba_scan_reset (nfa_wstate_set, next_state)) >= 0) {
00432     if (SXBA_bit_is_reset_set (cur_state_set, next_state)) {
00433       ret_val = SXTRUE;
00434       PUSH (nfa_ec_stack, next_state);
00435     }
00436       }
00437     }
00438   }
00439 
00440   return ret_val;
00441 }
00442 
00443 static void
00444 dfa_extract_trans (SXINT dfa_state, void (*dfa_fill_trans) (SXINT, SXINT, SXINT))
00445 {
00446   SXINT stateXt;
00447 
00448   XxY_Xforeach (XxY_out_trans, dfa_state, stateXt)
00449     (*dfa_fill_trans) (dfa_state, XxY_Y (XxY_out_trans, stateXt), XxY_out_trans2next_state [stateXt]);
00450 }
00451 
00452 static void
00453 dfa_fill_t_trans (SXINT dfa_state, SXINT t, SXINT next_dfa_state)
00454 {
00455   sxuse (dfa_state);
00456   sxuse (next_dfa_state);
00457   SXBA_1_bit (t_set, t);
00458 }
00459 
00460 static void
00461 dfa_fill_full_trans (SXINT dfa_state, SXINT t, SXINT next_dfa_state)
00462 {
00463   sxuse (dfa_state);
00464   pos2state [t2pos [t]] = next_dfa_state;
00465 
00466   if (dfa_state2pred_nb) {
00467     /* On en profite pour compter les predecesseurs de next_dfa_state */
00468     dfa_state2pred_nb [next_dfa_state]++;
00469     dfa_state2pred_nb [0]++;
00470   }
00471 }
00472 
00473 static void
00474 dfa_fill_dfa_state2pred_stack (SXINT dfa_state, SXINT t, SXINT next_dfa_state)
00475 {
00476   sxuse (t);
00477   PUSH (dfa_state2pred_stack [next_dfa_state], dfa_state);
00478 }
00479 
00480 static void
00481 fill_init_min (SXINT state, 
00482            void (*cur_dfa_extract_trans)(SXINT, void (*dfa_fill_t_trans) (SXINT dfa_state, SXINT t, SXINT next_dfa_state)))
00483 {
00484   SXINT t, pos, i, t_trans;
00485 
00486   (*cur_dfa_extract_trans)(state, dfa_fill_t_trans);
00487 
00488   t = -1;
00489   pos = 0;
00490 
00491   while ((t = sxba_scan_reset (t_set, t)) >= 0) {
00492     XH_push (XH_t_trans, t);
00493     t2pos [t] = ++pos;
00494   }
00495 
00496   XH_set (&XH_t_trans, &t_trans);
00497 
00498   (*cur_dfa_extract_trans)(state, dfa_fill_full_trans);
00499 
00500   XH_push (XH_trans_list_id, -t_trans);
00501 
00502   for (i = 1; i <= pos; i++)
00503     XH_push (XH_trans_list_id, pos2state [i]);
00504 
00505   /* A chaque etat state on lui associe la liste de ses successeurs ds un XH
00506      l'ordre des successeurs est donne' par l'ordre des terminaux des transitions
00507      chaque element d'un groupe a le meme ensemble de symboles terminaux, leurs successeurs
00508      peuvent donc se comparer simplement */
00509   XH_set (&XH_trans_list_id, &(state2attr [state].trans_list_id));
00510 
00511   state2attr [state].init_part = t_trans;
00512 }
00513 
00514 static void
00515 XH_part_set_oflw (SXINT old_size, SXINT new_size)
00516 {
00517   sxuse (old_size);
00518   part_set_id2part = (SXINT *) sxrealloc (part_set_id2part, new_size+1, sizeof (SXINT));
00519 }
00520 
00521 #if LLOG
00522 static SXINT configuration_nb;
00523 
00524 static void
00525 print_configuration (void)
00526 {
00527   SXINT part, state;
00528 
00529   printf ("\nConfiguration = %ld\n", (long) ++configuration_nb);
00530 
00531   for (part = 1; part <= last_partition; part++) {
00532     state = part2attr [part].state;
00533     printf ("Partition %ld = {%ld", (long)part, (long)state);
00534 
00535     while ((state = state2attr [state].next_state)) {
00536       printf (", %ld", (long)state);
00537     }
00538 
00539     fputs ("}\n", stdout);
00540   }
00541 }
00542 #endif /* LLOG */
00543 
00544 
00545 
00546 /* Structures qui sont utilisees par fsa2normalize appele' depuis dfa_minimize () */
00547 static SXINT **forward_stacks;
00548 
00549 static void
00550 forward (SXINT part, void (*f)(SXINT p, SXINT t, SXINT q))
00551 {
00552   SXINT next_part, t;
00553   SXINT *cur_forward_stack, *top_forward_stack;
00554 
00555   cur_forward_stack = forward_stacks [part];
00556   top_forward_stack = cur_forward_stack+TOP (cur_forward_stack);
00557 
00558   while (cur_forward_stack < top_forward_stack) {
00559     t = *++cur_forward_stack;
00560     next_part = *++cur_forward_stack;
00561     (*f)(part, t, next_part);
00562   }
00563 }
00564 
00565 
00566 /* Voici les resultats obtenus sur une RE dont le nb d'etats de l'automate deterministe est une exponentielle de la taille de la RE
00567 
00568 Cas ds lequel dfa_minimize utilise les transitions entrantes (dfa_state2pred_nb != NULL)
00569 echo "(a|b)*a(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)" | ./re2dfa.out
00570 "stdin":
00571 RE2NFA: state_nb = 21 (0ms)
00572 NFA2DFA: state_nb = 131074, total_trans_nb = 327682 (23581ms)
00573 constant_time_step_nb (with backward transitions) = DFA2min_DFA: state_nb = 131073, total_trans_nb = 327680 (1785ms)
00574 
00575 RE2EFNFA: state_nb = 35 (0ms)
00576 EFNFA2DFA: state_nb = 131073, total_trans_nb = 327680 (9364ms)
00577 constant_time_step_nb (with backward transitions) = 4718599
00578 EFDFA2min_DFA: state_nb = 131073, total_trans_nb = 327680 (1841ms)
00579 
00580 RE2DFA: state_nb = 131073 (13609ms)
00581 constant_time_step_nb (with backward transitions) = 4718599
00582 DFA2min_DFA: state_nb = 131073, total_trans_nb = 327680 (1857ms)
00583 
00584 
00585 Cas ds lequel dfa_minimize n'utilise pas les transitions entrantes (dfa_state2pred_nb == NULL)
00586 echo "(a|b)*a(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)(a|b)" | ./re2dfa.out
00587 "stdin":
00588 RE2NFA: state_nb = 21 (0ms)
00589 NFA2DFA: state_nb = 131074, total_trans_nb = 327682 (23565ms)
00590 constant_time_step_nb (without backward transitions) = 7888972
00591 DFA2min_DFA: state_nb = 131073, total_trans_nb = 327680 (2004ms)
00592 
00593 RE2EFNFA: state_nb = 35 (0ms)
00594 EFNFA2DFA: state_nb = 131073, total_trans_nb = 327680 (9364ms)
00595 constant_time_step_nb (without backward transitions) = 8086047
00596 EFDFA2min_DFA: state_nb = 131073, total_trans_nb = 327680 (2461ms)
00597 
00598 RE2DFA: state_nb = 131073 (13713ms)
00599 constant_time_step_nb (without backward transitions) = 8086047
00600 DFA2min_DFA: state_nb = 131073, total_trans_nb = 327680 (2977ms)
00601 
00602 Il semble que l'utilisation en "backward" des transitions entrantes soit plus rapide !!
00603 
00604 */
00605 
00606 /* Peut aussi s'appeler en stand alone */
00607 /* Algo "standard" on rafine les partitions */
00608 /* A partir d'une configuration initiale qui realise une partition de l'ensemble des etats avec la relation d'equiv :
00609    2 etats sont equiv ssi leurs transitions (t_set) sont egales
00610    L'algo assure qu'un etat est deplace' (change' de classe d'equiv) au plus log n fois
00611 */
00612 void
00613 dfa_minimize (SXINT cur_dfa_init_state, 
00614           SXINT cur_dfa_final_state, 
00615           SXINT eof_ste, 
00616           void (*cur_dfa_extract_trans)(SXINT, 
00617                         void (*dfa_fill_dfa_state2pred_stack) (SXINT dfa_state, 
00618                                            SXINT t, 
00619                                            SXINT next_dfa_state)), 
00620           void (*mindfa_fill_trans)(SXINT, SXINT, SXINT), 
00621           SXBOOLEAN to_be_normalized
00622 #ifdef ESSAI_INVERSE_MAPPING
00623           , struct inverse_mapping *inverse_mapping
00624 #endif /* ESSAI_INVERSE_MAPPING */
00625           )
00626 {
00627   SXINT                 state, next_state, partition, next_partition, bot, top, part_set_id, cur_part, bot2, t_trans, t, trans_list_id, new_part;
00628   SXINT                 size, pred_state, cur_state, next_part, cur_part_card, nb_max, id, nb, id_max, last_part_set_id, old_last_partition, last_new_part;
00629   SXINT                 *part2new_part, *new_part2part, *area, *base_area, *working_stack, *w2_stack;
00630   struct part2attr    *cur_part_ptr;
00631   struct state2attr   *cur_state_ptr;
00632 #if LOG
00633   SXINT                 constant_time_step_nb = 0;             
00634 #endif /* LOG */
00635 
00636   sxinitialise (id_max);
00637 
00638   XH_alloc (&XH_t_trans, "XH_t_trans", cur_dfa_final_state+1, 1, eof_ste, NULL, NULL);
00639 
00640   XH_alloc (&XH_trans_list_id, "XH_trans_list_id", cur_dfa_final_state+1, 1, eof_ste, NULL, NULL);
00641 
00642   XH_alloc (&XH_part_set, "XH_part_set", cur_dfa_final_state+1, 1, eof_ste, XH_part_set_oflw, NULL);
00643   part_set_id2part = (SXINT *) sxalloc (XH_size (XH_part_set)+1, sizeof (SXINT));
00644 
00645   working_stack = (SXINT*) sxalloc (2*cur_dfa_final_state+1, sizeof (SXINT)), working_stack [0] = 0;
00646 
00647   /* dfa_state2pred_nb = NULL; On n'a pas besoin des predecesseurs */
00648   dfa_state2pred_nb = (SXINT*) sxcalloc (cur_dfa_final_state+1, sizeof (SXINT)); /* On utilise les predecesseurs (voir commentaire de tete) */
00649 
00650   state2attr = (struct state2attr*) sxalloc (cur_dfa_final_state+1, sizeof (struct state2attr));
00651   part2attr = (struct part2attr*) sxcalloc (cur_dfa_final_state+1, sizeof (struct part2attr));
00652 
00653   w2_stack = (SXINT*) sxalloc (cur_dfa_final_state+1, sizeof (SXINT)), w2_stack [0] = 0;
00654 
00655   /* initialisation ... */
00656   last_partition = 0;
00657 
00658   t2pos = (SXINT *) sxalloc (eof_ste+1, sizeof (SXINT));
00659   pos2state = (SXINT *) sxalloc (eof_ste+1, sizeof (SXINT));
00660   t_set = sxba_calloc (eof_ste+1);
00661 
00662   for (state = cur_dfa_init_state; state <= cur_dfa_final_state ; state++) {
00663     fill_init_min (state, cur_dfa_extract_trans);
00664   }
00665 
00666   sxfree (t_set), t_set = NULL;
00667   sxfree (t2pos), t2pos = NULL;
00668   sxfree (pos2state), pos2state = NULL;
00669 
00670   /* Ici chaque etat a recu une "partition" pre_initiale qui est son t_trans On fabrique une vraie partition initiale */
00671   for (state = cur_dfa_init_state; state <= cur_dfa_final_state ; state++) {
00672     trans_list_id = state2attr [state].trans_list_id;
00673     bot = XH_X (XH_trans_list_id, trans_list_id);
00674     top = XH_X (XH_trans_list_id, trans_list_id+1);
00675 
00676     t_trans = XH_list_elem (XH_trans_list_id, bot++);
00677     XH_push (XH_part_set, t_trans);
00678 
00679     while (bot < top) {
00680       next_state = XH_list_elem (XH_trans_list_id, bot);
00681       next_part = state2attr [next_state].init_part;
00682       XH_push (XH_part_set, -next_part); /* Il ne faut pas les confondre plus tard avec des "vraies" partition */
00683 
00684       bot++;
00685     }
00686       
00687     if (!XH_set (&XH_part_set, &part_set_id))
00688       /* Nouveau */
00689       part_set_id2part [part_set_id] = next_part = ++last_partition;
00690     else
00691       next_part = part_set_id2part [part_set_id];
00692 
00693     /* On installe state ds next_part */
00694     init_set (state, next_part);
00695   }
00696 
00697 #if LLOG
00698   configuration_nb = 0;
00699 #endif /* LLOG */
00700     
00701   dfa_state2pred_stack = NULL;
00702   base_area = NULL;
00703 
00704   if (dfa_state2pred_nb) {
00705     SXINT              pred_part, cur_last_partition, cur_part_sub_card;
00706     SXINT              *w_state_stack, *top_state_ptr, *state_ptr, *tbp_part_stack, *tbp_state_stacks, *tbp_state_stack, *top_part_ptr, *part_ptr, *pred_stack;
00707     SXBA             w_state_set;
00708     struct part2attr *pred_part_ptr;
00709 
00710     /* version de minimize dans laquelle on a besoin des predecesseurs */
00711     size = dfa_state2pred_nb [0] + cur_dfa_final_state /* les comptes */;
00712 
00713     dfa_state2pred_stack = (SXINT **) sxalloc (cur_dfa_final_state+1, sizeof (SXINT*));
00714     area = base_area = (SXINT*) sxalloc (size+1, sizeof (SXINT));
00715     w_state_set = sxba_calloc (cur_dfa_final_state+1);
00716     w_state_stack = (SXINT *) sxalloc (cur_dfa_final_state+1, sizeof (SXINT));
00717     tbp_part_stack = (SXINT *) sxalloc (cur_dfa_final_state+1, sizeof (SXINT)), RAZ (tbp_part_stack);
00718     tbp_state_stacks = (SXINT *) sxalloc (2*cur_dfa_final_state+1, sizeof (SXINT)), RAZ (tbp_state_stacks);
00719 
00720     sxba_fill (w_state_set), SXBA_0_bit (w_state_set, 0);
00721     w_state_stack [0] = cur_dfa_final_state;
00722 
00723     for (state = 1; state <= cur_dfa_final_state; state++) {
00724       w_state_stack [state] = state; /* PUSH */
00725       dfa_state2pred_stack [state] = area;
00726       *area = 0;
00727       area += dfa_state2pred_nb [state]+1;
00728     }
00729 
00730     for (state = cur_dfa_init_state; state </*=*/ cur_dfa_final_state ; state++)
00731       /* On remplit dfa_state2pred_stack */
00732       (*cur_dfa_extract_trans)(state, dfa_fill_dfa_state2pred_stack);
00733 
00734     sxfree (dfa_state2pred_nb), dfa_state2pred_nb = NULL;
00735 
00736     for(;;) {
00737 #if LLOG
00738       print_configuration ();
00739 #endif /* LLOG */
00740 
00741       /* Ici, les etats a traiter ont ete mis ds (w_state_stack, w_state_set) */
00742       /* On decoupe les etats a traiter par leur appartenance a la meme partition */
00743       top_state_ptr = w_state_stack+TOP(w_state_stack);
00744 
00745       /* On compte */
00746       for (state_ptr = top_state_ptr; state_ptr > w_state_stack; state_ptr--) {
00747     pred_state = *state_ptr;
00748     pred_part = state2attr [pred_state].part;
00749 
00750     if (part2attr [pred_part].sub_card++ == 0) {
00751       /* 1ere fois que pred_part est trouve' */
00752       PUSH (tbp_part_stack, pred_part);
00753     }
00754       }
00755     
00756       /* On prepare les piles */
00757       RAZ (tbp_state_stacks);
00758 
00759       top_part_ptr = tbp_part_stack+TOP(tbp_part_stack);
00760 
00761       for (part_ptr = top_part_ptr; part_ptr > tbp_part_stack; part_ptr--) {
00762     pred_part_ptr = part2attr + *part_ptr;
00763     PUSH (tbp_state_stacks, 0);
00764     pred_part_ptr->tbp_state_stack = tbp_state_stacks + TOP (tbp_state_stacks);
00765     TOP (tbp_state_stacks) += pred_part_ptr->sub_card;
00766     pred_part_ptr->sub_card = 0;
00767       }
00768 
00769       /* On stocke */
00770       for (state_ptr = top_state_ptr; state_ptr > w_state_stack; state_ptr--) {
00771     pred_state = *state_ptr;
00772     SXBA_0_bit (w_state_set, pred_state);
00773     pred_part = state2attr [pred_state].part;
00774     tbp_state_stack = part2attr [pred_part].tbp_state_stack;
00775     PUSH (tbp_state_stack, pred_state);
00776       }
00777 
00778       RAZ (w_state_stack);
00779 
00780       /* On traite */
00781       cur_last_partition = last_partition;
00782 
00783       while (!IS_EMPTY (tbp_part_stack)) {
00784 #if LOG
00785     constant_time_step_nb++;             
00786 #endif /* LOG */
00787     cur_part = POP (tbp_part_stack);
00788     cur_part_ptr = part2attr+cur_part;
00789     cur_part_card = cur_part_ptr->card;
00790 
00791     if (cur_part_card > 1) {
00792       tbp_state_stack = cur_part_ptr->tbp_state_stack;
00793       cur_part_sub_card = TOP (tbp_state_stack);
00794 #if EBUG
00795       if (cur_part_sub_card > cur_part_card)
00796         sxtrap (ME, "dfa_minimize");
00797 #endif /* EBUG */
00798 
00799       RAZ (w2_stack);
00800       nb_max = cur_part_card-cur_part_sub_card;
00801       PUSH (w2_stack, nb_max); /* Pour les etats dont les successeurs n'ont pas bouge's */
00802       id_max = 1; /* Le TOP */
00803       last_part_set_id = XH_top (XH_part_set)-1;
00804     
00805       for (state_ptr = tbp_state_stack+TOP(tbp_state_stack); state_ptr > tbp_state_stack; state_ptr--) {
00806         cur_state = *state_ptr;
00807         cur_state_ptr = state2attr + cur_state;
00808 
00809         /* On recalcule ses etats successeurs */
00810         trans_list_id = cur_state_ptr->trans_list_id;
00811         bot = XH_X (XH_trans_list_id, trans_list_id);
00812         top = XH_X (XH_trans_list_id, trans_list_id+1);
00813 
00814         t_trans = XH_list_elem (XH_trans_list_id, bot++);
00815         XH_push (XH_part_set, t_trans);
00816 
00817         while (bot < top) {
00818 #if LOG
00819           constant_time_step_nb++;             
00820 #endif /* LOG */
00821           next_state = XH_list_elem (XH_trans_list_id, bot);
00822           next_partition = state2attr [next_state].part;
00823           XH_push (XH_part_set, next_partition);
00824 
00825           bot++;
00826         }
00827 
00828         if (!XH_set (&XH_part_set, &part_set_id)) {
00829           /* Nouveau */
00830           PUSH (w2_stack, 0);
00831           id = TOP (w2_stack);
00832 
00833 #if EBUG 
00834           if (TOP (w2_stack) != part_set_id-last_part_set_id+1)
00835         sxtrap (ME, "dfa_minimize");
00836 #endif /* EBUG */
00837         }
00838         else {
00839           id = (part_set_id <= last_part_set_id) ? 1 : part_set_id-last_part_set_id+1;
00840         }
00841 
00842         nb = ++(w2_stack [id]);
00843 
00844         if (nb > nb_max) {
00845           nb_max = nb;
00846           id_max = id;
00847         }
00848 
00849         cur_state_ptr->temp_id = part_set_id;
00850       }
00851 
00852       /* Si nb_max == cur_part_card, on ne change rien */
00853       if (nb_max < cur_part_card) {
00854         old_last_partition = last_partition;
00855 
00856         /* Ds cur_part on ne va pas deplacer le + grand groupe =>
00857            chacun des groupes deplaces a une taille bornee par cur_part_card/2 */
00858 
00859         /* C'est le sous-groupe qui n'a pas ete touche' qui est le plus populaire
00860            On deplace les etats du complementaire ... */
00861         for (state_ptr = tbp_state_stack+TOP(tbp_state_stack); state_ptr > tbp_state_stack; state_ptr--) {
00862 #if LOG
00863           constant_time_step_nb++;             
00864 #endif /* LOG */
00865           cur_state = *state_ptr;
00866 
00867           if (id_max != 1 && w2_stack [1] != 0)
00868         /* Etat implique' par le rafinement precedant */
00869         SXBA_1_bit (w_state_set, cur_state);
00870 
00871           cur_state_ptr = state2attr + cur_state;
00872           part_set_id = cur_state_ptr->temp_id;
00873           id = (part_set_id <= last_part_set_id) ? 1 : part_set_id-last_part_set_id+1;
00874 
00875           if (id != id_max) {
00876         /* On bouge cur_state */
00877         if ((next_part = w2_stack [id]) > 0) {
00878           /* 1ere fois */
00879           next_part = ++last_partition;
00880           w2_stack [id] = -next_part; /* Pour les coups d'apres */
00881         }
00882         else
00883           next_part = -next_part;
00884 
00885         /* cur_state est change' de partition */
00886         /* Ce changement ne peut etre valide' au cours de ce run, il le sera + tard sinon les futurs calculs ds XH_part_set peuvent etre faux */
00887         /* state2part [cur_state] = next_part; doit etre retarde' sinon les futurs calculs ds  XH_part_set peuvent etre faux */
00888         PUSH (working_stack, cur_state);
00889         PUSH (working_stack, next_part);
00890           }
00891           else
00892         /* On ne bouge pas la sous-part maximale */
00893         next_part = cur_part;
00894 
00895 #if EBUG
00896           if (next_part != cur_part && next_part <= old_last_partition)
00897         sxtrap (ME, "dfa_minimize");
00898 #endif /* EBUG */
00899 
00900           /* part_set_id2part [part_set_id] = next_part; semble inutile */
00901         }
00902         
00903         if (id_max != 1 && w2_stack [1] != 0) {
00904           /* Le sous-groupe non touche' par le rafinement pre'ce'dant n'est pas le plus populaire, il va donc etre de'place' aussi car il est non vide */
00905           next_part = ++last_partition;
00906 
00907           for (cur_state = cur_part_ptr->state; cur_state != 0; cur_state = state2attr [cur_state].next_state) { 
00908         if (!SXBA_bit_is_set_reset (w_state_set, cur_state)) {
00909           PUSH (working_stack, cur_state);
00910           PUSH (working_stack, next_part);
00911         }
00912           }
00913         }
00914       }
00915     }
00916       }
00917 
00918       if (!IS_EMPTY (working_stack)) {
00919     do {
00920       cur_part = POP (working_stack);
00921       cur_state = POP (working_stack);
00922       move (cur_state, cur_part);
00923 
00924       pred_stack = dfa_state2pred_stack [cur_state];
00925 
00926       for (state_ptr = pred_stack+TOP(pred_stack); state_ptr > pred_stack; state_ptr--) {
00927 #if LOG
00928         constant_time_step_nb++;             
00929 #endif /* LOG */
00930         pred_state = *state_ptr;
00931 
00932         if (SXBA_bit_is_reset_set (w_state_set, pred_state))
00933           PUSH (w_state_stack, pred_state);
00934       }
00935     } while (!IS_EMPTY (working_stack));
00936       }
00937       else
00938     break;
00939     }
00940 
00941     sxfree (w_state_stack);
00942     sxfree (w_state_set);
00943     sxfree (tbp_part_stack);
00944     sxfree (tbp_state_stacks);
00945   }
00946   else {
00947     /* version de minimize dans laquelle on n'utilise pas les predecesseurs */
00948     for(;;) {
00949 #if LLOG
00950       print_configuration ();
00951 #endif /* LLOG */
00952 
00953       for (cur_part = last_partition; cur_part >= 1; cur_part--) {
00954 #if LOG
00955     constant_time_step_nb++;             
00956 #endif /* LOG */
00957     cur_part_ptr = part2attr+cur_part;
00958     cur_part_card = cur_part_ptr->card;
00959 
00960     if (cur_part_card > 1) {
00961       RAZ (w2_stack);
00962       PUSH (w2_stack, 0); /* Pour les etats dont les successeurs n'ont pas bouge's */
00963       nb_max = 0;
00964       last_part_set_id = XH_top (XH_part_set)-1;
00965 
00966       for (cur_state = cur_part_ptr->state; cur_state != 0; cur_state = cur_state_ptr->next_state) {
00967         cur_state_ptr = state2attr + cur_state;
00968 
00969         /* On recalcule ses etats successeurs */
00970         trans_list_id = cur_state_ptr->trans_list_id;
00971         bot = XH_X (XH_trans_list_id, trans_list_id);
00972         top = XH_X (XH_trans_list_id, trans_list_id+1);
00973 
00974         t_trans = XH_list_elem (XH_trans_list_id, bot++);
00975         XH_push (XH_part_set, t_trans);
00976 
00977         while (bot < top) {
00978 #if LOG
00979           constant_time_step_nb++;             
00980 #endif /* LOG */
00981           next_state = XH_list_elem (XH_trans_list_id, bot);
00982           next_partition = state2attr [next_state].part;
00983           XH_push (XH_part_set, next_partition);
00984 
00985           bot++;
00986         }
00987 
00988         if (!XH_set (&XH_part_set, &part_set_id)) {
00989           /* Nouveau */
00990           PUSH (w2_stack, 0);
00991           id = TOP (w2_stack);
00992 
00993 #if EBUG 
00994           if (TOP (w2_stack) != part_set_id-last_part_set_id+1)
00995         sxtrap (ME, "dfa_minimize");
00996 #endif /* EBUG */
00997         }
00998         else {
00999           id = (part_set_id <= last_part_set_id) ? 1 : part_set_id-last_part_set_id+1;
01000         }
01001 
01002         nb = ++(w2_stack [id]);
01003 
01004         if (nb > nb_max) {
01005           nb_max = nb;
01006           id_max = id;
01007         }
01008 
01009         cur_state_ptr->temp_id = part_set_id;
01010       }
01011 
01012       /* Si nb_max == cur_part_card, on ne change rien */
01013       if (nb_max < cur_part_card) {
01014         old_last_partition = last_partition;
01015 
01016         /* Ds cur_part on ne va pas deplacer le + grand groupe =>
01017            chacun des groupes deplaces a une taille bornee par cur_part_card/2 */
01018         for (cur_state = cur_part_ptr->state; cur_state != 0; cur_state = cur_state_ptr->next_state) { 
01019 #if LOG
01020           constant_time_step_nb++;             
01021 #endif /* LOG */
01022           cur_state_ptr = state2attr + cur_state;
01023           part_set_id = cur_state_ptr->temp_id;
01024           id = (part_set_id <= last_part_set_id) ? 1 : part_set_id-last_part_set_id+1;
01025 
01026           if (id != id_max) {
01027         /* On bouge cur_state */
01028         if ((next_part = w2_stack [id]) > 0) {
01029           /* 1ere fois */
01030           next_part = ++last_partition;
01031           w2_stack [id] = -next_part; /* Pour les coups d'apres */
01032         }
01033         else
01034           next_part = -next_part;
01035 
01036         /* cur_state est change' de partition */
01037         /* Ce changement ne peut etre valide' au cours de ce run, il le sera + tard sinon les futurs calculs ds XH_part_set peuvent etre faux */
01038         /* state2part [cur_state] = next_part; doit etre retarde' sinon les futurs calculs ds  XH_part_set peuvent etre faux */
01039         PUSH (working_stack, cur_state);
01040         PUSH (working_stack, next_part);
01041           }
01042           else
01043         /* On ne bouge pas la sous-part maximale */
01044         next_part = cur_part;
01045 
01046 #if EBUG
01047           if (next_part != cur_part && next_part <= old_last_partition)
01048         sxtrap (ME, "dfa_minimize");
01049 #endif /* EBUG */
01050 
01051           /* part_set_id2part [part_set_id] = next_part; semble inutile */
01052         }
01053       }
01054     }
01055       }
01056 
01057       if (!IS_EMPTY (working_stack)) {
01058     do {
01059 #if LOG
01060       constant_time_step_nb++;             
01061 #endif /* LOG */
01062       cur_part = POP (working_stack);
01063       cur_state = POP (working_stack);
01064       move (cur_state, cur_part);
01065     } while (!IS_EMPTY (working_stack));
01066       }
01067       else
01068     break;
01069     }
01070   }
01071 
01072 #if LOG
01073   printf ("constant_time_step_nb (with%s backward transitions) = %ld\n", dfa_state2pred_stack ? "" : "out", (long)constant_time_step_nb);
01074 #endif /* LOG */
01075     
01076   sxfree (working_stack);
01077   sxfree (w2_stack);
01078   XH_free (&XH_part_set);
01079   sxfree (part_set_id2part), part_set_id2part = NULL;
01080 
01081   if (dfa_state2pred_stack) {
01082     sxfree (dfa_state2pred_stack), dfa_state2pred_stack = NULL;
01083     sxfree (base_area);
01084   }
01085 
01086   /* On assure seulement que l'etat initial a la valeur min
01087      et l'etat final la valeur max */
01088   /* On en a aussi besoin ds fsa_normalize () */
01089   part2new_part = (SXINT *) sxcalloc (last_partition+1, sizeof (SXINT));
01090   new_part2part = (SXINT *) sxalloc (last_partition+1, sizeof (SXINT));
01091   new_part = 1;
01092 
01093   for (state = cur_dfa_init_state; state <= cur_dfa_final_state; state++) {
01094     partition = state2attr [state].part;
01095 
01096     if (part2new_part [partition] == 0) {
01097       part2new_part [partition] = new_part;
01098       new_part2part [new_part] = partition;
01099       new_part++;
01100     }
01101   }
01102 
01103   last_new_part = new_part-1;
01104 
01105   if (!to_be_normalized) {
01106     for (new_part = 1; new_part <= last_new_part; new_part++) {
01107       partition = new_part2part [new_part];
01108     
01109       state = part2attr [partition].state;
01110       trans_list_id = state2attr [state].trans_list_id;
01111       bot = XH_X (XH_trans_list_id, trans_list_id);
01112       top = XH_X (XH_trans_list_id, trans_list_id+1);
01113 
01114       t_trans = -XH_list_elem (XH_trans_list_id, bot++);
01115       bot2 = XH_X (XH_t_trans, t_trans);
01116 
01117       while (bot < top) {
01118     next_state = XH_list_elem (XH_trans_list_id, bot);
01119     next_partition = state2attr [next_state].part;
01120     t = XH_list_elem (XH_t_trans, bot2);
01121 
01122     //  if (t == eof_ste)
01123     //    t = -1;
01124 
01125     (*mindfa_fill_trans)(new_part, t, part2new_part [next_partition]);
01126 
01127     bot++;
01128     bot2++;
01129       }
01130     }
01131   }
01132   else {
01133     /* Ici on assure en plus que si p ->t q alors, q > p (si possible : pas de cycle impliquant p) */
01134     /* ... on utilise fsa_normalize (SXINT init_state, SXINT final_state, void (*fsa_forward_trans)(), void (*fsa_fill_trans)()); */
01135     /* (*fsa_forward_trans)(p, f)  appelle (*f)(p, t, q) pour tout p ->t q
01136        fsa_normalize () appelle (*fsa_fill_trans)(p', t', q') pour toute transition p' ->t' q' renumerotee
01137     */
01138     SXINT trans_nb;
01139     SXINT *forward_list, *cur_forward_stack;
01140 
01141     /* on fabrique les structures pour forward () */
01142     /* On commence par calculer le nb de transitions */
01143     trans_nb = 0;
01144 
01145     for (new_part = 1; new_part <= last_new_part; new_part++) {
01146       partition = new_part2part [new_part];
01147       state = part2attr [partition].state;
01148       trans_list_id = state2attr [state].trans_list_id;
01149       bot = XH_X (XH_trans_list_id, trans_list_id)+1;
01150       top = XH_X (XH_trans_list_id, trans_list_id+1);
01151       trans_nb += top-bot;
01152     }
01153 
01154     /* Structures a remplir qui seront utilisees par forward () */
01155     forward_stacks = (SXINT **) sxalloc (last_partition+1, sizeof (SXINT *)), forward_stacks [0] = NULL;
01156     cur_forward_stack = forward_list = (SXINT *) sxalloc (2*trans_nb+last_partition+1, sizeof (SXINT));
01157 
01158     for (new_part = 1; new_part <= last_new_part; new_part++) {
01159       forward_stacks [new_part] = cur_forward_stack;
01160       partition = new_part2part [new_part];
01161       *cur_forward_stack = 0;
01162 
01163       state = part2attr [partition].state;
01164       trans_list_id = state2attr [state].trans_list_id;
01165       bot = XH_X (XH_trans_list_id, trans_list_id);
01166       top = XH_X (XH_trans_list_id, trans_list_id+1);
01167 
01168       t_trans = -XH_list_elem (XH_trans_list_id, bot++);
01169       bot2 = XH_X (XH_t_trans, t_trans);
01170       cur_forward_stack = forward_stacks [new_part];
01171 
01172       while (bot < top) {
01173     next_state = XH_list_elem (XH_trans_list_id, bot);
01174     next_partition = state2attr [next_state].part;
01175     t = XH_list_elem (XH_t_trans, bot2);
01176 
01177     PUSH (cur_forward_stack, t);
01178     PUSH (cur_forward_stack, part2new_part [next_partition]);
01179 
01180     bot++;
01181     bot2++;
01182       }
01183 
01184       cur_forward_stack += *cur_forward_stack + 1;
01185     }
01186 
01187 #ifdef ESSAI_INVERSE_MAPPING
01188     if (inverse_mapping) {
01189       /* L'appelant a demande' que l'on remplisse le mapping new_state -> {old_states}, on le dit a` fsa_normalize ... */
01190       SXINT new_norm_part, old_part, dfa_state;
01191       SXINT *new_state2old_state;
01192       SXBA  dfa_state_set;
01193 
01194       new_state2old_state = (SXINT*) sxalloc (last_new_part+1, sizeof (SXINT)), new_state2old_state [0] = 0;
01195       fsa_normalize (1, last_new_part, eof_ste, forward, mindfa_fill_trans, new_state2old_state);
01196       
01197       /* ... et on le fait */
01198       /* On alloue les structures c'est l'appelant qui les liberera */
01199       inverse_mapping->new_state2old_state_set_id = (SXINT*) sxalloc (last_new_part+1, sizeof (SXINT)), inverse_mapping->new_state2old_state_set_id [0] = 0;
01200       XH_alloc (&(inverse_mapping->XH_state_set), "inverse_mapping->XH_state_set", last_new_part+1, 1, (cur_dfa_final_state/last_new_part)+1, NULL, NULL);
01201 
01202       dfa_state_set = sxba_calloc (cur_dfa_final_state+1);
01203 
01204       for (new_norm_part = 1; new_norm_part <= last_new_part; new_norm_part++) {
01205     new_part = new_state2old_state [new_norm_part];
01206     old_part = new_part2part [new_part];
01207 
01208     dfa_state = part2attr [old_part].state;
01209 
01210     /* On a new_norm_part -> state */
01211     SXBA_1_bit (dfa_state_set, dfa_state);
01212 
01213     while ((dfa_state = state2attr [dfa_state].next_state)) {
01214       /* On a new_norm_part -> state */
01215       SXBA_1_bit (dfa_state_set, dfa_state);
01216     }
01217 
01218     dfa_state = 0;
01219 
01220     while ((dfa_state = sxba_scan_reset (dfa_state_set, dfa_state)) > 0)
01221       XH_push (inverse_mapping->XH_state_set, dfa_state);
01222 
01223     XH_set (&(inverse_mapping->XH_state_set), inverse_mapping->new_state2old_state_set_id+new_norm_part);
01224       }
01225 
01226       inverse_mapping->init_state = 1;
01227       inverse_mapping->final_state = last_new_part;
01228 
01229       sxfree (new_state2old_state);
01230     }
01231     else
01232       fsa_normalize (1, last_new_part, eof_ste, forward, mindfa_fill_trans, NULL);
01233 #else /* ESSAI_INVERSE_MAPPING */
01234     fsa_normalize (1, last_new_part, eof_ste, forward, mindfa_fill_trans);
01235 #endif /* ESSAI_INVERSE_MAPPING */
01236 
01237     sxfree (forward_stacks), forward_stacks = NULL;
01238     sxfree (forward_list);
01239   }
01240 
01241   sxfree (part2new_part);
01242   sxfree (new_part2part);
01243 
01244   sxfree (part2attr), part2attr = NULL;
01245   sxfree (state2attr), state2attr = NULL;
01246 
01247   XH_free (&XH_t_trans);
01248   XH_free (&XH_trans_list_id);
01249 }
01250 
01251 
01252 /* calcule new_state et ... */
01253 /* ... retourne SXTRUE ssi new_state existait deja */
01254 static SXBOOLEAN
01255 get_state (SXBA old_state_set, SXINT *new_state)
01256 {
01257   SXINT state = -1;
01258 
01259   while ((state = sxba_scan_reset (old_state_set, state)) >= 0)
01260     XH_push (XH_dfa_states, state);
01261 
01262   return XH_set (&XH_dfa_states, new_state);
01263 }
01264 
01265 /* Cette fonction est appelee pour chaque transition nfa_state ->t next_nfa_state */
01266 static void
01267 nfa_fill_trans (SXINT nfa_state, SXINT t, SXINT next_nfa_state)
01268 {
01269   sxuse (nfa_state);
01270   SXBA_1_bit (t2nfa_state_set [t], next_nfa_state);
01271 
01272   if (SXBA_bit_is_reset_set (t_set, t))
01273     PUSH (nfa_t_stack, t);
01274 }
01275 
01276 static void
01277 XxY_out_trans_oflw (SXINT old_size, SXINT new_size)
01278 {
01279   sxuse (old_size);
01280   XxY_out_trans2next_state = (SXINT*) sxrealloc (XxY_out_trans2next_state, new_size+1, sizeof (SXINT));
01281 }
01282 
01283 /* Point d'entree principal qui calcule l'automate deterministe */
01284 /* dfa_fill_trans est appele' pour sortir le dfa non minimal */
01285 /* et mindfa_fill_trans pour sortir l'automate minimal */
01286 void
01287 nfa2dfa (SXINT init_state, 
01288      SXINT final_state, 
01289      SXINT max_state,  /* en général, == 0 ; si > 0, on est dans le cas DAG (pas de trans
01290                   sortant de final_state) ; en contrepartie, on a le droit d'avoir
01291                   final_state != max_state, et on a le droit d'avoir des transitions
01292                   vers final_state qui ne sont pas sur eof_ste */
01293      SXINT eof_ste, 
01294      SXBOOLEAN (*empty_trans)(SXINT, SXBA), 
01295      void (*nfa_extract_trans)(SXINT, void (*nfa_fill_trans)(SXINT, SXINT, SXINT) ), 
01296      void (*dfa_fill_trans)(SXINT, SXINT, SXINT, SXBOOLEAN), 
01297      void (*mindfa_fill_trans)(SXINT, SXINT, SXINT), 
01298      SXBOOLEAN to_be_normalized
01299 #ifdef ESSAI_INVERSE_MAPPING
01300      , struct inverse_mapping *inverse_mapping
01301 #endif /* ESSAI_INVERSE_MAPPING */
01302      )
01303 {
01304   SXINT     dfa_state, new_dfa_state, bot, top, nfa_state, t, id, nfa_max_state;
01305   SXINT     *final_dfa_state_stack;
01306   SXBA      cur_state_set;
01307   SXBOOLEAN dfa_state_is_final;
01308 
01309   nfa_max_state = max_state == 0 ? final_state : max_state;
01310   nfa_empty_trans = empty_trans; /* Appels multiples */
01311 
01312   dfa_init_state = 1;
01313 
01314   if (empty_trans) {
01315     /* Il y a des transitions sur epsilon, on alloue qq structres */
01316     nfa_ec_stack = (SXINT*) sxalloc (nfa_max_state+1, sizeof (SXINT)), nfa_ec_stack [0] = 0;
01317     nfa_wstate_set = sxba_calloc (nfa_max_state+1);
01318   }
01319 
01320   nfa_t_stack = (SXINT*) sxalloc (eof_ste+1, sizeof (SXINT)), nfa_t_stack [0] = 0;
01321   DALLOC_STACK (final_dfa_state_stack, final_state);
01322   DALLOC_STACK (nfa_state_stack, nfa_max_state);
01323   t_set = sxba_calloc (eof_ste+1);
01324   t2nfa_state_set = sxbm_calloc (eof_ste+1, nfa_max_state+1);
01325   XH_alloc (&(XH_dfa_states), "XH_dfa_states", nfa_max_state+1, 1, 10, NULL, NULL);
01326 
01327   if (mindfa_fill_trans) {
01328     XxY_alloc (&XxY_out_trans, "XxY_out_trans", final_state+1, 1, 1, 0, XxY_out_trans_oflw, NULL);
01329     XxY_out_trans2next_state = (SXINT*) sxalloc (XxY_size (XxY_out_trans)+1, sizeof (SXINT));
01330   }
01331 
01332   /* traitement de l'etat initial */
01333   cur_state_set = t2nfa_state_set [0];
01334 
01335   SXBA_1_bit (cur_state_set, init_state);
01336 
01337   if (nfa_empty_trans)
01338     epsilon_closure (cur_state_set);
01339 
01340   get_state (cur_state_set, &dfa_state);
01341 
01342   DPUSH (nfa_state_stack, dfa_state);
01343 
01344   while (!IS_EMPTY (nfa_state_stack)) {
01345     dfa_state = DPOP (nfa_state_stack);
01346     dfa_state_is_final = SXFALSE;
01347 
01348     bot = XH_X (XH_dfa_states, dfa_state);
01349     top = XH_X (XH_dfa_states, dfa_state+1);
01350 
01351     while (bot < top) {
01352       nfa_state = XH_list_elem (XH_dfa_states, bot);
01353 
01354       if (nfa_state == final_state && max_state > 0) {
01355     dfa_state_is_final = SXTRUE;
01356     DPUSH (final_dfa_state_stack, dfa_state);
01357       }
01358 
01359       (*nfa_extract_trans) (nfa_state, nfa_fill_trans);
01360       bot++;
01361     }
01362 
01363     while (!IS_EMPTY (nfa_t_stack)) {
01364       t = POP (nfa_t_stack);
01365       SXBA_0_bit (t_set, t);
01366 
01367       if (t == eof_ste) {
01368     /* transition vers l'etat final unique, on la differe pour que l'etat final ait le + grand id */
01369     DPUSH (final_dfa_state_stack, dfa_state);
01370       }
01371       else { /* transition vers un état non final */
01372     cur_state_set = t2nfa_state_set [t];
01373 
01374     if (nfa_empty_trans)
01375       epsilon_closure (cur_state_set);
01376 
01377     if (!get_state (cur_state_set, &new_dfa_state)) {
01378       /* nouveau */
01379       DPUSH (nfa_state_stack, new_dfa_state);
01380     }
01381 
01382     /* Ici on a une transition dfa_state ->t new_dfa_state */
01383     /* C'est l'appelant qui se charge de stocker l'automate deterministe */
01384     if (dfa_fill_trans)
01385       (*dfa_fill_trans) (dfa_state, t, new_dfa_state, SXFALSE /* !is_final */);
01386 
01387     if (mindfa_fill_trans) {
01388       XxY_set (&XxY_out_trans, dfa_state, t, &id);
01389       XxY_out_trans2next_state [id] = new_dfa_state;
01390     }
01391       }
01392     }
01393   }
01394 
01395   /* Calcul de l'etat final */
01396   get_state (t2nfa_state_set [eof_ste], &dfa_final_state);
01397   dfa_state_nb = dfa_final_state;
01398   
01399   while (!IS_EMPTY (final_dfa_state_stack)) {
01400     dfa_state = DPOP (final_dfa_state_stack);
01401 
01402     if (dfa_fill_trans)
01403       (*dfa_fill_trans) (dfa_state, eof_ste, dfa_final_state, SXTRUE /* is_final */);
01404 
01405     if (mindfa_fill_trans) {
01406       XxY_set (&XxY_out_trans, dfa_state, eof_ste, &id);
01407       XxY_out_trans2next_state [id] = dfa_final_state;
01408     }
01409   }
01410 
01411   if (nfa_empty_trans) {
01412     sxfree (nfa_ec_stack), nfa_ec_stack = NULL;
01413     sxfree (nfa_wstate_set), nfa_wstate_set = NULL;
01414   }
01415 
01416   sxfree (nfa_t_stack), nfa_t_stack = NULL;
01417   DFREE_STACK (final_dfa_state_stack);
01418   DFREE_STACK (nfa_state_stack);
01419   sxbm_free (t2nfa_state_set), t2nfa_state_set = NULL;
01420   sxfree (t_set), t_set = NULL;
01421 
01422   if (mindfa_fill_trans) {
01423 #ifdef ESSAI_INVERSE_MAPPING
01424     if (inverse_mapping) {
01425       /* L'appelant a demande' que l'on remplisse le mapping new_state -> {old_states}, on le dit a` dfa_minimize ... */
01426       SXINT                  new_state, bot2, top2;
01427       SXBA                   nfa_state_set;
01428       struct inverse_mapping dfa_inverse_mapping;
01429 
01430       dfa_minimize (dfa_init_state, dfa_final_state, eof_ste, dfa_extract_trans, mindfa_fill_trans, to_be_normalized, &dfa_inverse_mapping);
01431 
01432       /* ... et on le fait */
01433       nfa_state_set = sxba_calloc (final_state+1);
01434 
01435       inverse_mapping->new_state2old_state_set_id = (SXINT*) sxalloc (dfa_inverse_mapping.final_state+1, sizeof (SXINT)), inverse_mapping->new_state2old_state_set_id [0] = 0;
01436       XH_alloc (&(inverse_mapping->XH_state_set), "inverse_mapping->XH_state_set", dfa_inverse_mapping.final_state+1, 1, (final_state/dfa_inverse_mapping.final_state)+1, NULL, NULL);
01437 
01438       for (new_state = dfa_inverse_mapping.init_state; new_state <= dfa_inverse_mapping.final_state; new_state++) {
01439     id = dfa_inverse_mapping.new_state2old_state_set_id [new_state];
01440     bot = XH_X (dfa_inverse_mapping.XH_state_set, id);
01441     top = XH_X (dfa_inverse_mapping.XH_state_set, id+1);
01442 
01443     while (bot < top) {
01444       dfa_state = XH_list_elem (dfa_inverse_mapping.XH_state_set, bot);
01445 
01446       bot2 = XH_X (XH_dfa_states, dfa_state);
01447       top2 = XH_X (XH_dfa_states, dfa_state+1);
01448 
01449       while (bot2 < top2) {
01450         nfa_state = XH_list_elem (XH_dfa_states, bot2);
01451         SXBA_1_bit (nfa_state_set, nfa_state);
01452 
01453         bot2++;
01454       }
01455 
01456       bot++;
01457     }
01458 
01459     nfa_state = 0;
01460 
01461     while ((nfa_state = sxba_scan_reset (nfa_state_set, nfa_state)) > 0) 
01462       XH_push (inverse_mapping->XH_state_set, nfa_state);
01463 
01464     XH_set (&(inverse_mapping->XH_state_set), inverse_mapping->new_state2old_state_set_id + new_state);
01465       }
01466 
01467       inverse_mapping->init_state = dfa_inverse_mapping.init_state;
01468       inverse_mapping->final_state = dfa_inverse_mapping.final_state;
01469 
01470       sxfree (dfa_inverse_mapping.new_state2old_state_set_id);
01471       XH_free (&dfa_inverse_mapping.XH_state_set);
01472 
01473       sxfree (nfa_state_set);
01474     }
01475     else
01476       dfa_minimize (dfa_init_state, dfa_final_state, eof_ste, dfa_extract_trans, mindfa_fill_trans, to_be_normalized, NULL);
01477 #else /* ESSAI_INVERSE_MAPPING */
01478     dfa_minimize (dfa_init_state, dfa_final_state, eof_ste, dfa_extract_trans, mindfa_fill_trans, to_be_normalized);
01479 #endif /* ESSAI_INVERSE_MAPPING */
01480 
01481     XxY_free (&XxY_out_trans);
01482     sxfree (XxY_out_trans2next_state), XxY_out_trans2next_state = NULL;
01483   }
01484   else {
01485 #ifdef ESSAI_INVERSE_MAPPING
01486     if (inverse_mapping) {
01487       /* L'appelant a demande' que l'on remplisse le mapping new_state -> {old_states}, sans appel a minimize ... */
01488       SXINT                  bot2, top2;
01489       SXBA                   nfa_state_set;
01490 
01491       /* ... et on le fait */
01492       nfa_state_set = sxba_calloc (final_state+1);
01493 
01494       inverse_mapping->new_state2old_state_set_id = (SXINT*) sxalloc (dfa_final_state+1, sizeof (SXINT)), inverse_mapping->new_state2old_state_set_id [0] = 0;
01495       XH_alloc (&(inverse_mapping->XH_state_set), "inverse_mapping->XH_state_set", dfa_final_state+1, 1, (final_state/dfa_final_state)+1, NULL, NULL);
01496 
01497       for (dfa_state = 1; dfa_state <= dfa_final_state; dfa_state++) {
01498     bot2 = XH_X (XH_dfa_states, dfa_state);
01499     top2 = XH_X (XH_dfa_states, dfa_state+1);
01500 
01501     while (bot2 < top2) {
01502       nfa_state = XH_list_elem (XH_dfa_states, bot2);
01503       SXBA_1_bit (nfa_state_set, nfa_state);
01504 
01505       bot2++;
01506     }
01507 
01508     nfa_state = 0;
01509 
01510     while ((nfa_state = sxba_scan_reset (nfa_state_set, nfa_state)) > 0) 
01511       XH_push (inverse_mapping->XH_state_set, nfa_state);
01512 
01513     XH_set (&(inverse_mapping->XH_state_set), inverse_mapping->new_state2old_state_set_id + dfa_state);
01514       }
01515 
01516       inverse_mapping->init_state = 1;
01517       inverse_mapping->final_state = dfa_final_state;
01518 
01519       sxfree (nfa_state_set);
01520     }
01521 #endif /* ESSAI_INVERSE_MAPPING */
01522   }
01523 
01524   XH_free (&XH_dfa_states);
01525 }
01526 
01527 
01528 /* Le module fsa_to_re.c a e'te' inse're' ici dans fsa_mngr.c Le 03/10/07 */
01529 
01530 
01531 
01532 
01533 
01534 
01535 
01536 
01537 
01538 
01539 
01540 
01541 char WHAT_FSA_TO_RE[] = "@(#)SYNTAX - $Id: fsa_mngr.c 1743 2009-06-08 13:32:55Z sagot $" WHAT_DEBUG;
01542 
01543 
01544 #define leaf (SXINT)1
01545 #define concat (SXINT)2
01546 #define star (SXINT)3
01547 #define or (SXINT)4
01548 #define plus (SXINT)5
01549 #define option (SXINT)6
01550 
01551 #define head_s_no (SXINT)67
01552 #define node_number_per_area (SXINT)20
01553 
01554 static char     **meta_op; /* op [6] = {"(", ")*", "(", ")+", "(", ")?"}; */
01555 
01556 static SXINT    S [7] [7] = {{0, 0, 0, 0, 0, 0, 0},
01557                  { /* bidon */ 0, 1, 0, 2, 1, 1, 1},
01558                  { /* leaf */ 0, 0, 0, 0, 0, 0, 0},
01559                  { /* concat */ 0, 3, 0, 4, 3, 5, 6},
01560                  { /* star */ 0, 1, 0, 2, 1, 1, 1},
01561                  { /* or */ 0, 1, 0, 6, 1, 1, 6},
01562                  { /* plus */ 0, 1, 0, 5, 1, 5, 1} /* option */ };
01563 static SXINT      SIZE, INITIAL_S;
01564 static SXBA /* SIZE */ *M /* 0:SIZE-1 */ ;
01565 struct node {
01566     struct node     *link;
01567     SXINT       name;
01568     union {
01569     struct {
01570         struct node     *left;
01571         struct node     *right;
01572     }   brother;
01573     char    *string_ptr;
01574     }   body;
01575 };
01576 struct tree_area {
01577     struct tree_area    *lnk;
01578     struct node     node_s [node_number_per_area];
01579 };
01580 static struct tree_area     *tree_area_ptr;
01581 static SXINT    cur_node_no;
01582 static struct node  ***re_ptrs /* 0:SIZE-1, 0:SIZE-1 */ ;
01583 
01584 /* re_ptrs(i,j) = pointeur vers l'arbre representant
01585 l'expression reguliere entre les noeuds i et j si M (i, j) */
01586 
01587 static SXINT    *in, *out /* 1:SIZE */ ;
01588 
01589 /* pour chaque noeud arite en entree et sortie */
01590 
01591 static SXBA /* SIZE */ to_be_processed, reached_set, loop_set;
01592 static struct node  **P_S /* 1:P_S_size */ ;
01593 
01594 struct tete {
01595     SXINT size;
01596     struct node     **T;
01597 };
01598 static struct tete  *tete;
01599 static SXINT       size_of_tete, top_of_tete, x_of_tete;
01600 #define tete_pop(n) (x_of_tete -= n)
01601 
01602 struct sets {
01603     SXINT   size;
01604     SXBA    set;    
01605 };
01606 static struct sets  *sets;
01607 static SXINT        size_of_sets, top_of_sets, x_of_sets;
01608 #define sets_pop(n) (x_of_sets -= n)
01609 
01610 struct ints {
01611     SXINT   size;
01612     SXINT       *T; 
01613 };
01614 static struct ints  *ints;
01615 static SXINT        size_of_ints, top_of_ints, x_of_ints;
01616 #define ints_pop(n) (x_of_ints -= n)
01617 
01618 static SXINT        *to_be_sorted /* 1:M */ ;
01619 static SXINT        size_of_to_be_sorted;
01620 
01621 static SXBA     succ_set;
01622 
01623 static SXBA_INDEX       prev, current;
01624 static struct node  *head_s [head_s_no];
01625 static struct node  *leafs_hd [head_s_no];
01626 static struct node  *canon (SXINT oper, struct node *left, struct node *right);
01627 static struct node  *reduce_or_son (struct node *visited);
01628 static struct node  *gen_prefixe (struct node ***p_s, SXBA set, struct node *node_ptr, SXINT or_no, SXINT *min_s, SXINT *MAX_s);
01629 static struct node  *gen_suffixe (struct node ***p_s, SXBA set, struct node *node_ptr, SXINT or_no, SXINT *min_s, SXINT *MAX_s);
01630 
01631 
01632 
01633 
01634 static struct node **tete_open (SXINT size)
01635 {
01636     struct tete *atete;
01637 
01638     if (tete == NULL) {
01639         sxprepare_for_possible_reset (tete);
01640     tete = (struct tete*) sxalloc ((size_of_tete = 5) + 1, sizeof (struct tete));
01641     top_of_tete = x_of_tete = 0;
01642     /* x_of_tete <= top-of_tete */
01643     }
01644     else if (x_of_tete > size_of_tete) {
01645     tete = (struct tete*) sxrealloc (tete, (size_of_tete *= 2) + 1, sizeof (struct tete));
01646     }
01647 
01648     atete = tete + x_of_tete;
01649 
01650     if (x_of_tete == top_of_tete) {
01651     atete->T = (struct node**) sxalloc (size + 1, sizeof (struct node*));
01652     atete->size = size;
01653     top_of_tete++;
01654     }
01655     else if (size > atete->size) {
01656         atete->T = (struct node**) sxrealloc (atete->T, size + 1, sizeof (struct node*));
01657         atete->size = size;
01658     }
01659 
01660     x_of_tete++;
01661     return atete->T;
01662 }
01663 
01664 static SXVOID tete_free (void)
01665 {
01666     if (tete != NULL) {
01667     struct tete *atete = tete + top_of_tete;
01668 
01669     while (--atete >= tete)
01670         sxfree (atete->T);
01671 
01672     sxfree (tete);
01673     }
01674 }
01675 
01676 
01677 static SXINT *ints_open (SXINT size)
01678 {
01679     struct ints *aints;
01680 
01681     if (ints == NULL) {
01682         sxprepare_for_possible_reset (ints);
01683     ints = (struct ints*) sxalloc ((size_of_ints = 5) + 1, sizeof (struct ints));
01684     top_of_ints = x_of_ints = 0;
01685     /* x_of_ints <= top-of_ints */
01686     }
01687     else if (x_of_ints > size_of_ints) {
01688     ints = (struct ints*) sxrealloc (ints, (size_of_ints *= 2) + 1, sizeof (struct ints));
01689     }
01690 
01691     aints = ints + x_of_ints;
01692 
01693     if (x_of_ints == top_of_ints) {
01694     aints->T = (SXINT*) sxalloc (size + 1, sizeof (SXINT));
01695     aints->size = size;
01696     top_of_ints++;
01697     }
01698     else if (size > aints->size) {
01699         aints->T = (SXINT*) sxrealloc (aints->T, size + 1, sizeof (SXINT));
01700         aints->size = size;
01701     }
01702 
01703     x_of_ints++;
01704     return aints->T;
01705 }
01706 
01707 static SXVOID ints_free (void)
01708 {
01709     if (ints != NULL) {
01710     struct ints *aints = ints + top_of_ints;
01711 
01712     while (--aints >= ints)
01713         sxfree (aints->T);
01714 
01715     sxfree (ints);
01716     }
01717 }
01718 
01719 
01720 static SXBA sets_open (SXINT size)
01721 {
01722     struct sets *asets;
01723 
01724     if (sets == NULL) {
01725         sxprepare_for_possible_reset (sets);
01726     sets = (struct sets*) sxalloc ((size_of_sets = 4) + 1, sizeof (struct sets));
01727     top_of_sets = x_of_sets = 0;
01728     /* x_of_sets <= top-of_sets */
01729     }
01730     else if (x_of_sets > size_of_sets) {
01731     sets = (struct sets*) sxrealloc (sets, (size_of_sets *= 2) + 1, sizeof (struct sets));
01732     }
01733 
01734     asets = sets + x_of_sets;
01735 
01736     if (x_of_sets == top_of_sets) {
01737     asets->set = sxba_calloc (size + 1);
01738     asets->size = size;
01739     top_of_sets++;
01740     }
01741     else {
01742     sxba_empty (asets->set);
01743 
01744     if (size != asets->size) {
01745         asets->set = sxba_resize (asets->set, size + 1);
01746         asets->size = size;
01747     }
01748     }
01749 
01750     x_of_sets++;
01751     return asets->set;
01752 }
01753 
01754 static SXVOID sets_free (void)
01755 {
01756     if (sets != NULL) {
01757     struct sets *asets = sets + top_of_sets;
01758 
01759     while (--asets >= sets)
01760         sxfree (asets->set);
01761 
01762     sxfree (sets);
01763     }
01764 }
01765 
01766 
01767 
01768 static struct node  *alloc_a_node (void)
01769 {
01770     struct tree_area    *p;
01771 
01772     if (cur_node_no == node_number_per_area) {
01773     p = tree_area_ptr;
01774     tree_area_ptr = (struct tree_area*) sxcalloc (1, sizeof (struct tree_area));
01775     tree_area_ptr->lnk = p;
01776     cur_node_no = 0;
01777     }
01778 
01779     return &(tree_area_ptr->node_s [cur_node_no++]);
01780 }
01781 
01782 
01783 
01784 static SXVOID   free_tree_areas (void)
01785 {
01786     struct tree_area    *p;
01787 
01788     while ((p = tree_area_ptr) , (p != NULL)) {
01789     tree_area_ptr = p->lnk;
01790     sxfree (p);
01791     }
01792 }
01793 
01794 
01795 
01796 static struct node  *create_leaf (SXBA_INDEX i, SXBA_INDEX j, SXINT (*get_name_refs) (SXBA_INDEX, SXBA_INDEX, char ** ))
01797 {
01798     struct node *leaf_node_ptr, **orig;
01799     char            *p;
01800 
01801     (*get_name_refs) (i, j, &p);
01802 
01803     for (leaf_node_ptr = *(orig = leafs_hd + (((long) p) % head_s_no)); leaf_node_ptr != NULL; leaf_node_ptr = leaf_node_ptr->link) {
01804     if (p == leaf_node_ptr->body.string_ptr)
01805         return (leaf_node_ptr);
01806     }
01807 
01808     leaf_node_ptr = alloc_a_node ();
01809     leaf_node_ptr->name = leaf;
01810     leaf_node_ptr->link = *orig;
01811     leaf_node_ptr->body.string_ptr = p;
01812     return *orig = leaf_node_ptr;
01813 }
01814 
01815 
01816 
01817 static struct node  *create_op (SXINT op, struct node *l, struct node *r)
01818 {
01819     struct node *p, **orig;
01820 
01821     for (p = *(orig = head_s + ((op + (((long) (l) ^ (long) (r)) >> 1)) % head_s_no)); p != NULL; p = p->link) {
01822     if (p->name == op && p->body.brother.left == l && p->body.brother.right == r)
01823         return (p);
01824     }
01825 
01826     p = alloc_a_node ();
01827     p->name = op;
01828     p->body.brother.left = l;
01829     p->body.brother.right = r;
01830     p->link = *orig;
01831     return *orig = p;
01832 }
01833 
01834 
01835 
01836 static struct node  *create_list (struct node **p_s, SXINT m, SXINT create_list_M, SXINT op)
01837 {
01838     SXINT       x;
01839     struct node *p, *q;
01840 
01841     x = create_list_M;
01842 
01843     for (p = p_s [x]; p == NULL; p = p_s [x]) {
01844     x--;
01845     }
01846 
01847     for (x--; x >= m; x--) {
01848     q = p_s [x];
01849 
01850     if (q != NULL)
01851         p = create_op (op, q, p);
01852     }
01853 
01854     return (p);
01855 }
01856 
01857 
01858 
01859 static SXBOOLEAN    is_tail (struct node *p1, struct node *p2)
01860 {
01861     /* Si p2 est une concatenation, regarde si le dernier composant est p1 */
01862     struct node *p;
01863 
01864     if (p2->name != concat)
01865     return (SXFALSE);
01866 
01867     for (p = p2; p->name == concat; p = p->body.brother.right) {
01868     }
01869 
01870     return (p == p1);
01871 }
01872 
01873 
01874 
01875 static SXINT    nb_op_sons (struct node *p, SXINT op)
01876 {
01877     if (p->name != op)
01878     return (1);
01879 
01880     return (1 + nb_op_sons (p->body.brother.right, op));
01881 }
01882 
01883 
01884 
01885 static SXVOID   gather_op_sons (struct node **p_s, SXINT *xp, struct node *p, SXINT op)
01886 {
01887     if (p->name != op) {
01888     p_s [++*xp] = p;
01889     }
01890     else {
01891     p_s [++*xp] = p->body.brother.left;
01892     gather_op_sons (p_s, xp, p->body.brother.right, op);
01893     }
01894 }
01895 
01896 
01897 static SXVOID   process_substr (struct node **p_s, SXINT xstar, SXINT xconc, SXINT process_substr_M)
01898 {
01899     struct node     *star_son_ptr;
01900     SXINT       d, y;
01901 
01902     star_son_ptr = p_s [xstar]->body.brother.left;
01903 
01904     if (star_son_ptr == p_s [xconc]) {
01905     p_s [xconc] = NULL;
01906     p_s [xstar] = canon (plus, star_son_ptr, NULL);
01907     }
01908     else if (star_son_ptr->name == concat) {
01909     y = nb_op_sons (star_son_ptr, concat);
01910     d = xconc - ((xconc < xstar) ? y : 1);
01911 
01912     if (xconc < xstar || d + y <= process_substr_M) {
01913         struct node **q_s, **r_s /* 1:y */ ;
01914         SXINT       i, j;
01915         SXINT               x;
01916 
01917         q_s = tete_open (y);
01918         x = 0;
01919         gather_op_sons (q_s, &x, star_son_ptr, concat);
01920 
01921         if (xconc < xstar) {
01922         for (i = y; i >= 1; i--, xconc--) {
01923             if (xconc == 0 || q_s [i] != p_s [xconc]) {
01924             if (i == y) {
01925                 tete_pop (1);
01926                 return;
01927             }
01928 
01929             /* egalite entre i+1 .. y;normalisation
01930             ...UW{VW}X... => ...U{WV}WX... */
01931 
01932             r_s = tete_open (y);
01933 
01934             for (j = 1; j <= y; j++) {
01935                 r_s [j - i + ((j <= i) ? y : 0)] = q_s [j];
01936             }
01937 
01938             xconc++;
01939 
01940             for (; xstar > xconc; xstar--) {
01941                 p_s [xstar] = p_s [xstar - 1];
01942             }
01943 
01944             p_s [xconc] = canon (star, create_list (r_s, (SXINT)1, y, concat), NULL);
01945             tete_pop (2);
01946             process_substr (p_s, xconc, xconc + 1, process_substr_M);
01947             return;
01948             }
01949         }
01950         }
01951         else {
01952         for (i = 1; i <= y; i++) {
01953             if (q_s [i] != p_s [d + i]) {
01954             tete_pop (1);
01955             return;
01956             }
01957         }
01958         }
01959 
01960         for (i = d + 1; i <= d + y; i++) {
01961         p_s [i] = NULL;
01962         }
01963 
01964         tete_pop (1);
01965         p_s [xstar] = canon (plus, star_son_ptr, NULL);
01966     }
01967     }
01968 }
01969 
01970 
01971 
01972 static SXBOOLEAN    is_an_element (struct node *head_ptr, struct node *elem_ptr, SXINT oper)
01973 {
01974     struct node *p;
01975 
01976     for (p = head_ptr; p->name == oper; p = p->body.brother.right) {
01977     if (p->body.brother.left == elem_ptr)
01978         return (SXTRUE);
01979     }
01980 
01981     return (p == elem_ptr);
01982 }
01983 
01984 
01985 
01986 static SXBOOLEAN    is_a_subset (struct node **p_s, SXINT m1, SXINT M1, struct node **q_s, SXINT m2, SXINT M2)
01987 {
01988     SXINT       x1, x2;
01989     struct node *p2;
01990 
01991     x1 = m1 - 1;
01992 
01993     for (x2 = m2; x2 <= M2; x2++) {
01994     if ((p2 = q_s [x2]) != NULL) {
01995         for (x1++; x1 <= M1; x1++) {
01996         if (p2 == p_s [x1])
01997             break;
01998         }
01999 
02000         if (x1 > M1)
02001         return SXFALSE;
02002     }
02003     }
02004 
02005     return SXTRUE;
02006 }
02007 
02008 
02009 
02010 static SXBOOLEAN    is_a_member (struct node *p1, struct node *p2)
02011 {
02012     /* Check if the left son of p1 is
02013      - the left son of p2
02014      - or a [sub-]alternative of p2 */
02015     struct node     *p1_son, *p2_son;
02016     SXINT       xp1, xp2;
02017 
02018     if ((p1_son = p1->body.brother.left) == (p2_son = p2->body.brother.left))
02019     return (SXTRUE);
02020 
02021     if (p2_son->name != or)
02022     return (SXFALSE);
02023 
02024     if (p1_son->name != or)
02025     return (is_an_element (p2_son, p1_son, or));
02026 
02027     if ((xp1 = nb_op_sons (p1_son, or)) > (xp2 = nb_op_sons (p2_son, or)))
02028     return (SXFALSE);
02029     
02030     {
02031     struct node **p1_s /* 1:xp1 */ , **p2_s /* 1:xp2 */ ;
02032     SXINT       x;
02033     SXBOOLEAN   subsetp;
02034     
02035     p1_s = tete_open (xp1);
02036     p2_s = tete_open (xp2);
02037     x = 0;
02038     gather_op_sons (p1_s, &x, p1_son, or);
02039     x = 0;
02040     gather_op_sons (p2_s, &x, p2_son, or);
02041     subsetp = is_a_subset (p2_s, (SXINT)1, xp2, p1_s, (SXINT)1, xp1);
02042     tete_pop (2);
02043     return subsetp;
02044     }
02045 }
02046 
02047 
02048 
02049 static SXBOOLEAN    is_a_staror_elem (struct node *node_ptr, struct node **result_ptr)
02050 {
02051     SXINT           concat_no;
02052 
02053     *result_ptr = NULL;
02054 
02055     if (node_ptr->name != concat)
02056     return SXFALSE;
02057 
02058     concat_no = nb_op_sons (node_ptr, concat);
02059 
02060     {
02061     struct node **p_s /* 1:concat_no */, *or_ptr, *p ;
02062     SXINT   x, or_no;
02063 
02064     p_s = tete_open (concat_no);
02065     x = 0;
02066     gather_op_sons (p_s, &x, node_ptr, concat);
02067     p = p_s [concat_no];
02068 
02069     if (p->name != star) {
02070         tete_pop (1);
02071         return (SXFALSE);
02072     }
02073 
02074     or_ptr = p->body.brother.left;
02075 
02076     if (or_ptr->name != or) {
02077         tete_pop (1);
02078         return (SXFALSE);
02079     }
02080 
02081     p = create_list (p_s, (SXINT)1, concat_no - 1, concat);
02082     or_no = nb_op_sons (or_ptr, or);
02083 
02084     {
02085         struct node **q_s /* 1:or_no */ ;
02086 
02087         q_s = tete_open (or_no);
02088         x = 0;
02089         gather_op_sons (q_s, &x, or_ptr, or);
02090 
02091         for (x = 1; x <= or_no; x++) {
02092         if (q_s [x] == p) {
02093             q_s [x] = NULL;
02094             goto next;
02095         }
02096         }
02097 
02098         tete_pop (2);
02099         return (SXFALSE);
02100 
02101 next:       *result_ptr = create_op (concat, p, canon (star, create_list (q_s, (SXINT)1, or_no, or), NULL));
02102         tete_pop (2);
02103         return (SXTRUE);
02104     }
02105     }
02106 }
02107 
02108 
02109 
02110 static SXBOOLEAN    is_a_sublanguage (struct node *left, struct node *right)
02111 {
02112     struct node *left_son, *right_son;
02113     SXINT               or_no, concat_no;
02114 
02115     left_son = left->body.brother.left;
02116     right_son = right->body.brother.left;
02117 
02118     if (left_son->name != or || right_son->name != concat)
02119     return (SXFALSE);
02120 
02121     or_no = nb_op_sons (left_son, or);
02122     concat_no = nb_op_sons (right_son, concat);
02123 
02124     {
02125     struct node     **or_son_ptrs, **concat_son_ptrs;
02126     struct node *p;
02127     SXINT   x, cn;
02128     SXBOOLEAN       elementp;
02129 
02130     or_son_ptrs = tete_open (or_no);
02131     concat_son_ptrs = tete_open (concat_no);
02132     x = 0;
02133     gather_op_sons (or_son_ptrs, &x, left_son, or);
02134     x = 0;
02135     gather_op_sons (concat_son_ptrs, &x, right_son, concat);
02136 
02137     for (x = concat_no; x >= 1; x--) {
02138         p = concat_son_ptrs [x];
02139 
02140         if (((p->name != star) && (p->name != option)) || !is_an_element (left_son, p->body.brother.left, or))
02141         break;
02142     }
02143 
02144     if (x == concat_no) {
02145         tete_pop (2);
02146         return (SXFALSE);
02147     }
02148 
02149     if (x == 0) {
02150         tete_pop (2);
02151         return (SXTRUE);
02152     }
02153 
02154     if (x == 1) {
02155         p = concat_son_ptrs [1];
02156 
02157         if (p->name == or) {
02158         cn = nb_op_sons (p, or);
02159 
02160         {
02161             struct node     **c_s /* 1:cn */ ;
02162             SXINT       y;
02163             SXBOOLEAN   subsetp;
02164 
02165             c_s = tete_open (cn);
02166             y = 0;
02167             gather_op_sons (c_s, &y, p, or);
02168             subsetp = is_a_subset (or_son_ptrs, (SXINT)1, or_no, c_s, (SXINT)1, cn);
02169             tete_pop (3);
02170             return subsetp;
02171         }
02172         }
02173         else {
02174         elementp = is_an_element (left_son, p, or);
02175         tete_pop (2);
02176         return elementp;
02177         }
02178     }
02179     else {
02180         /* x>1 */
02181         elementp = is_an_element (left_son, create_list (concat_son_ptrs, (SXINT)1, x, concat), or);
02182         tete_pop (2);
02183         return elementp;
02184     }
02185     }
02186 }
02187 
02188 
02189 
02190 static SXVOID   transform (struct node **left, struct node **right)
02191 {
02192     struct node *left_son, *right_son;
02193     SXINT               cn1, cn2;
02194 
02195     left_son = (*left)->body.brother.left;
02196     right_son = (*right)->body.brother.left;
02197 
02198     if (left_son->name != concat || right_son->name != concat)
02199     return;
02200 
02201     cn1 = nb_op_sons (left_son, concat);
02202     cn2 = nb_op_sons (right_son, concat);
02203 
02204     {
02205     struct node **c1_s /* 1:cn1 */ , **c2_s /* 1:cn2 */ ;
02206     SXINT   x, y;
02207     struct node *p, *or_ptr;
02208 
02209     c2_s = tete_open (cn2);
02210     x = 0;
02211     gather_op_sons (c2_s, &x, right_son, concat);
02212 
02213     if (c2_s [cn2]->name != star) {
02214         tete_pop (1);
02215         return;
02216     }
02217 
02218     or_ptr = c2_s [cn2]->body.brother.left;
02219 
02220     if (or_ptr->name != or) {
02221         tete_pop (1);
02222         return;
02223     }
02224 
02225     c1_s = tete_open (cn1);
02226     x = 0;
02227     gather_op_sons (c1_s, &x, left_son, concat);
02228 
02229     if (c1_s [cn1]->name != star) {
02230         tete_pop (2);
02231         return;
02232     }
02233 
02234     for (x = cn1 - 1; x >= 1; x--) {
02235         p = c1_s [x];
02236 
02237         if (p->name != star)
02238         break;
02239     }
02240 
02241     if (x == 0) {
02242         tete_pop (2);
02243         return;
02244     }
02245 
02246 
02247 /* garde_fou */
02248 
02249     if (nb_op_sons (or_ptr, or) != cn1 - x + 1) {
02250             tete_pop (2);
02251         return;
02252     }
02253 
02254     for (y = x + 1; y <= cn1; y++) {
02255         if (!is_an_element (or_ptr, c1_s [y]->body.brother.left, or)) {
02256         tete_pop (2);
02257         return;
02258         }
02259     }
02260 
02261     p = create_list (c1_s, (SXINT)1, x, concat);
02262 
02263     if (!is_an_element (or_ptr, p, or)) {
02264         tete_pop (2);
02265         return;
02266     }
02267 
02268     *right = NULL;
02269     c1_s [x] = canon (or, p, create_list (c2_s, (SXINT)1, cn2 - 1, concat));
02270     *left = canon (star, create_list (c1_s, x, cn1, concat), NULL);
02271     tete_pop (2);
02272     }
02273 }
02274 
02275 
02276 
02277 static SXBOOLEAN    less (SXINT i, SXINT j)
02278 {
02279     return (long) (P_S [i]) < (long) (P_S [j]);
02280 }
02281 
02282 
02283 
02284 static struct node  *create_or_list (struct node **p_s, SXINT m, SXINT create_or_list_M)
02285 {
02286     SXINT   x;
02287     struct node     *v, *w;
02288 
02289     P_S = p_s;
02290 
02291     if (to_be_sorted == NULL) {
02292         sxprepare_for_possible_reset (to_be_sorted);
02293     to_be_sorted = (SXINT*) sxalloc ((size_of_to_be_sorted = create_or_list_M) + 1, sizeof (SXINT));
02294     }
02295     else if (create_or_list_M > size_of_to_be_sorted)
02296     to_be_sorted = (SXINT*) sxrealloc (to_be_sorted, (size_of_to_be_sorted = create_or_list_M) + 1, sizeof (SXINT));
02297     
02298     for (x = 1; x <= create_or_list_M; x++) {
02299     to_be_sorted [x] = x;
02300     }
02301 
02302     sort_by_tree (to_be_sorted, m, create_or_list_M, less);
02303     /* Suppression des alternatives identiques et construction du nouvel arbre */
02304     v = p_s [create_or_list_M];
02305 
02306     for (x = create_or_list_M - 1; x >= m; x--) {
02307     w = p_s [x];
02308 
02309     if (v != w)
02310         v = w;
02311     else
02312         p_s [x] = NULL;
02313     }
02314 
02315     return (create_list (p_s, m, create_or_list_M, or));
02316 }
02317 
02318 
02319 
02320 static struct node  *canon (SXINT oper, struct node *left, struct node *right)
02321 {
02322     SXINT       concat_no, or_no, left_name, cn;
02323     struct node     *p;
02324 
02325     switch (oper) {
02326     default: /* pour faire taire gcc -Wswitch-default */
02327 #if EBUG
02328       sxtrap("fsa_to_re","unknown switch case #1");
02329 #endif
02330       break;
02331     case leaf:
02332     /* leaf (error) */
02333     return NULL;
02334 
02335     case concat:
02336     /* op = concat */
02337 /* On canonicalise */
02338     concat_no = nb_op_sons (left, concat) + nb_op_sons (right, concat);
02339 
02340     {
02341         struct node **p_s /* 1:concat_no */ ;
02342         SXINT       x, xp, l_name, r_name, canon_cn;
02343         struct node     *l_ptr, *r_ptr, *rl_ptr;
02344 
02345         p_s = tete_open (concat_no);
02346         x = 0;
02347         gather_op_sons (p_s, &x, left, concat);
02348         xp = x;
02349         gather_op_sons (p_s, &x, right, concat);
02350         l_ptr = p_s [xp];
02351         r_ptr = p_s [xp + 1];
02352         l_name = l_ptr->name;
02353         r_name = r_ptr->name;
02354 
02355         switch (S [l_name] [r_name]) {
02356         case 0:
02357         /* error */
02358         fprintf (sxstderr, "Constructor error in fsa_to_re: unexpected node operator.");
02359         tete_pop (1);
02360         sxexit (1);
02361         /* FALLTHRU */
02362         case 1:
02363         /* general case */
02364         break;
02365 
02366         case 2:
02367         /* XYZ{YZ}V => X{YZ}+V */
02368         process_substr (p_s, xp + 1, xp, concat_no);
02369         break;
02370 
02371         case 3:
02372         /* V{XY}XYZ => V{XY}+Z */
02373         process_substr (p_s, xp, xp + 1, concat_no);
02374         break;
02375 
02376         case 4:
02377         /* ...{X}{Y}... */
02378         if (is_a_member (l_ptr, r_ptr) /* {U} {U|V} => {U|V} */ )
02379             p_s [xp] = NULL;
02380         else if (is_a_member (r_ptr, l_ptr) /* {U|V} {U} => {U|V} */ )
02381             p_s [xp + 1] = NULL;
02382         else if (is_tail (l_ptr, r_ptr->body.brother.left)
02383              /* {U} {V{U}} => {U|V} */
02384                                   ) {
02385             rl_ptr = r_ptr->body.brother.left;
02386             canon_cn = nb_op_sons (rl_ptr, concat);
02387 
02388             {
02389             struct node **q_s /* 1:canon_cn */ ;
02390             SXINT   canon_x;
02391 
02392             q_s = tete_open (canon_cn);
02393             canon_x = 0;
02394             gather_op_sons (q_s, &canon_x, rl_ptr, concat);
02395             p_s [xp] = NULL;
02396             p_s [xp + 1] = create_op (star, canon (or, l_ptr->body.brother.left, create_list (q_s, (SXINT)1, canon_cn - 1,
02397                  concat)), (struct node*)NULL);
02398             tete_pop (1);
02399             }
02400         }
02401         else if (is_tail (r_ptr, l_ptr->body.brother.left)
02402              /* {U{V}}{V} => {U{V}} */
02403                                   )
02404             p_s [xp + 1] = NULL;
02405         else if (is_a_sublanguage (l_ptr, r_ptr)
02406              /* {X|Y|Z|T}{X[Z]{T}} => {X|Y|Z|T} */
02407                             )
02408             p_s [xp + 1] = NULL;
02409         else
02410             transform (&(p_s [xp]), &(p_s [xp + 1]));
02411         /* {X{Y}{Z}}{T{X|Y|Z}} => {(X|T){Y}{Z}} */
02412 
02413         break;
02414 
02415         case 5:
02416         /* [X] {Y} or {X} {Y}+ or [X] {Y}+ */
02417         if (is_a_member (l_ptr, r_ptr))
02418             p_s [xp] = NULL;
02419 
02420         break;
02421 
02422         case 6:
02423         /* {X} [Y] or {X}+ {Y} or {X}+ [Y] */
02424         if (is_a_member (l_ptr, r_ptr))
02425             p_s [xp + 1] = NULL;
02426 
02427         break;
02428         default: /* pour faire taire gcc -Wswitch-default */
02429 #if EBUG
02430           sxtrap("fsa_to_re","unknown switch case #2");
02431 #endif
02432           break;
02433         }
02434 
02435         l_ptr = create_list (p_s, (SXINT)1, concat_no, concat);
02436         tete_pop (1);
02437         return l_ptr;
02438     }
02439 
02440     case star:
02441     /* star */
02442     left_name = left->name;
02443 
02444     if (left_name == star /* {{X}} => {X} */ )
02445         return (left);
02446 
02447     if (left_name == option /* {[X]} => {X} */  || left_name == plus
02448         /* {{X}+} => {X} */
02449                                     )
02450         return (create_op (star, left->body.brother.left, (struct node*)NULL));
02451 
02452     if (is_a_staror_elem (left, &p) /* {X{X|Y}} => {X{Y}} */ )
02453         return (canon (star, p, (struct node*)NULL));
02454 
02455     if (left_name == concat) {
02456         /* {[X] {Y}} => {X|Y} */
02457         cn = nb_op_sons (left, concat);
02458 
02459         {
02460         struct node **q_s /* 1:cn */ ;
02461         SXINT   x;
02462         struct node *l_ptr;
02463 
02464         q_s = tete_open (cn);
02465         x = 0;
02466         gather_op_sons (q_s, &x, left, concat);
02467 
02468         for (x = 1; x <= cn; x++) {
02469             if (q_s [x]->name == star || q_s [x]->name == option)
02470             q_s [x] = q_s [x]->body.brother.left;
02471             else {
02472             tete_pop (1);
02473             return (create_op (oper, left, right));
02474             }
02475         }
02476 
02477         l_ptr = create_op (star, create_or_list (q_s, (SXINT)1, cn), (struct node*)NULL);
02478         tete_pop (1);
02479         return l_ptr;
02480         }
02481     }
02482 
02483     break;
02484 
02485     case or:
02486     /* or */
02487     {
02488         struct node **p_s /* 1:or_no */ ;
02489         struct node     *l_ptr;
02490         SXINT       x;
02491         SXBOOLEAN is_option = SXFALSE;
02492 
02493         /* [X]|Y or X|[Y] or [X]|[Y] => [X|Y] */
02494         if (left->name == option) {
02495         left = left->body.brother.left;
02496         is_option = SXTRUE;
02497         }
02498 
02499         if (right->name == option) {
02500         right = right->body.brother.left;
02501         is_option = SXTRUE;
02502         }
02503 
02504         or_no = nb_op_sons (left, or) + nb_op_sons (right, or);
02505         p_s = tete_open (or_no);
02506         x = 0;
02507         gather_op_sons (p_s, &x, left, or);
02508         gather_op_sons (p_s, &x, right, or);
02509         l_ptr = create_or_list (p_s, (SXINT)1, or_no);
02510         tete_pop (1);
02511         return is_option ? create_op (option, l_ptr, (struct node*)NULL) : l_ptr;
02512     }
02513 
02514     case plus:
02515     /* plus */
02516     left_name = left->name;
02517 
02518     if (left_name == plus /* {{X}+}+ => {X}+ */  || left_name == star
02519         /* {{X}}+ => {X} */
02520                                      )
02521         return (left);
02522 
02523     if (left_name == option /* {[X]}+ => {X} */ )
02524         return (create_op (star, left->body.brother.left, (struct node*)NULL));
02525 
02526     break;
02527 
02528     case option:
02529     /* option */
02530     left_name = left->name;
02531 
02532     if (left_name == star /* [{X}] => {X} */  || left_name == option
02533         /* [[X]] => [X] */
02534                                     )
02535         return (left);
02536 
02537     if (left_name == plus /* [{X}+] => {X} */ )
02538         return (create_op (star, left->body.brother.left, (struct node*)NULL));
02539 
02540     if (is_a_staror_elem (left, &p) /* [X{X|Y}] => {X{Y}} */ )
02541         return (canon (star, p, (struct node*)NULL));
02542 
02543     break;
02544     }
02545 
02546     return (create_op (oper, left, right));
02547 }
02548 
02549 
02550 
02551 static SXBA_INDEX   get_a_pred (SXBA_INDEX n)
02552 {
02553     SXBA_INDEX  i = -1;
02554 
02555     while ((i = sxba_scan (to_be_processed, i)) >= 0) {
02556     if (SXBA_bit_is_set (M [i], n))
02557         break;
02558     }
02559 
02560     return i;
02561 }
02562 
02563 
02564 
02565 static SXVOID   gen_a_loop (SXBA_INDEX pred, SXBA_INDEX next, SXBA_INDEX loop)
02566 {
02567     /* Il y a une boucle elementaire sur l'etat loop
02568 soit t=trans(pred,next) et l=trans(loop,loop)
02569 si t=l alors 
02570     si pred=next=loop alors trans(pred,next)={t}
02571     sinon trans(pred,next)={t}+
02572 sinon si next=loop alors trans(pred,next)=t {l}
02573       sinon si pred=loop alors trans(pred,next)= {l} t
02574             sinon erreur
02575 */
02576     struct node     *t, *l;
02577 
02578     if ((l = re_ptrs [loop] [loop]) == (t = re_ptrs [pred] [next]))
02579     if (pred == next && next == loop) {
02580         re_ptrs [pred] [next] = canon (star, l, (struct node*)NULL);
02581     }
02582     else {
02583         re_ptrs [pred] [next] = canon (plus, l, (struct node*)NULL);
02584     }
02585     else if (next == loop)
02586     re_ptrs [pred] [next] = canon (concat, t, canon (star, l, (struct node*)NULL));
02587     else
02588     re_ptrs [pred] [next] = canon (concat, canon (star, l, (struct node*)NULL), t);
02589 }
02590 
02591 
02592 static SXVOID   gen_splits (SXBA_INDEX pred, SXBA_INDEX next)
02593 {
02594     /* Calcule les chemins entre pred et succ(next)*/
02595     SXBA_INDEX      succ;
02596     struct node *p1, *p2, *q;
02597 
02598     if (succ_set == NULL) {
02599         sxprepare_for_possible_reset (succ_set);
02600     succ_set = sxba_calloc (SIZE);
02601     }
02602 
02603     sxba_copy (succ_set, M [next]);
02604     /* M [next] est peut etre change dans la boucle.. */
02605     p1 = re_ptrs [pred] [next];
02606 
02607     succ = -1;
02608 
02609 
02610     while ((succ = sxba_scan (succ_set, succ)) >= 0) {
02611     p2 = re_ptrs [next] [succ];
02612 
02613     if (SXBA_bit_is_set (M [pred], succ)) {
02614         /* Il y a deja une ER */
02615         if ((q = re_ptrs [pred] [succ]) == p2)
02616         re_ptrs [pred] [succ] = canon (concat, canon (option, p1, (struct node*)NULL), q);
02617         else
02618         re_ptrs [pred] [succ] = canon (or, canon (concat, p1, p2), q);
02619     }
02620     else {
02621         re_ptrs [pred] [succ] = canon (concat, p1, p2);
02622         SXBA_1_bit (M [pred], succ);
02623         ++(out [pred]);
02624         ++(in [succ]);
02625     }
02626 
02627     if (pred == succ)
02628         if (pred != (SXBA_INDEX)INITIAL_S)
02629         SXBA_1_bit (loop_set, pred);
02630     }
02631 }
02632 
02633 
02634 
02635 static SXVOID   erase (SXBA_INDEX pred, SXBA_INDEX next)
02636 {
02637     /* Supprime la transition entre pred et next */
02638     SXBA_0_bit (M [pred], next);
02639     --(out [pred]);
02640     --(in [next]);
02641 }
02642 
02643 
02644 
02645 static SXBA_INDEX   get_current_node (SXBA get_current_node_to_be_processed)
02646 {
02647     SXINT s, n, e;
02648     SXBA_INDEX i, cur;
02649 
02650     s = e = SIZE;
02651     cur = -1;
02652     i = -1;
02653 
02654     while ((i = sxba_scan (get_current_node_to_be_processed, i)) >= 0) {
02655     if ((n = in [i]) < e) {
02656         cur = i;
02657         e = n;
02658     }
02659     else if (n == e)
02660         if ((n = out [i]) < s) {
02661         cur = i;
02662         s = n;
02663         }
02664     }
02665 
02666     return (cur);
02667 }
02668 
02669 
02670 static  void chose_larger_set (struct node ***p_s, SXBA set, SXINT *mM, SXINT *best_card, SXBA best_set, struct node **best_p, SXINT or_no);
02671 static struct node  *process (struct node ***p_s, SXBA set, SXINT or_no, SXINT *min_s, SXINT *MAX_s)
02672 {
02673     SXBA    /* or_no */ pre_set, post_set, middle_set;
02674     SXINT       pre_card, post_card;
02675     struct node     *pre_p, *post_p, *ret_ptr;
02676 
02677     pre_set = sets_open (or_no);
02678     post_set = sets_open (or_no);
02679     middle_set = sets_open (or_no);
02680     chose_larger_set (p_s, set, min_s, &pre_card, pre_set, &pre_p, or_no);
02681     chose_larger_set (p_s, set, MAX_s, &post_card, post_set, &post_p, or_no);
02682 
02683     if (pre_card >= post_card) {
02684     sxba_minus (sxba_copy (middle_set, set), pre_set);
02685     pre_p = gen_prefixe (p_s, pre_set, pre_p, or_no, min_s, MAX_s);
02686 
02687     if (!sxba_is_empty (middle_set))
02688         ret_ptr = canon (or, pre_p, process (p_s, middle_set, or_no, min_s, MAX_s));
02689     else
02690         ret_ptr = pre_p;
02691     }
02692     else {
02693     sxba_minus (sxba_copy (middle_set, set), post_set);
02694     post_p = gen_suffixe (p_s, post_set, post_p, or_no, min_s, MAX_s);
02695 
02696     if (!sxba_is_empty (middle_set))
02697         ret_ptr = canon (or, process (p_s, middle_set, or_no, min_s, MAX_s), post_p);
02698     else
02699         ret_ptr = post_p;
02700     }
02701 
02702     sets_pop (3);
02703     return ret_ptr;
02704 }
02705 
02706 
02707 
02708 static struct node  *factorize (struct node *or_ptr)
02709 {
02710     SXINT   or_no;
02711 
02712     or_no = nb_op_sons (or_ptr, or);
02713 
02714     {
02715     SXINT   *min_s, *MAX_s /* 1:or_no */ ;
02716     SXINT   i;
02717     SXINT       concat_no, j;
02718     struct node *p;
02719 
02720     min_s = ints_open (or_no);
02721     MAX_s = ints_open (or_no);
02722     i = concat_no = 0;
02723 
02724     for (p = or_ptr; p->name == or; p = p->body.brother.right) {
02725         min_s [++i] = 1;
02726         MAX_s [i] = j = nb_op_sons (p->body.brother.left, concat);
02727         concat_no = (j > concat_no) ? j : concat_no;
02728     }
02729 
02730     min_s [++i] = 1;
02731     MAX_s [i] = j = nb_op_sons (p, concat);
02732     concat_no = (j > concat_no) ? j : concat_no;
02733 
02734     {
02735         struct node     ***p_s /* 1:or_no, 1:concat_no */ ;
02736         SXBA    /* or_no */ set;
02737         SXINT       x;
02738         struct node     *ret_ptr;
02739 
02740         p_s = (struct node***) sxcalloc ((SXUINT) (or_no + 1), sizeof (struct node**));
02741         p_s [0] = NULL;
02742 
02743         for (i = 1; i <= or_no; i++)
02744         p_s [i] = tete_open (concat_no);
02745 
02746         i = 0;
02747 
02748         for (p = or_ptr; p->name == or; p = p->body.brother.right) {
02749         x = 0;
02750         gather_op_sons (p_s [++i], &x, p->body.brother.left, concat);
02751         }
02752 
02753         x = 0;
02754         gather_op_sons (p_s [++i], &x, p, concat);
02755         set = sets_open (or_no);
02756         sxba_fill (set), SXBA_0_bit (set, 0);
02757         ret_ptr = process (p_s, set, or_no, min_s, MAX_s);
02758         sets_pop (1);
02759         tete_pop (or_no);
02760         sxfree (p_s);
02761         ints_pop (2);
02762         return ret_ptr;
02763     }
02764     }
02765 }
02766 
02767 
02768 
02769 static struct node  *reduce (struct node *visited)
02770 {
02771     switch (visited->name) {
02772     case or:
02773     return (factorize (canon (or, reduce (visited->body.brother.left), reduce_or_son (visited->body.brother.right))))
02774          ;
02775 
02776     case concat:
02777     return (canon (concat, reduce (visited->body.brother.left), reduce (visited->body.brother.right)));
02778 
02779     case star:
02780     case plus:
02781     case option:
02782     return (canon (visited->name, reduce (visited->body.brother.left), (struct node*)NULL));
02783 
02784     case leaf:
02785     return (visited);
02786     default:
02787       return (struct node*)NULL; /* Pour compilos tatillons... */
02788     }
02789 }
02790 
02791 
02792 
02793 static struct node  *reduce_or_son (struct node *visited)
02794 {
02795     if (visited->name == or)
02796     return (canon (or, reduce (visited->body.brother.left), reduce_or_son (visited->body.brother.right)));
02797     else
02798     return (reduce (visited));
02799 }
02800 
02801 
02802 
02803 static  void chose_larger_set (struct node ***p_s /* 1:or_no, 1:concat_no */, SXBA set, SXINT *mM, SXINT *best_card, SXBA best_set, struct node **best_p, SXINT or_no)
02804 {
02805     SXBA    /* or_no */ working_set, c_set;
02806     SXBA_INDEX  i, j;
02807     SXINT        c_card;
02808     struct node     *c_p;
02809 
02810     working_set = sets_open (or_no);
02811     c_set = sets_open (or_no);
02812     sxba_copy (working_set, set);
02813     *best_card = 0;
02814     *best_p = NULL;
02815     sxba_empty (best_set);
02816     i = 0;
02817 
02818     while ((i = sxba_scan_reset (working_set, 0)) > 0) {
02819     sxba_empty (c_set);
02820     SXBA_1_bit (c_set, i);
02821     c_card = 1;
02822     c_p = p_s [i] [mM [i]];
02823     j = i;
02824 
02825     while ((j = sxba_scan (working_set, j)) >= 0) {
02826         if (c_p == p_s [j] [mM [j]]) {
02827         SXBA_1_bit (c_set, j);
02828         c_card++;
02829         SXBA_0_bit (working_set, j);
02830         }
02831     }
02832 
02833     if (c_card > *best_card) {
02834         *best_card = c_card;
02835         *best_p = c_p;
02836         sxba_copy (best_set, c_set);
02837     }
02838     }
02839 
02840     sets_pop (2);
02841 }
02842 
02843 
02844 
02845 static struct node  *gen_prefixe (struct node ***p_s, SXBA set, struct node *node_ptr, SXINT or_no, SXINT *min_s, SXINT *MAX_s)
02846 {
02847     SXBA_INDEX         i;
02848     SXINT       j;
02849     SXBOOLEAN   is_option, are_the_same;
02850     struct node     *c_ptr, *ret_ptr;
02851     SXBA    /* or_no */ c_set;
02852 
02853     c_set = sets_open (or_no);
02854     is_option = SXFALSE;
02855     sxba_copy (c_set, set);
02856     i = sxba_scan (set, 0); /* Element 0 non utilise. */
02857     j = ++(min_s [i]);
02858 
02859     if (j > MAX_s [i]) {
02860     is_option = SXTRUE;
02861     SXBA_0_bit (c_set, i);
02862     c_ptr = NULL;
02863     }
02864     else
02865     c_ptr = p_s [i] [j];
02866 
02867     are_the_same = SXTRUE;
02868 
02869     while ((i = sxba_scan (c_set, i)) >= 0) {
02870     j = ++(min_s [i]);
02871 
02872     if (j > MAX_s [i]) {
02873         is_option = SXTRUE;
02874         SXBA_0_bit (c_set, i);
02875     }
02876 
02877     if (c_ptr != p_s [i] [j])
02878         are_the_same = SXFALSE;
02879     }
02880 
02881     if (is_option) {
02882     if (!sxba_is_empty (c_set))
02883         ret_ptr = canon (concat, node_ptr, canon (option, process (p_s, c_set, or_no, min_s, MAX_s), (struct node*)NULL));
02884     else
02885         ret_ptr = node_ptr;
02886     }
02887     else if (are_the_same)
02888     ret_ptr = canon (concat, node_ptr, gen_prefixe (p_s, set, c_ptr, or_no, min_s, MAX_s));
02889     else
02890     ret_ptr = canon (concat, node_ptr, process (p_s, c_set, or_no, min_s, MAX_s));
02891 
02892     sets_pop (1);
02893     return ret_ptr;
02894 }
02895 
02896 
02897 
02898 static struct node  *gen_suffixe (struct node ***p_s, SXBA set, struct node *node_ptr, SXINT or_no, SXINT *min_s, SXINT *MAX_s)
02899 {
02900     SXBA_INDEX i;
02901     SXINT   j;
02902     SXBOOLEAN   is_option, are_the_same;
02903     struct node     *c_ptr, *ret_ptr;
02904     SXBA    /* or_no */ c_set;
02905 
02906     c_set = sets_open (or_no);
02907     is_option = SXFALSE;
02908     sxba_copy (c_set, set);
02909     i = sxba_scan (set, -1);
02910     j = --(MAX_s [i]);
02911 
02912     if (j < min_s [i]) {
02913     is_option = SXTRUE;
02914     SXBA_0_bit (c_set, i);
02915     c_ptr = NULL;
02916     }
02917     else
02918     c_ptr = p_s [i] [j];
02919 
02920     are_the_same = SXTRUE;
02921 
02922     while ((i = sxba_scan (c_set, i)) >= 0) {
02923     j = --(MAX_s [i]);
02924 
02925     if (j < min_s [i]) {
02926         is_option = SXTRUE;
02927         SXBA_0_bit (c_set, i);
02928     }
02929 
02930     if (c_ptr != p_s [i] [j])
02931         are_the_same = SXFALSE;
02932     }
02933 
02934     if (is_option) {
02935     if (!sxba_is_empty (c_set))
02936         ret_ptr = canon (concat, canon (option, process (p_s, c_set, or_no, min_s, MAX_s), (struct node*)NULL), node_ptr);
02937     else
02938         ret_ptr = node_ptr;
02939     }
02940     else if (are_the_same)
02941     ret_ptr = canon (concat, gen_suffixe (p_s, set, c_ptr, or_no, min_s, MAX_s), node_ptr);
02942     else
02943     ret_ptr = canon (concat, process (p_s, c_set, or_no, min_s, MAX_s), node_ptr);
02944 
02945     sets_pop (1);
02946     return ret_ptr;
02947 }
02948 
02949 
02950 
02951 
02952 static struct node  *cut (struct node *node_ptr)
02953 {
02954     if (node_ptr == NULL) {
02955     /* sous arbre deja coupe par ailleurs */
02956     return (struct node*)NULL;
02957     }
02958 
02959     switch (node_ptr->name) {
02960     case leaf:
02961     return (*(node_ptr->body.string_ptr) == SXNUL) ? (NULL) : (node_ptr);
02962 
02963     case concat:
02964     case or:
02965     node_ptr->body.brother.left = cut (node_ptr->body.brother.left);
02966     node_ptr->body.brother.right = cut (node_ptr->body.brother.right);
02967 
02968     return (node_ptr->body.brother.left == NULL && node_ptr->body.brother.right == NULL) ? (NULL) : (node_ptr);
02969 
02970     case star:
02971     case plus:
02972     case option:
02973     node_ptr->body.brother.left = cut (node_ptr->body.brother.left);
02974 
02975     return (node_ptr->body.brother.left == NULL) ? (NULL) : (node_ptr);
02976     default:
02977       return (struct node*)NULL; /* Pour compilos tatillons... */
02978     }
02979 }
02980 
02981 
02982 
02983 static VARSTR   tree_to_string (VARSTR varstr_ptr, struct node *node_ptr)
02984 {
02985   VARSTR    ret_ptr;
02986   struct node           *left, *right;
02987 
02988   if (node_ptr == NULL)
02989     return (varstr_ptr);
02990 
02991   switch (node_ptr->name) {
02992   case leaf:
02993     ret_ptr = varstr_catenate (varstr_ptr, node_ptr->body.string_ptr);
02994     break;
02995 
02996   case concat:
02997     /* version du 17/01/06 */
02998     left = node_ptr->body.brother.left;
02999     right = node_ptr->body.brother.right;
03000 
03001     if (left) {
03002       if (left->name == or)
03003     varstr_ptr = varstr_catenate (tree_to_string (varstr_catenate (varstr_ptr,
03004                                        "("),
03005                               left),
03006                       ")");
03007       else
03008     varstr_ptr = tree_to_string (varstr_ptr, left);
03009 
03010       if (right)
03011     varstr_ptr = varstr_catchar (varstr_ptr, ' ');
03012     }
03013 
03014     if (right) {
03015       if (right->name == or)
03016     varstr_ptr = varstr_catenate (tree_to_string (varstr_catenate (varstr_ptr,
03017                                        "("),
03018                               right),
03019                       ")");
03020       else
03021     varstr_ptr = tree_to_string (varstr_ptr, right);
03022     }
03023 
03024     return varstr_ptr;
03025 
03026     /* NOTREACHED break; */
03027 
03028   case star:
03029     ret_ptr = varstr_catenate (tree_to_string (varstr_catenate (varstr_ptr, meta_op ? meta_op [0] : "{"), node_ptr->body.brother.left), meta_op ? meta_op [1] : "}");
03030     break;
03031 
03032   case or:
03033     if (node_ptr->body.brother.left == NULL)
03034       ret_ptr = tree_to_string (varstr_ptr, node_ptr->body.brother.right);
03035     else if (node_ptr->body.brother.right == NULL)
03036       ret_ptr = tree_to_string (varstr_ptr, node_ptr->body.brother.left);
03037     else
03038       ret_ptr = tree_to_string (varstr_catenate (tree_to_string (varstr_ptr, node_ptr->body.brother.left), " | "),
03039                 node_ptr->body.brother.right);
03040 
03041     break;
03042 
03043   case plus:
03044     ret_ptr = varstr_catenate (tree_to_string (varstr_catenate (varstr_ptr, meta_op ? meta_op [2] : "{"), node_ptr->body.brother.left), meta_op ? meta_op [3] : "}+")
03045       ;
03046     break;
03047 
03048   case option:
03049     ret_ptr = varstr_catenate (tree_to_string (varstr_catenate (varstr_ptr, meta_op ? meta_op [4] : "["), node_ptr->body.brother.left), meta_op ? meta_op [5] : "]");
03050     break;
03051   default: /* pour faire taire gcc -Wswitch-default */
03052     sxinitialise(ret_ptr); /* pour faire taire gcc -Wuninitialized */                 
03053 #if EBUG
03054     sxtrap("fsa_to_re","unknown switch case #3");
03055 #endif
03056     break;
03057   }
03058 
03059   return ret_ptr;
03060 }
03061 
03062 
03063 
03064 
03065 static VARSTR
03066 fsa2re_body (VARSTR varstr_ptr, SXBA *R, SXBA *R_plus, SXINT size, SXINT initial_s, SXINT final_s, SXINT (*get_name_refs) (SXBA_INDEX, SXBA_INDEX, char **))
03067 {
03068     SXBA_INDEX i, j;
03069     SXBA    and_set;
03070     struct node     **re_ptrs_base;
03071 
03072 /* Cette fonction transforme l'ensemble des chemins entre initial_s et final_s
03073    de l'automate R en une expression reguliere. Le nom de la transition
03074    entre l'etat i et l'etat j est donne par la procedure
03075    utilisateur get_name_refs (i, j, string_ptr)
03076 */
03077 /* Les etats de l'automate sont dans [0..size]. */
03078  /* Automate sous forme de vecteur de bits et sa fermeture transitive */
03079 
03080     if (!SXBA_bit_is_set (R_plus [initial_s], final_s))
03081     return varstr_ptr;
03082 
03083     SIZE = size + 1;
03084     INITIAL_S = initial_s;
03085     tree_area_ptr = NULL;
03086     cur_node_no = node_number_per_area;
03087     M = sxbm_calloc (SIZE, SIZE);
03088     re_ptrs = (struct node***) sxalloc ( SIZE, sizeof (struct node**));
03089 
03090     {
03091     struct node **p;
03092 
03093     re_ptrs_base = p = (struct node**) sxcalloc ((SXUINT) (SIZE * SIZE), sizeof (struct node*));
03094 
03095     for (i = 0; i <= (SXBA_INDEX)size; i++) {
03096         re_ptrs [i] = p;
03097         p += SIZE;
03098     }
03099     }
03100 
03101     in = (SXINT*) sxcalloc ((SXUINT) SIZE, sizeof (SXINT));
03102     out = (SXINT*) sxcalloc ((SXUINT) SIZE, sizeof (SXINT));
03103     ints = NULL;
03104     sets = NULL;
03105     to_be_processed = sets_open (size);
03106     loop_set = sets_open (size);
03107     and_set = sets_open (size);
03108     tete = NULL;
03109     to_be_sorted = NULL;
03110     succ_set = NULL;
03111 
03112     for (i = 0; i < head_s_no; i++)
03113     leafs_hd [i] = head_s [i] = NULL;
03114 
03115     SXBA_1_bit (to_be_processed, initial_s);
03116     SXBA_1_bit (to_be_processed, final_s);
03117 
03118     for (i = 0; i <= (SXBA_INDEX)size; i++) {
03119     if (SXBA_bit_is_set (R_plus [initial_s], i) && SXBA_bit_is_set (R_plus [i], final_s))
03120         SXBA_1_bit (to_be_processed, i);
03121     }
03122 
03123     i = -1;
03124 
03125     while ((i = sxba_scan (to_be_processed, i)) >= 0) {
03126     sxba_and (sxba_copy (M [i], R [i]), to_be_processed);
03127     reached_set = M [i];
03128     j = -1;
03129 
03130     while ((j = sxba_scan (reached_set, j)) >= 0) {
03131         re_ptrs [i] [j] = create_leaf (i, j, get_name_refs);
03132         (out [i])++;
03133         (in [j])++;
03134 
03135         if (i == j)
03136         SXBA_1_bit (loop_set, i);
03137     }
03138     }
03139 
03140     SXBA_0_bit (loop_set, initial_s);
03141 
03142     sxba_copy (and_set, to_be_processed);
03143     SXBA_0_bit (and_set, initial_s);
03144     SXBA_0_bit (and_set, final_s);
03145 
03146     while (!sxba_is_empty (and_set)) {
03147     i = -1;
03148 
03149     while ((i = sxba_scan_reset (loop_set, i)) >= 0) {
03150         j = -1;
03151 
03152         while ((j = sxba_scan (to_be_processed, j)) >= 0) {
03153         if (SXBA_bit_is_set (M [j], i) && i != j)
03154             gen_a_loop (j, i, i);
03155         }
03156 
03157         erase (i, i);
03158     }
03159 
03160     current = get_current_node (and_set);
03161     prev = get_a_pred (current);
03162     gen_splits (prev, current);
03163     erase (prev, current);
03164 
03165     if (in [current] == 0) {
03166         SXBA_0_bit (to_be_processed, current);
03167         out [current] = 0;
03168         reached_set = M [current];
03169         i = -1;
03170 
03171         while ((i = sxba_scan (reached_set, i)) >= 0)
03172         (in [i])--;
03173 
03174         sxba_empty (M [current]);
03175     }
03176 
03177     sxba_copy (and_set, to_be_processed);
03178     SXBA_0_bit (and_set, initial_s);
03179     SXBA_0_bit (and_set, final_s);
03180     }
03181 
03182 
03183 /* Cas particulier de boucle sur l'etat final */
03184 
03185     if (SXBA_bit_is_set (M [final_s], final_s)) {
03186     gen_a_loop ((SXBA_INDEX)initial_s, (SXBA_INDEX)final_s, (SXBA_INDEX)final_s);
03187     erase ((SXBA_INDEX)final_s, (SXBA_INDEX)final_s);
03188     }
03189 
03190 
03191 /* Cas particulier de la transition de l'etat final a l'etat initial */
03192 
03193     if (SXBA_bit_is_set (M [final_s], initial_s))
03194     gen_splits ((SXBA_INDEX)initial_s, (SXBA_INDEX)final_s);
03195 
03196 
03197 /* Cas particulier de boucle sur l'etat initial */
03198 
03199     if (SXBA_bit_is_set (M [initial_s], initial_s)) {
03200     gen_a_loop ((SXBA_INDEX)initial_s, (SXBA_INDEX)final_s, (SXBA_INDEX)initial_s);
03201     erase ((SXBA_INDEX)initial_s, (SXBA_INDEX)initial_s);
03202     }
03203 
03204 
03205 /* Factorisation */
03206 
03207     re_ptrs [initial_s] [final_s] = reduce (re_ptrs [initial_s] [final_s]);
03208     /* on supprime les sous arbres ne produisant que la chaine vide */
03209     re_ptrs [initial_s] [final_s] = cut (re_ptrs [initial_s] [final_s]);
03210     varstr_ptr = tree_to_string (varstr_ptr, re_ptrs [initial_s] [final_s]);
03211     sxfree (out);
03212     sxfree (in);
03213     tete_free ();
03214     sets_free ();
03215     ints_free ();
03216 
03217     if (to_be_sorted != NULL)
03218       sxfree (to_be_sorted), to_be_sorted = NULL;
03219 
03220     if (succ_set != NULL)
03221       sxfree (succ_set), succ_set = NULL;
03222 
03223     sxfree (re_ptrs_base);
03224     sxfree (re_ptrs);
03225     sxbm_free (M);
03226     free_tree_areas ();
03227     return varstr_ptr;
03228 }
03229 
03230 
03231 /* Version analogue a fsa_to_re, mais on passe en plus les operateurs kleene et option */
03232 VARSTR
03233 fsa2re (VARSTR varstr_ptr, SXBA *R, SXBA *R_plus, SXINT size, SXINT initial_s, SXINT final_s, SXINT (*get_name_refs) (SXBA_INDEX, SXBA_INDEX, char **), char *op [6] /* op [6] = {"(", ")*", "(", ")+", "(", ")?"}; */)
03234 {
03235   meta_op = op;
03236   return fsa2re_body (varstr_ptr, R, R_plus, size, initial_s, final_s, get_name_refs);
03237 }
03238 
03239 
03240 /* Version analogue a fsa_to_re, mais on passe en plus les operateurs kleene et option */
03241 VARSTR
03242 fsa_to_re (VARSTR varstr_ptr, SXBA *R, SXBA *R_plus, SXINT size, SXINT initial_s, SXINT final_s, SXINT (*get_name_refs) (SXBA_INDEX, SXBA_INDEX, char **))
03243 {
03244   meta_op = NULL;
03245   return fsa2re_body (varstr_ptr, R, R_plus, size, initial_s, final_s, get_name_refs);
03246 }
03247 
03248 
03249 
03250 static SXUINT          eof_trans;
03251 static SXINT           dag_hd_trans_nb, final_state;
03252 #if LOG
03253 static VARSTR          wvstr;
03254 static SXINT            make_code_level_call;
03255 #endif /* LOG */
03256 static XxY_header      dag_hd;
03257 static XH_header       code_hd;
03258 static SXINT             *code2size;
03259 
03260 static struct dag_attr {
03261   SXINT   trans;
03262 } *dag_id2attr;
03263 
03264 static char *(*dag_get_trans_name)(SXINT);
03265 
03266 #define ATOMIC_TRANS   (SXUINT)1
03267 #define CAT_TRANS      (SXUINT)2
03268 #define OR_TRANS       (SXUINT)3
03269 #define OPTION_TRANS   (SXUINT)4
03270 #define FOR_TRANS      (SXUINT)5
03271 
03272 #define SHIFT          (SXBITS_PER_LONG-4)
03273 
03274 
03275 #define ATOMIC_CODE   (ATOMIC_TRANS << SHIFT)
03276 #define CAT_CODE      (CAT_TRANS << SHIFT)
03277 #define OR_CODE       (OR_TRANS << SHIFT)
03278 #define OPTION_CODE   (OPTION_TRANS << SHIFT)
03279 #define FOR_CODE      (FOR_TRANS << SHIFT)
03280 /* L'ancienne definition de ID_CODE etait :
03281       ~( ( (SXUINT)15) << SHIFT )
03282    de type SXUINT. La nouvelle definition a le type SXINT */
03283 #define ID_CODE       (SXINT_MAX >> 3)
03284 
03285 #define code2id(c)    (SXINT)((c) & ID_CODE)
03286 #define code2trans(c) ((c)>> SHIFT)
03287 
03288 static VARSTR
03289 print_code (VARSTR vstr, SXUINT code)
03290 {
03291   SXINT   trans_kind, id, bot, top, cur, trans1_kind;
03292   SXBOOLEAN atomic;
03293   char    *trans_name;
03294   SXUINT code1;
03295 
03296   trans_kind = code2trans (code);
03297   id = code2id (code);
03298   
03299   if (trans_kind == ATOMIC_TRANS) {
03300     trans_name = (*dag_get_trans_name) (id);
03301     vstr = varstr_lcatenate_with_escape (vstr, trans_name, strlen (trans_name), "?*+");
03302   }
03303   else {
03304     bot = XH_X (code_hd, id);
03305     top = XH_X (code_hd, id+1);
03306 
03307     switch (trans_kind) {
03308     case OPTION_TRANS :
03309       code1 = (SXUINT) XH_list_elem (code_hd, bot);
03310       atomic = bot == top-1 && code2trans (code1) == ATOMIC_TRANS;
03311 
03312       if (!atomic)
03313     vstr = varstr_lcatenate (vstr, "(", 1);
03314 
03315       vstr = print_code (vstr, code1);
03316       
03317       for (cur = bot+1; cur < top; cur++) {
03318     vstr = varstr_lcatenate (vstr, " ", 1);
03319     vstr = print_code (vstr, XH_list_elem (code_hd, cur));
03320       }
03321 
03322       if (atomic)
03323     vstr = varstr_lcatenate (vstr, "?", 1);
03324       else
03325     vstr = varstr_lcatenate (vstr, ")?", 2);
03326 
03327       break;
03328 
03329     case CAT_TRANS :
03330       for (cur = bot; cur < top; cur++) {
03331     if (cur > bot)
03332       vstr = varstr_lcatenate (vstr, " ", 1);
03333 
03334     code1 = (SXUINT) XH_list_elem (code_hd, cur);
03335     trans1_kind = code2trans (code1);
03336 
03337     if (trans1_kind == OR_TRANS|| trans1_kind == FOR_TRANS)
03338       vstr = varstr_lcatenate (vstr, "(", 1);
03339       
03340     vstr = print_code (vstr, code1);
03341 
03342     if (trans1_kind == OR_TRANS|| trans1_kind == FOR_TRANS)
03343       vstr = varstr_lcatenate (vstr, ")", 1);
03344       }
03345 
03346       break;
03347 
03348     case OR_TRANS :
03349     case FOR_TRANS :
03350       /* L'appelant a sorti les parentheses eventuelles */
03351       for (cur = bot; cur < top; cur++) {
03352     if (cur > bot)
03353       vstr = varstr_lcatenate (vstr, " | ", 3);
03354 
03355     code1 = (SXUINT) XH_list_elem (code_hd, cur);
03356 
03357     /* Pas de OR/FOR ds un OR/FOR */
03358 #if EBUG && 0
03359     trans1_kind = code2trans (code1);
03360 
03361     if (trans1_kind == OR_TRANS || trans1_kind == FOR_TRANS)
03362       sxtrap (ME, "print_code (no OR or FOR transition should be found as operand of an OR or FOR)");
03363 #endif /* EBUG && 0 */
03364       
03365     vstr = print_code (vstr, code1);
03366       }
03367 
03368       break;
03369 
03370     default :
03371       sxtrap (ME, "print_code (unknown transition kind)");
03372       break;
03373     }
03374   }
03375 
03376   return vstr;
03377 }
03378 
03379 
03380 
03381 static XxY_header paths, branches, pathXbranch, pathXtree;
03382 static XH_header  trees;
03383 static SXINT      *path2lgth, *path2tree, *branch2occur_nb, *tree2size, *tree2occur_nb, *code_stack;
03384 static SXINT      *paths_stack;
03385 static SXBA       branches_set, paths_set, final_paths_set;
03386 
03387 static void
03388 branches_oflw (SXINT old_size, SXINT new_size)
03389 {
03390   sxuse (old_size);
03391   branch2occur_nb = (SXINT *) sxrealloc (branch2occur_nb, new_size+1, sizeof (SXINT));
03392   branches_set = sxba_resize (branches_set, new_size+1);
03393 }
03394 
03395 static void
03396 paths_oflw (SXINT old_size, SXINT new_size)
03397 {
03398   sxuse (old_size);
03399   path2lgth = (SXINT *) sxrealloc (path2lgth, new_size+1, sizeof (SXINT));
03400   path2tree = (SXINT *) sxrealloc (path2tree, new_size+1, sizeof (SXINT));
03401   paths_set = sxba_resize (paths_set, new_size+1);
03402   final_paths_set = sxba_resize (final_paths_set, new_size+1);
03403   paths_stack = (SXINT *) sxrealloc (paths_stack, new_size+1, sizeof (SXINT));
03404 }
03405 
03406 static void
03407 trees_oflw (SXINT old_size, SXINT new_size)
03408 {
03409   sxuse (old_size);
03410   tree2size = (SXINT *) sxrealloc (tree2size, new_size+1, sizeof (SXINT));
03411   tree2occur_nb = (SXINT *) sxrealloc (tree2occur_nb, new_size+1, sizeof (SXINT));
03412 }
03413 
03414 static SXBOOLEAN
03415 set_code (SXUINT *id)
03416 {
03417   SXINT   size, bot, cur, top, code;
03418   SXBOOLEAN ret_val;
03419 
03420   ret_val = XH_set (&code_hd, (SXINT*) id);
03421 
03422   if (!ret_val) {
03423     /* 1ere fois, on calcul size */
03424     size = 0;
03425     bot = XH_X (code_hd, *id);
03426     top = XH_X (code_hd, *id+1);
03427 
03428     for (cur = bot; cur < top; cur++) {
03429       code = XH_list_elem (code_hd, cur);
03430 
03431       if (code2trans (code) == ATOMIC_TRANS)
03432     size++;
03433       else
03434     size += code2size [code2id (code)];
03435     }
03436 
03437     code2size [*id] = size;
03438   }
03439 
03440   return ret_val;
03441 }
03442 
03443 static SXINT gen_branch (SXINT branch, SXINT path, SXBA set, SXBA final_set);
03444 
03445 #if 0
03446 /* Reecrit un chemin path dans code_stack 
03447    L'element gauche de path se trouvera en sommet de pile
03448    retourne le top de code_stack avant le stockage */
03449 static SXINT
03450 gen_path (SXINT path)
03451 {
03452   SXINT code, bot, prev_path;
03453 
03454   bot = DTOP (code_stack);
03455 
03456   if (path) {
03457     prev_path = path;
03458 
03459     while (prev_path) {
03460       code = XxY_Y (paths, prev_path);
03461       DPUSH (code_stack, code);
03462       prev_path = XxY_X (paths, prev_path);
03463     }
03464   }
03465 
03466   return bot;
03467 }
03468 #endif /* 0 */
03469 
03470 
03471 static SXINT
03472 gen_tree (SXINT tree, SXINT path, SXBA set, SXBA final_set)
03473 {
03474   SXUINT  code, code2;
03475   SXINT   bot, cur, top, branch, top_tree_pos, branch_pos, nb, lgth, prev_branch_pos, prev_lgth;
03476   SXBOOLEAN is_leaf;
03477 
03478   sxinitialise (prev_lgth);
03479 
03480   top_tree_pos = DTOP (code_stack);
03481 
03482   if (tree) {
03483     bot = XH_X (trees, tree);
03484     top = XH_X (trees, tree+1);
03485     is_leaf = SXFALSE;
03486 
03487     if (final_set && SXBA_bit_is_set (final_set, path))
03488       is_leaf = SXTRUE;
03489 
03490     branch = XH_list_elem (trees, bot);
03491 
03492     if (branch == 0) {
03493       is_leaf = SXTRUE;
03494       bot++;
03495     }
03496   
03497     nb = 0;
03498 
03499     for (cur = bot; cur < top; cur++) {
03500       branch = XH_list_elem (trees, cur);
03501 
03502       branch_pos = gen_branch (branch, path, set, final_set);
03503 
03504       lgth = DTOP (code_stack)-branch_pos;
03505 
03506       if (lgth) {
03507     if (++nb == 1) {
03508       prev_branch_pos = branch_pos;
03509       prev_lgth = lgth;
03510     }
03511     else {
03512       if (nb == 2) {
03513         if (lgth > 1) {
03514           /* Vraie cat */
03515           while (DTOP (code_stack) > branch_pos) {
03516         code = (SXUINT) DPOP (code_stack);
03517         XH_push (code_hd, (SXINT) code);
03518           }
03519 
03520           set_code (&code);
03521           code |= CAT_CODE;
03522         }
03523         else
03524           code = (SXUINT) DPOP (code_stack);
03525 
03526         if (prev_lgth > 1) {
03527           while (prev_lgth-- > 0 ) {
03528         code2 = (SXUINT) DPOP (code_stack);
03529         XH_push (code_hd, (SXINT) code2);
03530           }
03531 
03532           set_code (&code2);
03533           code2 |= CAT_CODE;
03534           DPUSH (code_stack, (SXINT) code2);
03535         }
03536           
03537         DPUSH (code_stack, (SXINT) code);
03538       }
03539       else {
03540         if (lgth > 1) {
03541           /* Vraie cat */
03542           while (DTOP (code_stack) > branch_pos) {
03543         code = (SXUINT) DPOP (code_stack);
03544         XH_push (code_hd, (SXINT) code);
03545           }
03546 
03547           set_code (&code);
03548           code |= CAT_CODE;
03549           DPUSH (code_stack, (SXINT) code); /* stockage temporaire */
03550         }
03551       }
03552     }
03553       }
03554     }
03555 
03556     if (nb) {
03557       if (is_leaf) {
03558     /* Il faut faire une OPTION */
03559     if (nb == 1) {
03560       if (prev_lgth > 1) {
03561         while (prev_lgth-- > 0 ) {
03562           code = (SXUINT) DPOP (code_stack);
03563           XH_push (code_hd, (SXINT) code);
03564         }
03565 
03566         set_code (&code);
03567         code |= CAT_CODE;
03568       }
03569       else
03570         code = (SXUINT) DPOP (code_stack);
03571     }
03572     else {
03573       while (nb-- > 0) {
03574         code = (SXUINT) DPOP (code_stack);
03575         XH_push (code_hd, (SXINT) code);
03576       }
03577       
03578       set_code (&code);
03579       code |= FOR_CODE;
03580     }
03581         
03582     XH_push (code_hd, (SXINT) code);
03583     set_code (&code);
03584     code |= OPTION_CODE;
03585     DPUSH (code_stack, (SXINT) code);
03586       }
03587       else {
03588     if (nb == 1) {
03589       /* On ne fait rien, meme sur la concat eventuelle (si prev_lgth > 1) */
03590     }
03591     else {
03592       /* alternatives multiples, on en fait un vrai FOR */
03593       while (nb-- > 0) {
03594         code = (SXUINT) DPOP (code_stack);
03595         XH_push (code_hd, (SXINT) code);
03596       }
03597       
03598       set_code (&code);
03599       code |= FOR_CODE;
03600       DPUSH (code_stack, (SXINT) code);
03601     }
03602       }
03603     }
03604   }
03605 
03606   return top_tree_pos;
03607 }
03608 
03609 
03610 /* branch = (id, tree), on met tree puis id ds code_stack et on retourne l'ancien sommet de code_stack */
03611 static SXINT
03612 gen_branch (SXINT branch, SXINT path, SXBA set, SXBA final_set)
03613 {
03614   SXINT tree, tree_pos, id, pos, next_path;
03615 
03616   pos = DTOP (code_stack);
03617   id = XxY_X (branches, branch);
03618 
03619   if (set) {
03620     next_path = XxY_is_set (&paths, path, id);
03621 
03622     if (!SXBA_bit_is_set (set, next_path))
03623       return pos;
03624   }
03625   else
03626     next_path = 0;
03627 
03628   tree = XxY_Y (branches, branch);
03629 
03630   if (tree)
03631     tree_pos = gen_tree (tree, next_path, set, final_set);
03632 
03633   DPUSH (code_stack, id);
03634 
03635   return pos;
03636 }
03637 
03638 
03639 /* On a decide de factoriser "branch" */
03640 /* Si path1, ... pathp sont les chemins menant a branch on va produire qqchose de la forme
03641    (path1 | ... | pathp) branch
03642 */
03643 static SXINT
03644 factorize_branch (SXINT branch)
03645 {
03646   SXINT   bot_branch_pos;
03647 
03648   bot_branch_pos = gen_branch (branch, 0, NULL, NULL);
03649 
03650   gen_tree (path2tree [0] /* arbre a la racine */, 0 /* path de la racine */, paths_set /* Il faut passer par la */, final_paths_set);
03651 
03652   /* c'est l'appelant qui va gerer le contenu de code_stack */
03653   return bot_branch_pos;
03654 }
03655 
03656 /* On complete path_set avec tous les maillons */
03657 static void
03658 expand_paths (void)
03659 {
03660   SXINT path, prev_path;
03661 
03662   while (!IS_EMPTY (paths_stack)) {
03663     path = POP (paths_stack);
03664     prev_path = XxY_X (paths, path);
03665 
03666     if (prev_path && SXBA_bit_is_reset_set (paths_set, prev_path))
03667       PUSH (paths_stack, prev_path);
03668   }
03669 }
03670 
03671 
03672 static SXINT
03673 path2cost (SXINT path)
03674 {
03675   SXINT next_path;
03676 
03677   if (path == 0)
03678     return 0;
03679 
03680   XxY_Xforeach (paths, path, next_path) {
03681     if (!SXBA_bit_is_set (paths_set, next_path)) {
03682       /* next_path n'est pas un chemin de path_set, il va donc falloir
03683      dupliquer path */
03684       return path2lgth [path];
03685     }
03686   }
03687 
03688   return path2cost (XxY_X (paths, path));
03689 }
03690 
03691 
03692 /* On "genere" ds code_stack (path1 | ... | pathn) tree */
03693 /* Les "bons" pathi sont ds paths_set */
03694 static SXINT
03695 factorize_tree (SXINT tree)
03696 {
03697   SXINT bot_tree_pos;
03698 
03699   bot_tree_pos = gen_tree (tree, 0, NULL, NULL);
03700 
03701   gen_tree (path2tree [0] /* arbre a la racine */, 0 /* path de la racine */, paths_set, final_paths_set);
03702 
03703   /* c'est l'appelant qui va gerer le contenu de code_stack */
03704   return bot_tree_pos;
03705 }
03706 
03707 /* Un tree associe' a un noeud n est une liste ordonnee de couple n_tree = (a, p_tree)
03708    si n a une transition sur a conduisant au noeud p
03709    et p_tree est l'arbre associe' au noeud p */
03710 static SXINT
03711 make_tree (SXINT path)
03712 {
03713   SXINT   size, next_path, next_tree, next_branch, path_branch, tree, path_tree, code, bot, top;
03714   SXBOOLEAN is_leaf = SXFALSE;
03715 
03716   size = 0;
03717   bot = DTOP (code_stack);
03718 
03719   XxY_Xforeach (paths, path, next_path) {
03720     code = XxY_Y (paths, next_path);
03721 
03722     if (code) {
03723       next_tree = make_tree (next_path);
03724       size += tree2size [next_tree] /* tree2size [0] == 0 */ + ((code2trans (code) == ATOMIC_TRANS) ? 1 : code2size [code2id (code)]);
03725     
03726       if (XxY_set (&branches, code, next_tree, &next_branch))
03727     branch2occur_nb [next_branch]++;
03728       else
03729     branch2occur_nb [next_branch] = 1;
03730 
03731       DPUSH (code_stack, next_branch);
03732     
03733       XxY_set (&pathXbranch, path, next_branch, &path_branch);
03734     }
03735     else
03736       is_leaf = SXTRUE;
03737   }
03738 
03739   if (size) {
03740     for (top = DTOP (code_stack); top > bot; top--) {
03741       next_branch = DPOP (code_stack);
03742       SXBA_1_bit (branches_set, next_branch);
03743     }
03744 
03745     /* Il faut tous les mettre ds le meme ordre */
03746     if (is_leaf)
03747       XH_push (trees, 0); /* branche qui indique que la racine de l'arbre est (aussi) une feuille */
03748     
03749     next_branch = 0;
03750 
03751     while ((next_branch = sxba_scan_reset (branches_set, next_branch)) > 0) {
03752       XH_push (trees, next_branch);
03753     }
03754 
03755     if (!XH_set (&trees, &tree)) {
03756       tree2size [tree] = size;
03757       tree2occur_nb [tree] = 1;
03758     }
03759     else
03760       tree2occur_nb [tree]++;
03761   }
03762   else {
03763     tree = 0;
03764     tree2size [0] = 0;
03765   }
03766 
03767   path2tree [path] = tree;
03768   XxY_set (&pathXtree, path, tree, &path_tree);
03769 
03770   return tree;
03771 }
03772 
03773 /* ESSAI */
03774 static void
03775 erase_paths (SXBA cur_paths_set)
03776 {
03777   SXINT path;
03778 
03779   path = XxY_top (paths)+1;
03780 
03781   while ((path = sxba_0_rlscan (cur_paths_set, path)) >= 0) {
03782     XxY_erase (paths, path);
03783     path2lgth [path] = 0; /* prudence */
03784   }
03785 }
03786 
03787 /* On a supprime' des maillons ds paths, On note tout ce qui reste accessible */
03788 static SXBOOLEAN
03789 valid_paths (SXINT path)
03790 {
03791   SXINT   next_path;
03792   SXBOOLEAN ret_val = SXFALSE;
03793 
03794   XxY_Xforeach (paths, path, next_path) {
03795     if (SXBA_bit_is_reset_set (paths_set, next_path)) {
03796       valid_paths (next_path);
03797       ret_val = SXTRUE;
03798     }
03799   }
03800 
03801   return ret_val;
03802 }
03803 
03804 static SXBOOLEAN
03805 remake_structures (void)
03806 {
03807   sxba_empty (paths_set);
03808 
03809   if (!valid_paths (0))
03810     /* Tout a disparu */
03811     return SXFALSE;
03812 
03813   /* paths_set est l'ensemble des paths accessibles */
03814   erase_paths (paths_set);
03815 
03816   XxY_clear (&branches);
03817   XxY_clear (&pathXbranch);
03818   XxY_clear (&pathXtree);
03819   XH_clear (&trees);
03820 
03821   make_tree (0 /* racine */);
03822 
03823   return SXTRUE;
03824 }
03825 
03826 /* Supprime le maillon strategique */
03827 static void
03828 clear_path (SXINT path)
03829 {
03830   SXINT prev_path, next_path;
03831 
03832   prev_path = XxY_X (paths, path);
03833 
03834   if (prev_path == 0) {
03835     XxY_erase (paths, path);
03836     path2lgth [path] = 0; /* prudence */
03837   }
03838   else {
03839     XxY_Xforeach (paths, prev_path, next_path) {
03840       if (next_path != path) {
03841     /* embranchement => point strategique */
03842     XxY_erase (paths, path);
03843     path2lgth [path] = 0; /* prudence */
03844     break;
03845       }
03846     }
03847 
03848     if (next_path == 0)
03849       /* Un seul descendant, on va voir + haut */
03850       clear_path (prev_path);
03851   }
03852 }
03853 
03854 /* Supprime "tree" des structures et les met a jour
03855    Retourne SXTRUE ssi elles sont non vides */
03856 static SXBOOLEAN
03857 clear_tree (SXINT tree)
03858 {
03859   SXINT   path_tree, path;
03860   SXBOOLEAN ret_val;
03861 
03862   ret_val = SXTRUE;
03863 
03864   if (tree) {
03865     XxY_Yforeach (pathXtree, tree, path_tree) {
03866       path = XxY_X (pathXtree, path_tree);
03867 
03868       if (path)
03869     clear_path (path);
03870     }
03871 
03872     ret_val = remake_structures ();
03873   }
03874 
03875   return ret_val;
03876 }
03877 
03878 
03879 /* Supprime "branch" des structures et les met a jour
03880    Retourne SXTRUE ssi elles sont non vides */
03881 static SXBOOLEAN
03882 clear_branch (SXINT branch)
03883 {
03884   SXINT   path_branch, prev_path, next_path, code;
03885   SXBOOLEAN ret_val;
03886 
03887   ret_val = SXTRUE;
03888 
03889   if (branch) {
03890     XxY_Yforeach (pathXbranch, branch, path_branch) {
03891       prev_path = XxY_X (pathXbranch, path_branch);
03892       code = XxY_X (branches, branch);
03893       next_path = XxY_is_set (&paths, prev_path, code);
03894 
03895       /* On coupe la branche ... */
03896       /* ... sur le maillon strategique */
03897       clear_path (next_path);
03898     }
03899 
03900     ret_val = remake_structures ();
03901   }
03902 
03903   return ret_val;
03904 }
03905 
03906 
03907 
03908 /* Realise la meilleure factorisation, la supprime des structures et retourne SXTRUE
03909    sinon (structure vide ou plus de factorisation) retourne SXFALSE
03910 */
03911 static void
03912 extract_factor (void)
03913 {
03914   SXINT top, best_tree, best_tree_gain, tree, nb, gain, path_tree, path, best_branch, best_branch_gain, branch;
03915   SXINT code_size, path_branch, next_path, bot_tree, bot_branch;
03916   SXUINT code;
03917 
03918   /* On cherche la meilleure factorisation
03919      Elle peut impliquer soit un tree soit une branch
03920   */
03921 
03922   /* On regarde les tree */
03923   top = XH_top (trees);
03924 
03925   best_tree = 0;
03926   best_tree_gain = 0;
03927 
03928   for (tree = top-1; tree >= 0; tree--) {
03929     if ((nb = tree2occur_nb [tree]) > 1) {
03930       /* tree est partage' entre plusieurs path */
03931       /* gain de la factorisation de tree */
03932       gain = (nb-1) * (tree2size [tree]);
03933       /* Les prefixes vont peut etre devoir etre dupliques */
03934 
03935       sxba_empty (paths_set);
03936 
03937       XxY_Yforeach (pathXtree, tree, path_tree) {
03938     path = XxY_X (pathXtree, path_tree);
03939 
03940     if (path && SXBA_bit_is_reset_set (paths_set, path))
03941       PUSH (paths_stack, path);
03942       }
03943 
03944       expand_paths ();
03945 
03946       XxY_Yforeach (pathXtree, tree, path_tree) {
03947     path = XxY_X (pathXtree, path_tree);
03948 
03949     if (path)
03950       /* On ne compte pas le dernier maillon du chemin path */
03951       gain -= path2cost (XxY_X (paths, path));
03952       }
03953 
03954       if (gain > best_tree_gain) {
03955     best_tree = tree;
03956     best_tree_gain = gain;
03957       }
03958     }
03959   }
03960 
03961   /* ... et les branches */
03962   top = XxY_top (branches);
03963 
03964   best_branch = 0;
03965   best_branch_gain = 0;
03966 
03967   for (branch = top; branch > 0; branch--) {
03968     if ((nb = branch2occur_nb [branch]) > 1) {
03969       /* branch est partage' entre plusieurs path */
03970       /* gain de la factorisation de branch */
03971       code = (SXUINT) XxY_X (branches, branch);
03972       tree = XxY_Y (branches, branch);
03973 
03974       /* Si on factorize, on va gagner ... */
03975       if (code2trans (code) == ATOMIC_TRANS)
03976     code_size = 1;
03977       else
03978     code_size = code2size [code2id (code)];
03979 
03980       gain = (nb-1) * (code_size+tree2size [tree]);
03981 
03982       /* Les prefixes vont peut etre devoir etre dupliques */
03983       sxba_empty (paths_set);
03984 
03985       XxY_Yforeach (pathXbranch, branch, path_branch) {
03986     path = XxY_X (pathXbranch, path_branch);
03987     next_path = XxY_is_set (&paths, path, (SXINT) code);
03988 
03989     if (SXBA_bit_is_reset_set (paths_set, next_path))
03990       PUSH (paths_stack, next_path);
03991       }
03992 
03993       expand_paths ();
03994 
03995       XxY_Yforeach (pathXbranch, branch, path_branch) {
03996     path = XxY_X (pathXbranch, path_branch);
03997     
03998     if (path)
03999       gain -= path2cost (path);
04000       }
04001 
04002       if (gain > best_branch_gain) {
04003     best_branch = branch;
04004     best_branch_gain = gain;
04005       }
04006     }
04007   }
04008 
04009   if (best_tree || best_branch) {
04010     sxba_empty (paths_set);
04011     sxba_empty (final_paths_set);
04012 
04013     if (best_tree_gain >= best_branch_gain) {
04014       /* factorisation d'arbres */
04015       XxY_Yforeach (pathXtree, best_tree, path_tree) {
04016     path = XxY_X (pathXtree, path_tree);
04017 
04018     if (path && SXBA_bit_is_reset_set (paths_set, path)) {
04019       SXBA_1_bit (final_paths_set, path);
04020       PUSH (paths_stack, path);
04021     }
04022       }
04023 
04024       expand_paths ();
04025 
04026       bot_tree = factorize_tree (best_tree);
04027 
04028       /* On en fait un identifiant unique */
04029       if (DTOP (code_stack) > bot_tree+1) {
04030     /* Vraie cat */
04031     while (DTOP (code_stack) > bot_tree) {
04032       code = (SXUINT) DPOP (code_stack);
04033       XH_push (code_hd, (SXINT) code);
04034     }
04035 
04036     set_code (&code);
04037     code |= CAT_CODE;
04038     DPUSH (code_stack, (SXINT) code);
04039       }
04040 
04041       /* On nettoie et on met a jour toutes les structures impactees par la generation precedente */
04042       if (clear_tree (best_tree))
04043     extract_factor ();
04044 
04045       return;
04046     }
04047 
04048     /* factorisation de branches */
04049     /* On va faire cette factorisation */
04050     XxY_Yforeach (pathXbranch, best_branch, path_branch) {
04051       path = XxY_X (pathXbranch, path_branch);
04052 
04053       if (path && SXBA_bit_is_reset_set (paths_set, path)) {
04054     SXBA_1_bit (final_paths_set, path);
04055     PUSH (paths_stack, path);
04056       }
04057     }
04058 
04059     expand_paths ();
04060 
04061     bot_branch = factorize_branch (best_branch);
04062       
04063     /* On en fait un identifiant unique */
04064     if (DTOP (code_stack) > bot_branch+1) {
04065       /* Vraie cat */
04066       while (DTOP (code_stack) > bot_branch) {
04067     code = (SXUINT) DPOP (code_stack);
04068     XH_push (code_hd, (SXINT) code);
04069       }
04070 
04071       set_code (&code);
04072       code |= CAT_CODE;
04073       DPUSH (code_stack, (SXINT) code);
04074     }
04075 
04076     /* On nettoie et on met a jour toutes les structures impactees par la generation precedente */
04077     if (clear_branch (best_branch))
04078       extract_factor ();
04079 
04080     return;
04081   }
04082 
04083   /* On a atteint la racine avec une structure non vide et non factorisable (sauf peut-etre a gauche) */
04084   bot_tree = gen_tree (path2tree [0], 0, NULL, NULL);
04085     
04086   /* On en fait un identifiant unique */
04087   if (DTOP (code_stack) > bot_tree+1) {
04088     /* Vraie cat */
04089     while (DTOP (code_stack) > bot_tree) {
04090       code = (SXUINT) DPOP (code_stack);
04091       XH_push (code_hd, (SXINT) code);
04092     }
04093 
04094     set_code (&code);
04095     code |= CAT_CODE;
04096     DPUSH (code_stack, (SXINT) code);
04097   }
04098 }
04099 
04100 
04101 static SXUINT
04102 factorize_OR (SXINT or_code)
04103 {
04104   SXINT id, bot, cur, top, cur_trans_kind, path, cur_id, bot1, cur1, top1, lgth;
04105   SXBOOLEAN has_common;
04106   SXUINT code, code1, cur_code;
04107 
04108   /* On commence par fabriquer dans paths une factorisation gauche (arbre des prefixes) */
04109   XxY_clear (&paths);
04110 
04111   id = code2id (or_code);
04112   bot = XH_X (code_hd, id);
04113   top = XH_X (code_hd, id+1);
04114   has_common = SXFALSE;
04115 
04116   for (cur = bot; cur < top; cur++) {
04117     cur_code = (SXUINT) XH_list_elem (code_hd, cur);
04118     cur_trans_kind = code2trans (cur_code);
04119 
04120     if (cur_trans_kind == ATOMIC_TRANS || cur_trans_kind == OPTION_TRANS) {
04121       if (XxY_set (&paths, 0, (SXINT) cur_code, &path))
04122     has_common = SXTRUE;
04123 
04124       XxY_set (&paths, path, 0, &path); /* "etat" final */
04125     }
04126     else {
04127       cur_id = code2id (cur_code);
04128       bot1 = XH_X (code_hd, cur_id);
04129       top1 = XH_X (code_hd, cur_id+1);
04130       path = 0;
04131       lgth = 0;
04132 
04133       for (cur1 = bot1; cur1 < top1; cur1++) {
04134     code1 = (SXUINT) XH_list_elem (code_hd, cur1);
04135     lgth++;
04136     
04137     if (!XxY_set (&paths, path, (SXINT) code1, &path))
04138       path2lgth [path] = lgth;
04139     else
04140       has_common = SXTRUE;
04141       }
04142     
04143       XxY_set (&paths, path, 0, &path); /* "etat" final */
04144     }
04145   }
04146 
04147   /* Il y a de la factorisation gauche */
04148   /* ... on regarde s'il y a aussi de la factorisation droite sur les memes brins ... */
04149   /* ... que l'on genere ... */
04150   /* on fait ce qui suit */
04151   XxY_clear (&branches);
04152   XxY_clear (&pathXbranch);
04153   XxY_clear (&pathXtree);
04154   XH_clear (&trees);
04155 
04156   /* On fabrique maintenant les sous-arbres commun de l'arbre des prefixes */
04157   /* un arbre est un ensemble (un XH) de branches (une feuille est un arbre vide de code 0)
04158      une branche est un couple (XxY) (trans, arbre) */
04159   make_tree (0 /* racine */);
04160 
04161   /* exploiter les tailles pour obtenir la taille min */
04162   extract_factor ();
04163   /* Le resultat est dans code_stack */
04164       
04165   if (DTOP (code_stack) > 1) {
04166     /* Un FOR */
04167     while (!IS_EMPTY (code_stack)) {
04168       code = (SXUINT) DPOP (code_stack);
04169       XH_push (code_hd, (SXINT) code);
04170     }
04171   
04172     set_code (&code);
04173     code |= FOR_CODE;
04174   }
04175   else {
04176     code = (SXUINT) DPOP (code_stack);
04177   }
04178       
04179   return code;
04180 }
04181 
04182 
04183 static SXUINT
04184 make_code (SXUINT code1, SXUINT code2, SXUINT what_to_do)
04185 {
04186   SXINT trans1_kind, trans2_kind, id1, id2, bot1, cur1, top1, bot2, cur2, top2;
04187   SXUINT code;
04188 
04189 
04190 #if LOG
04191   if (make_code_level_call == 0)
04192     varstr_raz (wvstr);
04193 
04194   switch (what_to_do) {
04195   case ATOMIC_TRANS:
04196     wvstr = print_code (wvstr, code1);
04197     break;
04198   case CAT_TRANS:
04199     wvstr = varstr_lcatenate (wvstr, "(", 1);
04200     wvstr = print_code (wvstr, code1);
04201     wvstr = varstr_lcatenate (wvstr, ") . (", 5);
04202     wvstr = print_code (wvstr, code2);
04203     wvstr = varstr_lcatenate (wvstr, ")", 1);
04204     break;
04205   case OR_TRANS:
04206     wvstr = varstr_lcatenate (wvstr, "(", 1);
04207     wvstr = print_code (wvstr, code1);
04208     wvstr = varstr_lcatenate (wvstr, ") | (", 5);
04209     wvstr = print_code (wvstr, code2);
04210     wvstr = varstr_lcatenate (wvstr, ")", 1);
04211     break;
04212   case OPTION_TRANS:
04213     wvstr = varstr_lcatenate (wvstr, "(", 1);
04214     wvstr = print_code (wvstr, code1);
04215     wvstr = varstr_lcatenate (wvstr, ")?", 2);
04216     break;
04217   case FOR_TRANS:
04218     /* make_code ne fait jamais directement de FOR_TRANS */
04219     sxtrap (ME, "make_code (FOR_TRANS)");
04220     break;
04221   default:
04222     sxtrap (ME, "make_code");
04223     break;
04224   }
04225 
04226   wvstr = varstr_lcatenate (wvstr, " => ", 4);
04227 #endif /* LOG */
04228 
04229   switch (what_to_do) {
04230   case ATOMIC_TRANS:
04231     code = code1 | ATOMIC_CODE;
04232 
04233     break;
04234 
04235   case CAT_TRANS:
04236     trans1_kind = code2trans (code1);
04237     trans2_kind = code2trans (code2);
04238 
04239     if (trans1_kind == OR_TRANS) {
04240       /* On le factorise */
04241       code1 = factorize_OR (code1);
04242       trans1_kind = code2trans (code1);
04243     }
04244 
04245     if (trans2_kind == OR_TRANS) {
04246       /* On le factorise */
04247       code2 = factorize_OR (code2);
04248       trans2_kind = code2trans (code2);
04249     }
04250 
04251     if (trans1_kind == CAT_TRANS) {
04252       id1 = code2id (code1);
04253       bot1 = XH_X (code_hd, id1);
04254       top1 = XH_X (code_hd, id1+1);
04255 
04256       for (cur1 = bot1; cur1 < top1; cur1++) {
04257     XH_push (code_hd, XH_list_elem (code_hd, cur1));
04258       }
04259     }
04260     else {
04261       /* trans1_kind == ATOMIC_TRANS || trans1_kind == FOR_TRANS || trans1_kind == OPTION_TRANS */
04262       XH_push (code_hd, (SXINT) code1);
04263     }
04264 
04265     if (trans2_kind == CAT_TRANS) {
04266       id2 = code2id (code2);
04267       bot2 = XH_X (code_hd, id2);
04268       top2 = XH_X (code_hd, id2+1);
04269 
04270       for (cur2 = bot2; cur2 < top2; cur2++) {
04271     XH_push (code_hd, XH_list_elem (code_hd, cur2));
04272       }
04273     }
04274     else {
04275       /* trans2_kind == ATOMIC_TRANS || trans2_kind == FOR_TRANS || trans2_kind == OPTION_TRANS */
04276       XH_push (code_hd, (SXINT) code2);
04277     }
04278 
04279     set_code (&code);
04280     code |= CAT_CODE;
04281 
04282     break;
04283 
04284   case OR_TRANS:
04285     if (code1 == code2) {
04286       /* Au cas ou ... */
04287       code = code1;
04288     }
04289     else {
04290       trans1_kind = code2trans (code1);
04291       trans2_kind = code2trans (code2);
04292 
04293 #if EBUG
04294       if (trans1_kind == FOR_TRANS || trans2_kind == FOR_TRANS)
04295     /* FOR_TRANSes are never OR'ed */
04296     sxtrap (ME, "make_code (FOR_TRANS)");
04297 #endif /* EBUG */
04298 
04299       /* Ici, code1 et code2 sont issus du meme etat, si l'automate est de'terministe, ils ne commencent donc pas par le meme terminal */
04300       /* Soit code1 = X T et code2 = Y T, (suffixe de X et Y differents), T pouvant etre vide */
04301       /* Si T vide => X | Y
04302      Si T non vide
04303      Si X non vide et Y non vide => (X | Y) T
04304      Si X vide et Y non vide     =>  [Y] T
04305      Si X non vide et Y vide     =>  [X] T
04306      Si X vide et Y vide         => impossible
04307       */
04308     
04309       switch (trans1_kind) {
04310       case ATOMIC_TRANS:
04311       case CAT_TRANS:
04312       case OPTION_TRANS:
04313     XH_push (code_hd, (SXINT) code1);
04314     break;
04315 
04316       case OR_TRANS:
04317     id1 = code2id (code1);
04318     bot1 = XH_X (code_hd, id1);
04319     top1 = XH_X (code_hd, id1+1);
04320         
04321     for (cur1 = bot1; cur1 < top1; cur1++) {
04322       XH_push (code_hd, XH_list_elem (code_hd, cur1));
04323     }
04324 
04325     break;
04326 
04327       default :
04328     sxtrap (ME, "make_code");
04329     break;
04330       }
04331     
04332       switch (trans2_kind) {
04333       case ATOMIC_TRANS:
04334       case CAT_TRANS:
04335       case OPTION_TRANS:
04336     XH_push (code_hd, (SXINT) code2);
04337     break;
04338 
04339       case OR_TRANS:
04340     id2 = code2id (code2);
04341     bot2 = XH_X (code_hd, id2);
04342     top2 = XH_X (code_hd, id2+1);
04343         
04344     for (cur2 = bot2; cur2 < top2; cur2++) {
04345       XH_push (code_hd, XH_list_elem (code_hd, cur2));
04346     }
04347 
04348     break;
04349 
04350       default :
04351     sxtrap (ME, "make_code");
04352     break;
04353       }
04354 
04355       set_code (&code);
04356       code |= OR_CODE;
04357     }
04358 
04359     break;
04360 
04361   case OPTION_TRANS:
04362     trans1_kind = code2trans (code1);
04363 
04364     if (trans1_kind == OPTION_TRANS)
04365       return code1;
04366 
04367     if (trans1_kind == OR_TRANS)
04368       code1 = factorize_OR (code1);
04369 
04370     XH_push (code_hd, (SXINT) code1);
04371     set_code (&code);
04372     
04373     code |= OPTION_CODE;
04374 
04375     break;
04376 
04377   case FOR_TRANS:
04378     /* make_code ne fait jamais directement de FOR_TRANS */
04379     sxtrap (ME, "make_code (FOR_TRANS)");
04380 
04381     break;
04382 
04383   default :
04384     sxtrap (ME, "make_code");
04385     break;
04386   }
04387 
04388 #if LOG
04389   wvstr = print_code (wvstr, code);
04390 
04391   if (make_code_level_call == 0)
04392     printf ("%s\n", varstr_tostr (wvstr));
04393 
04394   trans1_kind = code2trans (code);
04395 
04396   if (trans1_kind != ATOMIC_TRANS) {
04397     id1 = code2id (code);
04398     bot1 = XH_X (code_hd, id1);
04399     top1 = XH_X (code_hd, id1+1);
04400 
04401     if (trans1_kind == OPTION_TRANS) {
04402       /* Si unique ca ne doit pas etre une OPTION */
04403       if (bot1+1 == top1 && code2trans (XH_list_elem (code_hd, bot1)) == OPTION_TRANS)
04404       sxtrap (ME, "make_code");
04405     }
04406     else {
04407       if (trans1_kind == CAT_TRANS) {
04408     /* On verifie qu'un cat ne contient pas de cat */
04409     for (cur1 = bot1; cur1 < top1; cur1++) {
04410       if (code2trans (XH_list_elem (code_hd, cur1)) == CAT_TRANS)
04411         sxtrap (ME, "make_code");
04412     }
04413       }
04414       else {
04415     /* trans1_kind == OR_TRANS || trans1_kind == FOR_TRANS */
04416     /* On verifie qu'un or ne contient ni or ni for */
04417     for (cur1 = bot1; cur1 < top1; cur1++) {
04418       trans1_kind = code2trans (XH_list_elem (code_hd, cur1));
04419 
04420       if (trans1_kind == OR_TRANS || trans1_kind == FOR_TRANS)
04421         sxtrap (ME, "make_code");
04422     }
04423       }
04424     }
04425   }
04426 #endif /* LOG */
04427 
04428   return code;
04429 }
04430 
04431 
04432 
04433 static void
04434 fill_dag_hd (SXINT p, SXINT t, SXINT q)
04435 {
04436   SXINT           dag_id;
04437   SXBOOLEAN         first_time;
04438   struct dag_attr *attr_ptr;
04439 
04440   first_time = !XxY_set (&dag_hd, p, q, &dag_id);
04441 
04442   attr_ptr = dag_id2attr+dag_id;
04443 
04444   if (first_time) {
04445     dag_hd_trans_nb++;
04446     attr_ptr->trans = ATOMIC_CODE | t;
04447   }
04448   else {
04449     /* On fait un or */
04450     attr_ptr->trans = (SXINT) make_code ((SXUINT) (attr_ptr->trans), ATOMIC_CODE | (SXUINT) t, OR_TRANS);
04451   }
04452 }
04453 
04454 
04455 /*
04456     ab|b      => [a]b
04457     [a]b|b    => [a]b
04458     a[b]|[b]  => [a][b]
04459     ab|[b]    => [[a]b]
04460     a[b]|b    => rien
04461 
04462     ab|a      => a[b]
04463     a[b]|a    => a[b]
04464     [a]b|[a]  => [a][b]
04465     ab|[a]    => [a[b]]
04466     [a]b|a    => rien
04467 */
04468 
04469 /* On forme, a partir de la concatenation de dag1_id et de dag2_id une transition unique
04470    qui vient s'inserer ds dag_hd */
04471 static SXINT
04472 make_a_new_trans (SXINT dag1_id, SXINT dag2_id)
04473 {
04474   SXINT           p, q, dag_id, code, code1, code2;
04475   struct dag_attr *attr_ptr;
04476   SXBOOLEAN         first_time;
04477 
04478 #if EBUG
04479   if (XxY_Y (dag_hd, dag1_id) != XxY_X (dag_hd, dag2_id))
04480     sxtrap (ME, "make_a_new_trans");
04481 #endif /* EBUG */
04482   
04483   p = XxY_X (dag_hd, dag1_id);
04484   q = XxY_Y (dag_hd, dag2_id);
04485 
04486   code1 = dag_id2attr [dag1_id].trans;
04487   code2 = dag_id2attr [dag2_id].trans;
04488 
04489   if ((SXUINT)code2 == (eof_trans | ATOMIC_CODE)) {
04490     if (code2trans (code1) == OR_TRANS) {
04491       /* On le factorise */
04492       code = factorize_OR (code1);
04493     }
04494     else
04495       code = code1;
04496   }
04497   else
04498     code = make_code (code1, code2, CAT_TRANS);
04499 
04500   first_time = !XxY_set (&dag_hd, p, q, &dag_id);
04501   attr_ptr = dag_id2attr+dag_id;
04502 
04503   if (first_time) {
04504     dag_hd_trans_nb++;
04505     attr_ptr->trans = code;
04506   }
04507   else {
04508     /* On fait un or */
04509     if ((SXUINT)attr_ptr->trans == (eof_trans | ATOMIC_CODE)) {
04510       attr_ptr->trans = (SXINT) make_code (code, (SXUINT) 0, OPTION_TRANS);
04511     }
04512     else
04513       attr_ptr->trans = (SXINT) make_code ((SXUINT) (attr_ptr->trans), code, OR_TRANS);
04514   }
04515 
04516   return dag_id;
04517 }
04518 
04519 
04520 static SXINT
04521 dag_reduce (void)
04522 {
04523   SXINT return_dag_id = 0, dag_id, trans_id, trans_id2, q;
04524 
04525   for (q = 2; q < final_state; q++) {
04526     dag_id = 0;
04527 
04528     XxY_Yforeach (dag_hd, q, trans_id) {
04529       /* p -> q */
04530       XxY_Xforeach (dag_hd, q, trans_id2) {
04531     /* q -> r */
04532     /* p != q != r (car DAG) */
04533     dag_id = make_a_new_trans (trans_id, trans_id2);
04534 #if LOG
04535     if (dag_id)
04536       printf ("Merged %ld -> %ld -> %ld into %ld -> %ld\n",
04537           XxY_X (dag_hd, trans_id), q, XxY_Y (dag_hd, trans_id2),
04538           XxY_X (dag_hd, trans_id), XxY_Y (dag_hd, trans_id2));
04539     else 
04540       printf ("Could not merge %ld -> %ld -> %ld\n",
04541           XxY_X (dag_hd, trans_id), q, XxY_Y (dag_hd, trans_id2));
04542 #endif /* LOG */      
04543       }
04544     }
04545 
04546     if (dag_id) {
04547       return_dag_id = dag_id;
04548 
04549       XxY_Yforeach (dag_hd, q, trans_id) {
04550     XxY_erase (dag_hd, trans_id);
04551     dag_hd_trans_nb--;
04552       }
04553       
04554       XxY_Xforeach (dag_hd, q, trans_id2) {
04555     XxY_erase (dag_hd, trans_id2);
04556     dag_hd_trans_nb--;
04557       }
04558     }
04559   }
04560 
04561   return return_dag_id;
04562 }
04563 
04564 
04565 static void
04566 code_hd_oflw (SXINT old_size, SXINT new_size)
04567 {
04568   sxuse (old_size);
04569   code2size = (SXINT*) sxrealloc (code2size, new_size+1, sizeof (SXINT));
04570 }
04571 
04572 
04573 static void
04574 dag_hd_oflw (SXINT old_size, SXINT new_size)
04575 {
04576   sxuse (old_size);
04577   dag_id2attr = (struct dag_attr*) sxrealloc (dag_id2attr, new_size+1, sizeof (struct dag_attr));
04578 }
04579 
04580 
04581 VARSTR
04582 dag2re (VARSTR varstr_ptr, 
04583     SXINT dag_init_state, 
04584     SXINT dag_final_state, 
04585     SXINT eof_ste, 
04586     void (*dag_extract_trans) (SXINT, void (*fill_dag_hd) (SXINT p, SXINT t, SXINT q)), 
04587     char *(*get_trans_name) (SXINT))
04588 {
04589   SXINT p, single_trans, code;
04590 
04591   eof_trans = (SXUINT)eof_ste;
04592   dag_get_trans_name = get_trans_name;
04593   final_state = dag_final_state;
04594 
04595   XH_alloc (&code_hd, "code_hd", dag_final_state+1, 1, 64, code_hd_oflw, NULL);
04596   code2size = (SXINT*) sxalloc (XH_size (code_hd)+1, sizeof (SXINT));
04597 
04598 #if LOG
04599   wvstr = varstr_alloc (256);
04600 #endif /* LOG */
04601   XxY_alloc (&dag_hd, "dag_hd", dag_final_state+1, 1, 1 /* Xforeach */, 1 /* Yforeach */, dag_hd_oflw, NULL);
04602   dag_id2attr = (struct dag_attr*) sxalloc (XxY_size (dag_hd)+1, sizeof (struct dag_attr));
04603 
04604   dag_hd_trans_nb = 0;
04605 
04606   for (p = dag_init_state; p < dag_final_state; p++) {
04607     (*dag_extract_trans) (p, fill_dag_hd);
04608   }
04609 
04610   /* Nelle factorisation des OR */
04611   XxY_alloc (&paths, "paths", 30, 1, 1 /* Xforeach */, 0, paths_oflw, NULL);
04612   path2lgth = (SXINT *) sxalloc (XxY_size (paths)+1, sizeof (SXINT));
04613   path2tree = (SXINT *) sxalloc (XxY_size (paths)+1, sizeof (SXINT));
04614   paths_set = sxba_calloc (XxY_size (paths)+1);
04615   final_paths_set = sxba_calloc (XxY_size (paths)+1);
04616   paths_stack = (SXINT *) sxalloc (XxY_size (paths)+1, sizeof (SXINT)), paths_stack [0] = 0;
04617   XxY_alloc (&branches, "branches", 30, 1, 0, 0, branches_oflw, NULL);
04618   branch2occur_nb = (SXINT *) sxalloc (XxY_size (branches)+1, sizeof (SXINT));
04619   branches_set = sxba_calloc (XxY_size (branches)+1);
04620   XxY_alloc (&pathXbranch, "pathXbranch", 30, 1, 0, 1 /* Yforeach */, NULL, NULL);
04621   XxY_alloc (&pathXtree, "pathXtree", 30, 1, 0, 1 /* Yforeach */, NULL, NULL);
04622   XH_alloc (&trees, "trees", 30, 1, 4, trees_oflw, NULL);
04623   tree2size = (SXINT *) sxalloc (XH_size (trees)+1, sizeof (SXINT));
04624   tree2occur_nb = (SXINT *) sxalloc (XH_size (trees)+1, sizeof (SXINT));
04625   DALLOC_STACK (code_stack, 100);
04626 
04627   single_trans = 1; /* Si trans unique ds le DAG */
04628 
04629 #if EBUG
04630   {
04631     SXINT prev_dag_hd_trans_nb = dag_hd_trans_nb;
04632 #endif /* EBUG */
04633     
04634     while (dag_hd_trans_nb > 1) {
04635       single_trans = dag_reduce ();
04636 #if EBUG
04637       if (dag_hd_trans_nb == prev_dag_hd_trans_nb)
04638     sxtrap (ME, "dag2re (could not extract unique initial and final states)");
04639       prev_dag_hd_trans_nb = dag_hd_trans_nb;
04640     }
04641 #endif /* EBUG */
04642   }
04643     
04644   code = dag_id2attr [single_trans].trans;
04645 
04646   if (code2trans (code) == OR_TRANS)
04647     code = factorize_OR (code);
04648   
04649   XxY_free (&paths);
04650   sxfree (paths_set), paths_set = NULL;
04651   sxfree (final_paths_set), final_paths_set = NULL;
04652   sxfree (paths_stack), paths_stack = NULL;
04653   sxfree (path2tree), path2tree = NULL;
04654   sxfree (path2lgth), path2lgth = NULL;
04655   XxY_free (&branches);
04656   sxfree (branch2occur_nb), branch2occur_nb = NULL;
04657   sxfree (branches_set), branches_set = NULL;
04658   XxY_free (&pathXbranch);
04659   XxY_free (&pathXtree);
04660   XH_free (&trees);
04661   sxfree (tree2size), tree2size = NULL;
04662   sxfree (tree2occur_nb), tree2occur_nb = NULL;
04663   DFREE_STACK (code_stack);
04664 
04665   varstr_ptr = print_code (varstr_ptr, code);
04666 
04667 #if LOG
04668   varstr_free (wvstr);
04669 #endif /* LOG */
04670   XxY_free (&dag_hd);
04671   sxfree (dag_id2attr), dag_id2attr = NULL;
04672   XH_free (&code_hd);
04673   sxfree (code2size), code2size = NULL;
04674 
04675   return varstr_ptr;
04676 }
04677 
04678 
04679 
04680 /* construction "rapide" d'un "dico" qui pourrait etre utilise' (lentement) ds sxspell */
04681 
04682 void
04683 word_tree_oflw (struct word_tree_struct *word_tree_ptr, SXINT old_size, SXINT new_size)
04684 {
04685   if (word_tree_ptr->final_path_set)
04686     word_tree_ptr->final_path_set = sxba_resize (word_tree_ptr->final_path_set, new_size+1);
04687   else
04688     word_tree_ptr->path2id = (SXINT *) sxrecalloc (word_tree_ptr->path2id, old_size+1, new_size+1, sizeof (SXINT));
04689 }
04690 
04691 
04692 /* Si to_be_mininized est SXTRUE, dico2 subira ulterieurement une phase de minimisation
04693    pour ce faire on a besoin d'une structure supplementaire (dico2_lgth2top_path_hd et dico2_lgth2path) */
04694 void
04695 word_tree_alloc (struct word_tree_struct *word_tree_ptr, 
04696          char *name, 
04697          SXINT word_nb, 
04698          SXINT word_lgth,
04699          SXINT Xforeach, 
04700          SXINT Yforeach, 
04701          SXBOOLEAN from_left_to_right, 
04702          SXBOOLEAN with_path2id, 
04703          void (*oflw) (SXINT, SXINT), 
04704          FILE *stats)
04705 {
04706   SXINT size;
04707 
04708   word_tree_ptr->name = name;
04709   word_tree_ptr->stats = stats;
04710   word_tree_ptr->private.from_left_to_right = from_left_to_right; /* Les mots sont lus de gauche a droite */
04711   word_tree_ptr->is_static = SXFALSE;
04712 
04713   size = word_nb*word_lgth;
04714 
04715   XxY_alloc (&word_tree_ptr->paths, word_tree_ptr->name, size+1, 1, Xforeach, Yforeach, oflw, NULL /* Pas word_tree_ptr->stats !! */);
04716   XxY_set (&word_tree_ptr->paths, 0, -1, &word_tree_ptr->root); /* word_tree_ptr->root == 1 */
04717 
04718   /* Il y a 2 facons de designer les etats finals */
04719   /* word_tree_ptr->path2id ne peut etre utilise' que si to_be_mininized == SXFALSE */
04720 
04721   /* Attention, les 2 qui suivent peuvent etre utilises ds une struct word_tree_ptr->struct
04722      Ils ne doivent donc pas etre liberes sans precaution */
04723   if (with_path2id) {
04724     word_tree_ptr->path2id = (SXINT *) sxcalloc (XxY_size (word_tree_ptr->paths)+1, sizeof (SXINT));
04725     word_tree_ptr->final_path_set = NULL;
04726   }
04727   else {
04728     word_tree_ptr->final_path_set = sxba_calloc (XxY_size (word_tree_ptr->paths)+1);
04729     word_tree_ptr->path2id = NULL;
04730   }
04731 
04732   word_tree_ptr->max_final_state_nb = word_tree_ptr->max_path_lgth = word_tree_ptr->max_trans = 0;
04733 }
04734 
04735 
04736 void
04737 word_tree_free (struct word_tree_struct *word_tree_ptr)
04738 {
04739   if (word_tree_ptr->stats) {
04740     fprintf (word_tree_ptr->stats, "// Statistics for \"%s\": total size (in bytes) = %ld\n", word_tree_ptr->name,
04741          sizeof (struct word_tree_struct)
04742          /* Le XxY */
04743          + sizeof (word_tree_ptr->paths.hash_display [0]) * (word_tree_ptr->paths.hash_size+1)
04744          + sizeof (word_tree_ptr->paths.hash_lnk [0]) * (word_tree_ptr->paths.top+1)
04745          + sizeof (word_tree_ptr->paths.display [0]) * (word_tree_ptr->paths.top+1)
04746          /* Pour l'instant, je suppose qu'il y-a pas de foreach !! */
04747          + ((word_tree_ptr->path2id) ? sizeof (SXINT) * (word_tree_ptr->max_final_state_nb + 1) : 0)
04748          + ((word_tree_ptr->final_path_set) ? (sizeof (SXBA_ELT) * (SXNBLONGS (SXBASIZE (word_tree_ptr->final_path_set))+1)) : (sizeof (SXINT) * (word_tree_ptr->max_final_state_nb + 1)))
04749          );
04750   }
04751 
04752   if (!word_tree_ptr->is_static) {
04753     XxY_free (&word_tree_ptr->paths);
04754 
04755     if (word_tree_ptr->final_path_set) sxfree (word_tree_ptr->final_path_set), word_tree_ptr->final_path_set = NULL;
04756     if (word_tree_ptr->path2id) sxfree (word_tree_ptr->path2id), word_tree_ptr->path2id = NULL;
04757   }
04758 }
04759 
04760 
04761 static SXUINT
04762 string_get_next_symb (struct sxdfa_private *sxdfa_private_ptr)
04763 {
04764   return sxdfa_private_ptr->from_left_to_right ? (SXUINT)(unsigned char)*sxdfa_private_ptr->ptr.char_ptr++ : (SXUINT)(unsigned char)*sxdfa_private_ptr->ptr.char_ptr--;
04765 }
04766 
04767 static SXUINT
04768 word_get_next_symb (struct sxdfa_private *sxdfa_private_ptr)
04769 {
04770   return sxdfa_private_ptr->from_left_to_right ? (SXUINT)*sxdfa_private_ptr->ptr.SXINT_ptr++ : (SXUINT)*sxdfa_private_ptr->ptr.SXINT_ptr--;
04771 }
04772 
04773 
04774 /* On ajoute le chemin contenu ds word_stack au DFA acyclique */
04775 /* Un etat f est final ssi il existe depuis f une transition sur -1 */
04776 SXINT
04777 word_tree_add_a_string (struct word_tree_struct *word_tree_ptr, char *string, SXINT string_lgth, SXINT id)
04778 {
04779   word_tree_ptr->private.ptr.char_ptr = (word_tree_ptr->private.from_left_to_right) ? string : string+string_lgth-1;
04780 
04781   return word_tree_add (word_tree_ptr, string_get_next_symb, string_lgth, id);
04782 }
04783 
04784 
04785 
04786 SXINT
04787 word_tree_add_a_word (struct word_tree_struct *word_tree_ptr, SXINT *input_stack, SXINT id)
04788 {
04789   word_tree_ptr->private.ptr.SXINT_ptr = (word_tree_ptr->private.from_left_to_right) ? input_stack + 1 : input_stack + *input_stack;
04790 
04791   return word_tree_add (word_tree_ptr, word_get_next_symb, *input_stack, id);
04792 }
04793 
04794 SXINT
04795 word_tree_add (struct word_tree_struct *word_tree_ptr, SXUINT (*get_next_symb) (struct sxdfa_private*), SXINT lgth, SXINT id)
04796 {
04797   SXINT trans, path, new_path, cur_lgth;
04798 
04799   path = word_tree_ptr->root; /* Racine */
04800 
04801   for (cur_lgth = 1; cur_lgth <= lgth; cur_lgth++) {
04802     trans = (SXINT) ((*get_next_symb) (&(word_tree_ptr->private)));
04803     
04804     if (!XxY_set (&(word_tree_ptr->paths), path, trans, &new_path)) {
04805       /* new_path est nouveau */
04806       if (trans > word_tree_ptr->max_trans)
04807     word_tree_ptr->max_trans = trans;
04808     }
04809 
04810     path = new_path;
04811   }
04812 
04813   if (lgth > word_tree_ptr->max_path_lgth)
04814     word_tree_ptr->max_path_lgth = lgth;
04815 
04816   /* marque d'un etat final */
04817   if (word_tree_ptr->final_path_set) {
04818     if (SXBA_bit_is_reset_set (word_tree_ptr->final_path_set, path))
04819       word_tree_ptr->max_final_state_nb++;
04820   }
04821   else {
04822     if (word_tree_ptr->path2id) {
04823       if (word_tree_ptr->path2id [path] == 0) {
04824     word_tree_ptr->max_final_state_nb++;
04825     word_tree_ptr->path2id [path] = id;
04826       }
04827     }
04828   }
04829 
04830   return path;
04831 }
04832 
04833 
04834 /* Recherche kw ds le fsa repre'sente' sous forme d'un sxdfa_struct et retourne l'etat final ou 0 si kw n'est pas reconnu */
04835 /* Si echec, kwl indique la partie suffixe non reconnue. */
04836 SXINT
04837 word_tree_seek_a_string (struct word_tree_struct *word_tree_ptr, char *kw, SXINT *kwl)
04838 {
04839   SXINT     lgth, trans, path, id;
04840 
04841   lgth = *kwl;
04842 
04843   if (lgth < 0)
04844     return 0;
04845 
04846   path = word_tree_ptr->root; /* Racine */
04847 
04848   while (lgth > 0) {
04849     trans = (SXINT) *kw++;
04850     
04851     if ((path = XxY_is_set (&(word_tree_ptr->paths), path, trans)) == 0) {
04852       /* Echec */
04853       *kwl = lgth;
04854       return 0;
04855     }
04856 
04857     lgth--;
04858   }
04859 
04860   /* Ici lgth == 0 et on a atteint path */
04861   /* C'est OK, uniquement s'il est final */
04862   *kwl = 0;
04863 
04864   if (word_tree_ptr->final_path_set)
04865     id = SXBA_bit_is_set (word_tree_ptr->final_path_set, path) ? path : 0;
04866   else
04867     id = word_tree_ptr->path2id [path];
04868 
04869   return id;
04870 }
04871 
04872 
04873 static SXINT      *sxdfa_lgth2path, *sxdfa_path2next;
04874 
04875 
04876 /* met ds sxdfa_path2next un chemin p de longueur l */
04877 /* 2 appels successifs de sxdfa_lp_push sont tels que path1 < path2
04878    il faut, pour une longueur donnee les recuperer ds le meme ordre */
04879 static void
04880 sxdfa_lp_push (SXINT path, SXINT lgth)
04881 {
04882   sxdfa_path2next [path] = sxdfa_lgth2path [lgth];
04883   sxdfa_lgth2path [lgth] = path;
04884 }
04885 
04886 
04887 static void
04888 sxdfa_lgth_alloc (SXINT max_path_lgth, SXINT max_path_nb)
04889 {
04890   sxdfa_lgth2path = (SXINT *) sxcalloc (max_path_lgth+1, sizeof (SXINT));
04891   sxdfa_path2next = (SXINT*) sxalloc (max_path_nb+1, sizeof (SXINT)), sxdfa_path2next [0] = max_path_lgth;
04892 #if 0
04893   sxdfa_lp_push (root, 0); /* pour le chemin vide */
04894 #endif /* 0 */
04895 }
04896 
04897 
04898 
04899 static void
04900 sxdfa_lgth_free (void)
04901 {
04902   sxfree (sxdfa_lgth2path), sxdfa_lgth2path = NULL;
04903   sxfree (sxdfa_path2next), sxdfa_path2next = NULL;
04904 }
04905 
04906 /* Tous les appels a dico2_add_a_word sont termines
04907    On remplit la sxdfa_struct */
04908 void
04909 word_tree2sxdfa (struct word_tree_struct *word_tree_ptr, struct sxdfa_struct *sxdfa_ptr, char *name, FILE *stats, SXBOOLEAN to_be_minimized)
04910 {
04911   SXINT     number_of_trans, max_trans_nb, arity, max_arity, last_path, path, next_path, t, trans_id, new_lgth, max_path_lgth, id;
04912   SXINT     where, last_new_path, new_path, next_new_path;
04913   SXBA      cur_t_set, leaf_set, inside_final_set;
04914   SXINT     *t2next_path, *new_path2lgth, *old_path2new_path;
04915   XH_header trans_list_hd;
04916 
04917   SXINT     *old_path2id = NULL;
04918 
04919   sxinitialise (new_lgth);
04920 
04921   last_path = XxY_top (word_tree_ptr->paths);
04922   leaf_set = sxba_calloc (last_path+1);
04923   inside_final_set = sxba_calloc (last_path+1);
04924   old_path2new_path = (SXINT *) sxalloc (last_path+1, sizeof (SXINT));
04925 
04926   if (word_tree_ptr->path2id && to_be_minimized) {
04927     /* On va considerer l'id caracteristique de la reconnaissance d'un mot comme etant une transition particuliere
04928        que l'on va remonter au + haut (des qu'un chemin a un fils unique) */
04929     SXINT   selected_path, prev_path;
04930     SXBA    tbp_path_set;
04931 
04932     old_path2id = (SXINT *) sxcalloc (last_path+1, sizeof (SXINT));
04933     tbp_path_set = sxba_calloc  (last_path+1);
04934 
04935     path = last_path+1;
04936 
04937     while ((path = sxba_0_rlscan (tbp_path_set, path)) > 0) {
04938       if ((id = word_tree_ptr->path2id [path])) {
04939     /* path est final ... */
04940     XxY_Xforeach (word_tree_ptr->paths, path, next_path) {
04941       break;
04942     }
04943 
04944     if (next_path == 0) {
04945       /* ... et c'est une feuille */
04946       /* On remonte au +loin pour trouver le premier noeud non unaire */
04947       SXBA_1_bit (leaf_set, path);
04948       prev_path = path;
04949 
04950       while ((selected_path = prev_path) != 1) {
04951         prev_path = XxY_X (word_tree_ptr->paths, selected_path);
04952         SXBA_1_bit (tbp_path_set, prev_path); /* pour ne pas le reexaminer */
04953 
04954         arity = 0;
04955 
04956         XxY_Xforeach (word_tree_ptr->paths, prev_path, next_path) {
04957           if (++arity > 1)
04958         break;
04959         }
04960 
04961         if (word_tree_ptr->path2id [prev_path]) {
04962           SXBA_1_bit (inside_final_set, prev_path);
04963           /* On ne remonte pas au-dela du 1er inside */
04964 
04965           if (arity == 1)
04966         selected_path = prev_path;
04967 
04968           break;
04969         }
04970 
04971         if (arity > 1) {
04972           /* arret */
04973           break;
04974         }
04975       }
04976 
04977       if (selected_path != path) {
04978         old_path2id [selected_path] = id;
04979         word_tree_ptr->path2id [path] = -id; /* deja utilisee */
04980       }
04981     }
04982     else
04983       SXBA_1_bit (inside_final_set, path);
04984       }
04985     }
04986 
04987     sxfree (tbp_path_set);
04988 
04989     new_path = 0;
04990 
04991     for (path = 1; path <= last_path; path++) {
04992       if (SXBA_bit_is_set (leaf_set, path)) {
04993     old_path2new_path [path] = 0;
04994       }
04995       else {
04996     old_path2new_path [path] = ++new_path;
04997       }
04998     }
04999 
05000     /* Ici Si word_tree_ptr->path2id [path] == -id alors il existe ds le chemin path un prefixe strict selected_path t.q. old_path2id [selected_path] = id
05001        (Le id doit etre remonte' de path a selected_path) */
05002   }
05003   else {
05004     /* On calcule leaf_set */
05005     if (word_tree_ptr->path2id) {
05006       for (path = 1; path <= last_path; path++) {
05007     if (word_tree_ptr->path2id [path]) {
05008       /* path est final */
05009       XxY_Xforeach (word_tree_ptr->paths, path, next_path) {
05010         break;
05011       }
05012       
05013       if (next_path == 0)
05014         /* ... et c'est une feuille */
05015         SXBA_1_bit (leaf_set, path);
05016       else
05017         SXBA_1_bit (inside_final_set, path);
05018     }
05019       }
05020     }
05021     else {
05022       path = 0;
05023 
05024       while ((path = sxba_scan (word_tree_ptr->final_path_set, path)) > 0) {
05025     /* path est final */
05026     XxY_Xforeach (word_tree_ptr->paths, path, next_path) {
05027       break;
05028     }
05029       
05030     if (next_path == 0)
05031       /* ... et c'est une feuille */
05032       SXBA_1_bit (leaf_set, path);
05033     else
05034       SXBA_1_bit (inside_final_set, path);
05035       }
05036     }
05037 
05038     /* ... et old_path2new_path */
05039     new_path = 0;
05040 
05041     for (path = 1; path <= last_path; path++) {
05042       if (SXBA_bit_is_set (leaf_set, path)) {
05043     old_path2new_path [path] = 0;
05044       }
05045       else {
05046     old_path2new_path [path] = ++new_path;
05047       }
05048     }
05049   }
05050 
05051   last_new_path = new_path;
05052 
05053   sxfree (leaf_set);
05054 
05055   cur_t_set = sxba_calloc (word_tree_ptr->max_trans+1);
05056   t2next_path = (SXINT*) sxalloc (word_tree_ptr->max_trans+1, sizeof (SXINT));
05057   
05058   max_path_lgth = word_tree_ptr->max_path_lgth;
05059 
05060   if (word_tree_ptr->path2id) max_path_lgth++;
05061 
05062   if (to_be_minimized) {
05063     new_path2lgth = (SXINT*) sxalloc (last_new_path+1, sizeof (SXINT)), new_path2lgth [0] = new_path2lgth [1] = 0;
05064 
05065     sxdfa_lgth_alloc (max_path_lgth, last_new_path);
05066   }
05067   else {
05068     new_path2lgth = NULL;
05069     sxdfa_lgth2path = NULL;
05070   }
05071 
05072   max_trans_nb = last_path/word_tree_ptr->max_final_state_nb + 1;
05073 
05074   /* Truc pour le cas ou *sxdfa_ptr est non vide (ca peut etre du garbage si structure declaree en automatique!!) */
05075   sxdfa_ptr->name = NULL;
05076   sxdfa_ptr->stats = NULL;
05077 
05078   sxdfa_alloc (sxdfa_ptr, last_new_path, last_new_path*max_trans_nb, name, stats);
05079   XH_alloc (&trans_list_hd, "trans_list_hd", last_new_path+1, 1, max_trans_nb, NULL, NULL);
05080 
05081   max_arity = number_of_trans = 0;
05082 
05083   for (path = 1; path <= last_path; path++) {
05084     new_path = old_path2new_path [path];
05085 
05086     if (new_path) {
05087       where = (DTOP (sxdfa_ptr->next_state_list)+1)<<1;
05088 
05089       if (SXBA_bit_is_set (inside_final_set, path))
05090     DPUSH (sxdfa_ptr->states, where|1);
05091       else
05092     DPUSH (sxdfa_ptr->states, where);
05093 
05094       if (new_path2lgth) {
05095     new_lgth = new_path2lgth [new_path];
05096     sxdfa_lp_push (new_path, new_lgth++);
05097       }
05098       
05099       if (word_tree_ptr->path2id) {
05100     if (to_be_minimized) {
05101       if ((id = word_tree_ptr->path2id [path])) {
05102         /* path est final */
05103         if (id > 0) {
05104           /* on fait une transition sur -id (sans successeur) */
05105           DPUSH (sxdfa_ptr->next_state_list, -id);
05106           sxdfa_ptr->states [DTOP (sxdfa_ptr->states)] |= 1; /* Il est final */
05107         }
05108         /* Sinon id a deja ete traite' */
05109       }
05110 
05111       if ((id = old_path2id [path])) {
05112         /* Transition remontee */
05113         DPUSH (sxdfa_ptr->next_state_list, -id);
05114         /* ... et on continue en sequence pour traiter les t transitions depuis path */
05115       }
05116     }
05117     else {
05118       if ((id = word_tree_ptr->path2id [path])) {
05119         /* path est final */
05120         /* on fait une transition sur -id (sans successeur) */
05121         DPUSH (sxdfa_ptr->next_state_list, -id);
05122         sxdfa_ptr->states [DTOP (sxdfa_ptr->states)] |= 1; /* Il est final */
05123         /* ... et on continue en sequence pour traiter les t transitions depuis path ... */
05124         /* ... Si path est inside final */
05125       }
05126     }
05127       }
05128 
05129       arity = 0;
05130 
05131       XxY_Xforeach (word_tree_ptr->paths, path, next_path) {
05132     arity++;
05133     t = XxY_Y (word_tree_ptr->paths, next_path);
05134     number_of_trans++;
05135 
05136     SXBA_1_bit (cur_t_set, t);
05137 
05138     if (word_tree_ptr->path2id && (id = word_tree_ptr->path2id [next_path]) > 0 && !SXBA_bit_is_set (inside_final_set, next_path)) {
05139       /* path est final non interne avec id */
05140       next_new_path = -id;
05141     }
05142     else {
05143       next_new_path = old_path2new_path [next_path]; /* Ca peut etre 0 (Etat final commun des feuilles) */
05144     }
05145 
05146     t2next_path [t] = next_new_path;
05147 
05148     if (new_path2lgth && (next_new_path > 0)) new_path2lgth [next_new_path] = new_lgth;
05149       }
05150 
05151       if (arity) {
05152     if (arity > max_arity)
05153       max_arity = arity;
05154 
05155     DPUSH (sxdfa_ptr->next_state_list, 0); /* bidon, place du next_trans */
05156     where = DTOP (sxdfa_ptr->next_state_list);
05157     t = -1;
05158 
05159     while ((t = sxba_scan_reset (cur_t_set, t)) >= 0) {
05160       XH_push (trans_list_hd, t);
05161       DPUSH (sxdfa_ptr->next_state_list, t2next_path [t]);
05162     }
05163 
05164     XH_set (&trans_list_hd, &trans_id);
05165 
05166     sxdfa_ptr->next_state_list [where] = XH_X (trans_list_hd, trans_id);
05167       }
05168     }
05169   }
05170 
05171   DPUSH (sxdfa_ptr->next_state_list, 0); /* place du next_trans */
05172   DPUSH (sxdfa_ptr->states, (DTOP (sxdfa_ptr->next_state_list))<<1);
05173 
05174   /* Les feuilles ont des transitions vides */
05175 
05176   /* ATTENTION truc */
05177   sxdfa_ptr->trans_list = trans_list_hd.list;
05178   sxdfa_ptr->trans_list[0]--; // l'offset 0 du .list est (nbre d'elt)+1
05179   trans_list_hd.list = (SXINT *) sxalloc (1, sizeof (SXINT));
05180   XH_free (&trans_list_hd);
05181 
05182   sxdfa_ptr->init_state = 1;
05183   sxdfa_ptr->last_state = sxdfa_ptr->states [0] - 1;
05184   sxdfa_ptr->number_of_out_trans = sxdfa_ptr->next_state_list [0] - 1;
05185   sxdfa_ptr->final_state_nb = word_tree_ptr->max_final_state_nb;
05186   sxdfa_ptr->max_path_lgth = max_path_lgth;
05187   sxdfa_ptr->max_arity = max_arity;
05188   sxdfa_ptr->max_t_val = word_tree_ptr->max_trans;
05189 
05190   sxdfa_ptr->is_static = SXFALSE;
05191   sxdfa_ptr->is_a_dag = SXTRUE;
05192   sxdfa_ptr->private.from_left_to_right = word_tree_ptr->private.from_left_to_right;
05193 
05194   sxfree (cur_t_set);
05195   sxfree (t2next_path);
05196 
05197   if (new_path2lgth) sxfree (new_path2lgth);
05198 
05199   word_tree_free (word_tree_ptr);
05200 
05201   sxfree (old_path2new_path);
05202   sxfree (inside_final_set);
05203 
05204   if (old_path2id) {
05205     sxfree (old_path2id);
05206   }
05207 
05208   if (to_be_minimized) {
05209     sxdfa_tree2min_dag (sxdfa_ptr);
05210     sxdfa_lgth_free ();
05211   }
05212 }
05213 
05214 
05215 void
05216 sxdfa_alloc (struct sxdfa_struct *sxdfa_ptr, SXINT state_nb, SXINT trans_nb, char *name, FILE *stats)
05217 {
05218   /* Ces tailles sont des majorants, on ne remplit donc pas les valeurs scalaires definitives */
05219   sxdfa_ptr->is_static = SXFALSE;
05220 
05221   if (name) sxdfa_ptr->name = name;
05222   if (stats) sxdfa_ptr->stats = stats;
05223 
05224   /* On en fait des dstack au cas ou */
05225   DALLOC_STACK (sxdfa_ptr->states, state_nb+1);
05226   DALLOC_STACK (sxdfa_ptr->next_state_list, state_nb+trans_nb+1);
05227   /* sxdfa_ptr->trans_list sera alloue' par ailleurs !! */
05228 }
05229 
05230 
05231 void
05232 sxdfa_free (struct sxdfa_struct *sxdfa_ptr)
05233 {
05234   if (sxdfa_ptr->stats) {
05235     fprintf (sxdfa_ptr->stats, "// Statistics for \"%s\": total size (in bytes) = %ld\n", sxdfa_ptr->name,
05236          sizeof (struct sxdfa_struct)
05237          + sizeof (SXINT) * (sxdfa_ptr->states [0] + 1)
05238          + sizeof (SXINT) * (sxdfa_ptr->next_state_list [0] + 1)
05239          + sizeof (SXINT) * (sxdfa_ptr->trans_list [0] + 1)
05240          );
05241   }
05242 
05243   if (!sxdfa_ptr->is_static) {
05244     DFREE_STACK (sxdfa_ptr->states);
05245     DFREE_STACK (sxdfa_ptr->next_state_list);
05246   }
05247 }
05248 
05249 
05250 /* On a un arbre en entree stocke ds io_dag sous la forme d'une struct sxdfa_struct
05251    Cet arbre a ete construit a` partir de la liste de ses chemins (mots) (par dico2_add_a_word () puis word_tree2sxdfa ())
05252    Le Dag minimal resultant est stocke' ds la meme structure.
05253 */
05254 /* On fabrique pour chaque sous-arbre de cet arbre un identifiant unique.
05255    Cet identifiant (c'est un XH) est une liste ordonnee de branches
05256    une branche est un couple (trans, tree) ou tree est l'identifiant du sous-arbre qui est atteint par transition sur trans
05257 */
05258 void
05259 sxdfa_tree2min_dag (struct sxdfa_struct *sxdfa_ptr)
05260 {
05261   SXINT      lgth, path, next_path, branch, tree, state, bot, top, next_tree, dico2_max_tree, is_final, bot_trans, where;
05262   SXINT      *state_ptr, *next_states_ptr, *top_next_state_ptr;
05263   SXINT      *cur_path2tree;
05264   XH_header  dico2_trees;
05265    
05266   if (sxdfa_lgth2path == NULL)
05267     sxtrap (ME, "sxdfa_dag_minimize");
05268 
05269   cur_path2tree = (SXINT*) sxalloc (sxdfa_ptr->last_state+1, sizeof (SXINT));
05270 
05271   XH_alloc (&dico2_trees, "dico2_trees", sxdfa_ptr->last_state+1, 1, sxdfa_ptr->number_of_out_trans/sxdfa_ptr->last_state + 1, NULL, NULL);
05272 
05273   /* On traite les path par longueur decroissante.  Comme ca on est sur que si path est un composant
05274      de next_path, les tree associes aux successeurs de path sont tous calcules */
05275   
05276   /* On suppose que l'automate d'entree a ete construit incrementalement par dico2_add_a_word () */
05277   for (lgth = sxdfa_path2next [0]; lgth >= 0; lgth--) {
05278     for (path = sxdfa_lgth2path [lgth]; path > 0; path = sxdfa_path2next [path]) {
05279       /* Obligatoirement non encore calcule' */
05280       state_ptr = sxdfa_ptr->states + path;
05281       bot = state_ptr [0];
05282 
05283       is_final = bot & 1;
05284       bot >>= 1;
05285       
05286       next_states_ptr = sxdfa_ptr->next_state_list + bot;
05287       top_next_state_ptr = sxdfa_ptr->next_state_list + (state_ptr [1]>>1);
05288       bot_trans = *next_states_ptr++;
05289 
05290       if (is_final) {
05291     /* Un prefixe du mot est dans le dico */
05292     /* path est final */
05293     XH_push (dico2_trees, 0); /* branche "vide" */
05294       }
05295 
05296       if (bot_trans < 0) {
05297     if (is_final) {
05298       /* L'etat state est final et -bot_trans est l'identifiant associe' ... */
05299       /* bot_trans est la branche ... */
05300       /* ... que l'on stocke ... */
05301       XH_push (dico2_trees, bot_trans);
05302 
05303       bot_trans = *next_states_ptr++;
05304 
05305       if (bot_trans < 0) {
05306         /* ici -bot_trans est l'identifiant associe' au mot unique qui sera reconnu sur
05307            le futur etat final */
05308         /* ... que l'on stocke ... */
05309         /* comme une branche */
05310         XH_push (dico2_trees, bot_trans);
05311         bot_trans = *next_states_ptr++; /* le trans_id */
05312       }
05313     }
05314     else {
05315       /* ici -bot_trans est l'identifiant associe' au mot unique qui sera reconnu sur
05316          le futur etat final */
05317       /* ... que l'on stocke ... */
05318       /* comme une branche */
05319       XH_push (dico2_trees, bot_trans);
05320       bot_trans = *next_states_ptr++; /* le trans_id */
05321     }
05322       }
05323 
05324       /* Ici bot_trans est un trans_id */
05325       XH_push (dico2_trees, bot_trans);
05326       
05327       while (next_states_ptr < top_next_state_ptr) {
05328     next_path = *next_states_ptr++;
05329     /* On fabrique la branche ... */
05330     branch = (next_path > 0) ? cur_path2tree [next_path] : next_path;
05331     /* ... que l'on stocke ... */
05332     XH_push (dico2_trees, branch);
05333       }
05334 
05335       /* ... pour fabriquer tree */
05336       XH_set (&(dico2_trees), &tree);
05337 
05338       cur_path2tree [path] = tree;
05339     }
05340   }
05341 
05342   /* Les id  des trees ont des valeurs croissantes des feuilles vers la racine, on ne les utilise donc pas directement
05343      pour faire les etats de l'automate */
05344   /* On fait donc cette passe supple'mentaire */
05345   dico2_max_tree = XH_top (dico2_trees);
05346 
05347   sxdfa_free (sxdfa_ptr);
05348 
05349   /* Ne touche pas a trans_list qui est reutilise' entre "i' et "o" */
05350 
05351   sxdfa_alloc (sxdfa_ptr, dico2_max_tree, XH_list_top (dico2_trees), NULL, NULL);
05352 
05353   for (tree = dico2_max_tree-1; tree > 0; tree--) {
05354     /* Non vide */
05355     state = dico2_max_tree-tree;
05356 
05357     bot = XH_X (dico2_trees, tree);
05358     top = XH_X (dico2_trees, tree+1);
05359 
05360     where = (TOP (sxdfa_ptr->next_state_list)+1)<<1;
05361     branch = XH_list_elem (dico2_trees, bot++);
05362 
05363     if (branch == 0) {
05364       /* tree est un etat final */
05365       PUSH (sxdfa_ptr->states, where|1);
05366       branch = XH_list_elem (dico2_trees, bot++);
05367     }
05368     else
05369       PUSH (sxdfa_ptr->states, where);
05370 
05371     if (branch < 0) {
05372       PUSH (sxdfa_ptr->next_state_list, branch);
05373       branch = XH_list_elem (dico2_trees, bot++);
05374 
05375       if (branch < 0) {
05376     PUSH (sxdfa_ptr->next_state_list, branch);
05377     branch = XH_list_elem (dico2_trees, bot++);
05378       }
05379     }
05380 
05381     /* ici branch est un trans_id */
05382     PUSH (sxdfa_ptr->next_state_list, branch);
05383 
05384     while (bot < top) {
05385       next_tree = XH_list_elem (dico2_trees, bot++);
05386       if (next_tree > 0) next_tree = dico2_max_tree-next_tree;
05387       PUSH (sxdfa_ptr->next_state_list, next_tree);
05388     }
05389   }
05390 
05391   PUSH (sxdfa_ptr->next_state_list, 0); /* place du next_trans */
05392   PUSH (sxdfa_ptr->states, (DTOP (sxdfa_ptr->next_state_list))<<1); /* celui de path */
05393 
05394   /* sxdfa_ptr->init_state conserve sa valeur */
05395   sxdfa_ptr->last_state = sxdfa_ptr->states [0] - 1;
05396   sxdfa_ptr->number_of_out_trans = sxdfa_ptr->next_state_list [0] - sxdfa_ptr->last_state - 1;
05397   /* sxdfa_ptr->final_state_nb conserve sa valeur */
05398   /* sxdfa_ptr->max_path_lgth conserve sa valeur */
05399   /* sxdfa_ptr->is_static conserve sa valeur (SXFALSE) */
05400   /* sxdfa_ptr->is_a_dag conserve sa valeur */
05401 
05402   sxfree (cur_path2tree), cur_path2tree = NULL;
05403 
05404   XH_free (&dico2_trees);
05405   /* dico2_free () est appele' par l'appelant (celui qui a appele' dico2_alloc ()) */
05406 }
05407 
05408 
05409 
05410 
05411 
05412 /* Cette fonction est appelee pour chaque transition nfa_state ->t next_nfa_state  ds nfa2sxdfa ()*/
05413 static void
05414 sxnfa_fill_trans (SXINT nfa_state, SXINT t, SXINT next_nfa_state)
05415 {
05416   sxuse (nfa_state);
05417   SXBA_1_bit (t2nfa_state_set [t], next_nfa_state);
05418   SXBA_1_bit (t_set, t);
05419 }
05420 
05421 
05422 void
05423 nfa2sxdfa (SXINT init_state, 
05424        SXINT cur_final_state, 
05425        SXINT cur_max_state, 
05426        SXINT eof_ste, 
05427        SXINT trans_nb, 
05428        SXBOOLEAN (*empty_trans)(SXINT, SXBA), 
05429        void (*nfa_extract_trans)(SXINT, void (*sxnfa_fill_trans) (SXINT nfa_state, SXINT t, SXINT next_nfa_state)), 
05430        struct sxdfa_struct *sxdfa_ptr, 
05431        SXBOOLEAN to_be_minimized, 
05432        SXBOOLEAN to_be_normalized)
05433 {
05434   SXINT     dfa_state, new_dfa_state, bot, top, nfa_state, t, max_trans_value, nb, prev_t, t_trans, nfa_max_state;
05435   SXBA      cur_state_set;
05436   SXBOOLEAN   dfa_state_is_final;
05437   XH_header trans_list_hd;
05438 
05439   sxinitialise (prev_t);
05440 
05441   nfa_max_state = cur_max_state == 0 ? cur_final_state : cur_max_state;
05442   nfa_empty_trans = empty_trans; /* Appels multiples */
05443 
05444   dfa_init_state = 1;
05445 
05446   if (nfa_empty_trans) {
05447     /* Il y a des transitions sur epsilon, on alloue qq structres */
05448     nfa_ec_stack = (SXINT*) sxalloc (nfa_max_state+1, sizeof (SXINT)), nfa_ec_stack [0] = 0;
05449     nfa_wstate_set = sxba_calloc (nfa_max_state+1);
05450   }
05451 
05452   sxdfa_alloc (sxdfa_ptr, cur_final_state, trans_nb, "nfa2sxdfa" /* name */, NULL /* stats */);
05453   /* a serait bien d'avoir en arg le nb de transitions de l'automate non-deterministe pour calculer
05454      une taille moyenne */
05455   XH_alloc (&trans_list_hd, "trans_list_hd", cur_final_state+1, 1, trans_nb/cur_final_state + 1, NULL, NULL);
05456 
05457   DALLOC_STACK (nfa_state_stack, nfa_max_state);
05458   t_set = sxba_calloc (eof_ste+1);
05459   t2nfa_state_set = sxbm_calloc (eof_ste+1, nfa_max_state+1);
05460   XH_alloc (&(XH_dfa_states), "XH_dfa_states", nfa_max_state+1, 1, 10, NULL, NULL);
05461 
05462   /* traitement de l'etat initial */
05463   cur_state_set = t2nfa_state_set [0];
05464 
05465   SXBA_1_bit (cur_state_set, init_state);
05466 
05467   if (nfa_empty_trans)
05468     epsilon_closure (cur_state_set);
05469 
05470   get_state (cur_state_set, &dfa_state);
05471 
05472   sxdfa_ptr->init_state = dfa_state;
05473   sxdfa_ptr->final_state_nb = sxdfa_ptr->number_of_out_trans = sxdfa_ptr->max_arity = 0;
05474   max_trans_value = 0;
05475 
05476   DPUSH (nfa_state_stack, dfa_state);
05477 
05478   while (!IS_EMPTY (nfa_state_stack)) {
05479     dfa_state = DPOP (nfa_state_stack);
05480     dfa_state_is_final = SXFALSE;
05481 
05482     bot = XH_X (XH_dfa_states, dfa_state);
05483     top = XH_X (XH_dfa_states, dfa_state+1);
05484 
05485     while (bot < top) {
05486       nfa_state = XH_list_elem (XH_dfa_states, bot);
05487 
05488       if (nfa_state == cur_final_state && cur_max_state > 0)
05489     dfa_state_is_final = SXTRUE;
05490 
05491       (*nfa_extract_trans) (nfa_state, sxnfa_fill_trans);
05492       bot++;
05493     }
05494 
05495     t = -1;
05496     nb = 0;
05497 
05498     while ((t = sxba_scan (t_set, t)) >= 0) {
05499       if (t == eof_ste || dfa_state_is_final) { /* transition arrivant sur un état final */
05500     dfa_state_is_final = SXTRUE;
05501     SXBA_0_bit (t_set, t);
05502     sxdfa_ptr->final_state_nb++; /* C'est la 1ere fois que dfa_state est examine' */
05503       }
05504       else {
05505     /* pas trans sur <EOW> */
05506     nb++;
05507     XH_push (trans_list_hd, t);
05508     prev_t = t;
05509       }
05510     }
05511 
05512     if (prev_t > max_trans_value)
05513       max_trans_value = prev_t;
05514 
05515     if (!XH_set (&trans_list_hd, &t_trans)) {
05516       /* Nelle trans */
05517       if (nb > sxdfa_ptr->max_arity)
05518     sxdfa_ptr->max_arity = nb;
05519     }
05520 
05521     /* On empile t_trans */
05522     DCHECK (sxdfa_ptr->next_state_list, nb+1);
05523     DSPUSH (sxdfa_ptr->next_state_list, t_trans);
05524 
05525     /* ... et "dfa_state" */
05526     if (dfa_state_is_final)
05527       DPUSH (sxdfa_ptr->states, (DTOP (sxdfa_ptr->next_state_list)<<1)+1);
05528     else
05529       DPUSH (sxdfa_ptr->states, (DTOP (sxdfa_ptr->next_state_list)<<1));
05530 
05531     t = -1;
05532 
05533     while ((t = sxba_scan_reset (t_set, t)) >= 0) { 
05534       cur_state_set = t2nfa_state_set [t];
05535 
05536       if (nfa_empty_trans)
05537     epsilon_closure (cur_state_set);
05538 
05539       if (!get_state (cur_state_set, &new_dfa_state)) {
05540     /* nouveau */
05541     DPUSH (nfa_state_stack, new_dfa_state);
05542     sxdfa_ptr->last_state = new_dfa_state; /* On ne "conserve" que le + grand */
05543       }
05544 
05545       /* Ici on a une transition dfa_state ->t new_dfa_state */
05546       DSPUSH (sxdfa_ptr->next_state_list, new_dfa_state);
05547       sxdfa_ptr->number_of_out_trans++;
05548     }
05549   }
05550 
05551   /* On finalise */
05552   DPUSH (sxdfa_ptr->next_state_list, 0);
05553   DPUSH (sxdfa_ptr->states, DTOP (sxdfa_ptr->next_state_list));
05554 
05555   sxdfa_ptr->max_t_val = max_trans_value;
05556 
05557   sxdfa_ptr->private.from_left_to_right = SXTRUE;
05558   sxdfa_ptr->is_a_dag = SXFALSE; /* En fait on sait pas */
05559   sxdfa_ptr->max_path_lgth = 0;/* sans objet si pas DAG et si DAG sera calcule' + tard !! */ 
05560 
05561 
05562   if (nfa_empty_trans) {
05563     sxfree (nfa_ec_stack), nfa_ec_stack = NULL;
05564     sxfree (nfa_wstate_set), nfa_wstate_set = NULL;
05565   }
05566 
05567   /* ATTENTION truc */
05568   sxdfa_ptr->trans_list = trans_list_hd.list;
05569   trans_list_hd.list = (SXINT *) sxalloc (1, sizeof (SXINT));
05570   XH_free (&trans_list_hd);
05571 
05572   DFREE_STACK (nfa_state_stack);
05573   sxbm_free (t2nfa_state_set), t2nfa_state_set = NULL;
05574   XH_free (&XH_dfa_states);
05575   sxfree (t_set), t_set = NULL;
05576 
05577   if (to_be_minimized) {
05578     sxdfa_minimize (sxdfa_ptr, to_be_normalized);
05579   }
05580 }
05581 
05582 
05583 void
05584 sxdfa_minimize (struct sxdfa_struct *sxdfa_ptr, SXBOOLEAN to_be_normalized)
05585 {
05586   SXINT                 state, next_state, partition, next_partition, bot, top, part_set_id, cur_part, t_trans, trans_list_id, new_part;
05587   SXINT                 size, pred_state, cur_state, next_part, cur_part_card, nb_max, id, nb, id_max, last_part_set_id, old_last_partition, trans_nb, is_final_state;
05588   SXINT                 *part2new_part, *new_part2part, *area, *base_area, *working_stack, *w2_stack;
05589   SXBA                  new_part_final_set;
05590   struct part2attr      *cur_part_ptr;
05591   struct state2attr     *cur_state_ptr;
05592 #if LOG
05593   SXINT                 constant_time_step_nb = 0;             
05594 #endif /* LOG */
05595 
05596   sxinitialise (id_max);
05597 
05598   XH_alloc (&XH_trans_list_id, "XH_trans_list_id", sxdfa_ptr->last_state+1, 1, sxdfa_ptr->max_arity, NULL, NULL);
05599 
05600   XH_alloc (&XH_part_set, "XH_part_set", sxdfa_ptr->last_state+1, 1, sxdfa_ptr->max_arity, XH_part_set_oflw, NULL);
05601   part_set_id2part = (SXINT *) sxalloc (XH_size (XH_part_set)+1, sizeof (SXINT));
05602 
05603   working_stack = (SXINT*) sxalloc (2*sxdfa_ptr->last_state+1, sizeof (SXINT)), working_stack [0] = 0;
05604 
05605   /* dfa_state2pred_nb = NULL; On n'a pas besoin des predecesseurs */
05606   dfa_state2pred_nb = (SXINT*) sxcalloc (sxdfa_ptr->last_state+1, sizeof (SXINT)); /* On utilise les predecesseurs (voir commentaire de tete) */
05607 
05608   state2attr = (struct state2attr*) sxalloc (sxdfa_ptr->last_state+1, sizeof (struct state2attr));
05609   part2attr = (struct part2attr*) sxcalloc (sxdfa_ptr->last_state+1, sizeof (struct part2attr));
05610 
05611   w2_stack = (SXINT*) sxalloc (sxdfa_ptr->last_state+1, sizeof (SXINT)), w2_stack [0] = 0;
05612 
05613   /* initialisation ... */
05614   last_partition = 0;
05615 
05616   for (state = sxdfa_ptr->init_state; state <= sxdfa_ptr->last_state ; state++) {
05617     /* Analogue de fill_init_min () */
05618     bot = sxdfa_ptr->states [state];
05619     is_final_state = bot & 1;
05620     bot >>= 1;
05621     top = sxdfa_ptr->states [state+1]>>1;
05622 
05623     t_trans = sxdfa_ptr->next_state_list [bot++];
05624 
05625     if (is_final_state)
05626       XH_push (XH_trans_list_id, -t_trans);
05627     else
05628       XH_push (XH_trans_list_id, t_trans);
05629 
05630     while (bot < top) {
05631       next_state = sxdfa_ptr->next_state_list [bot++];
05632       XH_push (XH_trans_list_id, next_state);
05633 
05634       if (dfa_state2pred_nb) {
05635     /* On en profite pour compter les predecesseurs de next_dfa_state */
05636     dfa_state2pred_nb [next_state]++;
05637     dfa_state2pred_nb [0]++;
05638       }
05639     }
05640 
05641     /* A chaque etat state on lui associe la liste de ses successeurs ds un XH
05642        l'ordre des successeurs est donne' par l'ordre des terminaux des transitions
05643        chaque element d'un groupe a le meme ensemble de symboles terminaux, leurs successeurs
05644        peuvent donc se comparer simplement */
05645     XH_set (&XH_trans_list_id, &(state2attr [state].trans_list_id));
05646 
05647     state2attr [state].init_part = t_trans;
05648   }
05649 
05650   /* Ici chaque etat a recu une "partition" pre_initiale qui est son t_trans On fabrique une vraie partition initiale */
05651   for (state = sxdfa_ptr->init_state; state <= sxdfa_ptr->last_state ; state++) {
05652     trans_list_id = state2attr [state].trans_list_id;
05653     bot = XH_X (XH_trans_list_id, trans_list_id);
05654     top = XH_X (XH_trans_list_id, trans_list_id+1);
05655 
05656     t_trans = XH_list_elem (XH_trans_list_id, bot++); /* peut etre <0 ou >0 suivant que les etats de la partition sont finals ou pas */
05657     XH_push (XH_part_set, t_trans);
05658 
05659     while (bot < top) {
05660       next_state = XH_list_elem (XH_trans_list_id, bot);
05661       next_part = state2attr [next_state].init_part;
05662       XH_push (XH_part_set, -next_part); /* Il ne faut pas les confondre plus tard avec des "vraies" partition */
05663 
05664       bot++;
05665     }
05666       
05667     if (!XH_set (&XH_part_set, &part_set_id))
05668       /* Nouveau */
05669       part_set_id2part [part_set_id] = next_part = ++last_partition;
05670     else
05671       next_part = part_set_id2part [part_set_id];
05672 
05673     /* On installe state ds next_part */
05674     init_set (state, next_part);
05675   }
05676 
05677 #if LLOG
05678   configuration_nb = 0;
05679 #endif /* LLOG */
05680     
05681   dfa_state2pred_stack = NULL;
05682   base_area = NULL;
05683 
05684   if (dfa_state2pred_nb) {
05685     SXINT              pred_part, cur_last_partition, cur_part_sub_card;
05686     SXINT              *w_state_stack, *top_state_ptr, *state_ptr, *tbp_part_stack, *tbp_state_stacks, *tbp_state_stack, *top_part_ptr, *part_ptr, *pred_stack;
05687     SXBA             w_state_set;
05688     struct part2attr *pred_part_ptr;
05689 
05690     /* version de minimize dans laquelle on a besoin des predecesseurs */
05691     size = dfa_state2pred_nb [0] + sxdfa_ptr->last_state /* les comptes */;
05692 
05693     dfa_state2pred_stack = (SXINT **) sxalloc (sxdfa_ptr->last_state+1, sizeof (SXINT*));
05694     area = base_area = (SXINT*) sxalloc (size+1, sizeof (SXINT));
05695     w_state_set = sxba_calloc (sxdfa_ptr->last_state+1);
05696     w_state_stack = (SXINT *) sxalloc (sxdfa_ptr->last_state+1, sizeof (SXINT));
05697     tbp_part_stack = (SXINT *) sxalloc (sxdfa_ptr->last_state+1, sizeof (SXINT)), RAZ (tbp_part_stack);
05698     tbp_state_stacks = (SXINT *) sxalloc (2*sxdfa_ptr->last_state+1, sizeof (SXINT)), RAZ (tbp_state_stacks);
05699 
05700     sxba_fill (w_state_set), SXBA_0_bit (w_state_set, 0);
05701     w_state_stack [0] = sxdfa_ptr->last_state;
05702 
05703     for (state = 1; state <= sxdfa_ptr->last_state; state++) {
05704       w_state_stack [state] = state; /* PUSH */
05705       dfa_state2pred_stack [state] = area;
05706       *area = 0;
05707       area += dfa_state2pred_nb [state]+1;
05708     }
05709 
05710     for (state = sxdfa_ptr->init_state; state < sxdfa_ptr->last_state ; state++)
05711       /* On remplit dfa_state2pred_stack */
05712       (*dfa_extract_trans)(state, dfa_fill_dfa_state2pred_stack);
05713 
05714     sxfree (dfa_state2pred_nb), dfa_state2pred_nb = NULL;
05715 
05716     for(;;) {
05717 #if LLOG
05718       print_configuration ();
05719 #endif /* LLOG */
05720 
05721       /* Ici, les etats a traiter ont ete mis ds (w_state_stack, w_state_set) */
05722       /* On decoupe les etats a traiter par leur appartenance a la meme partition */
05723       top_state_ptr = w_state_stack+TOP(w_state_stack);
05724 
05725       /* On compte */
05726       for (state_ptr = top_state_ptr; state_ptr > w_state_stack; state_ptr--) {
05727     pred_state = *state_ptr;
05728     pred_part = state2attr [pred_state].part;
05729 
05730     if (part2attr [pred_part].sub_card++ == 0) {
05731       /* 1ere fois que pred_part est trouve' */
05732       PUSH (tbp_part_stack, pred_part);
05733     }
05734       }
05735     
05736       /* On prepare les piles */
05737       RAZ (tbp_state_stacks);
05738 
05739       top_part_ptr = tbp_part_stack+TOP(tbp_part_stack);
05740 
05741       for (part_ptr = top_part_ptr; part_ptr > tbp_part_stack; part_ptr--) {
05742     pred_part_ptr = part2attr + *part_ptr;
05743     PUSH (tbp_state_stacks, 0);
05744     pred_part_ptr->tbp_state_stack = tbp_state_stacks + TOP (tbp_state_stacks);
05745     TOP (tbp_state_stacks) += pred_part_ptr->sub_card;
05746     pred_part_ptr->sub_card = 0;
05747       }
05748 
05749       /* On stocke */
05750       for (state_ptr = top_state_ptr; state_ptr > w_state_stack; state_ptr--) {
05751     pred_state = *state_ptr;
05752     SXBA_0_bit (w_state_set, pred_state);
05753     pred_part = state2attr [pred_state].part;
05754     tbp_state_stack = part2attr [pred_part].tbp_state_stack;
05755     PUSH (tbp_state_stack, pred_state);
05756       }
05757 
05758       RAZ (w_state_stack);
05759 
05760       /* On traite */
05761       cur_last_partition = last_partition;
05762 
05763       while (!IS_EMPTY (tbp_part_stack)) {
05764 #if LOG
05765     constant_time_step_nb++;             
05766 #endif /* LOG */
05767     cur_part = POP (tbp_part_stack);
05768     cur_part_ptr = part2attr+cur_part;
05769     cur_part_card = cur_part_ptr->card;
05770 
05771     if (cur_part_card > 1) {
05772       tbp_state_stack = cur_part_ptr->tbp_state_stack;
05773       cur_part_sub_card = TOP (tbp_state_stack);
05774 #if EBUG
05775       if (cur_part_sub_card > cur_part_card)
05776         sxtrap (ME, "dfa_minimize");
05777 #endif /* EBUG */
05778 
05779       RAZ (w2_stack);
05780       nb_max = cur_part_card-cur_part_sub_card;
05781       PUSH (w2_stack, nb_max); /* Pour les etats dont les successeurs n'ont pas bouge's */
05782       id_max = 1; /* Le TOP */
05783       last_part_set_id = XH_top (XH_part_set)-1;
05784     
05785       for (state_ptr = tbp_state_stack+TOP(tbp_state_stack); state_ptr > tbp_state_stack; state_ptr--) {
05786         cur_state = *state_ptr;
05787         cur_state_ptr = state2attr + cur_state;
05788 
05789         /* On recalcule ses etats successeurs */
05790         trans_list_id = cur_state_ptr->trans_list_id;
05791         bot = XH_X (XH_trans_list_id, trans_list_id);
05792         top = XH_X (XH_trans_list_id, trans_list_id+1);
05793 
05794         t_trans = XH_list_elem (XH_trans_list_id, bot++); /* peut etre <0 ou >0 suivant que les etats de la partition sont finals ou pas */
05795         XH_push (XH_part_set, t_trans);
05796 
05797         while (bot < top) {
05798 #if LOG
05799           constant_time_step_nb++;             
05800 #endif /* LOG */
05801           next_state = XH_list_elem (XH_trans_list_id, bot);
05802           next_partition = state2attr [next_state].part;
05803           XH_push (XH_part_set, next_partition);
05804 
05805           bot++;
05806         }
05807 
05808         if (!XH_set (&XH_part_set, &part_set_id)) {
05809           /* Nouveau */
05810           PUSH (w2_stack, 0);
05811           id = TOP (w2_stack);
05812 
05813 #if EBUG 
05814           if (TOP (w2_stack) != part_set_id-last_part_set_id+1)
05815         sxtrap (ME, "dfa_minimize");
05816 #endif /* EBUG */
05817         }
05818         else {
05819           id = (part_set_id <= last_part_set_id) ? 1 : part_set_id-last_part_set_id+1;
05820         }
05821 
05822         nb = ++(w2_stack [id]);
05823 
05824         if (nb > nb_max) {
05825           nb_max = nb;
05826           id_max = id;
05827         }
05828 
05829         cur_state_ptr->temp_id = part_set_id;
05830       }
05831 
05832       /* Si nb_max == cur_part_card, on ne change rien */
05833       if (nb_max < cur_part_card) {
05834         old_last_partition = last_partition;
05835 
05836         /* Ds cur_part on ne va pas deplacer le + grand groupe =>
05837            chacun des groupes deplaces a une taille bornee par cur_part_card/2 */
05838 
05839         /* C'est le sous-groupe qui n'a pas ete touche' qui est le plus populaire
05840            On deplace les etats du complementaire ... */
05841         for (state_ptr = tbp_state_stack+TOP(tbp_state_stack); state_ptr > tbp_state_stack; state_ptr--) {
05842 #if LOG
05843           constant_time_step_nb++;             
05844 #endif /* LOG */
05845           cur_state = *state_ptr;
05846 
05847           if (id_max != 1 && w2_stack [1] != 0)
05848         /* Etat implique' par le rafinement precedant */
05849         SXBA_1_bit (w_state_set, cur_state);
05850 
05851           cur_state_ptr = state2attr + cur_state;
05852           part_set_id = cur_state_ptr->temp_id;
05853           id = (part_set_id <= last_part_set_id) ? 1 : part_set_id-last_part_set_id+1;
05854 
05855           if (id != id_max) {
05856         /* On bouge cur_state */
05857         if ((next_part = w2_stack [id]) > 0) {
05858           /* 1ere fois */
05859           next_part = ++last_partition;
05860           w2_stack [id] = -next_part; /* Pour les coups d'apres */
05861         }
05862         else
05863           next_part = -next_part;
05864 
05865         /* cur_state est change' de partition */
05866         /* Ce changement ne peut etre valide' au cours de ce run, il le sera + tard sinon les futurs calculs ds XH_part_set peuvent etre faux */
05867         /* state2part [cur_state] = next_part; doit etre retarde' sinon les futurs calculs ds  XH_part_set peuvent etre faux */
05868         PUSH (working_stack, cur_state);
05869         PUSH (working_stack, next_part);
05870           }
05871           else
05872         /* On ne bouge pas la sous-part maximale */
05873         next_part = cur_part;
05874 
05875 #if EBUG
05876           if (next_part != cur_part && next_part <= old_last_partition)
05877         sxtrap (ME, "dfa_minimize");
05878 #endif /* EBUG */
05879 
05880           /* part_set_id2part [part_set_id] = next_part; semble inutile */
05881         }
05882         
05883         if (id_max != 1 && w2_stack [1] != 0) {
05884           /* Le sous-groupe non touche' par le rafinement pre'ce'dant n'est pas le plus populaire, il va donc etre de'place' aussi car il est non vide */
05885           next_part = ++last_partition;
05886 
05887           for (cur_state = cur_part_ptr->state; cur_state != 0; cur_state = state2attr [cur_state].next_state) { 
05888         if (!SXBA_bit_is_set_reset (w_state_set, cur_state)) {
05889           PUSH (working_stack, cur_state);
05890           PUSH (working_stack, next_part);
05891         }
05892           }
05893         }
05894       }
05895     }
05896       }
05897 
05898       if (!IS_EMPTY (working_stack)) {
05899     do {
05900       cur_part = POP (working_stack);
05901       cur_state = POP (working_stack);
05902       move (cur_state, cur_part);
05903 
05904       pred_stack = dfa_state2pred_stack [cur_state];
05905 
05906       for (state_ptr = pred_stack+TOP(pred_stack); state_ptr > pred_stack; state_ptr--) {
05907 #if LOG
05908         constant_time_step_nb++;             
05909 #endif /* LOG */
05910         pred_state = *state_ptr;
05911 
05912         if (SXBA_bit_is_reset_set (w_state_set, pred_state))
05913           PUSH (w_state_stack, pred_state);
05914       }
05915     } while (!IS_EMPTY (working_stack));
05916       }
05917       else
05918     break;
05919     }
05920 
05921     sxfree (w_state_stack);
05922     sxfree (w_state_set);
05923     sxfree (tbp_part_stack);
05924     sxfree (tbp_state_stacks);
05925   }
05926   else {
05927     /* version de minimize dans laquelle on n'utilise pas les predecesseurs */
05928     for(;;) {
05929 #if LLOG
05930       print_configuration ();
05931 #endif /* LLOG */
05932 
05933       for (cur_part = last_partition; cur_part >= 1; cur_part--) {
05934 #if LOG
05935     constant_time_step_nb++;             
05936 #endif /* LOG */
05937     cur_part_ptr = part2attr+cur_part;
05938     cur_part_card = cur_part_ptr->card;
05939 
05940     if (cur_part_card > 1) {
05941       RAZ (w2_stack);
05942       PUSH (w2_stack, 0); /* Pour les etats dont les successeurs n'ont pas bouge's */
05943       nb_max = 0;
05944       last_part_set_id = XH_top (XH_part_set)-1;
05945 
05946       for (cur_state = cur_part_ptr->state; cur_state != 0; cur_state = cur_state_ptr->next_state) {
05947         cur_state_ptr = state2attr + cur_state;
05948 
05949         /* On recalcule ses etats successeurs */
05950         trans_list_id = cur_state_ptr->trans_list_id;
05951         bot = XH_X (XH_trans_list_id, trans_list_id);
05952         top = XH_X (XH_trans_list_id, trans_list_id+1);
05953 
05954         t_trans = XH_list_elem (XH_trans_list_id, bot++); /* peut etre <0 ou >0 suivant que les etats de la partition sont finals ou pas */
05955         XH_push (XH_part_set, t_trans);
05956 
05957         while (bot < top) {
05958 #if LOG
05959           constant_time_step_nb++;             
05960 #endif /* LOG */
05961           next_state = XH_list_elem (XH_trans_list_id, bot);
05962           next_partition = state2attr [next_state].part;
05963           XH_push (XH_part_set, next_partition);
05964 
05965           bot++;
05966         }
05967 
05968         if (!XH_set (&XH_part_set, &part_set_id)) {
05969           /* Nouveau */
05970           PUSH (w2_stack, 0);
05971           id = TOP (w2_stack);
05972 
05973 #if EBUG 
05974           if (TOP (w2_stack) != part_set_id-last_part_set_id+1)
05975         sxtrap (ME, "dfa_minimize");
05976 #endif /* EBUG */
05977         }
05978         else {
05979           id = (part_set_id <= last_part_set_id) ? 1 : part_set_id-last_part_set_id+1;
05980         }
05981 
05982         nb = ++(w2_stack [id]);
05983 
05984         if (nb > nb_max) {
05985           nb_max = nb;
05986           id_max = id;
05987         }
05988 
05989         cur_state_ptr->temp_id = part_set_id;
05990       }
05991 
05992       /* Si nb_max == cur_part_card, on ne change rien */
05993       if (nb_max < cur_part_card) {
05994         old_last_partition = last_partition;
05995 
05996         /* Ds cur_part on ne va pas deplacer le + grand groupe =>
05997            chacun des groupes deplaces a une taille bornee par cur_part_card/2 */
05998         for (cur_state = cur_part_ptr->state; cur_state != 0; cur_state = cur_state_ptr->next_state) { 
05999 #if LOG
06000           constant_time_step_nb++;             
06001 #endif /* LOG */
06002           cur_state_ptr = state2attr + cur_state;
06003           part_set_id = cur_state_ptr->temp_id;
06004           id = (part_set_id <= last_part_set_id) ? 1 : part_set_id-last_part_set_id+1;
06005 
06006           if (id != id_max) {
06007         /* On bouge cur_state */
06008         if ((next_part = w2_stack [id]) > 0) {
06009           /* 1ere fois */
06010           next_part = ++last_partition;
06011           w2_stack [id] = -next_part; /* Pour les coups d'apres */
06012         }
06013         else
06014           next_part = -next_part;
06015 
06016         /* cur_state est change' de partition */
06017         /* Ce changement ne peut etre valide' au cours de ce run, il le sera + tard sinon les futurs calculs ds XH_part_set peuvent etre faux */
06018         /* state2part [cur_state] = next_part; doit etre retarde' sinon les futurs calculs ds  XH_part_set peuvent etre faux */
06019         PUSH (working_stack, cur_state);
06020         PUSH (working_stack, next_part);
06021           }
06022           else
06023         /* On ne bouge pas la sous-part maximale */
06024         next_part = cur_part;
06025 
06026 #if EBUG
06027           if (next_part != cur_part && next_part <= old_last_partition)
06028         sxtrap (ME, "dfa_minimize");
06029 #endif /* EBUG */
06030 
06031           /* part_set_id2part [part_set_id] = next_part; semble inutile */
06032         }
06033       }
06034     }
06035       }
06036 
06037       if (!IS_EMPTY (working_stack)) {
06038     do {
06039 #if LOG
06040       constant_time_step_nb++;             
06041 #endif /* LOG */
06042       cur_part = POP (working_stack);
06043       cur_state = POP (working_stack);
06044       move (cur_state, cur_part);
06045     } while (!IS_EMPTY (working_stack));
06046       }
06047       else
06048     break;
06049     }
06050   }
06051 
06052 #if LOG
06053   printf ("constant_time_step_nb (with%s backward transitions) = %ld\n", dfa_state2pred_stack ? "" : "out", (long)constant_time_step_nb);
06054 #endif /* LOG */
06055     
06056   sxfree (working_stack);
06057   sxfree (w2_stack);
06058   XH_free (&XH_part_set);
06059   sxfree (part_set_id2part), part_set_id2part = NULL;
06060 
06061   if (dfa_state2pred_stack) {
06062     sxfree (dfa_state2pred_stack), dfa_state2pred_stack = NULL;
06063     sxfree (base_area);
06064   }
06065 
06066   /* On assure seulement que l'etat initial a la valeur min
06067      et l'etat final la valeur max */
06068   /* On en a aussi besoin ds fsa_normalize () */
06069   part2new_part = (SXINT *) sxcalloc (last_partition+1, sizeof (SXINT));
06070   new_part2part = (SXINT *) sxalloc (last_partition+1, sizeof (SXINT));
06071   new_part = 1;
06072   trans_nb = 0;
06073 
06074   for (state = sxdfa_ptr->init_state; state <= sxdfa_ptr->last_state; state++) {
06075     partition = state2attr [state].part;
06076     state = part2attr [partition].state;
06077     trans_nb += sxdfa_ptr->states [state+1]-sxdfa_ptr->states [state]-1;
06078 
06079     if (part2new_part [partition] == 0) {
06080       part2new_part [partition] = new_part;
06081       new_part2part [new_part] = partition;
06082       new_part++;
06083     }
06084   }
06085 
06086   /* On prepare le nouveau sxdfa_ptr */
06087   sxdfa_free (sxdfa_ptr);
06088 
06089   sxdfa_alloc (sxdfa_ptr, last_partition, trans_nb, NULL, NULL);
06090   new_part_final_set = sxba_calloc (last_partition+1);
06091 
06092   sxdfa_ptr->final_state_nb = sxdfa_ptr->number_of_out_trans = 0;
06093     
06094   for (new_part = 1; new_part <= last_partition; new_part++) {
06095     partition = new_part2part [new_part];
06096     state = part2attr [partition].state;
06097 
06098     trans_list_id = state2attr [state].trans_list_id;
06099     bot = XH_X (XH_trans_list_id, trans_list_id);
06100     top = XH_X (XH_trans_list_id, trans_list_id+1);
06101 
06102     t_trans = XH_list_elem (XH_trans_list_id, bot++);
06103 
06104     if (t_trans < 0) {
06105       /* etat final */
06106       PUSH (sxdfa_ptr->next_state_list, -t_trans);
06107       PUSH (sxdfa_ptr->states, (TOP (sxdfa_ptr->next_state_list)<<1)+1);
06108 
06109       if (SXBA_bit_is_reset_set (new_part_final_set, new_part))
06110     sxdfa_ptr->final_state_nb++;
06111     }
06112     else {
06113       PUSH (sxdfa_ptr->next_state_list, t_trans);
06114       PUSH (sxdfa_ptr->states, (TOP (sxdfa_ptr->next_state_list)<<1));
06115     }
06116 
06117     sxdfa_ptr->number_of_out_trans += top-bot;
06118 
06119     while (bot < top) {
06120       next_state = XH_list_elem (XH_trans_list_id, bot);
06121       next_partition = state2attr [next_state].part;
06122       PUSH (sxdfa_ptr->next_state_list, part2new_part [next_partition]);
06123       bot++;
06124     }
06125   }
06126     
06127   PUSH (sxdfa_ptr->next_state_list, 0);
06128   PUSH (sxdfa_ptr->states, TOP (sxdfa_ptr->next_state_list));
06129 
06130   sxdfa_ptr->init_state = 1;
06131   sxdfa_ptr->last_state = last_partition;
06132   sxdfa_ptr->final_state_nb = sxdfa_ptr->number_of_out_trans = sxdfa_ptr->max_arity = 0;
06133   /* INCHANGE'S : 
06134      sxdfa_ptr->max_path_lgth;
06135      sxdfa_ptr->max_arity;
06136      sxdfa_ptr->max_t_val;
06137      sxdfa_ptr->private.from_left_to_right;
06138      sxdfa_ptr->is_a_dag = SXFALSE;
06139   */
06140 
06141   sxfree (new_part_final_set);
06142 
06143   sxfree (part2new_part);
06144   sxfree (new_part2part);
06145 
06146   sxfree (part2attr), part2attr = NULL;
06147   sxfree (state2attr), state2attr = NULL;
06148 
06149   XH_free (&XH_trans_list_id);
06150 
06151   if (to_be_normalized)
06152     sxdfa_normalize (sxdfa_ptr);
06153 }
06154 
06155 
06156 static void
06157 sxdfa_fill_old_state2max_path_lgth (struct sxdfa_struct *sxdfa_ptr, SXINT state)
06158 {
06159   SXINT bot, top, next_state, prev_max_path_lgth, next_max_path_lgth, max_path_lgth;
06160 
06161   if (SXBA_bit_is_reset_set (state_set, state)) {
06162     /* Pas de cycle sur state */
06163     prev_max_path_lgth = old_state2max_path_lgth [state];
06164 
06165     bot = sxdfa_ptr->states [state]>>1;
06166     top = sxdfa_ptr->states [state+1]>>1;
06167 
06168     while (++bot < top) {
06169       next_state = sxdfa_ptr->next_state_list [bot];
06170       next_max_path_lgth = old_state2max_path_lgth [next_state];
06171 
06172       if (next_max_path_lgth == 0 || next_max_path_lgth < prev_max_path_lgth) {
06173     /* C'est la 1ere fois qu'on tombe sur next_old_state */
06174     /* On a deja atteint next_old_state par un autre chemin "normal" mais plus court... */
06175     max_path_lgth = prev_max_path_lgth+1;
06176     old_state2max_path_lgth [next_state] = max_path_lgth;
06177 
06178     if (max_path_lgth > old_state2max_path_lgth [0])
06179       old_state2max_path_lgth [0] = max_path_lgth;
06180 
06181     sxdfa_fill_old_state2max_path_lgth (sxdfa_ptr, next_state);
06182       }
06183       /*
06184     else
06185     rien
06186       */
06187 
06188     }
06189 
06190     SXBA_0_bit (state_set, state);
06191   }
06192   else {
06193     /*
06194       Detection d'un cycle ds l'automate
06195       On ne touche pas a old_state2max_path_lgth [state]
06196     */
06197     normalized_is_cyclic = SXTRUE;
06198   }
06199 }
06200 
06201 
06202 void
06203 sxdfa_normalize (struct sxdfa_struct *sxdfa_ptr)
06204 {
06205   SXINT state, new_state, old_state, bot, top, next_old_state, next_new_state, is_final_state;
06206   SXINT *cur_to_be_sorted, *old_states, *old_next_state_list;
06207 
06208   old_state2max_path_lgth = (SXINT*) sxcalloc (sxdfa_ptr->last_state+1, sizeof (SXINT));
06209   state_set = sxba_calloc (sxdfa_ptr->last_state+1);
06210 
06211   SXBA_1_bit (state_set, sxdfa_ptr->init_state);
06212   old_state2max_path_lgth [sxdfa_ptr->init_state] = 1; /* pour reserver 0 a non encore traite' */
06213 
06214   /* On calcule la longueur maximale des chemins qui conduisent depuis l'etat initial a chaque etat de l'automate ... */
06215   normalized_is_cyclic = SXFALSE;
06216 
06217   sxdfa_fill_old_state2max_path_lgth (sxdfa_ptr, sxdfa_ptr->init_state);
06218 
06219   sxdfa_ptr->is_a_dag = !normalized_is_cyclic;
06220 
06221   if (sxdfa_ptr->is_a_dag)
06222     sxdfa_ptr->max_path_lgth = old_state2max_path_lgth [0];
06223 
06224   /* Attention, si l'automate en entree contient des cycles (c'est pas un DAG), l'algo precedent n'assure pas
06225      que l'etat final sera a` la distance max de l'etat initial, on y remedie */
06226   old_state2max_path_lgth [sxdfa_ptr->last_state] = sxdfa_ptr->last_state;
06227 
06228   /* ... On trie ces etats par ces longueurs ... */
06229   sxfree (state_set), state_set = NULL;
06230   cur_to_be_sorted = (SXINT*) sxalloc (sxdfa_ptr->last_state+1, sizeof (SXINT));
06231 
06232   for (state = 0; state <= sxdfa_ptr->last_state; state++)
06233     cur_to_be_sorted [state] = state;
06234 
06235   qsort(cur_to_be_sorted+sxdfa_ptr->init_state, sxdfa_ptr->last_state-sxdfa_ptr->init_state+1, sizeof (SXINT), cmp_old_state);
06236 
06237   sxfree (old_state2max_path_lgth), old_state2max_path_lgth = NULL;
06238 
06239   /* Pour des questions d'ordre de sortie, on a besoin de la correspondance old_state -> new_state */
06240   old_state2new_state = (SXINT*) sxalloc (sxdfa_ptr->last_state+1, sizeof (SXINT));
06241 
06242   for (new_state = sxdfa_ptr->init_state; new_state <= sxdfa_ptr->last_state; new_state++) {
06243     state = cur_to_be_sorted [new_state];
06244     old_state2new_state [state] = new_state;
06245   }
06246 
06247   /* ... et on sort l'automate "normalise' */
06248   /* par ordre croissant des etats d'origine de chaque transition (pour chaque p, on sort tous les p ->t q) */
06249   old_states = sxdfa_ptr->states;
06250   old_next_state_list = sxdfa_ptr->next_state_list;
06251 
06252   sxdfa_alloc (sxdfa_ptr, sxdfa_ptr->last_state, sxdfa_ptr->number_of_out_trans, NULL, NULL);
06253 
06254   for (new_state = sxdfa_ptr->init_state; new_state < sxdfa_ptr->last_state; new_state++) {
06255     old_state = cur_to_be_sorted [new_state];
06256 
06257     bot = old_states [old_state];
06258     is_final_state = bot & 1;
06259     bot >>= 1;
06260     top = old_states [old_state+1]>>1;
06261 
06262     PUSH (sxdfa_ptr->next_state_list, old_next_state_list [bot++]);
06263 
06264     if (is_final_state)
06265       PUSH (sxdfa_ptr->states, (TOP (sxdfa_ptr->next_state_list)<<1)+1);
06266     else
06267       PUSH (sxdfa_ptr->states, (TOP (sxdfa_ptr->next_state_list)<<1));
06268 
06269     while (bot < top) {
06270       next_old_state = old_next_state_list [bot++];
06271       next_new_state = old_state2new_state [next_old_state];
06272       PUSH (sxdfa_ptr->next_state_list, next_new_state);
06273     }
06274   }
06275 
06276   PUSH (sxdfa_ptr->next_state_list, 0);
06277   PUSH (sxdfa_ptr->states, TOP (sxdfa_ptr->next_state_list));
06278 
06279   /* Le reste de sxdfa_ptr est inchange' */
06280     
06281   sxfree (cur_to_be_sorted), cur_to_be_sorted = NULL;
06282   sxfree (old_state2new_state);
06283 
06284   sxfree (old_states);
06285   sxfree (old_next_state_list);
06286 }
06287 
06288 
06289 static SXBOOLEAN
06290 sxdfa_fill_dag_hd (struct sxdfa_struct *sxdfa_ptr, SXINT p, SXINT t, SXINT q)
06291 {
06292   SXINT           dag_id;
06293   SXBOOLEAN         first_time;
06294   struct dag_attr *attr_ptr;
06295 
06296   first_time = !XxY_set (&dag_hd, p, q, &dag_id);
06297 
06298   attr_ptr = dag_id2attr+dag_id;
06299 
06300   if (first_time) {
06301     dag_hd_trans_nb++;
06302     attr_ptr->trans = ATOMIC_CODE | (SXUINT) t;
06303   }
06304   else {
06305     /* On fait un or */
06306     attr_ptr->trans = (SXINT) make_code ((SXUINT) (attr_ptr->trans), ATOMIC_CODE | (SXUINT) t, OR_TRANS);
06307   }
06308 
06309   if (sxdfa_ptr->states [q] & 1) {
06310     /* etat final */
06311     /* Traitement des EOW */
06312     first_time = !XxY_set (&dag_hd, q, sxdfa_ptr->last_state+1, &dag_id);
06313 
06314     attr_ptr = dag_id2attr+dag_id;
06315 
06316     if (first_time) {
06317       dag_hd_trans_nb++;
06318       attr_ptr->trans = ATOMIC_CODE; /* t == 0 !! */
06319     }
06320     else {
06321       /* On fait un or */
06322       attr_ptr->trans = (SXINT) make_code ((SXUINT) (attr_ptr->trans), ATOMIC_CODE, OR_TRANS);
06323     }
06324   }
06325 
06326   return SXTRUE;
06327 }
06328 
06329 
06330 
06331 /* appelle la fonction f sur toutes les transitions issues de state
06332    Si f retourne SXFALSE, arret
06333 */
06334 void
06335 sxdfa_extract_trans (struct sxdfa_struct *sxdfa_ptr, SXINT state, SXBOOLEAN (*f)(struct sxdfa_struct *, SXINT, SXINT, SXINT))
06336 {
06337   SXINT trans_nb, bot, top, bot_trans, is_final;
06338   SXINT *state_ptr, *next_states_ptr, *bot_trans_list_ptr, *top_trans_list_ptr;
06339 
06340   state_ptr = sxdfa_ptr->states + state;
06341   bot = state_ptr [0];
06342   top = state_ptr [1]>>1;
06343 
06344   is_final = bot & 1;
06345   bot >>= 1;
06346 
06347   trans_nb = top-bot;
06348 
06349 #if EBUG
06350   if (trans_nb <= 0)
06351     sxtrap (ME, "sxdfa_extract_trans");
06352 #endif
06353   
06354   next_states_ptr = sxdfa_ptr->next_state_list + bot;
06355   bot_trans = *next_states_ptr++;
06356 
06357   if (bot_trans < 0) {
06358     if (is_final) {
06359       /* L'etat state est final et -bot_trans est l'identifiant associe' */
06360       if (!(*f)(sxdfa_ptr, state, bot_trans, 0 /* next_state */) || trans_nb == 1)
06361     return;
06362 
06363       bot_trans = *next_states_ptr++;
06364 
06365       if (bot_trans < 0) {
06366     /* ici -bot_trans est l'identifiant associe' au mot unique qui sera reconnu sur
06367        le futur etat final */
06368 #if EBUG
06369     if (trans_nb != 3)
06370       sxtrap (ME, "sxdfa_extract_trans");
06371 #endif /* EBUG */
06372 
06373     (*f)(sxdfa_ptr, state, bot_trans, *next_states_ptr);
06374     return; /* Ds tous les cas */
06375       }
06376 
06377       /* Ici bot_trans > 0 est l'identifiant d'un ensemble de transitions */
06378       trans_nb--;
06379     }
06380     else {
06381       /* ici -bot_trans est l'identifiant associe' au mot unique qui sera reconnu sur
06382      le futur etat final */
06383 #if EBUG
06384       if (trans_nb != 2)
06385     sxtrap (ME, "sxdfa_extract_trans");
06386 #endif /* EBUG */
06387 
06388       (*f)(sxdfa_ptr, state, bot_trans, *next_states_ptr);
06389       return; /* Ds tous les cas */
06390     }
06391   }
06392   else {
06393     if (is_final) {
06394       /* L'etat state est final (mais n'est pas une feuille) */
06395       if (!(*f)(sxdfa_ptr, state, -1, 0 /* next_state */) || trans_nb == 1)
06396     return;
06397     }
06398   }
06399 
06400   bot_trans_list_ptr = sxdfa_ptr->trans_list + bot_trans;
06401   top_trans_list_ptr = bot_trans_list_ptr + trans_nb -1;
06402 
06403   while (bot_trans_list_ptr < top_trans_list_ptr) {
06404     if (!(*f)(sxdfa_ptr, state, *bot_trans_list_ptr++, *next_states_ptr++))
06405       break;
06406   }
06407 }
06408 
06409 
06410 VARSTR
06411 sxdfadag2re (VARSTR varstr_ptr, struct sxdfa_struct *sxdfa_ptr, char *(*get_trans_name) (SXINT))
06412 {
06413   SXINT p, single_trans, code;
06414 
06415   dag_get_trans_name = get_trans_name;
06416   final_state = sxdfa_ptr->last_state;
06417 
06418   XH_alloc (&code_hd, "code_hd", final_state+1, 1, 
06419         sxdfa_ptr->number_of_out_trans/final_state + 1 /* si un jour ça explose ici, on peut tenter de remplacer ce truc malin par, genre, 64 */, 
06420         code_hd_oflw, NULL);
06421   code2size = (SXINT*) sxalloc (XH_size (code_hd)+1, sizeof (SXINT));
06422 
06423 #if LOG
06424   wvstr = varstr_alloc (256);
06425 #endif /* LOG */
06426   XxY_alloc (&dag_hd, "dag_hd", sxdfa_ptr->last_state+1, 1, 1 /* Xforeach */, 1 /* Yforeach */, dag_hd_oflw, NULL);
06427   dag_id2attr = (struct dag_attr*) sxalloc (XxY_size (dag_hd)+1, sizeof (struct dag_attr));
06428 
06429   dag_hd_trans_nb = 0;
06430 
06431   for (p = sxdfa_ptr->init_state; p < sxdfa_ptr->last_state; p++) {
06432     sxdfa_extract_trans (sxdfa_ptr, p, sxdfa_fill_dag_hd);
06433   }
06434 
06435   /* Nelle factorisation des OR */
06436   XxY_alloc (&paths, "paths", 30, 1, 1 /* Xforeach */, 0, paths_oflw, NULL);
06437   path2lgth = (SXINT *) sxalloc (XxY_size (paths)+1, sizeof (SXINT));
06438   path2tree = (SXINT *) sxalloc (XxY_size (paths)+1, sizeof (SXINT));
06439   paths_set = sxba_calloc (XxY_size (paths)+1);
06440   final_paths_set = sxba_calloc (XxY_size (paths)+1);
06441   paths_stack = (SXINT *) sxalloc (XxY_size (paths)+1, sizeof (SXINT)), paths_stack [0] = 0;
06442   XxY_alloc (&branches, "branches", 30, 1, 0, 0, branches_oflw, NULL);
06443   branch2occur_nb = (SXINT *) sxalloc (XxY_size (branches)+1, sizeof (SXINT));
06444   branches_set = sxba_calloc (XxY_size (branches)+1);
06445   XxY_alloc (&pathXbranch, "pathXbranch", 30, 1, 0, 1 /* Yforeach */, NULL, NULL);
06446   XxY_alloc (&pathXtree, "pathXtree", 30, 1, 0, 1 /* Yforeach */, NULL, NULL);
06447   XH_alloc (&trees, "trees", 30, 1, 4, trees_oflw, NULL);
06448   tree2size = (SXINT *) sxalloc (XH_size (trees)+1, sizeof (SXINT));
06449   tree2occur_nb = (SXINT *) sxalloc (XH_size (trees)+1, sizeof (SXINT));
06450   DALLOC_STACK (code_stack, 100);
06451 
06452   single_trans = 1; /* Si trans unique ds le DAG */
06453 
06454   while (dag_hd_trans_nb > 1) {
06455     single_trans = dag_reduce ();
06456   }
06457 
06458   code = dag_id2attr [single_trans].trans;
06459 
06460   if (code2trans (code) == OR_TRANS)
06461     code = factorize_OR (code);
06462   
06463   XxY_free (&paths);
06464   sxfree (paths_set), paths_set = NULL;
06465   sxfree (final_paths_set), final_paths_set = NULL;
06466   sxfree (paths_stack), paths_stack = NULL;
06467   sxfree (path2tree), path2tree = NULL;
06468   sxfree (path2lgth), path2lgth = NULL;
06469   XxY_free (&branches);
06470   sxfree (branch2occur_nb), branch2occur_nb = NULL;
06471   sxfree (branches_set), branches_set = NULL;
06472   XxY_free (&pathXbranch);
06473   XxY_free (&pathXtree);
06474   XH_free (&trees);
06475   sxfree (tree2size), tree2size = NULL;
06476   sxfree (tree2occur_nb), tree2occur_nb = NULL;
06477   DFREE_STACK (code_stack);
06478 
06479   varstr_ptr = print_code (varstr_ptr, code);
06480 
06481 #if LOG
06482   varstr_free (wvstr);
06483 #endif /* LOG */
06484   XxY_free (&dag_hd);
06485   sxfree (dag_id2attr), dag_id2attr = NULL;
06486   XH_free (&code_hd);
06487   sxfree (code2size), code2size = NULL;
06488 
06489   return varstr_ptr;
06490 
06491 }
06492 
06493 
06494 
06495 void
06496 sxdfa2c (struct sxdfa_struct *sxdfa_ptr, FILE *file, char *name, SXBOOLEAN is_static)
06497 {
06498   SXINT  i;
06499 
06500 
06501   fprintf (file, "\nstatic SXINT %s_states [%ld] = {\n", name, sxdfa_ptr->states [0]+1);
06502 
06503   for (i = 0; i <= sxdfa_ptr->states [0]; i++) {
06504     fprintf (file, "/* %ld */ %ld,\n", i, sxdfa_ptr->states [i]);
06505   }
06506 
06507   fprintf (file, "};\n");
06508 
06509   fprintf (file, "\nstatic SXINT %s_next_state_list [%ld] = {\n", name, sxdfa_ptr->next_state_list [0]+1);
06510 
06511   for (i = 0; i <= sxdfa_ptr->next_state_list [0]; i++) {
06512     fprintf (file, "/* %ld */ %ld,\n", i, sxdfa_ptr->next_state_list [i]);
06513   }
06514 
06515   fprintf (file, "};\n");
06516 
06517   fprintf (file, "\nstatic SXINT %s_trans_list [%ld] = {\n", name, sxdfa_ptr->trans_list [0]+1);
06518 
06519   for (i = 0; i <= sxdfa_ptr->trans_list [0]; i++) {
06520     fprintf (file, "/* %ld */ %ld,\n", i, sxdfa_ptr->trans_list [i]);
06521   }
06522 
06523   fprintf (file, "};\n");
06524 
06525   fprintf (file, "\n%sstruct sxdfa_struct %s = {\n", is_static ? "static " : "", name);
06526   fprintf (file, "/* init_state */ %ld,\n\
06527 /* last_state */ %ld,\n\
06528 /* number_of_out_trans */ %ld,\n\
06529 /* final_state_nb */ %ld,\n\
06530 /* max_path_lgth */ %ld,\n\
06531 /* max_arity */ %ld,\n\
06532 /* max_t_val */ %ld,\n\
06533 /* name */ \"%s\",\n\
06534 /* stats */ NULL,\n\
06535 %s_states,\n\
06536 %s_next_state_list,\n\
06537 %s_trans_list,\n\
06538 /* is_static */ SXTRUE,\n\
06539 /* is_a_dag */ %s,\n\
06540  {\n\
06541  /* from_left_to_right */ %s,\
06542  }\n",
06543        sxdfa_ptr->init_state,
06544        sxdfa_ptr->last_state,
06545        sxdfa_ptr->number_of_out_trans,
06546        sxdfa_ptr->final_state_nb,
06547        sxdfa_ptr->max_path_lgth,
06548        sxdfa_ptr->max_arity,
06549        sxdfa_ptr->max_t_val,
06550        name,
06551        name,
06552        name,
06553        name,
06554        sxdfa_ptr->is_a_dag ? "SXTRUE" : "SXFALSE",
06555        sxdfa_ptr->private.from_left_to_right ? "SXTRUE" : "SXFALSE"
06556        );
06557 
06558   fprintf (file, "};\n");
06559 }
06560 
06561 
06562 
06563 
06564 /* Valeurs retournees :
06565    Soit state pour sxdfa_seek ()
06566    et lgth = *input_stack
06567    (la valeur initiale de *input_stack = input_lgth)
06568 
06569    lgth\state |  >0    |   0
06570    ------------------------------
06571         0     |   I    |   II
06572    ------------------------------
06573         >0    | III    |   IV
06574    ------------------------------
06575 
06576    I  : input est reconnu en entier
06577    II : input est un prefixe (resp. suffixe) d'un ou plusieurs word (inconnus)
06578    III: word est un prefixe de longueur input_lgth-lgth de input
06579    IV : input_lgth-lgth symboles du prefixe (resp. suffixe) de input ont ete reconnus
06580 */
06581 
06582 
06583 /* kw ds le fsa repre'sente' sous forme d'un sxdfa_struct et retourne l'etat final ou 0 si kw n'est pas reconnu */
06584 /* Si echec, kwl indique la partie suffixe non reconnue. */
06585 /* Si pas from_left_to_right les mots sont ranges en sens inverse, on reconnait donc kw de droite a gauche */
06586 /* Si seek_prefix_or_suffix on regarde si le plus long prefixe (resp. suffixe si !from_left_to_right) de kw est un mot du dico
06587    ds ce cas on retourne l'identifiant ds le dico de ce prefixe (et *kwl est la longueur du suffixe (resp. prefixe) non reconnu */
06588 SXINT
06589 sxdfa_seek_a_string (struct sxdfa_struct *sxdfa_ptr, char *kw, SXINT *kwl)
06590 {
06591   sxdfa_ptr->private.ptr.char_ptr = (sxdfa_ptr->private.from_left_to_right) ? kw : kw+*kwl-1;
06592 
06593   return sxdfa_seek (sxdfa_ptr, string_get_next_symb, kwl);
06594 }
06595 
06596 
06597 
06598 SXINT
06599 sxdfa_seek_a_word (struct sxdfa_struct *sxdfa_ptr, SXINT *input_stack)
06600 {
06601   sxdfa_ptr->private.ptr.SXINT_ptr = (sxdfa_ptr->private.from_left_to_right) ? input_stack + 1 : input_stack + *input_stack;
06602 
06603   return sxdfa_seek (sxdfa_ptr, word_get_next_symb, input_stack);
06604 }
06605 
06606 /*  
06607     ret_val | lgth
06608    ---------|-------
06609      id>0   |   0    => OK
06610    -----------------
06611      id>0   |   >0   => le + long prefixe du mot est ds le dico (id), le suffixe est de longueur lgth
06612    -----------------
06613      id==0  |   0    => le mot est un prefixe de mots (non identifies) du dico
06614    -----------------
06615      id<0   |   0    => unused
06616    -----------------
06617      id==0  |   >0   => Echec total, le suffixe est de longueur lgth
06618    -----------------
06619      id<0   |   >0   => le mot est un prefixe du mot -id du dico
06620 
06621 */
06622 SXINT
06623 sxdfa_seek (struct sxdfa_struct *sxdfa_ptr, SXUINT (*get_next_symb) (struct sxdfa_private *), SXINT *input_lgth)
06624 {
06625   SXINT     lgth, cur_index, state, trans_nb, trans, mid_trans, bot, is_final, bot_trans, final_id, last_final_id, final_lgth;
06626   SXINT         *state_ptr, *next_states_ptr, *trans_list_ptr, *bot_trans_list_ptr, *top_trans_list_ptr, *mid_trans_list_ptr, *top_next_state_ptr;
06627 
06628   lgth = *input_lgth;
06629 
06630   if (lgth < 0)
06631     return 0;
06632 
06633   sxinitialise (final_lgth);
06634 
06635   final_id = last_final_id = 0;
06636   state = sxdfa_ptr->init_state;
06637 
06638   while (lgth > 0 && state > 0) {
06639     state_ptr = sxdfa_ptr->states + state;
06640     bot = state_ptr [0];
06641 
06642     is_final = bot & 1;
06643   
06644     next_states_ptr = sxdfa_ptr->next_state_list + (bot>>1);
06645     bot_trans = *next_states_ptr++;
06646     top_next_state_ptr = sxdfa_ptr->next_state_list + (state_ptr [1]>>1);
06647 
06648     if (bot_trans < 0) {
06649       if (is_final) {
06650     /* L'etat state est final et -bot_trans est l'identifiant associe' ... */
06651     /* ... mais lgth > 0, on n'est donc pas interesse' par cette transition */
06652     /* On note le +long prefixe du mot en entree reconnu */
06653     final_id = -bot_trans;
06654     final_lgth = lgth;
06655 
06656     if (next_states_ptr == top_next_state_ptr) {
06657       /* pas de transition => echec car lgth non nul */
06658       break;
06659     }
06660 
06661     bot_trans = *next_states_ptr++;
06662 
06663     if (bot_trans < 0) {
06664       /* ici -bot_trans est l'identifiant associe' au mot unique qui sera reconnu sur
06665          le futur etat final */
06666       last_final_id = -bot_trans;
06667       bot_trans = *next_states_ptr++; /* C'est un trans_id */
06668     }
06669       }
06670       else {
06671       /* ici -bot_trans est l'identifiant associe' au mot unique qui sera reconnu sur
06672      le futur etat final */
06673       last_final_id = -bot_trans;
06674       bot_trans = *next_states_ptr++; /* C'est un trans_id */
06675       }
06676     }
06677     else {
06678       if (is_final) {
06679     /* Un prefixe du mot est dans le dico */
06680     final_id = 1;
06681     final_lgth = lgth;
06682       }
06683     }
06684 
06685     cur_index = -1;
06686     bot_trans_list_ptr = trans_list_ptr = sxdfa_ptr->trans_list + bot_trans;
06687     top_trans_list_ptr = bot_trans_list_ptr + (top_next_state_ptr-next_states_ptr);
06688 
06689     trans = (SXINT) ((*get_next_symb) (&(sxdfa_ptr->private)));
06690     /* On cherche a quel index se trouve trans dans la "pile" trans_list_ptr ... */
06691     /* ... par dicho */
06692 
06693     while ((trans_nb = top_trans_list_ptr-bot_trans_list_ptr)) {
06694       mid_trans_list_ptr = bot_trans_list_ptr+trans_nb/2;
06695       mid_trans = *mid_trans_list_ptr;
06696 
06697       if (mid_trans == trans) {
06698     cur_index = mid_trans_list_ptr-trans_list_ptr;
06699     break;
06700       }
06701 
06702       if (mid_trans < trans)
06703     bot_trans_list_ptr = mid_trans_list_ptr+1;
06704       else
06705     top_trans_list_ptr = mid_trans_list_ptr;
06706     }
06707 
06708     if (cur_index < 0)
06709       /* Echec */
06710       break;
06711 
06712     lgth--;
06713     state = next_states_ptr [cur_index];
06714   }
06715 
06716   *input_lgth = lgth;
06717 
06718   if (lgth == 0) {
06719     /* On a reconnu le mot en entier ... */
06720     /* ... c'est OK uniquement si l'etat atteint est final */
06721     if (state == 0 || state < 0/* etat final feuille */) {
06722       /* Ok */
06723       if (state == 0)
06724     return last_final_id ? last_final_id : 1; /* OK : valeur retournee >0 et lgth == 0 */
06725 
06726       return -state;
06727     }
06728 
06729     bot = sxdfa_ptr->states [state];
06730 
06731     if (bot & 1 /* etat final "interne" */) {
06732       /* Ok */
06733 #if EBUG
06734       if (last_final_id != 0)
06735     sxtrap (ME, "sxdfa_seek");
06736 #endif /* EBUG */
06737 
06738       bot_trans = sxdfa_ptr->next_state_list [bot>>1];
06739 
06740       return bot_trans < 0 ? -bot_trans : 1; /* OK : valeur retournee >0 et lgth == 0 */
06741     }
06742 
06743     /* Ici le mot est un prefixe de mots du dico */
06744     /* On peut retourner plusieurs choses */
06745     /* le seul mot unique eventuel ou
06746        le +long prefixe du mot qui est ds le dico */
06747     /* On choisit le 2eme cas */
06748     if (final_id) {
06749       *input_lgth = final_lgth;
06750       return final_id; /* le + long prefixe du mot est ds le dico (final_id), le suffixe est de longueur final_lgth */
06751     }
06752 
06753     return 0; /* le mot est un prefixe de mots (non identifies) du dico */
06754   }
06755 
06756   /* Ici le mot n'a pas ete reconnu en entier */
06757   if (state == 0 /* etat final feuille */ || (sxdfa_ptr->states [state] & 1) /* etat final "interne" */) {
06758     /* Il y a un mot du dico qui est un prefixe du mot d'entree */
06759     return final_id ? -final_id : -1; /* le mot est un prefixe du mot -final_id du dico (il reste lgth char a reconnaitre ds -final_id) */
06760   }
06761     
06762   if (final_id) {
06763     *input_lgth = final_lgth;
06764     return final_id; /* le + long prefixe du mot est ds le dico (final_id), le suffixe est de longueur final_lgth */
06765   }
06766 
06767   return 0; /* Echec total, le suffixe est de longueur lgth */
06768 }
06769 
06770 
06771 
06772 
06773 /*  ***********************************************  COMB_VECTOR  ****************************************************************** */
06774 static SXINT                 max_class_value;
06775 static SXBA_INDEX_OR_ERROR   base_comb_vector;
06776 static SXINT                 *base2stack, char_stack_list_size, char_stack_list_top;
06777 static unsigned char         *char_stack_list;
06778 
06779 
06780 /* retourne l'index ou est installe' comb
06781    et modifie comb_vector en consequence */
06782 static SXINT
06783 install_a_comb (SXBA *comb_vector_ptr, SXBA comb, SXBA *base_pos_set_ptr)
06784 {
06785   SXINT  base_value;
06786   SXUINT comb_size, comb_vector_size, first_comb_elem, first_comb_word_index, free_comb_vector_elem, free_comb_vector_word_index, right_shift, left_shift, cword, cvword;
06787   SXUINT *last_comb_word, *first_comb_word, *free_comb_vector_word, *comb_word, *comb_vector_word;
06788   SXBA   comb_vector, base_pos_set;
06789   int    kind;
06790 
06791   sxinitialise (left_shift);
06792   sxinitialise (right_shift);
06793 
06794   comb_vector = *comb_vector_ptr;
06795   base_pos_set = *base_pos_set_ptr;
06796 
06797   comb_size = SXBASIZE (comb);
06798   last_comb_word = comb + SXNBLONGS (comb_size);
06799   comb_vector_size = SXBASIZE (comb_vector);
06800 
06801   first_comb_elem = sxba_scan (comb, -1);
06802   first_comb_word = comb + DIV (first_comb_elem) + 1; /* first_comb_elem se trouve ds ce mot ... */
06803   first_comb_word_index = MOD (first_comb_elem); /* ... ds cette position */
06804 
06805   if (base_comb_vector)
06806     free_comb_vector_elem = (SXUINT) base_comb_vector;
06807   else
06808     free_comb_vector_elem = first_comb_elem-1;
06809 
06810   for (;;) {
06811     free_comb_vector_elem = (SXUINT) sxba_0_lrscan (comb_vector, free_comb_vector_elem);
06812     if (free_comb_vector_elem == (SXUINT)(-1)) {
06813       /* possibilite' franchement improbable de debordement */
06814       comb_vector_size *= 2;
06815       *comb_vector_ptr = comb_vector = sxba_resize (comb_vector, (SXBA_INDEX) comb_vector_size);
06816       *base_pos_set_ptr = base_pos_set = sxba_resize (base_pos_set, (SXBA_INDEX) comb_vector_size);
06817       free_comb_vector_elem = sxba_0_lrscan (comb_vector, (SXBA_INDEX_OR_ERROR) free_comb_vector_elem);
06818     }
06819 
06820     base_value = (SXINT) (free_comb_vector_elem - first_comb_elem);
06821 
06822     if (!SXBA_bit_is_set (base_pos_set, base_value)) {
06823       /* On n'implante pas 2 combs differents sur la meme base_value */
06824       if (free_comb_vector_elem+comb_size >= comb_vector_size) {
06825     /* possibilite' de debordement */
06826     comb_vector_size *= 2;
06827     *comb_vector_ptr = comb_vector = sxba_resize (comb_vector, (SXBA_INDEX) comb_vector_size);
06828     *base_pos_set_ptr = base_pos_set = sxba_resize (base_pos_set, (SXBA_INDEX) comb_vector_size);
06829       }
06830 
06831       free_comb_vector_word = comb_vector + DIV (free_comb_vector_elem) + 1; /* first_comb_elem se trouve ds ce mot ... */
06832       free_comb_vector_word_index = MOD (free_comb_vector_elem); /* ... ds cette position */
06833 
06834       if (first_comb_word_index == free_comb_vector_word_index) {
06835     kind = 0;
06836       }
06837       else {
06838     if (first_comb_word_index > free_comb_vector_word_index) {
06839       kind = 1;
06840       right_shift = first_comb_word_index - free_comb_vector_word_index;
06841       left_shift = SXBITS_PER_LONG - right_shift;
06842     }
06843     else {
06844       kind = -1;
06845       left_shift = free_comb_vector_word_index - first_comb_word_index;
06846       right_shift = SXBITS_PER_LONG - left_shift;
06847     }
06848       }
06849 
06850       comb_word = first_comb_word;
06851       comb_vector_word = free_comb_vector_word;
06852 
06853       while (comb_word <= last_comb_word) {
06854     if ((cword = *comb_word)) {
06855       if ((cvword = *comb_vector_word)) {
06856         if (kind == 1) {
06857           if ((cword>>right_shift) & cvword)
06858         /* Echec */
06859         break;
06860 
06861           if ((cword = cword<<left_shift) && (cword & comb_vector_word [-1] /* existe toujours si word est non nul */))
06862         /* Echec */
06863         break;
06864         }
06865         else {
06866           if (kind == -1) {
06867         if ((cword<<left_shift) & cvword)
06868           /* Echec */
06869           break;
06870 
06871         if ((cword>>right_shift) & (comb_vector_word [1] /* existe toujours */))
06872           /* Echec */
06873           break;
06874           }
06875           else {
06876         if (cword & cvword)
06877           /* Echec */
06878           break;
06879           }
06880         }
06881       }
06882       else {
06883         if (kind) {
06884           if (kind == 1) {
06885         if ((cword = cword<<left_shift) && (cword & comb_vector_word [-1] /* existe toujours si word est non nul */))
06886           /* Echec */
06887           break;
06888           }
06889           else {
06890         if ((cword>>right_shift) & (comb_vector_word [1] /* existe toujours */))
06891           /* Echec */
06892           break;
06893           }
06894         }
06895       }
06896     }
06897 
06898     comb_word++;
06899     comb_vector_word++;
06900       }
06901 
06902       if (comb_word > last_comb_word) {
06903     /* Ca a marche' */
06904     comb_word = first_comb_word;
06905     comb_vector_word = free_comb_vector_word;
06906 
06907     while (comb_word <= last_comb_word) {
06908       if ((cword = *comb_word++)) {
06909         if (kind == 1) {
06910           *comb_vector_word |= cword>>right_shift;
06911 
06912           if ((cword = cword<<left_shift))
06913         comb_vector_word [-1] |= cword;
06914         }
06915         else {
06916           if (kind == -1) {
06917         *comb_vector_word |= cword<<left_shift;
06918 
06919         if ((cword = cword>>right_shift))
06920           comb_vector_word [1] |= cword;
06921           }
06922           else {
06923         *comb_vector_word |= cword;
06924           }
06925         }
06926       }
06927 
06928       comb_vector_word++;
06929     }
06930 
06931     SXBA_1_bit (base_pos_set, base_value);
06932 
06933     return  base_value;
06934       }
06935     }
06936   }
06937 }
06938 
06939 #if 0
06940 /* static a cause de cyclic_class_q_check */
06941 static struct classXq2attr {
06942   SXINT card, next, prev, working_nb, working_next; 
06943 } *classXq2attr;
06944 
06945 #if EBUG
06946 static void
06947 classXq_hd_oflw (SXINT old_size, SXINT new_size)
06948 {
06949   sxtrap (ME, "classXq_hd_oflw");
06950 #if 0
06951   classXq2attr = (struct classXq2attr *) sxrealloc (classXq2attr, new_size+1, sizeof (struct classXq2attr));
06952   classXq2p_set = sxbm_resize (classXq2p_set, old_size+1, new_size+1, sxdfa_last_state+1);
06953 #endif /* 0 */
06954 }
06955 #endif /* EBUG */
06956 #endif /* 0 */
06957 
06958 void
06959 sxdfa2comb_vector (struct sxdfa_struct *sxdfa_ptr, SXINT optim_kind, SXINT comb_vector_threshold, struct sxdfa_comb *sxdfa_comb_ptr)
06960 {
06961   SXINT         state, base_pos, size, max_base_pos, t, class, tooth, next_state, is_final_state, bot, bot_trans, stop_mask;
06962   SXINT         *state_ptr, *next_states_ptr, *top_next_states_ptr, *trans_list_ptr;
06963   SXINT         *state2base_pos, char_comb_cardinal = 0;
06964   SXUINT        *comb_vector_ptr, base_shift;
06965   unsigned char *char2class;
06966   SXBA          comb, comb_vector, char_comb, base_pos_set;
06967   SXBOOLEAN     is_generate_char_stack_list = (optim_kind == 2);
06968 
06969   if (sxdfa_ptr->max_t_val >= 256)
06970     sxtrap (ME, "sxdfa2comb_vector");
06971 
06972   /* On transforme les caracteres en classe */
06973   char2class = (unsigned char*) sxcalloc (256, sizeof (unsigned char));
06974 
06975   {
06976     SXBA  char_set;
06977     SXINT *cur_trans_list_ptr;
06978 
06979 
06980     char_set = sxba_calloc (256);
06981     trans_list_ptr = sxdfa_ptr->trans_list;
06982     cur_trans_list_ptr = trans_list_ptr + *trans_list_ptr;
06983 
06984     while (cur_trans_list_ptr > trans_list_ptr) {
06985       t = *cur_trans_list_ptr--;
06986       SXBA_1_bit (char_set, t);
06987     }
06988 
06989 #if 0
06990     if (optim_kind == 0)
06991       max_class_value = 1; /* Les classes 0 et 1 sont reservees (pour y mettre des id eventuels) */
06992     else
06993 #endif /* 0 */
06994       max_class_value = 2; /* Les classes 0 et 1 sont reservees (pour y mettre des id eventuels)  et la classe 2 pour la partie propre */
06995 
06996     t = -1;
06997 
06998     while ((t = sxba_scan (char_set, t)) >= 0) {
06999       /* l'ordre lexicographique est pre'serve' sur les classes */
07000       char2class [t] = ++max_class_value;
07001     }
07002 
07003     sxfree (char_set);
07004   }
07005 
07006   /* On remplit sxdfa_comb_ptr */
07007   {
07008     SXINT k;
07009 
07010     k = sxlast_bit (max_class_value);
07011 
07012     base_shift = sxdfa_comb_ptr->base_shift = (SXUINT) k + 1 /* stop_mask */;
07013     stop_mask = sxdfa_comb_ptr->stop_mask = ((SXUINT) 1) << k;
07014     sxdfa_comb_ptr->class_mask = stop_mask-1;
07015   }
07016 
07017   sxdfa_comb_ptr->is_static = SXFALSE;
07018   sxdfa_comb_ptr->is_a_dag = sxdfa_ptr->is_a_dag ;
07019   sxdfa_comb_ptr->private.from_left_to_right = sxdfa_ptr->private.from_left_to_right ;
07020   sxdfa_comb_ptr->char2class = char2class;
07021   sxdfa_comb_ptr->base2stack = NULL;
07022   sxdfa_comb_ptr->char_stack_list = NULL;
07023   sxdfa_comb_ptr->char_stack_list_top = 0;
07024 
07025   comb = sxba_calloc (max_class_value+1);
07026   char_comb = sxba_calloc (256);
07027 
07028   size = sxdfa_ptr->max_arity*sxdfa_ptr->last_state + max_class_value + 1;
07029   comb_vector = sxba_calloc (size);
07030   base_comb_vector = 0;
07031   base_pos_set = sxba_calloc (size);
07032 
07033   if (is_generate_char_stack_list) {
07034     base2stack = (SXINT*) sxcalloc (size, sizeof (SXINT));
07035     char_stack_list_size = size * 6;
07036     char_stack_list = (unsigned char *) sxalloc (char_stack_list_size, sizeof (unsigned char));
07037     char_stack_list_top = 1;
07038   }
07039 
07040   max_base_pos = 0;
07041   state2base_pos = (SXINT *) sxalloc (sxdfa_ptr->last_state+1, sizeof (SXINT)), state2base_pos [0] = 0;
07042 
07043   if (optim_kind > 2)
07044     sxtrap (ME, "sxdfa2comb_vector (unknown optim_kind ; note that generation of char_stack_list for optim_kind 1 is not yet implemented)");
07045 
07046   switch (optim_kind) {
07047   case 0 :
07048   case 2 :
07049     /* Essai (tres) simple chaque etat est pris ds l'ordre et est implante sur des bases differentes */
07050     for (state = sxdfa_ptr->init_state; state <= sxdfa_ptr->last_state; state++) {
07051       if ((state % comb_vector_threshold) == 0) {
07052     /* Tous les threshold, on repart comme si comb_vector etait vide */
07053     base_comb_vector = (SXBA_INDEX_OR_ERROR) (SXBASIZE (comb_vector));
07054     base_comb_vector = sxba_1_rlscan (comb_vector, base_comb_vector);
07055       }
07056   
07057       state_ptr = sxdfa_ptr->states + state;
07058 
07059       bot = state_ptr [0];
07060       is_final_state = bot & 1;
07061 
07062       next_states_ptr = sxdfa_ptr->next_state_list + (bot>>1);
07063       top_next_states_ptr = sxdfa_ptr->next_state_list + (state_ptr [1]>>1);
07064       
07065       bot_trans = *next_states_ptr++;
07066 
07067       if (bot_trans < 0) {
07068     if (is_final_state) {
07069       /* state est final et il lui est associe' l'id -bot_trans */
07070       SXBA_1_bit (comb, 0); /* On reserve donc la classe 0 */
07071       bot_trans = *next_states_ptr++;
07072 
07073       if (bot_trans < 0) {
07074         /* -bot_trans est un id remonte' */
07075         SXBA_1_bit (comb, 1); /* On reserve donc la classe 1 */
07076         bot_trans = *next_states_ptr++;
07077       }
07078     }
07079     else {
07080       /* -bot_trans est un id remonte' */
07081       SXBA_1_bit (comb, 0); /* On reserve donc la classe 0 */
07082       bot_trans = *next_states_ptr++;
07083     }
07084       }
07085       else {
07086     if (is_final_state)
07087       /* state est final  */
07088       SXBA_1_bit (comb, 0); /* On reserve donc la classe 0 */
07089       }
07090 
07091       trans_list_ptr = sxdfa_ptr->trans_list + bot_trans;
07092 
07093       if (is_generate_char_stack_list)
07094     char_comb_cardinal = 0;
07095 
07096       while (next_states_ptr++ < top_next_states_ptr) {
07097     t = *trans_list_ptr++;
07098     class = (SXINT) char2class [t];
07099     SXBA_1_bit (comb, class);
07100 
07101     if (is_generate_char_stack_list) {
07102       if (SXBA_bit_is_reset_set (char_comb, t))
07103         char_comb_cardinal++;
07104     }
07105       }
07106 
07107       state2base_pos [state] = base_pos = install_a_comb (&comb_vector, comb, &base_pos_set);
07108       sxba_empty (comb);
07109 
07110       if (is_generate_char_stack_list && char_comb_cardinal) {
07111     if (char_stack_list_size < char_stack_list_top + char_comb_cardinal + 1)
07112       char_stack_list = (unsigned char*) sxrealloc (char_stack_list, char_stack_list_size *= 2, sizeof (unsigned char));
07113     
07114     t = -1;
07115 
07116     base2stack [base_pos] = char_stack_list_top;
07117     char_stack_list [char_stack_list_top++] = (unsigned char) char_comb_cardinal;
07118 
07119     while ((t = sxba_scan_reset (char_comb, t)) >= 0) {
07120       char_stack_list [char_stack_list_top++] = (unsigned char) t;
07121     }
07122       }
07123 
07124       if (base_pos > max_base_pos)
07125     max_base_pos = base_pos;
07126     }
07127 
07128     sxdfa_comb_ptr->max = max_base_pos+max_class_value;
07129     /* cas particulier si l'etat initial est aussi un etat final (la chaine vide est ds le dico) */
07130 
07131     sxdfa_comb_ptr->init_base = 0;
07132     
07133     sxdfa_comb_ptr->comb_vector = (SXUINT *) sxcalloc (sxdfa_comb_ptr->max+1, sizeof (SXUINT));
07134 
07135     if (is_generate_char_stack_list) {
07136       sxdfa_comb_ptr->base2stack = base2stack;
07137       sxdfa_comb_ptr->char_stack_list = char_stack_list;
07138       sxdfa_comb_ptr->char_stack_list_top = char_stack_list_top;
07139     }
07140 
07141 
07142     for (state = sxdfa_ptr->init_state; state <= sxdfa_ptr->last_state; state++) {
07143       state_ptr = sxdfa_ptr->states + state;
07144       base_pos = state2base_pos [state];
07145       comb_vector_ptr = sxdfa_comb_ptr->comb_vector+base_pos;
07146 
07147       bot = state_ptr [0];
07148       is_final_state = bot & 1;
07149 
07150       next_states_ptr = sxdfa_ptr->next_state_list + (bot>>1);
07151       top_next_states_ptr = sxdfa_ptr->next_state_list + (state_ptr [1]>>1);
07152       
07153       bot_trans = *next_states_ptr++;
07154 
07155       if (bot_trans < 0) {
07156     if (is_final_state) {
07157       /* state est final et il lui est associe' l'id -bot_trans */
07158 #if EBUG
07159       if (comb_vector_ptr [0] != 0)
07160         sxtrap (ME, "sxdfa2comb_vector");
07161 #endif /* EBUG */
07162 
07163       comb_vector_ptr [0] = ((-bot_trans) << base_shift) + stop_mask;
07164 
07165       bot_trans = *next_states_ptr++;
07166 
07167       if (bot_trans < 0) {
07168         /* -bot_trans est un id remonte' */
07169 #if EBUG
07170         if (comb_vector_ptr [1] != 0)
07171           sxtrap (ME, "sxdfa2comb_vector");
07172 #endif /* EBUG */
07173 
07174         comb_vector_ptr [1] = ((-bot_trans) << base_shift) + 1 /* classe reservee */;
07175         bot_trans = *next_states_ptr++;
07176       }
07177     }
07178     else {
07179       /* -bot_trans est un id remonte' */
07180 #if EBUG
07181       if (comb_vector_ptr [0] != 0)
07182         sxtrap (ME, "sxdfa2comb_vector");
07183 #endif /* EBUG */
07184 
07185       comb_vector_ptr [0] = ((-bot_trans) << base_shift) /* o classe reservee */;
07186       bot_trans = *next_states_ptr++;
07187     }
07188       }
07189       else {
07190     if (is_final_state)
07191       comb_vector_ptr [0] = (1 << base_shift) + stop_mask;
07192       }
07193 
07194       /* On implante les vraies transitions */
07195       trans_list_ptr = sxdfa_ptr->trans_list + bot_trans;
07196 
07197       while (next_states_ptr < top_next_states_ptr) {
07198     next_state = *next_states_ptr++;
07199     t = *trans_list_ptr++;
07200     class = (SXINT) char2class [t];
07201 
07202     if (next_state <= 0) {
07203       /* final */
07204       tooth = stop_mask;
07205 
07206       if (next_state < 0)
07207         tooth |= (-next_state) << base_shift;
07208     }
07209     else {
07210       tooth = state2base_pos [next_state] << base_shift;
07211 
07212 #if 0
07213       if (sxdfa_ptr->states [next_state] & 1)
07214         /* Next-state est final, on le dit aussi sur l'appelant */
07215         tooth |= stop_mask;
07216 #endif /*0 */
07217     }
07218 
07219 
07220 #if EBUG
07221     if (comb_vector_ptr [class] != 0)
07222       sxtrap (ME, "sxdfa2comb_vector");
07223 #endif /* EBUG */
07224 
07225     comb_vector_ptr [class] = tooth + class;
07226       }
07227     }
07228 
07229 #if EBUG
07230     {
07231       SXINT nb;
07232 
07233       nb = sxba_cardinal (comb_vector);
07234 
07235       printf ("// comb_vector : size = %ld, used = %ld (%ld%%), size (bytes) = %ld\n", sxdfa_comb_ptr->max, nb, (100*nb)/sxdfa_comb_ptr->max,
07236           sizeof (unsigned char)*(256) + sizeof (SXINT)*(sxdfa_comb_ptr->max+1));
07237     }
07238 #endif /* EBUG */
07239 
07240     break;
07241 
07242   case 1:
07243     /* Partage des transitions communes entre plusieurs etats */
07244     {
07245       SXINT             top, trans_id_nb, trans_id, pos, min_class_value, nb, x, common_base_pos, gain, gain_total, class_set_card;
07246       SXINT             *pos2trans_id, *trans_id2state_list_hd, *state2next_state_with_same_trans_id, *ptr, *ptr2, *state_stack, *state_nb_bag, *state_nb_bag2, *save_next_states_ptr, *common_class2next_state;
07247       SXINT             *save_trans_list_ptr;
07248       SXBA              start_pos_set, common_comb, *class2next_state_set, *common_class2next_state_set, class_set, next_state_set;
07249       struct class_attr {
07250     SXINT *state2nb;
07251       }                 *class2attr, *attr_ptr, *common_class2attr;
07252       SXBOOLEAN           now;
07253       struct {
07254     SXINT nb, next_state, class;
07255       } popular, second_popular, void_popular;
07256 
07257       /* Les classes 0,1 et 2 sont reservees */
07258       min_class_value = 3;
07259 
07260       /* On trie les etats en clusters.  Chaque etat d'un cluster a le meme transition id */
07261 
07262       /* On commence par marquer ou commence chaque trans_id */
07263       top = sxdfa_ptr->trans_list [0];
07264       start_pos_set = sxba_calloc (top+1);
07265 
07266       trans_id_nb = 0;
07267 
07268       for (state = sxdfa_ptr->init_state; state <= sxdfa_ptr->last_state; state++) {
07269     state_ptr = sxdfa_ptr->states + state;
07270 
07271     bot = state_ptr [0];
07272     is_final_state = bot & 1;
07273 
07274     next_states_ptr = sxdfa_ptr->next_state_list + (bot>>1);
07275       
07276     pos = *next_states_ptr++;
07277 
07278     if (pos < 0) {
07279       if (is_final_state) {
07280         pos = *next_states_ptr++;
07281 
07282         if (pos < 0) {
07283           pos = *next_states_ptr++;
07284         }
07285       }
07286       else {
07287         pos = *next_states_ptr++;
07288       }
07289     }
07290 
07291     if (SXBA_bit_is_reset_set (start_pos_set, pos))
07292       trans_id_nb++;
07293       }
07294 
07295       pos2trans_id = (SXINT *) sxalloc (top+1, sizeof (SXINT)), pos2trans_id [0] = 0;
07296 
07297       trans_id2state_list_hd = (SXINT *) sxcalloc (trans_id_nb+2, sizeof (SXINT)), trans_id2state_list_hd [0] = 0;
07298       state2next_state_with_same_trans_id = (SXINT *) sxalloc (sxdfa_ptr->last_state+1, sizeof (SXINT)), state2next_state_with_same_trans_id [0] = 0;
07299 
07300       state_stack = (SXINT *) sxalloc (sxdfa_ptr->last_state+1, sizeof (SXINT)), state_stack [0] = 0;
07301       common_comb = sxba_calloc (max_class_value+1);
07302       class2next_state_set = sxbm_calloc (max_class_value+1, sxdfa_ptr->last_state+1);
07303       common_class2next_state_set = sxbm_calloc (max_class_value+1, sxdfa_ptr->last_state+1);
07304       common_class2next_state = (SXINT *) sxalloc (max_class_value+1, sizeof (SXINT));
07305       class_set = sxba_calloc (max_class_value+1);
07306 
07307       pos = 0;
07308 
07309       for (trans_id = 1; trans_id <= trans_id_nb; trans_id++) {
07310     pos = sxba_scan (start_pos_set, pos);
07311     pos2trans_id [pos] = trans_id;
07312       }
07313 
07314       sxfree (start_pos_set);
07315 
07316       for (state = sxdfa_ptr->init_state; state <= sxdfa_ptr->last_state; state++) {
07317     state_ptr = sxdfa_ptr->states + state;
07318     bot = state_ptr [0];
07319     is_final_state = bot & 1;
07320     next_states_ptr = sxdfa_ptr->next_state_list + (bot>>1);
07321     pos = *next_states_ptr++;
07322 
07323     if (pos < 0) {
07324       if (is_final_state) {
07325         pos = *next_states_ptr++;
07326 
07327         if (pos < 0) {
07328           pos = *next_states_ptr++;
07329         }
07330       }
07331       else {
07332         pos = *next_states_ptr++;
07333       }
07334     }
07335 
07336     trans_id = pos2trans_id [pos];
07337     state2next_state_with_same_trans_id [state] = trans_id2state_list_hd [trans_id];
07338     trans_id2state_list_hd [trans_id] = state;
07339       }
07340 
07341       /* Ici pour chaque trans_id state = trans_id2state_list_hd [trans_id] et state2next_state_with_same_trans_id [state] contiennent
07342      la liste des state ayant meme trans_id */
07343       /* On implante chacun de ces clusters l'un apres l'autre */
07344       class2attr = (struct class_attr*) sxcalloc (max_class_value+1, sizeof (struct class_attr));
07345       common_class2attr = (struct class_attr*) sxcalloc (max_class_value+1, sizeof (struct class_attr));
07346       ptr = state_nb_bag = (SXINT*) sxcalloc (max_class_value*(sxdfa_ptr->last_state+1)+1, sizeof (SXINT));
07347       ptr2 = state_nb_bag2 = (SXINT*) sxcalloc (max_class_value*(sxdfa_ptr->last_state+1)+1, sizeof (SXINT));
07348 
07349       for (class = min_class_value; class <= max_class_value; class++) {
07350     class2attr [class].state2nb = ptr;
07351     common_class2attr [class].state2nb = ptr2;
07352     ptr += sxdfa_ptr->last_state+1;
07353     ptr2 += sxdfa_ptr->last_state+1;
07354       }
07355 
07356       common_comb = sxba_calloc (max_class_value+1);
07357 
07358       /* Attention, ds le cas 2, sxdfa_comb_ptr->comb_vector peut deborder */
07359       sxdfa_comb_ptr->comb_vector = (SXUINT *) sxcalloc (size+1, sizeof (SXUINT));
07360       gain_total = 0;
07361 
07362       for (trans_id = 1;  trans_id <= trans_id_nb; trans_id++) {
07363     sxba_empty (class_set), class_set_card = 0;
07364 
07365     for (state = trans_id2state_list_hd [trans_id]; state != 0; state = state2next_state_with_same_trans_id [state]) {
07366       state_ptr = sxdfa_ptr->states + state;
07367 
07368       PUSH (state_stack, state);
07369 
07370       bot = state_ptr [0];
07371       is_final_state = bot & 1;
07372 
07373       next_states_ptr = sxdfa_ptr->next_state_list + (bot>>1);
07374       top_next_states_ptr = sxdfa_ptr->next_state_list + (state_ptr [1]>>1);
07375       
07376       bot_trans = *next_states_ptr++;
07377 
07378       if (bot_trans < 0) {
07379         if (is_final_state) {
07380           bot_trans = *next_states_ptr++;
07381 
07382           if (bot_trans < 0) {
07383         bot_trans = *next_states_ptr++;
07384           }
07385         }
07386         else {
07387           bot_trans = *next_states_ptr++;
07388         }
07389       }
07390 
07391       trans_list_ptr = sxdfa_ptr->trans_list + bot_trans;
07392 
07393       while (next_states_ptr < top_next_states_ptr) {
07394         next_state = *next_states_ptr++;
07395         t = *trans_list_ptr++;
07396         class = (SXINT) char2class [t];
07397 
07398         if (SXBA_bit_is_reset_set (class_set, class))
07399           class_set_card++;
07400 
07401         if (next_state >= 0) {
07402           attr_ptr = class2attr+class;
07403           nb = ++(attr_ptr->state2nb [next_state]);
07404 
07405           if (nb == 1)
07406         SXBA_1_bit (class2next_state_set [class], next_state);
07407         }
07408       }
07409     }
07410 
07411     void_popular.nb = void_popular.next_state = void_popular.class = 0;
07412 
07413     for (;;) {
07414       top = TOP (state_stack);
07415 
07416       if (top == 0)
07417         break;
07418 
07419       TOP (state_stack) = 0;
07420 
07421       if (top > 1 && class_set_card > 1) {
07422         /* On calcule les max pour chaque class */
07423         /* ... et le max des max ds popular */
07424         popular = void_popular;
07425         class = 0;
07426 
07427         while ((class = sxba_scan (class_set, class)) > 0) {
07428           attr_ptr = class2attr+class;
07429           next_state_set = class2next_state_set [class];
07430 
07431           next_state = -1;
07432 
07433           while ((next_state = sxba_scan (next_state_set, next_state)) >= 0) {
07434         nb = attr_ptr->state2nb [next_state];
07435 
07436         if (nb > popular.nb) {
07437           popular.nb = nb;
07438           popular.next_state = next_state;
07439           popular.class = class;
07440         }
07441           }
07442         }
07443 
07444         if (popular.nb > 1) {
07445           second_popular.nb = 0;
07446 
07447           class2attr [popular.class].state2nb [popular.next_state] = 0;
07448           SXBA_0_bit (class2next_state_set [popular.class], popular.next_state);
07449 
07450           /* On selectionne les etats qui ont une transition sur popular */
07451           /* ... et parmi ceux-la on fabrique second_popular */
07452           for (x = 1; x <= top; x++) {
07453         /* On installe les partie propres de chaque state */
07454         state = state_stack [x];
07455         state_ptr = sxdfa_ptr->states + state;
07456 
07457         bot = state_ptr [0];
07458         is_final_state = bot & 1;
07459 
07460         next_states_ptr = sxdfa_ptr->next_state_list + (bot>>1);
07461         top_next_states_ptr = sxdfa_ptr->next_state_list + (state_ptr [1]>>1);
07462       
07463         bot_trans = *next_states_ptr++;
07464 
07465         if (bot_trans < 0) {
07466           if (is_final_state) {
07467             bot_trans = *next_states_ptr++;
07468 
07469             if (bot_trans < 0) {
07470               bot_trans = *next_states_ptr++;
07471             }
07472           }
07473           else {
07474             bot_trans = *next_states_ptr++;
07475           }
07476         }
07477 
07478         save_trans_list_ptr = trans_list_ptr = sxdfa_ptr->trans_list + bot_trans;
07479         save_next_states_ptr = next_states_ptr;
07480 
07481         while (next_states_ptr < top_next_states_ptr) {
07482           next_state = *next_states_ptr++;
07483           t = *trans_list_ptr++;
07484           class = (SXINT) char2class [t];
07485 
07486           if (class == popular.class && next_state == popular.next_state) {
07487             nb = ++common_class2attr [class].state2nb [next_state];
07488 
07489             if (nb == 1)
07490               SXBA_1_bit (common_class2next_state_set [class], next_state);
07491 
07492             while (save_next_states_ptr < top_next_states_ptr) {
07493               next_state = *save_next_states_ptr++;
07494               t = *save_trans_list_ptr++;
07495               class = (SXINT) char2class [t];
07496 
07497               if (class != popular.class && next_state >= 0) {
07498             nb = ++common_class2attr [class].state2nb [next_state];
07499 
07500             if (nb == 1)
07501               SXBA_1_bit (common_class2next_state_set [class], next_state);
07502               
07503             if (nb > second_popular.nb) {
07504               second_popular.nb = nb;
07505               second_popular.next_state = next_state;
07506               second_popular.class = class;
07507             }
07508               }
07509             }
07510 
07511             break;
07512           }
07513         }
07514           }
07515 
07516           /* Le "gain" d'une utilisation de popular.next_state est -1 */
07517           /* Le "gain" d'une utilisation de second_popular.next_state est second_popular.nb-1 */
07518           if (second_popular.nb-2 > 0) {
07519         /* On fait un common_comb */
07520         sxba_empty (common_comb);
07521         class = 0;
07522         gain = 0;
07523 
07524         while ((class = sxba_scan (class_set, class)) > 0) {
07525           attr_ptr = common_class2attr+class;
07526           next_state_set = common_class2next_state_set [class];
07527 
07528           next_state = -1;
07529 
07530           while ((next_state = sxba_scan_reset (next_state_set, next_state)) >= 0) {
07531             nb = attr_ptr->state2nb [next_state];
07532 
07533             if (nb > 1) {
07534               SXBA_1_bit (common_comb, class);
07535               common_class2next_state [class] = next_state;
07536               gain += nb-1;
07537             }
07538 
07539             attr_ptr->state2nb [next_state] = 0;
07540           }
07541         }
07542 
07543         gain -= popular.nb;
07544 
07545 #if EBUG
07546         if (gain <= 0)
07547           sxtrap (ME, "sxdfa2comb_vector");
07548 #endif /* EBUG */
07549 
07550         gain_total += gain;
07551 
07552         /* On installe common_comb */
07553         common_base_pos = install_a_comb (&comb_vector, common_comb, &base_pos_set);
07554 
07555         if (common_base_pos > max_base_pos) {
07556           max_base_pos = common_base_pos;
07557       
07558           if (max_base_pos+max_class_value > size) {
07559             sxdfa_comb_ptr->comb_vector = (SXUINT *) sxrecalloc (sxdfa_comb_ptr->comb_vector, size+1, 2*size+1, sizeof (SXUINT));
07560             size *= 2;
07561           }
07562         }
07563         
07564         comb_vector_ptr = sxdfa_comb_ptr->comb_vector+common_base_pos;
07565         class = 0;
07566 
07567         while ((class = sxba_scan (common_comb, class)) > 0) {
07568 #if EBUG
07569           if (comb_vector_ptr [class] != 0)
07570             sxtrap (ME, "sxdfa2comb_vector");
07571 #endif /* EBUG */
07572 
07573           next_state = common_class2next_state [class];
07574 
07575           if (next_state < 0) {
07576             /* Normalement on ne passe jamais par la car un id (negatif) ne peut jamais etre le + populaire */
07577             /* final */
07578             tooth = ((-next_state) << base_shift) + stop_mask;
07579           }
07580           else {
07581             if (next_state == 0) {
07582               /* final */
07583               tooth = stop_mask;
07584             }
07585             else {
07586               tooth = next_state << base_shift;
07587             }
07588           }
07589 
07590           comb_vector_ptr [class] = tooth + class;
07591         }
07592           }
07593           else {
07594         common_base_pos = -1;
07595         /* Tout le (reste) du cluster est implante' ds propre */
07596         /* Il faut raze' les structures precedentes */
07597         class = 0;
07598 
07599         while ((class = sxba_scan (class_set, class)) > 0) {
07600           attr_ptr = common_class2attr+class;
07601           next_state_set = common_class2next_state_set [class];
07602 
07603           next_state = -1;
07604 
07605           while ((next_state = sxba_scan_reset (next_state_set, next_state)) >= 0) {
07606             attr_ptr->state2nb [next_state] = 0;
07607           }
07608         }
07609           }
07610         }
07611         else
07612           common_base_pos = -1;
07613       }
07614       else
07615         common_base_pos = -1;
07616       
07617       for (x = 1; x <= top; x++) {
07618         /* On installe les partie propres de chaque state */
07619         state = state_stack [x];
07620         state_ptr = sxdfa_ptr->states + state;
07621 
07622         bot = state_ptr [0];
07623         is_final_state = bot & 1;
07624 
07625         next_states_ptr = sxdfa_ptr->next_state_list + (bot>>1);
07626         top_next_states_ptr = sxdfa_ptr->next_state_list + (state_ptr [1]>>1);
07627       
07628         bot_trans = *next_states_ptr++;
07629 
07630         if (bot_trans < 0) {
07631           if (is_final_state) {
07632         SXBA_1_bit (comb, 0); /* On reserve donc la classe 0 */
07633         bot_trans = *next_states_ptr++;
07634 
07635         if (bot_trans < 0) {
07636           SXBA_1_bit (comb, 1); /* On reserve donc la classe 1 */
07637           bot_trans = *next_states_ptr++;
07638         }
07639           }
07640           else {
07641         SXBA_1_bit (comb, 0); /* On reserve donc la classe 0 */
07642         bot_trans = *next_states_ptr++;
07643           }
07644         }
07645         else {
07646           if (is_final_state)
07647         /* state est final  */
07648         SXBA_1_bit (comb, 0); /* On reserve donc la classe 0 */
07649         }
07650 
07651         trans_list_ptr = sxdfa_ptr->trans_list + bot_trans;
07652         now = common_base_pos == -1;
07653 
07654         while (next_states_ptr < top_next_states_ptr) {
07655           next_state = *next_states_ptr++;
07656           t = *trans_list_ptr++;
07657           class = (SXINT) char2class [t];
07658 
07659           if (common_base_pos == -1) {
07660         /* Pas de partie commune */
07661         SXBA_1_bit (comb, class);
07662           }
07663           else {
07664         if (next_state >= 0) {
07665           if (SXBA_bit_is_set (common_comb, class) && common_class2next_state [class] == next_state)
07666             /* Ds la partie commune */
07667             now = SXTRUE;
07668           else {
07669             /* en propre */
07670             SXBA_1_bit (comb, class);
07671           }
07672         }
07673         else
07674           /* Obligatoirement en propre */
07675           SXBA_1_bit (comb, class);
07676           }
07677         }
07678 
07679         if (now) {
07680           /* state doit etre implante' maintenant, il partage des parties communes avec common_comb */
07681           /* On doit aussi le faire disparaitre de class2attr */
07682           if (common_base_pos >= 0)
07683         SXBA_1_bit (comb, 2); /* ref vers la partie commune */
07684 
07685           base_pos = state2base_pos [state] = install_a_comb (&comb_vector, comb, &base_pos_set);
07686 
07687           if (state == sxdfa_ptr->init_state)
07688         /* La reconnaissance va commencer la */
07689         sxdfa_comb_ptr->init_base = base_pos << base_shift;
07690 
07691           if (base_pos > max_base_pos) {
07692         max_base_pos = base_pos;
07693       
07694         if (max_base_pos+max_class_value > size) {
07695           sxdfa_comb_ptr->comb_vector = (SXUINT *) sxrecalloc (sxdfa_comb_ptr->comb_vector, size+1, 2*size+1, sizeof (SXUINT));
07696           size *= 2;
07697         }
07698           }
07699 
07700           /* On remplit effectivement sxdfa_comb_ptr->comb_vector */
07701 
07702           comb_vector_ptr = sxdfa_comb_ptr->comb_vector+base_pos;
07703           next_states_ptr = sxdfa_ptr->next_state_list + (bot>>1);
07704 
07705           bot_trans = *next_states_ptr++;
07706 
07707           if (bot_trans < 0) {
07708         if (is_final_state) {
07709           /* state est final et il lui est associe' l'id -bot_trans */
07710 #if EBUG
07711           if (comb_vector_ptr [0] != 0)
07712             sxtrap (ME, "sxdfa2comb_vector");
07713 #endif /* EBUG */
07714 
07715           comb_vector_ptr [0] = ((-bot_trans) << base_shift) + stop_mask;
07716 
07717           bot_trans = *next_states_ptr++;
07718 
07719           if (bot_trans < 0) {
07720             /* -bot_trans est un id remonte' */
07721 #if EBUG
07722             if (comb_vector_ptr [1] != 0)
07723               sxtrap (ME, "sxdfa2comb_vector");
07724 #endif /* EBUG */
07725 
07726             comb_vector_ptr [1] = ((-bot_trans) << base_shift) + 1 /* classe reservee */;
07727             bot_trans = *next_states_ptr++;
07728           }
07729         }
07730         else {
07731           /* -bot_trans est un id remonte' */
07732 #if EBUG
07733           if (comb_vector_ptr [0] != 0)
07734             sxtrap (ME, "sxdfa2comb_vector");
07735 #endif /* EBUG */
07736 
07737           comb_vector_ptr [0] = ((-bot_trans) << base_shift) /* o classe reservee */;
07738           bot_trans = *next_states_ptr++;
07739         }
07740           }
07741           else {
07742         if (is_final_state)
07743           comb_vector_ptr [0] = (1 << base_shift) + stop_mask;
07744           }
07745 
07746           if (common_base_pos >= 0)
07747         comb_vector_ptr [2] = (common_base_pos << base_shift) + 2 /* 2 classe reservee pour la partie commune */;
07748 
07749           /* On implante les vraies transitions */
07750           trans_list_ptr = sxdfa_ptr->trans_list + bot_trans;
07751 
07752           while (next_states_ptr < top_next_states_ptr) {
07753         next_state = *next_states_ptr++;
07754         t = *trans_list_ptr++;
07755         class = (SXINT) char2class [t];
07756 
07757         if (next_state < 0) {
07758           /* final */
07759           tooth = ((-next_state) << base_shift) + stop_mask;
07760         }
07761         else {
07762           if (common_base_pos >= 0 /* Y'a une partie commune */
07763               && SXBA_bit_is_set (common_comb, class) /* et class est ds cette partie commune */
07764               && common_class2next_state [class] == next_state /* et transition vers le bon etat */)
07765             /* Implante' ds la partie commune => disponible pour qcqu'un d'autre */
07766             tooth = 0;
07767           else {
07768             /* Implante' ds la parie propre */
07769             if (next_state == 0)
07770               /* etat final */
07771               tooth = stop_mask;
07772             else
07773               tooth = next_state << base_shift; /* state2base_pos n'est pas complet, on laisse next_state et on fera une derniere passe */
07774           }
07775 
07776           nb = --(class2attr [class].state2nb [next_state]);
07777 
07778           if (nb == 0)
07779             SXBA_0_bit (class2next_state_set [class], next_state);
07780         }
07781 
07782 #if EBUG
07783         if (tooth && comb_vector_ptr [class] != 0)
07784           sxtrap (ME, "sxdfa2comb_vector");
07785 #endif /* EBUG */
07786 
07787         if (tooth)
07788           comb_vector_ptr [class] = tooth + class;
07789           }
07790         }
07791         else {
07792           /* On est sur un etat qui n'a rien a voir avec le common_comb courant, on le reserve donc pour le passage suivant */
07793           PUSH (state_stack, state);
07794         }
07795         
07796         sxba_empty (comb);
07797       }
07798     }
07799       }
07800 
07801       sxdfa_comb_ptr->max = max_base_pos+max_class_value;
07802 
07803       /* Derniere passe pour mettre a jour les "next_state" */
07804       for (pos = sxdfa_comb_ptr->max; pos >= 0; pos--) {
07805     comb_vector_ptr = sxdfa_comb_ptr->comb_vector + (SXUINT) pos;
07806     tooth = *comb_vector_ptr;
07807 
07808     if ((tooth & stop_mask) == 0 && (class = (SXINT) (tooth & sxdfa_comb_ptr->class_mask)) >= min_class_value /* vraie classe */) {
07809       base_pos = state2base_pos [tooth >>= base_shift];
07810       *comb_vector_ptr = (base_pos << base_shift) + (SXUINT) class;
07811     }
07812       }
07813 
07814 
07815 #if EBUG
07816       nb = sxba_cardinal (comb_vector);
07817 
07818       printf ("// comb_vector : size = %ld, used = %ld (%ld%%), size (bytes) = %ld, gain_total (bytes) = %ld\n", sxdfa_comb_ptr->max, nb, (100*nb)/sxdfa_comb_ptr->max,
07819           sizeof (struct sxdfa_comb)
07820           + sizeof (unsigned char) * 256
07821           + sizeof (SXINT) * (sxdfa_comb_ptr->max+1),
07822           gain_total*sizeof (SXINT));
07823 #endif /* EBUG */
07824 
07825       sxfree (pos2trans_id);
07826       sxfree (trans_id2state_list_hd);
07827       sxfree (state2next_state_with_same_trans_id);
07828       sxfree (state_stack);
07829       sxfree (common_comb);
07830       sxbm_free (class2next_state_set);
07831       sxbm_free (common_class2next_state_set);
07832       sxfree (common_class2next_state);
07833       sxfree (class_set);
07834       sxfree (class2attr);
07835       sxfree (common_class2attr);
07836       sxfree (state_nb_bag);
07837       sxfree (state_nb_bag2);
07838     }
07839 
07840     break;
07841 
07842   default:
07843     sxtrap (ME, "sxdfa2comb_vector");
07844     break;
07845   }
07846 
07847   sxfree (comb_vector);
07848   sxfree (comb);
07849   sxfree (state2base_pos);
07850 }
07851 
07852 
07853 void
07854 sxdfa_comb2c (struct sxdfa_comb *sxdfa_comb_ptr, FILE *file, char *dico_name, SXBOOLEAN is_static)
07855 {
07856   unsigned char class;
07857   SXUINT i;
07858 
07859   fprintf (file, "\nstatic SXUINT %s_comb_vector [%ld] = {", dico_name == NULL ? "" : dico_name, (long)sxdfa_comb_ptr->max+1);
07860 
07861   for (i = 0; i <= sxdfa_comb_ptr->max; i++) {
07862     if ((i % 10) == 0)
07863       fprintf (file, "\n/* %ld */ ", i);
07864 
07865     fprintf (file, "%ld, ", (long)sxdfa_comb_ptr->comb_vector [i]);
07866   }
07867 
07868   fprintf (file, "\n};\nstatic unsigned char %s_char2class [256] = {", dico_name == NULL ? "" : dico_name);
07869 
07870   for (i = 0; i <= 255; i++) {
07871     if ((i % 10) == 0)
07872       fprintf (file, "\n/* %ld */ ", i);
07873 
07874     class = sxdfa_comb_ptr->char2class [i];
07875     fputs ("\'", file);
07876 
07877     if (class == '\'')
07878       fputs ("\\'", file);
07879     else
07880       fprintf (file, "%s", SXCHAR_TO_STRING (class));
07881 
07882     fputs ("\', ", file);
07883   }
07884 
07885   fputs ("\n};\n", file);
07886 
07887   if (sxdfa_comb_ptr->base2stack) {
07888     fprintf (file, "\nstatic SXINT %s_base2stack [%ld] = {", dico_name == NULL ? "" : dico_name, (long)sxdfa_comb_ptr->max+1);
07889     
07890     for (i = 0; i <= sxdfa_comb_ptr->max; i++) {
07891       if ((i % 10) == 0)
07892     fprintf (file, "\n/* %ld */ ", i);
07893       
07894       fprintf (file, "%ld, ", (long)sxdfa_comb_ptr->base2stack [i]);
07895     }
07896     
07897     fprintf (file, "\n};\nstatic unsigned char %s_char_stack_list [%ld] = \"\\000\\\n", dico_name == NULL ? "" : dico_name, (long)sxdfa_comb_ptr->char_stack_list_top + 1);
07898     
07899     {
07900       SXINT sub_stack_remaining_height = 0;
07901       char c;
07902       
07903       for (i = 1; i < (SXUINT) sxdfa_comb_ptr->char_stack_list_top; i++) {
07904     if (sub_stack_remaining_height) {
07905       sub_stack_remaining_height--;
07906       c = (char) (sxdfa_comb_ptr->char_stack_list [i]);
07907       fprintf (file, "%s", SXCHAR_TO_STRING(c));
07908     } else {     
07909       //      if (i > 1)
07910       //fputs ("\"", file);
07911       
07912       sub_stack_remaining_height = (SXINT) (sxdfa_comb_ptr->char_stack_list [i]);
07913       //      fprintf (file, "\n/* %ld, %ld */ ", i, sub_stack_remaining_height);
07914       fputs ("\\\n", file);
07915 
07916       c = (char) sub_stack_remaining_height;
07917       //fprintf (file, "\"%s", SXCHAR_TO_STRING(c));
07918       fprintf (file, "%s", SXCHAR_TO_STRING(c));
07919     }
07920       }
07921       fputs ("\";\n", file);
07922     }
07923   }
07924 
07925   fprintf (file, "\n%sstruct sxdfa_comb %s = {\n", is_static ? "static " : "", dico_name == NULL ? "sxdfa_comb_dico_hd" : dico_name);
07926   fprintf (file, "%ld /* max */, %ld /* init_base */, %ld /* class_mask */, %ld /* stop_mask */, %ld /* base_shift */,\n",
07927       (long)sxdfa_comb_ptr->max, (long)sxdfa_comb_ptr->init_base, (long)sxdfa_comb_ptr->class_mask, (long)sxdfa_comb_ptr->stop_mask, (long)sxdfa_comb_ptr->base_shift);
07928         
07929   fprintf (file, "%s_char2class, %s_comb_vector,\n", dico_name == NULL ? "" : dico_name, dico_name == NULL ? "" : dico_name);
07930   fprintf (file, "1 /* is_static */, %i /* is_a_dag */,\n", (int)sxdfa_comb_ptr->is_a_dag);
07931   if (sxdfa_comb_ptr->base2stack)
07932     fprintf (file, "%s_base2stack /* base2stack */,\n %s_char_stack_list /* char_stack_list */, %ld,\n", dico_name, dico_name, char_stack_list_top);
07933   else
07934     fputs ("NULL /* base2stack */, NULL /* char_stack_list */, 0,\n", file);
07935   fprintf (file, "\"%s\" /* name */, 0,\n", dico_name);
07936   fprintf (file, "{%i /* from_left_to_right */,}\n};\n", (int)sxdfa_comb_ptr->private.from_left_to_right);
07937 }
07938 
07939 
07940 SXINT
07941 sxdfa_comb_seek_a_string (struct sxdfa_comb *sxdfa_comb_ptr, char *kw, SXINT *kwl)
07942 {
07943   sxdfa_comb_ptr->private.ptr.char_ptr = (sxdfa_comb_ptr->private.from_left_to_right) ? kw : kw+*kwl-1;
07944 
07945   return sxdfa_comb_seek (sxdfa_comb_ptr, string_get_next_symb, kwl);
07946 }
07947 
07948 
07949 
07950 SXINT
07951 sxdfa_comb_seek_a_word (struct sxdfa_comb *sxdfa_comb_ptr, SXINT *input_stack)
07952 {
07953   sxdfa_comb_ptr->private.ptr.SXINT_ptr = (sxdfa_comb_ptr->private.from_left_to_right) ? input_stack + 1 : input_stack + *input_stack;
07954 
07955   return sxdfa_comb_seek (sxdfa_comb_ptr, word_get_next_symb, input_stack);
07956 }
07957 
07958 
07959 SXINT
07960 sxdfa_comb_seek (struct sxdfa_comb *sxdfa_comb_ptr, SXUINT (*get_next_symb) (struct sxdfa_private *), SXINT *input_lgth)
07961 {
07962   SXUINT        base, tooth = sxdfa_comb_ptr->init_base;
07963   SXUINT        base_shift = sxdfa_comb_ptr->base_shift;
07964   SXUINT        class_mask = sxdfa_comb_ptr->class_mask, stop_mask = sxdfa_comb_ptr->stop_mask;
07965   SXUINT        *comb_vector = sxdfa_comb_ptr->comb_vector, *comb_vector_ptr;
07966   unsigned char class, *char2class = sxdfa_comb_ptr->char2class;
07967   SXINT     lgth = *input_lgth;
07968   SXUINT        last_final_id, final_id, final_lgth;
07969 
07970   if (/* tooth == 0 || modif du 07/12/07 (pour nelle version) */ lgth < 0)
07971     return 0;
07972 
07973   /* base_shift = sxdfa_comb_ptr->base_shift; deja fait !! */
07974 
07975   base = tooth >> base_shift;
07976 
07977   if (sxdfa_comb_ptr->max == 0)
07978     /* dico vide ne specifie que la chaine vide */
07979     return lgth == 0 ? base : 0;
07980 
07981   last_final_id = final_id = final_lgth = 0;
07982 
07983   for (;;) {
07984     /* On est sur une base */
07985     comb_vector_ptr = comb_vector + base;
07986     tooth = *comb_vector_ptr;
07987 
07988     if (tooth /* Base non vide... */ 
07989     && (tooth & class_mask) == 0 /* ... et qui n'est pas une dent appartenant à une autre base :
07990                      elle contient donc des infos (id déjà certain par
07991                      anticipation et/ou le fait que c'est un état final) */) {
07992       if (tooth & stop_mask) { /* Si on a atteint un état final (mais puisque c'est une base, il y a
07993                   des transitions qui en partent). Le préfixe courant est un mot du
07994                   dico ... */
07995     tooth >>= base_shift;
07996     /* ... dont l'id est ce tooth shifté. En effet, on est sur une base (des transitions en
07997        partent) qui est aussi un état final: on n'a donc pas pu connaître l'id par anticipation,
07998        et ce tooth shifté est bien l'id */
07999     if (lgth == 0) /* c'est donc bien ce mot qu'on avait en entrée */
08000       return tooth;
08001 
08002     /* Ici, le mot à reconnaître n'a le mot d'id tooth que comme prefixe strict */
08003     /* On note ce préfixe au cas où */
08004     final_id = tooth;
08005     final_lgth = lgth;
08006 
08007     /* Si d'ici il ne sort qu'une seule transition et qu'elle ne mène (directement ou non) qu'à
08008        un seul mot du dico alors on a l'id de ce mot. Ces infos sont dans... */
08009     tooth = comb_vector_ptr [1];
08010     /* ... de la façon suivante: si : */
08011     if ((tooth & class_mask) == 1) {
08012       /* alors on est bien dans ce cas où il n'y a plus qu'un mot possible selon le dico, et il
08013          a alors pour id: */
08014       last_final_id = tooth >> base_shift;
08015     }
08016       }
08017       else { /* On n'est pas sur un état final */
08018     if (lgth == 0) { /* si on a déjà fini le mot d'entrée, c'est donc un prefixe strict d'au
08019               moins un mot du dico, et en particulier du mot d'id last_final_id s'il est
08020               positionné */
08021       break;
08022     }
08023     /* tooth >> base_shift est l'id du seul mot que l'on peut atteindre en poursuivant d'ici par
08024        des transitions du dico. Or on est sûr qu'il est non nul, puisque tooth est non nul et
08025        que tooth & class_mask est nul */
08026     last_final_id = tooth >> base_shift;
08027       }
08028     }
08029     else {
08030       /* Base vide: la base tooth ne contient aucune info sur la transition courante car elle n'a
08031      rien de particulier (attention, tooth a du coup de bonnes chances d'être une dent
08032      appartenant à une autre base). On poursuit sagement le parcours... */
08033       if (lgth == 0) {
08034     /* ...sauf si le mot est fini: le mot en entree est alors un prefixe strict de mots du dico
08035      (ou d'un mot unique si last_final_id > 0, qui est alors son id) */
08036     break;
08037       }
08038     }
08039 
08040     /* on va donc avancer le long de la prochaine transition, qui se fait sur le prochain caractère
08041        de l'entrée. Ce caractère donne la classe à suivre dans le dico, d'où la transition si elle
08042        existe */
08043 
08044     if ((class = char2class [(*get_next_symb) (&(sxdfa_comb_ptr->private))]) == 0)
08045        /* Le caractere courant est invalide */ 
08046       break;
08047 
08048     tooth = comb_vector_ptr [class];
08049 
08050     if ((tooth & class_mask) != class) { /* on est tombé sur un endroit qui n'appartient pas à notre
08051       base : la transition recherchée n'existe pas. On fait break (sauf dans le cas -comb 1, où on
08052       fait des trucs) */
08053       /* On regarde s'il existe une "partie commune" a l'etat courant (pour -comb 1)*/
08054       tooth = comb_vector_ptr [2];
08055 
08056       if ((tooth & class_mask) != 2)
08057     /* ... non (pas -comb 1)*/
08058     break;
08059 
08060       /* ... oui, partie commune (-comb 1)*/
08061       /* On y va */
08062       comb_vector_ptr = comb_vector + (tooth >> base_shift);
08063       /* Ds la partie commune, on ne peut trouver que des "vraies" transitions */
08064       tooth = comb_vector_ptr [class];
08065     
08066       if ((tooth & class_mask) != class)
08067     /* echec ds la partie commune */
08068     break;
08069     }
08070 
08071     /* La transition est valide: depuis base, le caractère trouvé sur l'entrée a bien une
08072        transition, qui mène au nouveau tooth */
08073 
08074     lgth = --*input_lgth; /* transition OK */
08075 
08076     if (tooth & stop_mask) {
08077       /* Si on atterrit sur un état final qui n'est pas une base: c'est fini */
08078       if ((tooth >>= base_shift) == 0)
08079     tooth = (last_final_id) ? last_final_id /* id connu */ : 1 /* id inconnu, mais succès (il
08080                                       n'y a pas d'id dans le dico,
08081                                       c'est tout ;) ) */;
08082 
08083       /* On rend tooth dans tous les cas. Si *input_lgth est nul, c'est qu'on a gagné. S'il n'est
08084      pas nul, c'est qu'on a atteint un etat final du dico sans epuiser le mot en entree Le mot
08085      tooth du dico est donc un prefixe strict du mot en entree. C'est donc à l'utilisateur de
08086      faire la différence. */
08087       return tooth;
08088     }
08089 
08090     /* On doit continuer le parcours. tooth est forcément une base, puisque (1) on l'a atteint et
08091        (2) stop_mask est faux */
08092     base = tooth >> base_shift;
08093   }
08094 
08095   /* Echec, mais il y a (peut etre) un mot du dico qui est est un prefixe strict de l'entree
08096      on choisit de retourner ce mot */
08097   *input_lgth = final_lgth;
08098   return final_id;
08099 }
08100 
08101 void
08102 sxdfa_comb_free (struct sxdfa_comb *sxdfa_comb_ptr)
08103 {
08104   if (!sxdfa_comb_ptr->is_static) {
08105     if (sxdfa_comb_ptr->char2class) sxfree (sxdfa_comb_ptr->char2class), sxdfa_comb_ptr->char2class = NULL;
08106     if (sxdfa_comb_ptr->comb_vector) sxfree (sxdfa_comb_ptr->comb_vector), sxdfa_comb_ptr->comb_vector = NULL;
08107     if (sxdfa_comb_ptr->base2stack) sxfree (sxdfa_comb_ptr->base2stack), sxdfa_comb_ptr->base2stack = NULL;
08108     if (sxdfa_comb_ptr->char_stack_list) sxfree (sxdfa_comb_ptr->char_stack_list), sxdfa_comb_ptr->char_stack_list = NULL;
08109   }
08110 }
08111 
08112 /* ***************************************** SXDFA_PACKED ************************************************ */
08113 extern void
08114 sxdfa2sxdfa_packed (struct sxdfa_struct *sxdfa_ptr, struct sxdfa_packed_struct *sxdfa_packed_ptr, char *name, FILE *stats)
08115 {
08116 
08117   SXUINT k, base_shift, stop_mask, id_mask, top, t, trans_nb;
08118   SXUINT *delta_ptr;
08119 
08120   SXINT  state, next_state, bot_trans, bot, is_final;
08121   SXINT  *state_ptr, *next_states_ptr, *top_next_state_ptr, *trans_list_ptr;
08122 
08123 
08124   k = sxlast_bit (sxdfa_ptr->max_t_val);
08125   base_shift = k + 1 /* stop_mask */ + 1 /* id_mask */;
08126   top = sxdfa_ptr->next_state_list [0];
08127 
08128   if (((top<<base_shift)>>base_shift) != top) {
08129     /* oflw */
08130     /* On change de mode de representation, A FAIRE */
08131     /* Pour l'instant */
08132     sxtrap (ME, "sxdfa2sxdfa_packed");
08133   }
08134 
08135   /* Ici tout tient ds un SXUINT  [id || next] [stop] [taille || t] */
08136   sxdfa_packed_ptr->base_shift = base_shift;
08137   sxdfa_packed_ptr->stop_mask = stop_mask = ((SXUINT) 1) << k;
08138   sxdfa_packed_ptr->id_mask = id_mask = ((SXUINT) 1) << (k+1);
08139   sxdfa_packed_ptr->t_mask = stop_mask-1;
08140 
08141   sxdfa_packed_ptr->init_state = sxdfa_ptr->init_state;
08142   sxdfa_packed_ptr->last_state = sxdfa_ptr->last_state;
08143   sxdfa_packed_ptr->number_of_out_trans = sxdfa_ptr->number_of_out_trans;
08144   sxdfa_packed_ptr->final_state_nb = sxdfa_ptr->final_state_nb;
08145   sxdfa_packed_ptr->max_path_lgth = sxdfa_ptr->max_path_lgth;
08146   sxdfa_packed_ptr->max_arity = sxdfa_ptr->max_arity;
08147   sxdfa_packed_ptr->max_t_val = sxdfa_ptr->max_t_val;
08148   sxdfa_packed_ptr->name = name;
08149   sxdfa_packed_ptr->stats = stats;
08150 
08151   sxdfa_packed_ptr->is_static = SXFALSE;
08152   sxdfa_packed_ptr->is_a_dag = sxdfa_ptr->is_a_dag;
08153   sxdfa_packed_ptr->private.from_left_to_right = sxdfa_ptr->private.from_left_to_right;
08154 
08155   sxdfa_packed_ptr->delta = (SXUINT*) sxalloc (top+1, sizeof (SXINT));
08156 
08157   delta_ptr = sxdfa_packed_ptr->delta;
08158 
08159   for (state = sxdfa_ptr->init_state; state <= sxdfa_ptr->last_state; state++) {
08160     state_ptr = sxdfa_ptr->states + state;
08161     bot = state_ptr [0];
08162 
08163     is_final = bot & 1;
08164     bot >>= 1;
08165   
08166     next_states_ptr = sxdfa_ptr->next_state_list + bot;
08167     bot_trans = *next_states_ptr++;
08168     top_next_state_ptr = sxdfa_ptr->next_state_list + (state_ptr [1]>>1);
08169 
08170     if (bot_trans < 0) {
08171       if (is_final) {
08172     /* L'etat state est final et -bot_trans est l'identifiant associe' ... */
08173     /* ... mais lgth > 0, on n'est donc pas interesse' par cette transition */
08174     /* On note le +long prefixe du mot en entree reconnu */
08175     *++delta_ptr = ((-bot_trans)<<base_shift) + id_mask + stop_mask;
08176 
08177     bot_trans = *next_states_ptr++;
08178 
08179     if (bot_trans < 0) {
08180       /* ici -bot_trans est l'identifiant associe' au mot unique qui sera reconnu sur
08181          le futur etat final */
08182       *++delta_ptr = ((-bot_trans)<<base_shift) + id_mask;
08183       bot_trans = *next_states_ptr++; /* C'est un trans_id */
08184     }
08185       }
08186       else {
08187       /* ici -bot_trans est l'identifiant associe' au mot unique qui sera reconnu sur
08188      le futur etat final */
08189       *++delta_ptr = ((-bot_trans)<<base_shift) + id_mask;
08190       bot_trans = *next_states_ptr++; /* C'est un trans_id */
08191       }
08192 
08193       trans_nb = top_next_state_ptr - next_states_ptr;
08194       *++delta_ptr = (trans_nb<<base_shift);
08195     }
08196     else {
08197       trans_nb = (top_next_state_ptr - next_states_ptr)<<base_shift;
08198 
08199       if (is_final)
08200     /* Un prefixe du mot est dans le dico */
08201     *++delta_ptr = trans_nb + stop_mask;
08202       else
08203     *++delta_ptr = trans_nb;
08204     }
08205 
08206     trans_list_ptr = sxdfa_ptr->trans_list + bot_trans;
08207 
08208     while (next_states_ptr < top_next_state_ptr) {
08209       t = *trans_list_ptr++;
08210       next_state = *next_states_ptr++;
08211 
08212       if (next_state <= 0) {
08213     if (next_state < 0)
08214       *++delta_ptr = ((-next_state)<<base_shift) + id_mask + stop_mask + t;
08215     else
08216       *++delta_ptr = stop_mask + t;
08217       }
08218       else {
08219     next_state = sxdfa_ptr->states [next_state]>>1;
08220     *++delta_ptr = (next_state<<base_shift) + t;
08221       }
08222     }
08223   }
08224 
08225   sxdfa_packed_ptr->delta [0] = delta_ptr - sxdfa_packed_ptr->delta;
08226 
08227 #if EBUG
08228   if (top-1 != sxdfa_packed_ptr->delta [0])
08229     sxtrap (ME, "sxdfa2sxdfa_packed");
08230 #endif /* EBUG */
08231 
08232   sxdfa_free (sxdfa_ptr);
08233 
08234   if (sxdfa_ptr->trans_list) sxfree (sxdfa_ptr->trans_list), sxdfa_ptr->trans_list = NULL;
08235 }
08236 
08237 
08238 
08239 
08240 SXINT
08241 sxdfa_packed_seek_a_string (struct sxdfa_packed_struct *sxdfa_packed_ptr, char *kw, SXINT *kwl)
08242 {
08243   sxdfa_packed_ptr->private.ptr.char_ptr = (sxdfa_packed_ptr->private.from_left_to_right) ? kw : kw+*kwl-1;
08244 
08245   return sxdfa_packed_seek (sxdfa_packed_ptr, string_get_next_symb, kwl);
08246 }
08247 
08248 
08249 
08250 SXINT
08251 sxdfa_packed_seek_a_word (struct sxdfa_packed_struct *sxdfa_packed_ptr, SXINT *input_stack)
08252 {
08253   sxdfa_packed_ptr->private.ptr.SXINT_ptr = (SXINT *) ((sxdfa_packed_ptr->private.from_left_to_right) ? input_stack + 1 : input_stack + *input_stack);
08254 
08255   return sxdfa_packed_seek (sxdfa_packed_ptr, word_get_next_symb, input_stack);
08256 }
08257 
08258 
08259 
08260 /*
08261   <0  => reconnaissance d'un prefixe
08262   ==0 => echec
08263   >0  => succes
08264 */
08265 SXINT
08266 sxdfa_packed_seek (struct sxdfa_packed_struct *sxdfa_packed_ptr, SXUINT (*get_next_symb) (struct sxdfa_private *), SXINT *input_lgth)
08267 {
08268   SXUINT    lgth, base_shift, stop_mask, t_mask, tooth, trans_nb, id_mask, is_final, last_final_id, final_id, final_lgth, trans, mid_trans;
08269   SXUINT        *delta, *delta_ptr, *bot_delta_ptr, *top_delta_ptr, *mid_delta_ptr;
08270 
08271   sxinitialise (final_lgth);
08272 
08273   lgth = *input_lgth;
08274   
08275   base_shift = sxdfa_packed_ptr->base_shift;
08276   stop_mask = sxdfa_packed_ptr->stop_mask;
08277   t_mask = sxdfa_packed_ptr->t_mask;
08278   id_mask = sxdfa_packed_ptr->id_mask;
08279 
08280   last_final_id = final_id = 0;
08281 
08282   delta = sxdfa_packed_ptr->delta;
08283 
08284   delta_ptr = delta+sxdfa_packed_ptr->init_state;
08285   tooth = *delta_ptr++;
08286 
08287   while (lgth > 0) {
08288     is_final = tooth & stop_mask; /* si SXTRUE : forcement interne */
08289 
08290     if (tooth & id_mask) {
08291       if (is_final) {
08292     final_id = tooth>>base_shift;
08293     final_lgth = lgth;
08294 
08295     tooth = *delta_ptr++;
08296 
08297     if (tooth & id_mask) {
08298       last_final_id = tooth>>base_shift;
08299       tooth = *delta_ptr++;
08300     }
08301       }
08302       else {
08303     last_final_id = tooth>>base_shift;
08304       tooth = *delta_ptr++;
08305       }
08306     }
08307     else {
08308       if (is_final) {
08309     /* Un prefixe du mot est dans le dico */
08310     final_id = 1;
08311     final_lgth = lgth;
08312       }
08313     }
08314 
08315     trans = (*get_next_symb) (&(sxdfa_packed_ptr->private));
08316 
08317     /* On cherche a quel index se trouve trans dans la "pile" delta_ptr ... */
08318     /* ... par dicho */
08319     trans_nb = tooth>>base_shift;
08320     bot_delta_ptr = delta_ptr;
08321     top_delta_ptr = delta_ptr+trans_nb;
08322 
08323     for (;;) {
08324       mid_delta_ptr = bot_delta_ptr+trans_nb/2;
08325       tooth = *mid_delta_ptr;
08326 
08327       if ((mid_trans = tooth&t_mask) == trans)
08328     /* OK */
08329     break;
08330 
08331       if (mid_trans < trans)
08332     bot_delta_ptr = mid_delta_ptr+1;
08333       else
08334     top_delta_ptr = mid_delta_ptr;
08335 
08336       trans_nb = top_delta_ptr-bot_delta_ptr;
08337 
08338       if (trans_nb == 0) {
08339     tooth = 0;
08340     break; /* echec */
08341       }
08342     }
08343 
08344     if (tooth == 0)
08345       /* Echec */
08346       break;
08347 
08348     lgth--;
08349 
08350     if (tooth & stop_mask)
08351       break;
08352 
08353     delta_ptr = delta+(tooth>>base_shift);
08354     tooth = *delta_ptr++;
08355   }
08356 
08357   *input_lgth = lgth;
08358 
08359   if (lgth == 0) {
08360     /* On a reconnu le mot en entier ... */
08361     /* ... c'est OK uniquement si l'etat atteint est final */
08362     if (tooth & stop_mask) {
08363       if (last_final_id)
08364     return last_final_id;
08365 
08366       if (tooth & id_mask)
08367     return tooth>>base_shift;
08368 
08369       return 1; /* OK */
08370     }
08371 
08372     /* Ici le mot est un prefixe de mots du dico */
08373     /* On peut retourner plusieurs choses */
08374     /* le seul mot unique eventuel ou
08375        le +long prefixe du mot qui est ds le dico */
08376     /* On choisit le 2eme cas */
08377     if (final_id) {
08378       *input_lgth = final_lgth;
08379       return final_id; /* le + long prefixe du mot est ds le dico (final_id), le suffixe est de longueur final_lgth */
08380     }
08381 
08382     return 0; /* le mot est un prefixe de mots (non identifies) du dico */
08383   }
08384 
08385   if (tooth) {
08386     /* Il y a un mot du dico qui est un prefixe du mot d'entree */
08387     if (tooth & id_mask)
08388       return -(tooth>>base_shift);
08389 
08390     if (last_final_id)
08391       return -last_final_id;
08392 
08393     return -1;
08394   }
08395 
08396   /* Ici le mot n'a pas ete reconnu en entier */
08397   if (final_id)
08398     *input_lgth = final_lgth;
08399     
08400   return final_id; /* le + long prefixe du mot est ds le dico (final_id), le suffixe est de longueur final_lgth */
08401 }
08402 
08403 
08404 
08405 
08406 
08407 void
08408 sxdfa_packed2c (struct sxdfa_packed_struct *sxdfa_packed_ptr, FILE *file, char *name, SXBOOLEAN is_static)
08409 {
08410   SXUINT  i;
08411 
08412   fprintf (file, "\nstatic SXINT %s_delta [%ld] = {\n", name, sxdfa_packed_ptr->delta [0]+1);
08413 
08414   for (i = 0; i <= sxdfa_packed_ptr->delta [0]; i++) {
08415     fprintf (file, "/* %ld */ %ld,\n", i, sxdfa_packed_ptr->delta [i]);
08416   }
08417 
08418   fprintf (file, "};\n");
08419 
08420   fprintf (file, "\n%sstruct sxdfa_packed_struct %s = {\n", is_static ? "static " : "", name);
08421   fprintf (file, "/* init_state */ %ld,\n\
08422 /* last_state */ %ld,\n\
08423 /* number_of_out_trans */ %ld,\n\
08424 /* final_state_nb */ %ld,\n\
08425 /* max_path_lgth */ %ld,\n\
08426 /* max_arity */ %ld,\n\
08427 /* max_t_val */ %ld,\n\
08428 /* name */ \"%s\",\n\
08429 /* stats */ NULL,\n\
08430 /* base_shift */ %ld,\n\
08431 /* stop_mask */ %ld,\n\
08432 /* t_mask */ %ld,\n\
08433 /* id_mask */ %ld,\n\
08434 %s_delta,\n\
08435 /* is_static */ SXTRUE,\n\
08436 /* is_a_dag */ %s,\n\
08437  {\n\
08438  /* from_left_to_right */ %s,\
08439  }\n",
08440        sxdfa_packed_ptr->init_state,
08441        sxdfa_packed_ptr->last_state,
08442        sxdfa_packed_ptr->number_of_out_trans,
08443        sxdfa_packed_ptr->final_state_nb,
08444        sxdfa_packed_ptr->max_path_lgth,
08445        sxdfa_packed_ptr->max_arity,
08446        sxdfa_packed_ptr->max_t_val,
08447        name,
08448        sxdfa_packed_ptr->base_shift,
08449        sxdfa_packed_ptr->stop_mask,
08450        sxdfa_packed_ptr->t_mask,
08451        sxdfa_packed_ptr->id_mask,
08452        name,
08453        sxdfa_packed_ptr->is_a_dag ? "SXTRUE" : "SXFALSE",
08454        sxdfa_packed_ptr->private.from_left_to_right ? "SXTRUE" : "SXFALSE"
08455        );
08456 
08457   fprintf (file, "};\n");
08458 }
08459 
08460 
08461 void
08462 sxdfa_packed_free (struct sxdfa_packed_struct *sxdfa_packed_ptr)
08463 {
08464   if (sxdfa_packed_ptr->stats) {
08465     fprintf (sxdfa_packed_ptr->stats, "// Statistics for \"%s\": total size (in bytes) = %ld\n", sxdfa_packed_ptr->name,
08466          sizeof (struct sxdfa_packed_struct)
08467          + sizeof (SXUINT) * (sxdfa_packed_ptr->delta [0] + 1)
08468          );
08469   }
08470 
08471   if (!sxdfa_packed_ptr->is_static) {
08472     sxfree (sxdfa_packed_ptr->delta), sxdfa_packed_ptr->delta = NULL;
08473   }
08474 }
08475 
08476 
08477 static struct nfa_intersection_struct {
08478   SXINT   init_state, final_state, max_state, eof_ste;
08479   SXBA    t_set, p_set;
08480   SXINT   *t2q_hd;
08481   SXINT   top, size;
08482   struct t2q_list {
08483     SXINT p, next;
08484   }       *q_list;
08485 } nfa_intersection_struct_nfa1, nfa_intersection_struct_nfa2, *nfa_intersection_struct_ptr;
08486 
08487 static XH_header XH_intersection_state_list_hd;
08488 static SXBA      nfa_intersection_ec_set;
08489 static SXINT     *nfa_intersection_ec_stack;
08490 
08491 static void
08492 nfa_intersection_process_a_non_eps_trans (SXINT p, SXINT t, SXINT q)
08493 {
08494   SXINT hd, delta, top;
08495 
08496   sxuse(p); /* pour faire taire gcc -Wunused */
08497   /* On a une transition p ->t q non vide sur l'operande pointe' par nfa_intersection_struct_ptr */
08498   if (SXBA_bit_is_reset_set (nfa_intersection_struct_ptr->t_set, t))
08499     nfa_intersection_struct_ptr->t2q_hd [t] = q;
08500   else {
08501     hd = nfa_intersection_struct_ptr->t2q_hd [t];
08502 
08503     delta = (hd > 0) ? 2 : 1;
08504       
08505     if ((top = nfa_intersection_struct_ptr->top += delta) >= nfa_intersection_struct_ptr->size) {
08506       nfa_intersection_struct_ptr->size *= 2;
08507       nfa_intersection_struct_ptr->q_list = (struct t2q_list*) sxrealloc (nfa_intersection_struct_ptr->q_list, nfa_intersection_struct_ptr->size+1, sizeof (struct t2q_list));
08508     }
08509       
08510     nfa_intersection_struct_ptr->t2q_hd [t] = -top;
08511 
08512     if (hd > 0) {
08513       /* 1ere fois */
08514       nfa_intersection_struct_ptr->q_list [top].p = q;
08515       nfa_intersection_struct_ptr->q_list [top].next = top-1;
08516       nfa_intersection_struct_ptr->q_list [top-1].p = hd;
08517       nfa_intersection_struct_ptr->q_list [top-1].next = 0;
08518     }
08519     else {
08520       nfa_intersection_struct_ptr->q_list [top].p = q;
08521       nfa_intersection_struct_ptr->q_list [top].next = -hd;
08522     }
08523   }
08524 }
08525 
08526 static void
08527 nfa_intersection_fill_non_eps_trans (SXINT nfa_list,
08528                      void (*nfa1_extract_non_eps_trans)(SXINT, void (*)(SXINT, SXINT, SXINT)))
08529 {
08530   SXINT bot, top, nfa_state;
08531 
08532   bot = XH_X (XH_intersection_state_list_hd, nfa_list);
08533   top = XH_X (XH_intersection_state_list_hd, nfa_list+1);
08534 
08535   while (bot < top) {
08536     nfa_state = XH_list_elem (XH_intersection_state_list_hd, bot);
08537 
08538     nfa1_extract_non_eps_trans (nfa_state, nfa_intersection_process_a_non_eps_trans);
08539     
08540     bot++;
08541   }
08542 }
08543 
08544 /* Associe' a t, ds t2q_hd, on a un ensemble d'etats p.  Pour chaque p, on fait une eps closure.
08545    l'ensemble de tous les etats q atteints depuis tous les p sont tries et stockes ds un XH (XH_intersection_state_list_hd)
08546    et on retourne l'id ds cet XH */
08547 static SXINT
08548 nfa_intersection_make_eps_closure (SXINT t,
08549                    SXBOOLEAN (*nfa_extract_empty_trans) (SXINT, SXBA),
08550                    SXBOOLEAN  *contains_the_final_state)
08551 {
08552   SXINT     p, q, q_list, next;
08553   SXBOOLEAN is_the_final_state;
08554 
08555   is_the_final_state = (t == nfa_intersection_struct_ptr->eof_ste);
08556 
08557   p = nfa_intersection_struct_ptr->t2q_hd [t];
08558 
08559   if (p > 0) {
08560     /* etat unique */
08561     if (SXBA_bit_is_reset_set (nfa_intersection_struct_ptr->p_set, p) &&
08562     nfa_extract_empty_trans &&
08563     ((nfa_intersection_struct_ptr->max_state == 0) /* On doit regarder les trans depuis l'etat final */ || p != nfa_intersection_struct_ptr->final_state)) {
08564     PUSH (nfa_intersection_ec_stack, p);
08565     }
08566   }
08567   else {
08568     next = -p;
08569 
08570     do {
08571       p = nfa_intersection_struct_ptr->q_list [next].p;
08572 
08573       if (SXBA_bit_is_reset_set (nfa_intersection_struct_ptr->p_set, p) &&
08574       nfa_extract_empty_trans &&
08575       ((nfa_intersection_struct_ptr->max_state == 0) /* On doit regarder les trans depuis l'etat final */ || p != nfa_intersection_struct_ptr->final_state)) {
08576       PUSH (nfa_intersection_ec_stack, p);
08577       }
08578     } while ((next = nfa_intersection_struct_ptr->q_list [next].next) > 0);
08579   }
08580 
08581   /* nfa_intersection_ec_stack contient des etats dont il faut examiner les eps trans */
08582   while (!IS_EMPTY (nfa_intersection_ec_stack)) {
08583     p = POP (nfa_intersection_ec_stack);
08584 
08585     if ((*nfa_extract_empty_trans)(p, nfa_intersection_ec_set)) {
08586       /* wstate_set est non vide */
08587       q = 0; /* et non nfa_init_state-1, car dans certains cas (DAG) on n'a pas la garantie qu'une transition i -t-> j vérifie i<j */
08588 
08589       while ((q = sxba_scan_reset (nfa_intersection_ec_set, q)) >= 0) {
08590     if (SXBA_bit_is_reset_set (nfa_intersection_struct_ptr->p_set, q) &&
08591         ((nfa_intersection_struct_ptr->max_state == 0) /* On doit regarder les trans depuis l'etat final */ || q != nfa_intersection_struct_ptr->final_state)) {
08592       PUSH (nfa_intersection_ec_stack, q);
08593     }
08594       }
08595     }
08596   }
08597 
08598   q = 0;
08599 
08600   while ((q = sxba_scan_reset (nfa_intersection_struct_ptr->p_set, q)) > 0) {
08601     if (q == nfa_intersection_struct_ptr->final_state)
08602       is_the_final_state = SXTRUE;
08603 
08604     XH_push (XH_intersection_state_list_hd, q);
08605   }
08606 
08607   *contains_the_final_state = is_the_final_state;
08608 
08609   XH_set (&XH_intersection_state_list_hd, &q_list);
08610 
08611   return q_list;
08612 }
08613   
08614 #if EBUG
08615 static void
08616 print_nfa_intersection_state (SXINT nfa_list)
08617 {
08618   SXINT cur, bot, top, p;
08619 
08620   fputs ("{", stdout);
08621   bot = XH_X (XH_intersection_state_list_hd, nfa_list);
08622   top = XH_X (XH_intersection_state_list_hd, nfa_list+1);
08623 
08624   for (cur = bot; cur < top; cur++) {
08625     p = XH_list_elem (XH_intersection_state_list_hd, cur);
08626 
08627     if (cur > bot)
08628       fputs (", ", stdout);
08629 
08630     printf ("%ld", p);
08631   }
08632 
08633   fputs ("}", stdout);
08634 }
08635 
08636 static void
08637 print_nfa_intersection_trans (XxY_header *hd_ptr, SXINT nfa_intersection_state, SXINT t, SXINT next_nfa_intersection_state)
08638 {
08639   SXINT nfa1_list, nfa2_list, next_nfa1_list, next_nfa2_list;
08640 
08641   nfa1_list = XxY_X (*hd_ptr, nfa_intersection_state);
08642   fputs ("(", stdout);
08643   print_nfa_intersection_state (nfa1_list);
08644   fputs (", ", stdout);
08645   nfa2_list = XxY_Y (*hd_ptr, nfa_intersection_state);
08646   print_nfa_intersection_state (nfa2_list);
08647   printf (")\t%s\t(", sxstrget (t));
08648   next_nfa1_list = XxY_X (*hd_ptr, next_nfa_intersection_state);
08649   print_nfa_intersection_state (next_nfa1_list);
08650   fputs (", ", stdout);
08651   next_nfa2_list = XxY_Y (*hd_ptr, next_nfa_intersection_state);
08652   print_nfa_intersection_state (next_nfa2_list);
08653   fputs (")\n", stdout);
08654 }
08655 #endif /* EBUG */
08656 
08657 static SXINT                 *nfa_intersection_tbp_stack;
08658 static SXBA                  nfa_intersection_final_state_set;
08659 
08660 static void
08661 XxY_nfa_intersection_states_oflw (SXINT old_size, SXINT new_size)
08662 {
08663   sxuse (old_size); /* pour faire taire gcc -Wunused */
08664   nfa_intersection_tbp_stack = (SXINT *) sxrealloc (nfa_intersection_tbp_stack, new_size+1, sizeof (SXINT));
08665   nfa_intersection_final_state_set = sxba_resize (nfa_intersection_final_state_set, new_size+1);
08666 }
08667 
08668 /* Realise l'intersection de 2 automates qcq */
08669 SXBOOLEAN
08670 nfa_intersection (SXINT nfa1_init_state, 
08671           SXINT nfa1_final_state, 
08672           SXINT nfa1_max_state,  /* en général, == 0 ; si > 0, on est dans le cas DAG (pas de trans
08673                         sortant de final_state) ; en contrepartie, on a le droit d'avoir
08674                         final_state != max_state, et on a le droit d'avoir des transitions
08675                         vers final_state qui ne sont pas sur eof_ste */
08676           SXINT nfa1_eof_ste, 
08677           SXINT nfa2_init_state, 
08678           SXINT nfa2_final_state, 
08679           SXINT nfa2_max_state,
08680           SXINT nfa2_eof_ste, 
08681           SXBOOLEAN (*nfa1_empty_trans)(SXINT, SXBA),  
08682           SXBOOLEAN (*nfa2_empty_trans)(SXINT, SXBA), 
08683           void (*nfa1_extract_non_eps_trans)(SXINT, void (*)(SXINT, SXINT, SXINT)),
08684           void (*nfa2_extract_non_eps_trans)(SXINT, void (*)(SXINT, SXINT, SXINT)), 
08685           void (*nfa_intersection_fill_trans)(SXINT, SXINT, SXINT, SXBOOLEAN)
08686 #ifdef ESSAI_INVERSE_MAPPING
08687           , struct inverse_mapping *inverse_mapping
08688 #endif /* ESSAI_INVERSE_MAPPING */
08689           )
08690 {
08691   SXINT                 nfa_intersection_state, nfa1_list, nfa2_list, t, nfa_intersection_init_state, nfa_intersection_final_state = 0, triple, next_nfa_intersection_state, p, q;
08692   SXINT                 size1, size2;
08693   SXBA                  nfa_intersection_working_t_set;
08694   SXBA                  nfa_intersection_tbp_set = NULL;
08695   XxY_header            XxY_nfa_intersection_states_hd;
08696   XxYxZ_header          XxYxZ_work_hd;
08697   static SXINT          XxYxZ_work_foreach [6] = {1, 0, 1, 0, 0, 0};
08698   SXBOOLEAN             nfa1_list_contains_the_final_state, nfa2_list_contains_the_final_state, result_is_empty;
08699 
08700   /* chaque etat du intersection_nfa est un couple (liste1, liste2) stocke' ds
08701      XxY_nfa_intersection_states_hd.
08702      liste1 et liste2 sont des ensembles d'etats de nfa1 et de nfa2 ranges ds
08703      XH_intersection_state_list_hd
08704   */
08705   size1 = nfa1_max_state == 0 ? nfa1_final_state : nfa1_max_state;
08706   size2 = nfa2_max_state == 0 ? nfa2_final_state : nfa2_max_state;
08707 
08708 
08709   /* allocation des structures locales */
08710   nfa_intersection_struct_nfa1.init_state = nfa1_init_state;
08711   nfa_intersection_struct_nfa1.final_state = nfa1_final_state;
08712   nfa_intersection_struct_nfa1.max_state = nfa1_max_state;
08713   nfa_intersection_struct_nfa1.eof_ste = nfa1_eof_ste;
08714   nfa_intersection_struct_nfa1.t_set = sxba_calloc (nfa1_eof_ste+1);
08715   nfa_intersection_struct_nfa1.p_set = sxba_calloc (size1+1);
08716   nfa_intersection_struct_nfa1.t2q_hd = (SXINT *) sxalloc (nfa1_eof_ste+1, sizeof (SXINT));
08717   nfa_intersection_struct_nfa1.q_list = (struct t2q_list*) sxalloc ((nfa_intersection_struct_nfa1.size = size1) + 1, sizeof (struct t2q_list));
08718   nfa_intersection_struct_nfa1.top = 0;
08719 
08720   nfa_intersection_struct_nfa2.init_state = nfa2_init_state;
08721   nfa_intersection_struct_nfa2.final_state = nfa2_final_state;
08722   nfa_intersection_struct_nfa2.max_state = nfa2_max_state;
08723   nfa_intersection_struct_nfa2.eof_ste = nfa2_eof_ste;
08724   nfa_intersection_struct_nfa2.t_set = sxba_calloc (nfa2_eof_ste+1);
08725   nfa_intersection_struct_nfa2.p_set = sxba_calloc (size2+1);
08726   nfa_intersection_struct_nfa2.t2q_hd = (SXINT *) sxalloc (nfa2_eof_ste+1, sizeof (SXINT));
08727   nfa_intersection_struct_nfa2.q_list = (struct t2q_list*) sxalloc ((nfa_intersection_struct_nfa2.size = size2) + 1, sizeof (struct t2q_list));
08728   nfa_intersection_struct_nfa2.top = 0;
08729 
08730   nfa_intersection_working_t_set = sxba_calloc (nfa1_eof_ste+nfa2_eof_ste+1);
08731 
08732   XxY_alloc (&XxY_nfa_intersection_states_hd, "XxY_nfa_intersection_states_hd", size1 + size2 + 1, 1, 0, 0, XxY_nfa_intersection_states_oflw, NULL);
08733   nfa_intersection_tbp_stack = (SXINT *) sxalloc (XxY_size (XxY_nfa_intersection_states_hd)+1, sizeof (SXINT)), RAZ (nfa_intersection_tbp_stack);
08734   nfa_intersection_final_state_set = sxba_calloc (XxY_size (XxY_nfa_intersection_states_hd)+1);
08735 
08736   XxYxZ_alloc (&XxYxZ_work_hd, "XxYxZ_work_hd", size1 + size2 + 1, 1, XxYxZ_work_foreach, NULL, NULL);
08737 
08738   XH_alloc (&XH_intersection_state_list_hd, "XH_intersection_state_list_hd", size1 + size2 + 1,1, 2, NULL, NULL);
08739 
08740   nfa_intersection_ec_stack = (SXINT *) sxalloc (size1 + size2 + 1, sizeof (SXINT)), RAZ (nfa_intersection_ec_stack);
08741   nfa_intersection_ec_set = sxba_calloc (size1 + size2 + 1);
08742 
08743 
08744   nfa_intersection_struct_ptr = &(nfa_intersection_struct_nfa1);
08745   nfa_intersection_process_a_non_eps_trans (0 /* bidon */, 0 /* bidon */, nfa1_init_state);
08746   /* On fabrique la liste des etats de nfa1 que l'on peut atteindre (apres eps closure)
08747      sur la transition bidon 0 */
08748   nfa1_list = nfa_intersection_make_eps_closure (0, nfa1_empty_trans, &nfa1_list_contains_the_final_state);
08749   SXBA_0_bit (nfa_intersection_struct_nfa1.t_set, 0); /* RAZ de nfa_intersection_struct_nfa1 */
08750 
08751   nfa_intersection_struct_ptr = &(nfa_intersection_struct_nfa2);
08752   nfa_intersection_process_a_non_eps_trans (0 /* bidon */, 0 /* bidon */, nfa2_init_state);
08753   /* On fabrique la liste des etats de nfa1 que l'on peut atteindre (apres eps closure)
08754      sur la transition bidon 0 */
08755   nfa2_list = nfa_intersection_make_eps_closure (0, nfa2_empty_trans, &nfa2_list_contains_the_final_state);
08756   SXBA_0_bit (nfa_intersection_struct_nfa2.t_set, 0); /* RAZ de nfa_intersection_struct_nfa1 */
08757 
08758   XxY_set (&XxY_nfa_intersection_states_hd, nfa1_list, nfa2_list, &nfa_intersection_init_state);
08759 
08760   PUSH (nfa_intersection_tbp_stack, nfa_intersection_init_state);
08761 
08762   result_is_empty = SXTRUE;
08763 
08764   while (!IS_EMPTY (nfa_intersection_tbp_stack)) {
08765     nfa_intersection_state = DPOP (nfa_intersection_tbp_stack);
08766     nfa1_list = XxY_X (XxY_nfa_intersection_states_hd, nfa_intersection_state);
08767     nfa2_list = XxY_Y (XxY_nfa_intersection_states_hd, nfa_intersection_state);
08768 
08769     nfa_intersection_struct_ptr = &(nfa_intersection_struct_nfa1);
08770     nfa_intersection_fill_non_eps_trans (nfa1_list, nfa1_extract_non_eps_trans);
08771     nfa_intersection_struct_ptr = &(nfa_intersection_struct_nfa2);
08772     nfa_intersection_fill_non_eps_trans (nfa2_list, nfa2_extract_non_eps_trans);
08773 
08774     if (sxba_2op (nfa_intersection_working_t_set, SXBA_OP_COPY, nfa_intersection_struct_nfa1.t_set, SXBA_OP_AND, nfa_intersection_struct_nfa2.t_set)) {
08775       /* Il y a des transitions communes ... */
08776       t = 0;
08777 
08778       while ((t = sxba_scan (nfa_intersection_working_t_set, t)) > 0) {
08779     nfa_intersection_struct_ptr = &(nfa_intersection_struct_nfa1);
08780     nfa1_list = nfa_intersection_make_eps_closure (t, nfa1_empty_trans, &nfa1_list_contains_the_final_state);
08781     nfa_intersection_struct_ptr = &(nfa_intersection_struct_nfa2);
08782     nfa2_list = nfa_intersection_make_eps_closure (t, nfa2_empty_trans, &nfa2_list_contains_the_final_state);
08783 
08784     if (!XxY_set (&XxY_nfa_intersection_states_hd, nfa1_list, nfa2_list, &next_nfa_intersection_state)) {
08785       /* Nouvel etat */
08786       if (nfa1_list_contains_the_final_state && nfa2_list_contains_the_final_state) {
08787         /* next_nfa_intersection_state est un etat final */
08788         result_is_empty = SXFALSE;
08789         SXBA_1_bit (nfa_intersection_final_state_set, next_nfa_intersection_state);
08790 
08791         if (nfa1_max_state == 0)
08792           /* Il peut y avoir des transitions sortantes de l'etat final */
08793           PUSH (nfa_intersection_tbp_stack, next_nfa_intersection_state);
08794       }
08795       else
08796         PUSH (nfa_intersection_tbp_stack, next_nfa_intersection_state);
08797     }
08798 
08799     /* On a donc une transition nfa_intersection_state ->t next_nfa_intersection_state */
08800     /* On differe la sortie car elle peut ne pas conduire a un etat final */
08801 #if EBUG
08802     print_nfa_intersection_trans (&XxY_nfa_intersection_states_hd, nfa_intersection_state, t, next_nfa_intersection_state);
08803 #endif /* EBUG */
08804 
08805     XxYxZ_set (&XxYxZ_work_hd, nfa_intersection_state, t, next_nfa_intersection_state, &triple);
08806       }
08807     }
08808     else {
08809       /* Impasse les chemins qui arrivent la seront supprimes */
08810     }
08811 
08812     sxba_empty (nfa_intersection_struct_nfa1.t_set);
08813     sxba_empty (nfa_intersection_struct_nfa2.t_set);
08814   }
08815 
08816   if (!result_is_empty) {
08817     /* On fait un etat final unique d'id max ... */
08818     nfa_intersection_final_state = XxY_top (XxY_nfa_intersection_states_hd);
08819 
08820     if (!SXBA_bit_is_set (nfa_intersection_final_state_set, nfa_intersection_final_state)) {
08821       /* l'etat max n'est pas final */
08822       nfa_intersection_final_state++;
08823     }
08824 
08825     /* ... et on met les intersections vers cet etat */
08826     p = nfa_intersection_final_state;
08827 
08828     while ((p = sxba_1_rlscan (nfa_intersection_final_state_set, p)) > 0)
08829       XxYxZ_set (&XxYxZ_work_hd, p, nfa2_eof_ste /* !! */, nfa_intersection_final_state, &triple);
08830   
08831     /* Elimination des branches mortes ... */
08832     nfa_intersection_tbp_set = sxba_calloc (nfa_intersection_final_state+1);
08833 
08834     /* On marque les etats accessibles depuis l'etat final */
08835     PUSH (nfa_intersection_tbp_stack, nfa_intersection_final_state);
08836     SXBA_1_bit (nfa_intersection_tbp_set, nfa_intersection_final_state);
08837 
08838     while (!IS_EMPTY (nfa_intersection_tbp_stack)) {
08839       q = POP (nfa_intersection_tbp_stack);
08840 
08841       XxYxZ_Zforeach (XxYxZ_work_hd, q, triple) {
08842     p = XxYxZ_X (XxYxZ_work_hd, triple);
08843 
08844     if (SXBA_bit_is_reset_set (nfa_intersection_tbp_set, p))
08845       PUSH (nfa_intersection_tbp_stack, p);
08846       }
08847     }
08848 
08849     /* ... et sortie de l'intersection */
08850     for (p = nfa_intersection_init_state; p <= nfa_intersection_final_state; p++) {
08851       if (SXBA_bit_is_set (nfa_intersection_tbp_set, p)) {
08852     XxYxZ_Xforeach (XxYxZ_work_hd, p, triple) {
08853       q = XxYxZ_Z (XxYxZ_work_hd, triple);
08854 
08855       if (SXBA_bit_is_set (nfa_intersection_tbp_set, q))
08856         (*nfa_intersection_fill_trans)(p, XxYxZ_Y (XxYxZ_work_hd, triple), q, (SXBOOLEAN) (q == nfa_intersection_final_state));
08857     }
08858       }
08859     }
08860   }
08861 
08862   /* On libere tout */
08863 
08864   sxfree (nfa_intersection_struct_nfa1.t_set), nfa_intersection_struct_nfa1.t_set = NULL;
08865   sxfree (nfa_intersection_struct_nfa1.p_set), nfa_intersection_struct_nfa1.t_set = NULL;
08866   sxfree (nfa_intersection_struct_nfa1.t2q_hd), nfa_intersection_struct_nfa1.t2q_hd = NULL;
08867   sxfree (nfa_intersection_struct_nfa1.q_list), nfa_intersection_struct_nfa1.q_list = NULL;
08868 
08869   sxfree (nfa_intersection_struct_nfa2.t_set), nfa_intersection_struct_nfa2.t_set = NULL;
08870   sxfree (nfa_intersection_struct_nfa2.p_set), nfa_intersection_struct_nfa1.t_set = NULL;
08871   sxfree (nfa_intersection_struct_nfa2.t2q_hd), nfa_intersection_struct_nfa2.t2q_hd = NULL;
08872   sxfree (nfa_intersection_struct_nfa2.q_list), nfa_intersection_struct_nfa2.q_list = NULL;
08873 
08874   sxfree (nfa_intersection_working_t_set);
08875 
08876   XxYxZ_free (&XxYxZ_work_hd);
08877 
08878   sxfree (nfa_intersection_tbp_stack), nfa_intersection_tbp_stack = NULL;
08879   sxfree (nfa_intersection_final_state_set), nfa_intersection_final_state_set = NULL;
08880 
08881   sxfree (nfa_intersection_ec_stack), nfa_intersection_ec_stack = NULL;
08882   sxfree (nfa_intersection_ec_set), nfa_intersection_ec_set = NULL;
08883 
08884 #ifdef ESSAI_INVERSE_MAPPING
08885   if (!result_is_empty && inverse_mapping) {
08886     SXINT nfa1, bot1, top1, state1, nfa2, bot2, top2, state2;
08887 
08888     /* On alloue les structures c'est l'appelant qui les liberera */
08889     inverse_mapping->new_state2old_state_set_id = (SXINT*) sxalloc (nfa_intersection_final_state+1, sizeof (SXINT)), inverse_mapping->new_state2old_state_set_id [0] = 0;
08890     XH_alloc (&(inverse_mapping->XH_state_set), "inverse_mapping->XH_state_set", nfa_intersection_final_state+1, 1, ((nfa1_final_state+nfa2_final_state)/nfa_intersection_final_state)+1, NULL, NULL);
08891 
08892     for (p = 1; p <= nfa_intersection_final_state; p++) {
08893       if (SXBA_bit_is_set (nfa_intersection_tbp_set, p)) {
08894     nfa1 = XxY_X (XxY_nfa_intersection_states_hd, p);
08895     bot1 = XH_X (XH_intersection_state_list_hd, nfa1);
08896     top1 = XH_X (XH_intersection_state_list_hd, nfa1+1);
08897 
08898     nfa2 = XxY_Y (XxY_nfa_intersection_states_hd, p);
08899     bot2 = XH_X (XH_intersection_state_list_hd, nfa2);
08900     top2 = XH_X (XH_intersection_state_list_hd, nfa2+1);
08901 
08902     while (bot1 < top1 || bot2 < top2) {
08903       if (bot1 < top1)
08904         state1 = XH_list_elem (XH_intersection_state_list_hd, bot1);
08905       else
08906         state1 = SXINT_MAX;
08907 
08908       if (bot2 < top2)
08909         state2 = XH_list_elem (XH_intersection_state_list_hd, bot2);
08910       else
08911         state2 = SXINT_MAX;
08912 
08913       if (state1 == state2) {
08914         XH_push (inverse_mapping->XH_state_set, state1);
08915         bot1++;
08916         bot2++;
08917       }
08918       else {
08919         if (state1 < state2) {
08920           XH_push (inverse_mapping->XH_state_set, state1);
08921           bot1++;
08922         }
08923         else {
08924           XH_push (inverse_mapping->XH_state_set, state2);
08925           bot2++;
08926         }
08927       }
08928     }
08929 
08930     XH_set (&(inverse_mapping->XH_state_set), inverse_mapping->new_state2old_state_set_id + p);
08931       }
08932       else
08933     inverse_mapping->new_state2old_state_set_id [p] = 0;
08934     }
08935 
08936     inverse_mapping->init_state = nfa_intersection_init_state;
08937     inverse_mapping->final_state = nfa_intersection_final_state;
08938   }
08939 #endif /* ESSAI_INVERSE_MAPPING */
08940 
08941   if (!result_is_empty)
08942     sxfree (nfa_intersection_tbp_set);
08943 
08944   XxY_free (&XxY_nfa_intersection_states_hd);
08945   XH_free (&XH_intersection_state_list_hd);
08946 
08947   return !result_is_empty;
08948 }
08949 
08950 
08951 /* WRAPPERS */
08952 /* Petit wrappeur autour de sxdico_get */
08953 SXINT
08954 dico_seek (struct dico *dico, unsigned char *word, SXINT lgth)
08955 {
08956   return (SXINT) sxdico_get (dico, &word, &lgth);
08957 }
08958 
08959 /* Petits wrappeurs autour de sxdfa_comb_seek_a_string */
08960 SXINT
08961 sxdfa_comb_get (struct sxdfa_comb *dico, char *word, SXINT lgth)
08962 {
08963   SXINT id = sxdfa_comb_seek_a_string (dico, /* pas & */word, &lgth);
08964   return (lgth == 0 && id > 0) ? id : 0;
08965 }
08966 
08967 SXINT
08968 sxdfa_comb_get_bounded (struct sxdfa_comb *dico, char **word_ptr, SXINT *lgth_ptr)
08969 {
08970   SXINT prev_lgth = *lgth_ptr;
08971   SXINT id = sxdfa_comb_seek_a_string (dico, /* pas & */*word_ptr, lgth_ptr);
08972   if (dico->private.from_left_to_right)
08973     *word_ptr += prev_lgth - *lgth_ptr;
08974   /* else
08975     *word_ptr inchangé -- semble jamais utilisé
08976     */
08977   return (id > 0 && prev_lgth - *lgth_ptr > 0) ? id : 0;
08978 }
08979 
08980 
08981 
08982 
08983 
08984 
08985 
08986 
08987 
08988 
08989 
08990 
08991 
08992 
08993 
08994 
08995 
08996 
08997 
08998 
08999 #if 0
09000 
09001 
09002   /* This package allows the handling of (small) integers that can be used 
09003      to index unknown external structures.
09004      The two mains macros are
09005      sxindex_next () qui retourne le prochain index disponnible
09006      sxsindex_release () qui indique qu'un index est de nouveau disponible
09007   */
09008 
09009 
09010 
09011 #ifndef sxsindex_h
09012 #define sxsindex_h
09013 #include "SXante.h"
09014 
09015 #include "sxalloc.h"
09016 #include "sxstack.h"
09017 
09018   typedef struct {
09019     SXINT max_size /* current max_size */
09020     , index /* greater index ever returned */
09021       ;
09022     SXINT *free_stack /* Stack of already released sindexes Pile des index*/ ;
09023     void    (*oflw) (SXINT old_size, SXINT new_size);
09024   } sxsindex_header;
09025 
09026 
09027   extern void   sxindex_alloc (sxsindex_header *header,
09028                    SXINT initial_size,
09029                    void (*user_oflw) ());
09030 
09031 
09032 
09033 #define sxsindex_alloc(h,l,o)  ((h).max_size=l\
09034                                , (h).index=0\
09035                                , (h).oflw=o\
09036                                , (h).free_stack=NULL\
09037                               )
09038 
09039 #define sxsindex_next(h)      (((h).free_stack && (h).free_stack[0]) ? POP((h).free_stack)\
09040                                                                      : (((++(h).index == (h).max_size) ? (*(h).oflw)((h).max_size,(h).max_size*2), (h).max_size *= 2\
09041                                                                                                        : NULL)\
09042                                                                        , (h).index)\
09043                               )
09044 
09045 #define sxsindex_release h,x)  (((h).free_stack == NULL) ? (DALLOC_STACK((h).free_stack, ((h).max_size/10)+1))\
09046                                                          : NULL\
09047                                 , DPUSH((h).free_stack,x)\
09048                                )
09049 
09050 #define sxsindex_free(h)       ((h).free_stack ? (DFREE_STACK((h).free_stack))\
09051                                                : NULL\
09052                                )
09053 
09054 #include "SXpost.h"
09055 #endif /* sxsindex_h */
09056 #endif /* 0 */
09057 
09058 /*
09059  * Local Variables:
09060  * mode: C
09061  * version-control: yes
09062  * End:
09063  */

Generated on Wed Apr 21 16:39:33 2010 for syntax-6.0b7 by  doxygen 1.6.1