Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

Vérifier le sens d’un programme (analyse sémantique)

Après cette leçon: Je peux trouver les erreurs qu’un analyseur syntaxique ne voit pas.

Leçon de 50 min14 commandesLab de compilation et d’architecture : gcc, flex, bison et RISC-V dans une VM

Un rapport qui respecte toutes les règles

Le script d’inventaire d’un entrepôt finit par afficher total + pas. La grammaire l’accepte. Chaque jeton est correct.

Pourtant pas n’existait que dans une boucle déjà terminée. L’analyseur syntaxique vérifie la forme d’une phrase, pas son sens. Une autre partie du compilateur s’en charge.

À la fin de cette leçon

Remarque

Je peux trouver les erreurs qu’un analyseur syntaxique ne voit pas.

Mots-clés

MotCe que ça veut direExemple
Analyse sémantiquevérifier qu’un programme a un sens
Déclarationla ligne qui fait exister un nomint step
Portéela partie du programme où un nom existe
Table des symbolesla liste des noms que le compilateur connaît à cet endroit
Typele genre de valeur que contient une choseint
Avertissementun message qui n’arrête pas la construction

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Le compilateur tient une liste de noms

En parcourant l’arbre, le compilateur tient une table des symboles. Chaque { ouvre une nouvelle portée au-dessus des autres. Chaque déclaration ajoute un nom dans la portée du dessus. Chaque } jette cette portée.

Pour un nom, le compilateur cherche dans la portée du dessus, puis celle d’en dessous, et ainsi de suite. Un nom trouvé nulle part n’est pas déclaré. Les Runs montrent où vit step dans scope.c.

Aller dans le dossier du compilateur

Commande
cd ~/compiler

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Chaque ligne qui nomme step

Commande
grep -n "step" scope.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Exemple travaillé : les portées de scope.c

LigneCe qui se passeNoms connus
4 et 5main déclare unused et totalunused, total
6La boucle ouvre une portée et déclare iunused, total | i
7Le corps de la boucle déclare stepunused, total | i | step
9La boucle finit : ses portées sont jetéesunused, total
10printf utilise step : introuvableunused, total

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Compiler sans contrôle en plus

Commande
gcc -c scope.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Un fichier objet a-t-il été écrit ?

Commande
ls scope.o

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Demander les avertissements courants

Commande
gcc -Wall -c scope.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Une fonction se déclare avec ses paramètres

La table des symboles garde plus qu’un nom. Pour une fonction, elle garde aussi ses paramètres et leur type. square est déclarée avec un seul paramètre, un int.

Les Runs fabriquent deux copies de hello.c, sans toucher à l’original. Dans trop.c, l’appel reçoit deux nombres. Dans vide.c, il n’en reçoit aucun. Comparez ce que gcc répond.

Une copie avec un argument de trop

Commande
sed 's/square(7)/square(7, 8)/' hello.c > trop.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Compiler cette copie

Commande
gcc -c trop.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Une copie sans argument

Commande
sed 's/square(7)/square()/' hello.c > vide.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Compiler celle-ci

Commande
gcc -c vide.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Une erreur arrête, un avertissement non

Dans la copie format.c, printf reçoit le format %s, qui attend un texte, alors que square(7) donne un int. gcc sait lire un format de printf, donc il compare les types.

Cette fois, c’est un avertissement. La construction continue, et ls montre que format.o existe. Après une erreur, aucun fichier objet n’est écrit.

Une copie au mauvais format

Commande
sed 's/is %d/is %s/' hello.c > format.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

La compiler

Commande
gcc -c format.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Le fichier objet est-il là ?

Commande
ls format.o

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Erreur fréquente

Attention

Beaucoup de gens pensent qu’on peut ignorer un avertissement, puisque le programme se construit. Un avertissement dit : c’est permis, mais c’est très probablement faux. format.c se construit, puis lit un texte là où il n’y en a pas. Traitez chaque avertissement comme un bogue tant que vous ne savez pas pourquoi il est sans danger.

Python vérifie pendant l’exécution

Le C vérifie les noms et les types avant que le programme tourne : c’est un contrôle statique. Python ne les vérifie qu’au moment où la ligne s’exécute. La faute apparaît alors comme une erreur, à cet instant précis.

Les deux Runs lancent le programme. Aucune faute n’est trouvée avant que Python l’atteigne.

Un nom que Python ne connaît pas

Commande
python3 -c "print(prix)"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Un texte plus un nombre

Commande
python3 -c "print('total : ' + 12)"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Pour aller plus loin

Ajoutez à votre vérificateur un troisième problème, "inutilise". Il signale chaque nom déclaré puis jamais lu, avec la ligne de sa déclaration.

Essayez-le sur PROGRAMME avec une ligne de plus en tête, soit reserve = 1. Expliquez ensuite pourquoi gcc ne signale unused que sur demande, alors qu’il signale toujours step.

À propos de ce labo et de sa source: Lab de compilation et d’architecture : gcc, flex, bison et RISC-V dans une VM

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.