trafi

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

tfm.c (6612B)


      1 #include <assert.h>
      2 #include <stdbool.h>
      3 #include <stddef.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 
      7 #include "tfm.h"
      8 #include "tampex.h"
      9 
     10 #define TAMPON_LNGR_DEF 64 /* Longueur par défaut des tampons. */
     11 
     12 /* Tester la cohérence d’un tfm. */
     13 #define TFM_COHERENT(tfm) \
     14 	/* Le pointeur n’est pas NULL. */ \
     15 	assert((tfm)); \
     16 	/* Le pointeur vers le tampex des états n’est pas NULL. */ \
     17 	assert((tfm)->etats); \
     18 	/* Le pointeur vers le tampex des transitions n’est pas NULL. */ \
     19 	assert((tfm)->trans); \
     20 	/* Le pointeur vers le tampex des symboles n’est pas NULL. */ \
     21 	assert((tfm)->symbs);
     22 
     23 /* Chercher un symbole symb de longueur lngr dans le tampon te.
     24  * Renvoie la position du symbole dans tfm->symbs, ou -1 s’il ne s’y trouve
     25  * pas. */
     26 static ssize_t tfm_symb_chercher(char *te, char *symb, size_t lngr);
     27 
     28 /* Trier les transitions d’un état.
     29  * Renvoie 0, ou -1 en cas d’erreur. */
     30 static void trier_etat(struct tfm *tfm, size_t ietat);
     31 
     32 /* Comparer deux transition pour les trier.
     33  * Renvoie -1 si t1 est supérieur t2, 0 s’ils sont égales et 1 si t2 est
     34  * supérieure à t1. */
     35 static int trans_comparer(struct tfm *tfm, size_t t1, size_t t2);
     36 
     37 struct tfm *
     38 tfm_init(void)
     39 {
     40 	struct tfm *tfm;
     41 
     42 	if ((tfm = malloc(sizeof(struct tfm))) == NULL)
     43 		return NULL;
     44 
     45 	/* Initialiser les tampex. */
     46 	if ((tfm->etats = tampex_init(TAMPON_LNGR_DEF,
     47 		    sizeof(struct etat))) == NULL)
     48 		goto erreur1;
     49 	if ((tfm->trans = tampex_init(TAMPON_LNGR_DEF,
     50 		    sizeof(struct trans))) == NULL)
     51 		goto erreur2;
     52 	if ((tfm->symbs = tampex_init(TAMPON_LNGR_DEF,
     53 		    sizeof(char))) == NULL)
     54 		goto erreur3;
     55 
     56 	tfm->trie = 1;
     57 
     58 	TFM_COHERENT(tfm);
     59 
     60 	return tfm;
     61 
     62 erreur3:
     63 	tampex_libr(tfm->trans);
     64 erreur2:
     65 	tampex_libr(tfm->etats);
     66 erreur1:
     67 	free(tfm);
     68 	return NULL;
     69 }
     70 
     71 void
     72 tfm_libr(struct tfm *tfm)
     73 {
     74 	TFM_COHERENT(tfm);
     75 
     76 	tampex_libr(tfm->symbs);
     77 	tampex_libr(tfm->trans);
     78 	tampex_libr(tfm->etats);
     79 	free(tfm);
     80 }
     81 
     82 int
     83 tfm_ajt(struct tfm *tfm, size_t es, size_t ed, ssize_t se, ssize_t ss)
     84 {
     85 	ssize_t itrans; /* Identifiant de transition. */
     86 
     87 	TFM_COHERENT(tfm);
     88 
     89 	/* Assurer que l’état source existe. */
     90 	if (tampex_minim((void **)&tfm->etats, es) < 0)
     91 		return -1;
     92 	if (!tfm->etats[es].existe) {
     93 		tfm->etats[es].existe = 1;
     94 		tfm->etats[es].trans = -1;
     95 	}
     96 
     97 	/* Ajouter une transition. */
     98 	if ((itrans = tampex_empl((void **)&tfm->trans)) < 0)
     99 		return -1;
    100 
    101 	/* Construire la nouvelle transition. */
    102 	tfm->trans[itrans].se = se;
    103 	tfm->trans[itrans].ss = ss;
    104 	tfm->trans[itrans].ed = ed;
    105 	tfm->trans[itrans].prch = tfm->etats[es].trans;
    106 
    107 	/* Mettre à jour l’état. */
    108 	tfm->etats[es].trans = itrans;
    109 	tfm->etats[es].ntrans++;
    110 	tfm->etats[es].trie = 0;
    111 
    112 	/* Mettre à jour le tfm. */
    113 	tfm->trie = 0;
    114 
    115 	TFM_COHERENT(tfm);
    116 
    117 	return 0;
    118 }
    119 
    120 ssize_t
    121 tfm_symb_id(struct tfm *tfm, char *symb, size_t lngr)
    122 {
    123 	size_t i;
    124 	ssize_t id;
    125 
    126 	TFM_COHERENT(tfm);
    127 	assert(symb);
    128 	assert(lngr > 0);
    129 	assert(lngr <= TFM_TLL_SYMB_MAX);
    130 
    131 	/* La longueur de l’identifiant doit pouvoir entrer dans un octets. */
    132 	assert(TFM_TLL_SYMB_MAX <= 0xFF);
    133 
    134 	if ((id = tfm_symb_chercher(tfm->symbs, symb, lngr)) < 0) {
    135 		/* Le symbole n’a pas été trouvé: l’ajouter. */
    136 		i = id = tampex_nelem(tfm->symbs);
    137 		if (tampex_minim((void **)&tfm->symbs, i + lngr) < 0)
    138 		    return -1;
    139 		tfm->symbs[i++] = lngr;
    140 		memcpy(tfm->symbs + i, symb, lngr);
    141 	}
    142 
    143 	assert(id >= 0);
    144 	TFM_COHERENT(tfm);
    145 
    146 	return (id << 1) | TFM_SNORMAL;
    147 }
    148 
    149 ssize_t
    150 tfm_symb_obt(struct tfm *tfm, size_t id, char *symb, size_t max)
    151 {
    152 	unsigned char lngr;
    153 
    154 	TFM_COHERENT(tfm);
    155 	assert(symb);
    156 	assert(max > 0);
    157 	assert((id & 0x01) == TFM_SNORMAL);
    158 	assert(tampex_dedans(tfm->symbs, id >> 1));
    159 
    160 	id >>= 1;
    161 
    162 	lngr = *(tfm->symbs + id);
    163 
    164 	assert(lngr != 0);
    165 
    166 	/* Le symbole doit rentrer dans le tampon. */
    167 	if (lngr > max)
    168 		return -1;
    169 
    170 	/* Copier le symbole. */
    171 	memcpy(symb, tfm->symbs + id + 1, lngr);
    172 
    173 	return lngr;
    174 }
    175 
    176 int
    177 tfm_mfinal(struct tfm *tfm, size_t ietat)
    178 {
    179 	TFM_COHERENT(tfm);
    180 
    181 	/* Obtenir, modifier, puis écrire l’état. */
    182 	if (tampex_minim((void **)&tfm->etats, ietat) < 0)
    183 		return -1;
    184 	tfm->etats[ietat].final = 1;
    185 
    186 	TFM_COHERENT(tfm);
    187 
    188 	return 0;
    189 }
    190 
    191 int
    192 tfm_tfinal(struct tfm *tfm, size_t ietat)
    193 {
    194 	TFM_COHERENT(tfm);
    195 
    196 	if (tampex_minim((void **)&tfm->etats, ietat) < 0)
    197 		return -1;
    198 	return tfm->etats[ietat].final;
    199 }
    200 
    201 void
    202 tfm_trier(struct tfm *tfm)
    203 {
    204 	size_t ietat;
    205 
    206 	TFM_COHERENT(tfm);
    207 
    208 	if (tfm->trie)
    209 		return;
    210 
    211 	for (ietat = 0; tampex_dedans(tfm->etats, ietat); ietat++) {
    212 		if (!tfm->etats[ietat].trie && tfm->etats[ietat].existe) {
    213 		    trier_etat(tfm, ietat);
    214 		    tfm->etats[ietat].trie = 1;
    215 		}
    216 	}
    217 }
    218 
    219 /* Inspiré du programme de Simon Tatham disponible au
    220  * https://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.c */
    221 static void
    222 trier_etat(struct tfm *tfm, size_t ietat)
    223 {
    224 	TFM_COHERENT(tfm);
    225 
    226 	ssize_t liste, dern; /* Liste et son dernier élément. */
    227 	size_t listel; /* Longueur de la liste. */
    228 	size_t ts; /* Taille des segments. */
    229 	ssize_t s1, s2; /* Deux segments de la liste. */
    230 	size_t ts1, ts2; /* Taille des deux segments. */
    231 	size_t trans;
    232 	size_t i;
    233 
    234 	liste = tfm->etats[ietat].trans;
    235 	listel = tfm->etats[ietat].ntrans;
    236 	ts = 1;
    237 
    238 	while (ts < listel) {
    239 		s1 = s2 = liste;
    240 		liste = dern = -1;
    241 
    242 		while (s1 != -1) {
    243 		    ts1 = 0;
    244 		    for (i = 0; i < ts; i++) {
    245 		        ts1++;
    246 		        if ((s2 = tfm->trans[s2].prch) == -1)
    247 		            break;
    248 		    }
    249 
    250 		    ts2 = ts;
    251 
    252 		    while ((ts1 > 0) || ((ts2 > 0) && (s2 != -1))) {
    253 		        if (ts1 == 0) goto des2;
    254 		        if (ts2 == 0 || s2 == -1) goto des1;
    255 		        if (trans_comparer(tfm, s1, s2) <= 0) {
    256 		        des1:
    257 		            trans = s1;
    258 		            s1 = tfm->trans[s1].prch;
    259 		            ts1--;
    260 		        } else {
    261 		        des2:
    262 		            trans = s2;
    263 		            s2 = tfm->trans[s2].prch;
    264 		            ts2--;
    265 		        }
    266 
    267 		        if (dern != -1) {
    268 		            tfm->trans[dern].prch = trans;
    269 		        } else {
    270 		            liste = trans;
    271 		        }
    272 		        dern = trans;
    273 		    }
    274 		    tfm->trans[dern].prch = -1;
    275 
    276 		    s1 = s2;
    277 		}
    278 
    279 		ts *= 2;
    280 	}
    281 
    282 	tfm->etats[ietat].trans = liste;
    283 }
    284 
    285 static int
    286 trans_comparer(struct tfm *tfm, size_t t1, size_t t2)
    287 {
    288 	TFM_COHERENT(tfm);
    289 
    290 	if (tfm->trans[t1].se > tfm->trans[t2].se) return -1;
    291 	if (tfm->trans[t1].se == tfm->trans[t2].se) return 0;
    292 	return 1;
    293 }
    294 
    295 static ssize_t
    296 tfm_symb_chercher(char *ti, char *symb, size_t lngr)
    297 {
    298 	size_t pos;
    299 	unsigned char n;
    300 
    301 	assert(ti);
    302 	assert(symb);
    303 	assert(lngr > 0);
    304 
    305 	for (pos = 0; tampex_dedans(ti, pos); pos += n) {
    306 		n = ti[pos++];
    307 		if (lngr == n && memcmp(symb, ti + pos, n) == 0)
    308 		    return pos - 1;
    309 	}
    310 
    311 	return -1;
    312 }