Un polyglotte est un programme qui peut être exécuté dans au moins deux langages de programmation différents.
Quels conseils généraux avez-vous pour faire des polyglottes ou pour choisir des langues faciles à écrire pour une tâche spécifique?
S'il vous plaît poster les conseils qui pourraient être appliqués dans la plupart des situations. C'est-à-dire qu'ils ne devraient pas fonctionner uniquement dans les polyglottes de deux langues spécifiques. (Vous pouvez simplement poster une réponse à une question polyglotte si vous avez une astuce trop spécifique.) Mais vous pouvez introduire des fonctionnalités d'une langue qui facilitent l'utilisation de plusieurs langues ou qui peuvent facilement être ajoutées à des polyglots existants.
Merci de poster un pourboire par réponse. Et n'hésitez pas à suggérer une modification si un conseil spécifique à une langue s'applique également à une autre langue.
Diviser et conquérir
Lorsque vous écrivez un polyglotte dans un grand nombre de langues, vous ne pourrez pas nécessairement séparer immédiatement tous les flux de contrôle de la langue. Ainsi, vous aurez besoin de "vraies polyglottes" de certaines langues pendant un certain temps, permettant au même code de s'exécuter dans chacune d'elles. Tenez compte de deux règles principales:
Le flux de contrôle dans deux langues quelconques doit être très similaire ou très différent . Essayer de gérer un grand nombre de flux de contrôle entrelacés est une recette pour semer la confusion et rend votre programme difficile à modifier. Au lieu de cela, vous devriez limiter la quantité de travail que vous avez à faire en vous assurant que tous les programmes qui se trouvent au même endroit sont là pour la même raison et peuvent être exécutés en parallèle aussi longtemps que vous le souhaitez. En attendant, si une langue est très différente des autres, vous souhaitez que son exécution soit déplacée le plus rapidement possible vers un emplacement très différent, de sorte que vous n'ayez pas à essayer de rendre votre code conforme à deux modèles syntaxiques différents à la fois.
Cherchez des occasions de séparer une langue ou un groupe de langues similaires. Travaillez à partir de groupes plus importants jusqu'à des groupes plus petits. Une fois que vous avez un groupe de langues similaires à un moment donné du programme, vous devrez les séparer à un moment donné. Au début du programme, vous voudrez peut-être, par exemple, séparer les langues qui servent
#
de marqueur de commentaire des langues qui utilisent un autre marqueur de commentaire. Plus tard, vous aurez peut-être un point où toutes les langues utilisent laf(x)
syntaxe pour les appels de fonction, les commandes séparées avec des points-virgules et présentent des similitudes syntaxiques similaires. À ce stade, vous pouvez utiliser quelque chose de beaucoup plus spécifique à la langue pour les séparer, par exemple le fait que Ruby et Perl ne traitent pas les séquences d'échappement dans les''
chaînes, contrairement à Python et JavaScript.En général, le flux logique de votre programme devrait se transformer en un arbre, se divisant à plusieurs reprises en groupes de langues plus similaires les unes aux autres. Cela met la majeure partie de la difficulté à écrire le polyglotte dès le début, avant la première division. À mesure que le flux de contrôle se sépare de plus en plus et que les langues en cours d'exécution se ressemblent de plus en plus, votre tâche devient plus facile car vous pouvez utiliser une syntaxe plus avancée sans provoquer d'erreur de syntaxe pour les langues impliquées.
Un bon exemple est l'ensemble {JavaScript, Ruby, Perl, Python 3}; toutes ces langues acceptent les appels de fonction avec des parenthèses et peuvent séparer des instructions avec des points-virgules. Ils supportent également tous une
eval
déclaration qui vous permet effectivement de contrôler le flux de manière portable. (Perl est le meilleur de ces langages à séparer du groupe à l’avance, car il a une syntaxe différente pour les variables des autres).la source
Masquer le code dans les littéraux de chaîne
Dans la plupart des langues, un littéral de chaîne ne fait rien, ou fait quelque chose qui peut être facilement inversé (comme enfoncer la chaîne dans la pile). La syntaxe littérale de chaîne est également relativement non standardisée, en particulier pour les syntaxes alternatives utilisées par de nombreux langages pour gérer les chaînes avec des retours à la ligne incorporés; Par exemple, Python
""" ... """
, Perlq( ... )
et Lua[[ ... ]]
.Il y a deux utilisations principales de ceux-ci. La première consiste à vous permettre d’entrelacer des sections destinées à différentes langues en commençant une chaîne à la fin de la première section d’une langue et en la reprenant au début de la seconde: il devrait être assez facile d’éviter de fermer accidentellement la chaîne en raison de la diversité des fonctions. délimiteurs de chaînes entre différentes langues. L’autre est que de nombreux délimiteurs de chaîne ont une signification en tant que commande dans d’autres langues (souvent plus que des marqueurs de commentaire), ce qui vous permet de faire quelque chose du genre
x = [[4] ]
: une affectation sans danger dans les langues qui utilisent la notation JSON pour les listes, mais qui commence par la suite. une chaîne dans Lua (et vous permet ainsi de séparer le code Lua du reste, étant donné qu'il "saute" effectivement au suivant]]
).la source
Fin du programme
Vous pouvez terminer le programme brusquement dans une langue pour ignorer le code dans une autre langue.
Donc, fondamentalement, ce format peut être utilisé
où
end_program_in_languageN
est la commande pour terminer le programme.Par exemple, dans ma réponse dans Qu'apporterez-vous pour Thanksgiving? , J’ai terminé le programme en Dip, puis j’ai écrit le code d’une autre langue, V, afin que l’interprète Dip l’ignore.
Mais dans ce cas, toutes les langues n’ont pas une commande permettant de terminer le programme comme cela. Cependant, si un tel langage possède cette fonctionnalité, il convient de l'utiliser à bon escient.
Comme @LuisMendo l'a suggéré, vous pouvez créer une erreur (si elle est autorisée) pour terminer le programme si la langue ne possède pas déjà un "programme final" intégré.
la source
Variable ou code à l'intérieur de littéraux de chaîne
Les littéraux de chaîne entre guillemets sont généralement inoffensifs dans de nombreuses langues. Mais dans certaines langues, ils pourraient aussi contenir du code.
Dans Bash, vous pouvez utiliser
`...`
(cela ne termine pas le programme):En Tcl, vous pouvez utiliser
[...]
:En PHP, vous pouvez utiliser
${...}
(cela génère une erreur dans Bash, il doit donc apparaître après le code Bash):En Ruby, vous pouvez utiliser
#{...}
:Il pourrait y avoir aussi d'autres.
Ces grammaires ne sont pas compatibles. Cela signifie que vous pouvez mettre tout le code de ces langues dans une chaîne dans un emplacement inoffensif. Et il ignorera simplement le code non reconnu dans d'autres langues et les interprétera comme un contenu de chaîne.
Dans de nombreux cas, vous pouvez aussi facilement commenter un caractère de citation double et créer un polyglotte plus traditionnel.
la source
Aliasing variable
C’est probablement l’un des trucs les plus simples à utiliser (OMI), surtout qu’il peut atteindre de nombreuses langues.
Exemple:
Cela fonctionnera non seulement en Javascript, mais aussi en Python, Ruby, etc. Plus d'exemples plus tard, lorsque je penserai à d'autres. Bien entendu, les suggestions de commentaires / modifications de post sont les bienvenues.
la source
alert
pourprint
en Python (3 seulement) parce que la syntaxe de commentaire de JS,//
peut facilement être travaillé dans un programme Python, alors que celui de Python#
ne peut être utilisée dans JS.#
commentairesCette astuce est un sous-ensemble de symboles de commentaire Exploit et de citations de bloc dans au moins une langue.
Lors de la création de polyglottes avec plusieurs langues, en particulier les langues prêtes pour la production, par opposition aux esolangs, il peut être utile d'examiner les langues utilisées
#
dans les commentaires en bloc ou sur une seule ligne.#
, et il y a beaucoup de variété dans les caractères suivant le caractère#
.#
commentaire de ligne, ce qui signifie que le fait de commencer un commentaire de bloc dans une langue n’est qu’un commentaire ordinaire dans une autre, ce qui facilite son intégration.Voici une liste récapitulative rapide des langues qui utilisent
#
un commentaire de bloc (non exhaustif):Pour plus d'exemples, voir Rosetta Code .
Voici un exemple simple et rapide, à titre de démonstration:
la source
#- ... -#
.Différences d'opérateurs arithmétiques
Pour des langages similaires ou de simples polyglottes, il est parfois utile de rechercher des différences dans la manière dont les langages exécutent l'arithmétique. En effet, la plupart des langues (non-ésotériques) ont des opérateurs arithmétiques infixes et l'arithmétique peut être un moyen rapide et facile d'introduire une différence.
Par exemple:
^
est bitwise XOR dans certaines langues et exponentiation dans d'autres/
est la division entière dans certaines langues et la division à virgule flottante dans d'autres-1/2
est-1
dans certaines langues (arrondi au bas) et0
dans d'autres (arrondi à zéro)-1%2
est-1
dans certaines langues et1
dans d'autres--x
est un non-op dans certaines langues (double négation) et pré-décrémentation dans d'autres1/0
donne l'infini dans certaines langues et des erreurs dans d'autres1<<64
donne 0 dans certaines langues (débordement) et36893488147419103232
dans d'autresla source
x=1;["JS","Python"][--x]
, qui renvoie le nom du langage dans lequel il est exécuté (entre JS et Python).Utilisez Brainfuck
Presque toutes les implémentations de BF rejettent les caractères qui ne le sont pas
+-<>[].,
, ce qui est tout à notre avantage!Le BF est probablement l’un des langages les plus faciles à intégrer dans un polyglotte à cause de cette fonctionnalité, tant que vous écrivez la partie BF en premier. Une fois que vous avez écrit votre code BF, il vous suffit de modéliser tout autre code que vous avez autour de la structure BF.
Voici un exemple très simple:
Cela incrémente et génère des codes de caractères "pour toujours" (en fonction des paramètres d'exécution). Maintenant, si vous vouliez écrire un morceau de code au hasard, par exemple dans JS, vous pourriez faire:
Remarquez comment le JS est moulé autour du BF.
Assurez-vous de savoir que cela fonctionne mieux si vous êtes vraiment prêt à commencer avec BF; il est décemment plus difficile de commencer avec une autre langue et d'essayer d'intégrer le BF.
la source
[]
que nécessaire.x=>
change la cellule, ce qui dans ce cas importe peu, mais je voulais juste direUtilisez des langues dans lesquelles la plupart des caractères n'ont pas d'importance
Ceci est une généralisation de l'argument de Mama Fun Roll à propos de BF . Un esolang qui ignore la plupart des caractères est très utile dans les polyglottes. Également utile: un esolang dans lequel un grand nombre de caractères est interchangeable. Quelques exemples:
()[]{}<>
. (@
Parfois, une erreur se produit lorsque l'interprète tente de l'analyser au début d'un indicateur de débogage.)la source
@
erreur.exec('''...\t\n\40''')
Soyez conscient des commentaires de bloc imbriqués
Parfois, plusieurs langues utilisent la même syntaxe pour les commentaires de bloc, ce qui est le plus souvent un facteur de rupture pour la création d'un polyglotte avec les deux langues. Très rarement cependant, l’une des langues autorise les commentaires de bloc imbriqués, qui peuvent être utilisés pour créer des chemins de code distincts.
Par exemple, considérons ce polyglotte:
Nim et Lily utilisent
#[
et]#
pour commencer et terminer les commentaires de bloc, mais seul Nim autorise les commentaires de bloc imbriqués.Lily considère le second
#[
comme faisant partie du commentaire de bloc singulier et le premier]#
comme terminant le commentaire de bloc. (L'#
instruction print suivante de Lily est un commentaire de ligne qui cache le code de Nim.)Nim peut également voir le
#[]#
commentaire de bloc imbriqué (bien que vide) etprint("Lily")#
le commentaire de bloc externe.la source
Je ne sais pas si cela compte, mais ...
Utilisez une ligne shebang pour tout transformer en un
perl
programme valideSelon cette réponse et la documentation Perl, si vous transmettez un fichier commençant par une ligne shebang
perl
, il appelle le programme approprié pour l'exécuter. Par exemple, celaest exécuté par l'interpréteur Python si vous appelez
perl filename.py
.la source
perl
, il ne devient pas un programme Perl.perl
"? Cela ressemble à un bon mème philosoraptor ...Appelez des fonctions non existantes, puis quittez en évaluant leurs arguments
De nombreux langages de programmation sont capables d'analyser un identifiant arbitraire suivi d'une paire de parenthèses avec une expression à l'intérieur:
Parfois, la forme de l'identifiant en question peut être corrigée, car elle est nécessaire pour donner du code à une autre langue que vous utilisez. Cela pourrait au premier abord sembler poser problème, si l'identifiant ne correspond pas à une fonction du langage.
Cependant, de nombreux langages de programmation évaluent les arguments d'une fonction avant de vérifier si la fonction elle-même existe réellement (par exemple, Lua) et vous pouvez donc utiliser ce type de construction de toute façon. tout ce dont vous avez besoin est de quitter le programme quelque part dans les arguments de la fonction.
Voici un exemple, un polyglotte dc / Lua:
c2pq
est un programme en continu pour imprimer 2 et quitter; Lua voit cela comme le nom d'une fonction, mais il est possible d'empêcher l'erreur de placer une commande exit dans son argument. Le gros avantage de cette construction réside dans le fait que contrairement à une affectation (c2pq =
), elle n'est pas automatiquement incompatible avec les langages dans lesquels les noms de variables commencent par un sigil; La syntaxe du nom de fonction est beaucoup plus cohérente dans les langues que la syntaxe du nom de variable.la source