00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "config.h"
00028 #include <assert.h>
00029 #include <string.h>
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <sys/types.h>
00033 #ifdef HAVE_SYS_WAIT_H
00034 # include <sys/wait.h>
00035 #endif
00036 #include <unistd.h>
00037
00038 #include "dic.h"
00039 #include "regexp.h"
00040 #include "alist.h"
00041 #include "automaton.h"
00042
00043 #ifdef DEBUG_AUTOMATON
00044 #define DMSG(a) a
00045 #else
00046 #define DMSG(a)
00047 #endif
00048
00049 #define MAX_TRANSITION_LETTERS 256
00050
00051 typedef struct automaton_state_t *astate;
00052 typedef struct Automaton_t *Automaton;
00053
00054
00055
00056
00057
00058 automaton automaton_build (int init_state, int *ptl, int *PS, struct search_RegE_list_t *list);
00059 void automaton_delete (automaton a);
00060 int automaton_get_nstate (automaton a);
00061 int automaton_get_init (automaton a);
00062 int automaton_get_accept (automaton a, int state);
00063 int automaton_get_next_state (automaton a, int start, char l);
00064 void automaton_dump (automaton a, char* filename);
00065
00066
00067
00068
00069
00070
00071 static Automaton s_automaton_create ();
00072 static void s_automaton_delete (Automaton a);
00073
00074 static alist s_automaton_id_create (int id);
00075 static char* s_automaton_id_to_str (alist id);
00076
00077 static astate s_automaton_state_create (alist id);
00078
00079 static void s_automaton_add_state (Automaton a, astate s);
00080 static astate s_automaton_get_state (Automaton a, alist id);
00081
00082 static Automaton s_automaton_PS_to_NFA (int init_state, int *ptl, int *PS);
00083 static Automaton s_automaton_NFA_to_DFA (Automaton a, struct search_RegE_list_t *list);
00084 static automaton s_automaton_finalize (Automaton a);
00085 #ifdef DEBUG_AUTOMATON
00086 static void s_automaton_dump (Automaton a, char* filename);
00087 #endif
00088
00089
00090
00091
00092
00093 struct automaton_state_t {
00094 alist id;
00095 int accept;
00096 int id_static;
00097 astate next[MAX_TRANSITION_LETTERS];
00098 };
00099
00100 struct Automaton_t {
00101 int nstates;
00102 astate init_state;
00103 alist states;
00104 };
00105
00106 struct automaton_t {
00107 int nstates;
00108 int init;
00109 int *accept;
00110 int **trans;
00111 };
00112
00113
00114
00115
00116
00117 automaton
00118 automaton_build(int init_state, int *ptl, int *PS, struct search_RegE_list_t *list)
00119 {
00120 Automaton nfa,dfa;
00121 automaton final;
00122
00123 nfa = s_automaton_PS_to_NFA(init_state,ptl,PS);
00124 DMSG(printf("\n non deterministic automaton OK \n\n"));
00125 DMSG(s_automaton_dump(nfa,"auto_nfa"));
00126
00127 dfa = s_automaton_NFA_to_DFA(nfa, list);
00128 DMSG(printf("\n deterministic automaton OK \n\n"));
00129 DMSG(s_automaton_dump(dfa,"auto_dfa"));
00130
00131 final = s_automaton_finalize(dfa);
00132 DMSG(printf("\n final automaton OK \n\n"));
00133 DMSG(automaton_dump(final,"auto_fin"));
00134
00135 s_automaton_delete(nfa);
00136 s_automaton_delete(dfa);
00137 return final;
00138 }
00139
00140 void
00141 automaton_delete(automaton a)
00142 {
00143 int i;
00144 free(a->accept);
00145 for(i=0; i <= a->nstates; i++)
00146 free(a->trans[i]);
00147 free(a->trans);
00148 free(a);
00149 }
00150
00151 inline int
00152 automaton_get_nstates(automaton a)
00153 {
00154 return a->nstates;
00155 }
00156
00157 inline int
00158 automaton_get_init(automaton a)
00159 {
00160 return a->init;
00161 }
00162
00163 inline int
00164 automaton_get_accept(automaton a, int state)
00165 {
00166 return a->accept[state];
00167 }
00168
00169 inline int
00170 automaton_get_next_state(automaton a, int state, char l)
00171 {
00172 return a->trans[state][(int)l];
00173 }
00174
00175 void
00176 automaton_dump(automaton a, char* filename)
00177 {
00178 int i,l;
00179 FILE* f;
00180 #ifdef HAVE_SYS_WAIT_H
00181 pid_t pid;
00182 #endif
00183
00184 if (a == NULL)
00185 return ;
00186 f=fopen(filename,"w");
00187 fprintf(f,"digraph automaton {\n");
00188 for(i=1; i<=a->nstates; i++)
00189 {
00190 fprintf(f,"\t%d [label = \"%d\"",i,i);
00191 if (i == a->init)
00192 fprintf(f,", style = filled, color=lightgrey");
00193 if (a->accept[i])
00194 fprintf(f,", shape = doublecircle");
00195 fprintf(f,"];\n");
00196 }
00197 fprintf(f,"\n");
00198 for(i=1; i<=a->nstates; i++)
00199 for(l=0; l < MAX_TRANSITION_LETTERS; l++)
00200 if (a->trans[i][l])
00201 {
00202 fprintf(f,"\t%d -> %d [label = \"",i,a->trans[i][l]);
00203 regexp_print_letter(f,l);
00204 fprintf(f,"\"];\n");
00205 }
00206 fprintf(f,"fontsize=20;\n");
00207 fprintf(f,"}\n");
00208 fclose(f);
00209
00210 #ifdef HAVE_SYS_WAIT_H
00211 pid = fork ();
00212 if (pid > 0) {
00213 wait(NULL);
00214 } else if (pid == 0) {
00215 execlp("dotty","dotty",filename,NULL);
00216 printf("exec dotty failed\n");
00217 exit(1);
00218 }
00219 #endif
00220 }
00221
00222
00223
00224
00225
00226 void
00227 state_delete_fun(void* ps)
00228 {
00229 astate s = ps;
00230 alist_delete(s->id);
00231 free(s);
00232 }
00233
00234 static Automaton
00235 s_automaton_create()
00236 {
00237 Automaton a;
00238 a = (Automaton)malloc(sizeof(struct Automaton_t));
00239 a->nstates = 0;
00240 a->init_state = NULL;
00241 a->states = alist_create();
00242 alist_set_delete(a->states,state_delete_fun);
00243 return a;
00244 }
00245
00246
00247 static void
00248 s_automaton_delete(Automaton a)
00249 {
00250 alist_delete(a->states);
00251 free(a);
00252 }
00253
00254 static alist
00255 s_automaton_id_create(int id)
00256 {
00257 alist a = alist_create();
00258 alist_add(a,(void*)id);
00259 return a;
00260 }
00261
00262 static char* s_automaton_id_to_str(alist id)
00263 {
00264 static char s[250];
00265 memset(s,0,sizeof(s));
00266 alist_elt ptr;
00267 for(ptr = alist_get_first(id); ptr ; ptr = alist_get_next(id,ptr))
00268 {
00269 char tmp[50];
00270 sprintf(tmp,"%d ",(int)alist_elt_get_value(ptr));
00271 strcat(s,tmp);
00272 }
00273 return s;
00274 }
00275
00276 static astate
00277 s_automaton_state_create(alist id)
00278 {
00279 astate s;
00280 s = (astate)malloc(sizeof(struct automaton_state_t));
00281 s->id = id;
00282 s->accept = 0;
00283 memset(s->next,0,sizeof(astate)*MAX_TRANSITION_LETTERS);
00284 DMSG(printf("** state %s creation\n",s_automaton_id_to_str(id)));
00285 return s;
00286 }
00287
00288 static void
00289 s_automaton_add_state(Automaton a, astate s)
00290 {
00291 a->nstates ++;
00292 alist_add(a->states,(void*)s);
00293 DMSG(printf("** state %s added to automaton\n",s_automaton_id_to_str(s->id)));
00294 }
00295
00296 static astate
00297 s_automaton_get_state(Automaton a, alist id)
00298 {
00299 astate s;
00300 alist_elt ptr;
00301 for(ptr = alist_get_first(a->states) ; ptr ; ptr = alist_get_next(a->states,ptr))
00302 {
00303 s = alist_elt_get_value(ptr);
00304 if (alist_equal(s->id,id))
00305 {
00306
00307 return s;
00308 }
00309 }
00310 return NULL;
00311 }
00312
00313
00314
00315
00316
00317 Automaton
00318 s_automaton_PS_to_NFA(int init_state_id, int *ptl, int *PS)
00319 {
00320 int p;
00321 int maxpos = PS[0];
00322 Automaton nfa = NULL;
00323 alist temp_id;
00324 alist_elt ptr;
00325 astate temp_state,current_state;
00326 alist L;
00327 char used_letter[MAX_TRANSITION_LETTERS];
00328
00329 nfa = s_automaton_create();
00330 L = alist_create();
00331
00332
00333 temp_id = s_automaton_id_create(init_state_id);
00334 temp_state = s_automaton_state_create(temp_id);
00335 nfa->init_state = temp_state;
00336 s_automaton_add_state(nfa,temp_state);
00337 alist_add(L,temp_state);
00338
00339 while (! alist_is_empty(L))
00340 {
00341 current_state = (astate)alist_pop_first_value(L);
00342 DMSG(printf("** current state = %s\n",s_automaton_id_to_str(current_state->id)));
00343 memset(used_letter,0,sizeof(used_letter));
00344
00345 for(p=1; p < maxpos; p++)
00346 {
00347 int current_letter = ptl[p];
00348 if (used_letter[current_letter] == 0)
00349 {
00350
00351 int pos, ens = 0;
00352 for(pos = 1; pos <= maxpos; pos++)
00353 {
00354 if (ptl[pos] == current_letter &&
00355 (int)alist_elt_get_value(alist_get_first(current_state->id)) & (1 << (pos - 1)))
00356 ens |= PS[pos];
00357 }
00358
00359 if (ens)
00360 {
00361 temp_id = s_automaton_id_create(ens);
00362 temp_state = s_automaton_get_state(nfa,temp_id);
00363 if (temp_state == NULL)
00364 {
00365 temp_state = s_automaton_state_create(temp_id);
00366 s_automaton_add_state (nfa,temp_state);
00367 current_state->next[current_letter] = temp_state;
00368 alist_add(L,temp_state);
00369 }
00370 else
00371 {
00372 alist_delete(temp_id);
00373 current_state->next[current_letter] = temp_state;
00374 }
00375 }
00376 used_letter[current_letter] = 1;
00377 }
00378 }
00379 }
00380
00381 alist_delete(L);
00382
00383 for(ptr = alist_get_first(nfa->states); ptr ; ptr = alist_get_next(nfa->states,ptr))
00384 {
00385 astate s = (astate)alist_elt_get_value(ptr);
00386 if ((int)alist_elt_get_value(alist_get_first(s->id)) & (1 << (maxpos - 1)))
00387 s->accept = 1;
00388 }
00389
00390 return nfa;
00391 }
00392
00393
00394
00395
00396
00397 static alist
00398 s_automaton_successor(alist S, int letter, Automaton nfa, struct search_RegE_list_t *list)
00399 {
00400 alist R,r;
00401 alist_elt ptr;
00402 R = alist_create();
00403
00404 for(ptr = alist_get_first(S); ptr ; ptr = alist_get_next(S,ptr))
00405 {
00406 int i;
00407 alist t, Ry; astate y,z;
00408
00409 i = (int)alist_elt_get_value(ptr);
00410 t = s_automaton_id_create(i);
00411 assert(y = s_automaton_get_state(nfa,t));
00412 alist_delete(t);
00413
00414 Ry = alist_create();
00415
00416 if ((z = y->next[letter]) != NULL)
00417 {
00418 r = s_automaton_successor(z->id,RE_EPSILON,nfa, list);
00419 alist_insert(Ry,r);
00420 alist_delete(r);
00421 alist_insert(Ry,z->id);
00422 }
00423
00424
00425 if ((z = y->next[RE_EPSILON]) != NULL)
00426 {
00427 r = s_automaton_successor(z->id,letter,nfa, list);
00428 alist_insert(Ry,r);
00429 alist_delete(r);
00430 }
00431
00432 if (letter < RE_FINAL_TOK)
00433 {
00434 for(i = 0 ; i < DIC_SEARCH_REGE_LIST ; i++)
00435 if (list->valid[i])
00436 {
00437 if (list->letters[i][letter] && (z = y->next[(int)list->symbl[i]]) != NULL)
00438 {
00439 DMSG(printf("*** letter "));
00440 DMSG(regexp_print_letter(stdout,letter));
00441 DMSG(printf("is in "));
00442 DMSG(regexp_print_letter(stdout,i));
00443
00444 r = s_automaton_successor(z->id,RE_EPSILON,nfa, list);
00445 alist_insert(Ry,r);
00446 alist_delete(r);
00447 alist_insert(Ry,z->id);
00448 }
00449 }
00450 }
00451
00452 #if 0
00453 if (alist_is_empty(Ry))
00454 return Ry;
00455 #endif
00456
00457 alist_insert(R,Ry);
00458 alist_delete(Ry);
00459 }
00460
00461 return R;
00462 }
00463
00464 static void
00465 s_automaton_node_set_accept(astate s, Automaton nfa)
00466 {
00467 void* idx;
00468 alist_elt ptr;
00469
00470 DMSG(printf("=== setting accept for node (%s) :",s_automaton_id_to_str(s->id)));
00471 for(ptr = alist_get_first(nfa->states) ; ptr ; ptr = alist_get_next(nfa->states,ptr))
00472 {
00473 astate ns = (astate)alist_elt_get_value(ptr);
00474 idx = alist_elt_get_value(alist_get_first(ns->id));
00475 DMSG(printf("%s ",s_automaton_id_to_str(ns->id)));
00476 if (ns->accept && alist_is_in(s->id,idx))
00477 {
00478 DMSG(printf("(ok) "));
00479 s->accept = 1;
00480 }
00481 }
00482 DMSG(printf("\n"));
00483 }
00484
00485 static Automaton
00486 s_automaton_NFA_to_DFA(Automaton nfa, struct search_RegE_list_t *list)
00487 {
00488 Automaton dfa = NULL;
00489 alist temp_id;
00490 alist_elt ptr;
00491 astate temp_state, current_state;
00492 alist L;
00493 int letter;
00494
00495 dfa = s_automaton_create();
00496 L = alist_create();
00497
00498 temp_id = alist_clone(nfa->init_state->id);
00499 temp_state = s_automaton_state_create(temp_id);
00500 dfa->init_state = temp_state;
00501 s_automaton_add_state(dfa,temp_state);
00502 alist_add(L,temp_state);
00503 while (! alist_is_empty(L))
00504 {
00505 current_state = (astate)alist_pop_first_value(L);
00506 DMSG(printf("** current state = %s\n",s_automaton_id_to_str(current_state->id)));
00507 for(letter = 1; letter < DIC_LETTERS; letter++)
00508 {
00509
00510
00511 temp_id = s_automaton_successor(current_state->id,letter,nfa,list);
00512
00513 if (! alist_is_empty(temp_id))
00514 {
00515
00516 DMSG(printf("*** successor of %s for ",s_automaton_id_to_str(current_state->id)));
00517 DMSG(regexp_print_letter(stdout,letter));
00518 DMSG(printf(" = %s\n", s_automaton_id_to_str(temp_id)));
00519
00520 temp_state = s_automaton_get_state(dfa,temp_id);
00521
00522
00523
00524 if (temp_state == NULL)
00525 {
00526 temp_state = s_automaton_state_create(temp_id);
00527 s_automaton_add_state(dfa,temp_state);
00528 current_state->next[letter] = temp_state;
00529 alist_add(L,temp_state);
00530 }
00531 else
00532 {
00533 alist_delete(temp_id);
00534 current_state->next[letter] = temp_state;
00535 }
00536 }
00537 else
00538 {
00539 alist_delete(temp_id);
00540 }
00541 }
00542 }
00543
00544 for(ptr = alist_get_first(dfa->states) ; ptr ; ptr = alist_get_next(dfa->states,ptr))
00545 {
00546 astate s = (astate)alist_elt_get_value(ptr);
00547 s_automaton_node_set_accept(s,nfa);
00548 }
00549
00550 alist_delete(L);
00551 return dfa;
00552 }
00553
00554
00555
00556
00557
00558 static automaton
00559 s_automaton_finalize(Automaton a)
00560 {
00561 int i,l;
00562 automaton fa = NULL;
00563 alist_elt ptr;
00564 astate s;
00565
00566 if (a == NULL)
00567 return NULL;
00568
00569
00570 fa = (automaton)malloc(sizeof(struct automaton_t));
00571 fa->nstates = a->nstates;
00572 fa->accept = (int*) malloc((fa->nstates + 1)*sizeof(int));
00573 memset(fa->accept,0,(fa->nstates + 1)*sizeof(int));
00574 fa->trans = (int**)malloc((fa->nstates + 1)*sizeof(int*));
00575 for(i=0; i <= fa->nstates; i++)
00576 {
00577 fa->trans[i] = (int*)malloc(MAX_TRANSITION_LETTERS * sizeof(int));
00578 memset(fa->trans[i],0,MAX_TRANSITION_LETTERS * sizeof(int));
00579 }
00580
00581
00582 for(i = 1 , ptr = alist_get_first(a->states); ptr ; ptr = alist_get_next(a->states,ptr), i++)
00583 {
00584 s = (astate)alist_elt_get_value(ptr);
00585 s->id_static = i;
00586 }
00587
00588
00589 for(ptr = alist_get_first(a->states); ptr ; ptr = alist_get_next(a->states,ptr))
00590 {
00591 s = (astate)alist_elt_get_value(ptr);
00592 i = s->id_static;
00593
00594 if (s == a->init_state)
00595 fa->init = i;
00596 if (s->accept == 1)
00597 fa->accept[i] = 1;
00598
00599 for(l=0; l < MAX_TRANSITION_LETTERS; l++)
00600 if (s->next[l])
00601 fa->trans[i][l] = s->next[l]->id_static;
00602 }
00603
00604 return fa;
00605 }
00606
00607
00608
00609
00610
00611
00612 static void
00613 s_automaton_print_nodes(FILE* f, Automaton a)
00614 {
00615 char * sid;
00616 astate s;
00617 alist_elt ptr;
00618 for(ptr = alist_get_first(a->states) ; ptr != NULL ; ptr = alist_get_next(a->states,ptr))
00619 {
00620 s = alist_elt_get_value(ptr);
00621 sid = s_automaton_id_to_str(s->id);
00622 fprintf(f,"\t\"%s\" [label = \"%s\"",sid,sid);
00623 if (s == a->init_state)
00624 {
00625 fprintf(f,", style = filled, color=lightgrey");
00626 }
00627 if (s->accept)
00628 {
00629 fprintf(f,", shape = doublecircle");
00630 }
00631 fprintf(f,"];\n");
00632 }
00633 fprintf(f,"\n");
00634 }
00635
00636 static void
00637 s_automaton_print_edges(FILE* f, Automaton a)
00638 {
00639 int letter;
00640 char * sid;
00641 astate s;
00642 alist_elt ptr;
00643 for(ptr = alist_get_first(a->states) ; ptr != NULL ; ptr = alist_get_next(a->states,ptr))
00644 {
00645 s = (astate)alist_elt_get_value(ptr);
00646 for(letter=0; letter < 255; letter++)
00647 {
00648 if (s->next[letter])
00649 {
00650 sid = s_automaton_id_to_str(s->id);
00651 fprintf(f,"\t\"%s\" -> ",sid);
00652 sid = s_automaton_id_to_str(s->next[letter]->id);
00653 fprintf(f,"\"%s\" [label = \"",sid);
00654 regexp_print_letter(f,letter);
00655 fprintf(f,"\"];\n");
00656 }
00657 }
00658 }
00659 }
00660
00661 static void
00662 s_automaton_dump(Automaton a, char* filename)
00663 {
00664 FILE* f;
00665 #ifdef HAVE_SYS_WAIT_H
00666 pid_t pid;
00667 #endif
00668 if (a == NULL)
00669 return;
00670 f=fopen(filename,"w");
00671 fprintf(f,"digraph automaton {\n");
00672 s_automaton_print_nodes(f,a);
00673 s_automaton_print_edges(f,a);
00674 fprintf(f,"fontsize=20;\n");
00675 fprintf(f,"}\n");
00676 fclose(f);
00677
00678 #ifdef HAVE_SYS_WAIT_H
00679 pid = fork ();
00680 if (pid > 0) {
00681 wait(NULL);
00682 } else if (pid == 0) {
00683 execlp("dotty","dotty",filename,NULL);
00684 printf("exec dotty failed\n");
00685 exit(1);
00686 }
00687 #endif
00688 }
00689
00690
00691
00692
00693