Полиглот это программа , которая может работать в 2 -х или более различных языков программирования.
Какие общие советы вы имеете для создания полиглотов или выбора языков, на которых легко писать полиглоты для конкретной задачи?
Пожалуйста, опубликуйте советы, которые могут быть применены в большинстве ситуаций. Т.е. они не должны работать только в полиглотах двух конкретных языков. (Вы можете просто опубликовать ответ на вопрос о полиглоте, если у вас есть слишком конкретный совет.) Но вы можете ввести функции языка, которые облегчают работу со многими языками или могут быть добавлены к любым существующим полиглотам.
Пожалуйста, оставьте один совет за ответ. И не стесняйтесь предлагать редактировать, если подсказка для конкретного языка также применима к другому языку.
Разделяй и властвуй
Когда вы пишете полиглот на большом количестве языков, вы не обязательно сможете сразу отделить все потоки управления языком друг от друга. Таким образом, вам потребуется «истинный полиглот» некоторых языков в течение некоторого промежутка времени, чтобы один и тот же код мог запускаться на каждом из них. При этом необходимо учитывать два основных правила:
Поток управления на любых двух языках должен быть либо очень похожим, либо очень различным . Попытка обработать большое количество чередующихся потоков управления - это способ запутаться и усложнить изменение вашей программы. Вместо этого вы должны ограничить объем работы, которую вы должны выполнить, обеспечив, чтобы все программы, которые находятся в одном и том же месте, работали по одной и той же причине и могли успешно работать параллельно столько, сколько вам нужно. Между тем, если язык сильно отличается от других, вы хотите, чтобы его выполнение перемещалось в совсем другое место как можно скорее, чтобы вам не пришлось пытаться привести свой код в соответствие двум разным синтаксическим моделям одновременно.
Ищите возможности разделить один язык или группу похожих языков друг от друга. Работа от больших групп до небольших групп. Если у вас есть группа похожих языков на определенном этапе программы, вам нужно будет разделить их на определенном этапе. В начале программы вы можете, скажем, захотеть разделить языки, которые используют
#
в качестве маркера комментария, от языков, которые используют какой-либо другой маркер комментария. Позже, возможно, у вас есть точка, в которой все языки используютf(x)
синтаксис для вызовов функций, разделяют команды точкой с запятой и имеют сходные синтаксические сходства. В этот момент вы можете использовать нечто более специфичное для языка, чтобы разделить их, например, тот факт, что Ruby и Perl не обрабатывают escape-последовательности в''
строках, а Python и JavaScript делают.В общем, логический поток вашей программы должен закончиться как дерево, многократно разделяясь на группы языков, которые больше похожи друг на друга. Это ставит большую часть трудностей при написании полиглота в самом начале, до первого сплита. По мере того, как поток управления разветвляется все больше и больше, а языки, работающие в любой заданной точке, становятся все более и более похожими, ваша задача становится проще, поскольку вы можете использовать более сложный синтаксис, не вызывая причастность языков к синтаксической ошибке.
Хорошим примером является набор {JavaScript, Ruby, Perl, Python 3}; все эти языки принимают вызовы функций с круглыми скобками и могут разделять операторы точками с запятой. Все они также поддерживают
eval
оператор, который эффективно позволяет выполнять управление потоками в переносимом режиме. (Perl - лучший из этих языков для раннего отделения от группы, потому что у него другой синтаксис для переменных.)источник
Скрыть код внутри строковых литералов
В большинстве языков строковый литерал сам по себе либо ничего не делает, либо делает что-то, что можно легко перевернуть (например, поместить строку в стек). Строковый буквальный синтаксис также относительно нестандартен, особенно для альтернативных синтаксисов, которые многие языки используют для обработки строк со встроенными символами новой строки; например, у Python есть
""" ... """
, у Perl естьq( ... )
, а у Lua есть[[ ... ]]
.Есть два основных использования этих. Один из них заключается в том, чтобы позволить вам чередовать разделы, предназначенные для разных языков, путем запуска строки в конце первого раздела одного языка и возобновления ее в начале второго: довольно легко избежать случайного закрытия строки из-за разнообразия разделители строк между разными языками. Другой заключается в том, что многие разделители строк оказываются значимыми в качестве команды на других языках (часто в большей степени, чем маркеры комментариев), поэтому вы можете сделать что-то вроде этого
x = [[4] ]
, что является безопасным назначением в языках, которые используют нотацию JSON для списков, но которые начинаются строка в Lua (и, таким образом, позволяет отделить код Lua от остальных, учитывая, что он эффективно «переходит» к следующему]]
).источник
Завершение программы
Вы можете внезапно завершить программу на одном языке, чтобы она игнорировала код на другом языке.
Так что в основном этот формат может быть использован
где
end_program_in_languageN
команда для завершения программы.Например, в моем ответе в Что вы принесете на День благодарения? Я закончил программу на Dip, а затем написал код для другого языка, V, чтобы Dip-интерпретатор игнорировал его.
Но не во всех языках есть команда, которая может так просто завершить программу. Однако, если у такого языка есть особенность, его следует использовать с умом.
Как предложил @LuisMendo, вы можете создать ошибку (если это разрешено) для завершения программы, если в языке еще нет встроенной «программы завершения».
источник
Переменная или код внутри строковых литералов
Строковые литералы в двойных кавычках в большинстве случаев безвредны. Но в некоторых языках они также могут содержать код.
В Bash вы можете использовать
`...`
(это не завершает программу):В Tcl вы можете использовать
[...]
:В PHP вы можете использовать
${...}
(это создает ошибку в Bash, поэтому она должна появляться после кода Bash):В Ruby вы можете использовать
#{...}
:Там могут быть и другие.
Эти грамматики не совместимы. Это означает, что вы можете поместить весь код этих языков в одну строку в безопасном месте. И он будет просто игнорировать нераспознанный код на других языках и интерпретировать их как строковое содержимое.
Во многих случаях вы также можете легко закомментировать там символ двойной кавычки и сделать более традиционный полиглот.
источник
Переменная Aliasing
Вероятно, это один из самых простых (но IMO) наиболее важных приемов, особенно потому, что он может охватить очень много языков.
Пример:
Это будет работать не только в Javascript, но также в Python, Ruby и т. Д. Несколько примеров позже, когда я подумаю о некоторых других. Конечно, приветствуются комментарии и предложения.
источник
alert
чтобыprint
в Python (3 только) , потому что комментарий синтаксиса JS, в//
, может быть легко работал в программе Python, в то время как в Python#
не может быть разработан в JS.#
комментарииЭтот совет является подмножеством символов комментария Exploit и цитат по крайней мере на одном языке
При создании полиглотов со многими языками, особенно с готовыми к использованию языками, в отличие от esolang, может быть полезно взглянуть на языки, которые используются
#
в блочных или однострочных комментариях.#
, и есть большое разнообразие в символах после#
.#
комментария в виде строки, что означает, что то, что может начинать блочный комментарий на одном языке, является обычным комментарием на другом, что облегчает его встраивание.Вот краткий список языков, которые используются
#
в комментариях к блоку (не исчерпывающий):Для большего количества примеров, см. Rosetta Code .
Вот простой и быстрый пример в качестве демонстрации:
источник
#- ... -#
.Арифметические операторные расхождения
Для похожих языков или простых полиглотов иногда полезно искать различия в том, как языки выполняют арифметику. Это связано с тем, что большинство (неэзотерических) языков имеют инфиксные арифметические операторы, и арифметика может быть быстрым и простым способом введения различий.
Например:
^
поразрядный XOR в некоторых языках и возведение в степень в других/
целочисленное деление в некоторых языках и деление с плавающей точкой в других-1/2
--1
в некоторых языках (округление вниз) и0
в других (округление до нуля)-1%2
есть-1
в некоторых языках и1
в других--x
в некоторых языках не используется (двойное отрицание), а в других - перед декрементом1/0
дает бесконечность в некоторых языках и ошибки в других1<<64
дает 0 в некоторых языках (переполнение) и36893488147419103232
в другихисточник
x=1;["JS","Python"][--x]
, который возвращает имя языка, на котором он работает (между JS и Python).Используйте Brainfuck
Практически все реализации BF отбрасывают символы, которых нет
+-<>[].,
, что просто работает в нашу пользу!BF, вероятно, является одним из самых простых языков для работы с полиглотом благодаря этой функции, если вы сначала пишете часть BF. После того, как вы код BF выписал, это просто вопрос моделирования любой другой код , который вы имеете вокруг структуры BF.
Вот действительно простой пример:
Это в значительной степени увеличивает и выводит charcode «навсегда» (в зависимости от настроек времени выполнения). Теперь, если вы хотите написать случайный кусок кода, скажем, в JS, вы можете сделать:
Обратите внимание, как JS формируется вокруг BF.
Обязательно знайте, что это работает лучше всего, если вы действительно настроены начать с BF; Прилично труднее начать с другого языка и попытаться включить BF.
источник
[]
сколько необходимо.x=>
меняет ячейку, что в данном случае не имеет значения, но просто хотелось сказатьИспользуйте языки, на которых большинство символов не имеют значения
Это обобщение идеи Мама Фан Ролл о BF . Esolang, который игнорирует большинство символов, очень полезен в полиглотах. Также полезно: esolang, в котором большой набор символов взаимозаменяемы. Некоторые примеры:
()[]{}<>
. (@
иногда вызывает ошибку, когда интерпретатор пытается проанализировать его как начало флага отладки.)источник
@
ошибку.exec('''...\t\n\40''')
Будьте в курсе вложенных комментариев к блоку
Иногда несколько языков будут использовать один и тот же синтаксис для блочных комментариев, что чаще всего является нарушением условий для создания полиглота с двумя языками. Однако очень редко один из языков допускает вложенные блочные комментарии, которые могут быть использованы для создания отдельных путей кода.
Например, рассмотрим этот полиглот:
Nim и Lily используют
#[
и]#
для начала, и для завершения комментариев блока, но только Nim допускает вложенные комментарии блока.Лили рассматривает второе
#[
как часть единственного комментария блока, а первое -]#
как завершение комментария блока. (#
Следующий оператор печати Лили - это строковый комментарий, который скрывает код Нима.)В качестве альтернативы Nim рассматривает
#[]#
вложенный (хотя и пустой) комментарий блока и комментарийprint("Lily")#
внешнего блока.источник
Не уверен, что это считается, но ...
Используйте строку Шебанга, чтобы превратить все в правильную
perl
программуСогласно этому ответу и документации Perl, если вы передадите какой-либо файл, начинающийся со строки shebang
perl
, он вызовет соответствующую программу для его запуска. Например, этоисполняется интерпретатором Python, если вы звоните
perl filename.py
.источник
perl
, она не становится программой Perl.perl
»? Звучит как хороший философ-мем ...Вызовите несуществующие функции, затем выйдите, оценивая их аргументы
Многие языки программирования способны анализировать произвольный идентификатор, за которым следует пара круглых скобок с выражениями внутри:
Иногда форма рассматриваемого идентификатора может быть фиксированной из-за необходимости передавать код на другой язык, который вы используете. На первый взгляд это может вызвать проблемы, если идентификатор не соответствует функции, которую на самом деле имеет язык.
Тем не менее, многие языки программирования будут оценивать аргументы функции, прежде чем проверять, существует ли сама функция (например, Lua), и поэтому вы можете использовать такую конструкцию в любом случае; все, что вам нужно, это выйти из программы где-то внутри аргументов функции.
Вот пример, полиглот DC / Lua:
c2pq
программа постоянного тока для печати 2 и выхода; Lua видит это как имя функции, но Lua можно предотвратить ошибкой, поместив команду выхода в ее аргумент. Большим преимуществом этой конструкции является то, что в отличие от assignment (c2pq =
) она не является автоматически несовместимой с языками, в которых имена переменных начинаются с сигилы; Синтаксис имени функции гораздо более согласован во всех языках, чем синтаксис имени переменной.источник