trafi

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

commit 6bba0ec8dc617d4f59aeda294d4c7282a31e4e47
parent 5d1207c89094b0c740ce0c9fc6285ce6a47b78b0
Auteur: Loïc Daignault-Pichette <loic@asteride.xyz>
Date:   Sat,  4 Apr 2026 14:56:16 -0400

Revamper tout sauf les tfd

Diffstat:
MMakefile | 4++--
Matt.c | 62++++++++++++++++++++++++++++++++++++++++----------------------
Matt.h | 14+++++++-------
Mattvtfd.c | 5++---
Atampex.c | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atampex.h | 47+++++++++++++++++++++++++++++++++++++++++++++++
Dtampinf.c | 146-------------------------------------------------------------------------------
Dtampinf.h | 42------------------------------------------
Mtfm.c | 208+++++++++++++++++++++++++++++++++++--------------------------------------------
Mtfm.h | 68+++++++++++++++++++++++++++++++-------------------------------------
10 fichiers modifiés, 373 insertions(+), 376 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 tampinf.o tfm.o att.o tfd.o - ${CC} ${COPTS} -o "$@" attvtfd.o tampinf.o tfm.o att.o tfd.o +attvtfd: attvtfd.o tampex.o tfm.o att.o + ${CC} ${COPTS} -o "$@" attvtfd.o tampex.o tfm.o att.o net: rm -rf attvtfd *.o *.core diff --git a/att.c b/att.c @@ -1,9 +1,10 @@ #include <assert.h> #include <stddef.h> +#include <stdio.h> #include <string.h> #include "att.h" -#include "tampinf.h" +#include "tampex.h" #include "tfm.h" /* Séparateurs de champs. */ @@ -34,7 +35,7 @@ static int ajt_symb(struct tfm *tfm, char *t, size_t noct, ssize_t *id); * de symbole spéciaux. Renvoie la taille du symbole, ou -1 en cas d’erreur. */ static ssize_t symb_obt(struct tfm *tfm, ssize_t id, char *symb, size_t max); -/* Préparer la lecture du fichier f. +/* Lire un fichier au format .att. * La routine se fait peut-être une idée trop stricte du format .att et n’est * pas très flexible. */ struct tfm * @@ -55,6 +56,7 @@ att_lire(FILE *f) for (;;) { /* Premier champ: état source ou état final. */ switch (lire_champ(f, champ, TFM_TLL_SYMB_MAX, &noct)) { + default: assert(0); case SEP_ERR: goto erreur; case SEP_EOF: @@ -77,8 +79,9 @@ att_lire(FILE *f) /* Deuxième champ: état suivant. */ switch (lire_champ(f, champ, TFM_TLL_SYMB_MAX, &noct)) { + default: assert(0); case SEP_ERR: case SEP_EOF: case SEP_NL: - /* Une ligne ne peut contenir que deux champs. */ + /* Une ligne ne peut contenir seulement deux champs. */ goto erreur; case SEP_TB: /* Sauvegarder le champ dans ed. */ @@ -88,8 +91,9 @@ att_lire(FILE *f) /* Troisième champ: symbole d’entrée. */ switch (lire_champ(f, champ, TFM_TLL_SYMB_MAX, &noct)) { + default: assert(0); case SEP_ERR: case SEP_EOF: case SEP_NL: - /* Une ligne ne peut contenir que trois champs. */ + /* Une ligne ne peut contenir seulement trois champs. */ goto erreur; case SEP_TB: /* Sauvegarder le champ dans se. */ @@ -99,6 +103,7 @@ att_lire(FILE *f) /* Quatrième champ: symbole de sortie. */ switch (lire_champ(f, champ, TFM_TLL_SYMB_MAX, &noct)) { + default: assert(0); case SEP_ERR: case SEP_EOF: /* Doit se terminer sur une nouvelle ligne. */ case SEP_TB: /* Il ne peut y avoir plus de quatre champs. */ @@ -123,35 +128,40 @@ erreur: int att_ecrire(FILE *f, struct tfm *tfm) { - struct etat etat; - struct trans trans; - size_t ietat, itrans; - char symb[TFM_TLL_SYMB_MAX]; + size_t ietat; + size_t ntrans; + size_t itrans; ssize_t lngr; + char symb[TFM_TLL_SYMB_MAX]; assert(f); assert(tfm); /* Parcourir les états. */ - for (ietat = 0; tampinf_dedans(tfm->etats, ietat); ietat++) { - if (tampinf_obt(tfm->etats, ietat, 1, &etat) < 0) - return -1; + for (ietat = 0; tampex_dedans(tfm->etats, ietat); ietat++) { /* Parcourir les transitions. */ - for (itrans = etat.trans; etat.ntrans--; itrans = trans.prch) { - if (tampinf_obt(tfm->trans, itrans, 1, &trans) < 0) - return -1; - fprintf(f, "%zu\t%zu\t", ietat, trans.ed); - if ((lngr = symb_obt(tfm, trans.se, symb, + for (ntrans = tfm->etats[ietat].ntrans, + itrans = tfm->etats[ietat].trans; + ntrans--; + itrans = tfm->trans[itrans].prch) { + /* Afficher les états source et destination. */ + fprintf(f, "%zu\t%zu\t", ietat, tfm->trans[itrans].ed); + + /* Afficher le symbole d’entrée. */ + if ((lngr = symb_obt(tfm, tfm->trans[itrans].se, symb, TFM_TLL_SYMB_MAX)) < 0) return -1; fwrite(symb, 1, lngr, f); fputc('\t', f); - if ((lngr = symb_obt(tfm, trans.ss, symb, + + /* Afficher le symbole de sortie. */ + if ((lngr = symb_obt(tfm, tfm->trans[itrans].ss, symb, TFM_TLL_SYMB_MAX)) < 0) return -1; fwrite(symb, 1, lngr, f); - fputc('\n', f); + fprintf(f, "\n"); } + /* Afficher les transitions finales. */ if (tfm_tfinal(tfm, ietat)) fprintf(f, "%zu\n", ietat); @@ -168,6 +178,7 @@ lire_champ(FILE *f, char *t, size_t max, size_t *noct) assert(f); assert(t); + assert(max > 0); assert(noct); /* Si déjà la fin, renvoyer EOF. */ @@ -178,7 +189,7 @@ lire_champ(FILE *f, char *t, size_t max, size_t *noct) * jusqu’à ce que le tampon soit plein. */ for (i = 0; c != '\t' && c != '\n' && c != EOF; t[i++] = c, c = getc(f)) if (i >= max) - return SEP_ERR; + return SEP_ERR; *noct = i; @@ -198,10 +209,11 @@ nombre(char *t, size_t noct) size_t n; assert(t); + assert(noct > 0); for (i = n = 0; i < noct; n = n * 10 + (t[i++] - '0')) { if (t[i] < '0' || t[i] > '9') - return -1; + return -1; } return n; @@ -212,15 +224,21 @@ ajt_symb(struct tfm *tfm, char *t, size_t noct, ssize_t *id) { assert(tfm); assert(t); + assert(noct > 0); assert(id); /* Intercepter les symboles spéciaux. */ - if (noct == 3 && strncmp(t, "@0@", noct) == 0) { + if (noct == 3 && memcmp(t, "@0@", noct) == 0) { *id = TFM_SYMB_EPSILON; return 0; } - return tfm_symb_id(tfm, t, noct, id); + if ((*id = tfm_symb_id(tfm, t, noct)) < 0) + return -1; + + assert(*id >= 0); + + return 0; } static ssize_t diff --git a/att.h b/att.h @@ -8,24 +8,24 @@ /* Le format .att est composé de lignes et de champs. Les champs d’une même * ligne sont séparés par un caractère de tabulation. Il existe deux types de * lignes: l’un déclare une transition, l’autre un état comme final. On les - * distingue selon le nombre de champs que contient la ligne. Les transitions - * comptent quatre champs, qui sont: le numéro de l’état source, le numéro de - * l’état destination, le symbole d’entrée et le symbole de sortie. En voici un - * exemple: + * distingue selon le nombre de champs que contient la ligne. Les lignes du + * premier type comptent quatre champs, qui sont: l’identifiant de l’état + * source, l’identifiant de l’état destination, le symbole d’entrée et le + * symbole de sortie. Par exemple: * * 0 1 ᵘ u * * Certains symboles sont interprétés différemment par foma. La présente mise en * œuvre reconnaît @0@ comme le symbole epsilon (ε). D’autres sont à venir. * - * Les lignes qui déclarent un état comme final ne comptent qu’un seul champ, - * qu’occupe le numéro de l’état final. Par exemple: + * Les lignes du deuxième type ne comptent qu’un seul champ, qu’occupe + * l’identifiant d’un état à déclarer comme final. Par exemple: * * 1 */ /* Lire le fichier f au format .att. - * Initialise et renvoie un transducteur au format struct tfm, un NULL en cas + * Initialise et renvoie un transducteur au format struct tfm, ou NULL en cas * d’erreur. */ struct tfm *att_lire(FILE *f); diff --git a/attvtfd.c b/attvtfd.c @@ -2,7 +2,6 @@ #include "att.h" #include "tfm.h" -#include "tfd.h" int main(int argc, char **argv) @@ -25,8 +24,8 @@ main(int argc, char **argv) return 1; } - if (tfd_ecrire(ftfd, tfm) < 0) { - fprintf(stderr, "attvtf: erreur dans l’écriture du fichier .tfd\n"); + if (att_ecrire(ftfd, tfm) < 0) { + fprintf(stderr, "attvtf: erreur dans l’écriture du fichier .att\n"); return 1; } diff --git a/tampex.c b/tampex.c @@ -0,0 +1,153 @@ +#include <assert.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "tampex.h" + +/* Calculer l’adresse de l’entête d’un tampex. */ +#define ENTETE(te) ((Entete *)te - 1) + +/* Calculer l’adresse du tampon d’un tampex. */ +#define TAMPON(ent) (ent + 1) + +/* Tester la cohérence d’un tampex. */ +#define TAMPINF_COHERENT(te) \ + /* Le pointeur n’est pas NULL. */ \ + assert(ENTETE(te)); \ + /* Un élément a une taille supérieure à zéro. */ \ + assert((ENTETE(te))->s.tll > 0); \ + /* Le tampon peut contenir au moins un élément. */ \ + assert((ENTETE(te))->s.lngr > 0); \ + /* Le nombre d’éléments est inférieur ou égal à la longueur. */ \ + assert((ENTETE(te))->s.nelem <= (ENTETE(te))->s.lngr); + +/* La structure du tampon extensible a été conçue pour que son utilisation + * ressemble le plus possible à celle des tampons renvoyés par malloc(3). C’est + * donc sous cette forme qu’ils se présentent à l’utilisateur. Or, une partie + * de la réalité lui est cachée, car sous le tampon qui lui est renvoyé se + * trouve une entête contenant l’information nécessaire au bon fonctionnement + * des fonctions de cette bilbiothèque: la taille des éléments du tampon, + * exprimée en octets, la longueur du tampon, excluant l’entête et exprimée en + * multiples de la taille, et enfin le nombre d’éléments que contient le + * tampon. */ + +/* Entête d’un tampex. + * L’union assure que l’entête occupe un multiple de sizeof(long) octets. Cette + * solution vient de la seconde édition de The C Programming Language. */ +typedef union entete { + struct { + size_t tll; /* Taille des éléments. */ + size_t lngr; /* Longueur du tampon. */ + size_t nelem; /* Nombre d’éléments dans le tampon. */ + } s; + long alignement; +} Entete; + +void * +tampex_init(size_t lngr, size_t tll) +{ + Entete *ent; + + assert(lngr > 0); + assert(tll > 0); + + if ((ent = malloc(sizeof(Entete) + lngr * tll)) == NULL) + return NULL; + + ent->s.tll = tll; + ent->s.lngr = lngr; + ent->s.nelem = 0; + + /* Initialiser le tampon à zéro. */ + tampex_reinit(TAMPON(ent)); + + TAMPINF_COHERENT(TAMPON(ent)); + + return TAMPON(ent); +} + +void +tampex_reinit(void *ti) +{ + TAMPINF_COHERENT(ti); + + memset(ti, 0, ENTETE(ti)->s.tll * ENTETE(ti)->s.lngr); + + ENTETE(ti)->s.nelem = 0; +} + +void +tampex_libr(void *ti) +{ + TAMPINF_COHERENT(ti); + + free(ENTETE(ti)); +} + +void * +tampex_minim(void *ti, size_t i) +{ + size_t nlngr; /* Nouvelle longueur. */ + Entete *nent; /* Nouvelle entête. */ + size_t nnelem; /* Nouveau nombre d’éléments. */ + + TAMPINF_COHERENT(ti); + + /* Mettre à jour le nombre d’éléments, mais ne pas lui permettre de + * décroître. */ + nnelem = ENTETE(ti)->s.nelem; + if (nnelem < i + 1) + nnelem = i + 1; + + /* Ne pas agrandir le tampon s’il est déjà assez grand. */ + if (ENTETE(ti)->s.lngr > i) { + ENTETE(ti)->s.nelem = nnelem; + TAMPINF_COHERENT(ti); + return ti; + } + + /* Doubler la longueur jusqu’à ce qu’elle soit supérieure ou égale à la + * longueur recherchée. */ + for (nlngr = ENTETE(ti)->s.lngr; nlngr <= i; nlngr *= 2) + ; + + /* Agrandir le tampon et en initialiser à zéro la nouvelle partie. */ + if ((nent = realloc(ENTETE(ti), + sizeof(Entete) + nlngr * ENTETE(ti)->s.tll)) == NULL) + return NULL; + memset((char *)TAMPON(nent) + nent->s.lngr * nent->s.tll, 0, + (nlngr - nent->s.lngr) * nent->s.tll); + nent->s.lngr = nlngr; + nent->s.nelem = nnelem; + + TAMPINF_COHERENT(TAMPON(nent)); + + return TAMPON(nent); +} + +size_t +tampex_nelem(void *ti) +{ + TAMPINF_COHERENT(ti); + + return ENTETE(ti)->s.nelem; +} + +size_t +tampex_esp(void *ti) +{ + TAMPINF_COHERENT(ti); + + return ENTETE(ti)->s.nelem * ENTETE(ti)->s.tll; +} + +bool +tampex_dedans(void *ti, size_t i) +{ + TAMPINF_COHERENT(ti); + + if (i < ENTETE(ti)->s.nelem) + return 1; + return 0; +} diff --git a/tampex.h b/tampex.h @@ -0,0 +1,47 @@ +#ifndef TAMPEX_H +#define TAMPEX_H + +#include <stdbool.h> +#include <stddef.h> +#include <sys/types.h> + +/* Un tampex est un tampon extensible. Cette bibliothèque est une interface + * devant malloc(3), realloc(3) et free(3). Elle dispense de retenir + * explicitement la longueur d’un tampon, la taille des objets qui y sont + * placés ainsi que leur nombre. */ + +/* Initialiser un tampon pouvant contenir au moins lngr objets de tll octets + * chacun. + * Le tampon est initialisé à zéro. + * Renvoie le tampon, ou NULL en cas d’erreur. */ +void *tampex_init(size_t lngr, size_t tll); + +/* Réinitialiser le tampon te. + * Son contenu est aussi réinitialisé à zéro. */ +void tampex_reinit(void *te); + +/* Libérer l’espace utilisé par le tampon te. */ +void tampex_libr(void *te); + +/* Assurer que le tampon te soit assez grand pour contenir un élément à l’index + * i. + * Renvoie l’adresse du tampon, ou NULL en cas d’erreur. + * Il est possible, si le tampex doit être agrandi, que le tampon doivent être + * déplacé. Il est donc important de toujours sauvegarder l’adresse renvoyée. + * Il s’en suit aussi que toute référence au contenu d’un tampex doit être + * relative à la position en mémoire du tampon. */ +void *tampex_minim(void *te, size_t i); + +/* Obtenir le nombre d’éléments contenus dans le tampon te. + * Ce nombre correspond à la valeur de i la plus élevée donnée à + * tampex_minim(). */ +size_t tampex_nelem(void *te); + +/* Obtenir l’espace utilisé par les éléments du tampon te. */ +size_t tampex_esp(void *te); + +/* Renvoie 1 si l’indice i est dans la partie utilisée du tampon, 0 + * autrement. */ +bool tampex_dedans(void *te, size_t i); + +#endif diff --git a/tampinf.c b/tampinf.c @@ -1,146 +0,0 @@ -#include <assert.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> - -#include "tampinf.h" - -/* Calculer l’adresse de l’entête d’un taminf. */ -#define ENTETE(ti) ((Entete *)ti - 1) - -/* Calculer l’adresse du tampon d’un tampinf. */ -#define TAMPON(ent) (ent + 1) - -/* Tester la cohérence du tampon. */ -#define TAMPINF_COHERENT(ti) \ - /* Le pointeur n’est pas NULL. */ \ - assert(ENTETE(ti)); \ - /* Un élémENTETE(ti) a une taille supérieure à zéro. */ \ - assert((ENTETE(ti))->s.tll > 0); \ - /* Le tampon peut contenir au moins un élémENTETE(ti). */ \ - assert((ENTETE(ti))->s.lngr > 0); \ - /* Le nombre d’élémENTETE(ti)s est inférieur ou égal à la longueur. */ \ - assert((ENTETE(ti))->s.nelem <= (ENTETE(ti))->s.lngr); - -/* La structure du tampon infini a été conçue pour que son utilisation - * ressemble le plus possible à celle des tableaux statiques. C’est donc sous - * cette forme qu’ils se présentent à l’utilisateur. Or, une partie de la - * réalité lui est cachée, car sous le tampon qui lui est renvoyé sous trouve - * une entête contenant l’information nécessaires au bon fonctionnement des - * fonctions de cette bilbiothèque: la taille des éléments du tampon, exprimée - * en octets, la longueur du tampon, excluant l’entête et exprimée en multiples - * de la taille, et enfin le nombre d’éléments que contient le tampon. */ - -/* Entête d’un tampinf. - * L’union assure que l’entête occupe un multiple de sizeof(long) octets. */ -typedef union entete { - struct { - size_t tll; /* Taille des éléments. */ - size_t lngr; /* Longueur du tampon. */ - size_t nelem; /* Nombre d’éléments dans le tampon. */ - } s; - long alignement; -} Entete; - -void * -tampinf_init(size_t lngr, size_t tll) -{ - Entete *ent; - - assert(lngr > 0); - assert(tll > 0); - - if ((ent = malloc(sizeof(Entete) + lngr * tll)) == NULL) - return NULL; - - ent->s.tll = tll; - ent->s.lngr = lngr; - ent->s.nelem = 0; - - tampinf_reinit(TAMPON(ent)); - - TAMPINF_COHERENT(TAMPON(ent)); - - return TAMPON(ent); -} - -void -tampinf_reinit(void *ti) -{ - TAMPINF_COHERENT(ti); - - memset(ti, 0, ENTETE(ti)->s.tll * ENTETE(ti)->s.lngr); - - ENTETE(ti)->s.nelem = 0; -} - -void -tampinf_libr(void *ti) -{ - TAMPINF_COHERENT(ti); - - free(ENTETE(ti)); -} - -void * -tampinf_minim(void *ti, size_t i) -{ - size_t nlngr; /* Nouvelle longueur. */ - Entete *nent; /* Nouvelle entête. */ - size_t nnelem; /* Nouveau nombre d’éléments. */ - - TAMPINF_COHERENT(ti); - - nnelem = ENTETE(ti)->s.nelem; - if (nnelem < i + 1) - nnelem = i + 1; - - if (ENTETE(ti)->s.lngr > i) { - ENTETE(ti)->s.nelem = nnelem; - return ti; - } - - /* Doubler la longueur jusqu’à ce quelle soit supérieure ou égale à la - * longueur recherchée. */ - for (nlngr = ENTETE(ti)->s.lngr; nlngr <= i; nlngr *= 2) - ; - - /* Agrandir le tampon et en initialiser à zéro la nouvelle partie. */ - if ((nent = realloc(ENTETE(ti), - sizeof(Entete) + nlngr * ENTETE(ti)->s.tll)) == NULL) - return NULL; - memset((char *)TAMPON(nent) + nent->s.lngr * nent->s.tll, 0, - (nlngr - nent->s.lngr) * nent->s.tll); - nent->s.lngr = nlngr; - nent->s.nelem = nnelem; - - TAMPINF_COHERENT(TAMPON(nent)); - - return TAMPON(nent); -} - -size_t -tampinf_nelem(void *ti) -{ - TAMPINF_COHERENT(ti); - - return ENTETE(ti)->s.nelem; -} - -size_t -tampinf_esp(void *ti) -{ - TAMPINF_COHERENT(ti); - - return ENTETE(ti)->s.nelem * ENTETE(ti)->s.tll; -} - -bool -tampinf_dedans(void *ti, size_t i) -{ - TAMPINF_COHERENT(ti); - - if (i < ENTETE(ti)->s.nelem) - return 1; - return 0; -} diff --git a/tampinf.h b/tampinf.h @@ -1,42 +0,0 @@ -#ifndef TAMPINF_H -#define TAMPINF_H - -#include <stdbool.h> -#include <stddef.h> -#include <sys/types.h> - -/* Un tampinf est un tampon qui donne l’illusion d’être infini. - * - * L’adresse d’un tampon n’est pas statique, et plusieurs fonctions sont - * susceptibles de la changer. Ces fonctions renvoient toutes l’adresse - * courante du tampon. Toute variable qui contiendrait l’adresse du tampon doit - * être mise à jour à l’occasion de l’appel de ce genre de fonctions. */ - -/* Initialiser un tampon. - * La longueur est interprétée en multiples de tll. Le tampon est initialisé à - * zéro. - * Renvoie le tampon, ou NULL en cas d’erreur. */ -void *tampinf_init(size_t lngr, size_t tll); - -/* Réinitialiser le tampon ti. - * Son contenu est aussi réinitialisé à zéro. */ -void tampinf_reinit(void *ti); - -/* Libérer l’espace utilisé par le tampon ti. */ -void tampinf_libr(void *ti); - -/* Assurer que le tampon ti puisse contenir un élément à l’index i. - * Renvoie l’adresse du tampon, ou NULL en cas d’erreur. */ -void *tampinf_minim(void *ti, size_t i); - -/* Obtenir le nombre d’éléments contenus dans le tampon ti. */ -size_t tampinf_nelem(void *ti); - -/* Obtenir l’espace utilisé par les éléments du tampon ti. */ -size_t tampinf_esp(void *ti); - -/* Renvoie 1 si l’indice i est dans la partie utilisée du tampon, 0 - * autrement. */ -bool tampinf_dedans(void *ti, size_t i); - -#endif diff --git a/tfm.c b/tfm.c @@ -4,20 +4,25 @@ #include <string.h> #include "tfm.h" -#include "tampinf.h" +#include "tampex.h" #define TAMPON_LNGR_DEF 64 /* Longueur par défaut des tampons. */ +/* Tester la cohérence d’un tfm. */ #define TFM_COHERENT(tfm) \ + /* Le pointeur n’est pas NULL. */ \ assert((tfm)); \ + /* Le pointeur vers le tampex des états n’est pas NULL. */ \ assert((tfm)->etats); \ + /* Le pointeur vers le tampex des transitions n’est pas NULL. */ \ assert((tfm)->trans); \ + /* Le pointeur vers le tampex des symboles n’est pas NULL. */ \ assert((tfm)->symbs); -/* Chercher un symbole symb de longueur lngr dans le transducteur tfm. +/* Chercher un symbole symb de longueur lngr dans le tampon te. * Renvoie la position du symbole dans tfm->symbs, ou -1 s’il ne s’y trouve * pas. */ -static ssize_t tfm_symb_chercher(struct tampinf *ti, char *symb, size_t lngr); +static ssize_t tfm_symb_chercher(char *te, char *symb, size_t lngr); struct tfm * tfm_init(void) @@ -27,28 +32,28 @@ tfm_init(void) if ((tfm = malloc(sizeof(struct tfm))) == NULL) return NULL; - if ((tfm->etats = tampinf_init(TAMPON_LNGR_DEF, - sizeof(struct etat))) == NULL) { - free(tfm); - return NULL; - } - if ((tfm->trans = tampinf_init(TAMPON_LNGR_DEF, - sizeof(struct trans))) == NULL) { - tampinf_libr(tfm->etats); - free(tfm); - return NULL; - } - if ((tfm->symbs = tampinf_init(TAMPON_LNGR_DEF, - sizeof(char))) == NULL) { - tampinf_libr(tfm->etats); - tampinf_libr(tfm->trans); - free(tfm); - return NULL; - } + /* Initialiser les tampex. */ + if ((tfm->etats = tampex_init(TAMPON_LNGR_DEF, + sizeof(struct etat))) == NULL) + goto erreur1; + if ((tfm->trans = tampex_init(TAMPON_LNGR_DEF, + sizeof(struct trans))) == NULL) + goto erreur2; + if ((tfm->symbs = tampex_init(TAMPON_LNGR_DEF, + sizeof(char))) == NULL) + goto erreur3; TFM_COHERENT(tfm); return tfm; + +erreur3: + tampex_libr(tfm->trans); +erreur2: + tampex_libr(tfm->etats); +erreur1: + free(tfm); + return NULL; } void @@ -56,98 +61,99 @@ tfm_libr(struct tfm *tfm) { TFM_COHERENT(tfm); - tampinf_libr(tfm->etats); - tampinf_libr(tfm->trans); - tampinf_libr(tfm->symbs); + tampex_libr(tfm->symbs); + tampex_libr(tfm->trans); + tampex_libr(tfm->etats); free(tfm); } int tfm_ajt(struct tfm *tfm, size_t es, size_t ed, ssize_t se, ssize_t ss) { - ssize_t itrans; - struct etat etat; - struct trans trans; + void *tetp; /* Tampinf temporaire. */ + size_t itrans; /* Identifiant de transition. */ + TFM_COHERENT(tfm); - /* Obtenir l’état source. */ - if (tampinf_obt(tfm->etats, es, 1, &etat) < 0) + /* Assurer que l’état source existe. */ + if ((tetp = tampex_minim(tfm->etats, es)) == NULL) return -1; + tfm->etats = tetp; - /* Construire la nouvelle transition. */ - trans.se = se; - trans.ss = ss; - trans.ed = ed; - trans.prch = etat.trans; - - /* Ajouter la transition. */ - if ((itrans = tampinf_ajt(tfm->trans, 1, &trans)) < 0) + /* Ajouter une transitions. */ + itrans = tampex_nelem(tfm->trans); + if ((tetp = tampex_minim(tfm->trans, itrans)) == NULL) return -1; + tfm->trans = tetp; + + /* Construire la nouvelle transition. */ + tfm->trans[itrans].se = se; + tfm->trans[itrans].ss = ss; + tfm->trans[itrans].ed = ed; + tfm->trans[itrans].prch = tfm->etats[es].trans; /* Mettre à jour l’état. */ - etat.trans = itrans; - etat.ntrans++; - if (tampinf_plc(tfm->etats, es, 1, &etat) < 0) - return -1; + tfm->etats[es].trans = itrans; + tfm->etats[es].ntrans++; TFM_COHERENT(tfm); return 0; } -int -tfm_symb_id(struct tfm *tfm, char *symb, size_t lngr, ssize_t *id) +ssize_t +tfm_symb_id(struct tfm *tfm, char *symb, size_t lngr) { - ssize_t pos; - unsigned char n; + size_t i; + ssize_t id; + char *tip; TFM_COHERENT(tfm); assert(symb); assert(lngr > 0); - assert(id); - /* La longueur de l’identifiant doit pouvoir entrer dans un octets. */ - if (lngr > 0xFF) + /* Valider la taille du symbole. */ + if (lngr > TFM_TLL_SYMB_MAX) return -1; - if ((pos = tfm_symb_chercher(tfm->symbs, symb, lngr)) >= 0) + /* La longueur de l’identifiant doit pouvoir entrer dans un octets. */ + assert(TFM_TLL_SYMB_MAX <= 0xFF); + + if ((id = tfm_symb_chercher(tfm->symbs, symb, lngr)) >= 0) goto fin; /* Le symbole n’a pas été trouvé: l’ajouter. */ - n = lngr; - if ((pos = tampinf_ajt(tfm->symbs, 1, &n)) < 0) - return -1; - if (tampinf_ajt(tfm->symbs, n, symb) < 0) + i = id = tampex_nelem(tfm->symbs); + if ((tip = tampex_minim(tfm->symbs, i + lngr)) == NULL) return -1; + tfm->symbs = tip; + tfm->symbs[i++] = (unsigned char) lngr; + memcpy(tfm->symbs + i, symb, lngr); fin: + assert(id >= 0); TFM_COHERENT(tfm); - *id = pos; - return 0; + return id; } ssize_t tfm_symb_obt(struct tfm *tfm, size_t id, char *symb, size_t max) { - size_t lngr, i; - char *ctn; + unsigned char lngr; TFM_COHERENT(tfm); assert(symb); assert(max > 0); + assert(tampex_dedans(tfm->symbs, id)); - ctn = tampinf_ctn(tfm->symbs); - - assert(tampinf_dedans(tfm->symbs, id)); - lngr = *(unsigned char *)(ctn + id); + lngr = *(unsigned char *)(tfm->symbs + id); /* Le symbole doit rentrer dans le tampon. */ if (lngr > max) return -1; /* Copier le symbole. */ - for (i = 0, ctn += id + 1; i < lngr; i++) - symb[i] = ctn[i]; + memcpy(symb, tfm->symbs + id + 1, lngr); return lngr; } @@ -162,12 +168,14 @@ tfm_parc_symbs(struct tfm *tfm, size_t *id, char *symb, size_t max) assert(symb); assert(max > 0); - if (!tampinf_dedans(tfm->symbs, *id)) + /* Vérifier s’il reste au moins au symbole à lire. */ + if (!tampex_dedans(tfm->symbs, *id)) return 0; if ((lngr = tfm_symb_obt(tfm, *id, symb, max)) < 0) - return lngr; + return -1; + /* Préparer le prochain appel. */ *id += lngr + 1; return lngr; @@ -176,16 +184,15 @@ tfm_parc_symbs(struct tfm *tfm, size_t *id, char *symb, size_t max) int tfm_mfinal(struct tfm *tfm, size_t ietat) { - struct etat etat; + struct etat *tetp; TFM_COHERENT(tfm); /* Obtenir, modifier, puis écrire l’état. */ - if (tampinf_obt(tfm->etats, ietat, 1, &etat) < 0) - return -1; - etat.final = 1; - if (tampinf_plc(tfm->etats, ietat, 1, &etat) < 0) + if ((tetp = tampex_minim(tfm->etats, ietat)) == NULL) return -1; + tfm->etats = tetp; + tfm->etats[ietat].final = 1; TFM_COHERENT(tfm); return 0; @@ -194,74 +201,41 @@ tfm_mfinal(struct tfm *tfm, size_t ietat) int tfm_tfinal(struct tfm *tfm, size_t ietat) { - struct etat etat; + struct etat *tetp; TFM_COHERENT(tfm); - /* Obtenir l’état. */ - if (tampinf_obt(tfm->etats, ietat, 1, &etat) < 0) + if ((tetp = tampex_minim(tfm->etats, ietat)) == NULL) return -1; - - return etat.final; + return tfm->etats[ietat].final; } ssize_t tfm_ntrans(struct tfm *tfm, size_t ietat) { - struct etat etat; - - TFM_COHERENT(tfm); - - /* Obtenir l’état. */ - if (tampinf_obt(tfm->etats, ietat, 1, &etat) < 0) - return -1; - - return etat.ntrans; -} - -ssize_t -tfm_trans(struct tfm *tfm, size_t ietat) -{ - struct etat etat; - - TFM_COHERENT(tfm); - - /* Obtenir l’état. */ - if (tampinf_obt(tfm->etats, ietat, 1, &etat) < 0) - return -1; - - return etat.trans; -} - -ssize_t -tfm_trans_prch(struct tfm *tfm, size_t itrans) -{ - struct trans trans; + struct etat *tetp; TFM_COHERENT(tfm); - /* Obtenir la transition. */ - if (tampinf_obt(tfm->trans, itrans, 1, &trans) < 0) + if ((tetp = tampex_minim(tfm->etats, ietat)) == NULL) return -1; - - return trans.prch; + return tfm->etats[ietat].ntrans; } static ssize_t -tfm_symb_chercher(struct tampinf *ti, char *symb, size_t lngr) +tfm_symb_chercher(char *ti, char *symb, size_t lngr) { - char *ctn; unsigned pos; - unsigned n; + unsigned char n; + assert(ti); assert(symb); + assert(lngr > 0); - ctn = tampinf_ctn(ti); - - for (pos = 0; tampinf_dedans(ti, pos); pos += n) { - n = ((unsigned char *)ctn)[pos++]; - if (lngr == n && strncmp(symb, ctn + pos, n) == 0) - return pos-1; + for (pos = 0; tampex_dedans(ti, pos); pos += n) { + n = ti[pos++]; + if (lngr == n && memcmp(symb, ti + pos, n) == 0) + return pos - 1; } return -1; diff --git a/tfm.h b/tfm.h @@ -3,8 +3,7 @@ #include <stdbool.h> #include <stddef.h> - -#include "tampinf.h" +#include <sys/types.h> /* L’accronyme « tfm » veut dire « transducteur fini en mémoire ». */ @@ -12,25 +11,25 @@ #define TFM_SYMB_EPSILON -1 #define TFM_SYMB_ETOILE -2 -/* Une structure tfm représente un transducteur fini et renferme trois tampons - * infinis pour y stocker les états, les transitions entre les états et les - * symboles de plus d’un octet. Les symboles sont stocké à la Pascal, - * c’est-à-dire que les caractères d’une chaîne sont précédés d’un octet qui en - * indique la taille. Un symbole peut donc contenir le caractère NUL, mais il - * est limité à une longueur maximale de 255 octets. */ +/* Une structure tfm représente un transducteur fini et renferme trois tampex + * pour y stocker les états, les transitions entre les états et les symboles. + * Les symboles sont stockés à la Pascal, c’est-à-dire que les caractères d’une + * chaîne sont précédés d’un octet qui en indique la taille. Un symbole peut + * donc contenir le caractère NUL, mais il est limité à une longueur maximale + * de 255 octets. */ #define TFM_TLL_SYMB_MAX 255 /* Taille maximale d’un symbole. */ struct tfm { - struct tampinf *etats; - struct tampinf *trans; - struct tampinf *symbs; + struct etat *etats; /* Liste des états. */ + struct trans *trans; /* Liste des transitions. */ + char *symbs; /* Liste des symboles. */ }; -/* Un état contient l’identifiant d’une liste chaînée de ses transitions - * sortantes. Il donne aussi le nombre de transitions que cette liste - * contient. Il peut enfin est marqué comme final. trans et ntrans sont des - * indices dans le tampon tfm.trans. */ +/* Un état contient l’identifiant de sa première transition sortante, qui est + * en tête d’une liste chaînée rassemblant toutes ses transitions sortantes. Il + * donne aussi le nombre de transitions que cette liste contient. Il peut enfin + * être marqué comme final. trans est un indice dans le tampon tfm->trans. */ struct etat { size_t trans; /* Liste chaînée de transitions. */ @@ -38,11 +37,13 @@ struct etat { bool final; /* État final? */ }; -/* Les transitions qui partagent un même état source forment une liste chaînée, - * dont la taille est donnée dans cet état source. Les transitions ne sont pas - * nécessairement ordonnées. se et ss sont des indices dans le tampon tfm.etats. - * ed est un indice dans le tampon tfm.etats. prch est un indice dans le tampon - * tfm.trans. */ +/* Les transitions qui partagent un même état source forment une liste chaînée + * et dont la taille est donnée par le champ ntrans de cet état source. Les + * transitions d’une liste ne suivent pas d’ordre particulier. S’ils sont + * positifs, se et ss sont des indices dans le tampon tfm->symbs; s’ils sont + * strictement négatifs, ils contiennent des symboles spéciaux. ed est un + * indice dans le tampon tfm->etats. prch est un indice dans le tampon + * tfm->trans. */ struct trans { ssize_t se; /* Symbole d’entrée. */ @@ -59,16 +60,16 @@ struct tfm *tfm_init(void); /* Libérer un transducteur. */ void tfm_libr(struct tfm *tfm); -/* Ajouter une transition de l’état es à l’état ed avec les symboles d’entrée et - * de sortie se et ss au transducteur tfm. +/* Ajouter au transducteur tfm une transition de l’état es à l’état ed avec les + * symboles d’entrée et de sortie se et ss. * Renvoie 0, ou -1 en cas d’erreur. */ int tfm_ajt(struct tfm *tfm, size_t es, size_t ed, ssize_t se, ssize_t ss); -/* Obtenir l’identifiant id d’un symbole symb de longueur lngr dans le +/* Obtenir l’identifiant d’un symbole symb de longueur lngr dans le * transducteur tfm. - * Si le symbole est inconnu du transducteur, il est y ajouté de manière - * transparente. Renvoie 0, ou -1 en cas d’erreur. */ -int tfm_symb_id(struct tfm *tfm, char *symb, size_t lngr, ssize_t *id); + * Si le symbole est inconnu du transducteur, il y est ajouté de manière + * transparente. Renvoie l’identifiant, ou -1 en cas d’erreur. */ +ssize_t tfm_symb_id(struct tfm *tfm, char *symb, size_t lngr); /* Placer le symbole du transducteur tfm correspondant à l’identifiant id dans * le tampon symb, de taille max. @@ -79,9 +80,10 @@ ssize_t tfm_symb_obt(struct tfm *tfm, size_t id, char *symb, size_t max); /* Parcourir les symboles du transducteurs tfm. * Un symbole est placé dans le tampon symb, de taille max, à chaque appel. * L’identifiant id est un pointeur vers l’identifiant du prochain symbole à - * lire. Il est normalement initialisé à 0 avant le parcours. N’exporte que les - * symboles non-spéciaux. Renvoie la taille du symbole, 0 s’il ne reste plus de - * symbole à lire, ou -1 en cas d’erreur. */ + * lire. Il est normalement initialisé à 0 avant le parcours. Cette fonction + * n’exporte que les symboles non-spéciaux. + * Renvoie la taille du symbole, 0 s’il ne reste plus de symbole à lire, ou -1 + * en cas d’erreur. */ ssize_t tfm_parc_symbs(struct tfm *tfm, size_t *id, char *symb, size_t max); /* Marquer un état comme final. @@ -96,12 +98,4 @@ int tfm_tfinal(struct tfm *tfm, size_t ietat); * Renvoie ce nombre, ou -1 en cas d’erreur. */ ssize_t tfm_ntrans(struct tfm *tfm, size_t ietat); -/* Obtenir l’identifiant de la première transition sortante d’ietat. - * Renvoie cet identifiant, ou -1 en cas d’erreur. */ -ssize_t tfm_trans(struct tfm *tfm, size_t ietat); - -/* Obtenir l’identifiant de la transition suivant la transition itrans. - * Renvoie cet identifiant, ou -1 en cas d’erreur. */ -ssize_t tfm_trans_prch(struct tfm *tfm, size_t itrans); - #endif