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 }