Um poliglota é um programa que pode ser executado em 2 ou mais linguagens de programação diferentes.
Que dicas gerais você tem para criar poliglotas ou escolher idiomas fáceis de escrever poliglotas para uma tarefa específica?
Poste as dicas que podem ser aplicadas na maioria das situações. Ou seja, eles não devem funcionar apenas em poliglotas de dois idiomas específicos. (Você pode simplesmente postar uma resposta a uma pergunta poliglota se tiver uma dica muito específica.) Mas você pode introduzir recursos de um idioma que facilita o trabalho com muitos idiomas ou pode ser adicionado a qualquer poliglota existente.
Poste uma dica por resposta. E fique à vontade para sugerir edição se uma dica específica de idioma também se aplicar a outro idioma.
Dividir e conquistar
Quando você estiver escrevendo um poliglota em um grande número de idiomas, não poderá necessariamente separar todos os fluxos de controle do idioma imediatamente. Portanto, você precisará "poliglota verdadeira" em alguns idiomas por um certo período de tempo, permitindo que o mesmo código seja executado em cada um deles. Há duas regras principais a serem lembradas enquanto você faz isso:
O fluxo de controle em dois idiomas deve ser muito semelhante ou muito diferente . Tentar lidar com um grande número de fluxos de controle intercalados é uma receita para ficar confuso e dificulta a modificação do seu programa. Em vez disso, você deve limitar a quantidade de trabalho que você deve realizar, garantindo que todos os programas que estão no mesmo local estejam lá pelo mesmo motivo e possam ser executados em paralelo, contanto que você precise. Enquanto isso, se um idioma é muito diferente dos outros, você deseja que sua execução seja movida para um local muito diferente o mais rápido possível, para que você não precise tentar tornar seu código conforme dois modelos sintáticos diferentes ao mesmo tempo.
Procure oportunidades para dividir um idioma ou um grupo de idiomas semelhantes um do outro. Trabalhe de grupos maiores para grupos menores. Depois de ter um grupo de idiomas semelhantes, todos em um determinado ponto do programa, será necessário dividi-los em algum momento. No início do programa, você pode, digamos, querer dividir os idiomas que usam
#
como marcador de comentário dos idiomas que usam outro marcador de comentário. Posteriormente, talvez você tenha um ponto em que todos os idiomas usemf(x)
sintaxe para chamadas de função, separe comandos com ponto e vírgula e tenham semelhanças sintáticas semelhantes. Nesse ponto, você poderia usar algo muito mais específico da linguagem para dividi-los, por exemplo, o fato de Ruby e Perl não processarem seqüências de escape em''
strings, mas Python e JavaScript.Em geral, o fluxo lógico do seu programa deve terminar como uma árvore, dividindo-se repetidamente em grupos de idiomas que são mais semelhantes entre si. Isso coloca a maior parte da dificuldade em escrever o poliglota logo no início, antes da primeira divisão. À medida que o fluxo de controle se ramifica cada vez mais, e os idiomas que estão sendo executados em um determinado ponto se tornam cada vez mais semelhantes, sua tarefa fica mais fácil porque você pode usar uma sintaxe mais avançada sem causar erros de sintaxe nos idiomas envolvidos.
Um bom exemplo é o conjunto {JavaScript, Ruby, Perl, Python 3}; todos esses idiomas aceitam chamadas de função entre parênteses e podem separar instruções com ponto e vírgula. Todos eles também suportam uma
eval
declaração, que efetivamente permite que você faça o controle de fluxo de maneira portátil. (Perl é o melhor desses idiomas para se separar do grupo mais cedo, porque possui uma sintaxe diferente para variáveis dos outros.)fonte
Ocultar código dentro de literais de string
Na maioria dos idiomas, uma string literal por si só não faz nada ou pode ser facilmente revertida (como empurrar a string para a pilha). A sintaxe literal de string também é relativamente não padronizada, especialmente para as sintaxes alternativas que muitos idiomas usam para lidar com strings com novas linhas incorporadas; por exemplo, Python possui
""" ... """
, Perl possuiq( ... )
e Lua possui[[ ... ]]
.Existem dois usos principais deles. Uma é permitir intercalar seções destinadas a diferentes idiomas, iniciando uma sequência no final da primeira seção de uma língua e retomando-a no início da segunda: deve ser bastante fácil evitar o fechamento acidental da sequência devido à variedade de delimitadores de string entre diferentes idiomas. A outra é que muitos delimitadores de cadeia são significativos como um comando em outros idiomas (geralmente mais do que marcadores de comentários), para que você possa fazer algo como
x = [[4] ]
, que é uma atribuição inofensiva em idiomas que usam a notação JSON para listas, mas que inicia uma cadeia de caracteres em Lua (e, portanto, permite que você divida o código Lua do resto, pois ele efetivamente "salta" para o próximo]]
).fonte
Finalizando o programa
Você pode encerrar o programa abruptamente em um idioma para que ele ignore o código em outro idioma.
Então, basicamente, esse formato pode ser usado
Onde
end_program_in_languageN
está o comando para finalizar o programa.Por exemplo, na minha resposta em O que você trará para o Dia de Ação de Graças? , Encerrei o programa no Dip e, em seguida, escrevi o código para outro idioma, V, para que o intérprete do Dip o ignorasse.
Mas nem todos os idiomas têm um comando que pode finalizar o programa assim. No entanto, se esse idioma tiver esse recurso, ele deverá ser usado com sabedoria.
Como o @LuisMendo sugeriu, você pode criar um erro (se for permitido) para finalizar o programa se o idioma ainda não tiver um "programa final" embutido.
fonte
Variável ou código dentro de literais de string
Os literais de cadeia de caracteres com aspas duplas são inofensivos em muitos idiomas. Mas em alguns idiomas eles também podem conter código.
No Bash, você pode usar
`...`
(não termina o programa):No Tcl, você pode usar
[...]
:No PHP, você pode usar
${...}
(isso gera um erro no Bash, portanto deve aparecer após o código do Bash):No Ruby, você pode usar
#{...}
:Pode haver também outros.
Essas gramáticas não são compatíveis. Isso significa que você pode colocar todo o código desses idiomas em uma string em um local inofensivo. E apenas ignorará o código não reconhecido em outros idiomas e os interpretará como conteúdo da string.
Em muitos casos, você também pode comentar facilmente um caractere de aspas duplas e criar um poliglota mais tradicional.
fonte
Aliasing variável
Este é provavelmente um dos truques mais simples ainda (IMO) mais importantes a serem usados, especialmente porque ele pode alcançar muitos idiomas.
Exemplo:
Isso funcionará não apenas em Javascript, mas também em Python, Ruby, etc. Mais exemplos depois, quando penso em outros. Obviamente, sugestões de comentários / edições de post são bem-vindas.
fonte
alert
paraprint
em Python (3 apenas) porque a sintaxe comentário de JS,//
podem ser facilmente trabalhado em um programa Python, enquanto Python#
não pode ser trabalhado em JS.#
com base em comentáriosEsta dica é um subconjunto de símbolos de comentários de exploração e citações de bloco em pelo menos um idioma
Ao criar poliglotas com muitos idiomas, especialmente idiomas prontos para produção, em vez de esolangs, pode ser útil examinar os idiomas usados
#
em comentários de bloco ou de linha única.#
, e há muita variedade nos caracteres após o#
.#
como uma linha, o que significa que algo que pode iniciar um comentário em bloco em um idioma é apenas um comentário comum em outro, facilitando a inserção.Aqui está uma rápida lista resumida de idiomas que são usados
#
em um comentário em bloco (não exaustivo):Para mais exemplos, consulte Código Rosetta .
Aqui está um exemplo rápido e fácil, como uma demonstração:
fonte
#- ... -#
.Discrepâncias aritméticas do operador
Para idiomas semelhantes ou poliglotas simples, às vezes é útil procurar diferenças na forma como os idiomas executam aritmética. Isso ocorre porque a maioria das linguagens (não esotéricas) possui operadores aritméticos infix e a aritmética pode ser uma maneira rápida e fácil de introduzir uma diferença.
Por exemplo:
^
é XOR bit a bit em alguns idiomas e exponenciação em outros/
é divisão inteira em alguns idiomas e divisão de ponto flutuante em outros-1/2
está-1
em alguns idiomas (arredondar para baixo) e0
em outros (arredondar para zero)-1%2
está-1
em alguns idiomas e1
em outros--x
é um não operacional em alguns idiomas (dupla negação) e pré-decremento em outros1/0
dá infinito em alguns idiomas e erros em outros1<<64
dá 0 em alguns idiomas (overflow) e36893488147419103232
em outrosfonte
x=1;["JS","Python"][--x]
, que retorna o nome da linguagem em que é executado (entre JS e Python).Use Brainfuck
Praticamente todas as implementações do BF lançam caracteres que não são
+-<>[].,
, o que acontece a nosso favor!O BF é provavelmente um dos idiomas mais fáceis de trabalhar em um poliglota por causa desse recurso, desde que você escreva a parte do BF primeiro. Depois de escrever seu código BF, é apenas uma questão de modelar qualquer outro código que você tenha em torno da estrutura BF.
Aqui está um exemplo muito simples:
Isso praticamente incrementa e gera códigos de saída "para sempre" (dependendo das configurações de tempo de execução). Agora, se você quiser escrever um código aleatório, digamos, em JS, você pode:
Observe como o JS é moldado em torno do BF.
Certifique-se de saber que isso funciona melhor se você realmente começar a usar o BF; decentemente é mais difícil começar com outro idioma e tentar incorporar o AM.
fonte
[]
necessário.x=>
muda a célula, o que, neste caso, não importa, mas só queria dizer #Use idiomas nos quais a maioria dos caracteres não importa
Esta é uma generalização do argumento de Mama Fun Roll sobre AM . Um esolang que ignora a maioria dos caracteres é muito útil em poliglotas. Também é útil: um esolang no qual um grande conjunto de caracteres é intercambiável. Alguns exemplos:
()[]{}<>
. (@
às vezes causa um erro quando o intérprete tenta analisá-lo como o início de um sinalizador de depuração.)fonte
@
erro.exec('''...\t\n\40''')
Esteja ciente dos comentários de blocos aninhados
Às vezes, vários idiomas usam a mesma sintaxe para comentários em bloco, o que é mais comum do que nunca, para criar um poliglota com os dois idiomas. No entanto, muito ocasionalmente, um dos idiomas permitirá comentários de bloco aninhados, que podem ser abusados para criar caminhos de código separados.
Por exemplo, considere este poliglota:
Nim e Lily usam
#[
e]#
iniciam e encerram comentários de bloco, mas apenas Nim permite comentários de bloco aninhados.Lily considera o segundo
#[
como parte do comentário em bloco singular e o primeiro]#
como finalizando o comentário em bloco. (A#
declaração impressa de Lily a seguir é um comentário de linha que oculta o código de Nim.)Nim como alternativa, vê o
#[]#
comentário de bloco aninhado (embora vazio) eprint("Lily")#
o comentário de bloco externo.fonte
Não tenho certeza se isso conta, mas ...
Use uma linha shebang para transformar tudo em um
perl
programa válidoDe acordo com esta resposta e a documentação do Perl, se você passar qualquer arquivo que comece com uma linha shebang
perl
, ele chamará o programa apropriado para executá-lo. Por exemplo, issoé executado pelo interpretador Python se você chamar
perl filename.py
.fonte
perl
, ele não se torna um programa Perl.perl
"? Soa como um meme boa philosoraptor ...Chame funções inexistentes e saia enquanto avalia seus argumentos
Muitas linguagens de programação são capazes de analisar um identificador arbitrário seguido por um par de parênteses com expressões dentro:
Às vezes, a forma do identificador em questão pode ser corrigida, devido à necessidade de fornecer código para um idioma diferente que você está usando. Isso pode parecer a princípio causar problemas, se o identificador não corresponder a uma função que o idioma realmente possui.
No entanto, muitas linguagens de programação avaliarão os argumentos de uma função antes de verificar se a própria função realmente existe (por exemplo, Lua) e, portanto, você pode usar esse tipo de construção de qualquer maneira; tudo o que você precisa é sair do programa em algum lugar dentro dos argumentos da função.
Aqui está um exemplo, um poliglota dc / Lua:
c2pq
é um programa dc para imprimir 2 e sair; Lua vê isso como o nome de uma função, mas Lua pode ser impedida de erro através da colocação de um comando de saída em seu argumento. A grande vantagem dessa construção é que, diferentemente de uma atribuição (c2pq =
), ela não é automaticamente incompatível com idiomas nos quais os nomes de variáveis começam com um sigilo; A sintaxe do nome da função é muito mais consistente entre os idiomas do que a sintaxe do nome da variável.fonte