Quel est le mot-clé le plus courant dans la librairie standard Go ?
Dec 5, 2017 06:49 · 892 mots · 5 minutes de lecture
Ceci est une traduction du billet sur Medium de Francesc.
Ce billet est la transcription du dernier épisode de justforfunc titré «What’s the most common identifier in Go’s stdlib?». Le code pour le programme se trouve ici, dans le dépôt de justforfunc.
Si vous préférez regarder une vidéo à lire un article ;)
Le problème
Imaginez avoir le programme suivant et que vous souhaitiez en extraire tous les mots-clés.
Nous devons obtenir une liste contenant main
, fmt
et Println
.
Qu’est-ce qu’un mot-clé ?
Pour répondre à cette question il faut plonger un peu dans la théorie des langages. Juste un peu, pas d’inquiétude.
Les langages de programmation sont entre autres définis pas une série de règles qui définissent un programme valide. Ces règles ressemblent à ceci:
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" (
IfStmt | Block ) ] .
Cette règle nous indique ce à quoi l’instruction if
ressemble en Go. Les parties "if"
, ";"
, et "else"
sont les mots-clés de la règles qui nous aide à comprendre la structure du programme, alors que ExpressionBlock
, SimpleStmt
, etc sont d’autres règles.
L’ensemble de ces règles est appelé la grammaire du langage. Vous pouvez trouver l’ensemble dans la spécification du langage Go.
Ces règles ne sont pas définies pour les caractères présents dans le programme, mais sur des lexèmes (tokens en anglais). Ceux-ci sont atomiques comme if
ou else
, mais peuvent aussi être de type complexe comme les nombres entiers 42
, les nombres flottants 4.2
, les chaînes de caractères "hello"
, ou… les mots-clés tels que main
.
Comment sait-on que main
est un mot-clé et non un nombre ? Et bien il y a aussi des règles pour ça. En lisant la partie identifiers de la spécification du langage, vous trouverez cette règle:
identifier = letter { letter | unicode_digit } .
Dans cette règle, letter
et unicode_digit
ne représentent pas des lexèmes; ils sont une classe de caractères. Donc étant donné l’ensemble de ces règles, il devient presque simple d’écrire un programme qui va lire caractère par caractère et qui «émet» un lexème lorsqu’il détecte un groupe de caractères qui correspond à une règle.
Si nous commençons avec : fmt.Println
ça doit générer les lexèmes : fmt
en tant que mot-clé, .
, et Println
en mot-clé. Est-ce un appel de fonction ? À ce point nous ne pouvons pas le savoir, et ce n’est pas important. La seule structure est la séquence qui nous laisse découvrir l’ordre dans lequel les choses apparaissent.
Ce type de programme qui donne une séquence de lexèmes à partir d’une séquence de caractères est appelé un scanner. La librairie standard de Go fournit un scanner pour les programmes Go dans go/scanner
. Les types de lexèmes qu’il génère sont définis dans go/token
.
Utiliser go/scanner
Ok, on sait ce qu’est un scanner. Comment l’utilise-t’on ?
Lire les arguments depuis la ligne de commande
Commençons par un petit programme qui affiche simplement tous les arguments passés lorsqu’on l’exécute. Ce sera notre point de départ.
(Afficher tous les arguments de la ligne de commande)
Ensuite, nous devons scanner tous les fichiers passés en argument. Pour cela nous devons créer un nouveau scanner.Scanner
et l’initialiser avec le contenu du fichier.
Afficher chaque lexème
Avant de pouvoir appeler la méthode Init
du scanner.Scanner
nous allons lire le contenu du fichier et créer un token.FileSet
avec un token.File
par fichier que nous scannons.
Une fois le scanner initialisé nous pouvons appeler Scan
et afficher le lexème obtenu. Quand la fin du fichier scanné est atteinte, nous obtiendrons un lexème de fin de fichier EOF
(End Of File).
Compter les lexèmes
Super, nous pouvons afficher tous les tokens, mais nous avons besoin de garder une trace afin de savoir combien de fois nous trouvons chacun d’eux, pour les trier par occurence et afficher les 5 plus courants.
En Go, la meilleure façon de faire est d’utiliser une map dont la clé est le mot-clé et la valeur est le nombre d’occurences.
À chaque fois que l’on rencontre un mot-clé, nous devons incrémenter son compteur. À la fin, nous convertissons la map en une slice, que nous pouvons trier et afficher.
Certaines parties du code ont été retirées pour plus de clarté, le code complet se trouve ici, dans le dépôt justforfunc
Alors, quel est le mot-clé le plus courant ?
Lançons le programme en utilisans les contenus de github.com/golang/go
.
$ go install github.com/campoy/justforfunc/24-ast/scanner
$ scanner ~/go/src/**/*.go
82163 v
46584 err
44681 Args
43371 t
37717 x
Le mot-clé le plus courant est v
, tu parles de mots-clés courts ! Nous allons compter uniquement les mots-clés ayant au moins trois caractères, en modifiant légèrement le code:
for s, n := range counts {
if len(s) >= 3 {
pairs = append(pairs, pair{s, n})
}
}
Et relançons notre programme:
$ go install github.com/campoy/justforfunc/24-ast/scanner
$ scanner ~/go/src/**/*.go
46584 err
44681 Args
36738 nil
25761 true
21723 AddArg
Rien de surprenant ici, err
et nil
sont présents dans quasiment tous les programmes qui contient if err != nil
. Et pour Args
?
Ce sera le sujet d’un futur épisode.
Remerciements
Si vous avez apprécié cet épisode, n’oubliez pas de souscrire à justforfunc ! Aussi, vous pouvez soutenir la série sur patreon.
Merci à Francesc de nous avoir autorisé à traduire son article, sa chaîne vient de passer les 10 000 abonnés, bravo à lui !