Советы по созданию полиглотов


48

это программа , которая может работать в 2 -х или более различных языков программирования.

Какие общие советы вы имеете для создания полиглотов или выбора языков, на которых легко писать полиглоты для конкретной задачи?

Пожалуйста, опубликуйте советы, которые могут быть применены в большинстве ситуаций. Т.е. они не должны работать только в полиглотах двух конкретных языков. (Вы можете просто опубликовать ответ на вопрос о полиглоте, если у вас есть слишком конкретный совет.) Но вы можете ввести функции языка, которые облегчают работу со многими языками или могут быть добавлены к любым существующим полиглотам.

Пожалуйста, оставьте один совет за ответ. И не стесняйтесь предлагать редактировать, если подсказка для конкретного языка также применима к другому языку.

Ответы:


25

Используйте символы комментария

Простой способ создать многоязычный полиглот состоит в том, чтобы код был разделен на две части следующим образом:

  1. Первая часть выполняет реальную работу на языке A, безвредна на языке B (без ошибок) и заканчивается символом комментария языка A, который скрывает вторую часть на языке A.
  2. Вторая часть выполняет реальную работу на языке B.

таким образом

  • Язык А видит первую часть, которая выполняет работу, а затем комментарий.
  • Язык B видит бесполезную первую часть, а затем вторую часть, которая выполняет свою работу.

Единственная сложная часть здесь - это найти набор утверждений (первая часть), которые выполняют работу на языке A, но не дают ошибок на языке B. Некоторые предложения для этого:

  • Большинство основанных на стеке языков позволяют отображать только верхнюю часть стека в конце программы (иногда это даже по умолчанию, как в 05AB1E).
  • Некоторые языки игнорируют неопределенные операторы (например, Golfscript).

Простой пример использования этих рекомендаций можно найти здесь . Языки A и B - MATL и 05AB1E соответственно.


24

Используйте двумерные языки

В отличие от одномерных языков, которые обычно анализируют весь исходный код и вызывают синтаксические ошибки или нежелательные эффекты времени выполнения для вещей, которые они не понимают (таким образом, вы вынуждены скрывать от них код других языков), двумерные языки имеют тенденцию только разбирать код на пути выполнения, это означает, что вся остальная часть программы игнорируется. Существует также гораздо больше возможностей для разделения путей выполнения друг от друга в двух измерениях; Вы можете отправить указатель инструкции, поворачивающий в необычном направлении, например, вниз или даже влево (оборачивая в правую часть программы), чтобы быстро убрать его с пути. Методы, используемые в одномерных языках, также распространяются на двумерные языки (например, вы можете пропустить код с помощью;; в Befunge-98, в дополнение к простой отправке IP-адреса в странном направлении), что делает это в основном просто строгим выигрышем по сравнению с одномерным решением.

В качестве бонуса, некоторые двумерные языки имеют точку входа, отличную от верхнего левого угла программы, что означает, что вам не нужно прилагать никаких усилий, чтобы отделить их от других языков; они естественно отделятся от группы.


20

Знай свои истины и ложь

Каждый язык видит «истину» и «ложь» немного по-своему. Если у них сходный синтаксис, вы можете воспользоваться этим, добавив решение, которое языки будут обрабатывать по-разному.

В одном примере из потока Trick или Treat используется ''пустая строка. В Lua это оценивается как правдивое, но ложное в Python, поэтому следующее:

print(''and'trick'or'treat')

..печать разные строки на каждом языке.

Все, что нужно, это найти такую ​​ценность. Например, вы можете использовать '0', который оценивает falseв PHP, но trueв Python.


17

Цитаты как минимум на одном языке

Вот пример, который работает как на Python, так и на C ++

#include <iostream> /*
""" */
int main() {
    std::cout << "Hello World!\n";
}

/* """
print("Hello World!")
# */

Луис Мендо решил, что, на мой взгляд, это самое простое решение - использование комментариев.

Вы ищите один язык с блочным комментированием и другой язык, где обычный синтаксис в первом - это комментирующий синтаксис во втором.

Еще проще два языка с разными стилями комментирования блоков, которые взаимозаменяемо корректны по синтаксису, но я не потрудился проверить.

Проверьте это в Python 3.5 и C ++


2
В первой строке не должно быть точки с запятой.

Правда. Хороший вопрос
dexgecko

15

Разделяй и властвуй

Когда вы пишете полиглот на большом количестве языков, вы не обязательно сможете сразу отделить все потоки управления языком друг от друга. Таким образом, вам потребуется «истинный полиглот» некоторых языков в течение некоторого промежутка времени, чтобы один и тот же код мог запускаться на каждом из них. При этом необходимо учитывать два основных правила:

  • Поток управления на любых двух языках должен быть либо очень похожим, либо очень различным . Попытка обработать большое количество чередующихся потоков управления - это способ запутаться и усложнить изменение вашей программы. Вместо этого вы должны ограничить объем работы, которую вы должны выполнить, обеспечив, чтобы все программы, которые находятся в одном и том же месте, работали по одной и той же причине и могли успешно работать параллельно столько, сколько вам нужно. Между тем, если язык сильно отличается от других, вы хотите, чтобы его выполнение перемещалось в совсем другое место как можно скорее, чтобы вам не пришлось пытаться привести свой код в соответствие двум разным синтаксическим моделям одновременно.

  • Ищите возможности разделить один язык или группу похожих языков друг от друга. Работа от больших групп до небольших групп. Если у вас есть группа похожих языков на определенном этапе программы, вам нужно будет разделить их на определенном этапе. В начале программы вы можете, скажем, захотеть разделить языки, которые используют #в качестве маркера комментария, от языков, которые используют какой-либо другой маркер комментария. Позже, возможно, у вас есть точка, в которой все языки используют f(x)синтаксис для вызовов функций, разделяют команды точкой с запятой и имеют сходные синтаксические сходства. В этот момент вы можете использовать нечто более специфичное для языка, чтобы разделить их, например, тот факт, что Ruby и Perl не обрабатывают escape-последовательности в ''строках, а Python и JavaScript делают.

В общем, логический поток вашей программы должен закончиться как дерево, многократно разделяясь на группы языков, которые больше похожи друг на друга. Это ставит большую часть трудностей при написании полиглота в самом начале, до первого сплита. По мере того, как поток управления разветвляется все больше и больше, а языки, работающие в любой заданной точке, становятся все более и более похожими, ваша задача становится проще, поскольку вы можете использовать более сложный синтаксис, не вызывая причастность языков к синтаксической ошибке.

Хорошим примером является набор {JavaScript, Ruby, Perl, Python 3}; все эти языки принимают вызовы функций с круглыми скобками и могут разделять операторы точками с запятой. Все они также поддерживают evalоператор, который эффективно позволяет выполнять управление потоками в переносимом режиме. (Perl - лучший из этих языков для раннего отделения от группы, потому что у него другой синтаксис для переменных.)


13

Скрыть код внутри строковых литералов

В большинстве языков строковый литерал сам по себе либо ничего не делает, либо делает что-то, что можно легко перевернуть (например, поместить строку в стек). Строковый буквальный синтаксис также относительно нестандартен, особенно для альтернативных синтаксисов, которые многие языки используют для обработки строк со встроенными символами новой строки; например, у Python есть """ ... """, у Perl есть q( ... ), а у Lua есть [[ ... ]].

Есть два основных использования этих. Один из них заключается в том, чтобы позволить вам чередовать разделы, предназначенные для разных языков, путем запуска строки в конце первого раздела одного языка и возобновления ее в начале второго: довольно легко избежать случайного закрытия строки из-за разнообразия разделители строк между разными языками. Другой заключается в том, что многие разделители строк оказываются значимыми в качестве команды на других языках (часто в большей степени, чем маркеры комментариев), поэтому вы можете сделать что-то вроде этого x = [[4] ], что является безопасным назначением в языках, которые используют нотацию JSON для списков, но которые начинаются строка в Lua (и, таким образом, позволяет отделить код Lua от остальных, учитывая, что он эффективно «переходит» к следующему ]]).


13

Завершение программы

Вы можете внезапно завершить программу на одном языке, чтобы она игнорировала код на другом языке.

Так что в основном этот формат может быть использован

code_in_language1 end_program_in_language1 code_for_language2 end_program_in_language2 ...

где end_program_in_languageNкоманда для завершения программы.

Например, в моем ответе в Что вы принесете на День благодарения? Я закончил программу на Dip, а затем написал код для другого языка, V, чтобы Dip-интерпретатор игнорировал его.

"turkey"e#"corn"??"gravy"p&Ssalad
"turkey"e#"corn"??"gravy"                 
                         p&            # print stack and exit program (Dip) 
                           Ssalad      # Now that the program ended in Dip,
                                       # I can write V code that would otherwise
                                       # have caused errors in Dip

Но не во всех языках есть команда, которая может так просто завершить программу. Однако, если у такого языка есть особенность, его следует использовать с умом.

Как предложил @LuisMendo, вы можете создать ошибку (если это разрешено) для завершения программы, если в языке еще нет встроенной «программы завершения».


2
Даже если у языка нет функции или оператора для завершения программы, обычно возникает ошибка
Луис Мендо

1
@LuisMendo: Согласен, хотя учтите, что многие проблемы с полиглотированием запрещают выход из-за сбоев, потому что это слишком просто. Это хорошая идея, чтобы использовать его, когда они этого не делают.

1
Вы, вероятно, должны упомянуть, что код второй части все еще должен быть синтаксически правильным на первом языке, иначе большинство практических языков выдаст ошибку.
MilkyWay90

13

Переменная или код внутри строковых литералов

Строковые литералы в двойных кавычках в большинстве случаев безвредны. Но в некоторых языках они также могут содержать код.

В Bash вы можете использовать `...`(это не завершает программу):

"`echo Hello world! >/proc/$$/fd/1`"

В Tcl вы можете использовать [...]:

"[puts {hello world!};exit]"

В PHP вы можете использовать ${...}(это создает ошибку в Bash, поэтому она должна появляться после кода Bash):

"${die(print(Hello.chr(32).world.chr(33)))}";

В Ruby вы можете использовать #{...}:

"#{puts 'Hello world!';exit}"

Там могут быть и другие.

Эти грамматики не совместимы. Это означает, что вы можете поместить весь код этих языков в одну строку в безопасном месте. И он будет просто игнорировать нераспознанный код на других языках и интерпретировать их как строковое содержимое.

Во многих случаях вы также можете легко закомментировать там символ двойной кавычки и сделать более традиционный полиглот.


12

Переменная Aliasing

Вероятно, это один из самых простых (но IMO) наиболее важных приемов, особенно потому, что он может охватить очень много языков.

Пример:

print=alert;print("Hello World!")

Это будет работать не только в Javascript, но также в Python, Ruby и т. Д. Несколько примеров позже, когда я подумаю о некоторых других. Конечно, приветствуются комментарии и предложения.


5
Обратите внимание , что при выполнении , например JS / Python, это обычно короче псевдоним , alertчтобы printв Python (3 только) , потому что комментарий синтаксиса JS, в //, может быть легко работал в программе Python, в то время как в Python #не может быть разработан в JS.
ETHproductions

11

#комментарии

Этот совет является подмножеством символов комментария Exploit и цитат по крайней мере на одном языке

При создании полиглотов со многими языками, особенно с готовыми к использованию языками, в отличие от esolang, может быть полезно взглянуть на языки, которые используются #в блочных или однострочных комментариях.

  • Есть много языков с синтаксисом блочных комментариев, начинающихся с #, и есть большое разнообразие в символах после #.
  • Большинство из этих языков также допускают использование одиночного #комментария в виде строки, что означает, что то, что может начинать блочный комментарий на одном языке, является обычным комментарием на другом, что облегчает его встраивание.

Вот краткий список языков, которые используются #в комментариях к блоку (не исчерпывающий):

Language            Start       End      Single-line #?     Notes
------------------------------------------------------------------------------------------
Agena               #/          /#             ✓
AutoIt              #cs         #ce
Brat                #*          *#             ✓
C                   #if 0       #endif                      Not actually a comment
CoffeeScript        ###         ###            ✓            Needs to be on separate line
Common Lisp         #|          |#
Julia               #=          =#             ✓
Lily                #[          ]#             ✓
Objeck              #~          ~#             ✓
Perl 6              #`{         }#             ✓            Any bracketing chars will do
Picolisp            #{          }#             ✓
Scheme              #|          |#

Для большего количества примеров, см. Rosetta Code .

Вот простой и быстрый пример в качестве демонстрации:

#|
###
#`[

print("Julia")
#=

|#
(format t "Common Lisp")
#|

###
alert("CoffeeScript")
###

]#
say "Perl 6"
#`[

...

# ]# # ### # |# ; =#

Зефир имеет #- ... -#.
DLosc

11

Арифметические операторные расхождения

Для похожих языков или простых полиглотов иногда полезно искать различия в том, как языки выполняют арифметику. Это связано с тем, что большинство (неэзотерических) языков имеют инфиксные арифметические операторы, и арифметика может быть быстрым и простым способом введения различий.

Например:

  • ^ поразрядный XOR в некоторых языках и возведение в степень в других
  • / целочисленное деление в некоторых языках и деление с плавающей точкой в ​​других
    • Для языков с целочисленным делением -1/2- -1в некоторых языках (округление вниз) и 0в других (округление до нуля)
  • -1%2есть -1в некоторых языках и 1в других
  • --x в некоторых языках не используется (двойное отрицание), а в других - перед декрементом
  • 1/0 дает бесконечность в некоторых языках и ошибки в других
  • 1<<64дает 0 в некоторых языках (переполнение) и 36893488147419103232в других

3
Простой пример x=1;["JS","Python"][--x], который возвращает имя языка, на котором он работает (между JS и Python).
ETHproductions

10

Используйте Brainfuck

Практически все реализации BF отбрасывают символы, которых нет +-<>[].,, что просто работает в нашу пользу!

BF, вероятно, является одним из самых простых языков для работы с полиглотом благодаря этой функции, если вы сначала пишете часть BF. После того, как вы код BF выписал, это просто вопрос моделирования любой другой код , который вы имеете вокруг структуры BF.

Вот действительно простой пример:

.+[.+]

Это в значительной степени увеличивает и выводит charcode «навсегда» (в зависимости от настроек времени выполнения). Теперь, если вы хотите написать случайный кусок кода, скажем, в JS, вы можете сделать:

x=>"asdf".repeat(+x)[x*Math.random()*2+1|0]

Обратите внимание, как JS формируется вокруг BF.

Обязательно знайте, что это работает лучше всего, если вы действительно настроены начать с BF; Прилично труднее начать с другого языка и попытаться включить BF.


6
Для больших полиглотов, где несколько байтов экономии от интеграции BF мало помогают, я написал бы последний BF и упаковал другой код в столько, []сколько необходимо.
Sp3000

6
Это относится не только к брейкфук, но и к огромному количеству языков, похожих на брейкфук, и ко многим другим тарпитам Тьюринга.
0 '26

2
Первый x=>меняет ячейку, что в данном случае не имеет значения, но просто хотелось сказать
Роман Греф

7

Используйте языки, на которых большинство символов не имеют значения

Это обобщение идеи Мама Фан Ролл о BF . Esolang, который игнорирует большинство символов, очень полезен в полиглотах. Также полезно: esolang, в котором большой набор символов взаимозаменяемы. Некоторые примеры:

  • Пробелы игнорируют все, что не является пробелом, символом табуляции или новой строкой.
  • Brain-Flak в основном игнорирует все, кроме ()[]{}<>. ( @иногда вызывает ошибку, когда интерпретатор пытается проанализировать его как начало флага отладки.)
  • oOo CODE игнорирует все, кроме букв. Кроме того, все строчные буквы являются взаимозаменяемыми, как и все заглавные буквы.
  • Wierd различает только пробельные и непробельные символы.
  • В Wordy некоторые знаки препинания игнорируются, и все буквы взаимозаменяемы.
  • Как в скобках, так и в скобках ад игнорирует все, кроме скобок.

Я исправил эту @ошибку.
Пшеничный волшебник

Попробуйте объединить пробелы с Python
enedil

@enedil Вам не нужно иметь вкладки с Python. Вы можете использоватьexec('''...\t\n\40''')
MilkyWay90

5

Будьте в курсе вложенных комментариев к блоку

Иногда несколько языков будут использовать один и тот же синтаксис для блочных комментариев, что чаще всего является нарушением условий для создания полиглота с двумя языками. Однако очень редко один из языков допускает вложенные блочные комментарии, которые могут быть использованы для создания отдельных путей кода.

Например, рассмотрим этот полиглот:

#[#[]#print("Lily")#]#echo"Nim"

Nim и Lily используют #[и ]#для начала, и для завершения комментариев блока, но только Nim допускает вложенные комментарии блока.

Лили рассматривает второе #[как часть единственного комментария блока, а первое - ]#как завершение комментария блока. ( #Следующий оператор печати Лили - это строковый комментарий, который скрывает код Нима.)

В качестве альтернативы Nim рассматривает #[]#вложенный (хотя и пустой) комментарий блока и комментарий print("Lily")#внешнего блока.


4

Не уверен, что это считается, но ...

Используйте строку Шебанга, чтобы превратить все в правильную perlпрограмму

Согласно этому ответу и документации Perl, если вы передадите какой-либо файл, начинающийся со строки shebang perl, он вызовет соответствующую программу для его запуска. Например, это

#!/usr/bin/python

for i in range(6):
    print i**2

исполняется интерпретатором Python, если вы звоните perl filename.py.


3
Хотя программу можно вызывать с помощью perl, она не становится программой Perl.
Пауло Эберманн

2
@ PaŭloEbermann Я понимаю, что это граница, поэтому я начал свой ответ с "не уверен, если это имеет значение". :) Но что определяет настоящий Perl, если не «что написано в документации и возвращено эталонной реализацией perl»? Звучит как хороший философ-мем ...
Федерико Полони


4

Вызовите несуществующие функции, затем выйдите, оценивая их аргументы

Многие языки программирования способны анализировать произвольный идентификатор, за которым следует пара круглых скобок с выражениями внутри:

identifier(1 + 1)

Иногда форма рассматриваемого идентификатора может быть фиксированной из-за необходимости передавать код на другой язык, который вы используете. На первый взгляд это может вызвать проблемы, если идентификатор не соответствует функции, которую на самом деле имеет язык.

Тем не менее, многие языки программирования будут оценивать аргументы функции, прежде чем проверять, существует ли сама функция (например, Lua), и поэтому вы можете использовать такую ​​конструкцию в любом случае; все, что вам нужно, это выйти из программы где-то внутри аргументов функции.

Вот пример, полиглот DC / Lua:

c2pq(1 + #os.exit(print(3)))

c2pqпрограмма постоянного тока для печати 2 и выхода; Lua видит это как имя функции, но Lua можно предотвратить ошибкой, поместив команду выхода в ее аргумент. Большим преимуществом этой конструкции является то, что в отличие от assignment ( c2pq =) она не является автоматически несовместимой с языками, в которых имена переменных начинаются с сигилы; Синтаксис имени функции гораздо более согласован во всех языках, чем синтаксис имени переменной.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.