trafi

Transducteurs finis
git clone git://git.asteride.xyz/trafi.git
Journaux | Fichiers | Références

commit 5ca56d9bf1a793879188fdcb7dba607f6015663a
parent ffd28e8db2f60d01b6905db723b926d6cdb750ac
Auteur: Loïc Daignault-Pichette <loic@asteride.xyz>
Date:   Tue,  7 Apr 2026 11:40:26 -0400

Créer le segmenteur; un premier jet

Diffstat:
MMakefile | 4++--
Mattvtfd.c | 3++-
Mtfd.c | 609+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mtfd.h | 108+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
4 fichiers modifiés, 518 insertions(+), 206 suppressions(-)

diff --git a/Makefile b/Makefile @@ -9,8 +9,8 @@ COPTS = -Wall -Wextra -Wpedantic -std=c99 -O0 #-DNDEBUG -O3 -flto tout: attvtfd -attvtfd: attvtfd.o tampex.o tfm.o att.o - ${CC} ${COPTS} -o "$@" attvtfd.o tampex.o tfm.o att.o +attvtfd: attvtfd.o tampex.o tfm.o att.o tfd.o + ${CC} ${COPTS} -o "$@" attvtfd.o tampex.o tfm.o att.o tfd.o net: rm -rf attvtfd *.o *.core diff --git a/attvtfd.c b/attvtfd.c @@ -1,6 +1,7 @@ #include <stdio.h> #include "att.h" +#include "tfd.h" #include "tfm.h" int @@ -24,7 +25,7 @@ main(int argc, char **argv) return 1; } - if (att_ecrire(ftfd, tfm) < 0) { + if (tfd_ecrire(ftfd, tfm) < 0) { fprintf(stderr, "attvtf: erreur dans l’écriture du fichier .att\n"); return 1; } diff --git a/tfd.c b/tfd.c @@ -1,234 +1,531 @@ #include <assert.h> -#include <stddef.h> +#include <stdint.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "tampex.h" #include "tfd.h" #include "tfm.h" -#define TAMPON_LNGR_DEF 64 - -/* Obtenir la liste des symboles d’un transducteur. - * Renvoie un pointeur vers cette liste, ou NULL en cas d’erreur. */ -static struct tampinf *symboles_liste(struct tfm *tfm); - -/* Obtenir un index d’une liste de symboles telle que renvoyée par - * tampinf_liste. - * Renvoie un pointeur vers l’index, ou NULL en cas d’erreur. */ -static struct tampinf *symboles_index(struct tampinf *liste); - -/* Créer un automate au format tfm à partir des symboles d’un tfm. - * Renvoie un pointeur vers un tfm, ou NULL en cas d’erreur. */ -static struct tfm *automate_symbs(struct tfm *tfm, struct tampinf **ti); +#define TAMPON_LNGR_DEF 1 + +/* Obtenir la liste des symboles du transducteur tfm. + * corr est un tampex qui donne la correspondance entre les identifiants de + * symbole du tfm (id) et leur indice (i) dans la liste, de telle sorte que + * corr[id] == i. + * Renvoie un pointeur vers un tampex contenant cette liste, ou NULL en cas + * d’erreur. */ +static char *symboles_liste(struct tfm *tfm, uint32_t **corr); + +/* Obtenir la liste des identifiants de symbole d’entrée (se) et de sortie (ss) + * du transducteur tfm. + * Renvoie un pointeur vers un tampex contenant cette liste, ou NULL en cas + * d’erreur. */ +static int symboles_id(struct tfm *tfm, uint32_t *corr, uint16_t **se, + uint16_t **ss); + +/* Créer le segmenteur à partir d’une liste de symboles d’entrée. + * Renvoie un pointeur vers un tampex, ou NULL en cas d’erreur. */ +static uint16_t (*segmenteur(char *liste, uint16_t *se))[2]; + +/* Tester si la paire à l’indice i dans le segmenteur segm est libre. + * Renvoie 1 si elle est libre et 0 si elle ne l’est pas, ou -1 en cas + * d’erreur. */ +static int segmenteur_tlibre(uint16_t (**segm)[2], size_t i); + +/* Trouver une paire libre dans le segmenteur. + * Renvoie l’indice de la paire trouvée, ou -1 en cas d’erreur. */ +static ssize_t segmenteur_libre(uint16_t (**segm)[2]); + +/* Trouver la paire de base dans le segmenteur segm de l’état ietat dans + * l’automate tfm. + * Renvoie l’indice de la base, ou -1 en cas d’erreur. */ +static ssize_t segmenteur_base(uint16_t (**segm)[2], struct tfm *tfm, + size_t ietat); + +/* Créer un automate au formant tfm à partir d’une liste de symboles d’entrée. + * Renvoie un pointeur vers un tfm, ou NULL en cas d’erreur, et donne la liste + * des identifiants des de symbole associés aux états finaux dans ids. */ +static struct tfm *automate_symbs(char *liste, uint16_t *se, + uint32_t **finaux); int tfd_ecrire(FILE *f, struct tfm *tfm) { - struct tampinf *liste; /* Liste de symboles. */ - struct tampinf *index; /* Index de symboles. */ - size_t pos, tll; + unsigned char entete[TFD_ENTETE_TLL]; /* Contenu de l’entête. */ + size_t dec; /* Décalage actuel dans le fichier. */ + char *liste; /* Tampons extensibles. */ + uint16_t *tse, *tss; /* Autres tampons extensibles. */ + uint32_t *corr; /* Correspondance entre les identifiants de symbole. */ + uint16_t (*segm)[2]; /* Segmenteur. */ + size_t lngr; /* Longueur du tampon. */ + ssize_t res; /* Résultat d’une opérations. */ assert(f); assert(tfm); + dec = TFD_ENTETE_TLL; + if (fseek(f, dec, SEEK_SET) != 0) + return -1; + /* Écrire le nombre magique. */ - fputc((TFD_MAGIQUE >> 8) & 0xff, f); - fputc((TFD_MAGIQUE >> 0) & 0xff, f); + entete[0x00] = (TFD_MAGIQUE >> 8) & 0xFF; + entete[0x01] = (TFD_MAGIQUE >> 0) & 0xFF; /* Écrire la version. */ - fputc((TFD_VERSION >> 8) & 0xff, f); - fputc((TFD_VERSION >> 0) & 0xff, f); + entete[0x02] = (TFD_VERSION >> 8) & 0xFF; + entete[0x03] = (TFD_VERSION >> 0) & 0xFF; + + /* Écrire la liste de symboles. */ + entete[0x04] = (dec >> 24) & 0xFF; + entete[0x05] = (dec >> 16) & 0xFF; + entete[0x06] = (dec >> 8) & 0xFF; + entete[0x07] = (dec >> 0) & 0xFF; + if ((liste = symboles_liste(tfm, &corr)) == NULL) + return -1; + lngr = tampex_esp(liste); + entete[0x08] = (lngr >> 24) & 0xFF; + entete[0x09] = (lngr >> 16) & 0xFF; + entete[0x0A] = (lngr >> 8) & 0xFF; + entete[0x0B] = (lngr >> 0) & 0xFF; + res = fwrite(liste, 1, lngr, f); + if (res != (ssize_t) lngr) + return -1; + + dec += lngr; - /* Liste de symboles. */ - if ((liste = symboles_liste(tfm)) == NULL) + /* Écrire la liste des identifiants de symbole d’entrée. */ + entete[0x0C] = (dec >> 24) & 0xFF; + entete[0x0D] = (dec >> 16) & 0xFF; + entete[0x0E] = (dec >> 8) & 0xFF; + entete[0x0F] = (dec >> 0) & 0xFF; + if (symboles_id(tfm, corr, &tse, &tss) < 0) + return -1; + tampex_libr(corr); + lngr = tampex_esp(tse); + entete[0x10] = (lngr >> 24) & 0xFF; + entete[0x11] = (lngr >> 16) & 0xFF; + entete[0x12] = (lngr >> 8) & 0xFF; + entete[0x13] = (lngr >> 0) & 0xFF; + res = fwrite(tse, 1, lngr, f); + if (res != (ssize_t) lngr) return -1; - /* Index des symboles. */ - if ((index = symboles_index(liste)) == NULL) + dec += lngr; + + /* Écrire la liste des identifiants de symbole de sortie. */ + entete[0x14] = (dec >> 24) & 0xFF; + entete[0x15] = (dec >> 16) & 0xFF; + entete[0x16] = (dec >> 8) & 0xFF; + entete[0x17] = (dec >> 0) & 0xFF; + lngr = tampex_esp(tss); + entete[0x18] = (lngr >> 24) & 0xFF; + entete[0x19] = (lngr >> 16) & 0xFF; + entete[0x1a] = (lngr >> 8) & 0xFF; + entete[0x1b] = (lngr >> 0) & 0xFF; + res = fwrite(tse, 1, lngr, f); + tampex_libr(tss); + if (res != (ssize_t) lngr) return -1; - /* Écrire la position de l’index des symboles. */ - pos = TFD_ENTETE_FIN; - fputc((pos >> 24) & 0xff, f); - fputc((pos >> 16) & 0xff, f); - fputc((pos >> 8) & 0xff, f); - fputc((pos >> 0) & 0xff, f); - - /* Écrire la taille de l’index des symboles. */ - tll = tampinf_esp(index); - fputc((tll >> 24) & 0xff, f); - fputc((tll >> 16) & 0xff, f); - fputc((tll >> 8) & 0xff, f); - fputc((tll >> 0) & 0xff, f); - - /* Écrire la position de la liste de symboles. */ - pos += tll; - fputc((pos >> 24) & 0xff, f); - fputc((pos >> 16) & 0xff, f); - fputc((pos >> 8) & 0xff, f); - fputc((pos >> 0) & 0xff, f); - - /* Écrire la taille de la liste de symboles. */ - tll = tampinf_esp(liste); - fputc((tll >> 24) & 0xff, f); - fputc((tll >> 16) & 0xff, f); - fputc((tll >> 8) & 0xff, f); - fputc((tll >> 0) & 0xff, f); + dec += lngr; + + /* Écrire le segmenteur. */ + entete[0x1c] = (dec >> 24) & 0xFF; + entete[0x1d] = (dec >> 16) & 0xFF; + entete[0x1e] = (dec >> 8) & 0xFF; + entete[0x1f] = (dec >> 0) & 0xFF; + if ((segm = segmenteur(liste, tse)) == NULL) + return -1; + tampex_libr(liste); + tampex_libr(tse); + lngr = tampex_esp(segm); + entete[0x1c] = (lngr >> 24) & 0xFF; + entete[0x1d] = (lngr >> 16) & 0xFF; + entete[0x1e] = (lngr >> 8) & 0xFF; + entete[0x1f] = (lngr >> 0) & 0xFF; + res = fwrite(segm, 1, lngr, f); + if (res != (ssize_t) lngr) + return -1; + + /*for (size_t z = 0; tampex_dedans(segm, z); z++) { + printf("%lu\t%s%d\t%s%d\n", + z, + segm[z][0] & 0x01 ? "*" : "", + segm[z][0]>>1, + segm[z][1] & 0x01 ? "*" : "", + segm[z][1]>>1); + }*/ + + tampex_libr(segm); + + entete[TFD_ENTETE_TLL-1] = 0xFF; + + /* Écrire l’entête. */ + if (fseek(f, 0, SEEK_SET) != 0) + return -1; + if (fwrite(entete, 1, TFD_ENTETE_TLL, f) != TFD_ENTETE_TLL) + return -1; return 0; } -static struct tampinf * -symboles_liste(struct tfm *tfm) +static char * +symboles_liste(struct tfm *tfm, uint32_t **corr) { - struct tampinf *liste; + char *liste; /* Liste de symboles. */ + size_t i; /* Indice dans liste. */ char symb[TFM_TLL_SYMB_MAX]; /* Tampon à symbole. */ - size_t id, tll; - unsigned char n; + size_t isymb, isymbc; /* Identifiant de symbole (courant). */ + ssize_t lngr; /* Longueur d’un symbole. */ assert(tfm); - /* Initialiser la liste. */ - if ((liste = tampinf_init(TAMPON_LNGR_DEF, sizeof(char))) == NULL) + /* Initialiser les tampons. */ + if ((liste = tampex_init(TAMPON_LNGR_DEF, sizeof *liste)) == NULL) return NULL; + if ((*corr = tampex_init(TAMPON_LNGR_DEF, sizeof *corr)) == NULL) + goto erreur1; /* Parcourir les symboles. */ - id = 0; - while ((tll = tfm_parc_symbs(tfm, &id, symb, TFM_TLL_SYMB_MAX)) > 0) { - n = tll; - if (tampinf_ajt(liste, 1, &n) < 0) - goto erreur; - if (tampinf_ajt(liste, tll, symb) < 0) - goto erreur; + isymb = isymbc = i = 0; + while ((lngr = tfm_parc_symbs(tfm, &isymb, symb, + TFM_TLL_SYMB_MAX)) > 0) { + if (tampex_minim((void **)corr, isymbc) < 0) + goto erreur2; + (*corr)[isymbc] = i; + if (tampex_minim((void **)&liste, i + lngr) < 0) + goto erreur2; + liste[i++] = (unsigned char)lngr; + memcpy(liste + i, symb, lngr); + i += lngr; + isymbc = isymb; } + if (lngr < 0) + goto erreur2; return liste; -erreur: - tampinf_libr(liste); +erreur2: + tampex_libr(*corr); +erreur1: + tampex_libr(liste); return NULL; } -static struct tampinf * -symboles_index(struct tampinf *liste) +static int +symboles_id(struct tfm *tfm, uint32_t *corr, uint16_t **se, uint16_t **ss) { - struct tampinf *index; - char *ctn; /* Contenu de la liste. */ - size_t pos; /* Position dans la liste. */ - unsigned n; /* Taille d’un symbole. */ + char *dejala; /* Indique si l’identifiant est déjà dans se (& 1) ou + dans ss (& 2). */ + size_t ise; /* Indice dans se. */ + size_t iss; /* Indice dans ss. */ + size_t ietat; /* Identifiant d’état. */ + size_t ntrans; /* Nombre de transitions depuis un état. */ + size_t itrans; /* Identifiant de transition. */ + ssize_t isymb; /* Identifiant de symbole .*/ + + assert(tfm); + assert(corr); + + /* Initialiser les listes et le dejala. */ + if ((*se = tampex_init(TAMPON_LNGR_DEF, sizeof **se)) == NULL) + return -1; + if ((*ss = tampex_init(TAMPON_LNGR_DEF, sizeof **ss)) == NULL) + goto erreur1; + if ((dejala = tampex_init(TAMPON_LNGR_DEF, sizeof *dejala)) == NULL) + goto erreur2; + + ise = iss = 0; + + /* Parcourir les états. */ + for (ietat = 0; tampex_dedans(tfm->etats, ietat); ietat++) { + /* Parcourir les transitions. */ + for (itrans = tfm->etats[ietat].trans, + ntrans = tfm->etats[ietat].ntrans; + ntrans--; itrans = tfm->trans[itrans].prch) { + /* Ignorer les symboles spéciaux. */ + if ((isymb = tfm->trans[itrans].se) >= 0) { + if (tampex_minim((void **)&dejala, isymb) < 0) + goto erreur3; + /* Ne pas ajouter le symbole s’il est déjà là. */ + if (!(dejala[isymb] & 1)) { + if (tampex_minim((void **)se, ise) < 0) + goto erreur3; + (*se)[ise++] = corr[isymb]; + dejala[isymb] |= 1; + } + } + + /* Ignorer les symboles spéciaux. */ + if ((isymb = tfm->trans[itrans].ss) >= 0) { + if (tampex_minim((void **)&dejala, isymb) < 0) + goto erreur3; + /* Ne pas ajouter le symbole s’il est déjà là. */ + if (!(dejala[isymb] & 2)) { + if (tampex_minim((void **)ss, iss) < 0) + goto erreur3; + (*ss)[iss++] = corr[isymb]; + dejala[isymb] |= 2; + } + } + } + } + + tampex_libr(dejala); + return 0; + +erreur3: + tampex_libr(dejala); +erreur2: + tampex_libr(ss); +erreur1: + tampex_libr(se); + return -1; +} + +static uint16_t (* +segmenteur(char *liste, uint16_t *tse))[2] +{ + struct tfm *symbs; /* Automate des symboles. */ + uint32_t *finaux; /* Identifiants de symboles associés aux états + finaux. */ + uint16_t (*pile)[2]; /* Pile: (i, e). */ + ssize_t ipile; /* Indice dans la pile. */ + uint16_t (*segm)[2]; /* Segmenteur (base, orig). */ + ssize_t base; + uint16_t petat, pbase; + size_t ntrans, itrans; + unsigned char c; assert(liste); + assert(tse); - /* Initialiser l’index des symboles. */ - if ((index = tampinf_init(TAMPON_LNGR_DEF, sizeof(size_t))) == NULL) + /* Initialiser la pile. */ + if ((pile = tampex_init(TAMPON_LNGR_DEF, sizeof *pile)) == NULL) return NULL; - /* Obtenir le contenu de la liste de symboles. */ - if ((ctn = tampinf_ctn(liste)) == NULL) - goto erreur; + /* Initialiser le segmenteur. */ + if ((segm = tampex_init(TAMPON_LNGR_DEF, sizeof *segm)) == NULL) + goto erreur1; + + /* Créer l’automate de symboles. */ + if ((symbs = automate_symbs(liste, tse, &finaux)) == NULL) + goto erreur2; + + /* Empiler le premier état. */ + if ((ipile = tampex_empl((void **)&pile)) < 0) + goto erreur3; + assert(ipile == 0); + pile[ipile][0] = 0; + pile[ipile][1] = 0; + + do { + /* Dépiler. */ + ipile = tampex_dpl(pile); + pbase = pile[ipile][0]; + petat = pile[ipile][1]; + + /* Si petat est un état final. */ + if (tfm_tfinal(symbs, petat)) { + if ((base = segmenteur_libre(&segm)) < 0) + goto erreur3; + segm[pbase][0] = (base << 1) | 0x01; + pbase = base; + segm[pbase][0] = 1; /* Réverver. */ + segm[pbase][1] = (finaux[petat] << 1) | 0x01; + } - /* Parcourir les symboles. */ - for (pos = 0; tampinf_dedans(liste, pos); pos += n + 1) { - n = ((unsigned char *)ctn)[pos]; - if (tampinf_ajt(index, 1, &pos) < 0) - goto erreur; - } + /* S’il y a des transitions sortantes. */ + if ((ntrans = symbs->etats[petat].ntrans) > 0) { + if ((base = segmenteur_base(&segm, symbs, petat)) < 0) + goto erreur3; + segm[pbase][0] = (base << 1) | 0x00; + for (itrans = symbs->etats[petat].trans; ntrans--; + itrans = symbs->trans[itrans].prch) { + assert(symbs->trans[itrans].se >= 0); + if (tfm_symb_obt(symbs, symbs->trans[itrans].se, + (char *)&c, 1) != 1) + goto erreur3; + segm[base + c][0] = 1; /* Réserver la paire. */ + segm[base + c][1] = (pbase << 1) | 0x00; + if ((ipile = tampex_empl((void **)&pile)) < 0) + goto erreur3; + pile[ipile][0] = base + c; + pile[ipile][1] = symbs->trans[itrans].ed; + } + } else { + segm[pbase][0] = (0 << 1) | 0x01; + } + } while (tampex_nelem(pile)); + + tfm_libr(symbs); + tampex_libr(finaux); + tampex_libr(pile); - return index; + return segm; -erreur: - tampinf_libr(liste); +erreur3: + tfm_libr(symbs); + tampex_libr(finaux); +erreur2: + tampex_libr(segm); +erreur1: + tampex_libr(pile); return NULL; } -/* La routine fonction en parcourant tous les symboles d’un transducteur. Pour - * chaque caractère du symbole courant converti à un symbole, en partant de - * l’état zéro de l’automate de symboles, vérifier si une transition sortante - * correspond au symbole courant. Si non, l’ajouter à l’automate. Sauter à - * l’état cible et recommencer avec le caractère suivant. Une fois arrivé au - * bout du symbole, marquer l’état courant comme final et placer l’identifiant - * du symbole dans *ti à l’indice correspondant à cet état final. */ -static struct tfm * -automate_symbs(struct tfm *tfm, struct tampinf **ti) +static int +segmenteur_tlibre(uint16_t (**segm)[2], size_t i) { - struct tfm *symbs; - struct trans trans; - struct etat etat; - char symb[TFM_TLL_SYMB_MAX]; /* Tampon à symbole. */ - ssize_t lngr; /* Longueur du symbole. */ - size_t id, idp; /* Identifiants de symbole, courant et précédent. */ - ssize_t ids; /* Identifiant de symbole dans symbs. */ - ssize_t ie, iep; /* Identifiants d’état, courant et précédent. */ - size_t ic; /* Indice du caractère dans symb. */ + int ret; + assert(segm); + + if (tampex_minim((void **)segm, i) < 0) + return -1; + if ((*segm)[i][0] == 0) + ret = 1; + else + ret = 0; + return ret; +} + +static ssize_t +segmenteur_libre(uint16_t (**segm)[2]) +{ + size_t i; + + assert(segm); + + for (i = 1;; i++) { + switch (segmenteur_tlibre(segm, i)) { + case 0: continue; + case 1: return i; + default: return -1; + } + } + + assert(0); +} +static ssize_t +segmenteur_base(uint16_t (**segm)[2], struct tfm *tfm, size_t ietat) +{ + size_t i; + size_t itrans, ntrans; + char c; + + assert(segm); assert(tfm); + for (i = 1;; i++) { + for (itrans = tfm->etats[ietat].trans, + ntrans = tfm->etats[ietat].ntrans; + ntrans--; itrans = tfm->trans[itrans].prch) { + assert(tfm->trans[itrans].se >= 0); + + if (tfm_symb_obt(tfm, tfm->trans[itrans].se, &c, 1) != 1) + return -1; + switch (segmenteur_tlibre(segm, i + (unsigned char)c)) { + case 0: goto encore; + case 1: continue; + default: return -1; + } + } + return i; + encore:; + } + + assert(0); +} + +/* La routine fonctionne en parcourant tous les symboles d’un transducteur. + * À chaque nouveau symbole, il parcourt l’automate de symboles à partir de son + * premier état et passe d’état en état en suivant les caractères du symbole et + * en ajoutant les transitions manquantes. */ +static struct tfm * +automate_symbs(char *liste, uint16_t *se, uint32_t **finaux) +{ + struct tfm *symbs; /* Automate de symboles. */ + size_t pos; /* Position courante la liste. */ + uint16_t isymb; /* Indice d’un symbole. */ + int lngr; /* Longueur du symbole .*/ + size_t ietat, ietatp; /* Identifiants des états courant et + précédent. */ + size_t ntrans; /* Nombre de transitions. */ + size_t itrans; /* Identifiant de transiton. */ + ssize_t id; /* Identifiant de symbole. */ + char c; /* Caractère. */ + + assert(liste); + assert(se); + assert(finaux); + /* Initialiser l’automate de symboles. */ if ((symbs = tfm_init()) == NULL) return NULL; - /* Initialiser le tampon infini. */ - if ((*ti = tampinf_init(TAMPON_LNGR_DEF, sizeof(size_t))) == NULL) { - tfm_libr(symbs); - return NULL; - } + /* Initialiser *finaux. */ + if ((*finaux = tampex_init(TAMPON_LNGR_DEF, sizeof(size_t))) == NULL) + goto erreur1; /* Créer le premier état. */ - etat.final = 0; - etat.ntrans = 0; - etat.trans = 0; - if (tampinf_ajt(symbs->etats, 1, &etat) < 0) - goto erreur; + if (tampex_minim((void **)&symbs->etats, 0) < 0) + goto erreur2; /* Parcourir les symboles. */ - for (idp = id = 0; (lngr = tfm_parc_symbs(tfm, &id, symb, - TFM_TLL_SYMB_MAX)) > 0; idp = id) { - /* Parcourir les caractères. */ - for (ie = ic = 0; ic < (size_t)lngr; ic++) { - /* Obtenir l’identifiant de symbole. */ - if (tfm_symb_id(symbs, symb + ic, 1, &ids) < 0) - goto erreur; - /* Obtenir le prochain état. */ - if (tampinf_obt(symbs->etats, ie, 1, &etat) < 0) - goto erreur; - /* Parcourir les transitions. */ - trans.prch = etat.trans; - while (etat.ntrans--) { - /* Obtenir la prochaine transition. */ - if (tampinf_obt(symbs->trans, trans.prch, 1, &trans) - < 0) - goto erreur; - if (trans.se == ids) { - ie = trans.ed; - goto pcar; /* Passer au prochain caractère. */ + for (isymb = 0; tampex_dedans(se, isymb); isymb++) { + pos = se[isymb]; + /* Obtenir la longueur du symbole. */ + lngr = ((unsigned char *)liste)[pos++]; + + /* Parcourir les caractères du symbole. */ + for (ietat = 0; lngr--; pos++) { + + /* Chercher une transition sortante pour liste[pos]. */ + for (ntrans = symbs->etats[ietat].ntrans, + itrans = symbs->etats[ietat].trans; + ntrans--; + itrans = symbs->trans[itrans].prch) { + if (tfm_symb_obt(symbs, symbs->trans[itrans].se, + &c, 1) != 1) + goto erreur2; + if (c == liste[pos]) { + /* La bonne transition a été trouvée. Passer au + * prochain caractère et au prochain état. */ + ietat = symbs->trans[itrans].ed; + goto pcar; } } - /* Puisqu’aucune transition adéquate n’a été trouvée, en - * créer une. */ - etat.final = 0; - etat.ntrans = 0; - etat.trans = 0; - iep = ie; - if ((ie = tampinf_ajt(symbs->etats, 1, &etat)) < 0) - goto erreur; - if (tfm_ajt(symbs, iep, ie, ids, TFM_SYMB_EPSILON) < 0) - goto erreur; + + /* Aucune transition adéquate n’a été trouvée. En ajouter + * une. */ + ietatp = ietat; + ietat = tampex_nelem(symbs->etats); + if (tampex_minim((void **)&symbs->etats, ietat) < 0) + goto erreur2; + if ((id = tfm_symb_id(symbs, liste + pos, 1)) < 0) + goto erreur2; + if (tfm_ajt(symbs, ietatp, ietat, id, id) < 0) + goto erreur2; pcar:; } + /* Marquer le dernier état d’un symbole comme final. */ - if (tfm_mfinal(symbs, ie) < 0) - goto erreur; - /* Associer l’identifiant du symbole à l’état. */ - if (tampinf_plc(*ti, ie, 1, &idp) < 0) - goto erreur; + if (tfm_mfinal(symbs, ietat) < 0) + goto erreur2; + if (tampex_minim((void **)finaux, ietat) < 0) + goto erreur2; + (*finaux)[ietat] = isymb; } - if (lngr < 0) - goto erreur; return symbs; -erreur: +erreur2: + tampex_libr(*finaux); +erreur1: tfm_libr(symbs); - tampinf_libr(*ti); return NULL; } diff --git a/tfd.h b/tfd.h @@ -8,75 +8,89 @@ /* Le format .tfd est une représentation binaire du transducteur. Il a été * conçu pour être rapide à charger et à interpréter: nul besoin de le * désérialiser pour l’interpréter, et les structures de données qu’il utilise - * dispense d’un maximum de recherche. L’asbsence de sérialisation et de - * désérialisation freine la portabilité du fichier. En particulier, le format - * utilise le boutisme de l’hôte qui le compile. + * dispensent d’un maximum de recherche. L’absence de sérialisation et de + * désérialisation limite la portabilité du fichier. En particulier, le format + * utilise le boutisme de l’hôte qui l’a compilé. * Le format est composé de cinq segments, indexés dans une entête placée en - * début de fichier. Les segments sont les suivants: index des symboles, liste - * de symboles, segmenteur, automate, tableau des identifiants de symbole de - * sortie. + * début de fichier. Les segments sont les suivants: + * + * - liste des symboles, + * - liste des identifiants de symbole d’entrée + * - liste des identifiants de symbole de sortie + * - segmentaur + * - automate * * L’entête contient les champs suivants: * * 00 02 Nombre magique (0h5407) * 02 04 Version (0) - * 04 06 Position de l’index des symboles - * 06 08 Taille du l’index des symboles - * 08 0a Position de la liste de symboles - * 0a 0c Taille de la liste de symboles - * 0c 0e Position du segmenteur - * 0e 10 Taille du segmenteur - * 10 12 Position de l’automate - * 12 14 Taille de l’automate - * 14 16 Position des identifiants de symbole de sortie - * 16 18 Taille des identifiants de symbole de sortie + * 04 08 Décalage de la liste des symboles + * 08 0c Taille de la liste des symboles + * 0c 10 Décalage de la liste des identifiants de symbole d’entrée + * 10 14 Taille de la liste des identifiants de symbole d’entrée + * 14 18 Décalage de la liste des identifiants de symbole de sortie + * 18 0c Taille de la liste des identifiants de symbole de sortie + * 0c 20 Décalage du segmenteur + * 20 24 Taille du segmenteur + * 24 28 Décalage de l’automate + * 28 2c Taille de l’automate */ #define TFD_MAGIQUE 0x5407 #define TFD_VERSION 0 -#define TFD_ENTETE_FIN 0x18 +#define TFD_ENTETE_TLL 0x2c /* La liste des symboles se présente comme une suite chaînes de caractères * encodées à la Pascal, dans lesquelles les chaînes sont immédiatement * précédées d’un octet donnant la taille de la chaîne le suivant. * - * L’index des symboles est un tableau de pointeurs vers les symboles de la - * liste de symboles. Les identifiants de symbole sont des indices dans l’index - * des symboles. - * - * La structure du segmenteur s’inspire de la structure à deux tableaux proposée - * par Aho (1989: An Efficient Digital Search Algorithm by Using a Double-Array - * Structure). Elle consiste en un tableau dont les cellules contiennent - * chacune deux champs: la base et l’origine. Chaque champ occupe 2 octets, pour - * un total de 4 octets par cellule. Ces deux champs contiennent un drapeau dans - * leur bit le plus à droite. Celui de la base marque un état comme final (1) ou - * comme non-final (0); celui de l’origine indique si le champ doit bel et bien - * être interprété comme une origine (0), ou comme un identifiant de symbole. - * Une paire (base, origine) représente un état. Un état peut être désigné par - * son indice i. On passe d’un état à l’autre par la formule + * Les listes des identifiants de symbole d’entrée et de sortie sont une suite + * d’adresses relatives au début de la liste des symboles vers les symboles + * d’entrée ou de sortie, respectivement. + * + * La structure du segmenteur s’inspire de la structure à deux tableaux + * proposée par Aho (1989: An Efficient Digital Search Algorithm by Using a + * Double-Array Structure). Elle consiste en un tableau dont les cellules + * contiennent chacune chacune deux champs: la base ([0]) et l’origine ([1]). + * Chaque champ occupe 2 octets, pour un total de 4 octets par cellule. Ces + * deux champs contiennent un drapeau dans leur bit de poids faible. Celui de + * la base marque un état comme final (1) ou comme non-final (0); celui de + * l’origine indique si le champ doit bel et bien être interprété comme une + * origine (0), ou comme un identifiant de symbole. Le champ base doit avoir + * une valeur supérieure à 0, sauf si le bit de poids faible est activé: alors, + * c’est signe que l’état ne contient pas de transition sortante. Une paire + * (base, origine) représente un état. Un état peut être désigné par son indice + * i. On passe d’un état à l’autre par la formule * - * i' = paire[i].base >> 1 + s, + * i' = (paire[i][0] >> 1) + s, * - * où s est un symbole d’entrée. Pour que la transition soit valide, il faut en - * plus satisfaire les équation suivante: + * où s est un symbole d’entrée. Pour que la transition soit valide, les + * conditions suivantes doivent aussi être satisfaites: * - * paire[i'].orig & 1 == 0, - * paire[i'].orig >> 1 == i. + * (paire[i'][1] & 1) == 0, + * (paire[i'][1] >> 1) == i. * * Autrement, on pourrait quitter n’importe quel état avec n’importe quel * symbole. - * Si, cependant, le drapeau de la base d’un symbole est brandi, * - * i'' = paire[i'].base >> 1 et - * symbole = paire[i''].orig >> 1. + * Si, cependant, le drapeau de la base d’un symbole est brandi, il s’agit + * d’un état final et + * + * i'' = paire[i'][0] >> 1 et + * symbole = paire[i''][1] >> 1. + * + * C’est-à-dire que le champ origine de l’état vers lequel il pointe représente + * en fait un symbole et que le champ base contient l’identifiant le l’état + * suivant. * - * La variable symbole contient l’identifiant du symbole. Elle est mise à jour - * chaque fois qu’un état final est rencontré parce que le segmenteur est - * glouton: il tente de reconnaître le symbole le plus long, ignorant ses - * préfixes qui sont aussi des symboles. Lorsque plus aucune transition n’existe - * qui n’accepte le prochain symbole d’entrée, le dernier symbole assigné est - * retourné et la position dans le mot entrée courante au moment où ce symbole - * a été assigné est restorée. + * La variable symbole contient l’identifiant du symbole. Lors de + * l’interprétation du segmenteur, elle est mise à jour chaque fois qu’un état + * final est rencontré, parce que le segmenteur est glouton: il tente de + * reconnaître le symbole le plus long, ignorant ses préfixes qui sont aussi + * des symboles. Lorsque plus aucune transition n’existe qui n’accepte le + * prochain symbole d’entrée, le dernier symbole assigné est retourné et la + * position dans le mot entrée courante au moment où ce symbole a été assigné + * est restorée. * * La structure de l’automate est aussi un tableau double. Elle s’inspire * cependant de l’extension de Mizobuchi, Sumitomo, Fuketa & Aoe (2000: An @@ -94,7 +108,7 @@ * tous être déterminisés: un symbole d’entrée peut mener à plus d’une * transition. La solution que je propose est de créer, dans ces cas, une liste * chaînée de transitions. Cette liste est signalée par un drapeau brandi dans - * le bit le plus à droite du champ origine. Les drapeaux de la base et de + * le bit de poids faible du champ origine. Les drapeaux de la base et de * l’origine ne peuvent être brandis en même temps. On passe d’un état à l’autre * par la formule: *