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 }