Tulis juru bahasa ayam!

8

Anda harus menulis penerjemah untuk bahasa keren bernama Chicken !

Anda harus membaca program Chicken dari file, input standar, argumen program atau fungsi, atau apa pun yang paling nyaman untuk bahasa Anda, serta input ke program.

Anda harus mencetak atau mengembalikan hasil interpretasi program sesuai dengan spesifikasi bahasa Chicken.

Keterangan lebih lanjut tentang bahasa ini .


Ikhtisar Program Ayam

Chicken beroperasi pada tumpukan tunggal, yang menyusun seluruh model memori. Saat instruksi dijalankan, program akan mendorong dan mengeluarkan nilai dari stack, tetapi ada juga instruksi yang memungkinkan program untuk memodifikasi bagian lain dari stack sesuai keinginan.

Ada tiga segmen dalam tumpukan:

  1. Register, pada indeks 0 dan 1. Indeks 0 adalah referensi ke stack itu sendiri, dan indeks 1 adalah referensi ke input pengguna. Paling banyak digunakan untuk instruksi 6 (lihat di bawah).
  2. Kode yang dimuat: untuk setiap baris kode ada sel di segmen ini yang berisi jumlah "ayam" di baris. Ini diisi dengan 0 (opcode untuk mengakhiri program) di akhir.
  3. Tumpukan program aktual, di mana nilai didorong / muncul saat program berjalan. Perhatikan bahwa segmen tidak terisolasi, yang berarti dimungkinkan untuk membuat kode modifikasi sendiri atau mengeksekusi kode dari segmen ruang stack ini.

The Chicken ISA

Kumpulan instruksi Chicken didasarkan pada berapa kali kata "chicken" muncul di setiap baris program. Baris kosong mengakhiri program dan mencetak nilai teratas dalam tumpukan.

Kumpulan instruksi Ayam, dengan jumlah "ayam" per baris:

  1. Dorong string literal "ayam" ke tumpukan
  2. Tambahkan dua nilai tumpukan teratas sebagai angka alami dan dorong hasilnya.
  3. Kurangi dua nilai teratas sebagai bilangan asli dan dorong hasilnya.
  4. Gandakan dua nilai teratas sebagai bilangan asli dan dorong hasilnya.
  5. Bandingkan dua nilai teratas untuk kesetaraan, tekan 1 jika sama dan 0 sebaliknya.
  6. Lihatlah instruksi selanjutnya untuk menentukan sumber mana yang akan memuat: 0 beban dari tumpukan, 1 beban dari input pengguna. Atas tumpukan poin ke alamat / indeks untuk memuat dari sumber yang diberikan; muat nilai itu dan dorong ke tumpukan. Karena ini adalah instruksi lebar ganda, penunjuk instruksi melewatkan instruksi yang digunakan untuk menentukan sumber.
  7. Atas tumpukan poin ke alamat / indeks untuk menyimpan. Nilai di bawah ini yang akan muncul dan disimpan dalam tumpukan pada indeks yang diberikan.
  8. Top of stack adalah offset relatif untuk melompat ke. Jika nilai di bawah ini benar, maka program melompat dengan offset.
  9. Menafsirkan bagian atas tumpukan sebagai ascii dan mendorong karakter yang sesuai.
  10. (10 + N) Mendorong angka literal n-10 ke tumpukan.

Contoh

Asumsikan programnya adalah:

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

(Program kucing. Perhatikan bahwa garis kosong diperlukan karena garis sebelumnya memiliki 6 "ayam".)

Masukan diberikan ke program Chicken

Chicken

Keluaran

Chicken

Implementasi referensi Chicken.js .


Deteksi kesalahan

Penerjemah harus meninggalkan kesalahan dan mengakhiri ketika kata apa pun yang bukan "ayam" ada di sumbernya.


Semoga berhasil!

Nilai Tinta
sumber
3
Anda perlu menyalin spesifikasi bahasa ke dalam pertanyaan. Pertanyaan tidak boleh bergantung pada tautan eksternal.
mbomb007
1
Penerjemah JS asli
mbomb007
Nah, kenapa tidak melakukannya sendiri?
1
Ini pertanyaanmu. Anda menentukan spesifikasi.
mbomb007
5
Input file membatasi tantangan ini untuk bahasa tertentu. Misalnya, membuatnya mustahil untuk menghasilkan jawaban ayam, yang saya yakin Anda akan setuju mengecewakan.
Aaron

Jawaban:

1

Ruby, 335 byte

Mengambil nama file input sebagai argumen baris perintah dan mengambil input pengguna (untuk instruksi # 6) dari STDIN.

Karena Ruby "truthy" (semuanya kecuali falsedan nil) berbeda dari Javascript "truthy" (Ruby truthy plus 0, string kosong, dll.), Mungkin ada beberapa kasus tepi di mana program yang berfungsi dengan baik pada penerjemah JS gagal pada yang satu ini karena instruksi # 8, seperti jika ""ada di stack. Saya sudah memperbaiki kasus terbesar, yang palsu 0.

Bekerja dengan program pengujian dan program Hello World di situs web Chicken.

+(/^(#{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

Penjelasan

Penerjemah segera memulai dengan menjalankan kecocokan regex /^(chicken|\s)*$/mterhadap seluruh file ( $<.read), yang memastikan file tersebut tidak berisi apa pun kecuali chickenspasi. Di Ruby, operator ini mengembalikan indeks untuk pertandingan, atau niljika tidak ditemukan.

Trik penghematan dua byte digunakan di sini: alih-alih mencocokkan secara langsung chicken, operator substitusi string #{}digunakan sebagai gantinya untuk juga menetapkan string itu ke variabel untuk nanti (menyimpan 1 byte), dan ketika menyimpan konten file ke variabel untuk diproses , itu menambahkan dua baris baru untuk memungkinkan linesfungsi nanti menambahkan secara alami tambahan 0ke akhir set instruksi. (Dua diperlukan karena mengabaikan trailing newline, yang diperlukan untuk program Chicken.)

Kesalahan yang digunakan adalah NoMethodError: undefined method '+@' for nil:NilClass, yang dilakukan dengan membungkus pertandingan regex di parens dan menempatkan +di depan. Jika file cocok dengan pola, Anda dapatkan +0, yang mengevaluasi 0dan menghasilkan secara normal.

Selanjutnya, tumpukan dirakit. Daftar awal harus dibuat sebelum referensi mandiri ke stack dapat ditetapkan, sehingga pengganti digunakan dan kemudian diganti. Pointer instruksi diatur ke 1bukan 2karena operator pasca kenaikan tidak ada di Ruby.

Akhirnya, ia menggunakan trik lambda dari @BassdropCumberwubwubwub untuk menentukan apa yang harus mendorong tumpukan berikutnya. Jika suatu operasi tidak mendorong apa pun ke stack, interpreter hanya mengeluarkan nilai tambahan sehingga stack tetap sama. (Ini menghemat byte daripada menambahkan operasi push ke setiap lambda tunggal.)

Kode tidak dikunci:

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
Nilai Tinta
sumber
Sebenarnya, saya tidak berpikir saya bisa mempersingkat ini. (+1)
4

Javascript ES6, 398 byte

Sejauh ini golf terpanjang yang pernah saya lakukan, saya yakin ini bisa diperbaiki tetapi otak saya tidak mengenali apa pun selain chickensaat ini.

(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]}

Saya akan mengedit penjelasan ketika otak saya mulai berfungsi kembali. Ini versi yang sedikit tidak diubah untuk saat ini.
Menghasilkan nilai falsey (0) untuk semua yang tidakchicken

(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]}

Coba di sini

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>

Bassdrop Cumberwubwubwub
sumber
Baiklah, biarkan saya menunggu jawaban lagi, dan cari tahu siapa pemenangnya.
Ini gagal dalam "Deteksi kesalahan". Anda dapat melakukannya dengan menambahkan if(!/^(chicken\s?)+$/.test(a))throw'There are any words except "chicken".';tepat pada awal penerjemah Anda.
Ismael Miguel
@ Matius, apa pendapat Anda tentang itu? Ada beberapa bahasa tertentu yang tidak memiliki tipe kesalahan, yang biasanya dapat menghasilkan nilai falsey. Agak kabur di OP jadi saya menganggap ini baik-baik saja.
Bassdrop Cumberwubwubwub
Anda dapat menampilkan kesalahan, memberi tahu mereka ada sesuatu yang salah.
1
@BassdropCumberwubwubwub Maksud OP adalah, misalnya, melemparkan pengecualian atau mengeluarkan sesuatu ke stderratau keluar dari program dengan kode bukan nol. Sesuatu yang menunjukkan bahwa ada sesuatu yang tidak benar. Di Javascript, Anda bisa melempar pengecualian, mengembalikan objek Galat, menampilkan lansiran, menulis ke konsol menggunakan console.erro()atau yang serupa.
Ismael Miguel