#include #include #include #include"analyseur_xml.h" /* symboles terminaux */ #define CHEVRON_FERMANT 1 #define DEBUT_BF 2 #define DEBUT_BO 3 #define CHAINE 4 #define FIN 5 #define ISSPACE(a) (a == ' ') || (a == '\n') || (a == '\t') #define YYTEXT_MAX 100 /* fonctions pour arbre abstrait */ noeud *cree_noeud(char *nom) { noeud *n = malloc(sizeof(noeud)); if(n == NULL){ fprintf(stderr, "erreur d'allocation\n"); exit(1); } n->nom = nom; n->premier_fils = NULL; n->dernier_fils = NULL; n->suiv = NULL; return n; } noeud *ajoute_fils(noeud *pere, noeud *fils) { if(pere->premier_fils == NULL){ pere->premier_fils = pere->dernier_fils = fils; return pere; } pere->dernier_fils->suiv = fils; pere->dernier_fils = fils; return pere; } void affiche_arbre(noeud *racine){ noeud *n; printf("<%s> ", racine->nom); for(n=racine->premier_fils; n!=NULL; n = n->suiv){ affiche_arbre(n); } printf(" ", racine->nom); } int compare_arbres_rec(noeud *racine1, noeud *racine2, int verbose, int profondeur) { noeud *f1, *f2; int resultat = 1; int i; if(verbose){ for(i=0; i %s\n", racine1->nom, racine2->nom); } if(strcmp(racine1->nom, racine2->nom)) return 0; for(f1 = racine1->premier_fils, f2 = racine2->premier_fils; f1 && f2 && resultat; f1 = f1->suiv, f2 = f2->suiv){ resultat = compare_arbres_rec(f1, f2, verbose, profondeur+1); } return ((f1 == NULL) && (f2 == NULL) && resultat); } int compare_arbres(noeud *racine1, noeud *racine2, int verbose) { return compare_arbres_rec(racine1, racine2, verbose, 0); } void libere_arbre(noeud *racine) { noeud *n; for(n=racine->premier_fils; n!=NULL; n = n->suiv){ libere_arbre(n); } free(racine); } /* analyseur lexical */ int DEBUG = 1; char yytext[YYTEXT_MAX]; int yyleng; int yylval; /* Compter les lignes pour afficher les messages d'erreur avec numero ligne */ int nb_ligne; int cc; /******************************************************************************* * Fonction qui ignore les espaces et commentaires. * Renvoie -1 si arrivé à la fin du fichier, 0 si tout va bien ******************************************************************************/ int mangeEspaces() { char c = fgetc(yyin); while( ISSPACE(c) ) { if( c == '\n' ) { nb_ligne++; } c = fgetc(yyin); } if ( feof(yyin) ) { return -1; } ungetc(c, yyin); return 0; } /******************************************************************************* * Lit un caractère et le stocke dans le buffer yytext ******************************************************************************/ char lireCar(void) { yytext[yyleng++] = fgetc(yyin); yytext[yyleng] = '\0'; return yytext[yyleng - 1]; } /******************************************************************************* * Remet le dernier caractère lu au buffer clavier et enlève du buffer yytext ******************************************************************************/ void delireCar() { char c; c = yytext[yyleng - 1]; yytext[--yyleng] = '\0'; ungetc(c, yyin); } /******************************************************************************* * Fonction principale de l'analyseur lexical, lit les caractères de yyin et * renvoie les tokens sous forme d'entier. Le code de chaque unité est défini * dans symboles.h sinon (mot clé, idententifiant, etc.). Pour les tokens de * type ID_FCT, ID_VAR et NOMBRE la valeur du token est dans yytext, visible * dans l'analyseur syntaxique. ******************************************************************************/ int inTag = 0; int yylex(void) { char c; yytext[yyleng = 0] = '\0'; /* Si j'ai trouvé la fin du fichier en lisant des espaces ... */ if( !inTag && mangeEspaces() == -1 ) { return FIN; /* Renvoie le marqueur de fin d'entrée */ } c = lireCar(); if(c == '>'){ if(DEBUG) { printf("CHEVRON_FERMANT\n"); } //inTag = 0; return CHEVRON_FERMANT; } if(c == '<'){ inTag = 1; c = lireCar(); if(c == '/'){ if(DEBUG) { printf("DEBUT_BF\n"); } return DEBUT_BF; } else{ delireCar(); if(DEBUG) { printf("DEBUT_BO\n"); } return DEBUT_BO; } } do{ c = lireCar(); inTag = 0; }while((c!= '<') && (c!= '>') && !feof(yyin) && !(ISSPACE(c))); delireCar(); if(DEBUG) { printf("CHAINE\n"); } return CHAINE; } /******************************************************************************* * Fonction auxiliaire appelée par l'analyseur syntaxique tout simplement pour * afficher des messages d'erreur et l'arbre XML ******************************************************************************/ void nom_token( int token, char *nom, char *valeur ) { //int i; strcpy( nom, "symbole" ); if(token == CHEVRON_FERMANT) strcpy( valeur, "CHEVRON_FERMANT"); else if(token == DEBUT_BF) strcpy( valeur, "DEBUT_BF"); else if(token == DEBUT_BO) strcpy( valeur, "DEBUT_BO"); else if(token == CHAINE) strcpy( valeur, "CHAINE"); } /* analyse syntaxique */ noeud *B(void); void LB(noeud *pere); char *BO(void); char *BF(void); void LCHAINE(void); void erreur(char *msg){ fprintf(stderr, "Ligne %d : erreur : %s\n", nb_ligne, msg); exit(1); } /* B -> BO LCHAINE LB LCHAINE BF */ noeud *B(void){ char *nom_bo; char *nom_bf; noeud *n; if(DEBUG) { printf("\n"); } if(cc == DEBUT_BO){ nom_bo = BO(); n = cree_noeud(nom_bo); LCHAINE(); LB(n); LCHAINE(); nom_bf = BF(); if(strcmp(nom_bo, nom_bf)){ fprintf(stderr, "Ligne %d : arbre mal forme: balise ouvrante : \"%s\" balise fermante : \"%s\"\n", nb_ligne, nom_bo, nom_bf); exit(1); } free(nom_bf); if(DEBUG) { printf("\n"); } return n; } erreur("B"); return NULL; } /* LCHAINE -> CHAINE LCHAINE */ /* | */ void LCHAINE(void){ if(cc == CHAINE){ cc = yylex(); LCHAINE(); return; } if((cc == DEBUT_BO) ||(cc == DEBUT_BF)){ return; } erreur("LCHAINE"); } /* LB -> B LB | */ void LB(noeud *pere) { noeud *fils = NULL; if(cc == DEBUT_BO){ fils = B(); ajoute_fils(pere, fils); LB(pere); return; } if(cc == DEBUT_BF){ return; } erreur("LB"); } /* BO -> DEBUT_BO CHAINE CHEVRON_FERMANT */ char *BO(void) { char *nom = NULL; if(DEBUG) { printf("\n"); } if(cc == DEBUT_BO){ cc = yylex(); if(cc == CHAINE){ nom = strdup(yytext); cc = yylex(); if(cc == CHEVRON_FERMANT){ cc = yylex(); if(DEBUG) { printf("\n"); } return nom; } } } erreur("BO"); return NULL; } /* BF -> DEBUT_BF CHAINE CHEVRON_FERMANT */ char *BF(void) { char *nom = NULL; if(cc == DEBUT_BF){ cc = yylex(); if(cc == CHAINE){ nom = strdup(yytext); cc = yylex(); if(cc == CHEVRON_FERMANT){ cc = yylex(); return nom; } } } erreur("BF"); return NULL; } noeud *analyseur_xml(void) { nb_ligne = 0; cc = yylex(); return B(); }