Bonjour,

J'essaie d'implémenter un programme capable d'évaluer une expression mathématique simple qui contient les opérateurs suivants : (, ), +, -, *, / et je butte sur la création de l'arbre syntaxique abstrait.

Je suis partie de la grammaire suivante :

Expr ::= Expr + Terme | Terme
Terme ::= Terme * Facteur | Facteur
Facteur ::= (Expr) | nombre

J'ai supprimé la récursivité à gauche :
Expr ::= Terme ExprSuite
ExprSuite ::= + Terme ExprSuite | epsilon
Terme ::= Facteur TermeSuite
TermeSuite ::= * Facteur TermeSuite | epsilon
Facteur ::= (Expr) | nombre

J'ai déterminé l'ensemble des premiers et des suivants :
Prem (Expr) => Prem (Facteur)
Prem (ExprReste) => {+, epsilon}
Prem (Terme) => Prem (Facteur)
Prem (TermeReste) => {*, epsilon}
Prem (Facteur) => {(, nombre}

Suiv (Expr) => {), EOF}
Suiv (ExprSuite) => Suiv (Expr)
Suiv (Terme) => Prem (ExprSuite)
Suiv (TermeSuite) => Suiv (Terme)
Suiv (Facteur) => Prem (TermeSuite)

J'ai ainsi obtenue la table de prédiction. Maintenant, mon problème se situe au niveau de la construction de l'arbre syntaxique abstrait, je ne vois pas à quel moment je dois ajouter quel type de jeton dans l'arbre.

Pour l'expression a + b * c j'aimerais obtenir l'arbre :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
 
  +
 /  \
a    *
    / \
   b   c
Au niveau du code source, j'ai produit cela et je bloque au niveau de la création de l'arbre (dans la partie analyse syntaxique) :

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
 
/**
 * Types definitions
 */
 
/**
 * \enum bool_t
 * \brief A boolean value is either true or false
 */
typedef enum bool_e {false, true} bool_t;
 
/**
 * \struct : token_t
 * \brief It represents a tokens : either an operator or an number
 */
typedef struct token_t {
	union {
		long nb; /*!< A number */
		char op; /*!< An operator */
	} token;
	int type; /*!< Token type 0 = digit, 1 = operator  */
} token_t;
 
/**
 * \struct : token_list_t
 * \brief A list of token is a /token/ and a pointer to the /next/ element of the list.
 */
typedef struct token_list_s {
	token_t token; /*!< A token */
	struct token_list_s * next; /*!< A pointer to the next token */
} token_list_t;
 
/**
 * \struct : token_queue_t
 * \brief A queue holds the head /hd/ and the tail /tl/ of the list
 */
typedef struct token_queue_s {
	struct token_list_s * hd; /*!< A pointer to head of the queue */
	struct token_list_s * tl; /*!< A pointer to tail of the queue */
} token_queue_t;
 
/**
 * \struct : token_tree_t
 * \brief A tree of tokens is a /token/ and two pointers toward its chidrens
 */
typedef struct token_tree_s {
	token_t token; /*!< A token */
	struct token_tree_s * left; /*!< A pointer to the left child */
	struct token_tree_s * right; /*!< A pointer to the right child */
} token_tree_t;
 
/**
 * List Implementation
 */
 
/**
 * \fn cons
 * \brief conses an element to the list
 *
 * @param token : token_t
 * @param list  : token_list_t
 * @return A pointer to the head of the list : token_list_t *
 */
token_list_t *
cons (token_t token, token_list_t * list) {
	token_list_t * elem = NULL;
	if ((elem = malloc(sizeof *elem)) == NULL) {
		perror("cons");
		return NULL;
	}
 
	elem->token = token;
	elem->next = list;
 
	return elem;
}
 
/**
 * \fn free_token_list
 * \brief frees the list of tokens /list/
 *
 * @param list : token_list_t
 */
void
free_token_list (token_list_t * list) {
	while (list != NULL) {
		token_list_t * current = list;
		list = list->next;
		free(current), current = NULL;
	}
}
 
/**
 * FIFO implementation
 */
 
/**
 * \fn token_list_init
 * \brief Initializes a queue of tokens
 *
 * @return A pointer to the queue : token_queue_t *
 */
token_queue_t *
token_queue_init (void) {
	token_queue_t * queue = NULL;
	if ((queue = malloc(sizeof *queue)) == NULL) {
		perror("malloc");
		return NULL;
	}
 
	queue->hd = queue->tl = NULL;
	return queue;
}
 
/**
 * \fn token_queue_is_empty
 * \brief Checks if the /queue/ is empty
 *
 * @param queue : token_queue_t
 * @return true if empty, otherwize false
 */
bool_t
token_queue_is_empty (token_queue_t * queue) {
	return queue->tl == NULL;
}
 
/**
 * \fn token_queue_push
 * \brief Pushes an element /token/ on the back of the tokens' queue /queue/
 *
 * @param token : token_t
 * @param queue : token_queue_t *
 * @return true is success, otherwize false : bool_t
 */
bool_t
token_queue_push (token_t token, token_queue_t * queue) {
	token_list_t * elem = NULL;
	if ((elem = cons(token, NULL)) == NULL) {
		perror("token_queue_push");
		return false;
	}
	if (token_queue_is_empty(queue))
		queue->hd = elem;
	else
		queue->tl->next = elem;
	queue->tl = elem;
 
	return true;
}
 
/**
 * \fn token_queue_pop
 * \brief Pops an element
 *
 * @param queue : token_queue_t *
 * @param elem  : token_t *
 * @return true is success, otherwize false : bool_t
 */
bool_t
token_queue_pop (token_queue_t * queue, token_t * elem) {
	token_list_t * cel;
	if ((cel = queue->hd) == NULL) {
		perror("token_queue_pop");
		return false;
	}
 
	*elem = cel->token;
 
	if ((queue->hd = cel->next) == NULL)
		queue->tl = NULL;
 
	free(cel), cel = NULL;
 
	return true;
}
 
/**
 * \fn token_queue_free
 * \brief Frees a queue of tokens
 *
 * @param queue : token_queue_t *
 */
void
free_token_queue (token_queue_t * queue) {
	free_token_list(queue->hd);
	free(queue);
}
 
/**
 * \fn token_tree_init
 * \brief Initializes a tree of tokens
 *
 * @return A pointer to a tree of tokens
 */
token_tree_t *
token_tree_init (void) {
	token_tree_t * tree = NULL;
	if ((tree = malloc(sizeof *tree)) == NULL) {
		perror("malloc");
		return NULL;
	}
 
	tree->left = tree->right = NULL;
 
	return tree;
}
 
/**
 * Lexical analysis
 */
 
/**
 * \fn is_operator
 * \brief Checks if /c/ is an operator
 *
 * @param c : unsigned int
 * @return true if /c/ is an operatoir, otherwize false : bool_t
 */
bool_t
is_operator(unsigned int c) {
	return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
}
 
/**
 * \fn is_token
 * \brief Checks if /c/ is a token
 *
 * @param c : unsigned int
 * @return true if /c/ is a token, otherwize false : bool_t
 */
bool_t
is_token (unsigned int c) {
	return isdigit(c) || is_operator(c);
}
 
/**
 * \fn read_token
 * \brief Reads a token and returns it
 *
 * @param stream : char **
 * @return The read token : token
 */
token_t
read_token (char ** stream) {
	token_t t;
 
	while (isspace(**stream))
		(*stream)++;
 
	if (is_token((unsigned int)**stream)) {
		if (isdigit((unsigned int)**stream)) {
			t.token.nb = strtol(*stream, stream, 10);
			t.type = 0; /* 0 = digit */
		} else {
			t.token.op = **stream;
			t.type = 1; /* 1 = operator */
			(*stream)++;
		}
	}
 
	return t;
}
 
/**
 * \fn tokenize
 * \brief This function divides the stream in a list of tokens
 *
 * @param stream : char *
 * @return A pointer to the list of tokens : token_queue_t *
 */
token_queue_t *
tokenize (char * stream) {
	token_queue_t * tokens, token_tree * ast = NULL;
	token_t gardien;
 
	tokens = token_queue_init();
 
	while (*stream)
		token_queue_push(read_token(&stream), tokens);
	/* And the gardien */
	gardien.type = 1;
	gardien.token.op = '\0';
	token_queue_push(gardien, tokens);
 
	return tokens;
}
 
/**
 * Syntax analysis
 */
 
/**
 * \fn syntax_error
 * \brief prints a syntax error
 *
 * @param f_tkn : const token_t
 * @param msg   : const char *
 */
void
syntax_error (const token_t f_tkn, const char * msg) {
	if (!f_tkn.type) /* digits */
		fprintf(stderr, "Syntax error : '%d' found. %s", current.token.nb, msg);
	else /* operators */
		fprintf(stderr, "Syntax error : '%c' found. %s", current.token.op, msg);
}
 
token_tree_t * /* Must be able to catch epsilon | nullifiable */
_expr (token_queue_t * tokens, token_tree * ast) {
	token_t current = tokens->hd->token;
 
	if (current.type == 1) {
		if (current.token.op == '+' || current.token.op == '-')
			/* ajoute jeton */;
			term();
			_expr();
		else if (current.token.op == ')')
			/* End */
	} else {
		syntax_error(current, "An operator is expected.");
	}
}
 
token_tree_t * /* Must be able to catch epsilon | nullifiable */
_term (token_queue_t * tokens, token_tree * ast) {
	token_t current = tokens->hd->token;
 
	if (current.type == 1) {
		if (current.token.op == '*' || current.token.op == '/')
			/* ajoute jeton */;
			factor();
			_expr();
		else if (current.token.op == ')')
			/* End -> return NULL */
	} else {
		syntax_error(current, "An operator is expected.");
	}
}
 
token_tree_t *
factor (token_queue_t * tokens, token_tree * ast) {
	token_t current = tokens->hd->token;
 
	if (current.type == 0) { /* digits */
		/* ajoute (digits); */
	} else if (current.type == 1 && current.token.op == '(') {
		expr(tokens);
	} else {
		syntax_error(current, "Number or opening brace is expected.");
	}
}
 
token_tree_t *
term (token_queue_t * tokens, token_tree * ast) {
	token_t current = tokens->hd->token;
 
	if (current.type == 0) { /* digits */
		factor(tokens);
		_term(tokens);
	} else if (current.type == 1 && current.token.op == '(') {
		factor(tokens);
		_term(tokens);
	} else {
		syntax_error(current, "Number or opening brace is expected.");
	}
}
 
token_tree_t *
expr (token_queue_t * tokens, token_tree * ast) {
	token_t current = tokens->hd->token;
 
	if (current.type == 0) { /* digits */
		term(tokens);
		_expr(tokens);
	} else if (current.type == 1 && current.token.op == '(') {
		term(tokens);
		_expr(tokens);
	} else {
		syntax_error(current, "Number or opening brace is expected.");
	}
}
 
/**
 * \fn parse
 * \brief Use a list of /tokens/ to make an abstract syntax tree
 *
 * @param tokens : token_queue_t *
 * @return An abstract syntax tree : token_tree_t *
 */
token_tree_t *
parse (token_queue_t * tokens) {
	return expr(tokens);
}
 
/**
 * \fn eval
 * \brief This function evaluates a mathematical expression and returns the result of this one
 *
 * @param expr : char *
 * @return The result of the mathematical expression : long
 */
long
eval (char * expr) {
	long result = 0;
	token_queue_t * tokens;
	token_tree_t * ast;
 
	tokens = tokenize(expr);
	ast = parse(tokens);
	/*result = compute_ast(ast);*/
 
	free_token_queue(tokens), tokens = NULL;
 
	return result;
}
 
int
main (void) {
	char expression[] = "0-2*((2+3)*(2-3))/5"; /* = 2 */
 
	printf("%d", eval(expression));
 
	return EXIT_SUCCESS;
}
Merci d'avance,
Lithrein