Files
compilateur-l/eval-final-projet/analyseur_xml.c
2016-04-19 09:06:38 +02:00

324 lines
7.0 KiB
C

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#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("</%s> ", 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<profondeur; i++) printf(" ");
printf("%s <------------> %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 = 0;
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("<B>\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("</B>\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("<BO>\n"); }
if(cc == DEBUT_BO){
cc = yylex();
if(cc == CHAINE){
nom = strdup(yytext);
cc = yylex();
if(cc == CHEVRON_FERMANT){
cc = yylex();
if(DEBUG) { printf("</BO>\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();
}