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
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Analyse sémantique | vérifier qu’un programme a un sens | |
| Déclaration | la ligne qui fait exister un nom | int step |
| Portée | la partie du programme où un nom existe | |
| Table des symboles | la liste des noms que le compilateur connaît à cet endroit | |
| Type | le genre de valeur que contient une chose | int |
| Avertissement | un 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
cd ~/compilerAffiché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
grep -n "step" scope.cAffiché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
| Ligne | Ce qui se passe | Noms connus |
|---|---|---|
| 4 et 5 | main déclare unused et total | unused, total |
| 6 | La boucle ouvre une portée et déclare i | unused, total | i |
| 7 | Le corps de la boucle déclare step | unused, total | i | step |
| 9 | La boucle finit : ses portées sont jetées | unused, total |
| 10 | printf utilise step : introuvable | unused, total |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Compiler sans contrôle en plus
gcc -c scope.cAffiché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 ?
ls scope.oAffiché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
gcc -Wall -c scope.cAffiché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
sed 's/square(7)/square(7, 8)/' hello.c > trop.cAffiché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
gcc -c trop.cAffiché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
sed 's/square(7)/square()/' hello.c > vide.cAffiché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
gcc -c vide.cAffiché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
sed 's/is %d/is %s/' hello.c > format.cAffiché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
gcc -c format.cAffiché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à ?
ls format.oAffiché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
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
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.