ポリグロット作成のヒント


48

2つの以上の異なるプログラミング言語で実行できるプログラムです。

ポリグロットを作成したり、特定のタスクのポリグロットを簡単に記述できる言語を選択したりするための一般的なヒントは何ですか?

ほとんどの状況に適用できるヒントを投稿してください。つまり、2つの特定の言語の多言語でのみ機能するべきではありません。(特定のヒントが多すぎる場合は、単にポリグロットの質問への回答を投稿できます。)しかし、多くの言語での作業や既存のポリグロットへの追加を容易にする言語の機能を導入できます。

回答ごとに1つのヒントを投稿してください。また、言語固有のヒントが別の言語にも当てはまる場合は、自由に編集を提案してください。

回答:


25

コメント記号を悪用する

2言語の多言語を作成する簡単な方法は、次のようにコードを2つの部分に分割することです。

  1. 最初の部分は言語Aで実際の作業を行い、言語Bでは無害(エラーなし)で終わり、言語Aのコメントシンボルで終わります。
  2. 2番目の部分は、言語Bで実際の作業を行います。

副<文>この[前述の事実の]結果として、それ故に、従って、だから◆【同】consequently; therefore <文>このような方法で、このようにして、こんなふうに、上に述べたように◆【同】in this manner <文>そのような程度まで<文> AひいてはB◆【用法】A and thus B <文>例えば◆【同】for example; as an example

  • 言語Aは、仕事をする最初の部分、そしてコメントを見る。
  • 言語Bは、役に立たない最初の部分を見てから、2番目の部分を見て、仕事をします。

ここで唯一難しい部分は、言語Bでエラーを出さずに言語Aでジョブを実行する一連のステートメント(最初の部分)を見つけることです。これに関するいくつかの提案:

  • ほとんどのスタックベースの言語では、プログラムの最後にスタックの最上部のみを表示できます(05AB1Eのように、これがデフォルトである場合もあります)。
  • 一部の言語は、未定義のステートメントを無視します(Golfscriptなど)。

これらのガイドラインを使用する簡単な例はここに見つけることができます。言語AおよびBは、それぞれMATLおよび05AB1Eです。


24

二次元言語を使用する

一般にソースコード全体を解析し、理解できないものに対して構文エラーまたは不要なランタイム効果を生成する1次元言語とは異なり(したがって、他の言語のコードを非表示にする必要があります)、2次元言語は実行パスのコードを解析します。これは、プログラムの残りの部分全体が無視されることを意味します。また、実行パスを2次元で互いに分離する余地があります。命令ポインターを下方向や左方向(プログラムの右側に回り込むなど)の異常な方向に向けて送信すると、すぐに邪魔にならないようにすることができます。1次元言語で役立つテクニックは、2次元言語にも一般化されます(たとえば、次のコードをスキップできます:;; Befunge-98では、IPを奇妙な方向に送信するだけでなく)、これは主に1次元ソリューションと比較して厳密なゲインになります。

おまけとして、いくつかの2次元言語にはプログラムの左上以外のエントリポイントがあります。つまり、他の言語から言語を分割するために努力する必要はありません。彼らは自然にグループから分離します。


20

真実と偽りを知る

各言語では、「true」と「false」の見方が少し異なります。それらに類似した構文がある場合、言語が異なる方法で処理するという決定を追加することにより、これを活用できます。

Trick or Treatスレッドの1つの例では''、空の文字列を使用しています。Luaでは、これは真実であると評価されますが、Pythonでは偽であるため、次のようになります。

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

..各言語で異なる文字列を印刷します。

必要なのは、このような値を見つけることだけです。たとえば、PHPでは'0'評価するfalsetruePython では評価するを使用できます。


17

少なくとも1つの言語のブロック引用

PythonとC ++の両方で機能する例を次に示します

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

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

Luis Mendoは、コメントを使用することが最も簡単な解決策だと思うことを提案しました。

ブロックコメントがある言語と、最初の正規構文が2番目の構文をコメントする別の言語を探します。

さらに簡単なのは、ブロックコメントスタイルが異なる2つの言語であり、これらは同じ意味で正しい構文ですが、確認するのは面倒です。

Python 3.5およびC ++で確認してください


2
そこの最初の行にはセミコロンがあってはなりません。

本当です。良い点
dexgecko

15

分割統治

多数の言語でポリグロットを作成する場合、必ずしもすべての言語の制御フローを相互にすぐに分離できるとは限りません。したがって、いくつかの言語を一定期間「真の多言語」にして、それぞれの言語で同じコードを実行できるようにする必要があります。これを行っている間、心に留めておくべき2つの主なルールがあります。

  • 2つの言語の制御フローは、非常に似ているか、非常に異なっている必要があります。多数のインターリーブされた制御フローを処理しようとすると、混乱するためのレシピであり、プログラムの変更が難しくなります。代わりに、同じ場所にあるすべてのプログラムが同じ理由でそこにあり、必要に応じて楽しく並行して実行できるようにすることで、実行する作業量を制限する必要があります。一方、言語が他の言語と大きく異なる場合は、実行をできるだけ早く別の場所に移動して、一度に2つの異なる構文モデルにコードを適合させる必要がないようにします。

  • 1つの言語、または同様の言語のグループを互いに分離する機会を探します。大規模なグループから小規模なグループまで作業します。プログラムの特定の時点で類似した言語のグループをすべて作成したら、それらをある時点で分割する必要があります。プログラムの開始時に、たとえば、#コメントマーカーとして使用する言語を、他のコメントマーカーを使用する言語から分離したい場合があります。後で、おそらく、すべての言語f(x)が関数呼び出しに構文を使用し、セミコロンでコマンドを分離し、同様の構文の類似性を持つ点があります。その時点で、言語固有のものをさらに分割して使用できます。たとえば、RubyとPerlは''文字列のエスケープシーケンスを処理しませんが、PythonとJavaScriptは処理します。

一般に、プログラムの論理的な流れはツリーになり、互いに類似した言語のグループに繰り返し分割されるはずです。これにより、最初の分割の前の最初にポリグロットを書くのが困難になります。制御フローがますます分岐し、任意の時点で実行されている言語がますます類似するようになると、関連する言語に構文エラーを引き起こすことなく、より高度な構文を使用できるため、タスクが簡単になります。

良い例は、{JavaScript、Ruby、Perl、Python 3}のセットです。これらの言語はすべて、括弧付きの関数呼び出しを受け入れ、ステートメントをセミコロンで区切ることができます。また、これらはすべてevalステートメントをサポートしています。これにより、移植可能な方法で効果的にフロー制御を行うことができます。(Perlは他の言語とは異なる変数の構文を持っているため、これらの言語の中でグループから早期に分離するのに最適な言語です。)


13

文字列リテラル内のコードを非表示

ほとんどの言語では、文字列リテラル自体は何もしないか、簡単に元に戻すことができるもの(文字列をスタックにプッシュするなど)を行います。文字列リテラル構文も、特に改行が埋め込まれた文字列を処理するために多くの言語で使用される代替構文の場合、比較的標準化されていません。たとえば、Pythonには""" ... """、Perlにはq( ... )、Luaには、があります[[ ... ]]

これらには主に2つの用途があります。1つは、ある言語の最初のセクションの最後で文字列を開始し、2番目のセクションの最初で文字列を再開することで、異なる言語を対象としたセクションをインターリーブできるようにすることです。異なる言語間の文字列区切り記号。もう1つは、多くの文字列区切り文字が他の言語のコマンドとして(コメントマーカーよりも多くの場合)意味があるため、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でプログラムを終了し、Dipインタープリターがそれを無視するように、別の言語Vのコードを作成しました。

"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
おそらく、2番目の部分のコードは最初の言語で構文的に正しいはずです。さもないと、ほとんどの実用的な言語でエラーがスローされます。
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}"

他にもあるかもしれません。

これらの文法は互換性がありません。つまり、これらの言語のすべてのコードを無害な場所の1つの文字列に入れることができます。そして、他の言語で認識されないコードを無視し、文字列コンテンツとして解釈します。

多くの場合、二重引用符を簡単にコメントアウトして、より伝統的なポリグロットを作成することもできます。


12

変数のエイリアス

これはおそらく、非常に多くの言語に到達する可能性があるため、使用する最も単純な(IMO)最も重要なトリックの1つです。

例:

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

これは、Javascriptだけでなく、Python、Rubyなどでも機能します。他のいくつかの例を考えると、後の例もあります。もちろん、コメントの提案/編集後の投稿は大歓迎です。


5
注たとえばJS / Pythonのをやったときに、それは別名に通常より短くだということalertprintはPython(3のみ)でJSのコメント構文ので、//Pythonのは、一方で、簡単に、Pythonプログラムに加工することができます#JSに加工することができません。
ETHproductions

11

#ベースのコメント

このヒントは、少なくとも1つの言語でのエクスプロイトコメントシンボルブロック引用のサブセットです

多くの言語、特にエソランとは対照的に生産準備の整った言語でポリグロットを作成する場合#、ブロックまたは単一行のコメントで使用する言語を調べると便利です。

  • で始まるブロックコメント構文を持つ多くの言語があり#、に続く文字にはさまざまなものがあります#
  • これらの言語のほとんどは、単一#の行コメントとしても使用できます。つまり、ある言語でブロックコメントを開始するものは、別の言語では単なる普通のコメントであり、簡単に収まります。

#ブロックコメントで使用する言語の概要リストを以下に示します(網羅的ではありません)。

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一部の言語(オーバーフロー)および36893488147419103232その他の言語では0を返します

3
簡単な例はx=1;["JS","Python"][--x]、実行される言語の名前を返す(JSとPythonの間)です。
ETHproductions

10

Brainfuckを使用する

ほとんどすべてのBF実装は+-<>[].,、そうではないcharをキャストします。

BF パートを最初に記述する限り、BFはおそらくこの機能のために、多言語に対応する最も簡単な言語の1つですBFコードを作成したら、BF構造の周りにある他のコードをモデリングするだけです。

これは本当に簡単な例です:

.+[.+]

これはかなり増加し、「ランタイム」に文字コード出力されます(ランタイム設定に依存)。たとえば、JSでランダムなコードを書きたい場合は、次のようにします。

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

JSがBFの周りにどのように成形されているかに注目してください。

BFから始めることに本当に慣れている場合は、これが最適に機能することを必ず確認してください。別の言語から始めてBFを組み込むのはかなり困難です。


6
BFの統合による数バイトの節約があまり役に立たない大きなポリグロットの場合、BFを最後に記述し、他のコード[]を必要なだけラップします。
Sp3000

6
これは、brainfuckだけでなく、brainfuckに類似した膨大な数の言語やその他のTuringターピットにも当てはまります。
0 'を

2
最初のx=>変化、この場合には重要ではありませんが、ただ言いたかったセル、
ローマGRAF

7

ほとんどの文字が関係ない言語を使用する

これは、ママファンロールのBFに関するポイントの一般化です。ほとんどの文字を無視するエソランは、ポリグロットで非常に便利です。また有用:多数の文字セットが交換可能なエソラン。いくつかの例:

  • 空白は、スペース、タブ、または改行以外のすべてを無視します。
  • Brain-Flakは基本的に以外のすべてを無視します()[]{}<>。(@インタープリターがデバッグフラグの開始として解析しようとすると、エラーが発生することがあります。)
  • oOo CODEは、文字を除くすべてを無視します。さらに、すべての小文字は、すべて大文字と同様に交換可能です。
  • Wierdは、空白文字と非空白文字のみを区別します。
  • 長ったらしい、一部の句読点は無視され、すべての文字は交換可能です。
  • 括弧括弧の両方の地獄は括弧を除くすべてを無視します。

その@エラーを修正しました。
小麦ウィザード

Pythonので空白を組み合わせて試してみてください
enedil

@enedil Pythonでタブを使用する必要はありません。次を使用できますexec('''...\t\n\40''')
MilkyWay90

5

ネストされたブロックのコメントに注意する

複数の言語がブロックコメントに同じ構文を使用する場合がありますが、これは多くの場合、2つの言語でポリグロットを作成するための契約違反となります。ただし、非常にまれに、言語の1つでネストされたブロックコメントが許可される場合があり、これを悪用して個別のコードパスを作成することができます。

たとえば、次のポリグロットを考えてみましょう。

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

NimとLilyは両方#[ともと]#を使用してブロックコメントを開始および終了しますが、ネストされたブロックコメントを許可するのはNimのみです。

Lilyは、2番目#[を単一のブロックコメントの一部と見なし、1番目をブロックコメントの]#終了と見なします。(#次のLilyのprintステートメントは、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ですか?良いphilosoraptorミームのように聞こえる...
フェデリコPoloni

1
このメタ回答も参照してください。)
Federico Poloni

4

存在しない関数を呼び出し、引数を評価しながら終了する

多くのプログラミング言語は、任意の識別子とそれに続く式を含む括弧のペアを解析できます。

identifier(1 + 1)

使用している別の言語にコードを提供する必要があるため、問題の識別子の形式が修正される場合があります。識別子が言語が実際に持っている機能に対応していない場合、最初は問題を引き起こすように思われるかもしれません。

ただし、多くのプログラミング言語は、関数自体が実際に存在するかどうか(Luaなど)を確認する前に、関数の引数を評価するため、この種の構造を使用できます。必要なのは、関数の引数内のどこかでプログラムを終了することだけです。

以下に、dc / Luaポリグロットの例を示します。

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

c2pq2を出力して終了するdcプログラムです。Luaはこれを関数の名前と見なしますが、引数にexitコマンドを配置することで、Luaのエラーを防ぐことができます。この構造の大きな利点は、代入(c2pq =)とは異なり、変数名がシギルで始まる言語と自動的に互換性がないことです。関数名の構文は、変数名の構文よりも言語間ではるかに一貫しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.