Dix-huit caractères, cinq mots
Le script de soldes d’une boutique en ligne contient la ligne remise = prix / 10. Vous y lisez cinq mots. Le compilateur, lui, reçoit dix-huit caractères, espaces comprises.
Avant de vérifier la grammaire, il faut regrouper ces caractères en mots et jeter les espaces. Cette partie du compilateur est petite et rapide. Elle est aussi facile à rater de façon discrète.
À la fin de cette leçon
Remarque
Je peux transformer un texte source en jetons.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Jeton | un mot du programme, avec sa nature | NOMBRE 12 |
| Analyseur lexical | la partie du compilateur qui fabrique les jetons | |
| Motif | une règle qui décrit une nature de jeton | [0-9]+ |
| Plus long jeton | prendre autant de caractères que le motif le permet | |
| Mot réservé | un mot que le langage garde pour lui | if |
| Générateur d’analyseur | un outil qui écrit l’analyseur à partir de motifs | flex |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Un jeton, c’est une nature et un texte
L’analyseur lexical est la première partie du compilateur proprement dit. Il lit les caractères de gauche à droite et rend des jetons.
Chaque jeton a une nature, comme NOMBRE ou NOM, et le texte dont il vient. Les espaces et les commentaires ne donnent aucun jeton. Ils marquent seulement où un jeton finit et où le suivant commence.
Exemple travaillé : remise = prix / 10
| Caractères | Nature | Texte |
|---|---|---|
| r e m i s e | NOM | remise |
| = | SIGNE | = |
| p r i x | NOM | prix |
| / | SIGNE | / |
| 1 0 | NOMBRE | 10 |
| Les quatre espaces | Aucun jeton | Ignorées |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Un petit analyseur à lancer
# Un petit analyseur : des nombres et quatre signes.
texte = "12 + 30*2"
jetons = []
i = 0
while i < len(texte):
car = texte[i]
if car == " ":
i = i + 1
elif car.isdigit():
debut = i
# On avance tant qu'il y a des chiffres : le plus long possible.
while i < len(texte) and texte[i].isdigit():
i = i + 1
jetons.append(["NOMBRE", texte[debut:i]])
elif car in "+-*/":
jetons.append(["SIGNE", car])
i = i + 1
else:
jetons.append(["ERREUR", car])
i = i + 1
print(jetons)
# Remplacez le texte par "7 % 20", puis relancez.
flex écrit l’analyseur à votre place
Écrire à la main l’analyseur d’un vrai langage est long. Un générateur d’analyseur comme flex l’écrit à partir d’une liste de motifs.
Dans calc.l, chaque règle associe un motif à une action. [0-9]+ veut dire un chiffre ou plus. Son action transforme le texte en nombre et rend le jeton NUMBER à l’analyseur syntaxique. Les Runs lisent les règles, puis reconstruisent la calculatrice depuis zéro.
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.
Les règles qui rendent un jeton
grep -n "return" calc.lAffiché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.
Combien de lignes dans calc.l ?
grep -c "" calc.lAffiché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.
Effacer ce que make a construit
make cleanAffiché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.
Reconstruire la calculatrice
makeAffiché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.
Et combien dans ce que flex écrit ?
wc -l lex.yy.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.
Ce que l’analyseur connaît, et le reste
Chaque Run ci-dessous envoie une ligne à la calculatrice. Notez quels messages viennent de l’analyseur lexical et lesquels de la grammaire.
La dernière règle de calc.l, un simple point, attrape tout caractère que les autres ont laissé. Elle écrit unexpected character et ne rend aucun jeton. La grammaire reçoit ensuite ce qui reste.
Aucune espace
echo "8*5" | ./calcAffiché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.
Beaucoup trop d’espaces
echo " 4 + 4 " | ./calcAffiché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 caractère inconnu
echo "6 ? 2" | ./calcAffiché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 lettre collée à un nombre
echo "9 + 1a" | ./calcAffiché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.
Des zéros devant
echo "0012 + 3" | ./calcAffiché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 virgule décimale
echo "3,5 + 1" | ./calcAffiché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’un analyseur rend un jeton par caractère, donc que 0012 fait quatre nombres. L’analyseur prend le plus long jeton : il continue tant que le motif convient. 0012 est donc un seul NOMBRE, et site un seul NOM, pas le mot réservé si suivi de te.
Pour aller plus loin
Étendez votre analyseur aux signes de deux caractères <=, >= et ==. Chacun doit donner un seul jeton SIGNE. Seuls, <, > et = restent comme avant.
Écrivez d’abord trois tests à vous. Expliquez ensuite, avec l’idée du plus long jeton, pourquoi a<=b ne doit pas donner < puis =.