128 lines
4.6 KiB
C
128 lines
4.6 KiB
C
|
|
#include "nfa_mccluskey.h"
|
||
|
|
#include "regexp.h"
|
||
|
|
#include <stdio.h>
|
||
|
|
|
||
|
|
mccluskey_auto *nfa_to_mccluskey(nfa *thenfa) {
|
||
|
|
// Nombre d'états dans le NFA
|
||
|
|
uint n = thenfa->trans->size_graph;
|
||
|
|
|
||
|
|
// Créer l'automate généralisé avec n+2 états
|
||
|
|
mccluskey_auto *mccluskey = (mccluskey_auto *)malloc(sizeof(mccluskey_auto));
|
||
|
|
mccluskey->size = n + 2;
|
||
|
|
mccluskey->matrix = (regexp ***)malloc((n + 2) * sizeof(regexp **));
|
||
|
|
|
||
|
|
// Initialiser toutes les cellules de la matrice à NULL
|
||
|
|
for (uint i = 0; i < n + 2; i++) {
|
||
|
|
mccluskey->matrix[i] = (regexp **)malloc((n + 2) * sizeof(regexp *));
|
||
|
|
for (uint j = 0; j < n + 2; j++) {
|
||
|
|
mccluskey->matrix[i][j] = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Ajouter les transitions du NFA à l'automate généralisé
|
||
|
|
for (uint q = 0; q < n; q++) {
|
||
|
|
// 0 à taille de l'alphabet
|
||
|
|
for (uint a = 0; a < thenfa->trans->size_alpha; a++) {
|
||
|
|
// récupérer la liste des états accessibles depuis l'état `q` par une
|
||
|
|
// transition étiquetée par la lettre `a` dans le NFA
|
||
|
|
dequeue *transitions = thenfa->trans->edges[q][a];
|
||
|
|
for (uint k = 0; k < size_dequeue(transitions); k++) {
|
||
|
|
uint r = lefread_dequeue(transitions, k);
|
||
|
|
// regarde si la transition existe déjà
|
||
|
|
if (mccluskey->matrix[q + 2][r + 2] == NULL) {
|
||
|
|
// si elle n'existe pas on la crée
|
||
|
|
// on crée une expression régulière qui représentant la lettre a
|
||
|
|
mccluskey->matrix[q + 2][r + 2] = reg_letter(thenfa->alpha_names[a]);
|
||
|
|
} else {
|
||
|
|
// si elle existe on fait l'union avec la lettre a
|
||
|
|
mccluskey->matrix[q + 2][r + 2] =
|
||
|
|
reg_union(mccluskey->matrix[q + 2][r + 2],
|
||
|
|
reg_letter(thenfa->alpha_names[a]));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Ajouter les transitions de l'état initial de l'automate généralisé vers les
|
||
|
|
// états initiaux du NFA
|
||
|
|
for (uint i = 0; i < size_dequeue(thenfa->initials); i++) {
|
||
|
|
// on lie l'état initial
|
||
|
|
uint initial_state = lefread_dequeue(thenfa->initials, i);
|
||
|
|
// on crée une transition epsilon pour decaler les états initiaux du NFA
|
||
|
|
// pour n'avoir qu'un seul état initial
|
||
|
|
mccluskey->matrix[0][initial_state + 2] = reg_epsilon();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Ajouter les transitions des états finaux du NFA vers l'état final de
|
||
|
|
// l'automate généralisé
|
||
|
|
for (uint i = 0; i < size_dequeue(thenfa->finals); i++) {
|
||
|
|
// on lie l'état final
|
||
|
|
uint final_state = lefread_dequeue(thenfa->finals, i);
|
||
|
|
// on crée une transition epsilon pour decaler les états finaux du NFA pour
|
||
|
|
// n'avoir qu'un seul état final
|
||
|
|
mccluskey->matrix[final_state + 2][1] = reg_epsilon();
|
||
|
|
}
|
||
|
|
|
||
|
|
return mccluskey;
|
||
|
|
}
|
||
|
|
|
||
|
|
regexp *nfa_mccluskey(nfa *thenfa) {
|
||
|
|
// Convertir le NFA en un automate généralisé
|
||
|
|
// on recupère le mccluskey_auto de thenfa
|
||
|
|
// premiere transphormation du NFA en automate généralisé
|
||
|
|
mccluskey_auto *gen_auto = nfa_to_mccluskey(thenfa);
|
||
|
|
// Nombre d'états dans l'automate
|
||
|
|
uint n = gen_auto->size;
|
||
|
|
// on recupère la matrice de l'automate
|
||
|
|
regexp ***matrix = gen_auto->matrix;
|
||
|
|
|
||
|
|
// Appliquer l'algorithme de Brzozowski-McCluskey
|
||
|
|
// k est l'état intermédiaire que l'on veut supprimer
|
||
|
|
for (uint k = 2; k < n; ++k) {
|
||
|
|
for (uint i = 0; i < n; ++i) {
|
||
|
|
for (uint j = 0; j < n; ++j) {
|
||
|
|
// si il y a une transition de i à k et de k à j
|
||
|
|
if (matrix[i][k] != NULL && matrix[k][j] != NULL) {
|
||
|
|
regexp *new_expr;
|
||
|
|
// on crée une nouvelle transition de i à j en passant par k
|
||
|
|
// on verifie si il y a une boucle sur k
|
||
|
|
if (matrix[k][k] != NULL) {
|
||
|
|
new_expr = reg_concat(matrix[i][k], reg_star(matrix[k][k]));
|
||
|
|
|
||
|
|
new_expr = reg_concat(new_expr, matrix[k][j]);
|
||
|
|
} else {
|
||
|
|
// Créer une nouvelle expression pour la transition de i à j via k
|
||
|
|
// sans boucle
|
||
|
|
new_expr = reg_concat(matrix[i][k], matrix[k][j]);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Si une transition directe de i à j existe déjà, faire l'union des
|
||
|
|
// deux expressions
|
||
|
|
if (matrix[i][j] != NULL) {
|
||
|
|
new_expr = reg_union(matrix[i][j], new_expr);
|
||
|
|
}
|
||
|
|
// Mettre à jour la matrice avec la nouvelle expression
|
||
|
|
matrix[i][j] = new_expr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// L'expression régulière finale est dans matrix[0][1]
|
||
|
|
regexp *final_regexp = matrix[0][1];
|
||
|
|
|
||
|
|
// Libérer la mémoire de l'automate généralisé
|
||
|
|
for (uint i = 0; i < n; ++i) {
|
||
|
|
for (uint j = 0; j < n; ++j) {
|
||
|
|
if (matrix[i][j] && !(i == 0 && j == 1)) {
|
||
|
|
// reg_free(matrix[i][j]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
free(matrix[i]);
|
||
|
|
}
|
||
|
|
free(matrix);
|
||
|
|
free(gen_auto);
|
||
|
|
|
||
|
|
return final_regexp;
|
||
|
|
}
|