trafi

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

att.c (7029B)


      1 #include <assert.h>
      2 #include <stddef.h>
      3 #include <stdio.h>
      4 #include <string.h>
      5 
      6 #include "att.h"
      7 #include "tampex.h"
      8 #include "tfm.h"
      9 
     10 /* Séparateurs de champs. */
     11 #define SEP_ERR -1 /* Pas un séparateur à proprement parler. */
     12 #define SEP_EOF  0
     13 #define SEP_NL   1
     14 #define SEP_TB   2
     15 
     16 /* Lire le prochain champ du fichier f, dans le tampon t de taille max.
     17  * Renvoie le séparateur qui a terminé le champ lu, et si ce séparateur est
     18  * SEP_TB ou SEP_NL, c’est-à-dire, si t a été modifié, place dans noct le nombre
     19  * de caractères écrits dans t. Si SEP_ERR est renvoyé, c’est que le tampon
     20  * était trop petit pour contenir le champ. */
     21 static int lire_champ(FILE *f, char *t, size_t max, size_t *noct);
     22 
     23 /* Convertir la chaîne de caractères t de contenant noct octets en nombre.
     24  * Renvoie le nombre, ou -1 en cas d’erreur. */
     25 static ssize_t nombre(char *t, size_t noct);
     26 
     27 /* Ajouter un symbole à un transducteur.
     28  * Renvoie l’identifiant du symbole, ou -1 en cas d’erreur. Doit être utilisé
     29  * un lieu de tfm_symb_id() pour intercepter les symboles spéciaux. */
     30 static ssize_t ajt_symb(struct tfm *tfm, char *t, size_t noct);
     31 
     32 /* Placer le symbole du transudcteur tfm correspondant à l’identifiant id dans
     33  * le tampon symb, de taille max.
     34  * Doit être utilisé au lieu de tfm_symb_obt() pour intercepter les identifiants
     35  * de symbole spéciaux. Renvoie la taille du symbole, ou -1 en cas d’erreur. */
     36 static ssize_t symb_obt(struct tfm *tfm, size_t id, char *symb, size_t max);
     37 
     38 /* Lire un fichier au format .att.
     39  * La routine se fait peut-être une idée trop stricte du format .att et n’est
     40  * pas très flexible. */
     41 struct tfm *
     42 att_lire(FILE *f)
     43 {
     44 	char champ[TFM_TLL_SYMB_MAX]; /* Tampon d’un champ. */
     45 	struct tfm *tfm; /* Tranducteur. */
     46 	ssize_t es, ed; /* États source et destination. */
     47 	ssize_t se, ss; /* Symboles d’entrée et de sortie. */
     48 	ssize_t n; /* Nombre. */
     49 	size_t noct; /* Nombre d’octets écrits dans champ. */
     50 
     51 	assert(f);
     52 
     53 	if ((tfm = tfm_init()) == NULL)
     54 		return NULL;
     55 
     56 	for (;;) {
     57 		/* Premier champ: état source ou état final. */
     58 		switch (lire_champ(f, champ, TFM_TLL_SYMB_MAX, &noct)) {
     59 		default: assert(0);
     60 		case SEP_ERR:
     61 		    goto erreur;
     62 		case SEP_EOF:
     63 		    /* C’est la fin du fichier et la dernière ligne est complète: tout va
     64 		     * bien. */
     65 		    return tfm;
     66 		case SEP_NL:
     67 		    /* La ligne ne contient qu’un champ. L’état qu’il contient doit être
     68 		     * marqué comme final. */
     69 		    if ((n = nombre(champ, noct)) < 0)
     70 		        goto erreur;
     71 		    if (tfm_mfinal(tfm, n) < 0)
     72 		        goto erreur;
     73 		    continue;
     74 		case SEP_TB:
     75 		    /* La ligne déclare une transition. Sauvegarder le champ dans es. */
     76 		     if ((es = nombre(champ, noct)) < 0)
     77 		         goto erreur;
     78 		}
     79 
     80 		/* Deuxième champ: état suivant. */
     81 		switch (lire_champ(f, champ, TFM_TLL_SYMB_MAX, &noct)) {
     82 		default: assert(0);
     83 		case SEP_ERR: case SEP_EOF: case SEP_NL:
     84 		    /* Une ligne ne peut contenir seulement deux champs. */
     85 		    goto erreur;
     86 		case SEP_TB:
     87 		    /* Sauvegarder le champ dans ed. */
     88 		    if ((ed = nombre(champ, noct)) < 0)
     89 		        goto erreur;
     90 		}
     91 
     92 		/* Troisième champ: symbole d’entrée. */
     93 		switch (lire_champ(f, champ, TFM_TLL_SYMB_MAX, &noct)) {
     94 		default: assert(0);
     95 		case SEP_ERR: case SEP_EOF: case SEP_NL:
     96 		    /* Une ligne ne peut contenir seulement trois champs. */
     97 		    goto erreur;
     98 		case SEP_TB:
     99 		    /* Sauvegarder le champ dans se. */
    100 		    if ((se = ajt_symb(tfm, champ, noct)) < 0)
    101 		        goto erreur;
    102 		}
    103 
    104 		/* Quatrième champ: symbole de sortie. */
    105 		switch (lire_champ(f, champ, TFM_TLL_SYMB_MAX, &noct)) {
    106 		default: assert(0);
    107 		case SEP_ERR:
    108 		case SEP_EOF: /* Doit se terminer sur une nouvelle ligne. */
    109 		case SEP_TB: /* Il ne peut y avoir plus de quatre champs. */
    110 		    goto erreur;
    111 		case SEP_NL:
    112 		    /* Sauvegarder le champ dans ss. */
    113 		    if ((ss = ajt_symb(tfm, champ, noct)) < 0)
    114 		        goto erreur;
    115 		}
    116 
    117 		if (tfm_ajt(tfm, es, ed, se, ss) < 0)
    118 		    goto erreur;
    119 	}
    120 
    121 	assert(0);
    122 
    123 erreur:
    124 	tfm_libr(tfm);
    125 	return NULL;
    126 }
    127 
    128 int
    129 att_ecrire(FILE *f, struct tfm *tfm)
    130 {
    131 	size_t ietat;
    132 	size_t ntrans;
    133 	size_t itrans;
    134 	ssize_t lngr;
    135 	char symb[TFM_TLL_SYMB_MAX];
    136 
    137 	assert(f);
    138 	assert(tfm);
    139 
    140 	/* Parcourir les états. */
    141 	for (ietat = 0; tampex_dedans(tfm->etats, ietat); ietat++) {
    142 		/* Parcourir les transitions. */
    143 		for (ntrans = tfm->etats[ietat].ntrans,
    144 		        itrans = tfm->etats[ietat].trans;
    145 		        ntrans--;
    146 		        itrans = tfm->trans[itrans].prch) {
    147 		    /* Afficher les états source et destination. */
    148 		    fprintf(f, "%zu\t%zu\t", ietat, tfm->trans[itrans].ed);
    149 
    150 		    /* Afficher le symbole d’entrée. */
    151 		    if ((lngr = symb_obt(tfm, tfm->trans[itrans].se, symb,
    152 		            TFM_TLL_SYMB_MAX)) < 0)
    153 		        return -1;
    154 		    fwrite(symb, 1, lngr, f);
    155 		    fputc('\t', f);
    156 
    157 		    /* Afficher le symbole de sortie. */
    158 		    if ((lngr = symb_obt(tfm, tfm->trans[itrans].ss, symb,
    159 		            TFM_TLL_SYMB_MAX)) < 0)
    160 		        return -1;
    161 		    fwrite(symb, 1, lngr, f);
    162 		    fprintf(f, "\n");
    163 		}
    164 
    165 		/* Afficher les transitions finales. */
    166 		if (tfm_tfinal(tfm, ietat))
    167 		    fprintf(f, "%zu\n", ietat);
    168 	}
    169 
    170 	return 0;
    171 }
    172 
    173 static int
    174 lire_champ(FILE *f, char *t, size_t max, size_t *noct)
    175 {
    176 	int c;
    177 	size_t i;
    178 
    179 	assert(f);
    180 	assert(t);
    181 	assert(max > 0);
    182 	assert(noct);
    183 
    184 	/* Si déjà la fin, renvoyer EOF. */
    185 	if ((c = getc(f)) == EOF)
    186 		return SEP_EOF;
    187 
    188 	/* Ajouter les caractères dans le tampon jusqu’au premier séparateur ou
    189 	 * jusqu’à ce que le tampon soit plein. */
    190 	for (i = 0; c != '\t' && c != '\n' && c != EOF; t[i++] = c, c = getc(f))
    191 		if (i >= max)
    192 		    return SEP_ERR;
    193 
    194 	*noct = i;
    195 
    196 	switch (c) {
    197 	case EOF: return SEP_EOF;
    198 	case '\n': return SEP_NL;
    199 	case '\t': return SEP_TB;
    200 	}
    201 
    202 	assert(0);
    203 }
    204 
    205 static ssize_t
    206 nombre(char *t, size_t noct)
    207 {
    208 	size_t i;
    209 	size_t n;
    210 
    211 	assert(t);
    212 	assert(noct > 0);
    213 
    214 	for (i = n = 0; i < noct; n = n * 10 + (t[i++] - '0')) {
    215 		if (t[i] < '0' || t[i] > '9')
    216 		    return -1;
    217 	}
    218 
    219 	return n;
    220 }
    221 
    222 static ssize_t
    223 ajt_symb(struct tfm *tfm, char *t, size_t noct)
    224 {
    225 	assert(tfm);
    226 	assert(t);
    227 	assert(noct > 0);
    228 
    229 	/* Intercepter les symboles spéciaux. */
    230 	if (noct == 18 && memcmp(t, "@_UNKNOWN_SYMBOL_@", noct) == 0)
    231 		return TFM_SYMB_AUTRE;
    232 	if (noct == 3 && memcmp(t, "@0@", noct) == 0)
    233 		return TFM_SYMB_EPSILON;
    234 	if (noct == 19 && memcmp(t, "@_IDENTITY_SYMBOL_@", noct) == 0)
    235 		return TFM_SYMB_IDENTITE;
    236 
    237 	return tfm_symb_id(tfm, t, noct);
    238 }
    239 
    240 static ssize_t
    241 symb_obt(struct tfm *tfm, size_t id, char *symb, size_t max)
    242 {
    243 	assert(tfm);
    244 	assert(symb);
    245 	assert(max > 0);
    246 
    247 	switch (id) {
    248 	case TFM_SYMB_AUTRE:
    249 		if (max < 18)
    250 		    return -1;
    251 		memcpy(symb, "@_UNKNOWN_SYMBOL_@", 18);
    252 		return 18;
    253 	case TFM_SYMB_EPSILON:
    254 		if (max < 3)
    255 		    return -1;
    256 		memcpy(symb, "@0@", 3);
    257 		return 3;
    258 	case TFM_SYMB_IDENTITE:
    259 		if (max < 19)
    260 		    return -1;
    261 		memcpy(symb, "@_IDENTITY_SYMBOL_@", 19);
    262 		return 19;
    263 	}
    264 
    265 	assert((id & 0x01) == TFM_SNORMAL);
    266 
    267 	return tfm_symb_obt(tfm, id, symb, max);
    268 }