#include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #else #define _(x) x #endif #include "exceptions.h" #include "numbers.h" #include "meta.h" /*************************\ * * * Meta Parser * * * \*************************/ static char meta_ops[] = ":.;(){}[=, "; static char meta_firsts[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"; static char meta_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_0123456789"; phon_t *phons = NULL; field_t *fields = NULL; pattern_t *patterns = NULL; instruct_t *instructs = NULL; /* Fonction interne pour déterminer si une chaîne forme un identifier correct. */ static int isident(char *word) { if (!strchr(meta_firsts, *word)) { return 0; } while (*word) { if (!strchr(meta_chars, *(word++))) { return 0; } } return 1; } /* La fonction getword pour le meta parser. Beaucoup plus simple que le parser normal. */ static char *getword(char *line, char *p) { char o; do { o = *(p++) = *line; line++; } while ((*line) && (!strchr(meta_ops, o)) && (!strchr(meta_ops, *line))); *p = '\0'; return line; } /* La terrible fonction meta_parse_line. Elle lit une chaîne correspondant à une ligne du fichier texte d'entrée. Le problème réside surtout dans le fait qu'il y a des variables globales et des effets de bords, ce qui empèche le découpage en sous routines. */ void meta_parse_line(char *line) { char buffer[BUFSIZ], *first = NULL, m = 0, *p1 = NULL, *p2 = NULL, *Fnames[MAXF], *Fimplicits[MAXF], *Snames[MAXF], *Sinames[MAXF], gotname = 0, goteoi = 0, errbuff[BUFSIZ]; phon_t *phon = NULL; field_t *field = NULL; pattern_t *pattern = NULL; instruct_t *instruct = NULL; metaexpr_t *metaexpr = NULL, *tmetaexpr, *tabmetaexpr[MAXM]; int Fsizes[MAXF], Fvalues[MAXF], Itypes[MAXF], Etypes[MAXF], nbfields = 0, valid, i, nbimplicit = 0; if (*line == '#') { return; } sprintf(errbuff, _("Read line '%s'"), line); pushcontext(errbuff); while (*line) { line = getword(line, buffer); sprintf(errbuff, _("Analysing word '%s'"), buffer); pushcontext(errbuff); if (!m) { /* Premier mot lut de la chaîne */ if (*line != ':') { exception(1, _("Missing operator ':'")); } line++; switch (buffer[0]) { case 'F': first = Estrdup(&buffer[1]); m = 1; break; case 'P': first = Estrdup(&buffer[1]); pattern = (pattern_t *) Emalloc(sizeof(pattern_t)); pattern->name = first; pattern->next = NULL; m = 2; break; case 'p': m = 3; break; case 'I': m = 4; break; } } else { /* Nous avons lut le premier mot, nous savons ce qu'il faut faire. */ switch (m) { case 1: /* Champ */ if (gotname) { Fsizes[nbfields++] = char_to_number(buffer, &valid); if (!valid) { exception(1, _("Invalid number.")); } if (*line) { if (*line != ';') { exception(1, _("Expecting ';' for field separator.")); } line++; gotname = 0; } else { field = (field_t *) Emalloc(sizeof(field_t)); field->next = fields->next; fields->next = field; field->name = first; field->names = (char **) Emalloc(nbfields * sizeof(char *)); field->sizes = (int *) Emalloc(nbfields * sizeof(int)); for (i = 0; i < nbfields; i++) { field->names[i] = Fnames[i]; field->sizes[i] = Fsizes[i]; } field->nbr = nbfields; } } else { if (*line != ',') { exception(1, _("Expecting ',' for field separator.")); } line++; Fnames[nbfields] = Estrdup(buffer); gotname = 1; } break; case 2: /* Pattern */ if (*buffer == '[') { tmetaexpr = (metaexpr_t *) Emalloc(sizeof(metaexpr_t)); tmetaexpr->name = NULL; tmetaexpr->string = NULL; tmetaexpr->left = metaexpr; metaexpr = tmetaexpr; } else { tmetaexpr = (metaexpr_t *) Emalloc(sizeof(metaexpr_t)); tmetaexpr->left = tmetaexpr->right = NULL; tmetaexpr->type = 0; if (*buffer == '.') { tmetaexpr->type = 1; popcontext(); line = getword(line, buffer); sprintf(errbuff, _("Analysing word '%s'"), buffer); pushcontext(errbuff); } if (!isident(buffer)) { exception(1, _("Identifier incorrect.")); } tmetaexpr->name = Estrdup(buffer); if (*line == '=') { if (*(++line) != '.') { exception(1, _("Error: Expecting a . after a =")); } popcontext(); line = getword(++line, buffer); sprintf(errbuff, _("Analysing word '%s'"), buffer); pushcontext(errbuff); if (!isident(buffer)) { exception(1, _("Identifier incorrect.")); } tmetaexpr->string = Estrdup(buffer); } else { tmetaexpr->string = NULL; } if (metaexpr) { metaexpr->right = tmetaexpr; } else { metaexpr = tmetaexpr; } if (*line == ';' || !*line) { tabmetaexpr[nbfields++] = metaexpr; if (*line) line++; metaexpr = NULL; } if (!*line) { pattern = (pattern_t *) Emalloc(sizeof(pattern_t)); pattern->next = patterns->next; patterns->next = pattern; pattern->name = first; pattern->expr = (metaexpr_t **) Emalloc(nbfields * sizeof(metaexpr_t *)); for (i = 0; i < nbfields; i++) { pattern->expr[i] = tabmetaexpr[i]; } pattern->nbr = nbfields; } } break; case 3: /* Phonème */ if (p1) { if (p2) { exception(1, _("Extra parameters for field 'p'.")); } else { if (isident(buffer)) { p2 = Estrdup(buffer); } else { exception(1, _("Identifier incorrect.")); } if (*line) { exception(1, _("Unexpected char at end of line.")); } phon = (phon_t *) Emalloc(sizeof(phon_t)); phon->next = phons->next; phons->next = phon; phon->p1 = p1; phon->p2 = p2; } } else { if (isident(buffer)) { p1 = Estrdup(buffer); if (*line != '=') { exception(1, _("Expecting operator '=' for field 'p'.")); } line++; } else { exception(1, _("Identifier incorrect.")); } } break; case 4: /* Instruction */ if (!goteoi) { if (isident(buffer) || (*buffer == '.')) { Etypes[nbfields] = 0; if (*buffer == '.') { Etypes[nbfields] = 1; popcontext(); line = getword(line, buffer); sprintf(errbuff, _("Analysing word '%s'"), buffer); pushcontext(errbuff); } Fnames[nbfields] = Estrdup(buffer); if (*line == '=') { if (*(++line) != '.') { exception(1, _("Error: character . expected.")); } popcontext(); line = getword(++line, buffer); sprintf(errbuff, _("Analysing word '%s'"), buffer); pushcontext(errbuff); if (!isident(buffer)) { exception(1, _("Identifier incorrect.")); } Snames[nbfields] = Estrdup(buffer); } else { Snames[nbfields] = NULL; } nbfields++; if (*line == ';') { goteoi = 1; line++; } } } else { if (!isident(buffer)) { exception(1, _("Identifier incorrect.")); } Fimplicits[nbimplicit] = Estrdup(buffer); if (*line != '=') { exception(1, _("= expected after an implicit name")); } popcontext(); line = getword(++line, buffer); sprintf(errbuff, _("Analysing word '%s'"), buffer); pushcontext(errbuff); if (*buffer == '.') { Itypes[nbimplicit] = 1; popcontext(); line = getword(line, buffer); sprintf(errbuff, _("Analysing word '%s'"), buffer); pushcontext(errbuff); if (!isident(buffer)) { exception(1, _("Identifier incorrect")); } Sinames[nbimplicit] = Estrdup(buffer); } else { Sinames[nbimplicit] = NULL; Itypes[nbimplicit] = 2; Fvalues[nbimplicit] = char_to_number(buffer, &valid); if (!valid) { if (!isident(buffer)) { exception(1, _("Identifier incorrect")); } Sinames[nbimplicit] = Estrdup(buffer); Itypes[nbimplicit] = 0; } } nbimplicit++; if (*line) { if (*line != ';') { exception(1, _("expecting ; as field separator")); } line++; } else { instruct = (instruct_t *) Emalloc(sizeof(instruct_t)); instruct->next = instructs->next; instructs->next = instruct; instruct->names = (char **) Emalloc(nbfields * sizeof(char *)); instruct->strings = (char **) Emalloc(nbfields * sizeof(char *)); instruct->etypes = (int *) Emalloc(nbfields * sizeof(int)); instruct->implicits = (char **) Emalloc(nbimplicit * sizeof(char *)); instruct->ivalues = (int *) Emalloc(nbimplicit * sizeof(int)); instruct->istrings = (char **) Emalloc(nbimplicit * sizeof(char *)); instruct->itypes = (int *) Emalloc(nbimplicit * sizeof(int)); for (i = 0; i < nbfields; i++) { instruct->names[i] = Fnames[i]; instruct->strings[i] = Snames[i]; instruct->etypes[i] = Etypes[i]; } instruct->nbexplicit = nbfields; for (i = 0; i < nbimplicit; i++) { instruct->implicits[i] = Fimplicits[i]; instruct->ivalues[i] = Fvalues[i]; instruct->istrings[i] = Sinames[i]; instruct->itypes[i] = Itypes[i]; } instruct->nbimplicit = nbimplicit; goteoi = 0; } } break; } } popcontext(); } popcontext(); } /* Initialiseur et destructeur du meta parser */ int meta_init(void) { if (!(phons = (phon_t *) malloc(sizeof(phon_t)))) { return -1; } phons->p1 = phons->p2 = NULL; phons->next = NULL; if (!(fields = (field_t *) malloc(sizeof(field_t)))) { return -1; } fields->name = NULL; fields->names = NULL; fields->sizes = NULL; fields->next = NULL; if (!(patterns = (pattern_t *) malloc(sizeof(pattern_t)))) { return -1; } patterns->name = NULL; patterns->expr = NULL; patterns->next = NULL; if (!(instructs = (instruct_t *) malloc(sizeof(instruct_t)))) { return -1; } instructs->names = NULL; instructs->strings = NULL; instructs->etypes = NULL; instructs->implicits = NULL; instructs->ivalues = NULL; instructs->istrings = NULL; instructs->itypes = NULL; return 0; } static void recurs_free_phon(phon_t * phon) { if (phon->next) { recurs_free_phon(phon->next); } free(phon->p1); free(phon->p2); free(phon); } static void recurs_free_field(field_t * field) { int i; if (field->next) { recurs_free_field(field->next); } free(field->name); for (i = 0; i < field->nbr; i++) { free(field->names[i]); } free(field->names); free(field->sizes); free(field); } static void recurs_free_metaexpr(metaexpr_t * metaexpr) { if (metaexpr->left) { recurs_free_metaexpr(metaexpr->left); } if (metaexpr->right) { recurs_free_metaexpr(metaexpr->right); } if (metaexpr->name) { free(metaexpr->name); } if (metaexpr->string) { free(metaexpr->string); } free(metaexpr); } static void recurs_free_pattern(pattern_t * pattern) { int i; if (pattern->next) { recurs_free_pattern(pattern->next); } free(pattern->name); for (i = 0; i < pattern->nbr; i++) { recurs_free_metaexpr(pattern->expr[i]); } free(pattern->expr); free(pattern); } static void recurs_free_instruct(instruct_t * instruct) { int i; if (instruct->next) { recurs_free_instruct(instruct->next); } for (i = 0; i < instruct->nbexplicit; i++) { free(instruct->names[i]); if (instruct->strings[i]) { free(instruct->strings[i]); } } for (i = 0; i < instruct->nbimplicit; i++) { free(instruct->implicits[i]); free(instruct->istrings[i]); } free(instruct->names); free(instruct->strings); free(instruct->etypes); free(instruct->implicits); free(instruct->istrings); free(instruct->itypes); free(instruct); } void meta_flush(void) { if (phons->next) recurs_free_phon(phons->next); if (fields->next) recurs_free_field(fields->next); if (patterns->next) recurs_free_pattern(patterns->next); if (instructs->next) recurs_free_instruct(instructs->next); free(phons); free(fields); free(patterns); free(instructs); phons = NULL; fields = NULL; patterns = NULL; instructs = NULL; } int meta_load(char *n) { FILE *f; char buf[BUFSIZ], errctx[BUFSIZ], *p; int i = 0; pushcontext(_("Loading meta file")); sprintf(errctx, _("Opening file '%s'"), n); pushcontext(errctx); if (!(f = fopen(n, "r"))) { pushcontext(strerror(errno)); return 1; } popcontext(); pushcontext(_("Reading file")); while (fgets(buf, BUFSIZ, f)) { sprintf(errctx, _("Reading line %i"), ++i); pushcontext(errctx); if ((p = strchr(buf, '\r'))) { *p = '\0'; } if ((p = strchr(buf, '\n'))) { *p = '\0'; } meta_parse_line(buf); popcontext(); } popcontext(); popcontext(); fclose(f); return 0; } #ifndef HAVE_CONFIG_H /* Programme de test si on compile le meta parser indépendament du reste du projet */ void main(void) { phon_t *phon; field_t *field; pattern_t *pattern; instruct_t *instruct; int i; if (meta_init()) exception(1, _("Meta parser init failed.")); meta_load("instructions.txt"); fprintf(stderr, "\nListe des phonèmes:\n"); for (phon = phons->next; phon; phon = phon->next) { fprintf(stderr, " o %s <===> %s\n", phon->p1, phon->p2); } fprintf(stderr, "\nListe des champs:\n"); for (field = fields->next; field; field = field->next) { fprintf(stderr, " o Champ nommé %s, contenant %i parties:\n", field->name, field->nbr); for (i = 0; i < field->nbr; i++) { fprintf(stderr, " + %s (%i bits)\n", field->names[i], field->sizes[i]); } } fprintf(stderr, "\nListe des patterns:\n"); for (pattern = patterns->next; pattern; pattern = pattern->next) { fprintf(stderr, " o Pattern nommée %s, contenant %i metaexpressions:\n", pattern->name, pattern->nbr); for (i = 0; i < pattern->nbr; i++) { fprintf(stderr, " + %s (%s) type: %s\n", pattern->expr[i]->name ? pattern->expr[i]->name : "Opérateur [", pattern->expr[i]->string ? pattern->expr[i]->string : "Aucune chaîne associée", pattern->expr[i]->type ? "Constante prédéfinie" : pattern-> expr[i]->left ? "Binaire" : pattern->expr[i]->right ? "Unaire" : "Feuille"); if (pattern->expr[i]->left) { fprintf(stderr, " - gauche: %s (%s) type: %s\n", pattern->expr[i]->left->name ? pattern->expr[i]->left->name : "Opérateur [", pattern->expr[i]->left->string ? pattern->expr[i]-> left->string : "Aucune chaîne associée", pattern->expr[i]->left->type ? "Constante prédéfinie" : "Feuille"); } if (pattern->expr[i]->right) { fprintf(stderr, " - droite: %s (%s) type: %s\n", pattern->expr[i]->right->name ? pattern->expr[i]->right->name : "Opérateur [", pattern->expr[i]->right->string ? pattern->expr[i]-> right->string : "Aucune chaîne associée", pattern->expr[i]->right->type ? "Constante prédéfinie" : "Feuille"); } } } fprintf(stderr, "\nListe des instructions:\n"); for (instruct = instructs->next; instruct; instruct = instruct->next) { fprintf(stderr, " o Instruction contenant %i champs explicites et %i champs implicites.\n", instruct->nbexplicit, instruct->nbimplicit); fprintf(stderr, " => Champs explicites.\n"); for (i = 0; i < instruct->nbexplicit; i++) { fprintf(stderr, " + %s <= %s (type %s)\n", instruct->names[i], instruct->strings[i] ? instruct->strings[i] : "Pas de chaîne associée", instruct->etypes[i] ? "prédéfinit" : "direct"); } fprintf(stderr, " => Champs implicites.\n"); for (i = 0; i < instruct->nbimplicit; i++) { switch (instruct->itypes[i]) { case 0: fprintf(stderr, " + %s <= %s (type direct)\n", instruct->implicits[i], instruct->istrings[i]); break; case 1: fprintf(stderr, " + %s <= %s (type prédéfinit)\n", instruct->implicits[i], instruct->istrings[i]); break; case 2: fprintf(stderr, " + %s <= %i (type valeur)\n", instruct->implicits[i], instruct->ivalues[i]); break; } } } } #endif