Поради щодо створення поліглотів


48

це програма , яка може працювати в 2 -х або більше різних мов програмування.

Які загальні поради щодо створення поліглотів або вибору мов, які легко написати поліглотами для конкретного завдання?

Будь ласка, опублікуйте поради, які можна застосувати в більшості ситуацій. Тобто вони не повинні працювати тільки в поліглотах двох конкретних мов. (Ви можете просто опублікувати відповідь на запитання поліглоту, якщо у вас занадто конкретна порада.) Але ви можете ввести особливості мови, яка полегшує роботу з багатьма мовами або легко додається до будь-яких існуючих поліглотів.

Будь ласка, опублікуйте одну пораду за кожну відповідь. І не соромтесь запропонувати редагувати, якщо конкретна мова стосується й іншої мови.

Відповіді:


25

Використовуйте символи коментарів

Простий спосіб створити двомовний поліглот - це розділити код на дві частини так:

  1. Перша частина робить фактичну роботу мовою A, нешкідлива для мови B (без помилок) і закінчується мовою-символом коментаря, який приховує другу частину до мови A.
  2. Друга частина робить фактичну роботу мовою B.

Таким чином

  • Мова A бачить першу частину, яка виконує завдання, а потім коментар.
  • Мова B бачить марну першу частину, а потім другу частину, яка виконує завдання.

Єдиною складною частиною є пошук набору висловлювань (перша частина), які виконують роботу мовою A, не допускаючи помилок у мові B. Деякі пропозиції щодо цього:

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

Простий приклад, який використовує ці вказівки, можна знайти тут . Мови A і B відповідно MATL та 05AB1E .


24

Використовуйте двовимірні мови

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

У якості бонусу кілька двовимірних мов мають точку входу, відмінну від верхнього лівого кута програми, що означає, що вам не потрібно докладати жодних зусиль, щоб розділити їх від інших мов; вони відірвуться від групи природним шляхом.


20

Знайте свої правди та помилки

Кожна мова бачить "справжню" та "помилкову" дещо по-іншому. Якщо вони мають подібний синтаксис, ви можете скористатися цим, додавши рішення про те, що мови будуть працювати по-різному.

Один приклад з використання потоку Trick or Treat ''- порожній рядок. У Луа це оцінюється як простий, але хибний у 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 не обробляють послідовності втечі в ''рядках, але 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

Змінне згладжування

Це, мабуть, один із найпростіших до цих пір (ІМО) найважливіших хитрощів у використанні, тим більше, що він може охопити стільки мов.

Приклад:

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

Це працюватиме не лише у Javascript, але й у Python, Ruby тощо. Більше прикладів пізніше, коли я думаю про деякі інші. Звичайно, пропозиції щодо коментарів / редагування публікацій вітаються.


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

11

#-за коментарі

Ця порада є підмножиною символів "Експлуатувати коментарі" та " Блок-котирування" принаймні однією мовою

Створюючи поліглоти з багатьма мовами, особливо мовою, готовою до виробництва, на відміну від esolangs, може бути корисним подивитися на мови, які використовуються #в блокових або однорядкових коментарях.

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

Ось короткий підсумковий список мов, які використовують #у блочному коментарі (не вичерпний):

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              #|          |#

Більше прикладів див . У коді розетки .

Ось швидкий і простий приклад, як демонстрація:

#|
###
#`[

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

2
Перша x=>змінює осередок, що в даному випадку не має значення, а просто хотів сказати
Роман Гряф

7

Використовуйте мови, якими більшість символів не має значення

Це узагальнення точки Mama Fun Roll про BF . Езоланг, який ігнорує більшість символів, дуже корисний у поліглотах. Також корисний: езоланг, у якому великий набір символів взаємозамінні. Деякі приклади:

  • Пробіл ігнорує все, що не є пробілом, вкладками чи новим рядком.
  • Мозок-Флак в основному ігнорує все, крім того ()[]{}<>. ( @іноді викликає помилку, коли інтерпретатор намагається проаналізувати її як початок прапора налагодження.)
  • oOo КОД ігнорує все, крім букв. Крім того, всі малі літери є взаємозамінними, як і всі великі літери.
  • Wierd розрізняє лише символи пробілу та символи, які не є пробілами.
  • У Wordy деякі знаки пунктуації ігноруються, а всі літери є взаємозамінними.
  • І Парентез, і Парентез Пекло ігнорують все, крім дужок.

Я виправив цю @помилку.
Пшеничний майстер

Спробуйте поєднати Whitespace з Python
enedil

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

5

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

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

Наприклад, розглянемо цей поліглот:

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

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

Лілі розглядає другий #[як частину однини блочного коментаря, а перший - ]#як завершення блочного коментаря. ( #Наступна заява про друк Лілі - це рядковий коментар, який приховує код Німа.)

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


4

Не впевнений, чи зараховується це, але ...

Використовуйте рядок shebang, щоб перетворити все на дійсну perlпрограму

Відповідно до цієї відповіді та документації Perl, якщо ви передасте будь-який файл, який починається з рядка shebang perl, він викликає відповідну програму для його запуску. Наприклад, це

#!/usr/bin/python

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

виконується інтерпретатором Python, якщо ви телефонуєте perl filename.py.


3
Хоча програму можна викликати perl, вона не стає програмою Perl.
Paŭlo Ebermann

2
@ PaŭloEbermann Я розумію, що це межа, тому я почав свою відповідь з "не впевнений, чи є вона". :) Але що визначає справжній Perl, якщо не "те, що написано в документації та повернуто еталонною реалізацією perl"? Звучить як гарний філософський мем ...
Федеріко Полоні

1
(Дивіться також цю
метавідповідь

4

Викличте неіснуючі функції, а потім вийдіть під час оцінки своїх аргументів

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

identifier(1 + 1)

Іноді форма відповідного ідентифікатора може бути виправлена, оскільки вона потрібна для надання коду іншій мові, яку ви використовуєте. На перший погляд це може спричинити проблеми, якщо ідентифікатор не відповідає функції, якою є насправді мова.

Однак багато мов програмування оцінюють аргументи функції, перш ніж перевірити, чи існує сама функція (наприклад, Lua), і тому ви можете використовувати таку конструкцію в будь-якому випадку; все, що вам потрібно - це вийти з програми десь усередині аргументів функції.

Ось приклад поліглота постійного струму / Lua:

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

c2pq- програма постійного струму для друку 2 та виходу; Lua розглядає це як ім'я функції, але Lua можна не допустити помилок, розмістивши команду exit у своєму аргументі. Великою перевагою цієї конструкції є те, що на відміну від присвоєння ( c2pq =), воно не є автоматично несумісним з мовами, в яких імена змінних починаються з sigil; Синтаксис імен функції набагато більше відповідає мовам, ніж синтаксис змінної імені.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.