Analyser des expressions
Construisez un arbre syntaxique.
Analyser des expressions est une leçon C Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C Academy comprend 4 leçons au total.
Des tokens à l’arbre
L’analyse syntaxique transforme un flux plat de tokens en un arbre syntaxique abstrait structuré (AST). L’arbre encode la priorité et le regroupement que les tokens bruts ne font qu’indiquer.
Pour 3 + 4 * 2, l’AST imbrique la multiplication sous l’addition, de sorte que le résultat est 11 et non 14.
Structure d’un nœud AST
Chaque Node est soit une feuille contenant un nombre, soit une opération binaire avec deux enfants. Une structure étiquetée contenant une union conserve une utilisation mémoire réduite.
Le caractère de l’opérateur distingue +, -, * et / à l’exécution.
typedef struct Node {
enum { N_NUM, N_BINOP } kind;
union {
int value; /* N_NUM */
struct { /* N_BINOP */
char op;
struct Node *left, *right;
} bin;
};
} Node;Allouer des nœuds
Deux petits constructeurs allouent des Nodes sur le tas. Construire l’arbre de bas en haut signifie que les feuilles sont créées en premier, puis enveloppées dans des Nodes opérateurs.
Dans un interpréteur de production, vous suivriez ces allocations afin de les libérer plus tard.
#include <stdlib.h>
static Node *num(int v) {
Node *n = malloc(sizeof *n);
n->kind = N_NUM; n->value = v;
return n;
}
static Node *binop(char op, Node *l, Node *r) {
Node *n = malloc(sizeof *n);
n->kind = N_BINOP;
n->bin.op = op; n->bin.left = l; n->bin.right = r;
return n;
}La grammaire
Nous utilisons une grammaire classique avec gestion des priorités. expr traite + et -, term traite * et /, et factor traite les nombres et les parenthèses.
Comme les règles de priorité supérieure sont placées plus profondément, la multiplication est automatiquement prioritaire sur l'addition.
/* Grammar (EBNF):
expr = term { ('+' | '-') term } ;
term = factor { ('*' | '/') factor } ;
factor = NUMBER | '(' expr ')' ; */Reconnaître les jetons
Un utilitaire expect consomme un jeton du type requis ou interrompt l'exécution. Il constitue le contrat entre l'analyseur syntaxique et l'analyseur lexical.
Nous réutilisons les utilitaires de prélecture cur et bump de la leçon sur l'analyse lexicale.
#include <stdio.h>
#include <stdlib.h>
static void expect(TokKind k) {
if (cur().kind != k) {
fprintf(stderr, "parse error: unexpected token\n");
exit(1);
}
bump();
}Analyser un facteur
Un facteur est l'atome de la grammaire : soit un nombre littéral, soit une sous-expression entre parenthèses. Les parenthèses relancent récursivement parse_expr.
C'est cette récursion qui donne leur nom aux analyseurs syntaxiques descendants récursifs.
static Node *parse_expr(void);
static Node *parse_factor(void) {
if (cur().kind == TOK_NUM) {
int v = cur().value; bump();
return num(v);
}
expect(TOK_LPAREN);
Node *e = parse_expr();
expect(TOK_RPAREN);
return e;
}Analyser un terme
Un terme analyse un facteur, puis boucle tant qu'il rencontre * ou /, en regroupant chacun dans un nœud binop associatif à gauche.
L'associativité à gauche signifie que 8 / 4 / 2 est analysé comme (8 / 4) / 2 = 1.
static Node *parse_term(void) {
Node *left = parse_factor();
while (cur().kind == TOK_STAR || cur().kind == TOK_SLASH) {
char op = (cur().kind == TOK_STAR) ? '*' : '/';
bump();
left = binop(op, left, parse_factor());
}
return left;
}Analyser une expression
La règle principale reprend le fonctionnement de parse_term, mais traite + et -. Chaque niveau appelle la règle de priorité immédiatement supérieure, ce qui produit un arbre correctement imbriqué.
Cette structure à trois fonctions constitue le cœur de l'analyseur syntaxique.
static Node *parse_expr(void) {
Node *left = parse_term();
while (cur().kind == TOK_PLUS || cur().kind == TOK_MINUS) {
char op = (cur().kind == TOK_PLUS) ? '+' : '-';
bump();
left = binop(op, left, parse_term());
}
return left;
}Examiner l'arbre
Ce programme analyse une expression et l'affiche à nouveau sous une forme entièrement parenthésée, ce qui révèle comment les priorités ont été résolues.
Le générateur de sortie récursif parcourt la même structure de nœuds que celle construite par l'analyseur syntaxique.
#include <stdio.h>
typedef struct Node {
int is_num; int value;
char op; struct Node *l, *r;
} Node;
static Node *N(int v){ Node*n=calloc(1,sizeof*n); n->is_num=1; n->value=v; return n; }
static Node *B(char o,Node*a,Node*b){ Node*n=calloc(1,sizeof*n); n->op=o; n->l=a; n->r=b; return n; }
static void show(Node *n){
if (n->is_num){ printf("%d", n->value); return; }
printf("("); show(n->l); printf(" %c ", n->op); show(n->r); printf(")");
}
int main(void){
/* 3 + 4 * 2 -> (3 + (4 * 2)) */
Node *ast = B('+', N(3), B('*', N(4), N(2)));
show(ast); printf("\n");
return 0;
}Éviter la récursion gauche
Une grammaire naïve comme expr = expr '+' term amènerait parse_expr à s'appeler indéfiniment. L'analyse descendante récursive ne peut pas gérer la récursion gauche directe.
Réécrire la règle sous la forme d'une boucle while sur { '+' term } permet d'éviter complètement la récursion infinie.
Pourquoi un AST ?
L'AST sépare la syntaxe de l'exécution. Le même arbre peut être évalué, optimisé ou compilé en bytecode sans nouvelle analyse syntaxique.
Nous allons maintenant parcourir cet arbre pour calculer sa valeur.
Vérification rapide
Observez comment les niveaux de la grammaire imposent les priorités.
Récapitulatif
Vous avez écrit un analyseur syntaxique descendant récursif : des structures de nœuds AST, des constructeurs et les fonctions expr/term/factor qui encodent les priorités et l'associativité à gauche.
L'arbre obtenu est prêt pour l'évaluation.
Questions Fréquemment Posées
La leçon « Analyser des expressions » est-elle gratuite ?
Oui — le texte complet de « Analyser des expressions » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C Academy, passe à CoddyKit PRO. Le cours C Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Analyser des expressions » ?
Construisez un arbre syntaxique. Tu pratiques C Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer C Academy ?
Aucune expérience préalable n'est requise. C Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.
Combien de temps prend la leçon « Analyser des expressions » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon C Academy ?
Oui. Chaque leçon C Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Découper l’entrée en jetons
- Analyser des expressions
- Évaluer l’arbre
- Ajouter des variables