1. Principes de base
Pour comprendre Brainfuck, vous devez imaginer un tableau infini de cellules initialisées par 0
chacun.
...[0][0][0][0][0]...
Quand le programme brainfuck démarre, il pointe vers n'importe quelle cellule.
...[0][0][*0*][0][0]...
Si vous déplacez le pointeur vers la droite >
vous déplacez le pointeur de la cellule X à la cellule X+1
...[0][0][0][*0*][0]...
Si vous augmentez la valeur de la cellule +
vous obtenez :
...[0][0][0][*1*][0]...
Si vous augmentez à nouveau la valeur de la cellule +
vous obtenez :
...[0][0][0][*2*][0]...
Si vous diminuez la valeur de la cellule -
vous obtenez :
...[0][0][0][*1*][0]...
Si vous déplacez le pointeur vers la gauche <
vous déplacez le pointeur de la cellule X à la cellule X-1
...[0][0][*0*][1][0]...
2. Entrée
Pour lire le caractère, vous utilisez la virgule ,
. Ce qu'il fait est : Lit le caractère depuis l'entrée standard et écrit son code ASCII décimal dans la cellule actuelle.
Jetez un coup d'œil à Table ASCII . Par exemple, le code décimal de !
es 33
alors que a
es 97
.
Imaginons que la mémoire de votre programme BF ressemble à ça :
...[0][0][*0*][0][0]...
En supposant que l'entrée standard représente a
si vous utilisez une virgule ,
l'opérateur, ce que BF fait, c'est lire a
code ASCII décimal 97
à la mémoire :
...[0][0][*97*][0][0]...
C'est ce que vous voulez généralement penser, mais la vérité est un peu plus complexe. La vérité est que BF ne lit pas un caractère mais un octet (quel que soit cet octet). Laissez-moi vous montrer un exemple :
Dans linux
$ printf ł
des empreintes :
ł
qui est un caractère polonais spécifique. Ce caractère n'est pas codé par l'encodage ASCII. Dans ce cas, il s'agit de l'encodage UTF-8, ce qui signifie qu'il prenait plus d'un octet dans la mémoire de l'ordinateur. Nous pouvons le prouver en faisant un dump hexadécimal :
$ printf ł | hd
qui montre :
00000000 c5 82 |..|
Les zéros sont décalés. 82
est le premier et c5
est le deuxième octet représentant ł
(dans l'ordre où nous allons les lire). |..|
est une représentation graphique qui n'est pas possible dans ce cas.
Eh bien, si vous passez ł
comme entrée de votre programme BF qui lit un seul octet, la mémoire du programme ressemblera à ceci :
...[0][0][*197*][0][0]...
Pourquoi 197
? Eh bien 197
décimal est c5
hexadécimal. Cela vous semble familier ? Bien sûr. C'est le premier octet de ł
!
3. Sortie
Pour imprimer un caractère, vous utilisez le point .
Ce qu'il fait : En supposant que nous traitions la valeur réelle de la cellule comme un code ASCII décimal, nous imprimons le caractère correspondant sur la sortie standard.
Imaginons que la mémoire de votre programme BF ressemble à ça :
...[0][0][*97*][0][0]...
Si vous utilisez l'opérateur point (.) maintenant, ce que BF fait est d'imprimer :
a
Parce que a
Le code décimal en ASCII est 97
.
Donc, par exemple, un programme BF comme celui-ci (97 plus 2 points) :
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..
Augmentera la valeur de la cellule vers laquelle il pointe jusqu'à 97 et l'imprimera 2 fois.
aa
4. Boucles
Dans la boucle BF, il y a une boucle de début [
et fin de la boucle ]
. Vous pouvez penser que c'est comme while en C/C++ où la condition est la valeur réelle de la cellule.
Jetez un coup d'œil au programme BF ci-dessous :
++[]
++
incrémente deux fois la valeur réelle de la cellule :
...[0][0][*2*][0][0]...
Et []
c'est comme while(2) {}
donc c'est une boucle infinie.
Disons que nous ne voulons pas que cette boucle soit infinie. Nous pouvons faire par exemple :
++[-]
Ainsi, à chaque fois qu'une boucle se déroule, elle décrémente la valeur réelle de la cellule. Une fois que la valeur réelle de la cellule est 0
la boucle se termine :
...[0][0][*2*][0][0]... loop starts
...[0][0][*1*][0][0]... after first iteration
...[0][0][*0*][0][0]... after second iteration (loop ends)
Considérons encore un autre exemple de boucle finie :
++[>]
Cet exemple montre qu'il n'est pas nécessaire de terminer la boucle sur la cellule où elle a commencé :
...[0][0][*2*][0][0]... loop starts
...[0][0][2][*0*][0]... after first iteration (loop ends)
Cependant, il est bon de terminer là où nous avons commencé. Pourquoi ? Parce que si la boucle se termine dans une autre cellule qu'elle a commencée, nous ne pouvons pas supposer où sera le pointeur de cellule. Pour être honnête, cette pratique rend le brainfuck moins brainfuck.