Léo G
Messages : 12 Date d'inscription : 04/02/2015
| Sujet: Code source d'une implantation du projet Lun 2 Mar - 21:31 | |
| Voici un ensemble de fichier dont un Makefile contenant le début du projet. Ce début gère la récupération d'un CSP depuis le fichier, la construction des arbres et domaines et liste de variable. On stocke aussi dans les variables les contraintes les concernant. - module arbre:
arbre.c - Code:
-
#include "arbre.h"
arbre cons_noeud(int nature, float* valeur) { arbre a = (arbre)malloc(1 * sizeof(noeud)); /* allocation dynamique d'un noeud */ if(nature != A_IDF) a->valeur = (float*) malloc(1 * sizeof(float)); else a->valeur = valeur; a->nature = nature; a->frangin = a->fils = NULL; /* le noeud est pour l'instant une feuille sans fils ni frangin */ return a; }
void videArbre(arbre a) { if(a!=NULL) { videArbre(a->fils); /* vide le fils */ videArbre(a->frangin); /* puis vide le frangin */ if(a->nature != A_IDF) free(a->valeur); free(a); /* et enfin vide a */ } }
arbre attache_papa_frangin(arbre papa, arbre frangin) { papa->frangin = frangin; return papa; }
arbre attache_papa_fils(arbre papa, arbre fils) { papa->fils = fils; return papa; }
void afficheArbre(arbre a, int espace) { int i; for(i=0 ; i<espace ; i++) /* indentation */ fprintf(stderr, " "); if(a != NULL) { afficheArbreBis(a); /* affiche en lettre la nature du noeud (qui est un int) */ afficheArbre(a->fils, espace+2); /* affichage du fils avec une plus grande identation */ afficheArbre(a->frangin, espace); /* affichage du frangin avec une meme indentation pour donner l'impression d'un arbre en penchant la tete a gauche */ } else fprintf(stderr, "ø\n"); }
void afficheArbreBis(arbre a) { switch(a->nature) { case 10: fprintf(stderr, "IDF"); break; case 11: fprintf(stderr, "ENTIER %d", (int)(*(a->valeur)));break; case 12: fprintf(stderr, "REEL %f", *(a->valeur));break; case 13: fprintf(stderr, "BOOLEEN, %d", (int)(*(a->valeur)));break; case 14: fprintf(stderr, "SQRT"); break; case 15: fprintf(stderr, "SIN"); break; case 16: fprintf(stderr, "COS"); break; case 17: fprintf(stderr, "TAN"); break; case 18: fprintf(stderr, "ET"); break; case 19: fprintf(stderr, "OU"); break; case 20: fprintf(stderr, "NON"); break; case 21: fprintf(stderr, "EGAL"); break; case 22: fprintf(stderr, "DIFFERENT"); break; case 23: fprintf(stderr, "SUPERIEUR_OU_EGAL"); break; case 24: fprintf(stderr, "INFERIEUR_OU_EGAL"); break; case 25: fprintf(stderr, "SUPERIEUR"); break; case 26: fprintf(stderr, "INFERIEUR"); break; case 27: fprintf(stderr, "PLUS"); break; case 28: fprintf(stderr, "MOINS"); break; case 29: fprintf(stderr, "MULTIPLIE_PAR"); break; case 30: fprintf(stderr, "DIVISE_PAR"); break; case 31: fprintf(stderr, "MODULO"); break; default: fprintf(stderr, "noeud inconnu"); } fprintf(stderr, "\n"); }
float evalue_contrainte(arbre a) { switch(a->nature) { case A_IDF: return *(a->valeur); case A_ENTIER: return *(a->valeur); case A_REEL: return *(a->valeur); case A_BOOLEEN: return *(a->valeur); case A_SQRT: return sqrt(evalue_contrainte(a->fils)); case A_SIN: return sin(evalue_contrainte(a->fils)); case A_COS: return cos(evalue_contrainte(a->fils)); case A_TAN: return tan(evalue_contrainte(a->fils)); case A_ET: return (evalue_contrainte(a->fils) && evalue_contrainte(a->fils->frangin)); case A_OU: return (evalue_contrainte(a->fils) || evalue_contrainte(a->fils->frangin)); case A_NON: return (!(evalue_contrainte(a->fils))); case A_EGAL: return (evalue_contrainte(a->fils) == evalue_contrainte(a->fils->frangin)); case A_DIFFERENT: return (evalue_contrainte(a->fils) != evalue_contrainte(a->fils->frangin)); case A_SUPERIEUR_OU_EGAL: return (evalue_contrainte(a->fils) >= evalue_contrainte(a->fils->frangin)); case A_INFERIEUR_OU_EGAL: return (evalue_contrainte(a->fils) <= evalue_contrainte(a->fils->frangin)); case A_SUPERIEUR: return (evalue_contrainte(a->fils) > evalue_contrainte(a->fils->frangin)); case A_INFERIEUR: return (evalue_contrainte(a->fils) < evalue_contrainte(a->fils->frangin)); case A_PLUS: return (evalue_contrainte(a->fils) + evalue_contrainte(a->fils->frangin)); case A_MOINS: return (evalue_contrainte(a->fils) - evalue_contrainte(a->fils->frangin)); case A_MULTIPLIE_PAR: return (evalue_contrainte(a->fils) * evalue_contrainte(a->fils->frangin)); case A_DIVISE_PAR: return (evalue_contrainte(a->fils) / evalue_contrainte(a->fils->frangin)); case A_MODULO: return (float)((int)evalue_contrainte(a->fils) % (int)evalue_contrainte(a->fils->frangin)); default: return 0; } }
arbre.h - Code:
-
#ifndef _ARBRE #define _ARBRE
#include <stdlib.h> #include <stdio.h> #include <math.h>
#define A_IDF 10 #define A_ENTIER 11 #define A_REEL 12 #define A_BOOLEEN 13 #define A_SQRT 14 #define A_SIN 15 #define A_COS 16 #define A_TAN 17 #define A_ET 18 #define A_OU 19 #define A_NON 20 #define A_EGAL 21 #define A_DIFFERENT 22 #define A_SUPERIEUR_OU_EGAL 23 #define A_INFERIEUR_OU_EGAL 24 #define A_SUPERIEUR 25 #define A_INFERIEUR 26 #define A_PLUS 27 #define A_MOINS 28 #define A_MULTIPLIE_PAR 29 #define A_DIVISE_PAR 30 #define A_MODULO 31
typedef struct noeud { int nature; /* prend la valeur d'une des constantes ci dessus */ float* valeur; // on y stocke soit un reel, soit un entier, soit 0 ou 1 struct noeud* fils; /* pointeur sur le fils */ struct noeud* frangin; /* pointeur sur le frangin */ }noeud; typedef noeud* arbre;
arbre cons_noeud(int nature, float* valeur); /* alloue un noeud, en y stockant sa nature. son fils et frangin sont NULL */
void videArbre(arbre a); /* vide a en entamant par sa famille */
arbre attache_papa_frangin(arbre papa, arbre frangin); /* met dans *papa.frangin le pointeur frangin */
arbre attache_papa_fils(arbre papa, arbre fils); /* met dans *papa.fils le pointeur fils */
void afficheArbre(arbre a, int espace); /* affiche recursivement l'arbre */
void afficheArbreBis(arbre a); /* affiche en lettre la nature d'un noeud de l'arbre */
float evalue_contrainte(arbre a); /* retourne le resultat de l'expression que contient l'arbre a */
#endif
- module domaine:
domaine.c - Code:
-
#include "domaine.h" domaine creer_domaine(){ return NULL; } int est_vide(domaine d){ return (d == NULL); } int taille(domaine d){ domaine courant = d; int taille = 0; while(courant != NULL){ taille++; courant = courant->suivant; } return taille; } int deja_presente(domaine d, int value){ domaine courant = d; while(courant != NULL){ if(courant->valeur == value) return 1; courant = courant->suivant; } return 0; } int ajouter_valeur(domaine* d, int value){ //Fonction qui ajoute la valeur "au bon endroit" afin d'obtenir des domaines triés domaine courant = *d; domaine precedent; domaine maillon = malloc(sizeof(struct s_element)); if(est_vide(*d)){ //Si le domaine pointe sur NULL on l'initalise comme il faut et lui affecte value (*d) = maillon; (*d)->suivant = NULL; (*d)->precedent = NULL; (*d)->valeur = value; return 1; } maillon->valeur = value; if(!(deja_presente(*d, value))){ //On exécutera le reste uniquement si la valeur n'est pas présente dans le domaine if((*d)->valeur > value){ /* Si la valeur à ajouter est inférieure à la première valeur du domaine alors * on fait pointer le précédent du domaine sur l'élément à ajouter * et on fait commencer le domaine au nouvel élément */ (*d)->precedent = maillon; maillon->suivant = *d; *d = maillon; return 1; } //Pour les cas où on ajoute au milieu et à la fin while(courant != NULL){ if(value < courant->valeur){ /* La valeur à ajouter est inférieure à la valeur de courant alors * le suivant de l'élément à ajouter va pointer sur courant * on fait pointer le précédent de courant sur l'élément à ajouter * le précédent de l'élément à ajouter va pointer sur précédent * on fait pointer le suivant de précédent sur l'élément à ajouter */ maillon->suivant = courant; courant->precedent = maillon; maillon->precedent = precedent; precedent->suivant = maillon; return 1; } //On fait avancer les itérateurs precedent = courant; courant = courant->suivant; } if(courant == NULL){ /*On a parcouru tout le domaine sans insérer d'élément * c'est donc que sa valeur est supérieure à toutes les autres valeurs du domaine * on fait donc pointer le suivant de précédent sur l'élément à ajouter * on met le suivant de l'élément à ajouter à NULL puisqu'il est le dernier élément du domaine */ precedent->suivant = maillon; maillon->suivant = NULL; return 1; } } return 0; } void afficher_domaine(domaine d){ domaine courant = d; if(est_vide(d)) fprintf(stderr, "le domaine est vide\n"); while(courant != NULL){ fprintf(stderr, "%d ", courant->valeur); courant = courant->suivant; } fprintf(stderr,"\n"); } domaine initialiser(int borne_inf, int borne_sup){ int i; domaine new_d = NULL; if(borne_sup < borne_inf){ fprintf(stderr, "La borne supérieure est inférieure à la borne inférieure : %d < %d\n", borne_sup, borne_inf); //Dans ce cas le domaine renvoyé sera vide } for(i = borne_inf; i <= borne_sup; i++) ajouter_valeur(&new_d, i); return new_d; } domaine union_domaine(domaine d1, domaine d2){ domaine courant_d1; domaine courant_d2; domaine new_d = NULL; if(est_vide(d1)) return d2; if(est_vide(d2)) return d1; courant_d1 = d1; courant_d2 = d2; if(taille(d1) > taille(d2)){ //On parcourt les listes jusqu'à la fin de la plus petite while(courant_d2 != NULL){ ajouter_valeur(&new_d, courant_d1->valeur); ajouter_valeur(&new_d, courant_d2->valeur); courant_d1 = courant_d1->suivant; courant_d2 = courant_d2->suivant; } //Puis on termine le parcourt de la plus grande while(courant_d1 != NULL){ ajouter_valeur(&new_d, courant_d1->valeur); courant_d1 = courant_d1->suivant; } } else{ while(courant_d1 != NULL){ ajouter_valeur(&new_d, courant_d1->valeur); ajouter_valeur(&new_d, courant_d2->valeur); courant_d1 = courant_d1->suivant; courant_d2 = courant_d2->suivant; } while(courant_d2 != NULL){ ajouter_valeur(&new_d, courant_d2->valeur); courant_d2 = courant_d2->suivant; } } return new_d; } domaine intersection(domaine d1, domaine d2){ domaine courant_d1; domaine courant_d2; domaine new_d = NULL; if(est_vide(d1) || est_vide(d2)) return NULL; courant_d1 = d1; courant_d2 = d2; if(taille(d1) > taille(d2)){ while(courant_d2 != NULL){ //On ajoute uniquement si la valeur courante est aussi dans l'autre domaine if(deja_presente(d1, courant_d2->valeur)) ajouter_valeur(&new_d, courant_d2->valeur); courant_d1 = courant_d1->suivant; courant_d2 = courant_d2->suivant; } while(courant_d1 != NULL){ if(deja_presente(d2, courant_d1->valeur)) ajouter_valeur(&new_d, courant_d1->valeur); courant_d1 = courant_d1->suivant; } } else{ while(courant_d1 != NULL){ if(deja_presente(d2, courant_d1->valeur)) ajouter_valeur(&new_d, courant_d1->valeur); courant_d1 = courant_d1->suivant; courant_d2 = courant_d2->suivant; } while(courant_d2 != NULL){ if(deja_presente(d1, courant_d2->valeur)) ajouter_valeur(&new_d, courant_d2->valeur); courant_d2 = courant_d2->suivant; } } return new_d; } domaine dupliquer_domaine(domaine d){ domaine new_d = NULL; domaine courant = d; while(courant != NULL){ //Pour chaque valeur du domaine d on l'ajoutera au nouveau domaine ajouter_valeur(&new_d, courant->valeur); courant = courant->suivant; } return new_d; }
void vider_domaine(domaine d){ if(d != NULL){ vider_domaine(d->suivant); free(d); } }
listeDomaine creer_listeDomaine(){ return NULL; }
void ajouter_listeDomaine(listeDomaine* ld, domaine d){ listeDomaine new = (listeDomaine) malloc(1 * sizeof(maillonListeDomaine)); new->d = d; new->suivant = *ld; *ld = new; }
void vider_listeDomaine(listeDomaine l){ if(l != NULL){ vider_listeDomaine(l->suivant); vider_domaine(l->d); free(l); } }
domaine.h - Code:
-
#ifndef DOMAINE #define DOMAINE #include <stdio.h> #include <stdlib.h>
struct s_element{ int valeur; //Un élément du domaine possède une valeur, ici un entier struct s_element* suivant; //Un pointeur sur l'élément suivant struct s_element* precedent; //Et un autre sur l'élément précédent }; typedef struct s_element* domaine; domaine creer_domaine(); //Met à nul le domaine int est_vide(domaine); //Renvoie 1 si le domaine est vide (comprendre est NULL) 0 sinon int taille(domaine); //Renvoie la taille du domaine passé en argument int deja_presente(domaine , int); //Renvoie 1 si l'entier est déjà dans le domaine 0 sinon int ajouter_valeur(domaine* , int); //Renvoie 1 si la valeur a été ajoutée 0 sinon void afficher_domaine(domaine); //Affiche le domaine passé en argument avec un valeur par ligne domaine dupliquer_domaine(domaine); //Duplique le domaine passer en argument domaine initialiser(int borne_inf, int borne_sup); //Renvoie un domaine contenant toutes les valeurs entre borne_inf et borne_sup incluses domaine union_domaine(domaine d1, domaine d2); //Renvoie l'union des domaines d1 et d2 domaine intersection(domaine d1, domaine d2); //Renvoie l'intersection des domaines d1 et d2 void vider_domaine(domaine d); // Vide recursivement d
typedef struct maillonListeDomaine{ domaine d; struct maillonListeDomaine* suivant; }maillonListeDomaine; typedef maillonListeDomaine* listeDomaine;
listeDomaine creer_listeDomaine(); // retourne NULL void ajouter_listeDomaine(listeDomaine* ld, domaine d); // ajoute d dans ld void vider_listeDomaine(listeDomaine l); // vide ld et les domaines dedans recursivement #endif
- module listeContrainte:
listeContrainte.c - Code:
-
#include "listeContrainte.h"
listeContrainte creer_liste_contrainte() { return NULL; }
void ajouter_contrainte(listeContrainte* l, arbre a, char* presenceVariable) { // ajout en debut de liste listeContrainte new = (listeContrainte) malloc(1 * sizeof(maillonContrainte)); new->a = a; new->presenceVariable = presenceVariable; new->suivant = *l; *l = new; }
int est_vide_liste_contrainte(listeContrainte l) { return l == NULL; }
int enlever_contrainte(listeContrainte* l, int indice) { listeContrainte precedent, courant = *l; if(est_vide_liste_contrainte(*l)) return 0; if(indice == 0) // si on supprime le premier de la liste { // il faut changer l *l = (*l)->suivant; free(courant); return 1; } while(courant != NULL && indice != 0) { precedent = courant; courant = courant->suivant; indice--; } if(courant != NULL) { precedent->suivant = courant->suivant; free(courant); return 1; } return 0; }
void vider_liste_contrainte(listeContrainte* l) { while(enlever_contrainte(l, 0)) // tant qu'on arrive a enlever un element, on continue ; }
void afficher_liste_contrainte(listeContrainte l) { int i=1; fprintf(stderr, "Debut d'affichage d'un ensemble de contraintes"); while(l != NULL) { fprintf(stderr, "\nPresence de variables dans contrainte %d: %s\n", i, l->presenceVariable); fprintf(stderr, "Arbre de contrainte %d:\n", i++); afficheArbre(l->a, 0); l = l->suivant; } fprintf(stderr, "Fin d'affichage d'un ensemble de contraintes\n"); }
listeContrainte.h - Code:
-
#ifndef _LISTECONTRAINTE_ #define _LISTECONTRAINTE_
#include "arbre.h"
typedef struct maillonContrainte { arbre a; // arbre des contraintes char* presenceVariable; // chaine de 0 et 1. si presenceVariable[i] == 1, alors il y a la variable d'indice i dans l'arbre de la contrainte, sinon elle n'y est pas struct maillonContrainte* suivant; }maillonContrainte; typedef maillonContrainte* listeContrainte;
listeContrainte creer_liste_contrainte(); // renvoi un pointeur sur NULL
void ajouter_contrainte(listeContrainte* l, arbre a, char* presenceVariable); // creer une contrainte et la place au debut de l
int est_vide_liste_contrainte(listeContrainte l); // retourne 1 si l est vide, 0 sinon
int enlever_contrainte(listeContrainte* l, int indice); // retourne 1 si arrive a enlever la contrainte d'indice dans l, 0 sinon
void vider_liste_contrainte(listeContrainte* l); // vide la liste
void afficher_liste_contrainte(listeContrainte l); // affiche les arbre de chaque contraintes
#endif
- module listeVariable:
listeVariable.c - Code:
-
#include "listeVariable.h"
listeVariable creer_listeVariable() { return NULL; }
void ajouter_listeVariable(listeVariable* l, char* nom) { listeVariable new = (listeVariable) malloc(1 * sizeof(structVariable)); new->nom = nom; new->valeur = 0; new->l = creer_liste_contrainte(); new->d = creer_domaine(); new->suivant = *l; new->precedent = NULL; *l = new; }
void afficher_listeVariable(listeVariable l) { fprintf(stderr, "Debut d'affichage d'un liste de variable"); while(l != NULL) { fprintf(stderr, "\nNom variable : %s\n", l->nom); fprintf(stderr, "Valeur : %f\n", l->valeur); afficher_liste_contrainte(l->l); fprintf(stderr, "Domaine :\n"); afficher_domaine(l->d); l = l->suivant; } fprintf(stderr, "Fin d'affichage d'une liste de variable\n"); }
void concat_listeVariable(listeVariable* l1, listeVariable* l2) { listeVariable courant = *l1; if(*l1 == NULL) // si l1 est vide, la concatenantion de l1 avec l2 est l2 *l1 = *l2; else if(*l2 != NULL) {// si l2 n'est pas NULL, alors on change les pointeurs precedent du premier de l2 et suivant du dernier de l1 while(courant->suivant != NULL) // cherche le dernier pointeur de l1 courant = courant->suivant; courant->suivant = *l2; // change le dernier pointeur 'suivant' de l1 pour pointer sur le premier element de l2 (*l2)->precedent = courant; // change le premier pointeur 'preceden't de l2 pour pointer sur le dernier element de l1 } // sinon si l2 est NULL, la concatenation est de l1 avec l2 est l1 donc on change rien }
void affecterDommaine_listeVariable(listeVariable l, domaine d) { while(l != NULL) { l->d = d; l = l->suivant; } }
void affecterContraintes_listeVariable(structVariable* variable, listeContrainte* lc, int nombreVariable) { int indiceVariable=0, indiceContrainte, i; listeContrainte contrainte, courant, suivant; char* presenceVariable; while(variable != NULL) { // pour chaque variable, on va chercher et lui ajouter des contraintes contrainte = *lc; indiceContrainte = 0; while(contrainte != NULL) { // pour chaque contrainte pas encore affectee (donc presente dans lc) presenceVariable = contrainte->presenceVariable; for(i=indiceVariable+1 ; i<nombreVariable ; i++) // on regarde la presence des variables d'indice plus grand dans la contrainte if(presenceVariable[i] == '1') break; if(presenceVariable[indiceVariable] == '1' && i == nombreVariable) // si cette contrainte fait intervenir cette variable et ne fait pas intervenir de variable d'indice plus grand { // cela veut dire que on a eu aucun '1' entre (exclus) dans l'intervale d'indice ]indiceVariable, nombreVariable[ du tableau presenceVariable. donc que la contrainte ne fait intervenir aucune variable d'indice plus grand que la variable en cours. donc on enleve cette contrainte de lc et on la met dans la liste des contraintes de cette variable ajouter_contrainte(&(variable->l), contrainte->a, contrainte->presenceVariable); contrainte = contrainte->suivant; // on doit faire passer au suivant ici car on fait un free sur cette contrainte dans la fonction juste en dessous enlever_contrainte(lc, indiceContrainte); // comme on enleve la contrainte, l'indice de la prochaine ne change pas dans lc donc on ne change pas indiceContrainte } else // si on n'enleve pas la contrainte, l'indice de la prochaine est l'indice + 1 { indiceContrainte++; contrainte = contrainte->suivant; } } variable = variable->suivant; indiceVariable++; } suivant = *lc; while(suivant != NULL) { courant = suivant; suivant = courant->suivant; videArbre(courant->a); free(courant->presenceVariable); free(courant); } // arriver ici, si il reste des contraintes dans lc, elles ne font intervenir aucune variable donc des contraintes inutiles donnes par un utilisateur soucieux d'embeter le codeur de ce programme. ces dernieres lignes lui sont dedicacees. }
structVariable* retournerVariablePortantNom(listeVariable l, char* nom, int* indiceVariable) { int i=0; while(l != NULL && strcmp(l->nom, nom) != 0) { l = l->suivant; i++; } if(l == NULL) { fprintf(stderr, "Erreur ligne %d, utilisation d'une variable '%s' sans la declarer auparavant en donnant son domaine, le programme quitte donc.\n", num_ligne, nom); exit(EXIT_FAILURE); } *indiceVariable = i; return l; }
void vider_listeVariable(listeVariable l) { listeContrainte courant, suivant; if(l != NULL) { suivant = l->l; while(suivant != NULL) { courant = suivant; suivant = courant->suivant; videArbre(courant->a); free(courant->presenceVariable); free(courant); } vider_listeVariable(l->suivant); free(l->nom); free(l); } }
structVariable* premiereVariable(listeVariable l) { return l; // la premire variable est la premire de la liste }
structVariable* derniereVariable(listeVariable l) { // la derniere variable est celle dont le pointeur suivant pointe sur NULL while(l->suivant != NULL) l = l->suivant; return l; }
structVariable* variableSuivante(structVariable* variable) { return variable->suivant; }
structVariable* variablePrecedent(structVariable* variable) { return variable->precedent; }
int finListeVariable(structVariable* variable) { return (variable == NULL); }
int verifier_les_contraintes(structVariable* variable) { listeContrainte l = variable->l; while(l != NULL) { if(evalue_contrainte(l->a) == 0) return 0; l = l->suivant; } return 1; }
listeVariable.h - Code:
-
#ifndef _LISTEVARIABLE_ #define _LISTEVARIABLE_
#include <string.h> #include "listeContrainte.h" #include "domaine.h"
extern int num_ligne; // recouvre la variable num_ligne du fichier lex.l
typedef struct structVariable { char* nom; float valeur; listeContrainte l; domaine d; struct structVariable* precedent; struct structVariable* suivant; }structVariable; typedef structVariable* listeVariable;
listeVariable creer_listeVariable(); // retourne NULL
void ajouter_listeVariable(listeVariable* l, char* nom); // ajoute une variable en debut de liste
void afficher_listeVariable(listeVariable l); // affiche iterativement l
void concat_listeVariable(listeVariable* l1, listeVariable* l2); // met l2 apres l1 en modifiant l1. pour cela on change le pointeur 'suivant' du dernier element de l1 et le pointeur 'precedent' du premier de l2
void affecterDommaine_listeVariable(listeVariable l, domaine d); // met d dans toutes les variables de l
void affecterContraintes_listeVariable(structVariable* variable, listeContrainte* lc, int nombreVariable); // pour chaque variable de lv, on prend un sous-ensemble des contraintes de lc et on les met dans la liste des contraintes de cette variable. // une contrainte est mise dans la liste d'une variable // - si la contrainte fait intervenir cette variable // - si la contrainte ne fait pas intervenir de variable d'indice plus grand // si il reste des contraintes non asignee a une variable en fin de cette procedure, on les supprime
structVariable* retournerVariablePortantNom(listeVariable l, char* nom, int* indiceVariable); // retourne un pointeur sur la variable portant ce nom si elle existe, sinon quitte le programme. on place aussi l'indice de cette variable dans *indiceVariable
void vider_listeVariable(listeVariable l); // vide recursivement l
structVariable* premiereVariable(listeVariable l); // renvoi l
structVariable* derniereVariable(listeVariable l); // renvoi le dernier element de l
structVariable* variableSuivante(structVariable* variable); // renvoi variable->suivant
structVariable* variablePrecedent(structVariable* variable); // renvoi variable->precedent
int finListeVariable(structVariable* variable); // renvoi variable == NULL
int verifier_les_contraintes(structVariable* variable); // renvoi 0 si l'evaluation d'au moins un des arbres de contrainte dans variable->l vaut 0 // sinon renvoi 1 // renvoi aussi 1 si la variable n'a pas de contrainte
#endif
- module Lex et Yacc:
lex.l - Code:
-
%{ #include "arbre.h" #include "y.tab.h" int num_ligne=1; %} %option nounput noinput noyywrap %% "," {return(VIRGULE);} ".." {;return(POINT_POINT);} ":" {return(DEUX_POINTS);} "(" {return(PO);} ")" {return(PF);} "[" {return(CO);} "]" {return(CF);} "{" {return(AO);} "}" {return(AF);} "+" {return(PLUS);} "-" {return(MOINS);} "*" {return(MULTIPLIE_PAR);} "/" {return(DIVISE_PAR);} "%" {return(MODULO);} "=" {return(EGAL);} "!=" {return(DIFFERENT);} ">=" {return(SUPERIEUR_OU_EGAL);} "<=" {return(INFERIEUR_OU_EGAL);} ">" {return(SUPERIEUR);} "<" {return(INFERIEUR);} "&&" {return(ET);} "||" {return(OU);} "!" {return(NON);} "XD" {return(XD);} "C" {return(C);} "U" {return(UNION);} "ALLDIFF" {return(ALLDIFF);} "SQRT" {return(SQRT);} "SIN" {return(SIN);} "COS" {return(COS);} "TAN" {return(TAN);} 0.0|[0-9]+[.][0-9]+ { yylval.valeur = atof(yytext); return(REEL);} 0|[1-9][0-9]* { yylval.valeur = atoi(yytext); return(ENTIER);} "TRUE"|"FALSE" { if (strcmp("true", yytext)) yylval.valeur = 1; else yylval.valeur = 0; return(BOOLEEN);} [a-z][a-z\_]*[0-9\_]* {yylval.chaine = strdup(yytext); return(IDF);} [\n] num_ligne++; [\t] ; " " ; . {return(ERREUR);} %%
yacc.y - Code:
-
%{ #include "arbre.h" #include "listeVariable.h" extern int yylex(); /* pour supprimer un warning */ extern int yyerror(); /* pour supprimer un warning */ extern FILE* yyin; /* pour remplacer stdin par un fichier */ extern void yylex_destroy();
extern int num_ligne; // recouvre la variable num_ligne du fichier lex.l
listeContrainte listeContraintes;
listeVariable listeVariables; // la grande liste de toutes les variables listeVariable variablesPartageantDomaine; // une sous liste des variables ayant le meme domaine. cette liste contiendra pendant l'analyse chaque liste ayant un domaine domaine domaineVariable; // ce domaine contiendra pendant l'analyse chaque domaine communs aux variables dans variablePartageantDomaine domaine domaineVariable2; ; // ce domaine est utile pour en faire l'union avec le premier. c'est dans celui ci qu'on ajoute les valeurs. puis en fin d'ajout, on fait l'union entre le premier et le deuxieme qu'on stocke dans le premier listeDomaine listeDomaines; // comme un domaine peut etre commun a plusieurs variable, la liberation d'un domaine ne peut se faire avec la liberation d'une variable. on stock tous les domaines dans cette liste pour tous les vider correctement en fin du programme
structVariable* variable;
int nombreVariable = 0; int indiceVariable;
char* presenceVariable; // chaine de 0 et 1. si presenceVariable[i] == 1, alors il y a la variable d'indice i dans l'arbre de la contrainte, sinon elle n'y est pas
%}
%union { arbre arbre; float valeur; char* chaine; }
%type <chaine> IDF
%type <valeur> ENTIER REEL BOOLEEN
%type <arbre> fonction nombre expression7 expression6 expression5 expression4 expression3 expression2 expression1 expression
%token XD C %token VIRGULE DEUX_POINTS POINT_POINT %token PO PF CO CF AO AF %token UNION ALLDIFF %token PLUS MOINS MULTIPLIE_PAR DIVISE_PAR MODULO %token ET OU NON EGAL DIFFERENT SUPERIEUR_OU_EGAL INFERIEUR_OU_EGAL SUPERIEUR INFERIEUR %token ENTIER REEL BOOLEEN %token SQRT SIN COS TAN %token IDF ERREUR
%% programme: XD liste_var_dom C liste_contraintes ;
liste_var_dom: var_dom liste_var_dom | var_dom ;
var_dom: {// on est juste avant l'analyse d'une liste de variable partageant un domaine. On creer donc la liste des variables partageant ce domaine ainsi que ce domaine variablesPartageantDomaine = creer_listeVariable(); domaineVariable = creer_domaine(); domaineVariable2 = creer_domaine(); } liste_variables DEUX_POINTS union_domaine { // on est juste apres l'analyse des variables partageant un domaine. le domaine est plein et la liste des variables l'utilisant aussi. il faut donc ratacher ce domaine a ces variables, puis mettre ce sous ensemble des variables du CSP dans l'ensemble des variables du CSP affecterDommaine_listeVariable(variablesPartageantDomaine, domaineVariable); // ratachement du domaine a toutes les variable l'utilisant concat_listeVariable(&listeVariables, &variablesPartageantDomaine); // on rajoute ce sous ensemble de variable dans l'ensemble des variable } ;
liste_variables: IDF VIRGULE liste_variables { // si on trouve une variable, il faut l'ajouter au sous ensemble des variables et augmenter le nombre de variables ajouter_listeVariable(&variablesPartageantDomaine, $1); // ajoute la variable en donnant son nom en parametre nombreVariable++; // augmente le nombre de variable } | IDF { // pareil que juste au dessus ajouter_listeVariable(&variablesPartageantDomaine, $1); nombreVariable++; } ;
union_domaine: domaine UNION union_domaine { // on est juste apres l'analyse d'un domaine, on doit faire l'union entre celui qu'on vient de construire, et celui qu'on avait auparavant ajouter_listeDomaine(&listeDomaines, domaineVariable2); // on ajoute ce domaine a la liste des domaines juste pour garder la trace des domaines a supprimer en fin du programme domaineVariable = union_domaine(domaineVariable, domaineVariable2); domaineVariable2 = creer_domaine(); // on refait un nouveau domaine vide si jamais on en rencontre un autre par la suite } | domaine { // pareil qu'au dessus ajouter_listeDomaine(&listeDomaines, domaineVariable2); domaineVariable = union_domaine(domaineVariable, domaineVariable2); domaineVariable2 = creer_domaine(); } ;
domaine: AO liste_entiers AF | intervalle ;
liste_entiers: ENTIER VIRGULE liste_entiers {// on trouve un entier a ajouter dans le domaine, donc on l'ajoute ajouter_valeur(&domaineVariable2, $1); } | ENTIER {// pareil qu'au dessus ajouter_valeur(&domaineVariable2, $1); } ;
intervalle: CO ENTIER POINT_POINT ENTIER CF { // on trouve le domaine est un intervalle donc on initialise le domain a cet interval domaineVariable2 = initialiser($2, $4); // initialise le domaine entre la borne inferieur et la borne superieur } ;
liste_contraintes: contrainte liste_contraintes | contrainte ;
contrainte: { // on est sur le point d'analyser une contraintes, on creer son tableau de presence des variables en l'initialisant presenceVariable = (char*) malloc((nombreVariable+1) * sizeof(char)); // + 1 pour avoir le \0 en fin de chaine presenceVariable[nombreVariable] = '\0'; for(indiceVariable=0 ; indiceVariable<nombreVariable ; indiceVariable++) // prepare le tableau de presence des variables dans la contrainte qu'on commence a lire en mettant toutes les cases a 0 presenceVariable[indiceVariable] = '0'; // des qu'on trouve par la suite une variable dans la contrainte, on met l'indice de cette variable a '1' dans ce tableau } expression { // on a fini d'analyser la contrainte. on ajoute un maillon dans la liste des contraintes pour celle-ci en donnant son arbre et son tableau de presence des variables ajouter_contrainte(&listeContraintes, $2, presenceVariable); } | ALLDIFF PO liste_variables PF ;
expression: expression1 { $$ = $1; } | expression OU expression1 { $$ = attache_papa_fils(cons_noeud(A_OU, NULL), attache_papa_frangin($1, $3)); } ;
expression1: expression2 { $$ = $1; } | expression1 ET expression2 { $$ = attache_papa_fils(cons_noeud(A_ET, NULL), attache_papa_frangin($1, $3)); } ;
expression2: expression3 { $$ = $1; } | expression2 EGAL expression3 { $$ = attache_papa_fils(cons_noeud(A_EGAL, NULL), attache_papa_frangin($1, $3)); } | expression2 DIFFERENT expression3 { $$ = attache_papa_fils(cons_noeud(A_DIFFERENT, NULL), attache_papa_frangin($1, $3)); } ;
expression3: expression4 { $$ = $1; } | expression3 SUPERIEUR_OU_EGAL expression4 { $$ = attache_papa_fils(cons_noeud(A_SUPERIEUR_OU_EGAL, NULL), attache_papa_frangin($1, $3)); } | expression3 INFERIEUR_OU_EGAL expression4 { $$ = attache_papa_fils(cons_noeud(A_INFERIEUR_OU_EGAL, NULL), attache_papa_frangin($1, $3)); } | expression3 SUPERIEUR expression4 { $$ = attache_papa_fils(cons_noeud(A_SUPERIEUR, NULL), attache_papa_frangin($1, $3)); } | expression3 INFERIEUR expression4 { $$ = attache_papa_fils(cons_noeud(A_INFERIEUR, NULL), attache_papa_frangin($1, $3)); } ;
expression4: expression5 { $$ = $1; } | expression4 PLUS expression5 { $$ = attache_papa_fils(cons_noeud(A_PLUS, NULL), attache_papa_frangin($1, $3)); } | expression4 MOINS expression5 { $$ = attache_papa_fils(cons_noeud(A_MOINS, NULL), attache_papa_frangin($1, $3)); } ;
expression5: expression6 { $$ = $1; } | expression5 MULTIPLIE_PAR expression6 { $$ = attache_papa_fils(cons_noeud(A_MULTIPLIE_PAR, NULL), attache_papa_frangin($1, $3)); } | expression5 DIVISE_PAR expression6 { $$ = attache_papa_fils(cons_noeud(A_DIVISE_PAR, NULL), attache_papa_frangin($1, $3)); } | expression5 MODULO expression6 { $$ = attache_papa_fils(cons_noeud(A_MODULO, NULL), attache_papa_frangin($1, $3)); } ;
expression6: expression7 { $$ = $1; } | NON PO expression PF { $$ = attache_papa_fils(cons_noeud(A_NON, NULL), $3); } ;
expression7: PO expression PF { $$ = $2; } | nombre { $$ = $1; } | IDF { // si on trouve une variable dans l'arbre contraintes, il faut dire que cette contrainte apparait dans le tableau presence, et il faut creer un noeud en donant un pointeur sur sa valeur variable = retournerVariablePortantNom(listeVariables, $1, &indiceVariable); // on chope un pointeur sur la variable de ce nom (et au passage on recupere son indice) presenceVariable[indiceVariable] = '1'; // il faut dire que cette variable est presente dans cette contraintes, donc on met a 1 son indice dans le tableau de presence $$ = cons_noeud(A_IDF, &(variable->valeur)); // le deuxieme parametre est le pointeur sur la valeur de la variable ayant le nom de l'IDF free($1); // $1 vien d'un appel a strdup dans le fichier lex, il ne faut pas oublier de le liberer } | fonction { $$ = $1; } ;
fonction: SQRT PO expression4 PF { $$ = attache_papa_fils(cons_noeud(A_SQRT, NULL), $3); } | SIN PO expression4 PF { $$ = attache_papa_fils(cons_noeud(A_SIN, NULL), $3); } | COS PO expression4 PF { $$ = attache_papa_fils(cons_noeud(A_COS, NULL), $3); } | TAN PO expression4 PF { $$ = attache_papa_fils(cons_noeud(A_TAN, NULL), $3); } ;
nombre: ENTIER { $$ = cons_noeud(A_ENTIER, NULL); *($$->valeur) = $1; } | REEL { $$ = cons_noeud(A_REEL, NULL); *($$->valeur) = $1; } | BOOLEEN { $$ = cons_noeud(A_BOOLEEN, NULL); *($$->valeur) = $1; } ;
%% int yyerror() { fprintf(stderr,"Erreur de syntaxe ligne %d\n", num_ligne); return 0; }
int main(int argc, char* argv[]) {
// initialisations listeVariables = creer_listeVariable(); domaineVariable2 = creer_domaine(); listeContraintes = creer_liste_contrainte(); listeDomaines = creer_listeDomaine();
//analyse du fichier yyin=fopen("csp.txt", "r"); /* ouverture du fichier contenant le CSP */ yyparse(); fclose(yyin);
affecterContraintes_listeVariable(listeVariables, &listeContraintes, nombreVariable); // affichage resultat afficher_listeVariable(listeVariables);
// vidages vider_listeDomaine(listeDomaines); vider_listeVariable(listeVariables); yylex_destroy(); return EXIT_SUCCESS; }
- Makefile et fichier de test:
Makefile - Code:
-
CC = gcc -g -lm -Wall # g pour debugueur, lm pour math.h, Wall pour warnings
LISTE = arbre.o y.tab.c lex.o listeContrainte.o listeVariable.o domaine.o
all: clear main clean
main: $(LISTE) $(CC) $(LISTE) -o main
listeContrainte.o: listeContrainte.c listeContrainte.h
listeVariable.o: listeVariable.c listeVariable.h
domaine.o : domaine.c domaine.h
arbre.o: arbre.c arbre.h
y.tab.c: yacc.y yacc -d yacc.y -o y.tab.c
lex.o: lex.yy.c y.tab.c
lex.yy.c: lex.l flex -o lex.yy.c lex.l
clean: rm $(LISTE) lex.yy.c y.tab.h
clear: clear
csp.txt - Code:
-
XD x, y : [1..10] z : {1,2,3} U {44,55,66}
C 5 *2-1 = x x > 5 x != y y > 5 z > y z > x
z = x + y z > 0 z < 78
5 + 8
Tous est fonctionnel sur mon ordit, pour tester il vous suffit d'enregistrer l'ensemble de ces fichier dans un dossier et de lancer la commande make puis de lancer le programme avec ./main Il manque la fonction - Léo G a écrit:
- affecter_valeur: // Dimitri c'est ce que je te disais
Entré: une variable Sortie: 1 si on arrive à modifier la valeur de cette variable avec la prochaine valeur à affecter depuis le domaine 0 si il n'y a plus/pas de valeur dans le domaine à affecter pour pouvoir implanter mes 2 algorithmes. Pour cette fonction il faut penser au cas où aucune valeur n'a été affecté à la variable par exemple en initialisant les variables lors de la construction de la liste avec une valeur en dehors du domaine. Concernant ceux qui ne savent pas trop quoi faire j'ai deux trois idées en tête: Pour le groupe 1 qui s'est chargé du lex et yacc, j'aimerai bien qu'ils nous fournissent des jeux de tests pour des CSP et des fonctions d'affichages personnalisés en fonction du domaine du CSP (par exemple représenter facilement des Sudoku et faire un affichage de la grille). J'aimerai bien aussi faire un générateur de CSP (admettant au moins une solution) (cela nécessite surement d'utiliser un algorithme de résolution) Pour le groupe donnée, il faut commencer à réfléchir sur les structures de données nécessaire à l'algorithme récursif d'Hugo et Anthony, réfléchir aux domaines et l'arc consistance pour les domaines (j'ai lancé des pistes dans ce sujet https://projetprog.kanak.fr/t7-domaine-leurs-representations) et optimiser le code existant. Il faut aussi faire une fonction qui tri les variables avant la résolution par un critère (avec Dimitri on s'était dit par ordre décroissant pour chaque variable du nombre égale à (nombre d'apparition dans les contraintes) divisé par (nombre d'élément dans son domaine)) Pour le groupe algorithmes, il faut réfléchir au fonctions nécessaire et structure de données nécessaires à l’implantation d'autres algorithmes tel que - algorithmes rétrospectifs (look-back) Back-jumping Conflict-directed backjumping (CDBJ) Back-marking - algorithmes prospectifs (look-ahead) Forward-checking MAC (Maintaining Arc Consistency) Real-full-lookahead - algorithmes incomplet (méthode aléatoire), stochastiques recuit simulé recherche taboue GSAT et hill-climbing | |
|