95 votes

Quels types de modèles pourrais-je imposer sur le code pour le rendre plus facile à traduire dans un autre langage de programmation?

Je me lance dans un projet secondaire dont le but est de traduire du code d'un langage de programmation à un autre. Les langages avec lesquels je commence sont le PHP et le Python (passer de Python à PHP devrait être plus facile pour commencer), mais idéalement j'aimerais pouvoir ajouter d'autres langages avec (relativement) facilité. Le plan est le suivant:

  • Ceci est orienté vers le développement web. Le code original et cible reposera sur des frameworks (que je devrai également écrire). Ces frameworks adopteront un design pattern MVC et suivront des conventions de codage strictes. Cela devrait rendre la traduction quelque peu plus facile.

  • Je m'intéresse également à l'IOC et à l'injection de dépendances, car cela pourrait rendre le processus de traduction plus facile et moins sujet aux erreurs.

  • Je vais utiliser le module parser de Python, qui me permettra de manipuler l'Arbre de Syntaxe Abstraite. Apparemment, la méthode la plus proche que je peux obtenir avec PHP est token_get_all(), ce qui est un bon début.

  • À partir de là, je pourrai construire l'AST, les tables de symboles et le flux de contrôle.

Ensuite, je crois que je pourrai commencer à produire du code. Je n'ai pas besoin d'une traduction parfaite. Je devrai quand même passer en revue le code généré et corriger les problèmes. Idéalement, le traducteur devrait signaler les traductions problématiques.

Avant que vous demandiez "Quel est l'intérêt de tout ça ?" La réponse est... Ce sera une expérience d'apprentissage intéressante. Si vous avez des idées sur la manière de rendre cela moins intimidant, veuillez me le faire savoir.


EDIT:

Je suis plus intéressé par le fait de savoir quels types de modèles je pourrais imposer sur le code pour le rendre plus facile à traduire (par exemple : IoC, SOA ?) que par la manière de faire la traduction.

120voto

Ira Baxter Points 48153

J'ai été en train de construire des outils (DMS Software Reengineering Toolkit) pour manipuler des programmes à usage général (la traduction de langage étant un cas spécial) depuis 1995, soutenu par une solide équipe de scientifiques informatiques. DMS fournit une analyse générique du parsing, construction d'AST, tables de symboles, analyse de flux de contrôle et de données, application de règles de traduction, régénération de texte source avec des commentaires, etc., tous paramétrés par des définitions explicites de langages informatiques.

La quantité de machinerie dont vous avez besoin pour faire cela bien est immense (surtout si vous voulez être capable de le faire pour plusieurs langages de manière générale), et ensuite vous avez besoin de parseurs fiables pour des langages avec des définitions peu fiables (PHP est l'exemple parfait de ceci).

Il n'y a rien de mal à penser à construire un traducteur de langage à langage ou à essayer, mais je pense que vous trouverez que c'est une tâche beaucoup plus grande pour des langages réels que vous ne le pensez. Nous avons investi environ 100 années-hommes uniquement dans DMS, et encore 6-12 mois dans chaque définition de langage "fiable" (y compris celle que nous avons douloureusement construite pour PHP), beaucoup plus pour des langages difficiles comme le C++. Ce sera une "expérience d'apprentissage infernale"; ça l'a été pour nous. (Vous trouverez peut-être la section Papers techniques sur le site Web mentionné ci-dessus intéressante pour démarrer rapidement cet apprentissage).

Beaucoup de gens tentent souvent de construire une sorte de machinerie généralisée en commençant par une technologie avec laquelle ils sont familiers, qui fait une partie du travail. (Les AST de Python sont un excellent exemple). La bonne nouvelle, c'est que cette partie du travail est faite. La mauvaise nouvelle, c'est que cette machinerie a des milliers d'hypothèses intégrées, dont la plupart vous ne découvrirez que lorsque vous essaierez de la forcer à faire autre chose. À ce moment-là, vous découvrirez que la machinerie est câblée pour faire ce qu'elle fait à l'origine, et résistera vraiment à votre tentative de la faire faire autre chose. (Je soupçonne qu'essayer de faire en sorte que l'AST de Python modèle PHP sera très amusant).

La raison pour laquelle j'ai commencé à construire DMS à l'origine était de construire des fondations qui avaient très peu de telles hypothèses intégrées. Elle en a certaines qui nous donnent des maux de tête. Jusqu'à présent, pas de trous noirs. (La partie la plus difficile de mon travail ces 15 dernières années est d'essayer d'empêcher de telles hypothèses de s'introduire).

Beaucoup de gens font également l'erreur de penser que s'ils peuvent parser (et peut-être obtenir un AST), ils sont bien avancés pour faire quelque chose de compliqué. L'une des leçons difficiles est que vous avez besoin de tables de symboles et d'analyses de flux pour faire une bonne analyse ou transformation de programmes. Les AST sont nécessaires mais pas suffisants. C'est la raison pour laquelle le livre sur les compilateurs d'Aho&Ullman ne s'arrête pas au chapitre 2. (Le PO a raison de prévoir de construire une machinerie supplémentaire au-delà de l'AST). Pour en savoir plus sur ce sujet, consultez Life After Parsing.

La remarque sur "je n'ai pas besoin d'une traduction parfaite" pose problème. Ce que les traducteurs faibles font, c'est convertir les 80% "faciles" du code, laissant les 20% difficiles à faire manuellement. Si l'application que vous envisagez de convertir est assez petite, et que vous n'envisagez de la convertir qu'une fois correctement, alors ce 20% est correct. Si vous souhaitez convertir de nombreuses applications (ou même la même avec des modifications mineures dans le temps), ce n'est pas bien. Si vous essayez de convertir 100K lignes de code source, alors 20% équivaut à 20 000 lignes de code originales difficiles à traduire, comprendre et modifier dans le contexte d'autres 80 000 lignes de programme traduit que vous ne comprenez déjà pas. Cela nécessite un énorme effort. Au niveau du million de lignes, cela est tout simplement impossible en pratique. (Étonnamment, il y a des gens qui se méfient des outils automatisés et insistent pour traduire des systèmes à un million de lignes manuellement; c'est encore plus difficile et ils découvrent généralement cette difficulté avec de longs retards, des coûts élevés et souvent un échec total).

Ce que vous devez viser pour traduire des systèmes à grande échelle est des taux de conversion proches de 99%, sinon il est probable que vous ne pourrez pas terminer la partie manuelle de l'activité de traduction.

Une autre considération clé est la taille du code à traduire. Il faut beaucoup d'énergie pour construire un traducteur fonctionnel et robuste, même avec de bons outils. Bien que cela puisse sembler sexy et cool de construire un traducteur au lieu de simplement faire une conversion manuelle, pour de petits codes (par exemple, jusqu'à environ 100K lignes de code source à notre expérience), l'économie ne justifie tout simplement pas cela. Personne n'aime cette réponse, mais si vous devez vraiment traduire seulement 10K lignes de code source, vous êtes probablement mieux de serrer les dents et de le faire. Et oui, c'est douloureux.

Je considère nos outils comme extrêmement bons (mais bon, je suis assez partial). Et il est encore très difficile de construire un bon traducteur; il nous faut environ 1,5 à 2 années-hommes et nous savons comment utiliser nos outils. La différence est qu'avec autant de machinerie, nous réussissons considérablement plus souvent que nous échouons.

13voto

Eli Bendersky Points 82298

Ma réponse portera sur la tâche spécifique d'analyse syntaxique de Python afin de le traduire dans une autre langue, et non sur les aspects de plus haut niveau que Ira a bien abordés dans sa réponse.

En bref: ne pas utiliser le module analyseur, il y a une façon plus facile.

Le module ast, disponible depuis Python 2.6, est bien plus adapté à vos besoins car il vous donne un AST prêt à l'emploi. J'ai écrit un article à ce sujet l'année dernière, mais en résumé, utilisez la méthode parse de ast pour analyser le code source Python en un AST. Le module parser vous donnera un arbre d'analyse, pas un AST. Soyez conscient de la différence.

Maintenant, étant donné que les AST de Python sont assez détaillés, une fois que vous avez un AST le travail n'est pas très difficile côté front-end. Je suppose que vous pouvez avoir rapidement un prototype simple pour certaines parties de la fonctionnalité prêt. Cependant, parvenir à une solution complète prendra plus de temps, principalement parce que les sémantiques des langages sont différentes. Un sous-ensemble simple du langage (fonctions, types de base, etc.) peut être facilement traduit, mais une fois que vous arrivez aux couches plus complexes, vous aurez besoin d'une machinerie lourde pour émuler le cœur d'un langage dans un autre. Par exemple, considérez les générateurs et les compréhensions de listes de Python qui n'existent pas en PHP (à ma connaissance, qui est avouons-le pauvre en ce qui concerne PHP).

Pour vous donner un dernier conseil, envisagez l'outil 2to3 créé par les développeurs Python pour traduire le code Python 2 en code Python 3. Du côté front-end, il a la plupart des éléments dont vous avez besoin pour traduire Python en quelque chose. Cependant, étant donné que les cœurs de Python 2 et 3 sont similaires, aucune machinerie d'émulation n'est nécessaire ici.

5voto

Wayne Werner Points 10172

Rédiger un traducteur n'est pas impossible, surtout si l'on considère que le stagiaire de Joel l'a fait pendant l'été.

Si vous voulez en faire un pour une seule langue, c'est facile. Si vous en voulez pour plusieurs langues, c'est un peu plus difficile, mais pas trop. La partie la plus difficile est que, bien qu'un langage complet de Turing puisse faire ce que fait un autre langage complet de Turing, les types de données intégrés peuvent changer radicalement ce que fait un langage.

Par exemple :

word = 'Ceci n'est pas un mot'
print word[::-2]

prendrait beaucoup de code C++ pour être dupliqué (ok, vous pouvez le faire assez rapidement avec certaines constructions de boucles, mais quand même).

C'est un peu une parenthèse, je suppose.

Avez-vous déjà écrit un analyseur syntaxique basé sur une grammaire de langage ? Vous voudrez probablement apprendre à le faire si vous ne l'avez pas déjà fait, car c'est la partie principale de ce projet. Ce que je ferais serait de concevoir une syntaxe basique complète de Turing, quelque chose de assez similaire à Python bytecode. Ensuite, vous créez un analyseur lexical/syntaxique qui prend une grammaire de langage (peut-être en utilisant BNF), et en fonction de la grammaire, compile le langage en votre langage intermédiaire. Ensuite, ce que vous voudrez faire, c'est le contraire - créer un analyseur de votre langage vers des langages cibles basés sur la grammaire.

Le problème le plus évident que je vois est qu'au début, vous créerez probablement du code horriblement inefficace, surtout dans des langages plus puissants* comme Python.

Mais si vous le faites de cette manière, vous pourrez probablement trouver des moyens d'optimiser la sortie au fur et à mesure. Pour résumer :

  • lire la grammaire fournie
  • compiler le programme en syntaxe intermédiaire (mais aussi complète de Turing)
  • compiler le programme intermédiaire en langage final (basé sur la grammaire fournie)
  • ...?
  • Profit!(?)

*par puissant je veux dire que cela prend 4 lignes :

myinput = raw_input("Entrez quelque chose : ")
print myinput.replace('a', 'A')
print sum(ord(c) for c in myinput)
print myinput[::-1]

Montrez-moi un autre langage qui peut faire quelque chose comme ça en 4 lignes, et je vous montrerai un langage aussi puissant que Python.

3voto

Ian Points 2104

Il y a quelques réponses vous disant de ne pas vous embêter. Eh bien, c'est utile comme réponse, n'est-ce pas? Vous voulez apprendre? Vous pouvez apprendre. C'est une compilation. Il se trouve simplement que votre langage cible n'est pas du code machine, mais un autre langage de haut niveau. Cela se fait tout le temps.

Il y a un moyen relativement facile de commencer. Tout d'abord, allez chercher http://sourceforge.net/projects/lime-php/ (si vous voulez travailler en PHP) ou quelque chose du genre et passez en revue le code d'exemple. Ensuite, vous pouvez écrire un analyseur lexical en utilisant une séquence d'expressions régulières et alimenter des jetons dans le parseur que vous générez. Vos actions sémantiques peuvent soit produire du code directement dans un autre langage, soit construire une structure de données (pensez aux objets, mec) que vous pouvez manipuler et parcourir pour générer du code de sortie.

Vous avez de la chance avec PHP et Python car à bien des égards, ce sont le même langage mais avec une syntaxe différente. La partie difficile est de surmonter les différences sémantiques entre les formes grammaticales et les structures de données. Par exemple, Python a des listes et des dictionnaires, tandis que PHP n'a que des tableaux associatifs.

L'approche du "débutant" est de construire quelque chose qui fonctionne bien pour un sous-ensemble restreint du langage (tel que des déclarations d'impression simples, des calculs simples et des affectations de variables), puis de supprimer progressivement les limitations. C'est essentiellement ce que tous les "grands" de ce domaine ont fait.

Oh, et comme vous n'avez pas de types statiques en Python, il est peut-être préférable d'écrire et de compter sur des fonctions PHP comme "python_add" qui ajoutent des nombres, des chaînes ou des objets selon la manière dont Python le fait.

Évidemment, cela peut devenir beaucoup plus gros si vous le permettez.

0voto

ptomato Points 24461

Vous pourriez jeter un coup d'œil au compilateur Vala, qui traduit Vala (un langage similaire à C#) en C.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X