trafi

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

commit c9dc5b7b93c6b562aedfb90cf1bc914a110170e8
parent dcbe1426ea6217b983631500641676c60077c719
Auteur: Loïc Daignault-Pichette <loic@asteride.xyz>
Date:   Fri, 10 Apr 2026 22:14:29 -0400

Réintégrer les listes d’identifiants de symbole

Il s’agit des liste d’identifiants de symbole d’entrée et de sortie.

Diffstat:
Mitfd.c | 19+++++++++++--------
Mitfd.h | 24++++++++++++++----------
Mtfd.c | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mtfd.h | 25++++++++++++++++++-------
4 fichiers modifiés, 156 insertions(+), 75 suppressions(-)

diff --git a/itfd.c b/itfd.c @@ -57,15 +57,18 @@ itfd_ouvrir(int df) /* Lire les informations sur les segments. */ itfd->symbs = itfd->f + LIRE_32(itfd->f, 0x06); itfd->symbs_lngr = LIRE_32(itfd->f, 0x0A); - itfd->segm = itfd->f + LIRE_32(itfd->f, 0x0E); - itfd->segm_lngr = LIRE_32(itfd->f, 0x12); - itfd->trans = itfd->f + LIRE_32(itfd->f, 0x16); - itfd->trans_lngr = LIRE_32(itfd->f, 0x1A); - if (itfd->symbs + itfd->symbs_lngr != itfd->segm) - goto erreur2; - if (itfd->segm + itfd->segm_lngr != itfd->trans) - goto erreur2; + itfd->se = itfd->f + LIRE_32(itfd->f, 0x0E); + itfd->se_lngr = LIRE_32(itfd->f, 0x12); + + itfd->ss = itfd->f + LIRE_32(itfd->f, 0x16); + itfd->ss_lngr = LIRE_32(itfd->f, 0x1A); + + itfd->segm = itfd->f + LIRE_32(itfd->f, 0x1E); + itfd->segm_lngr = LIRE_32(itfd->f, 0x22); + + itfd->trans = itfd->f + LIRE_32(itfd->f, 0x26); + itfd->trans_lngr = LIRE_32(itfd->f, 0x2A); return itfd; diff --git a/itfd.h b/itfd.h @@ -6,16 +6,20 @@ /* Interpréter un transducteur fini sur le disque. */ struct itfd { - int df; /* Descripteur de fichier. */ - uint8_t *f; /* Contenu du fichier. */ - off_t lngr; /* Longueur du fichier, en octets. */ - int version; /* Version du format tfd. */ - uint8_t *symbs; /* Position de la liste de symboles. */ - size_t symbs_lngr; /* Longueur de la liste de symboles. */ - uint8_t *segm; /* Position du segmenteur. */ - size_t segm_lngr; /* Longueur du segmenteur. */ - uint8_t *trans; /* Position du transducteur. */ - size_t trans_lngr; /* Longueur du transducteur. */ + int df; /* Descripteur de fichier. */ + uint8_t *f; /* Contenu du fichier. */ + off_t lngr; /* Longueur du fichier, en octets. */ + int version; /* Version du format tfd. */ + uint8_t *symbs; /* Position de la liste de symboles. */ + size_t symbs_lngr; /* Longueur de la liste de symboles. */ + uint8_t *se; /* Position de la liste de symboles d’entrée. */ + size_t se_lngr; /* Longueur de la liste de symboles d’entrée. */ + uint8_t *ss; /* Position de la liste de symboles de sortie. */ + size_t ss_lngr; /* Longueur de la liste de symboles de sortie. */ + uint8_t *segm; /* Position du segmenteur. */ + size_t segm_lngr; /* Longueur du segmenteur. */ + uint8_t *trans; /* Position du transducteur. */ + size_t trans_lngr; /* Longueur du transducteur. */ }; /* Ouvrir un fichier tfd pour l’interpréter. diff --git a/tfd.c b/tfd.c @@ -24,7 +24,7 @@ static void *ecrire_32(void *tp, uint32_t val); /* Créer le segmenteur de symboles. * Renvoie un pointeur vers un tampex, ou NULL en cas d’erreur. */ -static void *segmenteur(struct tfm *tfm); +static void *segmenteur(struct tfm *tfm, uint16_t *se); /* Trouver une paire libre dans le segmenteur. * Renvoie l’indice de la paire trouvée, ou -1 en cas d’erreur. */ @@ -43,14 +43,16 @@ static int segmenteur_tlibre(uint16_t (**segm)[2], size_t i); /* Créer un automate au format tfm à partir d’une liste de symboles d’entrée. * Renvoie un pointeur vers un tfm, ou NULL en cas d’erreur. */ -static struct tfm *automate_symbs(struct tfm *tfm, uint32_t **finaux); +static struct tfm *automate_symbs(struct tfm *tfm, uint16_t *se, + uint32_t **finaux); -/* Créer la liste des identifiants de symbole utilisés comme symboles d’entrée. - * Renvoie un pointeur vers un tampex, ou NULL en cas d’erreur. */ -static uint16_t *symboles_entree(struct tfm *tfm); +/* Obtenir la liste des identifiants de symbole d’entrée (se) et de sortie (ss) + * du tranducteur tfm. + * Renvoie 0, ou -1 en cas d’erreur. */ +static int symboles_id(struct tfm *tfm, uint16_t **se, uint16_t **ss); /* Afficher un segmenteur en sortie standard. */ -static void segmenteur_afficher(struct tfm *tfm); +static void segmenteur_afficher(struct tfm *tfm, uint16_t *se); /* Créer le transducteur à parir d’un tfm. * Renvoie un pointeur vers un tampex, ou NULL en cas d’erreur. */ @@ -63,6 +65,7 @@ tfd_ecrire(FILE *f, struct tfm *tfm) uint8_t *pent; /* Pointeur vers l’entête. */ size_t dec; /* Décalage courant dans le fichier. */ void *te; /* Pointeur réutilisable vers un tampon extensible. */ + void *se; /* Liste d’identifiants de symboles d’entrée. */ size_t lngr; /* Longueur d’un tampon. */ assert(f); @@ -98,15 +101,57 @@ tfd_ecrire(FILE *f, struct tfm *tfm) if (fseek(f, dec, SEEK_SET) != 0) return -1; + /* Écrire la liste d’identifiants de symbole d’entrée. */ + if (symboles_id(tfm, (uint16_t **)&se, (uint16_t **)&te) < 0) + return -1; + lngr = tampex_esp(se); + if (fwrite(se, 1, lngr, f) != lngr) { + tampex_libr(se); + tampex_libr(te); + return -1; + } + pent = ecrire_32(pent, dec); + pent = ecrire_32(pent, lngr); + + dec += lngr; + dec = ALIGNER(dec, 2); + if (fseek(f, dec, SEEK_SET) != 0) { + tampex_libr(se); + tampex_libr(te); + return -1; + } + + /* Écrire la liste d’identifiants de symbole de sortie. */ + lngr = tampex_esp(te); + if (fwrite(te, 1, lngr, f) != lngr) { + tampex_libr(se); + tampex_libr(te); + return -1; + } + tampex_libr(te); + pent = ecrire_32(pent, dec); + pent = ecrire_32(pent, lngr); + + dec += lngr; + dec = ALIGNER(dec, 2); + if (fseek(f, dec, SEEK_SET) != 0) { + tampex_libr(se); + return -1; + } + /* Écrire le segmenteur. */ - if ((te = segmenteur(tfm)) == NULL) + if ((te = segmenteur(tfm, se)) == NULL) { + tampex_libr(se); return -1; + } lngr = tampex_esp(te); if (fwrite(te, 1, lngr, f) != lngr) { tampex_libr(te); + tampex_libr(se); return -1; } tampex_libr(te); + tampex_libr(se); pent = ecrire_32(pent, dec); pent = ecrire_32(pent, lngr); @@ -157,7 +202,7 @@ ecrire_32(void *tp, uint32_t val) } static void * -segmenteur(struct tfm *tfm) +segmenteur(struct tfm *tfm, uint16_t *se) { uint16_t (*segm)[2]; /* Segmenteur (base, origine). */ struct tfm *symbs; /* Automate des symboles. */ @@ -179,7 +224,7 @@ segmenteur(struct tfm *tfm) goto erreur1; /* Créer l’automate de symboles. */ - if ((symbs = automate_symbs(tfm, &finaux)) == NULL) + if ((symbs = automate_symbs(tfm, se, &finaux)) == NULL) goto erreur2; /* Le premier état ne peut être final; car un symbole doit avoir une @@ -222,13 +267,13 @@ segmenteur(struct tfm *tfm) ntrans--; itrans = symbs->trans[itrans].prch) { assert((symbs->trans[itrans].se & 0x01) == - TFM_SNORMAL); + TFM_SNORMAL); 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] = (isegm << 1) | 0x00; - bmax = MAX(isegm, bmax); + bmax = MAX(isegm, bmax); if ((ipile = tampex_empl((void **)&pile)) < 0) goto erreur3; pile[ipile][0] = base + c; @@ -249,7 +294,7 @@ segmenteur(struct tfm *tfm) /* Désactiver les paires vides. */ for (isegm = 0; tampex_dedans(segm, isegm); isegm++) if (segm[isegm][0] == 0) - segm[isegm][1] = (0 << 1) | 0x01; + segm[isegm][1] = (0 << 1) | 0x01; return segm; @@ -329,7 +374,7 @@ segmenteur_tlibre(uint16_t (**segm)[2], size_t i) } static void -segmenteur_afficher(struct tfm *tfm) +segmenteur_afficher(struct tfm *tfm, uint16_t *se) { size_t i; uint16_t (*segm)[2]; @@ -337,7 +382,7 @@ segmenteur_afficher(struct tfm *tfm) assert(tfm); assert(segm); - segm = segmenteur(tfm); + segm = segmenteur(tfm, se); for (i = 0; tampex_dedans(segm, i); i++) { printf("%lu\t%s%u\t%s%u", @@ -362,10 +407,9 @@ segmenteur_afficher(struct tfm *tfm) * 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(struct tfm *tfm, uint32_t **finaux) +automate_symbs(struct tfm *tfm, uint16_t *se, uint32_t **finaux) { struct tfm *symbs; - uint16_t *se; /* Liste de symboles d’entrée. */ size_t pos; /* Position courante dans la liste de symboles. */ uint16_t isymb; /* Indice d’un symbole. */ ssize_t id; /* Identifiant de symbole. */ @@ -382,16 +426,13 @@ automate_symbs(struct tfm *tfm, uint32_t **finaux) if ((symbs = tfm_init()) == NULL) return NULL; - if ((se = symboles_entree(tfm)) == NULL) - goto erreur1; - /* Initialiser *finaux. */ if ((*finaux = tampex_init(TAMPON_LNGR_DEF, sizeof(uint32_t))) == NULL) - goto erreur2; + goto erreur1; /* Créer le premier état. */ if (tampex_minim((void **)&symbs->etats, 0) < 0) - goto erreur3; + goto erreur2; /* Parcourir les symboles. */ for (isymb = 0; tampex_dedans(se, isymb); isymb++) { @@ -410,7 +451,7 @@ automate_symbs(struct tfm *tfm, uint32_t **finaux) itrans = symbs->trans[itrans].prch) { if (tfm_symb_obt(symbs, symbs->trans[itrans].se, &c, 1) != 1) - goto erreur3; + goto erreur2; if (c == tfm->symbs[pos]) { /* La bonne transition a été trouvée. Passer au * prochain caractère et au prochain état. */ @@ -424,53 +465,54 @@ automate_symbs(struct tfm *tfm, uint32_t **finaux) ietatp = ietat; ietat = tampex_nelem(symbs->etats); if (tampex_minim((void **)&symbs->etats, ietat) < 0) - goto erreur3; + goto erreur2; if ((id = tfm_symb_id(symbs, tfm->symbs + pos, 1)) < 0) - goto erreur3; + goto erreur2; if (tfm_ajt(symbs, ietatp, ietat, id, id) < 0) - goto erreur3; + goto erreur2; pcar:; } /* Marquer le dernier état d’un symbole comme final. */ if (tfm_mfinal(symbs, ietat) < 0) - goto erreur3; + goto erreur2; if (tampex_minim((void **)finaux, ietat) < 0) - goto erreur3; + goto erreur2; (*finaux)[ietat] = se[isymb]; } - tampex_libr(se); return symbs; -erreur3: - tampex_libr(*finaux); erreur2: - tampex_libr(se); + tampex_libr(*finaux); erreur1: tfm_libr(symbs); return NULL; } -static uint16_t * -symboles_entree(struct tfm *tfm) +static int +symboles_id(struct tfm *tfm, uint16_t **se, uint16_t **ss) { - uint16_t *se; - size_t i; /* Indice dans se. */ - bool *dejala; /* Indique si l’identifiant est déjà dans se. */ + size_t ise, iss; /* Indices dans se et ss. */ + char *dejala; /* Indique si l’identifiant est déjà dans se (& 0x01) ou + dans ss (& 0x02). */ size_t ietat, ntrans, itrans; size_t isymb; /* Identifiant de symbole. */ assert(tfm); + assert(se); + assert(ss); - /* Initialiser se et dejala. */ - if ((se = tampex_init(TAMPON_LNGR_DEF, sizeof(uint16_t))) == NULL) - return NULL; - if ((dejala = tampex_init(TAMPON_LNGR_DEF, sizeof *dejala)) == NULL) + /* Initialiser se, ss et dejala. */ + if ((*se = tampex_init(TAMPON_LNGR_DEF, sizeof(uint16_t))) == NULL) + return -1; + if ((*ss = tampex_init(TAMPON_LNGR_DEF, sizeof(uint16_t))) == NULL) goto erreur1; + if ((dejala = tampex_init(TAMPON_LNGR_DEF, sizeof *dejala)) == NULL) + goto erreur2; - i = 0; + ise = iss = 0; /* Parcourir les états. */ for (ietat = 0; tampex_dedans(tfm->etats, ietat); ietat++) { @@ -478,6 +520,8 @@ symboles_entree(struct tfm *tfm) for (itrans = tfm->etats[ietat].trans, ntrans = tfm->etats[ietat].ntrans; ntrans--; itrans = tfm->trans[itrans].prch) { + + /* Symbole d’entrée. */ /* Ignorer les symboles spéciaux. */ if (((isymb = tfm->trans[itrans].se) & 0x01) == TFM_SSPECIAL) @@ -485,25 +529,44 @@ symboles_entree(struct tfm *tfm) isymb >>= 1; /* Ne pas ajouter le symbole s’il est déjà la. */ if (tampex_minim((void **)&dejala, isymb) < 0) - goto erreur2; - if (dejala[isymb]) + goto erreur3; + if (dejala[isymb] & 0x01) continue; /* Ajouter le symbole. */ - if (tampex_minim((void **)&se, i) < 0) - goto erreur2; - se[i++] = isymb; - dejala[isymb] = 1; + if (tampex_minim((void **)se, ise) < 0) + goto erreur3; + (*se)[ise++] = isymb; + dejala[isymb] |= 0x01; + + /* Symbole de sortie. */ + /* Ignorer les symboles spéciaux. */ + if (((isymb = tfm->trans[itrans].ss) & 0x01) == + TFM_SSPECIAL) + continue; + isymb >>= 1; + /* Ne pas ajouter le symbole s’il est déjà la. */ + if (tampex_minim((void **)&dejala, isymb) < 0) + goto erreur3; + if (dejala[isymb] & 0x02) + continue; + /* Ajouter le symbole. */ + if (tampex_minim((void **)ss, iss) < 0) + goto erreur3; + (*ss)[iss++] = isymb; + dejala[isymb] |= 0x02; } } tampex_libr(dejala); - return se; + return 0; -erreur2: +erreur3: tampex_libr(dejala); +erreur2: + tampex_libr(ss); erreur1: tampex_libr(se); - return NULL; + return -1; } static void * diff --git a/tfd.h b/tfd.h @@ -12,10 +12,11 @@ * de presque toutes les valeurs qu’il contient suivent le boutisme de l’hôte * qui l’a compilé. * - * Le format comprend une entête et trois segments. L’entête contient des + * Le format comprend une entête et cinq segments. L’entête contient des * informations sur le fichier, de même que l’emplacement et la longueur de * chacun des trois segments. Les segments sont les suivants: liste des - * symboles, segmenteur et transducteur. + * symboles, liste d’identifiants de symbole d’entrée, liste d’identifiant de + * symbole de sortie, segmenteur et transducteur. * * L’entête contient les champs suivants: * @@ -24,10 +25,14 @@ * 04 05 Témoin de boutisme (0h00FF) * 06 09 Emplacement de la liste des symboles * 0A 0D Longueur de la liste des symboles - * 0e 11 Emplacement du segmenteur - * 12 15 Longueur du segmenteur - * 16 19 Emplacement du transducteur - * 1A 1D Longueur du transducteur + * 0E 11 Emplacement de la liste d’identifiants de symbole d’entrée + * 12 15 Longueur de la liste d’identifiants de symbole d’entrée + * 16 19 Emplacement de la liste d’identifiants de symbole de sortie + * 1A 1D Longueur de la liste d’identifiants de symbole de sortie + * 1E 21 Emplacement du segmenteur + * 22 25 Longueur du segmenteur + * 26 29 Emplacement du transducteur + * 2A 2D Longueur du transducteur * * Le nombre magique (0h5407) sert à identifier un fichier comme un fichier au * format tfd. Le champ suivant indique la version du format utilisé. Le témoin @@ -42,13 +47,19 @@ #define TFD_MAGIQUE 0x5407 /* Nombre magique. */ #define TFD_VERSION 0 /* Version courante. */ #define TFD_TEMOIN 0x00FF /* Témoin de boutisme. */ -#define TFD_ENTETE_TLL 0x1E /* Taille de l’entête. */ +#define TFD_ENTETE_TLL 0x2E /* Taille de l’entête. */ /* La liste de symboles et le segmenteur de symboles permettent au transducteur * de manipuler des symboles de plusieurs octets. Les identifiants de symbole * renvoyés par le segmenteur et reçus et renvoyés par le transducteur sont des * indices dans la liste de symboles. * + * La liste d’identifiants de symbole d’entrée est incluse pour permettre la + * génération de mots d’entrée. + * + * La liste d’identifiants de symbole de sortie est incluse pour permettre la + * génération de mots de sortie en présence du symbole spécial AUTRE. + * * 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 non-signé donnant la taille de la chaîne le suivant. La