354 lines
9.5 KiB
C
354 lines
9.5 KiB
C
|
|
#include "shell_languages.h"
|
||
|
|
|
||
|
|
#include "error.h"
|
||
|
|
#include "shell_languages.h"
|
||
|
|
#include "nfa.h"
|
||
|
|
#include "regexp.h"
|
||
|
|
|
||
|
|
// #define MAX_LANGUAGES 2048
|
||
|
|
// language* languages[MAX_LANGUAGES];
|
||
|
|
// int nb_languages = 0;
|
||
|
|
|
||
|
|
#define MAX_OBJECTS 2048
|
||
|
|
object* objects[MAX_OBJECTS];
|
||
|
|
int nb_objects = 0;
|
||
|
|
|
||
|
|
unsigned short minicount = 0;
|
||
|
|
unsigned short syntcount = 0;
|
||
|
|
|
||
|
|
/************************/
|
||
|
|
/* Création/Suppression */
|
||
|
|
/************************/
|
||
|
|
|
||
|
|
object* object_language_new_reg(char* name, regexp* theregexp) {
|
||
|
|
object* theobject;
|
||
|
|
MALLOC(theobject, 1);
|
||
|
|
theobject->name = strdup(name);
|
||
|
|
theobject->type = LANGUAGE;
|
||
|
|
theobject->parent = -1;
|
||
|
|
language* lang;
|
||
|
|
MALLOC(lang, 1);
|
||
|
|
lang->type = SPE_REG;
|
||
|
|
lang->reg = theregexp;
|
||
|
|
lang->minauto = -1;
|
||
|
|
theobject->lan = lang;
|
||
|
|
return theobject;
|
||
|
|
}
|
||
|
|
|
||
|
|
object* object_language_new_nfa(char* name, int i) {
|
||
|
|
if (objects[i]->type != AUTOMATON) {
|
||
|
|
fprintf(stderr, "Error: this is not an automata variable.\n");
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
object* theobject;
|
||
|
|
MALLOC(theobject, 1);
|
||
|
|
theobject->name = strdup(name);
|
||
|
|
theobject->type = LANGUAGE;
|
||
|
|
theobject->parent = -1;
|
||
|
|
language* lang;
|
||
|
|
MALLOC(lang, 1);
|
||
|
|
lang->type = SPE_NFA;
|
||
|
|
lang->nfa = i;
|
||
|
|
lang->minauto = -1;
|
||
|
|
theobject->lan = lang;
|
||
|
|
return theobject;
|
||
|
|
}
|
||
|
|
|
||
|
|
object* object_automata_new(char* name, nfa* A) {
|
||
|
|
object* theobject;
|
||
|
|
MALLOC(theobject, 1);
|
||
|
|
theobject->name = strdup(name);
|
||
|
|
theobject->type = AUTOMATON;
|
||
|
|
theobject->parent = -1;
|
||
|
|
automata* aut;
|
||
|
|
MALLOC(aut, 1);
|
||
|
|
aut->nfa = A;
|
||
|
|
theobject->aut = aut;
|
||
|
|
return theobject;
|
||
|
|
}
|
||
|
|
|
||
|
|
void object_free(object* theobject) {
|
||
|
|
if (theobject == NULL) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
// Libération du nom
|
||
|
|
free(theobject->name);
|
||
|
|
|
||
|
|
switch (theobject->type) {
|
||
|
|
case AUTOMATON:
|
||
|
|
if (theobject->aut == NULL) {
|
||
|
|
free(theobject);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
nfa_delete(theobject->aut->nfa);
|
||
|
|
free(theobject->aut);
|
||
|
|
break;
|
||
|
|
case LANGUAGE:
|
||
|
|
if (theobject->lan == NULL) {
|
||
|
|
free(theobject);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
// Si le langage est spécifié par une expression,
|
||
|
|
// on la libère.
|
||
|
|
if (theobject->lan->type == SPE_REG) {
|
||
|
|
if (theobject->lan->reg) {
|
||
|
|
reg_free(theobject->lan->reg);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Si le langage est spécifié par un NFA, on enlève
|
||
|
|
// le flag qui protège ce NFA.
|
||
|
|
else if (theobject->lan->type == SPE_NFA) {
|
||
|
|
objects[theobject->lan->nfa]->parent = -1;
|
||
|
|
}
|
||
|
|
// Si le langage est associèe à un minimal, on enlève
|
||
|
|
// le flag qui protège ce minimal.
|
||
|
|
if (theobject->lan->minauto != -1) {
|
||
|
|
objects[theobject->lan->minauto]->parent = -1;
|
||
|
|
}
|
||
|
|
free(theobject->lan);
|
||
|
|
break;
|
||
|
|
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
free(theobject);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*************************************/
|
||
|
|
/* Récupération/insertion d'un objet */
|
||
|
|
/*************************************/
|
||
|
|
|
||
|
|
int object_get_from_name(char* name) {
|
||
|
|
for (int i = 0; i < nb_objects; i++) {
|
||
|
|
if (objects[i] && strcmp(objects[i]->name, name) == 0) {
|
||
|
|
return i;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
int object_delete_from_name(char* name) {
|
||
|
|
int i = object_get_from_name(name);
|
||
|
|
if (i == -1) {
|
||
|
|
fprintf(stderr, "Error: unknown variable.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
else if (objects[i] && objects[i]->parent != -1) {
|
||
|
|
fprintf(stderr, "Error: this is a protected variable.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
object_free(objects[i]);
|
||
|
|
nb_objects--;
|
||
|
|
if (nb_objects > 0) {
|
||
|
|
objects[i] = objects[nb_objects];
|
||
|
|
}
|
||
|
|
return i;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int object_add_language_reg(char* name, regexp* theregexp) {
|
||
|
|
if (theregexp == NULL) {
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nb_objects == MAX_OBJECTS) {
|
||
|
|
ERROR("Error: too many objects are already stored in memory.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
int i = object_get_from_name(name);
|
||
|
|
|
||
|
|
if (i != -1 && objects[i]->parent == -1) {
|
||
|
|
// Si il y a déjà un objet à ce nom et qu'il n'est pas protégé
|
||
|
|
DEBUG("Warning: an object with name %s already exists\n", name);
|
||
|
|
object_free(objects[i]);
|
||
|
|
objects[i] = object_language_new_reg(name, theregexp);
|
||
|
|
return i;
|
||
|
|
}
|
||
|
|
else if (i != -1 && objects[i]->parent != -1) {
|
||
|
|
fprintf(stderr, "Error: cannot assign a new object to a protected variable.\n");
|
||
|
|
reg_free(theregexp);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
objects[nb_objects++] = object_language_new_reg(name, theregexp);
|
||
|
|
return nb_objects - 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int object_add_language_nfa(char* name, int j) {
|
||
|
|
if (j == -1 || objects[j]->type != AUTOMATON) {
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nb_objects == MAX_OBJECTS) {
|
||
|
|
ERROR("Error: too many objects are already stored in memory.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
int i = object_get_from_name(name);
|
||
|
|
|
||
|
|
if (i != -1 && objects[i]->parent == -1) {
|
||
|
|
// Si il y a déjà un objet à ce nom et qu'il n'est pas protégé
|
||
|
|
DEBUG("Warning: an object with name %s already exists\n", name);
|
||
|
|
object_free(objects[i]);
|
||
|
|
objects[i] = object_language_new_nfa(name, j);
|
||
|
|
objects[j]->parent = i;
|
||
|
|
return i;
|
||
|
|
}
|
||
|
|
else if (i != -1 && objects[i]->parent != -1) {
|
||
|
|
fprintf(stderr, "Error: cannot assign a new object to a protected variable.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
objects[nb_objects++] = object_language_new_nfa(name, j);
|
||
|
|
objects[j]->parent = nb_objects - 1;
|
||
|
|
return nb_objects - 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int object_add_automata(char* name, nfa* A) {
|
||
|
|
if (A == NULL) {
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nb_objects == MAX_OBJECTS) {
|
||
|
|
ERROR("Error: too many objects are already stored in memory.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
int i = object_get_from_name(name);
|
||
|
|
|
||
|
|
// Si il y a déjà un objet à ce nom
|
||
|
|
if (i != -1 && objects[i]->parent == -1) {
|
||
|
|
DEBUG("Warning: an object with name %s already exists\n", name);
|
||
|
|
object_free(objects[i]);
|
||
|
|
objects[i] = object_automata_new(name, A);
|
||
|
|
return i;
|
||
|
|
}
|
||
|
|
else if (i != -1 && objects[i]->parent != -1) {
|
||
|
|
fprintf(stderr, "Error: cannot assign a new object to a protected variable.\n");
|
||
|
|
nfa_delete(A);
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
objects[nb_objects++] = object_automata_new(name, A);
|
||
|
|
return nb_objects - 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static int object_compare(const void* pob1, const void* pob2) {
|
||
|
|
object* ob1 = *(object* const*)pob1;
|
||
|
|
object* ob2 = *(object* const*)pob2;
|
||
|
|
if (ob1 == NULL) {
|
||
|
|
if (ob2 == NULL) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
if (ob2 == NULL) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
return strcmp(ob1->name, ob2->name);
|
||
|
|
}
|
||
|
|
|
||
|
|
void object_sort_array(void) {
|
||
|
|
qsort(objects, nb_objects, sizeof(object*), &object_compare);
|
||
|
|
}
|
||
|
|
|
||
|
|
/****************************/
|
||
|
|
/* Affichage d'informations */
|
||
|
|
/****************************/
|
||
|
|
|
||
|
|
void object_print_langs(void) {
|
||
|
|
// Calcul du nombre de langages
|
||
|
|
ushort count = 0;
|
||
|
|
for (int i = 0; i < nb_objects; i++) {
|
||
|
|
if (objects[i]->type == LANGUAGE) {
|
||
|
|
count++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
printf("#### There are %d language(s) in memory:\n\n", count);
|
||
|
|
|
||
|
|
if (count > 0) {
|
||
|
|
count = 1;
|
||
|
|
}
|
||
|
|
for (int i = 0; i < nb_objects; i++) {
|
||
|
|
if (objects[i]->type == LANGUAGE) {
|
||
|
|
printf("#### %d: %s\n", count, objects[i]->name);
|
||
|
|
if (objects[i]->lan->type == SPE_REG) {
|
||
|
|
printf(" Specified by a regular expression\n");
|
||
|
|
printf(" Regexp: ");
|
||
|
|
reg_print(objects[i]->lan->reg);
|
||
|
|
}
|
||
|
|
else if (objects[i]->lan->type == SPE_NFA) {
|
||
|
|
printf(" Specified by an automaton.\n");
|
||
|
|
}
|
||
|
|
printf("\n");
|
||
|
|
count++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void object_print_autos(void) {
|
||
|
|
// Calcul du nombre d'automates'
|
||
|
|
ushort count = 0;
|
||
|
|
for (int i = 0; i < nb_objects; i++) {
|
||
|
|
if (objects[i]->type == AUTOMATON) {
|
||
|
|
count++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
printf("#### There are %d automata in memory:\n\n", count);
|
||
|
|
|
||
|
|
if (count > 0) {
|
||
|
|
count = 1;
|
||
|
|
}
|
||
|
|
for (int i = 0; i < nb_objects; i++) {
|
||
|
|
if (objects[i]->type == AUTOMATON) {
|
||
|
|
printf("#### %d: %s\n", count, objects[i]->name);
|
||
|
|
if (objects[i]->parent != -1 && objects[objects[i]->parent]->type == LANGUAGE) {
|
||
|
|
printf(" Protected: tied to the language %s.\n",
|
||
|
|
objects[objects[i]->parent]->name);
|
||
|
|
}
|
||
|
|
printf("\n");
|
||
|
|
count++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/************************************************/
|
||
|
|
/* Calculs d'informations sur un objet existant */
|
||
|
|
/************************************************/
|
||
|
|
|
||
|
|
// Calcul du DFA minimal d'un langage
|
||
|
|
int shell_compute_minimal(int i) {
|
||
|
|
if (objects[i]->type != LANGUAGE) {
|
||
|
|
fprintf(stderr, "Should be a language.\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
language* lang = objects[i]->lan;
|
||
|
|
if (lang->minauto == -1) {
|
||
|
|
DEBUG("Computing the minimal automaton of a language");
|
||
|
|
nfa* A;
|
||
|
|
if (lang->type == SPE_REG) {
|
||
|
|
A = reg_thompson(lang->reg);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
A = objects[lang->nfa]->aut->nfa;
|
||
|
|
}
|
||
|
|
|
||
|
|
char* newname;
|
||
|
|
MALLOC(newname, 20);
|
||
|
|
sprintf(newname, "SYSMINI%04d", minicount++);
|
||
|
|
lang->minauto = object_add_automata(newname, nfa_brzozowski(A));
|
||
|
|
free(newname);
|
||
|
|
// On protège le NFA minimal qu'on a créé
|
||
|
|
objects[lang->minauto]->parent = i;
|
||
|
|
|
||
|
|
nfa_delete(A);
|
||
|
|
}
|
||
|
|
return lang->minauto;
|
||
|
|
}
|