Kippleを解釈してください!


12

前書き

Kippleは、2003年3月にRune Bergによって発明されたスタックベースの難解なプログラミング言語です。

Kippleには、27のスタック、4つの演算子、および制御構造があります。

スタック

スタックは命名されているa- zと32ビット符号付き整数を含んでいます。また@、数値の出力をより便利にするための特別なスタックがあります。数字がにプッシュされる@と、その数字の数字のASCII値が実際にプッシュされます。(たとえば、12を@に押した場合、49を押し、次に50を押し@ます。)

iプログラムが実行される前に、入力が入力スタックにプッシュされます。インタープリターは、i実行前に保存する値を要求します。実行が終了すると、出力スタック上のすべてoがポップされ、ASCII文字として出力されます。これはKippleの唯一のIOメカニズムであるため、Kippleプログラムとの対話は不可能です。

オペレーター

オペランドは、スタック識別子または符号付き32ビット整数のいずれかです。

プッシュ:>または<

構文:Operand>StackIndentifierまたはStackIndentifier<Operand

Push演算子は、オペランドを左に取り、指定されたスタックにプッシュします。たとえば12>a、値12をstackにプッシュしますaa>bstackから一番上の値をポップし、stack aにプッシュしますb。空のスタックをポップすると常に0 a<bが返されb>aます。これはと同等です。a<b>c最上位から値ポップbの両方にとプッシュをcしてa

追加: +

構文: StackIndentifier+Operand

追加演算子は、スタックの一番上の項目とオペランドの合計をスタックにプッシュします。オペランドがスタックの場合、値はそこからポップされます。たとえば、スタックの最上位の値aが1の場合、a+23をプッシュします。aが空の場合、a+22をプッシュします。スタックの一番上の値場合abがある1と2は、a+bスタックから値2をポップアップ表示されますbし、スタックに3を押しますa

減算: -

構文: StackIndentifier-Operand

Subtract演算子は、Add演算子とまったく同じように機能しますが、加算ではなく減算する点が異なります。

晴れ: ?

構文: StackIndentifier?

Clear演算子は、最上位のアイテムが0の場合、スタックを空にします。

インタープリターは演算子の隣にないものをすべて無視するため、次のプログラムが機能しますa+2 this will be ignored c<i。ただし、コメントを追加する適切な方法は、#文字を使用することです。a #と行末文字の間のすべてのものは、実行前に削除されます。ASCII文字#10は、Kippleの行末として定義されています。

オペランドは2つの演算子で共有a>b c>b c?できますa>b<c?。たとえば、と書くことができます。

プログラム1>a<2 a+aa、値を[1 4](下から上へ)含むようになり、ではありません[1 3]-オペレーターも同様です。

制御構造

Kippleには、ループという制御構造が1つしかありません。

構文: (StackIndentifier code )

指定されたスタックが空でない限り、一致する括弧内のコードが繰り返されます。ループには他のループが含まれる場合があります。たとえば(a a>b)、stackのすべての値をstackにa移動しますbが、順序は逆になります。機能的には同じですが、これを行うよりエレガントな方法は(a>b)です。

100>@ (@>o)

これは出力されます 100

33>o 100>o 108>o 114>o 111>o 87>o 32>o 111>o 108>o 108>o 101>o 72>o

これは印刷されます"Hello World!"oスタックが出力されているとき、スタックの一番上から一番下まで文字をポップし始めます。

#prime.k by Jannis Harder
u<200
#change 200


k<2>m
u-2
(u-1 u>t u>z u<t
  (k>e e+0 e>r)
  (e>k)
  m+1
  m>t
  m>z
  m<t
  t<0>z? t?
  1>g
  (r>b
    m+0 m>a
    b+0 b>w
    (a-1 
      b+0 b>j
      j?
      1>s
      (j<0>s j?)
      s?
      (s<0 w+0 w>b s?)
      a>t
      a>z
      t>a
      b-1
      b>t
      b>z
      t>b
      z<0>t? z?
    a?)
    b?
    1>p
    (b<0 b? 0>p)
    p?
    (p 0>r? 0>p? 0>g)
  )
  g?
  (g m+0 m>k 0>g?)
u?)
(k>@
  10>o
  (@>o)
)

これは素数ジェネレータですが、どのように機能するのかわかりません。

ルール

  • Kippleを解釈するプログラム/関数を作成する必要があります。このプログラム/関数は、ソースファイルを介してKippleプログラムを取得するか、STDINを介してユーザーから直接取得します。STDINが使用できない場合は、キーボード入力から取得し、特定の印刷できない文字が入力されるまで入力を取得する必要があります。たとえば、インタプリタがx86マシンコードで記述されている場合、キーボードから文字ごとにKippleプログラムを取得し、それが行われるまで続けますesc(または印刷可能な文字を出力しない他のキー)が押されるます。

  • 構文エラーやスタックオーバーフローなどのエラーが発生した場合、何らかの方法で確認する必要があります。たとえば、0の代わりに10を返すか、インタープリター/コンパイラーによって生成されたエラーメッセージを返さなければなりません

  • コードゴルフのその他の規則は、このチャレンジに適用されます。

  • コードは、Kippleのサンプルアーカイブのいくつかの例でテストされます

これはです。バイト単位の最短コードが優先されます。幸運を!


Kippleにはオプションの演算子があります"が、これは仕様の一部ではなく、公式インタープリターの単なる追加機能です。ここでは言及していませんので、提出する際にサポートする必要はありません。

仕様の一部に疑問がある場合は、Javaで書かれた公式のインタープリターで調べることができます。これにより、コンパイルされたプログラムとソースコードを含むzipファイルがダウンロードされます。GPLの下でライセンスされています。


1
私たちは持っている 32ビットの符号付き整数を使用するか、私たちはホスト実装の自然な整数型で行くことができますか?(最も重要なケースは、おそらく符号なし32ビット整数、符号付きまたは符号なし8ビット整数、および任意精度整数です。)
Martin Ender

まあ、それは私が内心ウィキで見つけたものでした。はい、なぜならあなたのインタープリターは、そのメカニズムがこの機能に基づいている他のkippleプログラムと互換性がない可能性があるからです

エラーが発生した場合の動作について、より具体的に説明できますか?間違った答えを返すかエラーを出力することはできますが、エラーを出力することはできませんか?
アレックスA.

@Alex A.はい、それはプログラムの出力と見なすことができ、エラーメッセージと同じ出力を持つキップルプログラムを作成できるためです。また、エラーメッセージを出力する関数/ステートメントを持たないことは「安い」(使用する文字数が少ない)です。

3
ソースプログラムで発生する可能性のある空白は何ですか?istdinからソースプログラムを取得する場合、どのように入力を要求できますか?
orlp

回答:


6

C、709 702バイト

バイトスコアは改行(削除可能)が削除されていますが、読みやすくするために、改行を付けてここに投稿します。

#define R return
#define C ;break;case
c[999]={};*P=c;*S[28];M[99999]={};t;*T;
u(s,v){S[s]+=28;*S[s]=v;
if(s>26){for(t=v/10;t;t/=10)S[s]+=28;T=S[s];do{*T=48+v%10;T-=28;}while(v/=10);}}
o(s){t=S[s]-M>27;S[s]-=28*t;R S[s][28]*t;}
I(s){R s<65?27:s-97;}
O(int*p){if(!isdigit(*p))R o(I(*p));
for(;isdigit(p[-1]);--p);for(t=0;isdigit(*p);t*=10,t+=*p++-48);R t;}

main(i,a){for(i=0;i<28;++i)S[i]=M+i;
for(;~(*++P=getchar()););P=c+1;
for(;;){i=I(P[-1]);switch(*P++){
case 35:for(;*P++!=10;)
C'<':u(i,O(P))
C'>':u(I(*P),O(P-2))
C'+':u(i,*S[i]+O(P))
C'-':u(i,*S[i]-O(P))
C'?':if(!*S[i])S[i]=M+i
C'(':for(i=1,T=P;i;++T)i+=(*T==40)-(*T==41);if(S[I(*P)]-M<28)P=T;else u(26,P-c)
C')':P=c+o(26)-1
C-1:for(;i=o(14);)putchar(i); R 0;}}}

gcc -w golf.c-wあなたの正気のために警告を黙らせる)でコンパイルします。

i入力を除くすべてをサポートします。これは、stdinからコードを取得した場合の方法についての質問に対して、askerがまだ応答していないためです。構文エラーは報告しません。


メインポストのコメントで「i」スタックに関する質問に回答しました。

ところでそれはどのようにキップルプログラムを読みますか?コマンド引数経由?どうやって使うの?

@GLASSIC標準入力のプログラムを期待しています。
orlp

ときまで ?実行を開始する方法は?

@GLASSICプログラムを標準入力に渡すだけです。例./a.out < prime.k
orlp

3

Ruby、718バイト(現在は競合していない)

私は非常に疲れている

ファイルはコマンドライン引数としてロードされ、入力はSTDINを介して送信されます。または、入力を必要としない場合は、ファイルをSTDINにパイプしますiレジスタに。

仕様に関する混乱のため、現在のバージョンは処理していません a<b>c適切にされてため、修正されるまで競合し。

a<b>c現在修正されています。ただし、primes関数を実行すると依然として間違った結果が返されるため、競合しない答えのままです。

(f=$<.read.gsub(/#.*?\n|\s[^+-<>#()?]*\s/m,' ').tr ?@,?`
t=Array.new(27){[]}
t[9]=STDIN.read.bytes
k=s=2**32-1
r=->c{c=c[0];c[0]==?(?(s[c[1..-2]]while[]!=t[c[1].ord-96]):(c=c.sub(/^(.)<(\D)>(.)/){$1+"<#{t[$2.ord-96].pop||0}>"+$3}.sub(/(\d+|.)(\W)(\d+|.)?/){_,x,y,z=*$~
a=x.ord-96
b=(z||?|).ord-96
q=->i,j=z{j[/\d/]?j.to_i: (t[i]||[]).pop||0}
l=t[a]
y<?-?(x==z ?l[-1]*=2:l<<(l.pop||0)+q[b]
l[-1]-=k while l[-1]>k/2):y<?.?(x==z ?l[-1]=0:l<<(l.pop||0)-q[b]
l[-1]+=k while l[-1]<-k/2-1):y<?>?t[a]+=a<1?q[b].to_s.bytes: [q[b]]:y<???
(t[b]+=b<1?q[a,x].to_s.bytes: [q[a,x]]): l[-1]==0?t[a]=[]:0
z||x}while c !~/^(\d+|.)$/)}
s=->c{(z=c.scan(/(\((\g<1>|\s)+\)|[^()\s]+)/m)).map &r}
s[f]
$><<t[15].reverse.map(&:chr)*'')rescue 0

とにかく+1。フィボナッチプログラムを試しましたか?
edc65

@ edc65フィボナッチ数列プログラムも間違ったものを出力します:0 1 1 2 4 8 16...それが仕様エラーかどうか疑問に思います
Value Ink

いいえ、フィボナッチプログラムは、ラインは、例えば、がらくたでa+0ナンセンスである
edc65

素数に関する問題は、ネストされた制御構造を処理しないことだと思いますが、ルビーについてはあまり知らないので、推測が正しいとは思えません。

このプログラムは/(\((\g<1>|\s)+\)|[^()\s]+)/m、トークンとトークンのグループを分割するために使用する再帰的な正規表現の一致のため、ネストされた括弧のセットを適切に処理する必要があります。(regex101でテストします)。おそらく残りの解析ではエラーになりますが、どこにあるのかわかりません。
バリューインク
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.