Dans ce dépot, il y a un interpréteur de brainfuck, ainsi qu'un compilateur depuis un langage minimal vers du brainfuck
L'interpréteur
---------------
Vous pouvez utiliser l'interpréteur de plusieurs manière :
* ``brainfuck.py FILE`` va vous permettre d'exécuter le code contenu dans le fichier spécifié.
* ``brainfuck.py -i CODE`` vous permet d'exécuter le code passé directement en argument
exemple : ``brainfuck.py -i ">+++++++++++++++++++++++++++++++++++++."`` va afficher ``%`` et quitter
* ``brainfuck.py`` : si vous appelez le programme sans argument, il va lancer une session interactive
### Le brainfuck
Le brainfuck est un langage ésotérique créé en 1993 par Urban Müller, qui ne s'écrit qu'avec 8 caractères.
Pour plus d'informations, veuillez consultez [wikipédia](https://fr.wikipedia.org/wiki/Brainfuck), ou la page d'[esolang dédié](https://esolangs.org/wiki/brainfuck).
Il n'y pas de spécificatons officiel du brainfuck, mais cet interpréteur à une implémentation "[nice](http://www.muppetlabs.com/~breadbox/bf/standards.html)"
Cet interpréteur a plusieurs particularité, par rapport à d'autres implémentations du brainfuck :
- Le tableau est infini vers la droite, tenter d'aller avant la case 0 provoque un crash
- Les entiers utilisés sont des big-int : pas de limite supérieure, et donc pas d'overflow.
Par exemple, ``[+]``, contrairement à certaines implémentations, ne va pas remettre la case à 0, mais boucler indéfinimment.
- Les entiers ne peuvent pas être négatif : si un code tente de le faire, le programme va crasher.
- On peut utiliser ``#`` pour debug :
lorsque l'interpréteur exécutera cette instruction, il affichera l'état de la mémoire (avec l'emplacement du pointeur, et la valeur de la case pointée)
Pour affecter une valeur à une variable, c'est très simple : ``a = var``, où var est une expression.
#### Des structures de controle usuelles
Le If (avec ou sans else),
```C
if (condition) {
//code_block
} else {
//Code block
}
```
et le while :
```C
while (condition) {
//code_block
}
```
Il n'y a pour l'instant pas de commande pour faire des sauts (pas de break, etc.)
#### Les fonctions
vous pouvez déclarer des fonctions ainsi :
```C
def add(a,b) {
return a + b;
}
```
La fonction n'arrète pas son exécution au return automatiquement !!! Le return doit impérativement être la dernière instruction, et ne doit pas être dans un block.
Par exemple, la fonction suivante est invalide :
```C
def est_pair(a) {
if (a%2 == 0) {
return 1;
} else {
return 0;
}
}
```
mais la fonction
```C
def est_pair(a) {
var res;
if (a%2 == 0) {
res = 1;
} else {
res = 0;
}
return res;
}
```
est valide. (Dans ce cas, on aurait juste pu mettre ``return a%2 == 0;``)
Pour appeler une fonction, il vous suffit d'écrire ``f(x)`` . Si vous voulez appeler la fonction est_pair, vous pourrez par exemple écrire :
```C
if (est_pair(a)) {
//Do something
}
```
**Attention :** Appeler une fonction avec un nombre d'argument différend de celui utilisé dans la déclaration est *undefined behavior*.
Il n'y a pas de concept de variables globales : on ne peut utiliser que des variables locales, dans la fonction.
Il est possible (bien qu'inutile) de déclarer une fonction dans une fonction. La seule différence est qu'elle ne peut pas être appelé depuis l'extérieur.
Ex :
```C
def a() {
def b() {
c(); //Valide
}
c(); //Valide
}
def c() {
//Do something
}
def d() {
c(); //Valide
a(); //Valide
b(); //Non valide
}
```
**Attention** : Aucune récursivité n'est possible !!! Cela fera tourner indéfiniment le compilateur.
#### Les fonctions en brainfuck :
Vous pouvez également inclure directement du brainfuck :
```
bf add {{ //2
[-<+>]<
}}
```
Lors de l'appel d'une fonction brainfuck, tout les arguments sont mis dans l'orde d'appel dans le tableau, et le pointeur pointe sur le dernier élément. La fonction doit laisser derrière elle que des cases vides, et la première case (ou il y avait le premier argument) est la valeur de retour.
Il est donc essentiel d'appeler la fonction brainfuck avec le bon nombre d'argument.
#### Opérateurs utilisables :
Actuellement, on peut utiliser les opérateurs suivants (rappel : il n'y a qu'un seul type, l'entier).
- ``a + b`` : somme de a et b
- ``a - b`` : différence de a et de b. Attention : si b > a, le programme crash.
- ``a * b`` : produit de a et de b
- ``a / b`` : quotient de a et de b (division entière bien sur)
- ``a % b`` : reste de la division euclidienne de a par b
- ``a == b`` : vaut 1 si a = b, 0 sinon
- On peut aussi utiliser ``a != b``, ``a > b``, ``a >= b``, ``a <b``,et``a<=b``
Pour l'instant, il n'y a pas d'opérateur de logique booléenne (``&&``, ``||``), ni d'opérateur comme ``&``, ...
#### Les import
Vous pouvez écrire une déclaration d'import ainsi : ``import "my_file.mg"``, avec my_file.mg le chemin vers le fichier en question.
Vous pouvez également mettre un chemin absolu.
Un import fonctionne de manière simple : il simule un copier-coller du fichier importé dans le fichier qui fait l'appel
#### La stdlib
Le compilateur va avec une librairie standard. Pour l'utiliser, il faut bien penser à écrire ``import "/path/to/stdlib.mg"`` dans votre fichier.
la librairie standard comporte pour l'instanc seulement 4 fonctions :
- La fonction ``putc(val)``. Elle affiche le caractère représentée par la valeur de val.
- La fonction ``scanc()``. Elle récupère un caractère depuis l'entrée standard.
- La fonction ``debug()``. Elle affiche les informations de debug. (équivalent à mettre ``#`` dans le brainfuck).
Cette instruction ne fonctionnera que si l'implémentation du brainfuck comprend le ``#``.
- La fonction ``print_int(val)``. Cette fonction va afficher la représentation décimal du nombre passé en argument.
Utilisation
--------
Pour utiliser ce programme, il vous faudra une version suffisemment récente de python. Ce programme n'a été testé que sur python 3.7 et 3.8, mais devrait fonctionner pour quelques version précédentes, et pour les suivantes.
La seule dépendance est le module ``termcolor``, qui sert à afficher certains messages en couleur.
Pour l'installer : ``pip3 install termcolor``, ou ``py -m pip install termcolor`` sur Windows.