1 |
6 |
mcafruni |
/*********************************************************************************************/
|
2 |
|
|
/* MODULE PREPARATEUR */
|
3 |
|
|
/* ce module a pour but de lire le fichier Syntaxe du programme et de générer l'arbre des */
|
4 |
|
|
/* lexèmes qui lui correspond. */
|
5 |
|
|
/* */
|
6 |
|
|
/* Le seul point d'accès de ce module est la fonction init_arbre qui reçoit le nom du */
|
7 |
|
|
/* fichier Syntaxe à utiliser. */
|
8 |
|
|
/* */
|
9 |
|
|
/*********************************************************************************************/
|
10 |
|
|
|
11 |
|
|
#include "preparateur.h"
|
12 |
|
|
|
13 |
|
|
/* Inclusion des modules de la bibliothèque standard. */
|
14 |
|
|
#include <stdio.h>
|
15 |
|
|
#include <string.h>
|
16 |
|
|
|
17 |
|
|
/* Inclusion des autres modules utilisés du projet. */
|
18 |
|
|
#include <debogueur.h>
|
19 |
|
|
#include <parametres.h>
|
20 |
|
|
#include <dialogue.h>
|
21 |
|
|
#include <formateur.h>
|
22 |
|
|
#include <adaptateur.h>
|
23 |
|
|
|
24 |
|
|
/* Ces macros sont utilisées pour les comparaisons de chaines. Leur valeur détermine la */
|
25 |
|
|
/* sensibilité ou non du préparateur à la casse lors de la lecture du fichier Syntaxe. */
|
26 |
|
|
#define string_comp strcasecmp
|
27 |
|
|
#define lexeme_comp lexcaseid
|
28 |
|
|
|
29 |
|
|
type_noeud *root = NULL; /* Définition de la racine de l'arbre des lexèmes. */
|
30 |
|
|
|
31 |
|
|
/* Numéro de ligne et fichier Syntaxe courant. */
|
32 |
|
|
static int ligne=1;
|
33 |
|
|
static char * n_fich;
|
34 |
|
|
static FILE * f_syn;
|
35 |
|
|
|
36 |
|
|
/*********************************************************************************************/
|
37 |
|
|
/* */
|
38 |
|
|
/* Définition des objets décrivant la syntaxe et l'organisation du fichier Syntaxe. On */
|
39 |
|
|
/* trouve : */
|
40 |
|
|
/* */
|
41 |
|
|
/* la table des mots clefs, qui contient les valeurs spécifiant un type de lexème. */
|
42 |
|
|
/* la table des propriétés, regroupant le nom des différentes propriétés. */
|
43 |
|
|
/* la table des fonctions qui peuvent être exécutées à la lecture du fichier Syntaxe. */
|
44 |
|
|
/* */
|
45 |
|
|
/*********************************************************************************************/
|
46 |
|
|
|
47 |
|
|
|
48 |
|
|
/* TABLES DES MOTS CLEF */
|
49 |
|
|
typedef struct
|
50 |
|
|
{
|
51 |
|
|
char * nom;
|
52 |
|
|
type_type_lex code;
|
53 |
|
|
} type_table;
|
54 |
|
|
|
55 |
|
|
/* Table statique des mots clefs correspondant aux types de base. */
|
56 |
|
|
#define NUM_KEYWORD 2 /* Nombre de mots clef reconnus par le préparateur. */
|
57 |
|
|
static type_table table_clef_base[NUM_KEYWORD] =
|
58 |
|
|
{ { "alpha" , ALPHA}
|
59 |
|
|
, { "int" , NUM}
|
60 |
|
|
};
|
61 |
|
|
|
62 |
|
|
/* Table dynamique des mots clefs correspondant aux sous types. */
|
63 |
|
|
static type_table * table_clef_sst=NULL;
|
64 |
|
|
|
65 |
|
|
|
66 |
|
|
/* TABLE DES PROPRIETES */
|
67 |
|
|
#define NUM_PROP 3
|
68 |
|
|
static char *prop_table[NUM_PROP] =
|
69 |
|
|
{ "TMO"
|
70 |
|
|
, "MSK"
|
71 |
|
|
, "FUN"
|
72 |
|
|
};
|
73 |
|
|
enum {TMO, MSK, FUN}; /* Codes symboliques pour les différentes propriétés. */
|
74 |
|
|
|
75 |
|
|
|
76 |
|
|
/* TABLE DES FONCTIONS */
|
77 |
|
|
/* Définition des fonctions de paramétrage du preparateur. Elles seront exécutées à la */
|
78 |
|
|
/* demande du fichier Syntaxe lors de la rencontre de l'instruction SET. */
|
79 |
|
|
|
80 |
|
|
/* En cas d'erreur, ces fonctions renvoient 1 et positionnent la variable errcode du module */
|
81 |
|
|
/* erreur. La fonction appelante se charge de l'affichage de l'erreur. */
|
82 |
|
|
|
83 |
|
|
int casse()
|
84 |
|
|
{
|
85 |
|
|
casse_sens = 1;
|
86 |
|
|
DIALOGUE(NULL, 0, B_CASSE);
|
87 |
|
|
return 0;
|
88 |
|
|
}
|
89 |
|
|
|
90 |
|
|
int nocasse()
|
91 |
|
|
{
|
92 |
|
|
casse_sens = 0;
|
93 |
|
|
DIALOGUE(NULL, 0, B_NOCASSE);
|
94 |
|
|
return 0;
|
95 |
|
|
}
|
96 |
|
|
|
97 |
|
|
int macrofile() /* Cette fonction lit le nom du fichier macro par défaut et l'enregistre. */
|
98 |
|
|
{
|
99 |
|
|
long pos=ftell(f_syn);
|
100 |
|
|
type_lexeme * l;
|
101 |
|
|
|
102 |
|
|
DIALOGUE(NULL, 0, B_MAC_DEF);
|
103 |
|
|
|
104 |
|
|
l=get_lexeme(f_syn);
|
105 |
|
|
if (l==NULL)
|
106 |
|
|
{
|
107 |
|
|
err_code=S_BAD_ARG;
|
108 |
|
|
return 1;
|
109 |
|
|
}
|
110 |
|
|
if (!TYPE_IS(l, ALPHA) || !LIT_MPV(l->type))
|
111 |
|
|
{
|
112 |
|
|
FREE_LEX(l);
|
113 |
|
|
fseek(f_syn,pos-ftell(f_syn),SEEK_CUR); /* On "remet" le lexème. */
|
114 |
|
|
err_code=S_BAD_ARG;
|
115 |
|
|
return 1;
|
116 |
|
|
}
|
117 |
|
|
|
118 |
|
|
if (fich_macro_def!=NULL) free(fich_macro_def);
|
119 |
|
|
fich_macro_def=l->valeur.alpha;
|
120 |
|
|
/* On supprime la valeur du lexème pour que la chaine ne soit pas libérée. */
|
121 |
|
|
l->type=RET_MPV(l->type);
|
122 |
|
|
FREE_LEX(l);
|
123 |
|
|
|
124 |
|
|
err_code = NO_ERR;
|
125 |
|
|
return 0;
|
126 |
|
|
}
|
127 |
|
|
|
128 |
|
|
int setdefine()
|
129 |
|
|
{
|
130 |
|
|
long pos=ftell(f_syn);
|
131 |
|
|
type_lexeme * lex;
|
132 |
|
|
|
133 |
|
|
DIALOGUE(NULL, 0, B_INIT_D);
|
134 |
|
|
|
135 |
|
|
lex=get_lexeme(f_syn);
|
136 |
|
|
if (lex==NULL)
|
137 |
|
|
{ /* Erreur de lecture de l'argument. */
|
138 |
|
|
err_code=S_BAD_ARG;
|
139 |
|
|
return 1;
|
140 |
|
|
}
|
141 |
|
|
if (!TYPE_IS(lex,ALPHA))
|
142 |
|
|
{ /* L'argument n'a pas le bon type. */
|
143 |
|
|
FREE_LEX(lex);
|
144 |
|
|
fseek(f_syn,pos-ftell(f_syn),SEEK_CUR); /* On "remet" le lexème. */
|
145 |
|
|
err_code=S_BAD_ARG;
|
146 |
|
|
return 1;
|
147 |
|
|
}
|
148 |
|
|
if (define_str!=NULL) free(define_str);
|
149 |
|
|
define_str=malloc(strlen(lex->valeur.alpha)+1);
|
150 |
|
|
strcpy(define_str, lex->valeur.alpha);
|
151 |
|
|
FREE_LEX(lex);
|
152 |
|
|
|
153 |
|
|
err_code = NO_ERR;
|
154 |
|
|
return 0;
|
155 |
|
|
}
|
156 |
|
|
|
157 |
|
|
int setundef()
|
158 |
|
|
{
|
159 |
|
|
long pos=ftell(f_syn);
|
160 |
|
|
type_lexeme * lex;
|
161 |
|
|
|
162 |
|
|
DIALOGUE(NULL, 0, B_INIT_U);
|
163 |
|
|
|
164 |
|
|
lex=get_lexeme(f_syn);
|
165 |
|
|
if (lex==NULL)
|
166 |
|
|
{ /* Erreur de lecture de l'argument. */
|
167 |
|
|
err_code=S_BAD_ARG;
|
168 |
|
|
return 1;
|
169 |
|
|
}
|
170 |
|
|
if (!TYPE_IS(lex,ALPHA))
|
171 |
|
|
{ /* L'argument n'a pas le bon type. */
|
172 |
|
|
FREE_LEX(lex);
|
173 |
|
|
fseek(f_syn,pos-ftell(f_syn),SEEK_CUR); /* On "remet" le lexème. */
|
174 |
|
|
err_code=S_BAD_ARG;
|
175 |
|
|
return 1;
|
176 |
|
|
}
|
177 |
|
|
if (undef_str!=NULL) free(undef_str);
|
178 |
|
|
undef_str=malloc(strlen(lex->valeur.alpha)+1);
|
179 |
|
|
strcpy(undef_str, lex->valeur.alpha);
|
180 |
|
|
FREE_LEX(lex);
|
181 |
|
|
|
182 |
|
|
err_code = NO_ERR;
|
183 |
|
|
return 0;
|
184 |
|
|
}
|
185 |
|
|
|
186 |
|
|
int setinclude()
|
187 |
|
|
{
|
188 |
|
|
long pos=ftell(f_syn);
|
189 |
|
|
type_lexeme * lex;
|
190 |
|
|
|
191 |
|
|
DIALOGUE(NULL, 0, B_INIT_I);
|
192 |
|
|
|
193 |
|
|
lex=get_lexeme(f_syn);
|
194 |
|
|
if (lex==NULL)
|
195 |
|
|
{
|
196 |
|
|
err_code=S_BAD_ARG;
|
197 |
|
|
return 1; /* Erreur de lecture de l'argument. */
|
198 |
|
|
}
|
199 |
|
|
if (!TYPE_IS(lex,ALPHA)) /* L'argument n'a pas le bon type. */
|
200 |
|
|
{
|
201 |
|
|
FREE_LEX(lex);
|
202 |
|
|
fseek(f_syn,pos-ftell(f_syn),SEEK_CUR); /* On "remet" le lexème. */
|
203 |
|
|
err_code=S_BAD_ARG;
|
204 |
|
|
return 1;
|
205 |
|
|
}
|
206 |
|
|
|
207 |
|
|
if (include_str!=NULL) free(include_str);
|
208 |
|
|
include_str=malloc(strlen(lex->valeur.alpha)+1);
|
209 |
|
|
strcpy(include_str, lex->valeur.alpha);
|
210 |
|
|
FREE_LEX(lex);
|
211 |
|
|
|
212 |
|
|
err_code = NO_ERR;
|
213 |
|
|
return 0;
|
214 |
|
|
}
|
215 |
|
|
|
216 |
|
|
int setsep()
|
217 |
|
|
{
|
218 |
|
|
type_lexeme * lex;
|
219 |
|
|
lex=get_lexeme(f_syn);
|
220 |
|
|
|
221 |
|
|
DIALOGUE(NULL, 0, B_INIT_SEP);
|
222 |
|
|
|
223 |
|
|
if (lex==NULL)
|
224 |
|
|
{
|
225 |
|
|
err_code=S_BAD_ARG;
|
226 |
|
|
return 1;
|
227 |
|
|
}
|
228 |
|
|
if (seplex!=NULL) FREE_LEX(seplex);
|
229 |
|
|
if (TYPE_IS(lex, OP) && lex->valeur.op==NL) ligne++;
|
230 |
|
|
seplex=lex;
|
231 |
|
|
|
232 |
|
|
err_code = NO_ERR;
|
233 |
|
|
return 0;
|
234 |
|
|
}
|
235 |
|
|
|
236 |
|
|
int sst_max=0; /* Nombre maximal de sous-types réservés dans la table. */
|
237 |
|
|
|
238 |
|
|
int setnumsst()
|
239 |
|
|
{
|
240 |
|
|
long pos=ftell(f_syn);
|
241 |
|
|
type_lexeme * lex;
|
242 |
|
|
|
243 |
|
|
DIALOGUE(NULL, 0, B_PREP_SST);
|
244 |
|
|
|
245 |
|
|
if (table_clef_sst!=NULL) /* Réutilisation de SSTNUM. */
|
246 |
|
|
{
|
247 |
|
|
err_code = S_SEC_SST_DEC;
|
248 |
|
|
return 1;
|
249 |
|
|
}
|
250 |
|
|
|
251 |
|
|
lex=get_lexeme(f_syn);
|
252 |
|
|
if (lex==NULL)
|
253 |
|
|
{ /* Erreur de lecture de l'argument. */
|
254 |
|
|
err_code=S_BAD_ARG;
|
255 |
|
|
return 1;
|
256 |
|
|
}
|
257 |
|
|
if (!TYPE_IS(lex,NUM)) /* L'argument n'a pas le bon type. */
|
258 |
|
|
{
|
259 |
|
|
FREE_LEX(lex);
|
260 |
|
|
fseek(f_syn,pos-ftell(f_syn),SEEK_CUR); /* On "remet" le lexème. */
|
261 |
|
|
err_code=S_BAD_ARG;
|
262 |
|
|
return 1;
|
263 |
|
|
}
|
264 |
|
|
sst_max=lex->valeur.num;
|
265 |
|
|
|
266 |
|
|
FREE_LEX(lex);
|
267 |
|
|
/* Allocation des tables locales et globale des sous types. */
|
268 |
|
|
regle_typage = (type_paire *) malloc(sst_max*sizeof(type_paire));
|
269 |
|
|
if (regle_typage==NULL) DIALOGUE("preparateur(setnumsst)", 0, F_ERR_MEM);
|
270 |
|
|
table_clef_sst = (type_table*) malloc(sst_max*sizeof(type_table));
|
271 |
|
|
if (table_clef_sst==NULL) DIALOGUE("preparateur(setnumsst)", 0, F_ERR_MEM);
|
272 |
|
|
|
273 |
|
|
err_code = NO_ERR;
|
274 |
|
|
return 0;
|
275 |
|
|
}
|
276 |
|
|
|
277 |
|
|
int setnewsst()
|
278 |
|
|
{
|
279 |
|
|
long pos=ftell(f_syn);
|
280 |
|
|
type_lexeme * lex;
|
281 |
|
|
char * nom, *filtre;
|
282 |
|
|
type_type_lex code;
|
283 |
|
|
int i, bk=0;
|
284 |
|
|
|
285 |
|
|
DIALOGUE(NULL, 0, B_ADD_SST);
|
286 |
|
|
|
287 |
|
|
/* Vérification que la déclaration du nombre de sous-types est valide. */
|
288 |
|
|
if (regle_typage==NULL || table_clef_sst==NULL || nbr_sous_types>=sst_max)
|
289 |
|
|
{
|
290 |
|
|
err_code=S_BAD_SST_DEC;
|
291 |
|
|
return 1;
|
292 |
|
|
}
|
293 |
|
|
|
294 |
|
|
/* Lecture du mot clef correspondant au sous-type. */
|
295 |
|
|
lex=get_lexeme(f_syn);
|
296 |
|
|
if (lex==NULL)
|
297 |
|
|
{
|
298 |
|
|
err_code=S_BAD_ARG;
|
299 |
|
|
return 1; /* Erreur de lecture de l'argument. */
|
300 |
|
|
}
|
301 |
|
|
if (!TYPE_IS(lex,ALPHA)) /* L'argument n'a pas le bon type. */
|
302 |
|
|
{
|
303 |
|
|
FREE_LEX(lex);
|
304 |
|
|
fseek(f_syn,pos-ftell(f_syn),SEEK_CUR); /* On "remet" le lexème. */
|
305 |
|
|
err_code=S_BAD_ARG;
|
306 |
|
|
return 1;
|
307 |
|
|
}
|
308 |
|
|
/* Ajout du mot clef. */
|
309 |
|
|
nom = lex->valeur.alpha;
|
310 |
|
|
/* On supprime la valeur pour qu'elle ne soit pas libérée par FREE_LEX. */
|
311 |
|
|
lex->type=RET_MPV(lex->type);
|
312 |
|
|
FREE_LEX(lex);
|
313 |
|
|
|
314 |
|
|
|
315 |
|
|
/* Lecture de la règle de typage correspondant au sous-type. */
|
316 |
|
|
lex=get_lexeme(f_syn);
|
317 |
|
|
if (lex==NULL)
|
318 |
|
|
{
|
319 |
|
|
err_code=S_BAD_ARG;
|
320 |
|
|
return 1; /* Erreur de lecture de l'argument. */
|
321 |
|
|
}
|
322 |
|
|
if (!TYPE_IS(lex,ALPHA)) /* L'argument n'a pas le bon type. */
|
323 |
|
|
{
|
324 |
|
|
FREE_LEX(lex);
|
325 |
|
|
free(nom);
|
326 |
|
|
fseek(f_syn,pos-ftell(f_syn),SEEK_CUR); /* On "remet" le lexème. */
|
327 |
|
|
err_code=S_BAD_ARG;
|
328 |
|
|
return 1;
|
329 |
|
|
}
|
330 |
|
|
/* Ajout de la règle à la table. */
|
331 |
|
|
filtre=lex->valeur.alpha;
|
332 |
|
|
/* On supprime la valeur pour qu'elle ne soit pas libérée par FREE_LEX. */
|
333 |
|
|
lex->type=RET_MPV(lex->type);
|
334 |
|
|
FREE_LEX(lex);
|
335 |
|
|
|
336 |
|
|
/* Lecture du code correspondant au sous-type. */
|
337 |
|
|
lex=get_lexeme(f_syn);
|
338 |
|
|
if (lex==NULL)
|
339 |
|
|
{
|
340 |
|
|
err_code=S_BAD_ARG;
|
341 |
|
|
return 1; /* Erreur de lecture de l'argument. */
|
342 |
|
|
}
|
343 |
|
|
if (!TYPE_IS(lex,NUM)) /* L'argument n'a pas le bon type. */
|
344 |
|
|
{
|
345 |
|
|
FREE_LEX(lex);
|
346 |
|
|
free(nom);
|
347 |
|
|
free(filtre);
|
348 |
|
|
fseek(f_syn,pos-ftell(f_syn),SEEK_CUR); /* On "remet" le lexème. */
|
349 |
|
|
err_code=S_BAD_ARG;
|
350 |
|
|
return 1;
|
351 |
|
|
}
|
352 |
|
|
/* Vérification de la valeur du code demandé. */
|
353 |
|
|
if (lex->valeur.num<0 || lex->valeur.num>MAX_SOUS_TYPES)
|
354 |
|
|
{ /* Le nombre de sous-types codables est limité... */
|
355 |
|
|
FREE_LEX(lex);
|
356 |
|
|
free(nom);
|
357 |
|
|
free(filtre);
|
358 |
|
|
err_code=S_DEP_SST;
|
359 |
|
|
fseek(f_syn,pos-ftell(f_syn),SEEK_CUR); /* On "remet" le lexème. */
|
360 |
|
|
return 1;
|
361 |
|
|
}
|
362 |
|
|
code=CODE_TYPE(lex->valeur.num);
|
363 |
|
|
FREE_LEX(lex);
|
364 |
|
|
|
365 |
|
|
for (i=0 ; i<nbr_sous_types ; i++)
|
366 |
|
|
{ /* Avertissements éventuels si il y a redéfinition du nom ou du type. */
|
367 |
|
|
/* Vérifiction que le code n'est pas déjà attribué à un autre sous-type. */
|
368 |
|
|
if (!bk && table_clef_sst[i].code==code
|
369 |
|
|
&& string_comp(table_clef_sst[i].nom, nom))
|
370 |
|
|
{ /* Avertissement, le même sous-type a deux noms différents. */
|
371 |
|
|
DIALOGUE(nom, 0, W_REDEF_CODE);
|
372 |
|
|
bk=1; /* On s'assure que le message n'est affiché qu'uns fois. */
|
373 |
|
|
}
|
374 |
|
|
|
375 |
|
|
/* Vérification que le nom n'est pas déjà attribué. */
|
376 |
|
|
if (!bk && table_clef_sst[i].code!=code
|
377 |
|
|
&& !string_comp(table_clef_sst[i].nom, nom))
|
378 |
|
|
{ /* Avertissement, le nom est déjà utilisé. */
|
379 |
|
|
DIALOGUE(nom, 0, W_REDEF_SST);
|
380 |
|
|
bk=1; /* On s'assure que le message n'est affiché qu'uns fois. */
|
381 |
|
|
}
|
382 |
|
|
}
|
383 |
|
|
|
384 |
|
|
/* Mise à jour des valeurs lues dans les tables locale et globale. */
|
385 |
|
|
table_clef_sst[nbr_sous_types].nom=nom;
|
386 |
|
|
table_clef_sst[nbr_sous_types].code=code;
|
387 |
|
|
regle_typage[nbr_sous_types].chaine=filtre;
|
388 |
|
|
regle_typage[nbr_sous_types].code=code;
|
389 |
|
|
|
390 |
|
|
nbr_sous_types++; /* Incrémentation du nombre de sous types effectivement déclarés. */
|
391 |
|
|
|
392 |
|
|
err_code=NO_ERR;
|
393 |
|
|
return 0;
|
394 |
|
|
}
|
395 |
|
|
|
396 |
|
|
#define SET "SET" /* Nom symbolique de la commande SET. */
|
397 |
|
|
#define NUM_FONC 9
|
398 |
|
|
|
399 |
|
|
/* Dans cette structure, on stocke les différents couples commande/fonction. On peut ainsi */
|
400 |
|
|
/* facilement ajouter de nouvelles commandes de description de la syntaxe sans avoir à */
|
401 |
|
|
/* modifier la fonction principale de génération de l'arbre. */
|
402 |
|
|
struct
|
403 |
|
|
{
|
404 |
|
|
char * nom;
|
405 |
|
|
int (*fonction)();
|
406 |
|
|
} fonc_table[NUM_FONC] =
|
407 |
|
|
{ { "CASSE" , &casse}
|
408 |
|
|
, { "NOCASSE" , &nocasse}
|
409 |
|
|
, { "MACROFILE" , ¯ofile}
|
410 |
|
|
, { "UNDEFSTR" , &setundef}
|
411 |
|
|
, { "DEFINESTR" , &setdefine}
|
412 |
|
|
, { "INCLUDESTR" , &setinclude}
|
413 |
|
|
, { "SEP" , &setsep}
|
414 |
|
|
, { "NUMSST" , &setnumsst}
|
415 |
|
|
, { "NEWSST" , &setnewsst}
|
416 |
|
|
};
|
417 |
|
|
|
418 |
|
|
/* Cette macro réinitialise les variables à positionner par le préparateur. Elle est appelée */
|
419 |
|
|
/* à chaque initialisation d'arbre de lexèmes (lecture de fichier syntaxe). */
|
420 |
|
|
|
421 |
|
|
#define REINIT \
|
422 |
|
|
{\
|
423 |
|
|
if (table_clef_sst!=NULL)\
|
424 |
|
|
{ /* Vidage de la table des sous types. */\
|
425 |
|
|
int i;\
|
426 |
|
|
for (i=0 ; i<nbr_sous_types ; i++) free(table_clef_sst[i].nom);\
|
427 |
|
|
free(table_clef_sst);\
|
428 |
|
|
}\
|
429 |
|
|
table_clef_sst=NULL;\
|
430 |
|
|
if (fich_macro_def!=NULL) free(fich_macro_def);\
|
431 |
|
|
fich_macro_def=NULL;\
|
432 |
|
|
if (define_str!=NULL) free(define_str);\
|
433 |
|
|
define_str=NULL;\
|
434 |
|
|
if (undef_str!=NULL) free(undef_str);\
|
435 |
|
|
undef_str=NULL;\
|
436 |
|
|
if (include_str!=NULL) free(include_str);\
|
437 |
|
|
include_str=NULL;\
|
438 |
|
|
if (seplex!=NULL) FREE_LEX(seplex);\
|
439 |
|
|
seplex=NULL;\
|
440 |
|
|
if (regle_typage!=NULL)\
|
441 |
|
|
{\
|
442 |
|
|
for ( ; nbr_sous_types>0 ; nbr_sous_types--)\
|
443 |
|
|
free(regle_typage[nbr_sous_types-1].chaine);\
|
444 |
|
|
free(regle_typage);\
|
445 |
|
|
regle_typage=NULL;\
|
446 |
|
|
}\
|
447 |
|
|
casse_sens=1;\
|
448 |
|
|
sst_max=0;\
|
449 |
|
|
nbr_sous_types=0;\
|
450 |
|
|
}
|
451 |
|
|
|
452 |
|
|
|
453 |
|
|
/*********************************************************************************************/
|
454 |
|
|
/* FONCTION place_lexeme */
|
455 |
|
|
/* */
|
456 |
|
|
/* type_noeud * place_lexeme(type_lexeme * l, type_noeud * cur_root) */
|
457 |
|
|
/* */
|
458 |
|
|
/* Cette fonction reçoit un lexème et un noeud. Elle recherche le lexème dans les fils du */
|
459 |
|
|
/* noeud et si elle le trouve, elle renvoie un pointeur sur lui, sinon elle le crée et */
|
460 |
|
|
/* renvoie ce nouveau pointeur. */
|
461 |
|
|
/* */
|
462 |
|
|
/*********************************************************************************************/
|
463 |
|
|
|
464 |
|
|
type_noeud * place_lexeme(type_lexeme * l, type_noeud * cur_root)
|
465 |
|
|
{
|
466 |
|
|
char * msg_orig="préparateur(place_lexeme)";
|
467 |
|
|
type_noeud * cur_fils = (cur_root->ptr_fils);
|
468 |
|
|
|
469 |
|
|
while (cur_fils != NULL)
|
470 |
|
|
{
|
471 |
|
|
if (lexeme_comp(l, &(cur_fils->lexeme))) return cur_fils;
|
472 |
|
|
cur_fils = cur_fils->ptr_frere;
|
473 |
|
|
}
|
474 |
|
|
ALLOC_NOEUD(cur_fils);
|
475 |
|
|
cur_fils->ptr_frere = cur_root->ptr_fils;
|
476 |
|
|
LEX_COPY(l, &(cur_fils->lexeme));
|
477 |
|
|
cur_root->ptr_fils = cur_fils;
|
478 |
|
|
return cur_fils;
|
479 |
|
|
}
|
480 |
|
|
|
481 |
|
|
|
482 |
|
|
/*********************************************************************************************/
|
483 |
|
|
/* FONCTION lit_feuille */
|
484 |
|
|
/* */
|
485 |
|
|
/* type_feuille * lit_feuille(FILE * f_syn) */
|
486 |
|
|
/* */
|
487 |
|
|
/* Cette fonction reçoit le fichier Syntaxe ouvert à la bonne position et lit les */
|
488 |
|
|
/* différentes propriétés qui s'y trouve. A partir de cette lecture, elle crée une feuille */
|
489 |
|
|
/* pour les enregistrer et renvoie un pointeur vers celle-ci. En cas d'erreur, un pointeur */
|
490 |
|
|
/* NULL est retourné et le fichier est laissé à la position de l'erreur. */
|
491 |
|
|
/* */
|
492 |
|
|
/*********************************************************************************************/
|
493 |
|
|
|
494 |
|
|
#define OPERATEUR (TYPE_IS(lex, OP))
|
495 |
|
|
#define VAL_OP ((lex->valeur).op)
|
496 |
|
|
#define VAL_ALPHA ((lex->valeur).alpha)
|
497 |
|
|
|
498 |
|
|
#define ERR_LF(val) {\
|
499 |
|
|
if (lex!=NULL) FREE_LEX(lex);\
|
500 |
|
|
if (mask_ptr!=NULL) FREE_MASK(mask_ptr);\
|
501 |
|
|
DIALOGUE(n_fich, ligne, val);\
|
502 |
|
|
return NULL;\
|
503 |
|
|
}
|
504 |
|
|
/* Comme la lecture d'une feuille n'est pas sensible a la présence de sauts de ligne, la */
|
505 |
|
|
/* macro suivante se charge de les éliminer. La terminaison est assurée par EOF. */
|
506 |
|
|
/* La macro commence par libérer l'espace du lexème précédent sauf si celui-ci est NULL. */
|
507 |
|
|
#define LIT_LEXEME {\
|
508 |
|
|
do\
|
509 |
|
|
{\
|
510 |
|
|
if (lex!=NULL) FREE_LEX(lex);\
|
511 |
|
|
lex=get_lexeme(f_syn);\
|
512 |
|
|
if (lex==NULL) ERR_LF(err_code)\
|
513 |
|
|
if (OPERATEUR && VAL_OP==NL) ligne++;\
|
514 |
|
|
}\
|
515 |
|
|
while (OPERATEUR && VAL_OP==NL);\
|
516 |
|
|
}
|
517 |
|
|
|
518 |
|
|
#define INIT_MASK {\
|
519 |
|
|
if (mask_ptr==NULL)\
|
520 |
|
|
{\
|
521 |
|
|
ALLOC_MASK(mask_ptr);\
|
522 |
|
|
mask_ptr->taille=0;\
|
523 |
|
|
mask_ptr->valeur=0;\
|
524 |
|
|
}\
|
525 |
|
|
if (mask_ptr==NULL)\
|
526 |
|
|
DIALOGUE("préparateur(lit_feuille)", 0, F_ERR_MEM);\
|
527 |
|
|
}
|
528 |
|
|
|
529 |
|
|
type_feuille * lit_feuille()
|
530 |
|
|
{
|
531 |
|
|
char * msg_orig="preparateur(lit_feuille)";
|
532 |
|
|
int i, c, tmo_lu=0, i_fun=0;
|
533 |
|
|
type_valeur_mask tmp_msk=0;
|
534 |
|
|
type_lexeme * lex=NULL;
|
535 |
|
|
type_ptr_fgm fun_ptr[MAX_FONCTIONS];
|
536 |
|
|
type_mask * mask_ptr=NULL;
|
537 |
|
|
type_feuille * tmp_feuille;
|
538 |
|
|
|
539 |
|
|
LIT_LEXEME /* Lit le premier lexème différent de NL. */
|
540 |
|
|
while (!OPERATEUR || (VAL_OP!=EOF && VAL_OP!=ACO))
|
541 |
|
|
{
|
542 |
|
|
if (!TYPE_IS(lex, ALPHA)) ERR_LF(S_BAD_PROP);
|
543 |
|
|
/* Détermination de la propriété. */
|
544 |
|
|
i=-1;
|
545 |
|
|
while (++i<NUM_PROP && string_comp(prop_table[i], VAL_ALPHA));
|
546 |
|
|
if (i==NUM_PROP) ERR_LF(S_BAD_PROP); /* Propriété inexistante. */
|
547 |
|
|
switch (i)
|
548 |
|
|
{ /* lecture de la valeur de la propriété. */
|
549 |
|
|
case TMO : LIT_LEXEME;
|
550 |
|
|
if (!TYPE_IS(lex,NUM)) ERR_LF(S_BAD_VAL);
|
551 |
|
|
INIT_MASK;
|
552 |
|
|
tmo_lu=1;
|
553 |
|
|
mask_ptr->taille=(lex->valeur).num;
|
554 |
|
|
break;
|
555 |
|
|
case MSK : LIT_LEXEME;
|
556 |
|
|
if (!TYPE_IS(lex,ALPHA)||VAL_ALPHA[0]!='_')
|
557 |
|
|
ERR_LF(S_BAD_VAL);
|
558 |
|
|
INIT_MASK;
|
559 |
|
|
i=1; tmp_msk=0;
|
560 |
|
|
while ((c=VAL_ALPHA[i++])!='\0')
|
561 |
|
|
{
|
562 |
|
|
if (c!='0' && c!='1')
|
563 |
|
|
{
|
564 |
|
|
if (c!='_') ERR_LF(S_BAD_VAL);
|
565 |
|
|
}
|
566 |
|
|
else
|
567 |
|
|
{
|
568 |
|
|
tmp_msk<<=1;
|
569 |
|
|
tmp_msk+=(c-'0');
|
570 |
|
|
}
|
571 |
|
|
}
|
572 |
|
|
(mask_ptr->valeur)|=tmp_msk;
|
573 |
|
|
break;
|
574 |
|
|
case FUN : if (i_fun==MAX_FONCTIONS) ERR_LF(S_DEP_FUNC_NB);
|
575 |
|
|
LIT_LEXEME;
|
576 |
|
|
if (!TYPE_IS(lex,ALPHA)) ERR_LF(S_BAD_VAL);
|
577 |
|
|
fun_ptr[i_fun]=alias(VAL_ALPHA);
|
578 |
|
|
if (fun_ptr[i_fun]==NULL)
|
579 |
|
|
{ /* Fonction inexistante. */
|
580 |
|
|
ERR_LF(S_BAD_FUN);
|
581 |
|
|
}
|
582 |
|
|
i_fun++;
|
583 |
|
|
break;
|
584 |
|
|
default : return NULL;
|
585 |
|
|
}
|
586 |
|
|
LIT_LEXEME;
|
587 |
|
|
}
|
588 |
|
|
|
589 |
|
|
FREE_LEX(lex);
|
590 |
|
|
ALLOC_FEUILLE(tmp_feuille);
|
591 |
|
|
if (!tmo_lu && mask_ptr!=NULL)
|
592 |
|
|
{ /* On ignore le masque si il n'a pas de taille spécifiée. */
|
593 |
|
|
FREE_MASK(mask_ptr);
|
594 |
|
|
mask_ptr=NULL;
|
595 |
|
|
}
|
596 |
|
|
tmp_feuille->mask_primaire=mask_ptr;
|
597 |
|
|
|
598 |
|
|
/* Recopie de la liste des fonctions de génération de masque. */
|
599 |
|
|
tmp_feuille->nbr_func=i_fun;
|
600 |
|
|
if (i_fun)
|
601 |
|
|
{
|
602 |
|
|
tmp_feuille->ptr_func=(type_ptr_fgm *) (malloc(i_fun*sizeof(type_ptr_fgm)));
|
603 |
|
|
if (tmp_feuille->ptr_func==NULL)
|
604 |
|
|
DIALOGUE("préparateur(lit_feuille)", 0, F_ERR_MEM);
|
605 |
|
|
while ((i_fun--)>0)
|
606 |
|
|
{
|
607 |
|
|
tmp_feuille->ptr_func[i_fun] = fun_ptr[i_fun];
|
608 |
|
|
}
|
609 |
|
|
}
|
610 |
|
|
else tmp_feuille->ptr_func=NULL;
|
611 |
|
|
|
612 |
|
|
return tmp_feuille;
|
613 |
|
|
}
|
614 |
|
|
|
615 |
|
|
|
616 |
|
|
/*********************************************************************************************/
|
617 |
|
|
/* FONCTION init_arbre */
|
618 |
|
|
/* */
|
619 |
|
|
/* int init_arbre(char * fichier_syntaxe) */
|
620 |
|
|
/* */
|
621 |
|
|
/* Cette fonction reçoit le nom du fichier Syntaxe, l'ouvre et y lit les informations. Elle */
|
622 |
|
|
/* les utilise pour mettre à jour l'arbre des lexèmes défini dans le commun (root). Les */
|
623 |
|
|
/* erreurs de format sont signalées. */
|
624 |
|
|
/* La valeur de retour est le nombre d'erreurs rencontrées. */
|
625 |
|
|
/* */
|
626 |
|
|
/*********************************************************************************************/
|
627 |
|
|
|
628 |
|
|
int init_arbre(char * fichier_syntaxe)
|
629 |
|
|
|
630 |
|
|
|
631 |
|
|
#define ERREUR(val) {\
|
632 |
|
|
DIALOGUE(fichier_syntaxe, ligne, val);\
|
633 |
|
|
err=1;\
|
634 |
|
|
}
|
635 |
|
|
/* Lecture d'un lexème non NULL, au pire EOF, tout en comptant les lignes. */
|
636 |
|
|
/* Le lexème précédent est libéré sauf s'il est NULL. */
|
637 |
|
|
#define LIT_VALIDE {\
|
638 |
|
|
if (lex!=NULL) FREE_LEX(lex);\
|
639 |
|
|
while ((lex=get_lexeme(f_syn))==NULL)\
|
640 |
|
|
{\
|
641 |
|
|
err=1;\
|
642 |
|
|
ERREUR(err_code);\
|
643 |
|
|
}\
|
644 |
|
|
if (OPERATEUR && VAL_OP==NL) ligne++;\
|
645 |
|
|
}
|
646 |
|
|
/* Recherche de la prochaine accolade ouvrante (instruction suivante) */
|
647 |
|
|
#define ACO_SUIV do LIT_VALIDE while (!OPERATEUR || (VAL_OP!=ACO && VAL_OP!=EOF))
|
648 |
|
|
#define LIGNE_SUIV do LIT_VALIDE while (!OPERATEUR || (VAL_OP!=NL && VAL_OP!=EOF))
|
649 |
|
|
|
650 |
|
|
{
|
651 |
|
|
char * msg_orig="preparateur(init_arbre)";
|
652 |
|
|
type_lexeme * lex=NULL;
|
653 |
|
|
int err=0,gblerr=0; /* err est vrai lors d'une erreur, gblerr s'il y a eu une erreur */
|
654 |
|
|
type_noeud * courant;
|
655 |
|
|
type_feuille * feuille=NULL;
|
656 |
|
|
|
657 |
|
|
/* Réinitialisation des différentes variables locales et globales. */
|
658 |
|
|
REINIT;
|
659 |
|
|
ALLOC_NOEUD(root);
|
660 |
|
|
|
661 |
|
|
f_syn=fopen(fichier_syntaxe, "rb"); /* ouverture du fichier Syntaxe. */
|
662 |
|
|
if (f_syn==NULL)
|
663 |
|
|
{
|
664 |
|
|
DIALOGUE(NULL, 0, W_NO_SYNTAX);
|
665 |
|
|
return 0;
|
666 |
|
|
}
|
667 |
|
|
|
668 |
|
|
n_fich = fichier_syntaxe; /* Positionne la variable commune au module. */
|
669 |
|
|
ligne=1; /* Initialisation du numéro de ligne au début du fichier. */
|
670 |
|
|
|
671 |
|
|
do /* Lecture du fichier Syntaxe jusqu'à la première accolade ouvrante. */
|
672 |
|
|
{
|
673 |
|
|
LIT_VALIDE;
|
674 |
|
|
if (TYPE_IS(lex, ALPHA) && !string_comp(VAL_ALPHA, SET))
|
675 |
|
|
{ /* On a rencontré une commande SET, lecture des arguments. */
|
676 |
|
|
int i=-1;
|
677 |
|
|
LIT_VALIDE;
|
678 |
|
|
if (!TYPE_IS(lex, ALPHA))
|
679 |
|
|
{
|
680 |
|
|
ERREUR(S_BAD_ARG);
|
681 |
|
|
gblerr++;
|
682 |
|
|
LIGNE_SUIV;
|
683 |
|
|
}
|
684 |
|
|
else
|
685 |
|
|
{
|
686 |
|
|
while (++i<NUM_FONC && /* Recherche de la fonction. */
|
687 |
|
|
string_comp(fonc_table[i].nom, VAL_ALPHA));
|
688 |
|
|
if (i==NUM_FONC)
|
689 |
|
|
{ /* La fonction demandée n'existe pas. */
|
690 |
|
|
ERREUR(S_BAD_ARG);
|
691 |
|
|
gblerr++;
|
692 |
|
|
LIGNE_SUIV;
|
693 |
|
|
}
|
694 |
|
|
else if (fonc_table[i].fonction())
|
695 |
|
|
{ /* Les paramètres de la fonction sont mal spécifiés. */
|
696 |
|
|
affiche_message(fichier_syntaxe, ligne);
|
697 |
|
|
gblerr++;
|
698 |
|
|
LIGNE_SUIV;
|
699 |
|
|
}
|
700 |
|
|
}
|
701 |
|
|
}
|
702 |
|
|
else if (!OPERATEUR || (VAL_OP!=ACO && VAL_OP!=EOF && VAL_OP!=NL))
|
703 |
|
|
{ /* Si on a un lexème interdit (erreur dans le fichier Syntaxe). */
|
704 |
|
|
gblerr++;
|
705 |
|
|
ERREUR(S_SYN_ERR);
|
706 |
|
|
LIGNE_SUIV; /* On ne tient pas compte de la ligne erronée. */
|
707 |
|
|
}
|
708 |
|
|
} while (!OPERATEUR || (VAL_OP!=ACO && VAL_OP!=EOF));
|
709 |
|
|
|
710 |
|
|
do /* Lecture des différentes instructions. */
|
711 |
|
|
{
|
712 |
|
|
courant=root;
|
713 |
|
|
err=0;
|
714 |
|
|
LIT_VALIDE;
|
715 |
|
|
if (OPERATEUR && VAL_OP==EOF) err=2;
|
716 |
|
|
if (OPERATEUR && VAL_OP==ACF) ERREUR(S_DCL_VIDE) /* Déclaration vide. */
|
717 |
|
|
else while ((!OPERATEUR || VAL_OP!=ACF) && !err)
|
718 |
|
|
{ /* Placer les lexèmes dans l'arbre jusqu'à ACF. */
|
719 |
|
|
if (LIT_MPV(lex->type) && TYPE_IS(lex, ALPHA))
|
720 |
|
|
{ /* Si on a un mot clef, on ajuste le type (on supprime la valeur) */
|
721 |
|
|
int i, key=0;
|
722 |
|
|
/* Recherche dans les mots clef de base. */
|
723 |
|
|
for (i=0 ; i<NUM_KEYWORD && !key ; i++)
|
724 |
|
|
if (!string_comp(table_clef_base[i].nom, VAL_ALPHA))
|
725 |
|
|
{
|
726 |
|
|
lex->type=table_clef_base[i].code;
|
727 |
|
|
key=1;
|
728 |
|
|
}
|
729 |
|
|
/* Recherche dans les mots clef des sous-types. */
|
730 |
|
|
for (i=0 ; i<nbr_sous_types && !key ; i++)
|
731 |
|
|
if (!string_comp(table_clef_sst[i].nom, VAL_ALPHA))
|
732 |
|
|
{
|
733 |
|
|
lex->type=table_clef_sst[i].code;
|
734 |
|
|
key=1;
|
735 |
|
|
}
|
736 |
|
|
if (key) free(lex->valeur.alpha);
|
737 |
|
|
}
|
738 |
|
|
courant = place_lexeme(lex, courant);
|
739 |
|
|
LIT_VALIDE;
|
740 |
|
|
if (OPERATEUR && VAL_OP==EOF) ERREUR(S_DCL_NON_TERM);
|
741 |
|
|
}
|
742 |
|
|
|
743 |
|
|
/* Redéfinition d'une instruction déjà lue. */
|
744 |
|
|
if (courant->ptr_feuille!=NULL) ERREUR(S_REDEF_INS);
|
745 |
|
|
|
746 |
|
|
if (!err) feuille=lit_feuille(); /* Lecture de la feuille. */
|
747 |
|
|
if (feuille==NULL) err=1; /* Le message d'erreur est géré à la lecture. */
|
748 |
|
|
|
749 |
|
|
/* Si la lecture est réussie, il faut mémoriser la nouvelle instruction. */
|
750 |
|
|
if (!err) courant->ptr_feuille=feuille;
|
751 |
|
|
else ACO_SUIV; /* Erreur de lecture, on passe à l'instruction suivante. */
|
752 |
|
|
gblerr+=(err==1); /* Le code d'erreur est uniquement 1. */
|
753 |
|
|
}
|
754 |
|
|
while (!OPERATEUR || VAL_OP!=EOF);
|
755 |
|
|
FREE_LEX(lex);
|
756 |
|
|
fclose(f_syn);
|
757 |
|
|
return gblerr;
|
758 |
|
|
}
|
759 |
|
|
|
760 |
|
|
/* Fonction de libération des structures contenues dans un arbre. */
|
761 |
|
|
void free_arbre(type_noeud * courant)
|
762 |
|
|
{
|
763 |
|
|
type_noeud * fils_courant;
|
764 |
|
|
|
765 |
|
|
if (courant==NULL) return;
|
766 |
|
|
fils_courant=courant->ptr_fils;
|
767 |
|
|
while (fils_courant!=NULL)
|
768 |
|
|
{ /* On efface récursivement tous les sous arbres. */
|
769 |
|
|
free_arbre(fils_courant);
|
770 |
|
|
fils_courant=fils_courant->ptr_frere;
|
771 |
|
|
}
|
772 |
|
|
/* On efface le champ valeur des lexèmes ALPHA. */
|
773 |
|
|
if (TYPE_IS(&(courant->lexeme), ALPHA) && LIT_MPV(courant->lexeme.type)
|
774 |
|
|
&& (courant->lexeme.valeur.alpha!=NULL))
|
775 |
|
|
free(courant->lexeme.valeur.alpha);
|
776 |
|
|
FREE_NOEUD(courant);
|
777 |
|
|
}
|
778 |
|
|
|
779 |
|
|
/* Fonction de libération des structures crées par init_arbre. */
|
780 |
|
|
void clear_preparateur()
|
781 |
|
|
{
|
782 |
|
|
free_arbre(root);
|
783 |
|
|
root=NULL; /* root a été libéré par la fonction free_arbre. */
|
784 |
|
|
REINIT;
|
785 |
|
|
}
|
786 |
|
|
|