S01E10 — 07-08-2024.
La tuyauterie d’un compilateur.
jour 10.
Appelé la carte ou le tuyau, ce concept définit l’ensemble des phases qu’un compilateur va exécuter. Et cela va dépendre de votre objectif, mais aussi de vos connaissances techniques pour être capable de réaliser chacune d’entre elles.
Généralement, il y a un découpage qui est fait en trois parties distinctes :
front-end— ça englobetokenizer,parseretanalyzer.middle-end— ça concerne l’optimisation du code.back-end— ça gère la génération du code.
Maintenant, on comprend qu’un compilateur n’est qu’un traducteur qui va effectuer une série de transformation pour viser un langage cible. Je prends le langage A et le transforme en langage B. Pour y parvenir, il faut s’imaginer le compilateur comme une route de voyage. Si je veux faire un Paris-Vienne, cela va se faire en plusieurs étapes. Je vais conduire un certain nombre d’heure, me reposer, vérifier que tout est okay avant de repartir puis je répète cela, jusqu’à arriver à Vienne.
Dans l’écriture d’un compilateur c’est la même chose. Il y a des airs de repos qu’on peut utiliser, je m’explique — je souhaite écrire un compilateur qui compile mon langage vers le code machine en me générant un executable spécifique à chaque plateformes (Linux, MacOs, Windows). C’est un chemin très long, si je veux y aller d’une traite, je peux me décourager face aux innombrables difficultés que je vais rencontrer. D’où, l’idée d’y aller étape par étape. D’abord, je vais jusqu’à l’interpréteur — à cette étape, je peux vérifier que mon langage a bien le bon comportement. De plus, je vais avoir plusieurs possibilités — transpiler mon ast vers un langage de mon choix, rajouter un système de type, effectuer des optimisations, créer une machine virtuelle ou encore compiler vers le code machine.
De un, j’ai déjà un prototype valide et de deux, je reste motivé. C’est très important la motivation, avancer même si c’est peu, c’est déjà mieux que de ne rien faire.
Ma tuyauterie ressemble à ça :
```zo
fun main() {
println("👋 🌍 👽");
}
```
pathname/dirname
|
↓
╭-----------╮
╭---------------→| reader |←---------------╮
| ╰-----------╯ |
| | |
| bytes |
| ↓ |
| ╭-----------╮ |
|---------------→| tokenizer |←---------------|
| ╰-----------╯ |
| | |
| tokens |
| ↓ |
| ╭-----------╮ |
|---------------→| parser |←---------------|
| ╰-----------╯ |
╭----------╮ | ╭----------╮
| interner | ast | reporter |------------------╮
╰----------╯ ↓ ╰----------╯ ↓
| ╭-----------╮ | ╭-------------╮
|---------------→| analyzer |←---------------|---------------→| interpreter |
| ╰-----------╯ | ╰-------------╯
| | | |
| ast typed | value
| ↓ | ↓
| ╭-----------╮ |
|---------------→| codegen |←---------------| `👋 🌍 👽`
| ╰-----------╯ |
| | |
| bytecode |
| ↓ |
| ╭-----------╮ |
╰---------------→| builder |←---------------╯
╰-----------╯
|
|
|
|
|
.exe --|-- py -------------→ ```py
| # -*- coding: utf-8 -*-
wat/wasm
| def main():
↓ print("👋 🌍 👽")
if __name__ == "__main__":
main()
```
Grosso modo hein ! Et tout n’est pas encore câblé. Je n’ai pas fait la liaison entre interner et interpreter. Ce qu’il faut comprendre c’est que interner et reporter sont en général toujours transmis à chaque phase du compilateur. C’est modulable, c’est-à-dire que je pourrai rajouter optimizer plus tard lorsque j’aurai plus de billes, à part la simplification de sous-expressions constantes. Je n’ai pas la connaissance pour faire quelque chose de pertinent. Tain, je me rends compte qu’il y a tellement de boulot à faire. Ça me rend déjà fou rien que d’y penser.
Presque une semaine que je n’ai pas discuté avec un humain ou vu la lumière du jour. Bah oui, il faut savoir ce qu’on veut dans la vie. Sociabilisé ou coder son propre turfu ? Faites vos jeux.