1013 lines
29 KiB
C
1013 lines
29 KiB
C
/*****************************/
|
|
/* Gestionnaire de commandes */
|
|
/*****************************/
|
|
|
|
#include "shell_commands.h"
|
|
|
|
/******************************************************************************/
|
|
/* Récupération des automates désignés par une commande */
|
|
/******************************************************************************/
|
|
|
|
genob *shell_genob_from_command(com_command *thecom) {
|
|
// Si la commande est mal formée
|
|
if (thecom == NULL || thecom->main == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
// On récupère l'objet correspondant au premier maillon
|
|
int i = object_get_from_name(thecom->main->string);
|
|
if (i == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
// L'objet généralisé qu'on va retourner
|
|
genob *new = NULL;
|
|
|
|
// La chaîne complète
|
|
string_chain *thechain = thecom->main;
|
|
|
|
// Tant qu'il y a des maillons
|
|
while (thechain != NULL) {
|
|
// On prend le prochain maillon
|
|
thechain = thechain->next;
|
|
// On regarde le type de l'objet
|
|
switch (objects[i]->type) {
|
|
case LANGUAGE: {
|
|
// Si il n'y pas de maillon suivant et pas de paramètre
|
|
// La commande désigne simplement le langage
|
|
if (thechain == NULL && thecom->params == NULL) {
|
|
MALLOC(new, 1);
|
|
new->type = OG_LANG;
|
|
new->theob = objects[i]->lan;
|
|
return new;
|
|
}
|
|
|
|
// Sinon la commande continue pour désigner l'automate minimal.
|
|
com_keyword key = key_from_string_chain(thechain);
|
|
switch (key) {
|
|
case CM_MINI:
|
|
i = shell_compute_minimal(i);
|
|
break;
|
|
|
|
default:
|
|
return NULL;
|
|
break;
|
|
}
|
|
} break;
|
|
case AUTOMATON: {
|
|
// Pour l'instant seul le cas d'un automate simple est géré
|
|
if (thechain == NULL && thecom->params == NULL) {
|
|
MALLOC(new, 1);
|
|
new->type = OG_AUTO;
|
|
new->theob = objects[i]->aut->nfa;
|
|
return new;
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/******************************/
|
|
/* Application d'une commande */
|
|
/******************************/
|
|
|
|
static bool com_apply_command_rec(string_chain *thechain, com_parameters *pars,
|
|
int i) {
|
|
if (i == -1) {
|
|
shell_command_error();
|
|
return false;
|
|
}
|
|
|
|
switch (objects[i]->type) {
|
|
case LANGUAGE: {
|
|
language *thelang = objects[i]->lan;
|
|
if (thechain == NULL && pars == NULL) {
|
|
if (thelang->type == SPE_REG) {
|
|
fprintf(stdout,
|
|
"This language is specified by a regular expression:\n");
|
|
reg_print(thelang->reg);
|
|
}
|
|
else if (thelang->type == SPE_NFA) {
|
|
fprintf(stdout, "This language is specified by an automaton:\n");
|
|
nfa_view(objects[thelang->nfa]->aut->nfa);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
com_keyword key = key_from_string_chain(thechain);
|
|
|
|
switch (key) {
|
|
case CM_MINI:
|
|
shell_compute_minimal(i);
|
|
return com_apply_command_rec(thechain->next, pars, thelang->minauto);
|
|
break;
|
|
|
|
default:
|
|
shell_command_error();
|
|
return false;
|
|
break;
|
|
}
|
|
} break;
|
|
case AUTOMATON: {
|
|
automata *theauto = objects[i]->aut;
|
|
if (thechain == NULL && pars == NULL) {
|
|
print_title_box(100, true, stdout, 1, "Automaton.");
|
|
nfa_view(theauto->nfa);
|
|
return true;
|
|
}
|
|
com_keyword key = key_from_string_chain_single(thechain);
|
|
switch (key) {
|
|
case CM_RUN:
|
|
shell_make_nfa_run(theauto, pars);
|
|
break;
|
|
|
|
default:
|
|
shell_command_error();
|
|
return false;
|
|
break;
|
|
}
|
|
} break;
|
|
default:
|
|
shell_command_error();
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool com_apply_command(com_command *thecom) {
|
|
if (thecom == NULL || thecom->main == NULL) {
|
|
shell_command_error();
|
|
return false;
|
|
}
|
|
|
|
// On commence par regarder si le premier maillon de la commande correspond
|
|
// à
|
|
// une variable.
|
|
int i = object_get_from_name(thecom->main->string);
|
|
if (i != -1) {
|
|
// Si c'est le cas, la commande est récursive
|
|
return com_apply_command_rec(thecom->main->next, thecom->params, i);
|
|
}
|
|
|
|
// Sinon, le premier maillon doit être le seul et doit correspondre à un
|
|
// keyword
|
|
if (thecom->main->next) {
|
|
shell_command_error();
|
|
return false;
|
|
}
|
|
|
|
com_keyword key = string_to_keyword(thecom->main->string);
|
|
switch (key) {
|
|
case CM_SAVE:
|
|
return shell_save_to_file(thecom->params);
|
|
break;
|
|
case CM_CODE:
|
|
return shell_code_to_file(thecom->params);
|
|
break;
|
|
case CM_SAVESESSION:
|
|
return shell_save_session(thecom->params);
|
|
break;
|
|
case CM_LOADSESSION:
|
|
return shell_load_session(thecom->params);
|
|
break;
|
|
case CM_DELETE:
|
|
return shell_delete(thecom->params);
|
|
break;
|
|
case CM_RESET:
|
|
return shell_reset(thecom->params);
|
|
break;
|
|
case CM_SORT:
|
|
return shell_sort(thecom->params);
|
|
break;
|
|
case CM_BMCK:
|
|
return shell_mccluskey_reg(NULL, thecom->params);
|
|
break;
|
|
case CM_THOMPSON:
|
|
return shell_thompson_nfa(NULL, thecom->params);
|
|
break;
|
|
case CM_GLUSHKOV:
|
|
return shell_glushkov_nfa(NULL, thecom->params);
|
|
break;
|
|
case CM_HOPCROFT:
|
|
return shell_hopcroft_nfa(NULL, thecom->params);
|
|
break;
|
|
case CM_MIRROR:
|
|
return shell_mirror_nfa(NULL, thecom->params);
|
|
break;
|
|
case CM_TRIMNFA:
|
|
return shell_trim_nfa(NULL, thecom->params);
|
|
break;
|
|
case CM_KLEENE:
|
|
return shell_kleene_nfa(NULL, thecom->params);
|
|
break;
|
|
case CM_INTERSEC:
|
|
return shell_intersect_nfa(NULL, thecom->params);
|
|
break;
|
|
case CM_CONCAT:
|
|
return shell_concat_nfa(NULL, thecom->params);
|
|
break;
|
|
case CM_UNION:
|
|
return shell_union_nfa(NULL, thecom->params);
|
|
break;
|
|
case CM_DETERMIN:
|
|
return shell_determinize_nfa(NULL, thecom->params);
|
|
break;
|
|
case CM_MINI:
|
|
case CM_BRZOZO:
|
|
return shell_minimize_nfa(NULL, thecom->params);
|
|
break;
|
|
case CM_OPEN:
|
|
return shell_open_object(NULL, thecom->params);
|
|
break;
|
|
default:
|
|
shell_command_error();
|
|
return false;
|
|
break;
|
|
}
|
|
shell_command_error();
|
|
return false;
|
|
}
|
|
|
|
int com_apply_link_command(char *name, com_command *thecom) {
|
|
if (thecom == NULL || thecom->main == NULL) {
|
|
shell_command_error();
|
|
return -1;
|
|
}
|
|
if (!check_varname(name)) {
|
|
return -1;
|
|
}
|
|
|
|
// Premier cas: la commande est juste un texte à traiter comme une regexp
|
|
if (thecom->thetype == CMT_RAW) {
|
|
regexp *myexp;
|
|
myexp = parse_string_regexp(thecom->main->string);
|
|
|
|
if (myexp == NULL) {
|
|
return -1;
|
|
}
|
|
int i = object_add_language_reg(name, myexp);
|
|
reg_print(myexp);
|
|
return i;
|
|
}
|
|
|
|
// Si le premier maillon est un nom de variable, alors il s'agit juste de
|
|
// faire une copie
|
|
int i = index_from_string_chain(thecom->main);
|
|
if (i != -1 && thecom->params == NULL) {
|
|
object_copy_generic(i, name);
|
|
return true;
|
|
}
|
|
|
|
// On sait maintenant que le premier argument est un keyword
|
|
// Dans ce cas il ne peut pas y avoir de nesting.
|
|
com_keyword key = key_from_string_chain_single(thecom->main);
|
|
|
|
switch (key) {
|
|
case CM_BMCK:
|
|
return shell_mccluskey_reg(name, thecom->params);
|
|
break;
|
|
case CM_THOMPSON:
|
|
return shell_thompson_nfa(name, thecom->params);
|
|
break;
|
|
case CM_GLUSHKOV:
|
|
return shell_glushkov_nfa(name, thecom->params);
|
|
break;
|
|
case CM_HOPCROFT:
|
|
return shell_hopcroft_nfa(name, thecom->params);
|
|
break;
|
|
case CM_MIRROR:
|
|
return shell_mirror_nfa(name, thecom->params);
|
|
break;
|
|
case CM_TRIMNFA:
|
|
return shell_trim_nfa(name, thecom->params);
|
|
break;
|
|
case CM_KLEENE:
|
|
return shell_kleene_nfa(name, thecom->params);
|
|
break;
|
|
case CM_INTERSEC:
|
|
return shell_intersect_nfa(name, thecom->params);
|
|
break;
|
|
case CM_CONCAT:
|
|
return shell_concat_nfa(name, thecom->params);
|
|
break;
|
|
case CM_UNION:
|
|
return shell_union_nfa(name, thecom->params);
|
|
break;
|
|
case CM_DETERMIN:
|
|
return shell_determinize_nfa(name, thecom->params);
|
|
break;
|
|
case CM_MINI:
|
|
case CM_BRZOZO:
|
|
return shell_minimize_nfa(name, thecom->params);
|
|
break;
|
|
case CM_LINK:
|
|
return shell_linktolang_nfa(name, thecom->params);
|
|
break;
|
|
case CM_OPEN:
|
|
return shell_open_object(name, thecom->params);
|
|
break;
|
|
default:
|
|
shell_command_error();
|
|
return false;
|
|
break;
|
|
}
|
|
shell_command_error();
|
|
return false;
|
|
}
|
|
|
|
/******************************/
|
|
/* Calculs de nouveaux objets */
|
|
/******************************/
|
|
|
|
// Ajout d'un nouvel objet en copiant un objet déjà existant dans la table
|
|
int object_copy_generic(int i, char *newname) {
|
|
if (i == -1) {
|
|
fprintf(stderr, "Error: this is not a valid object to copy.\n");
|
|
return -1;
|
|
}
|
|
switch (objects[i]->type) {
|
|
case AUTOMATON:
|
|
return object_add_automata(newname, nfa_copy(objects[i]->aut->nfa));
|
|
break;
|
|
case LANGUAGE:
|
|
if (objects[i]->lan->type == SPE_REG) {
|
|
return object_add_language_reg(newname, reg_copy(objects[i]->lan->reg));
|
|
}
|
|
else {
|
|
int j = object_add_automata(
|
|
newname, nfa_copy(objects[objects[i]->lan->nfa]->aut->nfa));
|
|
return object_add_language_nfa(newname, j);
|
|
}
|
|
|
|
default:
|
|
return -1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Calcule un nouveau NFA avec la méthode de Glushkov à partir d'un langage.
|
|
int shell_glushkov_nfa(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 1) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i = index_from_string_chain(pars->param->main);
|
|
if (i == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
|
|
if (i < 0 || objects[i]->type != LANGUAGE ||
|
|
objects[i]->lan->type != SPE_REG) {
|
|
fprintf(stderr, "Error: Glushkov's algorithm can only be applied to a "
|
|
"language specified by a regular expression.\n");
|
|
return -1;
|
|
}
|
|
DEBUG("Computing an automaton from a language");
|
|
nfa *automaton = reg_glushkov(objects[i]->lan->reg);
|
|
if (automaton == NULL) {
|
|
fprintf(stderr, "Error: unable to compute the Glushkov automaton.\n"
|
|
"Please implement reg_glushkov().\n");
|
|
return -1;
|
|
}
|
|
if (varname) {
|
|
return object_add_automata(varname, automaton);
|
|
}
|
|
else {
|
|
nfa_view(automaton);
|
|
nfa_delete(automaton);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Calcule le miroir d'un nfa à partir d'un langage.
|
|
int shell_mirror_nfa(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 1) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i = index_from_string_chain(pars->param->main);
|
|
if (i == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
|
|
if (i < 0 || objects[i]->type != AUTOMATON) {
|
|
fprintf(stderr, "Error: Can only make the mirror of a NFA.\n");
|
|
return -1;
|
|
}
|
|
DEBUG("Computing the mirror of an automaton");
|
|
nfa *automaton = nfa_mirror(objects[i]->aut->nfa);
|
|
if (automaton == NULL) {
|
|
fprintf(stderr, "Error: unable to compute the mirror automaton.\n"
|
|
"Please implement nfa_mirror().\n");
|
|
return -1;
|
|
}
|
|
if (varname) {
|
|
return object_add_automata(varname, automaton);
|
|
}
|
|
else {
|
|
nfa_view(automaton);
|
|
nfa_delete(automaton);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int shell_hopcroft_nfa(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 1) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i = index_from_string_chain(pars->param->main);
|
|
if (i == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
|
|
if (i < 0 || objects[i]->type != AUTOMATON) {
|
|
fprintf(stderr, "Error: Can only minimize a NFA.\n");
|
|
return -1;
|
|
}
|
|
DEBUG("Minimizing with Hopcroft");
|
|
nfa *automaton = nfa_hopcroft(objects[i]->aut->nfa);
|
|
if (automaton == NULL) {
|
|
fprintf(stderr, "Error: unable to compute the Hopcroft automaton.\n"
|
|
"Please implement nfa_hopcroft().\n");
|
|
return -1;
|
|
}
|
|
if (varname) {
|
|
return object_add_automata(varname, automaton);
|
|
}
|
|
else {
|
|
nfa_view(automaton);
|
|
nfa_delete(automaton);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int shell_mccluskey_reg(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 1) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i = index_from_string_chain(pars->param->main);
|
|
if (i == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
|
|
if (i < 0 || objects[i]->type != AUTOMATON) {
|
|
fprintf(stderr, "Error: Brzozowski and McCluskey's algorithm can only be "
|
|
"applied to a NFA.\n");
|
|
return -1;
|
|
}
|
|
DEBUG("Computing a regular expression from an automaton");
|
|
regexp *exp = nfa_mccluskey(objects[i]->aut->nfa);
|
|
if (exp == NULL) {
|
|
fprintf(stderr, "Error: unable to compute the regular expression.\n"
|
|
"Please implement nfa_mccluskey().\n");
|
|
return -1;
|
|
}
|
|
if (varname) {
|
|
return object_add_language_reg(varname, exp);
|
|
}
|
|
else {
|
|
reg_print(exp);
|
|
reg_free(exp);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Calcule un nouveau NFA avec la méthode de thompson à partir d'un langage.
|
|
int shell_thompson_nfa(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 1) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i = index_from_string_chain(pars->param->main);
|
|
if (i == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
|
|
if (i < 0 || objects[i]->type != LANGUAGE ||
|
|
objects[i]->lan->type != SPE_REG) {
|
|
fprintf(stderr, "Error: Thomson's algorithm can only be applied to a "
|
|
"language specified by a regular expression.\n");
|
|
return -1;
|
|
}
|
|
DEBUG("Computing an automaton from a language");
|
|
nfa *automaton = reg_thompson(objects[i]->lan->reg);
|
|
if (automaton == NULL) {
|
|
fprintf(stderr, "Error: unable to compute the Thompson automaton.\n"
|
|
"Please implement reg_thompson().\n");
|
|
return -1;
|
|
}
|
|
if (varname) {
|
|
return object_add_automata(varname, automaton);
|
|
}
|
|
else {
|
|
nfa_view(automaton);
|
|
nfa_delete(automaton);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Union de deux NFAs
|
|
int shell_union_nfa(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 2) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i1 = index_from_string_chain(pars->param->main);
|
|
int i2 = index_from_string_chain(pars->next->param->main);
|
|
if (i1 == -1 || i2 == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
if (i1 < 0 || i2 < 0 || objects[i1]->type != AUTOMATON ||
|
|
objects[i2]->type != AUTOMATON) {
|
|
fprintf(stderr,
|
|
"Error: The union algorithm requires two automata as input.\n");
|
|
return -1;
|
|
}
|
|
nfa *automaton = nfa_union(objects[i1]->aut->nfa, objects[i2]->aut->nfa);
|
|
|
|
if (automaton == NULL) {
|
|
fprintf(stderr, "Error: unable to compute the union.\n"
|
|
"Please implement nfa_union().\n");
|
|
return -1;
|
|
}
|
|
if (varname) {
|
|
return object_add_automata(varname, automaton);
|
|
}
|
|
else {
|
|
nfa_view(automaton);
|
|
nfa_delete(automaton);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Concatène deux NFAs
|
|
int shell_concat_nfa(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 2) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i1 = index_from_string_chain(pars->param->main);
|
|
int i2 = index_from_string_chain(pars->next->param->main);
|
|
if (i1 == -1 || i2 == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
if (i1 < 0 || i2 < 0 || objects[i1]->type != AUTOMATON ||
|
|
objects[i2]->type != AUTOMATON) {
|
|
fprintf(
|
|
stderr,
|
|
"Error: The concatenation algorithm requires two automata as input.\n");
|
|
return -1;
|
|
}
|
|
nfa *automaton = nfa_concat(objects[i1]->aut->nfa, objects[i2]->aut->nfa);
|
|
|
|
if (automaton == NULL) {
|
|
fprintf(stderr, "Error: unable to compute the concatenation.\n"
|
|
"Please implement nfa_concat().\n");
|
|
return -1;
|
|
}
|
|
if (varname) {
|
|
return object_add_automata(varname, automaton);
|
|
}
|
|
else {
|
|
nfa_view(automaton);
|
|
nfa_delete(automaton);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Étoile de Kleene sur un NFA
|
|
int shell_kleene_nfa(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 1) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i = index_from_string_chain(pars->param->main);
|
|
if (i == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
if (i < 0 || objects[i]->type != AUTOMATON) {
|
|
fprintf(stderr, "Error: The Kleene star algorithm can only be applied to "
|
|
"an automaton.\n");
|
|
return -1;
|
|
}
|
|
nfa *automaton = nfa_star(objects[i]->aut->nfa);
|
|
|
|
if (automaton == NULL) {
|
|
fprintf(stderr, "Error: unable to compute the Kleene star automaton.\n"
|
|
"Please implement nfa_star().\n");
|
|
return -1;
|
|
}
|
|
if (varname) {
|
|
return object_add_automata(varname, automaton);
|
|
}
|
|
else {
|
|
nfa_view(automaton);
|
|
nfa_delete(automaton);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Calcule un nouveau NFA en supprimant tous les états non-accessibles ou non
|
|
// co-accessibles
|
|
int shell_trim_nfa(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 1) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i = index_from_string_chain(pars->param->main);
|
|
if (i == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
if (i < 0 || objects[i]->type != AUTOMATON) {
|
|
fprintf(stderr, "Error: Can only trim an automaton.\n");
|
|
return -1;
|
|
}
|
|
|
|
nfa *automaton = nfa_trim(objects[i]->aut->nfa);
|
|
|
|
if (automaton == NULL) {
|
|
fprintf(stderr, "Error: unable to compute the trimmed automaton.\n"
|
|
"Please implement nfa_trim().\n");
|
|
return -1;
|
|
}
|
|
|
|
if (varname) {
|
|
return object_add_automata(varname, automaton);
|
|
}
|
|
else {
|
|
nfa_view(automaton);
|
|
nfa_delete(automaton);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Calcule un nouveau NFA en réalisant l'intersection de deux NFAs existants
|
|
int shell_intersect_nfa(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 2) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i1 = index_from_string_chain(pars->param->main);
|
|
int i2 = index_from_string_chain(pars->next->param->main);
|
|
if (i1 == -1 || i2 == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
if (i1 < 0 || i2 < 0 || objects[i1]->type != AUTOMATON ||
|
|
objects[i2]->type != AUTOMATON) {
|
|
fprintf(
|
|
stderr,
|
|
"Error: The intersection algorithm requires two automata as input.\n");
|
|
return -1;
|
|
}
|
|
nfa *automaton =
|
|
nfa_intersect(objects[i1]->aut->nfa, objects[i2]->aut->nfa, true);
|
|
|
|
if (automaton == NULL) {
|
|
fprintf(stderr, "Error: unable to compute the intersection automaton.\n"
|
|
"Please implement nfa_intersect().\n");
|
|
return -1;
|
|
}
|
|
|
|
if (varname) {
|
|
return object_add_automata(varname, automaton);
|
|
}
|
|
else {
|
|
nfa_view(automaton);
|
|
nfa_delete(automaton);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Calcule un nouveau NFA déterministe complet en déterminisant un NFA déjà
|
|
// existant
|
|
int shell_determinize_nfa(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 1) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i = index_from_string_chain(pars->param->main);
|
|
if (i == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
if (i < 0 || objects[i]->type != AUTOMATON) {
|
|
fprintf(stderr, "Error: The subset construction can only be applied to an "
|
|
"automaton.\n");
|
|
return -1;
|
|
}
|
|
|
|
nfa *automaton = nfa_determinize(objects[i]->aut->nfa, true);
|
|
|
|
if (automaton == NULL) {
|
|
fprintf(stderr, "Error: unable to compute the determinized automaton.\n"
|
|
"Please implement nfa_determinize().\n");
|
|
return -1;
|
|
}
|
|
|
|
if (varname) {
|
|
return object_add_automata(varname, automaton);
|
|
}
|
|
else {
|
|
nfa_view(automaton);
|
|
nfa_delete(automaton);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Calcule un automate minimal à partir d'un NFA
|
|
int shell_minimize_nfa(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 1) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i = index_from_string_chain(pars->param->main);
|
|
if (i == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
if (i < 0 || objects[i]->type != AUTOMATON) {
|
|
fprintf(stderr, "Error: the minimization algorithm can only be applied to "
|
|
"an automaton.\n");
|
|
return -1;
|
|
}
|
|
nfa *automaton = nfa_brzozowski(objects[i]->aut->nfa);
|
|
|
|
if (automaton == NULL) {
|
|
fprintf(stderr, "Error: unable to compute the minimal automaton by "
|
|
"Brzozowski's algorithm.\n"
|
|
"Please implement nfa_brzozowski().\n");
|
|
return -1;
|
|
}
|
|
|
|
if (varname) {
|
|
return object_add_automata(varname, automaton);
|
|
}
|
|
else {
|
|
nfa_view(automaton);
|
|
nfa_delete(automaton);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Links an existing nfa to a nex language
|
|
int shell_linktolang_nfa(char *varname, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 1) {
|
|
shell_arguments_error();
|
|
return -1;
|
|
}
|
|
int i = index_from_string_chain(pars->param->main);
|
|
if (i == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
if (i < 0 || objects[i]->type != AUTOMATON) {
|
|
fprintf(stderr, "Error: the argument should be an automata variable.\n");
|
|
return -1;
|
|
}
|
|
return object_add_language_nfa(varname, i);
|
|
}
|
|
|
|
// Sauvegarde d'un objet
|
|
bool shell_save_to_file(com_parameters *params) {
|
|
if (com_nbparams(params) != 2) {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
com_command **pararray = com_getparamarray(params);
|
|
int i = index_from_string_chain(pararray[0]->main);
|
|
if (i == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
if (!com_israw(pararray[1])) {
|
|
fprintf(stderr, "Error: cannot parse the filename\n");
|
|
return false;
|
|
}
|
|
char *filename = pararray[1]->main->string;
|
|
printf("saving %s in the file: \"%s\".\n", params->param->main->string,
|
|
filename);
|
|
files_save_object(objects[i], filename);
|
|
free(pararray);
|
|
return true;
|
|
}
|
|
|
|
// Sauvegarde sous forme de code d'un automate
|
|
bool shell_code_to_file(com_parameters *params) {
|
|
if (com_nbparams(params) != 2) {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
com_command **pararray = com_getparamarray(params);
|
|
int i = index_from_string_chain(pararray[0]->main);
|
|
if (i == -1) {
|
|
shell_variable_error();
|
|
return false;
|
|
}
|
|
|
|
if (objects[i]->type != AUTOMATON) {
|
|
fprintf(stderr, "Error: code can only be applied to an automaton\n");
|
|
return false;
|
|
}
|
|
|
|
if (!com_israw(pararray[1])) {
|
|
fprintf(stderr, "Error: cannot parse the filename\n");
|
|
return false;
|
|
}
|
|
char *filename = pararray[1]->main->string;
|
|
printf("sending the code of %s in file \"%s\".\n",
|
|
params->param->main->string, filename);
|
|
nfa2code(objects[i]->aut->nfa, filename);
|
|
free(pararray);
|
|
return true;
|
|
}
|
|
|
|
// Sauvegarde d'une session complète
|
|
bool shell_save_session(com_parameters *params) {
|
|
if (com_nbparams(params) != 1) {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
if (!com_israw(params->param)) {
|
|
fprintf(stderr, "Error: cannot parse the filename\n");
|
|
return false;
|
|
}
|
|
char *filename = params->param->main->string;
|
|
printf("saving the session in the file: \"%s\".\n", filename);
|
|
files_save_session(filename);
|
|
return false;
|
|
}
|
|
|
|
// Chargement d'une session à partir d'un fichier
|
|
bool shell_load_session(com_parameters *params) {
|
|
if (com_nbparams(params) != 1) {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
if (!com_israw(params->param)) {
|
|
fprintf(stderr, "Error: cannot parse the filename\n");
|
|
return false;
|
|
}
|
|
char *filename = params->param->main->string;
|
|
printf("loading the session saved in the file: \"%s\".\n", filename);
|
|
files_load_session(filename);
|
|
return false;
|
|
}
|
|
|
|
// Suppression d'un objet
|
|
int shell_delete(com_parameters *params) {
|
|
if (com_nbparams(params) != 1 || !com_single(params->param)) {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
return object_delete_from_name(params->param->main->string);
|
|
}
|
|
|
|
// Effacement des noms d'un automate
|
|
int shell_reset(com_parameters *params) {
|
|
if (com_nbparams(params) != 1 || !com_single(params->param)) {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
int i = object_get_from_name(params->param->main->string);
|
|
if (i == -1) {
|
|
fprintf(stderr, "Error: unknown variable.\n");
|
|
return -1;
|
|
}
|
|
|
|
if (objects[i]->type != AUTOMATON || objects[i]->aut == NULL) {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
nfa_reset_state_names(objects[i]->aut->nfa);
|
|
return true;
|
|
}
|
|
|
|
// Tri des objets
|
|
bool shell_sort(com_parameters *params) {
|
|
if (params != NULL) {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
object_sort_array();
|
|
return true;
|
|
}
|
|
|
|
// Ouverture d'un objet
|
|
bool shell_open_object(char *varname, com_parameters *params) {
|
|
if (com_nbparams(params) != 1 || params->param->thetype != CMT_RAW ||
|
|
varname == NULL) {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
files_read_object(params->param->main->string, varname);
|
|
return true;
|
|
}
|
|
|
|
// Calcul d'un NFA aléatoire
|
|
bool shell_random_nfa(char *, com_parameters *, bool) {
|
|
/* if (com_nbparams(params) != 3) {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
com_command* arg1 = params->param;
|
|
com_command* arg2 = params->next->param;
|
|
com_command* arg3 = params->next->next->param;
|
|
if (!com_single(arg1) || !com_single(arg2) || !com_single(arg3)) {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
|
|
char* end;
|
|
int nb1 = strtol(arg1->main->string, &end, 10);
|
|
if (*end != '\0') {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
int nb2 = strtol(arg2->main->string, &end, 10);
|
|
if (*end != '\0') {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
int nb3 = strtol(arg3->main->string, &end, 10);
|
|
if (*end != '\0') {
|
|
shell_arguments_error();
|
|
return false;
|
|
} */
|
|
|
|
return false;
|
|
/* if (det)
|
|
return object_add_automata(varname, dfa_random(nb1, nb2, nb3));
|
|
else
|
|
return object_add_automata(varname, nfa_random(nb1, nb2, nb3)); */
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* Affichage - fonctions appellées par le gestionnaire de commandes */
|
|
/********************************************************************/
|
|
|
|
bool shell_make_nfa_run(automata *aut, com_parameters *pars) {
|
|
if (com_nbparams(pars) != 1 || !com_single(pars->param)) {
|
|
shell_arguments_error();
|
|
return false;
|
|
}
|
|
dequeue *states = nfa_compute_runs(aut->nfa, pars->param->main->string);
|
|
if (states == NULL) {
|
|
printf("Error: this is not a valid word for this automaton.\n");
|
|
return false;
|
|
}
|
|
printf("Set of states reached: ");
|
|
if (isempty_dequeue(states)) {
|
|
printf("∅.\n");
|
|
}
|
|
else {
|
|
printf("{");
|
|
for (uint i = 0; i < size_dequeue(states) - 1; i++) {
|
|
nfa_print_state(aut->nfa, lefread_dequeue(states, i), stdout);
|
|
printf(",");
|
|
}
|
|
nfa_print_state(aut->nfa, lefread_dequeue(states, size_dequeue(states) - 1),
|
|
stdout);
|
|
printf("}.\n");
|
|
}
|
|
|
|
// On teste si on a atteint un état final
|
|
uint i = 0;
|
|
uint j = 0;
|
|
while (i < size_dequeue(states) && j < size_dequeue(aut->nfa->finals)) {
|
|
if (lefread_dequeue(states, i) == lefread_dequeue(aut->nfa->finals, j)) {
|
|
printf("The word is accepted.\n");
|
|
return true;
|
|
}
|
|
else if (lefread_dequeue(states, i) <
|
|
lefread_dequeue(aut->nfa->finals, j)) {
|
|
i++;
|
|
}
|
|
else {
|
|
j++;
|
|
}
|
|
}
|
|
printf("The word is rejected.\n");
|
|
return true;
|
|
}
|