通訳通訳


25

この質問に対するジョージ・エジソンのコメントに基づいて、最小の自己解釈通訳を書きます。

  • 選択した言語を使用できます。
  • 空の言語はカウントされません。プログラムの長さは少なくとも2文字でなければなりません。
  • プログラムは言語全体を解釈する必要はなく、言語機能のチューリング完全サブセット(インタープリターを含む)のみを解釈する必要があります。
  • クインはカウントされません。
  • 言語の組み込みeval関数または同等の関数を使用しないでください。同じことがのために行くapplyなど、

1
(うーん。私は何かをする必要があります/usr/bin/cat)チューリング完全性はどうですか?
明唐

@ SHiNKiROU:ありがとう、私はそれをテストとは思わなかった。更新しました。
ホアロングタム

関連:言語がスタックオーバーフローでそれ自体書かれた最小のインタープリターですが、ここで与えられた規則を実際に遵守する回答はほとんどありません(1つだけですか?)。
dmckee

1
そのScheme sexpパーサーを書き換える必要がありますか、それともホスト言語は大丈夫だと考えることができますか?
JB

@JB:言語の文字列処理ユーティリティは、sexpパーサーを含めて問題ありません。
ホアロングタム

回答:


19

CI-260

,(1p0(2d())(41(2d())('#((1p0()(10()(1d,1p$)=)<)$2d,1p$)(40(1d,1c$^)(''(1d,^)('0
'9('0-(,'0'9('0-2p10*+1p$)(!1d)~)$^)(0($)'$(^)'^(&)'&(c)'c(p)'p(d)'d(=)'=(<)'<(
>)'>(~)'~(.)'.(,)',(!)'!(+)'+(-)'-(*)'*(/)'/(%)'%()38p(1p3p0(3d)((2)(3)=p1d1p$)
=)$)~)=)=,2p$&)=)=)<)$$

320→260:単純な文字から命令へのマッピングをプッシュし、それらを折り返します。これにより、1ケースあたりのコードサイズは半分になります(18ケースあります)が、折りたたみを行うには30文字かかります。

これは、私が作成した言語のもう1つです(Gistでホストされる基本インタープリター)。言語がコードの断片を具体化するという点でユニークです。つまり、このスタックベースの言語の命令の文字列は、他の言語のデータ構造またはクロージャと同じ効果に使用されます。

1^      # Push a 1, and "lift" it to be a code literal.
(5 +)   # Define a code literal.
&       # Join the two code literals, forming (1 5 +)
$       # Execute the code literal.

インタープリターは、実行する前にプログラム全体のコードフラグメントを構築するため、コンパイラーと見なすこともできます。このため、インタープリターをスタックしても、実行時の指数関数的なオーバーヘッドは発生しません。

インタプリタは、そのすべての演算子をホストインタプリタから直接派生します。ただし、解析は自動的に行われるため、コードの大部分は、文字をそれぞれのコードリテラルに変換する単なるシーケンスです。これはを使用することと同じではありませんが、evalプログラミング言語の実装がホスト言語/アーキテクチャのセマンティクスにどの程度依存しているかを明らかにします。


言語リファレンス:

通訳はこちら

ブロック

  • ( ... )

    「ブロック」を作成します。これは、事実上、コンテキストのない命令のリストです。内部的には、マシンコードである場合もあります。

  • ブロック $

    ブロックを呼び出します。呼び出される側には、呼び出されるブロックを含むグローバルスタックが渡されます。

  • ^

    値を上げます。つまり、その値をプッシュするブロックに変換します。

       1 ^
    == (1)
    
  • block1 block2 &

    2つのブロックを結合し、両方を順番に実行する1つを形成します。

       (1) (2) &
    == (1 2)
    

スタック操作

  • n c

    スタックのn番目の値をコピーします。

       5 4 3 2 1 0 3c
    == 5 4 3 2 1 0 3
    
  • n p

    スタックのn番目の値を取り出します(削除して、前面に表示します)。

       5 4 3 2 1 0 3p
    == 5 4 2 1 0 3
    
  • n d

    スタックからn個の値をドロップします。 0dノーオペレーションです。

       5 4 3 2 1 0 3d
    == 5 4 3
    

関係演算子

  • ab(on_true)(on_false) =

    aがbに等しいかどうかをテストします。最初の引数以外をすべて使用し、on_trueまたはon_falseを呼び出します。一方の引数がゼロで、もう一方が他のタイプの場合、結果は偽になります。それ以外の場合、aとbは整数でなければなりません。

       3 3 ('0+ .) (1d) =
    == 3 '0+ .
    
  • ab(on_true)(on_false) <

    aがbより小さいかどうかをテストします。aとbは整数でなければなりません。

       3 5 (1d 5) () <
    == 3 1d 5
    == 5
    
  • ab(on_true)(on_false) >

    aがbより大きいかどうかをテストします。aとbは整数でなければなりません。

       3 5 (1d 5) () >
    == 3
    
  • lo hi(on_true)(on_false) ~

    lo <= a <= hiかどうかをテストします。a、lo、およびhiは整数でなければなりません。

       3 0 10 ('0+ .) (1d) ~
    == 3 '0+ .
    

I / O

  • c .

    文字cを入れます(スタックから消費します)。

  • ,

    キャラクターを取得し、スタックにプッシュします。ファイルの終わりに達した場合、-1がプッシュされます。

  • c !

    キャラクターを取得します。Cのungetcのように、プッシュバックは1つだけ許可されます。

整数リテラル

  • 'c

    文字cをプッシュします。

  • [0-9] +

    10進整数をプッシュします。

算術

  • ab +
  • ab -
  • ab *

    2つの数値を加算/減算/乗算します。

       3 5 + 7 3 + *
    == 80
    
  • ab /

  • ab %

    除算とモジュラス。Cとは異なり、これらは負の無限大に向かって丸められます。

その他

  • コード#コメント

    #文字は、行の最後にすべてをコメントアウト。

  • )

    ブロックの終了に使用されます。プログラム全体を終了するためにも使用できます。

  • 他のすべての文字は無視されます。


24

バイナリラムダ計算、232 ビット(29バイト)

0101000110100000000101011000000000011110000101111110011110000101110011110000001111000010110110111001111100001111100001011110100111010010110011100001101100001011111000011111000011100110111101111100111101110110000110010001101000011010

詳細については、 http://en.wikipedia.org/wiki/Binary_lambda_calculus#Lambda_encoding を参照してください


2
なぜこれが受け入れられた答えではないのかD:BLCは素晴らしい!

まったく説明できますか?
-PyRulez

1
残念ながら、ウィキペディアはBinary Lambda Calculusページを削除しました。私のtromp.github.io/cl/cl.htmlページは、保存されたコピーと、インタープリターの動作を説明した論文にリンクしています。
ジョンTromp

13

私はこれを信用できませんが、私はこの驚くべきものを共有すると思った:

Brainf ***(423)

>>>+[[-]>>[-]++>+>+++++++[<++++>>++<-]++>>+>+>+++++[>++>++++++<<-]+>>>,<++[[>[
->>]<[>>]<<-]<[<]<+>>[>]>[<+>-[[<+>-]>]<[[[-]<]++<-[<+++++++++>[<->-]>>]>>]]<<
]<]<[[<]>[[>]>>[>>]+[<<]<[<]<+>>-]>[>]+[->>]<<<<[[<<]<[<]+<<[+>+<<-[>-->+<<-[>
+<[>>+<<-]]]>[<+>-]<]++>>-->[>]>>[>>]]<<[>>+<[[<]<]>[[<<]<[<]+[-<+>>-[<<+>++>-
[<->[<<+>>-]]]<[>+<-]>]>[>]>]>[>>]>>]<<[>>+>>+>>]<<[->>>>>>>>]<<[>.>>>>>>>]<<[
>->>>>>]<<[>,>>>]<<[>+>]<<[+<<]<]

10

BlockScript-535

{[B':=?0:B';=?0:B'}=?0:B'{=?,A!,A!d1c&:B'?=?,A!,A!2e&:B''=?,,A!d3c&:B{[B'0<?0:B
'9>?0:1}!?B'0-{[,g!?c'0-B10*d+A!:Bd]A!d3c&}!:B'#=?{[,10=?,]A!:A!}!:,A!Bb&}{[AC[
B]DB?[AB{[Bh&hbhn!}{[B[AB]C?1-eA!:b}&[C1=?E[C]FHc&B!:C2=?{G?D:E[C}!FHcI!:C3=?E[
C]B!:C'!=?G[ABC]Hc&dbh&D?b@I!B!:b@I!:C'&=?HB!:C'@=?FGDI!:C'[=?GF&HDI!:C']=?F[A]
HDI!:C',=?,B!:C'.=?G.FHDI!:C'a'z{[DC<?0:DB>?0:1}!?Ce-HA!B!:C'A'Ze!?F[B]Cg-dA!B!
:{C'+=?{[CB+}:C'-=?{[CB-}:C'*=?{[CB*}:C'/=?{[CB/}:C'%=?{[CB%}:C'<=?{[CB<}:C'>=?
{[CB>}:C'==?{[CB=}:0}!?H[A][B]Ge!B!:FHDI!:c},c!0ac&0&0&0bho!;

BlockScriptは、このチャレンジのために特別に作成した、単純なスパゲッティスタックベースの言語です。基本インタープリターはblockscript.cです。

サンプルプログラム(最初の15個のフィボナッチ数を印刷):

{[B?B10/A!B10%d&:0}
{[B0<?'-.0B-A!:{B?Bh!{[B?B[A]A!B[B]'0+.:}!:'0.}!10.}
{[B?Dd!DC+B1-CecA!:}
0 1 15d!
;

インタープリターは、標準入力からソースコードとプログラム入力の両方をこの順序で読み取ります。つまり、インタープリター内のインタープリター内でインタープリターを実行するには、単にコピーして貼り付けます。

# Level 1
{[B':=?0:B';=?0:B'}=?0:B'{=?,A!,A!d1c&:B'?=?,A!,A!2e&:B''=?,,A!d3c&:B{[B'0<?0:B
'9>?0:1}!?B'0-{[,g!?c'0-B10*d+A!:Bd]A!d3c&}!:B'#=?{[,10=?,]A!:A!}!:,A!Bb&}{[AC[
B]DB?[AB{[Bh&hbhn!}{[B[AB]C?1-eA!:b}&[C1=?E[C]FHc&B!:C2=?{G?D:E[C}!FHcI!:C3=?E[
C]B!:C'!=?G[ABC]Hc&dbh&D?b@I!B!:b@I!:C'&=?HB!:C'@=?FGDI!:C'[=?GF&HDI!:C']=?F[A]
HDI!:C',=?,B!:C'.=?G.FHDI!:C'a'z{[DC<?0:DB>?0:1}!?Ce-HA!B!:C'A'Ze!?F[B]Cg-dA!B!
:{C'+=?{[CB+}:C'-=?{[CB-}:C'*=?{[CB*}:C'/=?{[CB/}:C'%=?{[CB%}:C'<=?{[CB<}:C'>=?
{[CB>}:C'==?{[CB=}:0}!?H[A][B]Ge!B!:FHDI!:c},c!0ac&0&0&0bho!;

# Level 2
{[B':=?0:B';=?0:B'}=?0:B'{=?,A!,A!d1c&:B'?=?,A!,A!2e&:B''=?,,A!d3c&:B{[B'0<?0:B
'9>?0:1}!?B'0-{[,g!?c'0-B10*d+A!:Bd]A!d3c&}!:B'#=?{[,10=?,]A!:A!}!:,A!Bb&}{[AC[
B]DB?[AB{[Bh&hbhn!}{[B[AB]C?1-eA!:b}&[C1=?E[C]FHc&B!:C2=?{G?D:E[C}!FHcI!:C3=?E[
C]B!:C'!=?G[ABC]Hc&dbh&D?b@I!B!:b@I!:C'&=?HB!:C'@=?FGDI!:C'[=?GF&HDI!:C']=?F[A]
HDI!:C',=?,B!:C'.=?G.FHDI!:C'a'z{[DC<?0:DB>?0:1}!?Ce-HA!B!:C'A'Ze!?F[B]Cg-dA!B!
:{C'+=?{[CB+}:C'-=?{[CB-}:C'*=?{[CB*}:C'/=?{[CB/}:C'%=?{[CB%}:C'<=?{[CB<}:C'>=?
{[CB>}:C'==?{[CB=}:0}!?H[A][B]Ge!B!:FHDI!:c},c!0ac&0&0&0bho!;

# Level 3
{[B?B10/A!B10%d&:0}
{[B0<?'-.0B-A!:{B?Bh!{[B?B[A]A!B[B]'0+.:}!:'0.}!10.}
{[B?Dd!DC+B1-CecA!:}
0 1 15d!
;

映画Inceptionのように、3レベルよりも深く進むことはほとんどできません。時間の問題ではなく、スペースの問題です。BlockScriptはメモリを大量にリークしますが、これは言語自体の設計方法に関係しています。


言語リファレンス:

通訳はこちら

BlockScriptでは、「スタック」はあなたが慣れているような後続の操作によって上書きされる配列ではありません。実際には不変のリンクリストとして実装され、スタックはプログラムの期間中持続します。また、(演算子を除く@)演算子はスタックから値を削除しません。ただし、スタックの変更は、それらが発生するブロックにのみ影響します。

値の選択

  • a を通して z

    スタックから0〜25番目のアイテムを取得し、スタックにプッシュします。 aスタックの先頭、または最後にプッシュされたアイテムを指します。

  • A を通して Z

    現在のフレームの0〜25番目のアイテムを取得し、スタックにプッシュします。

  • [

    「フレーム」を開いて、スタックの先頭にあるスタック参照(以下を参照)からアイテムを選択します。 [マッチングは必要ありませんが、]フレームはレキシカルにスコープされます。BlockScriptでは、「スコープ」はブロックを形成する中括弧({... })によって決定されます。したがって、ブロック内でフレームを開いても、ブロック外のコードには影響しません。

  • ]

    現在のフレームを閉じて、前のフレーム(存在する場合)に戻ります。

ブロック

  • { ... }

    「ブロック」を作成し、スタックにプッシュします。ブロック内では、スタックはブロックの前から始まりますが、呼び出し元のスタックは一番上にプッシュされます。スタックはBlockScriptでは永続的で不変なので、ブロックはクロージャーです。イディオムの{[手段は、次に(使用引数を選択開始するフレームを開き、ブロックを開きA介してZ)。ブロックの戻り値は、}到達したときのスタックの先頭です。

    例:

    '3 '2 '1 {[ b. d. f. B. C. D. A! } 'D 'C 'B d!;
    

    これは印刷され123BCD123DCB123BCD123DCB…ます。小文字はスタック値を参照し、大文字は引数を参照します(フレームは呼び出し元のスタックに設定されているため)。 A!呼び出し元のヘッド(呼び出されるブロックであることが保証されています)を取得して呼び出します。なぜそれがBCD1回おきに反転するのか疑問に思っているのならB. C. D.、ブロックが自分自身を呼び出す直前にそれらの引数を逆順にプッシュするからです。

  • !

    ブロックを呼び出します。戻り値をスタックにプッシュします。

スタック参照

  • &

    スタック参照を作成し、スタックにプッシュします。これを「スーパーコン」と考えてください。スタック上のすべてのアイテムを効果的に取り出し、そこから「タプル」を形成するからです。イディオム&[こと何らかの手段abcと呼ばが前に今でアクセス可能なABC(ブロックの残りの部分またはまで]遭遇しました)。

    1 &つには、通常必要とされるよりも多くの値をキャプチャするため、BlockScriptは設計上メモリをリークします。

  • @

    スタック参照が指すスタックに切り替えますa。この演算子はかなり奇妙ですが、BlockScriptのセルフインタープリターは、同じ引数を2回プッシュする必要がないように、数回使用します。効果@(または、スタック操作)は、それが呼び出されたブロックに限定されます。また、フレームはの影響を受けない@ため、スタックを切り替えた後に必要な値を取得するためにフレームを使用できます。

条件式

  • ? <on true> : <on false>

    Cの三項演算子のような条件式。つまり、a「true」(つまり、整数ゼロに等しくない)の場合、<on true>を実行し、そうでない場合は<on false>を実行します。

I / O

注:入力および出力はUTF-8で行われます。「文字」は、Unicodeインデックスに対応する整数です。

  • ,

    入力の次の文字を取得し、スタックにプッシュします。入力の終わりに達した場合は、代わりに-1を押します。

  • .

    スタックの先頭に文字を出力します。

整数/文字リテラル

注:整数と文字は、BlockScriptで同じものです。

  • 'c

    文字cをプッシュします。

  • [0-9] +

    10進整数をプッシュします。

算術

これらの演算子は整数値でのみ機能します。

  • +計算b+ a(結果をプッシュしますが、どちらの値も破棄しません)。
  • -計算b- a
  • *計算b* a
  • /計算b/ a(整数除算。負の無限大に向かって丸めます)。
  • %b%を計算しaます(整数モジュラス。負の無限大に向かって丸めます)。

関係演算子

これらの演算子は整数値でのみ機能します。

  • <bが未満の場合a、1をプッシュし、そうでない場合は0をプッシュします。
  • >
  • =

その他

  • # 行末へのコメント
  • プログラムは次で終わる必要があります ;
  • 他のすべての文字は無視されます。

2
キリスト。CIで行ったように仕様を共有しますか?
ケーシー

@Casey:参照を追加しました。
ジョーイアダムス

1
あなたが夢を見ていることを知りたいですか?...レベル4で
Mateen Ulhaq

3

ゾゾテスLISP:414

素敵なブロックを取得するために追加された改行は不要であり、カウントされません。

((\(E V A L)(E(r)'(())))(\(x e)(?(s x)(V x e)((\(b j)(?(= b ")(a j)(?(= b \)x
(?(= b ?)(?(E(a j)e)(E(a(d j))e)(E(a(d(d j)))e))(?(s b)(A b(E(a j)e)(E(a(d j)
)e))(E(a(d(d b)))(L(a(d b))j e)))))))(E(a x)e)(d x))))(\(x g)(? g(?(= x(a(a
g)))(d(a g))(V x(d g)))x))(\(f h v)(?(= f r)(r)(?(= f p)(p h)(?(= f s)(s h)(?
(= f a)(a h)(?(= f d)(d h)(?(= f =)(= h v)(c h v))))))))(\(k v i)(? k(L(d k)(
d v)(c(c(a k)(E(a v)i))i))i)))

理論的には、それ自体を実行できるはずですが、元のインタープリターはBrainFuckバイナリーであり、それ自体がインタープリターなので、各パーツをテストすることしかできませんでした。それ自体と簡単な表現(p p)を与えられたとき、私はこれまでに待っていた40分よりも多くの時間を必要とし、高速を使用していると思うjitbfでそれを実行して、Perl Inline-Cを使用してCコードをオンザフライで実行しています。

Zozotezにはconsを変更する手段がなく、:バインディングを更新するために(setq / define)必要があるため、Zozotez全体を実装することはできません。また、インタープリターでは使用しないため、明示的なbegin / prognまたは&rest引数、マクロ、および特殊な印刷引数も実装しませんでした。私は含めましたpそれを使用していません(印刷)しましたので、プログラムは元のインタープリターのように計算を明示的に印刷する必要があります。

同じ権利なし:

;; A stand alone Zozotez script need to be
;; contained in one expression, here with
;; all functions provided as arguments to
;; get them bound in the dynamic environment
((\ (E V A L)
  (E(r)'(())))
 ;; E (EVAL)
 (\ (x e)
   (? (s x)
      (V x e)
      ((\ (b j)
         (? (= b ") (a j)
         (? (= b \) x
         (? (= b ?) (? (E(a j)e) (E(a(d j))e) (E(a(d(d j)))e))
         (? (s b)
            (A b (E(a j)e) (E (a(d j))e))
            (E (a(d(d b))) (L(a(d b))j e)))))))
       (E (a x) e)(d x))))
 ;; V (VALUE / symbol->value)
 (\ (x g)
   (? g
      (? (= x (a (a g)))
         (d (a g))
         (V x (d g)))
      x))
 ;; A (APPLY) but just for primitives
 (\ (f h v)
   (? (= f r) (r)
   (? (= f p) (p h)
   (? (= f s) (s h)
   (? (= f a) (a h)
   (? (= f d) (d h)
   (? (= f =)
      (= h v)
      (c h v))))))))
 ;; L ( joint evLis / extend-env)
 (\ (k v i)
   (? k
      (L (d k) 
         (d v)
     (c (c (a k) 
           (E (a v) i)) 
        i))
      i)))

0

CHIQRSX9 +(おそらく競合しない)、2バイト

+I

を使用せずにこのHQ9 +ベースの言語で自己解釈インタープリターを作成する方法はありません。STDINIを処理する組み込みインタープリターを実行します。


1
ルールのどこにも、組み込みの自己通訳は禁止されているとは書かれていません。for evalとは、プログラムではなく式のためです。
エリックアウトゴルファー

この言語でどのように素数を計算しますか?
-pppery

@ppperry Xは、実装に依存する方法で言語をチューリング完全にする(つまり素数を計算できる)ことになっています。
ドルカハンはモニカを

Esolangページによれば、PerlインタープリターのXコマンドはプログラムをランダムに混乱させて実行します。つまり、コマンドよりも決定論的に素数を計算することはできません。X指定した方法で使用できるインタープリターの例を教えてください。
pppery

@ppperryどうやらPerlで書かれたインタープリターが唯一のインタープリターであるようです。また、特定の値で「ランダム化」されたときに素数を計算するプログラムがあるとどうなりますか?
ドルカハンはモニカを

0

同時ファイルシステムBefunge 98-53 \ 18バイト(ほぼ間違いなくチート)

制限のない完全な53バイトインタープリター(IP分割とラッピングを含む複雑なタイミングの相互作用はテストしていませんが):

v ;;;;;;;;
>]390'ai@
 t;;;;;;;;
;>zzzzz#;

という名前のファイルから入力を読み取ります a、実行します。自己修正コードを使用できないというルールでは指定されていません。

ラッピングを許可しない18バイトインタープリター(コードの一方の端のIP移動と反対側の端からの開始):

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