ニワトリ通訳を書こう!


8

Chickenというクールな言語のインタープリターを作成する必要があります。

チキンプログラムは、ファイル、標準入力、プログラムまたは関数の引数など、言語にとって最も便利なもの、およびプログラムへの入力から読み取る必要があります。

チキン言語仕様に従ってプログラムを解釈した結果を印刷または返す必要があります。

言語に関する詳細な説明


鶏肉プログラムの概要

Chickenは、メモリモデル全体を構成する単一のスタックで動作します。命令が実行されると、プログラムはスタックから値をプッシュおよびポップしますが、プログラムがスタックの他の部分を自由に変更できるようにする命令もあります。

スタックには3つのセグメントがあります。

  1. インデックス0および1のレジスター。インデックス0はスタック自体への参照であり、インデックス1はユーザー入力への参照です。主に手順6で使用されます(下記参照)。
  2. ロードされたコード:コードの各行について、このセグメントにはセルがあり、その行には「鶏」の数が含まれています。これには最後に0(プログラム終了のオペコード)が埋め込まれます。
  3. プログラムの実行時に値がプッシュ/ポップされる実際のプログラムスタック。セグメントは分離されていないことに注意してください。つまり、スタックスペースのこのセグメントから自己変更コードを作成したり、コードを実行したりできます。

チキンISA

チキンの命令セットは、プログラムの各行に「チキン」という単語が現れる回数に基づいています。空の行はプログラムを終了し、スタックの最上位の値を出力します。

1行あたりの「鶏」の数による鶏の指示セット:

  1. リテラル文字列 "chicken"をスタックにプッシュします
  2. 上位2つのスタック値を自然数として追加し、結果をプッシュします。
  3. 上位2つの値を自然数として減算し、結果をプッシュします。
  4. 上位2つの値を自然数として乗算し、結果をプッシュします。
  5. 上位2つの値が等しいかどうかを比較し、等しい場合は1を、そうでない場合は0をプッシュします。
  6. 次の命令を見て、どのソースからロードするかを決定します。0はスタックからロードし、1はユーザー入力からロードします。スタックのトップは、指定されたソースからロードするアドレス/インデックスを指します。その値をロードしてスタックにプッシュします。これは倍幅の命令であるため、命令ポインタはソースを決定するために使用される命令をスキップします。
  7. スタックのトップは、格納するアドレス/インデックスを指します。その下の値はポップされ、指定されたインデックスでスタックに格納されます。
  8. スタックの先頭は、ジャンプする相対オフセットです。その下の値が正しい場合、プログラムはオフセットでジャンプします。
  9. スタックの先頭をASCIIとして解釈し、対応する文字をプッシュします。
  10. (10 + N)リテラル数n-10をスタックにプッシュします。

プログラムは次のとおりです。

chicken chicken chicken chicken chicken chicken chicken chicken chicken chicken chicken
chicken chicken chicken chicken chicken chicken
(an empty line)

(猫のプログラム。前の行に6つの「鶏」があるため、空の行が必要であることに注意してください。)

鶏肉プログラムに提供される入力

Chicken

出力

Chicken

Chicken.jsリファレンス実装


エラー検出

インタプリタはエラーを残し、「ニワトリ」ではない単語がソースに存在する場合に終了する必要があります。


幸運を!


3
言語仕様を質問にコピーする必要があります。質問は外部リンクに依存すべきではありません。
mbomb007 2016年


さて、自分でもやってみませんか?

1
それはあなたの質問です。仕様を決定します。
mbomb007 2016年

5
ファイル入力は、この課題を特定の言語に制限します。たとえば、それはチキンの答えを生成することを不可能にします、私はあなたが同意するだろうとがっかりします。
アーロン

回答:


1

Ruby、335バイト

入力ファイル名をコマンドライン引数として受け取り、STDINから(命令#6の)ユーザー入力を受け取ります。

Rubyの「真実」(falseおよびを除くすべてnil)がJavascriptの「真実」(Rubyの真実プラス0、空の文字列など)とは異なるため、JSインタープリターで正常に動作するプログラムがこれで失敗するエッジケースがあるかもしれません命令""がスタックにある場合などの#8のため。しかし、私は最大のケースを修正しました0

チキンのウェブサイトにあるテストプログラムとハローワールドプログラムで動作します。

+(/^(#{c='chicken'}|\s)*$/m=~f=$<.read+"

")
s=[0,STDIN.read]+f.lines.map{|l|l.split.size};s[0]=s;i=1
s<<(s[i]<10?[->{c},->{x,y=s.pop 2;x+y},->{x,y=s.pop 2;x-y},->{s.pop*s.pop},->{s.pop==s.pop},->{s[s[i+=1]][s.pop]},->{s[s.pop]=s.pop;s.pop},->{l,k,j=s.pop 3;i+=j if k&&k!=0;l},->{s.pop.chr}][s[i]-1][]:s[i]-10)while s[i+=1]>0
$><<s.pop

説明

インタプリタ/^(chicken|\s)*$/mは、ファイル全体($<.read)に対して正規表現一致を実行することにより、すぐに開始します。これにより、ファイルにchicken空白のみが含まれるようになります。Rubyでは、この演算子は一致のインデックスを返すか、またはnil見つからなかった場合に返します。

ここでは、2つのバイト節約のトリックが使用されます。直接一致する代わりにchicken、文字列置換演算子#{}が代わりにその文字列を変数に割り当てて(1バイトを節約)、ファイルの内容を変数に保存して処理するときに使用されます。 、2つの改行をlines追加して、後で関数0が命令セットの最後にエクストラを自然に追加できるようにします。(チキンプログラムに必要な後続の改行が無視されるため、2つ必要です。)

使用されるエラーはですNoMethodError: undefined method '+@' for nil:NilClass。これは、正規表現の一致を括弧で囲み、+前に置くことで行われます。ファイルがパターンに一致する場合、を取得します。+0これは、に評価され0、通常どおり続行されます。

次に、スタックが組み立てられます。スタックへの自己参照を割り当てる前に、初期リストを作成する必要があるため、プレースホルダーが使用され、置き換えられます。Rubyにはポストインクリメント演算子が存在しないため、の1代わりに命令ポインタが設定され2ています。

最後に、@ BassdropCumberwubwubwubのラムダトリックを使用して、次にスタックにプッシュするものを決定します。操作によってスタックに何もプッシュされない場合、インタプリタはスタックに同じ値を維持するように、追加の値をポップするだけです。(これにより、すべてのラムダにプッシュ操作を追加するよりもバイトが節約されます。)

Ungolfedコード:

f = $<.read + "\n\n"
+(/^(chicken|\s)*$/m =~ f)
s = [0, STDIN.read] + f.lines.map{|l|l.split.size}
s[0] = s
i = 1

while s[i += 1] > 0
    if s[i] < 10
        s.push [
            ->{'chicken'},
            ->{
                x,y = s.pop 2
                x+y
                },
            ->{
                x,y = s.pop 2
                x-y
                },
            ->{s.pop*s.pop},
            ->{s.pop==s.pop},
            ->{s[s[i+=1]][s.pop]},
            ->{s[s.pop]=s.pop;s.pop},
            ->{
                l,k,j=s.pop 3
                i+=j if k&&k!=0
                l
                },
            ->{s.pop.chr}
        ][s[i] - 1][]
    else
        s.push(s[i] - 10)
    end
end

print s.pop

実際、これを短くすることはできないと思います。(+1)

4

JavaScript ES6、398バイト

これまでで最も長いゴルフですが、これは改善できると確信していますが、私の脳はchickenこの時点以外には何も認識していません。

(a,b)=>{for(c='chicken',s=[j=0,b,...A=a.split`
`.map(m=>m.split(c).length-1)],i=A.length+2;j<A.length;([_=>s[++i]=c,_=>s[--i]=s[i]+s[i+1],_=>s[--i]=s[i]-s[i+1],_=>s[--i]=s[i]*s[i+1],_=>s[--i]=s[i]==s[i+1],_=>s[i]=s[2+j++]?b[s[i]]:s[s[i]],_=>s[s[i--]]=s[i--],_=>j+=s[--i]?s[--i+2]:0,_=>s[i]=String.fromCharCode(s[i])][s[j+2]-1]||(_=>s[++i]=s[j+1]-10))(j++));return /[^chicken \n]\w/g.test(a)?0:s[i]}

脳が機能し始めたときの説明を編集します。ここでは、今のところ少しゴルフに慣れていないバージョンです。
でないすべての場合に誤った値(0)を出力しますchicken

(a,b)=>{
    for(c='chicken',s=[j=0,b,...A=a.split`
    `.map(m=>m.split(c).length-1)],i=A.length+2; // loop init
    j<A.length; // loop condition
    ( // everything else
        [
            _=>s[++i]=c,
            _=>s[--i]=s[i]+s[i+1],
            _=>s[--i]=s[i]-s[i+1],
            _=>s[--i]=s[i]*s[i+1],
            _=>s[--i]=s[i]==s[i+1],
            _=>s[i]=s[2+j++]?b[s[i]]:s[s[i]],
            _=>s[s[i--]]=s[i--],
            _=>j+=s[--i]?s[--i+2]:0,
            _=>s[i]=String.fromCharCode(s[i])
        ][s[j+2]-1]
        ||(_=>s[++i]=s[j+1]-10)
    )(j++)
);
return /[^chicken \n]\w/g.test(a)?0:s[i]}

ここで試してください

f=
  (a,b)=>{for(c='chicken',s=[j=0,b,...A=a.split`
`.map(m=>m.split(c).length-1)],i=A.length+2;j<A.length;([_=>s[++i]=c,_=>s[--i]=s[i]+s[i+1],_=>s[--i]=s[i]-s[i+1],_=>s[--i]=s[i]*s[i+1],_=>s[--i]=s[i]==s[i+1],_=>s[i]=s[2+j++]?b[s[i]]:s[s[i]],_=>s[s[i--]]=s[i--],_=>j+=s[--i]?s[--i+2]:0,_=>s[i]=String.fromCharCode(s[i])][s[j+2]-1]||(_=>s[++i]=s[j+1]-10))(j++));return /[^chicken \n]\w/g.test(a)?0:s[i]}

i.innerHTML = f(`chicken chicken chicken chicken chicken chicken chicken chicken chicken chicken chicken
chicken chicken chicken chicken chicken chicken
`, 'Hello world!')
<pre id=i>


さて、私はいくつかのより多くの答えを待って、勝者が誰であるかを見つけましょう。

これは「エラー検出」に失敗します。あなたif(!/^(chicken\s?)+$/.test(a))throw'There are any words except "chicken".';はあなたの通訳の冒頭に直接追加することでそれを行うことができます。
Ismael Miguel

@マシュー、そのことについてどう思いますか?エラーの種類がない特定の言語があり、それらは通常、代わりに誤った値を出力します。それはOPでやや曖昧なので、これで大丈夫だと思いました。
Bassdrop Cumberwubwubwub 2016年

エラーを出力して、何かが間違っていることを伝えることができます。

1
@BassdropCumberwubwubwub OPの意味するところは、たとえば、例外をスローしstderrたり、何かを出力したり、ゼロ以外のコードでプログラムを終了したりすることです。何かが正しくないことを示すもの。JavaScriptでは、例外をスローしたり、Errorオブジェクトを返したり、アラートを表示しconsole.erro()たり、コンソールを使用して、または同様のものを書き込むことができます。
Ismael Miguel
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.