BFPY: Transpilateur Python vers Brainfuck

… parce que c'est les vacances

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

BFPY

Récemment, il y a eu plusieurs sujets de création de langages de programmation (avec Acid et Seventh). Quand nohar a décidé de créer Pulp, un environnement d'exécution pour faciliter la compilation de nos langages, je me suis un peu penché sur le monde de la compilation et de l'informatique bas niveau. D'ordinaire, je suis plutôt tourné vers le haut niveau, mais étonnamment cela m'a beaucoup intéressé. Du coup depuis quelques semaines je joue avec le bytecode de python, j'essaye d'écrire des programmes de différents paradigmes en bytecode pour trouver le meilleur jeu d'instruction, etc…

Et puis, dans le sujet de Pulp, quelqu'un a parlé de Brainfuck, et je me suis dit qu'il ferait une bonne VM (pas vraiment performant avec les 10 millions de + qu'il faut pour charger un seul int, mais c'est marrant). Du coup je me suis lancé dans la création d'un transpilateur Python vers Brainfuck.

Je procède très simplement: je désassemble la fonction que je veux transpiler, et je traduis chaque instruction en Brainfuck, en utilisant la mémoire comme une pile.

Exemple

Imaginons que je veuille transpiler une fonction foo définie par lambda x, y, z: x * 6 + y - z et l'appeler avec les arguments 8, 4 et 5 (pour obtenir 47 donc):

1
2
3
4
5
6
7
8
from bfpy import Bytecode, Machine

foo = lambda x, y, z: x * 6 + y - z
bf = Bytecode.from_function(foo, x=8, y=4, z=5)
print(bf)  # bytecode brainfuck obtenu
vm = Machine(bf)
vm.run()
print(vm.current)  # affiche l'élément en haut de la pile, ici 47

Ce code m'affiche ceci lorsque je l'exécute:

1
2
>++++++++>++++++[-<[>>+>+<<<-]>>>[<<<+>>>-]<<]<[-]>>[-<<+>>]<<>++++[<+>-]<>+++++[<->-]<
47

Ce qu'il reste à faire

  • Implémenter un système de type en mémoire, de sorte à ce que la taille d'un élément de la pile ne soit pas restreint à un octet, mais puisse s'étendre sur plusieurs (notamment pour les chaines de caractère).
  • Implémenter un environnement dans la mémoire BF et un algorithme qui trouve un endroit libre dans la mémoire pour stocker des objets Python (actuellement l'environnement est un dictionnaire à part entière).
  • Compléter la traduction des instructions du bytecode Python, car pour l'instant je n'implémente que le chargement de constantes et de variables, et les opérateurs arithmétiques.

Ça fait beaucoup de choses à faire pour un projet complètement inutile, mais comme je suis en vacances, j'en profite :P

Source

Vous pouvez télécharger BFPY (même si ça n'a pas (encore) beaucoup d'intérêt) ici.

Édité par felko

Anciennement AlphaZeta

+17 -0

Omg xD GG !

C'est toujours drôle quand y'a du brainfuck quelque part. Par contre je comprend jamais rien… Est-ce que tu as prévu une sorte d'article/tuto/information plus détaillé dessus ?

+3 -0
Auteur du sujet

Tu veux dire sur les codes Brainfuck en eux-mêmes ou sur le code en général ?

Je n'ai pas prévu mais c'est envisageable :)

Déjà je pense que si je commente mon code ça sera déjà un peu mieux. Je m'en charge tout à l'heure

Anciennement AlphaZeta

+0 -0
Auteur du sujet

Salut,

Je me suis remis à BFPY après une petite pause (quelques autres projets + vacances) et je suis toujours coincé à cette étape:

Implémenter un système de type en mémoire, de sorte à ce que la taille d'un élément de la pile ne soit pas restreint à un octet, mais puisse s'étendre sur plusieurs (notamment pour les chaines de caractère).

J'ai repensé à la façon dont les langages bas niveau comme C gèrent ce problème, mais cela implique de "demander" la valeur selon la position et le type. Or, en Python, étant un langage dynamiquement typé, je ne peux pas savoir à l'avance quel type "demander".

Du coup je suis bloqué, un coup de main serait la bienvenue :euh:

Merci d'avance,

AZ.

Édité par felko

Anciennement AlphaZeta

+3 -0

Peut être pourrais tu t'inspirer de la façon dont Python réserve réellement la mémoire ? Je ne sais pas comment ça se passe concrêtement mais est ce que réserver la mémoire au dernier moment ne suffirait pas ? Comme ça tu connais toutes les infos dont tu as besoin…

Je trouve ton projet intéressant et assez fun ! Bon Courage ! ;)

+1 -0
Auteur du sujet

Le souci c'est que si mes objets s'étendent sur plusieurs octets, je dois changer le sens des instructions < et >, pour que ça ajoute/enlève à l'addresse non pas de 1 mais de la taille de l'objet en cours/précédent. Je sais pas si je peux faire ça sans enlever un peu de l'intérêt de départ.

Qu'en pensez-vous ? Dois-je en rester au pur Brainfuck ou je peux un peu changer ?

EDIT: Ah mais nan c'est totalement con ce que je viens de dire, si je fais ça ça aura plus aucun sens de faire + ou - :euh:

Je dois donc en rester au pur Brainfuck, et trouver un moyen pour y "sérialiser" mes objets

Édité par felko

Anciennement AlphaZeta

+0 -0
Auteur du sujet

Salut,

Je viens de penser à une solution pour mon problème:

Si on ajoute deux autres instructions, genre, { et } qui déplacent le curseur à l'objet suivant ou précédent. Comme ça on garde < et > qui déplacent, eux, d'une case mémoire, et on de-sugar { et } en termes de déplacements de case mémoire grâce à un tableau qui recense les adresses de mes objets.

C'est dommage parce que c'est la rentrée, mais j'espère pouvoir y consacrer un peu de temps les fins de semaines.

felko

Anciennement AlphaZeta

+4 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte