Brainfuck et Masturbation Intellectuelle !

by dinosaure

Il est là le plus dur, mais le plus passionnant, le Brainfuck. Écrire un programme en Brainfuck, c’est plus difficile je pense qu’écrire un programme en Assembleur quoique la comparaison ne devrait pas ce faire puisque je n’ai jamais programmer en Assembleur (trop dépendant de l’architecture du processeur). Néanmoins, programmer en Brainfuck, c’est tout de même difficile. Les notions à apprendre sont simple, il y 8 opérateurs, pas très compliqué à retenir. Mais quant on sait que la notion de condition n’y est pas nativement, on ce retrouve, pas restreint dans les possibilités du langages (puisqu’il est Turing-complet quand même) mais on ce retrouve à devoir taper un nombre incalculable de caractère pour au final faire peu de chose.

Là où le Brainfuck est réellement intéressant, c’est justement qu’il est Turing-complet et que théoriquement, il est capable de faire tout les programmes possibles et inimaginable. Après, c’est à savoir si il est humain de programmer avec car quand on regarde les opérateurs … C’est moche, affreux, etc … D’où le nom de Brainfuck. Alors programmer avec, non. Cependant, il existe un exercice très simple en lien avec le Brainfuck: un compilateur !

La compilation, pour les langages comme le C ou le C++, c’est une affaire d’ingénieur très compétent car il existe encore des zones obscures quant il s’agit de l’optimisation. Mais Brainfuck est un langage pas très compliqué à prendre en main et de ce fait, il est pas très compliqué de faire un compilateur de Branfuck. Si on ce réfère correctement à ce que nous dit Wikipédia et aux différents opérateurs (Wikipédia donne même une analogie en C donc bon), on sait immédiatement qu’au final, notre compilateur ne tiendra que par une suite de if et else if ou d’un switch ... case pour les plus propres. C’est mon cas. Et voici donc mon super compilateur Brainfuck :

#include <iostream>
#include <fstream>
#include <sstream>
#include <stack>

using namespace std;

int main(int argc, char* argv[]) {
    if(argc == 2) {
        ifstream        file(argv[1]);
        string          buffer;
        string          f;
        int             l = 0;

        while(getline(file, buffer)) {
            if(l != 0)
                f += buffer + "\n";

            ++l;
        }

        unsigned char   b[1024] = {0};
        char*           k;
        unsigned char*  x = b;
        stack<char*>    y;

        k = const_cast<char*>(f.c_str());

        while(*k) {
            switch(*k)
            {
                case '+': ++*x;
                    break;
                case '-': --*x;
                    break;
                case '>': ++x;
                    break;
                case '<': --x;
                    break;
                case ',': *x = cin.get();
                    break;
                case '.': cout << *x;
                    break;
                case '[': y.push(k + 1);
                    break;
                case ']':
                    if(*x) {
                        k = y.top();
                        continue;
                    } else
                        y.pop();
                    break;
           }

           cout.flush();
           ++k;
        }
    }

    return 0;
}

Bon là, il s’agit seulement de prendre ce que nous dit Wikipédia, hein … Mais, ici, il y a quelque chose qui change. En effet, si vous mettez ce programme dans votre /usr/local/bin (votre petit bac à sable de vos programmes) et que vous créez un fichier du genre:

#!/usr/local/bin/brainfuck

++++++++++
[
    >+++++++>++++++++++>+++>+<<<<-
]
>++.
>+.
+++++++.
.
+++.
>++.
<<+++++++++++++++.
>.
+++.
------.
--------.
>+.
>.

Un coup de chmod +x mon_brainfuck.bf et ensuite ./mon_brainfuck.bf, Et voilà, un beau « Hello World! » ! En effet, mon programme n’est pas réellement un compilateur comme on pourrait l’entendre mais un interpréteur de fichier Brainfuck (extension *.bf steuplé). Bon, après, je pense que ceci est spécifique à un environnement type UNIX mais voilà un programme qui n’a aucun intérêt à être utilisé mais qui est quand même ludique pour ce qui est du fonctionnement du langage Brainfuck. Le fonctionnement d’un compilateur tel que le g++ est un peu plus complexe que cela à vrai dire !

Notez tout de même le poids monstrueux de mon programme (32 Kio) mais je pense que c’est dû aux include … Enfin après, j’ai pas chercher non plus à faire la course aux poids (le compilateur actuel du créateur du Brainfuck fait 171 octets). Donc si vous voulez vous amuser à faire un compilateur je vous suggère celui-ci, c’est simple, rapide et pas pratique !